Compare commits
346 Commits
dev
...
wip-secure
Author | SHA1 | Date | |
---|---|---|---|
efc16a9e80 | |||
161f272f41 | |||
6aa6c0020c | |||
acd46940e4 | |||
00a25f1533 | |||
bc0a1eb1b3 | |||
cd3f483df0 | |||
38a183cf3b | |||
5ed6e84cc7 | |||
7c1a0fc323 | |||
f16066549f | |||
659da66106 | |||
c07eaba873 | |||
bb420bd45d | |||
3902432864 | |||
33efbeda8a | |||
8206fb0519 | |||
2687286489 | |||
d5e52e21f7 | |||
367fc24aa8 | |||
bf45206d1a | |||
397b2ae2ea | |||
f0ebb305ec | |||
e629d2d999 | |||
9b2601e450 | |||
a20c13fffe | |||
20a2d8dc1c | |||
297bf7e090 | |||
ed024d081e | |||
4ddd4191bc | |||
32ef63028b | |||
70bd001171 | |||
b53f376d70 | |||
621c147483 | |||
841076fd9e | |||
80492e902b | |||
f058fe0be6 | |||
8fde3dea77 | |||
ac9238a7f0 | |||
45412e5042 | |||
d76d50f1c4 | |||
f1c76ada43 | |||
9dbd85ba08 | |||
2c707c3acd | |||
0fae963d90 | |||
90df178c35 | |||
dc053149d0 | |||
bce81d0487 | |||
a8eba4df4d | |||
1bb36b74c2 | |||
e21910a1f7 | |||
4b30036973 | |||
ea5919ab6b | |||
43232ff569 | |||
6a9fd04437 | |||
dc2d46b9c0 | |||
666744bda3 | |||
ba09fbeec9 | |||
916ecc30d1 | |||
1536a60a3d | |||
b7418afede | |||
82a0bf3212 | |||
cb79224c7a | |||
b850e25f5b | |||
8f0f7ef333 | |||
0bfaead177 | |||
1b93dbe12c | |||
72d286fbba | |||
033faf6f6b | |||
eb3651ce59 | |||
bf1f843306 | |||
6cc5669772 | |||
cb1fbdcaf0 | |||
c83dc4d601 | |||
36bbac539f | |||
9a1cd9341f | |||
3a6a5ffe01 | |||
971de060d5 | |||
3ea57f1d6a | |||
fa05e59863 | |||
de7ff360dc | |||
7f1f9a082d | |||
6553cdc068 | |||
e44771f67d | |||
cbe17c03e4 | |||
4c4d841038 | |||
060ae113a1 | |||
540124d2f7 | |||
9df947aa74 | |||
66333cbbe7 | |||
3353ed3b66 | |||
447923a231 | |||
3179a6834b | |||
70a470b81e | |||
fff7848cd6 | |||
1fb6cb483b | |||
33e72c8d34 | |||
8629e2600a | |||
2e644dc020 | |||
f4a6bc1991 | |||
19fd45211f | |||
ace03bb0e9 | |||
8819142128 | |||
d905af6cd1 | |||
0f084b19f1 | |||
91263b9dcf | |||
40e4d0f39c | |||
06a17e4425 | |||
cbca403158 | |||
3b8d6c8587 | |||
d59380b4dd | |||
f4df121e3d | |||
3d91fa2475 | |||
96f786de20 | |||
fcbbfc4a65 | |||
b93e9e75e6 | |||
4daf5452e8 | |||
af905a2f58 | |||
8ef5920d84 | |||
b554d32133 | |||
2203d6db59 | |||
07b55bb3ec | |||
874b7aecfa | |||
cf8e9f798d | |||
800945d951 | |||
4c3b0f820b | |||
0756349c86 | |||
490c587737 | |||
15df9edca1 | |||
2d73b85f92 | |||
70d4925483 | |||
dda2ea6fcb | |||
a165e568a8 | |||
a539e52abe | |||
e62df51258 | |||
17e7c7d48b | |||
6f1173e45a | |||
225c8de7a2 | |||
05f8dad425 | |||
8b6971a164 | |||
91359174f6 | |||
b012b93d89 | |||
34e770c5f5 | |||
0460a419c5 | |||
79834aedf3 | |||
2ca8bcda56 | |||
8ced778def | |||
d91ca22587 | |||
a47b9d580a | |||
fc8a54f39b | |||
3ae25fbe31 | |||
36acc87f30 | |||
5b7244d339 | |||
9efa5bb209 | |||
211486f60e | |||
b21002207a | |||
1fc0ae3066 | |||
712cff2867 | |||
a103cd819f | |||
553a2724a4 | |||
bf0583cbda | |||
5a5842d26c | |||
3f8f3f4e54 | |||
4ad6c84d31 | |||
8e215cba69 | |||
1e3b71def3 | |||
90b057af95 | |||
4e35c09a85 | |||
1e0034c66f | |||
ae91b825e6 | |||
3c8b3f2d04 | |||
79fbdc4e15 | |||
284ea45648 | |||
9c33cb44e2 | |||
77a9f47352 | |||
04a5d38f79 | |||
452950d80b | |||
a79d9b1823 | |||
6e3a790a46 | |||
7be997f597 | |||
ef1ee6c1c9 | |||
e196cea667 | |||
105416990a | |||
c0d1f7711a | |||
f123be98b2 | |||
15b0bba329 | |||
734a4c7c31 | |||
3ce2b44b7d | |||
5f0eaa9771 | |||
cd7b36b761 | |||
b72acef8ed | |||
74f2d4d174 | |||
bedc9d4b2c | |||
70b36fd79f | |||
7baed78b65 | |||
7cca126efc | |||
433e8b8736 | |||
c026b8c40d | |||
88df6b30ce | |||
d324a57f06 | |||
55bed1926c | |||
8c9dcdb90f | |||
0ebcbe0ad5 | |||
a9cbb2c092 | |||
c5227c52c4 | |||
0af5e43944 | |||
cd16f8c3b6 | |||
0f7ec33dac | |||
993c3df09e | |||
fccb48cc2d | |||
64ddf15620 | |||
68ef56b572 | |||
99c19ceac0 | |||
f95f9a35fc | |||
5f1ac2afac | |||
2ee53fd5be | |||
9fb2cf4d42 | |||
612fa0cae8 | |||
875e85c646 | |||
94ecca2967 | |||
1fea424052 | |||
4abd782b62 | |||
13b04d50b0 | |||
36b1178fc0 | |||
527e7029b9 | |||
18c07721d9 | |||
6ac700811a | |||
cd62aa2f38 | |||
72a78c5f3e | |||
db292850b0 | |||
8e6272bafd | |||
90e1f4a447 | |||
31c32b9636 | |||
d6aef04a77 | |||
0f08f14dc0 | |||
6d9806613c | |||
c0c2aa00f3 | |||
6d5cd7b604 | |||
98860ccf46 | |||
bc5805b341 | |||
3a4d27c3bf | |||
c88ef43310 | |||
326e71f7b1 | |||
532d3c13f6 | |||
9f26ad40f9 | |||
c8a99317bc | |||
2296e10f15 | |||
ca68434f18 | |||
a1de7a4afd | |||
b692c0b6ce | |||
8ba1e35b9d | |||
765ec610c9 | |||
43c33fef21 | |||
9bcc7cd30b | |||
0b7d8310df | |||
c6f07d4f55 | |||
94a0e77fcc | |||
91d5c20a56 | |||
9b898ce597 | |||
a49411c02d | |||
fcd13d4f6f | |||
ef1be364e7 | |||
8472320629 | |||
19acab1363 | |||
98e1ae53e2 | |||
eb2321aa79 | |||
8febe70665 | |||
ee4ab3b40c | |||
281643afb0 | |||
86f1e36035 | |||
929a8eadbc | |||
e355a4b2eb | |||
132798be23 | |||
c72e66a901 | |||
40d32ec1d5 | |||
1377f5c7bc | |||
bee714311b | |||
b368d4624e | |||
583f7217fc | |||
e8b0979de6 | |||
c4b4ac48fd | |||
8436ba3e02 | |||
8b1f91ca86 | |||
73f6907e9a | |||
d6bfef7657 | |||
0fafd81b79 | |||
2ac9c2cb68 | |||
e8547cc849 | |||
3495f04810 | |||
68a891f6de | |||
b8dbc0c1c0 | |||
6964cf8d46 | |||
c959c0a74a | |||
7b0a4c11ec | |||
a926cbee46 | |||
23d8990596 | |||
76ae404827 | |||
e868e28ed9 | |||
2283a5b167 | |||
8d0b7c5855 | |||
3fb7fe34c4 | |||
10687a80e4 | |||
a8bcfaed53 | |||
ab200f8988 | |||
b443fd46d8 | |||
0473822172 | |||
d0b5f586c4 | |||
f6895393d9 | |||
f78b49f075 | |||
aa3115d2ca | |||
924a6c812c | |||
fd50bf6422 | |||
7c0e7cbb71 | |||
26004da704 | |||
7013b09715 | |||
3969fd484b | |||
eeab1d9fda | |||
deb355d960 | |||
1d4df82bde | |||
f49e87cf99 | |||
e38c2f20e8 | |||
0e5f01f240 | |||
e04dd6cb7d | |||
f4b6bbfbd5 | |||
2e8c58a53d | |||
f6e326869f | |||
c16f2473e5 | |||
d85ffa8539 | |||
987cd93ce3 | |||
e82faa5961 | |||
514cfe7b0b | |||
dd2eb66875 | |||
6ccdbf50cd | |||
e2cca54e08 | |||
721f45f7d4 | |||
774ebd23f9 | |||
bfdacb1941 | |||
beeb5d34b0 | |||
3d3faba263 | |||
a56795ff79 | |||
00d644ef07 | |||
672de68e56 | |||
e47bc4c04d | |||
0b6a8eecce | |||
eaaea26603 | |||
e1c80c9abc |
23
TODO.md
23
TODO.md
@@ -5,10 +5,10 @@
|
|||||||
- when moby wlan is explicitly set down (via ip link set wlan0 down), /var/lib/trust-dns/dhcp-configs doesn't get reset
|
- 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)
|
- `ip monitor` can detect those manual link state changes (NM-dispatcher it seems cannot)
|
||||||
- or try dnsmasq?
|
- or try dnsmasq?
|
||||||
- trust-dns: can't recursively resolve api.mangadex.org
|
- trust-dns can't resolve `abs.twimg.com`
|
||||||
- nor `m.wikipedia.org` (`dyna.wikipedia.org`)
|
- trust-dns can't resolve `social.kernel.org`
|
||||||
- and *sometimes* apple.com fails
|
|
||||||
- sandbox: link cache means that if i update ~/.config/... files inline, sandboxed programs still see the old version
|
- sandbox: link cache means that if i update ~/.config/... files inline, sandboxed programs still see the old version
|
||||||
|
- mpv: continues to play past the end of some audio files
|
||||||
- mpv: audiocast has mpv sending its output to the builtin speakers unless manually changed
|
- mpv: audiocast has mpv sending its output to the builtin speakers unless manually changed
|
||||||
- mpv: no way to exit fullscreen video on moby
|
- mpv: no way to exit fullscreen video on moby
|
||||||
- uosc hides controls on FS, and touch doesn't support unhiding
|
- uosc hides controls on FS, and touch doesn't support unhiding
|
||||||
@@ -24,16 +24,13 @@
|
|||||||
- `dmesg | grep 'hid_bpf: error while preloading HID BPF dispatcher: -22'`
|
- `dmesg | grep 'hid_bpf: error while preloading HID BPF dispatcher: -22'`
|
||||||
- `s6` is not re-entrant
|
- `s6` is not re-entrant
|
||||||
- so if the desktop crashes, the login process from `unl0kr` fails to re-launch the GUI
|
- so if the desktop crashes, the login process from `unl0kr` fails to re-launch the GUI
|
||||||
- nwg-panel will sometimes create nested bars (happens maybe when i turn an external display off, then on?)
|
|
||||||
- wg-home is unreachable for a couple minutes when switching between LAN/WAN/3G
|
|
||||||
- because the endpoint DNS changes.
|
|
||||||
- causes calls to not transfer from WiFi -> cellular.
|
|
||||||
|
|
||||||
## REFACTORING:
|
## REFACTORING:
|
||||||
- add import checks to my Python nix-shell scripts
|
- add import checks to my Python nix-shell scripts
|
||||||
- consolidate ~/dev and ~/ref
|
- consolidate ~/dev and ~/ref
|
||||||
- ~/dev becomes a link to ~/ref/cat/mine
|
- ~/dev becomes a link to ~/ref/cat/mine
|
||||||
- fold hosts/common/home/ssh.nix -> hosts/common/users/colin.nix
|
- fold hosts/common/home/ssh.nix -> hosts/common/users/colin.nix
|
||||||
|
- don't hardcode IP addresses so much in servo
|
||||||
|
|
||||||
### sops/secrets
|
### sops/secrets
|
||||||
- rework secrets to leverage `sane.fs`
|
- rework secrets to leverage `sane.fs`
|
||||||
@@ -59,6 +56,10 @@
|
|||||||
- then i can tune the kernels for hardening, without duplicating that work 4 times
|
- 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
|
- zfs: replace this with something which doesn't require a custom kernel build
|
||||||
- mpv: add media looping controls (e.g. loop song, loop playlist)
|
- mpv: add media looping controls (e.g. loop song, loop playlist)
|
||||||
|
- curlftpfs: replace with something better
|
||||||
|
- safer (rust? actively maintained? sandboxable?)
|
||||||
|
- handles spaces/symbols in filenames
|
||||||
|
- has better multi-stream perf (e.g. `sane-sync-music` should be able to copy N items in parallel)
|
||||||
|
|
||||||
### security/resilience
|
### security/resilience
|
||||||
- validate duplicity backups!
|
- validate duplicity backups!
|
||||||
@@ -68,6 +69,7 @@
|
|||||||
- 95% of its use is for remote media access and stuff which isn't in VCS (~/records)
|
- 95% of its use is for remote media access and stuff which isn't in VCS (~/records)
|
||||||
- port all sane.programs to be sandboxed
|
- port all sane.programs to be sandboxed
|
||||||
- sandbox `curlftpfs`
|
- sandbox `curlftpfs`
|
||||||
|
- sandbox `nix`
|
||||||
- sandbox `sshfs-fuse`
|
- sandbox `sshfs-fuse`
|
||||||
- enforce that all `environment.packages` has a sandbox profile (or explicitly opts out)
|
- enforce that all `environment.packages` has a sandbox profile (or explicitly opts out)
|
||||||
- revisit "non-sandboxable" apps and check that i'm not actually just missing mountpoints
|
- revisit "non-sandboxable" apps and check that i'm not actually just missing mountpoints
|
||||||
@@ -77,8 +79,6 @@
|
|||||||
- lock down dbus calls within the sandbox
|
- lock down dbus calls within the sandbox
|
||||||
- otherwise anyone can `systemd-run --user ...` to potentially escape a sandbox
|
- otherwise anyone can `systemd-run --user ...` to potentially escape a sandbox
|
||||||
- <https://github.com/flatpak/xdg-dbus-proxy>
|
- <https://github.com/flatpak/xdg-dbus-proxy>
|
||||||
- remove `.ssh` access from Firefox!
|
|
||||||
- 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?)
|
- 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.
|
- it adds like 50-70ms launch time _on my laptop_. i'd hate to know how much that is on the pinephone.
|
||||||
- make dconf stuff less monolithic
|
- make dconf stuff less monolithic
|
||||||
@@ -92,14 +92,13 @@
|
|||||||
- cleanup waybar/nwg-panel so that it's not invoking playerctl every 2 seconds
|
- cleanup waybar/nwg-panel so that it's not invoking playerctl every 2 seconds
|
||||||
- nwg-panel: doesn't know that virtual-desktop 10/TV exists
|
- nwg-panel: doesn't know that virtual-desktop 10/TV exists
|
||||||
- install apps:
|
- install apps:
|
||||||
- compass viewer (moby)
|
|
||||||
- display QR codes for WiFi endpoints: <https://linuxphoneapps.org/apps/noappid.wisperwind.wifi2qr/>
|
- display QR codes for WiFi endpoints: <https://linuxphoneapps.org/apps/noappid.wisperwind.wifi2qr/>
|
||||||
- shopping list (not in nixpkgs): <https://linuxphoneapps.org/apps/ro.hume.cosmin.shoppinglist/>
|
- shopping list (not in nixpkgs): <https://linuxphoneapps.org/apps/ro.hume.cosmin.shoppinglist/>
|
||||||
- offline Wikipedia (or, add to `wike`)
|
- offline Wikipedia (or, add to `wike`)
|
||||||
- offline docs viewer (gtk): <https://github.com/workbenchdev/Biblioteca>
|
- offline docs viewer (gtk): <https://github.com/workbenchdev/Biblioteca>
|
||||||
- some type of games manager/launcher
|
- some type of games manager/launcher
|
||||||
- Gnome Highscore (retro games)?: <https://gitlab.gnome.org/World/highscore>
|
- Gnome Highscore (retro games)?: <https://gitlab.gnome.org/World/highscore>
|
||||||
- better maps for mobile (Osmin (QtQuick)? Pure Maps (Qt/Kirigami)?
|
- better maps for mobile (Osmin (QtQuick)? Pure Maps (Qt/Kirigami)?)
|
||||||
- note-taking app: <https://linuxphoneapps.org/categories/note-taking/>
|
- note-taking app: <https://linuxphoneapps.org/categories/note-taking/>
|
||||||
- Folio is nice, uses standard markdown, though it only supports flat repos
|
- Folio is nice, uses standard markdown, though it only supports flat repos
|
||||||
- OSK overlay specifically for mobile gaming
|
- OSK overlay specifically for mobile gaming
|
||||||
@@ -149,6 +148,8 @@
|
|||||||
- have xdg-open parse `<repo:...> URIs (or adjust them so that it _can_ parse)
|
- have xdg-open parse `<repo:...> URIs (or adjust them so that it _can_ parse)
|
||||||
- sane-bt-search: show details like 5.1 vs stereo, h264 vs h265
|
- sane-bt-search: show details like 5.1 vs stereo, h264 vs h265
|
||||||
- maybe just color these "keywords" in all search results?
|
- maybe just color these "keywords" in all search results?
|
||||||
|
- transmission: apply `sane-tag-media` path fix in `torrent-done` script
|
||||||
|
- many .mkv files do appear to be tagged: i'd just need to add support in my own tooling
|
||||||
- uninsane.org: make URLs relative to allow local use (and as offline homepage)
|
- uninsane.org: make URLs relative to allow local use (and as offline homepage)
|
||||||
- email: fix so that local mail doesn't go to junk
|
- email: fix so that local mail doesn't go to junk
|
||||||
- git sendmail flow adds the DKIM signatures, but gets delivered locally w/o having the sig checked, so goes into Junk
|
- git sendmail flow adds the DKIM signatures, but gets delivered locally w/o having the sig checked, so goes into Junk
|
||||||
|
@@ -10,9 +10,13 @@
|
|||||||
|
|
||||||
# don't enable wifi by default: it messes with connectivity.
|
# don't enable wifi by default: it messes with connectivity.
|
||||||
# systemd.services.iwd.enable = false;
|
# systemd.services.iwd.enable = false;
|
||||||
|
# networking.wireless.enable = false;
|
||||||
# systemd.services.wpa_supplicant.enable = false;
|
# systemd.services.wpa_supplicant.enable = false;
|
||||||
sane.programs.wpa_supplicant.enableFor.user.colin = lib.mkForce false;
|
# sane.programs.wpa_supplicant.enableFor.user.colin = lib.mkForce false;
|
||||||
sane.programs.wpa_supplicant.enableFor.system = lib.mkForce false;
|
# sane.programs.wpa_supplicant.enableFor.system = lib.mkForce false;
|
||||||
|
# don't auto-connect to wifi networks
|
||||||
|
# see: <https://networkmanager.dev/docs/api/latest/NetworkManager.conf.html#device-spec>
|
||||||
|
networking.networkmanager.unmanaged = [ "type:wifi" ];
|
||||||
|
|
||||||
sops.secrets.colin-passwd.neededForUsers = true;
|
sops.secrets.colin-passwd.neededForUsers = true;
|
||||||
|
|
||||||
@@ -25,9 +29,13 @@
|
|||||||
sane.ovpn.addrV4 = "172.26.55.21";
|
sane.ovpn.addrV4 = "172.26.55.21";
|
||||||
# sane.ovpn.addrV6 = "fd00:0000:1337:cafe:1111:1111:20c1:a73c";
|
# sane.ovpn.addrV6 = "fd00:0000:1337:cafe:1111:1111:20c1:a73c";
|
||||||
sane.services.duplicity.enable = true;
|
sane.services.duplicity.enable = true;
|
||||||
|
sane.services.rsync-net.enable = true;
|
||||||
|
|
||||||
sane.nixcache.remote-builders.desko = false;
|
sane.nixcache.remote-builders.desko = false;
|
||||||
|
|
||||||
|
sane.programs.sane-private-unlock-remote.enableFor.user.colin = true;
|
||||||
|
sane.programs.sane-private-unlock-remote.config.hosts = [ "servo" ];
|
||||||
|
|
||||||
sane.programs.sway.enableFor.user.colin = true;
|
sane.programs.sway.enableFor.user.colin = true;
|
||||||
sane.programs.iphoneUtils.enableFor.user.colin = true;
|
sane.programs.iphoneUtils.enableFor.user.colin = true;
|
||||||
sane.programs.steam.enableFor.user.colin = true;
|
sane.programs.steam.enableFor.user.colin = true;
|
||||||
|
@@ -15,6 +15,9 @@
|
|||||||
# sane.guest.enable = true;
|
# sane.guest.enable = true;
|
||||||
sane.image.extraBootFiles = [ pkgs.bootpart-uefi-x86_64 ];
|
sane.image.extraBootFiles = [ pkgs.bootpart-uefi-x86_64 ];
|
||||||
|
|
||||||
|
sane.programs.sane-private-unlock-remote.enableFor.user.colin = true;
|
||||||
|
sane.programs.sane-private-unlock-remote.config.hosts = [ "servo" ];
|
||||||
|
|
||||||
sane.programs.stepmania.enableFor.user.colin = true;
|
sane.programs.stepmania.enableFor.user.colin = true;
|
||||||
sane.programs.sway.enableFor.user.colin = true;
|
sane.programs.sway.enableFor.user.colin = true;
|
||||||
|
|
||||||
@@ -23,6 +26,8 @@
|
|||||||
|
|
||||||
sops.secrets.colin-passwd.neededForUsers = true;
|
sops.secrets.colin-passwd.neededForUsers = true;
|
||||||
|
|
||||||
|
sane.services.rsync-net.enable = true;
|
||||||
|
|
||||||
# default config: https://man.archlinux.org/man/snapper-configs.5
|
# default config: https://man.archlinux.org/man/snapper-configs.5
|
||||||
# defaults to something like:
|
# defaults to something like:
|
||||||
# - hourly snapshots
|
# - hourly snapshots
|
||||||
|
@@ -23,10 +23,11 @@
|
|||||||
# XXX colin: phosh doesn't work well with passwordless login,
|
# XXX colin: phosh doesn't work well with passwordless login,
|
||||||
# so set this more reliable default password should anything go wrong
|
# so set this more reliable default password should anything go wrong
|
||||||
users.users.colin.initialPassword = "147147";
|
users.users.colin.initialPassword = "147147";
|
||||||
# services.getty.autologinUser = "root"; # allows for emergency maintenance?
|
|
||||||
|
|
||||||
sops.secrets.colin-passwd.neededForUsers = true;
|
sops.secrets.colin-passwd.neededForUsers = true;
|
||||||
|
|
||||||
|
sane.services.rsync-net.enable = true;
|
||||||
|
|
||||||
sane.programs.sway.enableFor.user.colin = true;
|
sane.programs.sway.enableFor.user.colin = true;
|
||||||
sane.programs.sway.config.mod = "Mod1"; #< alt key instead of Super
|
sane.programs.sway.config.mod = "Mod1"; #< alt key instead of Super
|
||||||
sane.programs.blueberry.enableFor.user.colin = false; # bluetooth manager: doesn't cross compile!
|
sane.programs.blueberry.enableFor.user.colin = false; # bluetooth manager: doesn't cross compile!
|
||||||
|
@@ -14,7 +14,7 @@
|
|||||||
# sane.programs.matrix-synapse.enableFor.user.colin = true;
|
# sane.programs.matrix-synapse.enableFor.user.colin = true;
|
||||||
|
|
||||||
sane.roles.build-machine.enable = true;
|
sane.roles.build-machine.enable = true;
|
||||||
sane.programs.zsh.config.showDeadlines = false; # ~/knowledge doesn't always exist
|
sane.programs.sane-deadlines.config.showOnLogin = false; # ~/knowledge doesn't always exist
|
||||||
sane.programs.consoleUtils.suggestedPrograms = [
|
sane.programs.consoleUtils.suggestedPrograms = [
|
||||||
"consoleMediaUtils" # notably, for go2tv / casting
|
"consoleMediaUtils" # notably, for go2tv / casting
|
||||||
"pcConsoleUtils"
|
"pcConsoleUtils"
|
||||||
@@ -32,10 +32,12 @@
|
|||||||
sane.nixcache.remote-builders.desko = false;
|
sane.nixcache.remote-builders.desko = false;
|
||||||
sane.nixcache.remote-builders.servo = false;
|
sane.nixcache.remote-builders.servo = false;
|
||||||
# sane.services.duplicity.enable = true; # TODO: re-enable after HW upgrade
|
# sane.services.duplicity.enable = true; # TODO: re-enable after HW upgrade
|
||||||
|
sane.services.rsync-net.enable = true;
|
||||||
|
|
||||||
# automatically log in at the virtual consoles.
|
# automatically log in at the virtual consoles.
|
||||||
# using root here makes sure we always have an escape hatch
|
# using root here makes sure we always have an escape hatch.
|
||||||
services.getty.autologinUser = "root";
|
# XXX(2024-07-27): this is incompatible with my s6-rc stuff, which needs to auto-login as `colin` to start its user services.
|
||||||
|
# services.getty.autologinUser = "root";
|
||||||
|
|
||||||
sane.image.extraBootFiles = [ pkgs.bootpart-uefi-x86_64 ];
|
sane.image.extraBootFiles = [ pkgs.bootpart-uefi-x86_64 ];
|
||||||
|
|
||||||
|
@@ -14,7 +14,7 @@
|
|||||||
# show zfs datasets: `zfs list` (will be empty if haven't imported)
|
# show zfs datasets: `zfs list` (will be empty if haven't imported)
|
||||||
# show zfs properties (e.g. compression): `zfs get all pool`
|
# show zfs properties (e.g. compression): `zfs get all pool`
|
||||||
# set zfs properties: `zfs set compression=on pool`
|
# set zfs properties: `zfs set compression=on pool`
|
||||||
{ ... }:
|
{ lib, pkgs, ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
# hostId: not used for anything except zfs guardrail?
|
# hostId: not used for anything except zfs guardrail?
|
||||||
@@ -131,6 +131,20 @@
|
|||||||
the contents should be a subset of what's in ../media/datasets.
|
the contents should be a subset of what's in ../media/datasets.
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
systemd.services.dedupe-media = {
|
||||||
|
description = "transparently de-duplicate /var/media entries by using block-level hardlinks";
|
||||||
|
script = ''
|
||||||
|
${lib.getExe' pkgs.util-linux "hardlink"} /var/media --reflink=always --ignore-time --verbose
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
systemd.timers.dedupe-media = {
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
timerConfig = {
|
||||||
|
OnStartupSec = "23min";
|
||||||
|
OnUnitActiveSec = "720min";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
# btrfs doesn't easily support swapfiles
|
# btrfs doesn't easily support swapfiles
|
||||||
# swapDevices = [
|
# swapDevices = [
|
||||||
# { device = "/nix/persist/swapfile"; size = 4096; }
|
# { device = "/nix/persist/swapfile"; size = 4096; }
|
||||||
|
@@ -30,6 +30,14 @@ in
|
|||||||
|
|
||||||
config = {
|
config = {
|
||||||
networking.domain = "uninsane.org";
|
networking.domain = "uninsane.org";
|
||||||
|
systemd.network.networks."50-eth0" = {
|
||||||
|
matchConfig.Name = "eth0";
|
||||||
|
networkConfig.Address = [
|
||||||
|
"205.201.63.12/32"
|
||||||
|
"10.78.79.51/22"
|
||||||
|
];
|
||||||
|
networkConfig.DNS = [ "10.78.79.1" ];
|
||||||
|
};
|
||||||
|
|
||||||
sane.ports.openFirewall = true;
|
sane.ports.openFirewall = true;
|
||||||
sane.ports.openUpnp = true;
|
sane.ports.openUpnp = true;
|
||||||
|
@@ -20,6 +20,7 @@ let
|
|||||||
bitcoind = pkgs.bitcoind;
|
bitcoind = pkgs.bitcoind;
|
||||||
# wrapper to run bitcoind with the tor onion address as externalip (computed at runtime)
|
# wrapper to run bitcoind with the tor onion address as externalip (computed at runtime)
|
||||||
_bitcoindWithExternalIp = pkgs.writeShellScriptBin "bitcoind" ''
|
_bitcoindWithExternalIp = pkgs.writeShellScriptBin "bitcoind" ''
|
||||||
|
set -xeu
|
||||||
externalip="$(cat /var/lib/tor/onion/bitcoind/hostname)"
|
externalip="$(cat /var/lib/tor/onion/bitcoind/hostname)"
|
||||||
exec ${bitcoind}/bin/bitcoind "-externalip=$externalip" "$@"
|
exec ${bitcoind}/bin/bitcoind "-externalip=$externalip" "$@"
|
||||||
'';
|
'';
|
||||||
@@ -63,23 +64,62 @@ in
|
|||||||
passwordHMAC = "30002c05d82daa210550e17a182db3f3$6071444151281e1aa8a2729f75e3e2d224e9d7cac3974810dab60e7c28ffaae4";
|
passwordHMAC = "30002c05d82daa210550e17a182db3f3$6071444151281e1aa8a2729f75e3e2d224e9d7cac3974810dab60e7c28ffaae4";
|
||||||
};
|
};
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
|
# checkblocks: default 6: how many blocks to verify on start
|
||||||
|
checkblocks=3
|
||||||
# don't load the wallet, and disable wallet RPC calls
|
# don't load the wallet, and disable wallet RPC calls
|
||||||
disablewallet=1
|
disablewallet=1
|
||||||
# proxy all outbound traffic through Tor
|
# proxy all outbound traffic through Tor
|
||||||
proxy=127.0.0.1:9050
|
proxy=127.0.0.1:9050
|
||||||
'';
|
'';
|
||||||
|
extraCmdlineOptions = [
|
||||||
|
# "-debug"
|
||||||
|
# "-debug=estimatefee"
|
||||||
|
# "-debug=http"
|
||||||
|
# "-debug=net"
|
||||||
|
"-debug=proxy"
|
||||||
|
"-debug=rpc"
|
||||||
|
# "-debug=validation"
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
users.users.bitcoind-mainnet.extraGroups = [ "tor" ];
|
users.users.bitcoind-mainnet.extraGroups = [ "tor" ];
|
||||||
|
|
||||||
systemd.services.bitcoind-mainnet.serviceConfig.RestartSec = "30s"; #< default is 0
|
systemd.services.bitcoind-mainnet = {
|
||||||
|
after = [ "tor.service" ];
|
||||||
|
requires = [ "tor.service" ];
|
||||||
|
serviceConfig.RestartSec = "30s"; #< default is 0
|
||||||
|
|
||||||
|
# hardening (systemd-analyze security bitcoind-mainnet)
|
||||||
|
serviceConfig.StateDirectory = "bitcoind-mainnet";
|
||||||
|
serviceConfig.LockPersonality = true;
|
||||||
|
serviceConfig.MemoryDenyWriteExecute = "true";
|
||||||
|
serviceConfig.NoNewPrivileges = "true";
|
||||||
|
serviceConfig.PrivateDevices = "true";
|
||||||
|
serviceConfig.PrivateMounts = true;
|
||||||
|
serviceConfig.PrivateTmp = "true";
|
||||||
|
serviceConfig.PrivateUsers = true;
|
||||||
|
serviceConfig.ProcSubset = "pid";
|
||||||
|
serviceConfig.ProtectControlGroups = true;
|
||||||
|
serviceConfig.ProtectHome = true;
|
||||||
|
serviceConfig.ProtectHostname = true;
|
||||||
|
serviceConfig.ProtectKernelLogs = true;
|
||||||
|
serviceConfig.ProtectKernelModules = true;
|
||||||
|
serviceConfig.ProtectKernelTunables = true;
|
||||||
|
serviceConfig.ProtectProc = "invisible";
|
||||||
|
serviceConfig.ProtectSystem = lib.mkForce "strict";
|
||||||
|
serviceConfig.RemoveIPC = true;
|
||||||
|
serviceConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6";
|
||||||
|
serviceConfig.RestrictNamespaces = true;
|
||||||
|
serviceConfig.RestrictSUIDSGID = true;
|
||||||
|
serviceConfig.SystemCallArchitectures = "native";
|
||||||
|
serviceConfig.SystemCallFilter = [ "@system-service" ];
|
||||||
|
};
|
||||||
|
|
||||||
sane.users.colin.fs.".bitcoin/bitcoin.conf" = sane-lib.fs.wantedSymlinkTo config.sops.secrets."bitcoin.conf".path;
|
|
||||||
sops.secrets."bitcoin.conf" = {
|
sops.secrets."bitcoin.conf" = {
|
||||||
mode = "0600";
|
mode = "0600";
|
||||||
owner = "colin";
|
owner = "colin";
|
||||||
group = "users";
|
group = "users";
|
||||||
};
|
};
|
||||||
|
|
||||||
sane.programs.bitcoind.enableFor.user.colin = true; # for debugging/administration: `bitcoin-cli`
|
sane.programs.bitcoin-cli.enableFor.user.colin = true; # for debugging/administration: `bitcoin-cli`
|
||||||
}
|
}
|
||||||
|
@@ -72,13 +72,11 @@
|
|||||||
|
|
||||||
{ config, pkgs, ... }:
|
{ config, pkgs, ... }:
|
||||||
{
|
{
|
||||||
sane.persist.sys.byStore.ext = [
|
sane.persist.sys.byStore.private = [
|
||||||
|
# clightning takes up only a few MB. but then several hundred MB of crash logs that i should probably GC.
|
||||||
{ user = "clightning"; group = "clightning"; mode = "0710"; path = "/var/lib/clightning"; method = "bind"; }
|
{ user = "clightning"; group = "clightning"; mode = "0710"; path = "/var/lib/clightning"; method = "bind"; }
|
||||||
];
|
];
|
||||||
|
|
||||||
# `lightning-cli` finds its RPC file via `~/.lightning/bitcoin/lightning-rpc`, to message the daemon
|
|
||||||
sane.user.fs.".lightning".symlink.target = "/var/lib/clightning";
|
|
||||||
|
|
||||||
# see bitcoin.nix for how to generate this
|
# see bitcoin.nix for how to generate this
|
||||||
services.bitcoind.mainnet.rpc.users.clightning.passwordHMAC =
|
services.bitcoind.mainnet.rpc.users.clightning.passwordHMAC =
|
||||||
"befcb82d9821049164db5217beb85439$2c31ac7db3124612e43893ae13b9527dbe464ab2d992e814602e7cb07dc28985";
|
"befcb82d9821049164db5217beb85439$2c31ac7db3124612e43893ae13b9527dbe464ab2d992e814602e7cb07dc28985";
|
||||||
@@ -105,6 +103,7 @@
|
|||||||
users.users.clightning.extraGroups = [ "tor" ];
|
users.users.clightning.extraGroups = [ "tor" ];
|
||||||
|
|
||||||
systemd.services.clightning.after = [ "tor.service" ];
|
systemd.services.clightning.after = [ "tor.service" ];
|
||||||
|
systemd.services.clightning.requires = [ "tor.service" ];
|
||||||
|
|
||||||
# lightning-config contains fields from here:
|
# lightning-config contains fields from here:
|
||||||
# - <https://docs.corelightning.org/docs/configuration>
|
# - <https://docs.corelightning.org/docs/configuration>
|
||||||
@@ -117,13 +116,15 @@
|
|||||||
# - feature configs (i.e. experimental-xyz options)
|
# - feature configs (i.e. experimental-xyz options)
|
||||||
sane.services.clightning.extraConfig = ''
|
sane.services.clightning.extraConfig = ''
|
||||||
# log levels: "io", "debug", "info", "unusual", "broken"
|
# log levels: "io", "debug", "info", "unusual", "broken"
|
||||||
log-level=info:lightningd
|
log-level=info
|
||||||
|
# log-level=info:lightningd
|
||||||
# log-level=debug:lightningd
|
# log-level=debug:lightningd
|
||||||
|
# log-level=debug
|
||||||
|
|
||||||
# peerswap:
|
# peerswap:
|
||||||
# - config example: <https://github.com/fort-nix/nix-bitcoin/pull/462/files#diff-b357d832705b8ce8df1f41934d613f79adb77c4cd5cd9e9eb12a163fca3e16c6>
|
# - config example: <https://github.com/fort-nix/nix-bitcoin/pull/462/files#diff-b357d832705b8ce8df1f41934d613f79adb77c4cd5cd9e9eb12a163fca3e16c6>
|
||||||
# XXX: peerswap crashes clightning on launch. stacktrace is useless.
|
# XXX: peerswap crashes clightning on launch. stacktrace is useless.
|
||||||
# plugin=${pkgs.peerswap}/bin/peerswap
|
# plugin={pkgs.peerswap}/bin/peerswap
|
||||||
# peerswap-db-path=/var/lib/clightning/peerswap/swaps
|
# peerswap-db-path=/var/lib/clightning/peerswap/swaps
|
||||||
# peerswap-policy-path=...
|
# peerswap-policy-path=...
|
||||||
'';
|
'';
|
||||||
@@ -134,6 +135,5 @@
|
|||||||
group = "clightning";
|
group = "clightning";
|
||||||
};
|
};
|
||||||
|
|
||||||
sane.programs.clightning.enableFor.user.colin = true; # for debugging/admin: `lightning-cli`
|
sane.programs.lightning-cli.enableFor.user.colin = true; # for debugging/admin:
|
||||||
sane.programs.clightning.packageUnwrapped = config.sane.services.clightning.package;
|
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
{ ... }:
|
{ lib, ... }:
|
||||||
|
lib.mkIf false #< 2024/07/27: i don't use it, too much surface-area for me to run it pro-bono (`systemd-analyze security monero`)
|
||||||
{
|
{
|
||||||
services.i2p.enable = true;
|
services.i2p.enable = true;
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
# as of 2023/11/26: complete downloaded blockchain should be 200GiB on disk, give or take.
|
# as of 2023/11/26: complete downloaded blockchain should be 200GiB on disk, give or take.
|
||||||
{ ... }:
|
{ lib, ... }:
|
||||||
|
lib.mkIf false #< 2024/07/27: i don't use it, too much surface-area for me to run it pro-bono (`systemd-analyze security monero`)
|
||||||
{
|
{
|
||||||
sane.persist.sys.byStore.ext = [
|
sane.persist.sys.byStore.ext = [
|
||||||
# /var/lib/monero/lmdb is what consumes most of the space
|
# /var/lib/monero/lmdb is what consumes most of the space
|
||||||
|
@@ -1,10 +1,10 @@
|
|||||||
# tor settings: <https://2019.www.torproject.org/docs/tor-manual.html.en>
|
# tor settings: <https://2019.www.torproject.org/docs/tor-manual.html.en>
|
||||||
{ lib, ... }:
|
{ lib, ... }:
|
||||||
{
|
{
|
||||||
# tor hidden service hostnames aren't deterministic, so persist.
|
sane.persist.sys.byStore.ephemeral = [
|
||||||
# might be able to get away with just persisting /var/lib/tor/onion, not sure.
|
# N.B.: tor hidden service hostnames aren't deterministic, so if you need them
|
||||||
sane.persist.sys.byStore.plaintext = [
|
# to be preserved across reboots then persist /var/lib/tor/onion in "private" store.
|
||||||
{ user = "tor"; group = "tor"; mode = "0710"; path = "/var/lib/tor"; method = "bind"; }
|
{ user = "tor"; group = "tor"; mode = "0710"; path = "/var/lib/tor"; method = "bind"; }
|
||||||
];
|
];
|
||||||
|
|
||||||
# tor: `tor.enable` doesn't start a relay, exit node, proxy, etc. it's minimal.
|
# tor: `tor.enable` doesn't start a relay, exit node, proxy, etc. it's minimal.
|
||||||
|
@@ -10,7 +10,7 @@
|
|||||||
./gitea.nix
|
./gitea.nix
|
||||||
./goaccess.nix
|
./goaccess.nix
|
||||||
./ipfs.nix
|
./ipfs.nix
|
||||||
./jackett.nix
|
./jackett
|
||||||
./jellyfin.nix
|
./jellyfin.nix
|
||||||
./kiwix-serve.nix
|
./kiwix-serve.nix
|
||||||
./komga.nix
|
./komga.nix
|
||||||
|
@@ -44,7 +44,7 @@ in
|
|||||||
# everything configured below was fine: used ejabberd for several months.
|
# everything configured below was fine: used ejabberd for several months.
|
||||||
lib.mkIf false
|
lib.mkIf false
|
||||||
{
|
{
|
||||||
sane.persist.sys.byStore.plaintext = [
|
sane.persist.sys.byStore.private = [
|
||||||
{ user = "ejabberd"; group = "ejabberd"; path = "/var/lib/ejabberd"; method = "bind"; }
|
{ user = "ejabberd"; group = "ejabberd"; path = "/var/lib/ejabberd"; method = "bind"; }
|
||||||
];
|
];
|
||||||
sane.ports.ports = lib.mkMerge ([
|
sane.ports.ports = lib.mkMerge ([
|
||||||
|
@@ -83,8 +83,8 @@
|
|||||||
# sieve_plugins = sieve_imapsieve
|
# sieve_plugins = sieve_imapsieve
|
||||||
# }
|
# }
|
||||||
|
|
||||||
mail_debug = yes
|
# mail_debug = yes
|
||||||
auth_debug = yes
|
# auth_debug = yes
|
||||||
# verbose_ssl = yes
|
# verbose_ssl = yes
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
@@ -18,10 +18,10 @@ let
|
|||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
sane.persist.sys.byStore.plaintext = [
|
sane.persist.sys.byStore.private = [
|
||||||
# TODO: mode? could be more granular
|
# TODO: mode? could be more granular
|
||||||
{ user = "opendkim"; group = "opendkim"; path = "/var/lib/opendkim"; method = "bind"; }
|
{ user = "opendkim"; group = "opendkim"; path = "/var/lib/opendkim"; method = "bind"; }
|
||||||
{ user = "root"; group = "root"; path = "/var/lib/postfix"; method = "bind"; }
|
{ user = "root"; group = "root"; path = "/var/lib/postfix"; method = "bind"; } #< probably not *all* of postfix needs to actually be persisted (e.g. not the conf dir)
|
||||||
{ user = "root"; group = "root"; path = "/var/spool/mail"; method = "bind"; }
|
{ user = "root"; group = "root"; path = "/var/spool/mail"; method = "bind"; }
|
||||||
# *probably* don't need these dirs:
|
# *probably* don't need these dirs:
|
||||||
# "/var/lib/dhparams" # https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/security/dhparams.nix
|
# "/var/lib/dhparams" # https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/security/dhparams.nix
|
||||||
|
@@ -12,10 +12,6 @@
|
|||||||
device = "/var/media";
|
device = "/var/media";
|
||||||
options = [ "rbind" ];
|
options = [ "rbind" ];
|
||||||
};
|
};
|
||||||
fileSystems."/var/export/pub" = {
|
|
||||||
device = "/var/www/sites/uninsane.org/share";
|
|
||||||
options = [ "rbind" ];
|
|
||||||
};
|
|
||||||
# fileSystems."/var/export/playground" = {
|
# fileSystems."/var/export/playground" = {
|
||||||
# device = config.fileSystems."/mnt/persist/ext".device;
|
# device = config.fileSystems."/mnt/persist/ext".device;
|
||||||
# fsType = "btrfs";
|
# fsType = "btrfs";
|
||||||
@@ -55,4 +51,11 @@
|
|||||||
- be a friendly troll
|
- be a friendly troll
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
sane.fs."/var/export/.public_for_test/test" = {
|
||||||
|
wantedBy = [ "nfs.service" "sftpgo.service" ];
|
||||||
|
file.text = ''
|
||||||
|
automated tests read this file to probe connectivity
|
||||||
|
'';
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@@ -80,12 +80,6 @@ in
|
|||||||
port = 21;
|
port = 21;
|
||||||
debug = true;
|
debug = true;
|
||||||
}
|
}
|
||||||
{
|
|
||||||
# binding this means any LAN client can connect (also WAN traffic forwarded from the gateway)
|
|
||||||
address = "10.78.79.51";
|
|
||||||
port = 21;
|
|
||||||
debug = true;
|
|
||||||
}
|
|
||||||
{
|
{
|
||||||
# binding this means any wireguard client can connect
|
# binding this means any wireguard client can connect
|
||||||
address = "10.0.10.5";
|
address = "10.0.10.5";
|
||||||
@@ -93,6 +87,12 @@ in
|
|||||||
debug = true;
|
debug = true;
|
||||||
tls_mode = 2; # 2 = "implicit FTPS": client negotiates TLS before any FTP command.
|
tls_mode = 2; # 2 = "implicit FTPS": client negotiates TLS before any FTP command.
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
# binding this means any LAN client can connect (also WAN traffic forwarded from the gateway)
|
||||||
|
address = "10.78.79.51";
|
||||||
|
port = 21;
|
||||||
|
debug = true;
|
||||||
|
}
|
||||||
{
|
{
|
||||||
# binding this means any LAN client can connect (also WAN traffic forwarded from the gateway)
|
# binding this means any LAN client can connect (also WAN traffic forwarded from the gateway)
|
||||||
address = "10.78.79.51";
|
address = "10.78.79.51";
|
||||||
@@ -107,6 +107,13 @@ in
|
|||||||
debug = true;
|
debug = true;
|
||||||
tls_mode = 2; # 2 = "implicit FTPS": client negotiates TLS before any FTP command.
|
tls_mode = 2; # 2 = "implicit FTPS": client negotiates TLS before any FTP command.
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
# binding this means any LAN client can connect via `ftp.uninsane.org` (TLS only)
|
||||||
|
address = config.sane.netns.doof.netnsPubIpv4;
|
||||||
|
port = 990;
|
||||||
|
debug = true;
|
||||||
|
tls_mode = 2; # 2 = "implicit FTPS": client negotiates TLS before any FTP command.
|
||||||
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
# active mode is susceptible to "bounce attacks", without much benefit over passive mode
|
# active mode is susceptible to "bounce attacks", without much benefit over passive mode
|
||||||
|
@@ -129,14 +129,14 @@ def getAuthResponse(ip: str, username: str, password: str) -> dict:
|
|||||||
return mkAuthOk(username, permissions = {
|
return mkAuthOk(username, permissions = {
|
||||||
"/": PERM_RW,
|
"/": PERM_RW,
|
||||||
"/playground": PERM_RW,
|
"/playground": PERM_RW,
|
||||||
"/pub": PERM_RO,
|
"/.public_for_test": PERM_RO,
|
||||||
})
|
})
|
||||||
if isWireguard(ip):
|
if isWireguard(ip):
|
||||||
# allow any user from wireguard
|
# allow any user from wireguard
|
||||||
return mkAuthOk(username, permissions = {
|
return mkAuthOk(username, permissions = {
|
||||||
"/": PERM_RW,
|
"/": PERM_RW,
|
||||||
"/playground": PERM_RW,
|
"/playground": PERM_RW,
|
||||||
"/pub": PERM_RO,
|
"/.public_for_test": PERM_RO,
|
||||||
})
|
})
|
||||||
if isLan(ip):
|
if isLan(ip):
|
||||||
if username == "anonymous":
|
if username == "anonymous":
|
||||||
@@ -144,7 +144,7 @@ def getAuthResponse(ip: str, username: str, password: str) -> dict:
|
|||||||
return mkAuthOk("anonymous", permissions = {
|
return mkAuthOk("anonymous", permissions = {
|
||||||
"/": PERM_RO,
|
"/": PERM_RO,
|
||||||
"/playground": PERM_RW,
|
"/playground": PERM_RW,
|
||||||
"/pub": PERM_RO,
|
"/.public_for_test": PERM_RO,
|
||||||
})
|
})
|
||||||
if username == "anonymous":
|
if username == "anonymous":
|
||||||
# anonymous users from the www can have even more limited access.
|
# anonymous users from the www can have even more limited access.
|
||||||
@@ -154,7 +154,7 @@ def getAuthResponse(ip: str, username: str, password: str) -> dict:
|
|||||||
"/": PERM_LIST, #< REQUIRED, even for lftp to list a subdir
|
"/": PERM_LIST, #< REQUIRED, even for lftp to list a subdir
|
||||||
"/media": PERM_DENY,
|
"/media": PERM_DENY,
|
||||||
"/playground": PERM_DENY,
|
"/playground": PERM_DENY,
|
||||||
"/pub": PERM_RO,
|
"/.public_for_test": PERM_RO,
|
||||||
# "/README.md": PERM_RO, #< does not work
|
# "/README.md": PERM_RO, #< does not work
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@@ -2,9 +2,8 @@
|
|||||||
{ config, pkgs, lib, ... }:
|
{ config, pkgs, lib, ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
sane.persist.sys.byStore.plaintext = [
|
sane.persist.sys.byStore.private = [
|
||||||
# TODO: mode? could be more granular
|
{ user = "git"; group = "gitea"; mode = "0750"; path = "/var/lib/gitea"; method = "bind"; }
|
||||||
{ user = "git"; group = "gitea"; path = "/var/lib/gitea"; method = "bind"; }
|
|
||||||
];
|
];
|
||||||
services.gitea.enable = true;
|
services.gitea.enable = true;
|
||||||
services.gitea.user = "git"; # default is 'gitea'
|
services.gitea.user = "git"; # default is 'gitea'
|
||||||
@@ -109,6 +108,10 @@
|
|||||||
locations."/" = {
|
locations."/" = {
|
||||||
proxyPass = "http://127.0.0.1:3000";
|
proxyPass = "http://127.0.0.1:3000";
|
||||||
};
|
};
|
||||||
|
# fuck you @anthropic
|
||||||
|
locations."= /robots.txt".extraConfig = ''
|
||||||
|
return 200 "User-agent: *\nDisallow: /\n";
|
||||||
|
'';
|
||||||
# gitea serves all `raw` files as content-type: plain, but i'd like to serve them as their actual content type.
|
# gitea serves all `raw` files as content-type: plain, but i'd like to serve them as their actual content type.
|
||||||
# or at least, enough to make specific pages viewable (serving unoriginal content as arbitrary content type is dangerous).
|
# or at least, enough to make specific pages viewable (serving unoriginal content as arbitrary content type is dangerous).
|
||||||
locations."~ ^/colin/phone-case-cq/raw/.*.html" = {
|
locations."~ ^/colin/phone-case-cq/raw/.*.html" = {
|
||||||
|
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
lib.mkIf false # i don't actively use ipfs anymore
|
lib.mkIf false # i don't actively use ipfs anymore
|
||||||
{
|
{
|
||||||
sane.persist.sys.byStore.plaintext = [
|
sane.persist.sys.byStore.private = [
|
||||||
# TODO: mode? could be more granular
|
# TODO: mode? could be more granular
|
||||||
{ user = "261"; group = "261"; path = "/var/lib/ipfs"; method = "bind"; }
|
{ user = "261"; group = "261"; path = "/var/lib/ipfs"; method = "bind"; }
|
||||||
];
|
];
|
||||||
|
@@ -1,34 +0,0 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
|
||||||
|
|
||||||
{
|
|
||||||
sane.persist.sys.byStore.plaintext = [
|
|
||||||
# TODO: mode? we only need this to save Indexer creds ==> migrate to config?
|
|
||||||
{ user = "root"; group = "root"; path = "/var/lib/jackett"; method = "bind"; }
|
|
||||||
];
|
|
||||||
services.jackett.enable = true;
|
|
||||||
|
|
||||||
systemd.services.jackett.after = [ "wireguard-wg-ovpns.service" ];
|
|
||||||
systemd.services.jackett.partOf = [ "wireguard-wg-ovpns.service" ];
|
|
||||||
systemd.services.jackett.serviceConfig = {
|
|
||||||
# run this behind the OVPN static VPN
|
|
||||||
NetworkNamespacePath = "/run/netns/ovpns";
|
|
||||||
ExecStartPre = [ "${lib.getExe pkgs.sane-scripts.ip-check} --no-upnp --expect ${config.sane.netns.ovpns.netnsPubIpv4}" ]; # abort if public IP is not as expected
|
|
||||||
|
|
||||||
# patch jackett to listen on the public interfaces
|
|
||||||
# ExecStart = lib.mkForce "${pkgs.jackett}/bin/Jackett --NoUpdates --DataFolder /var/lib/jackett/.config/Jackett --ListenPublic";
|
|
||||||
};
|
|
||||||
|
|
||||||
# jackett torrent search
|
|
||||||
services.nginx.virtualHosts."jackett.uninsane.org" = {
|
|
||||||
forceSSL = true;
|
|
||||||
enableACME = true;
|
|
||||||
# inherit kTLS;
|
|
||||||
locations."/" = {
|
|
||||||
proxyPass = "http://${config.sane.netns.ovpns.netnsVethIpv4}:9117";
|
|
||||||
recommendedProxySettings = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
sane.dns.zones."uninsane.org".inet.CNAME."jackett" = "native";
|
|
||||||
}
|
|
||||||
|
|
68
hosts/by-name/servo/services/jackett/default.nix
Normal file
68
hosts/by-name/servo/services/jackett/default.nix
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.services.jackett;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
sane.persist.sys.byStore.private = [
|
||||||
|
# TODO: mode? we only need this to save Indexer creds ==> migrate to config?
|
||||||
|
{ user = "jackett"; group = "jackett"; path = "/var/lib/jackett"; method = "bind"; }
|
||||||
|
];
|
||||||
|
services.jackett.enable = true;
|
||||||
|
|
||||||
|
systemd.services.jackett.after = [ "wireguard-wg-ovpns.service" ];
|
||||||
|
systemd.services.jackett.partOf = [ "wireguard-wg-ovpns.service" ];
|
||||||
|
systemd.services.jackett = {
|
||||||
|
# run this behind the OVPN static VPN
|
||||||
|
serviceConfig.NetworkNamespacePath = "/run/netns/ovpns";
|
||||||
|
serviceConfig.ExecStartPre = [ "${lib.getExe pkgs.sane-scripts.ip-check} --no-upnp --expect ${config.sane.netns.ovpns.netnsPubIpv4}" ]; # abort if public IP is not as expected
|
||||||
|
# patch in `--ListenPublic` so that it's reachable from the netns veth.
|
||||||
|
# this also makes it reachable from the VPN pub address. oh well.
|
||||||
|
serviceConfig.ExecStart = lib.mkForce "${cfg.package}/bin/Jackett --ListenPublic --NoUpdates --DataFolder '${cfg.dataDir}'";
|
||||||
|
serviceConfig.RestartSec = "30s";
|
||||||
|
|
||||||
|
# hardening (systemd-analyze security jackett)
|
||||||
|
# TODO: upstream into nixpkgs
|
||||||
|
serviceConfig.StateDirectory = "jackett";
|
||||||
|
serviceConfig.LockPersonality = true;
|
||||||
|
serviceConfig.NoNewPrivileges = true;
|
||||||
|
# serviceConfig.MemoryDenyWriteExecute = true; #< Failed to create CoreCLR, HRESULT: 0x80004005
|
||||||
|
serviceConfig.PrivateDevices = true;
|
||||||
|
serviceConfig.PrivateMounts = true;
|
||||||
|
serviceConfig.PrivateTmp = true;
|
||||||
|
serviceConfig.PrivateUsers = true;
|
||||||
|
serviceConfig.ProcSubset = "pid";
|
||||||
|
serviceConfig.ProtectClock = true;
|
||||||
|
serviceConfig.ProtectControlGroups = true;
|
||||||
|
serviceConfig.ProtectHome = true;
|
||||||
|
serviceConfig.ProtectHostname = true;
|
||||||
|
serviceConfig.ProtectKernelLogs = true;
|
||||||
|
serviceConfig.ProtectKernelModules = true;
|
||||||
|
serviceConfig.ProtectKernelTunables = true;
|
||||||
|
serviceConfig.ProtectProc = "invisible";
|
||||||
|
serviceConfig.ProtectSystem = "strict";
|
||||||
|
serviceConfig.RemoveIPC = true;
|
||||||
|
serviceConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6";
|
||||||
|
serviceConfig.RestrictNamespaces = true;
|
||||||
|
serviceConfig.RestrictSUIDSGID = true;
|
||||||
|
serviceConfig.SystemCallArchitectures = "native";
|
||||||
|
serviceConfig.SystemCallFilter = [ "@system-service" "~@privileged" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
# jackett torrent search
|
||||||
|
services.nginx.virtualHosts."jackett.uninsane.org" = {
|
||||||
|
forceSSL = true;
|
||||||
|
enableACME = true;
|
||||||
|
# inherit kTLS;
|
||||||
|
locations."/" = {
|
||||||
|
proxyPass = "http://${config.sane.netns.ovpns.netnsVethIpv4}:9117";
|
||||||
|
recommendedProxySettings = true;
|
||||||
|
};
|
||||||
|
locations."= /robots.txt".extraConfig = ''
|
||||||
|
return 200 "User-agent: *\nDisallow: /\n";
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
sane.dns.zones."uninsane.org".inet.CNAME."jackett" = "native";
|
||||||
|
}
|
||||||
|
|
@@ -21,6 +21,9 @@
|
|||||||
enableACME = true;
|
enableACME = true;
|
||||||
# inherit kTLS;
|
# inherit kTLS;
|
||||||
locations."/".proxyPass = "http://127.0.0.1:8013";
|
locations."/".proxyPass = "http://127.0.0.1:8013";
|
||||||
|
locations."= /robots.txt".extraConfig = ''
|
||||||
|
return 200 "User-agent: *\nDisallow: /\n";
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
sane.dns.zones."uninsane.org".inet.CNAME."w" = "native";
|
sane.dns.zones."uninsane.org".inet.CNAME."w" = "native";
|
||||||
|
@@ -17,6 +17,9 @@ in
|
|||||||
locations."/" = {
|
locations."/" = {
|
||||||
proxyPass = "http://127.0.0.1:${builtins.toString port}";
|
proxyPass = "http://127.0.0.1:${builtins.toString port}";
|
||||||
};
|
};
|
||||||
|
locations."= /robots.txt".extraConfig = ''
|
||||||
|
return 200 "User-agent: *\nDisallow: /\n";
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
sane.dns.zones."uninsane.org".inet.CNAME."komga" = "native";
|
sane.dns.zones."uninsane.org".inet.CNAME."komga" = "native";
|
||||||
}
|
}
|
||||||
|
@@ -38,15 +38,10 @@ in {
|
|||||||
nginx.enable = true;
|
nginx.enable = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.services.lemmy.serviceConfig = {
|
|
||||||
# fix to use a normal user so we can configure perms correctly
|
|
||||||
DynamicUser = mkForce false;
|
|
||||||
User = "lemmy";
|
|
||||||
Group = "lemmy";
|
|
||||||
};
|
|
||||||
systemd.services.lemmy.environment = {
|
systemd.services.lemmy.environment = {
|
||||||
RUST_BACKTRACE = "full";
|
RUST_BACKTRACE = "full";
|
||||||
RUST_LOG = "warn";
|
RUST_LOG = "error";
|
||||||
|
# RUST_LOG = "warn";
|
||||||
# RUST_LOG = "debug";
|
# RUST_LOG = "debug";
|
||||||
# RUST_LOG = "trace";
|
# RUST_LOG = "trace";
|
||||||
# upstream defaults LEMMY_DATABASE_URL = "postgres:///lemmy?host=/run/postgresql";
|
# upstream defaults LEMMY_DATABASE_URL = "postgres:///lemmy?host=/run/postgresql";
|
||||||
@@ -73,6 +68,73 @@ in {
|
|||||||
|
|
||||||
sane.dns.zones."uninsane.org".inet.CNAME."lemmy" = "native";
|
sane.dns.zones."uninsane.org".inet.CNAME."lemmy" = "native";
|
||||||
|
|
||||||
|
systemd.services.lemmy = {
|
||||||
|
# fix to use a normal user so we can configure perms correctly
|
||||||
|
# XXX(2024-07-28): this hasn't been rigorously tested:
|
||||||
|
# possible that i've set something too strict and won't notice right away
|
||||||
|
serviceConfig.DynamicUser = mkForce false;
|
||||||
|
serviceConfig.User = "lemmy";
|
||||||
|
serviceConfig.Group = "lemmy";
|
||||||
|
|
||||||
|
# hardening (systemd-analyze security lemmy)
|
||||||
|
# a handful of these are specified in upstream nixpkgs, but mostly not
|
||||||
|
serviceConfig.LockPersonality = true;
|
||||||
|
serviceConfig.NoNewPrivileges = true;
|
||||||
|
serviceConfig.MemoryDenyWriteExecute = true;
|
||||||
|
serviceConfig.PrivateDevices = true;
|
||||||
|
serviceConfig.PrivateMounts = true;
|
||||||
|
serviceConfig.PrivateTmp = true;
|
||||||
|
serviceConfig.PrivateUsers = true;
|
||||||
|
serviceConfig.ProcSubset = "pid";
|
||||||
|
|
||||||
|
serviceConfig.ProtectClock = true;
|
||||||
|
serviceConfig.ProtectControlGroups = true;
|
||||||
|
serviceConfig.ProtectHome = true;
|
||||||
|
serviceConfig.ProtectHostname = true;
|
||||||
|
serviceConfig.ProtectKernelLogs = true;
|
||||||
|
serviceConfig.ProtectKernelModules = true;
|
||||||
|
serviceConfig.ProtectKernelTunables = true;
|
||||||
|
serviceConfig.ProtectProc = "invisible";
|
||||||
|
serviceConfig.ProtectSystem = "strict";
|
||||||
|
serviceConfig.RemoveIPC = true;
|
||||||
|
serviceConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6";
|
||||||
|
|
||||||
|
serviceConfig.RestrictNamespaces = true;
|
||||||
|
serviceConfig.RestrictSUIDSGID = true;
|
||||||
|
serviceConfig.SystemCallArchitectures = "native";
|
||||||
|
serviceConfig.SystemCallFilter = [ "@system-service" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.lemmy-ui = {
|
||||||
|
# hardening (systemd-analyze security lemmy-ui)
|
||||||
|
# TODO: upstream into nixpkgs
|
||||||
|
serviceConfig.LockPersonality = true;
|
||||||
|
serviceConfig.NoNewPrivileges = true;
|
||||||
|
# serviceConfig.MemoryDenyWriteExecute = true; #< it uses v8, JIT
|
||||||
|
serviceConfig.PrivateDevices = true;
|
||||||
|
serviceConfig.PrivateMounts = true;
|
||||||
|
serviceConfig.PrivateTmp = true;
|
||||||
|
serviceConfig.PrivateUsers = true;
|
||||||
|
serviceConfig.ProcSubset = "pid";
|
||||||
|
|
||||||
|
serviceConfig.ProtectClock = true;
|
||||||
|
serviceConfig.ProtectControlGroups = true;
|
||||||
|
serviceConfig.ProtectHome = true;
|
||||||
|
serviceConfig.ProtectHostname = true;
|
||||||
|
serviceConfig.ProtectKernelLogs = true;
|
||||||
|
serviceConfig.ProtectKernelModules = true;
|
||||||
|
serviceConfig.ProtectKernelTunables = true;
|
||||||
|
serviceConfig.ProtectProc = "invisible";
|
||||||
|
serviceConfig.ProtectSystem = "strict";
|
||||||
|
serviceConfig.RemoveIPC = true;
|
||||||
|
serviceConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6";
|
||||||
|
|
||||||
|
serviceConfig.RestrictNamespaces = true;
|
||||||
|
serviceConfig.RestrictSUIDSGID = true;
|
||||||
|
serviceConfig.SystemCallArchitectures = "native";
|
||||||
|
serviceConfig.SystemCallFilter = [ "@system-service" "@pkey" "@sandbox" ];
|
||||||
|
};
|
||||||
|
|
||||||
#v DO NOT REMOVE: defaults to 0.3, instead of latest, so always need to explicitly set this.
|
#v DO NOT REMOVE: defaults to 0.3, instead of latest, so always need to explicitly set this.
|
||||||
services.pict-rs.package = pict-rs;
|
services.pict-rs.package = pict-rs;
|
||||||
|
|
||||||
@@ -82,10 +144,38 @@ in {
|
|||||||
# - via CLI flags (overrides everything above)
|
# - via CLI flags (overrides everything above)
|
||||||
# some of the CLI flags have defaults, making it the only actual way to configure certain things even when docs claim otherwise.
|
# some of the CLI flags have defaults, making it the only actual way to configure certain things even when docs claim otherwise.
|
||||||
# CLI args: <https://git.asonix.dog/asonix/pict-rs#user-content-running>
|
# CLI args: <https://git.asonix.dog/asonix/pict-rs#user-content-running>
|
||||||
systemd.services.pict-rs.serviceConfig.ExecStart = lib.mkForce (lib.concatStringsSep " " [
|
systemd.services.pict-rs = {
|
||||||
"${lib.getBin pict-rs}/bin/pict-rs run"
|
serviceConfig.ExecStart = lib.mkForce (lib.concatStringsSep " " [
|
||||||
"--media-video-max-frame-count" (builtins.toString (30*60*60))
|
"${lib.getBin pict-rs}/bin/pict-rs run"
|
||||||
"--media-process-timeout 120"
|
"--media-video-max-frame-count" (builtins.toString (30*60*60))
|
||||||
"--media-video-allow-audio" # allow audio
|
"--media-process-timeout 120"
|
||||||
]);
|
"--media-video-allow-audio" # allow audio
|
||||||
|
]);
|
||||||
|
|
||||||
|
# hardening (systemd-analyze security pict-rs)
|
||||||
|
# TODO: upstream into nixpkgs
|
||||||
|
serviceConfig.LockPersonality = true;
|
||||||
|
serviceConfig.NoNewPrivileges = true;
|
||||||
|
serviceConfig.MemoryDenyWriteExecute = true;
|
||||||
|
serviceConfig.PrivateDevices = true;
|
||||||
|
serviceConfig.PrivateMounts = true;
|
||||||
|
serviceConfig.PrivateTmp = true;
|
||||||
|
serviceConfig.PrivateUsers = true;
|
||||||
|
serviceConfig.ProcSubset = "pid";
|
||||||
|
serviceConfig.ProtectClock = true;
|
||||||
|
serviceConfig.ProtectControlGroups = true;
|
||||||
|
serviceConfig.ProtectHome = true;
|
||||||
|
serviceConfig.ProtectHostname = true;
|
||||||
|
serviceConfig.ProtectKernelLogs = true;
|
||||||
|
serviceConfig.ProtectKernelModules = true;
|
||||||
|
serviceConfig.ProtectKernelTunables = true;
|
||||||
|
serviceConfig.ProtectProc = "invisible";
|
||||||
|
serviceConfig.ProtectSystem = "strict";
|
||||||
|
serviceConfig.RemoveIPC = true;
|
||||||
|
serviceConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6";
|
||||||
|
serviceConfig.RestrictNamespaces = true;
|
||||||
|
serviceConfig.RestrictSUIDSGID = true;
|
||||||
|
serviceConfig.SystemCallArchitectures = "native";
|
||||||
|
serviceConfig.SystemCallFilter = [ "@system-service" ];
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@@ -20,11 +20,11 @@
|
|||||||
./signal.nix
|
./signal.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
sane.persist.sys.byStore.plaintext = [
|
sane.persist.sys.byStore.private = [
|
||||||
{ user = "matrix-synapse"; group = "matrix-synapse"; path = "/var/lib/matrix-synapse"; method = "bind"; }
|
{ user = "matrix-synapse"; group = "matrix-synapse"; path = "/var/lib/matrix-synapse"; method = "bind"; }
|
||||||
];
|
];
|
||||||
services.matrix-synapse.enable = true;
|
services.matrix-synapse.enable = true;
|
||||||
services.matrix-synapse.log.root.level = "WARNING"; # accepts "DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL" (?)
|
services.matrix-synapse.log.root.level = "ERROR"; # accepts "DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL" (?)
|
||||||
services.matrix-synapse.settings = {
|
services.matrix-synapse.settings = {
|
||||||
server_name = "uninsane.org";
|
server_name = "uninsane.org";
|
||||||
|
|
||||||
|
@@ -5,7 +5,7 @@
|
|||||||
# - recommended to use mautrix-discord: <https://github.com/NixOS/nixpkgs/pull/200462>
|
# - recommended to use mautrix-discord: <https://github.com/NixOS/nixpkgs/pull/200462>
|
||||||
lib.mkIf false
|
lib.mkIf false
|
||||||
{
|
{
|
||||||
sane.persist.sys.byStore.plaintext = [
|
sane.persist.sys.byStore.private = [
|
||||||
{ user = "matrix-synapse"; group = "matrix-synapse"; path = "/var/lib/mx-puppet-discord"; method = "bind"; }
|
{ user = "matrix-synapse"; group = "matrix-synapse"; path = "/var/lib/mx-puppet-discord"; method = "bind"; }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@@ -99,7 +99,7 @@ in
|
|||||||
})
|
})
|
||||||
];
|
];
|
||||||
|
|
||||||
sane.persist.sys.byStore.plaintext = [
|
sane.persist.sys.byStore.private = [
|
||||||
# TODO: mode?
|
# TODO: mode?
|
||||||
{ user = "matrix-appservice-irc"; group = "matrix-appservice-irc"; path = "/var/lib/matrix-appservice-irc"; method = "bind"; }
|
{ user = "matrix-appservice-irc"; group = "matrix-appservice-irc"; path = "/var/lib/matrix-appservice-irc"; method = "bind"; }
|
||||||
];
|
];
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
lib.mkIf false # disabled 2024/01/11: i don't use it, and pkgs.mautrix-signal had some API changes
|
lib.mkIf false # disabled 2024/01/11: i don't use it, and pkgs.mautrix-signal had some API changes
|
||||||
{
|
{
|
||||||
sane.persist.sys.byStore.plaintext = [
|
sane.persist.sys.byStore.private = [
|
||||||
{ user = "mautrix-signal"; group = "mautrix-signal"; path = "/var/lib/mautrix-signal"; method = "bind"; }
|
{ user = "mautrix-signal"; group = "mautrix-signal"; path = "/var/lib/mautrix-signal"; method = "bind"; }
|
||||||
{ user = "signald"; group = "signald"; path = "/var/lib/signald"; method = "bind"; }
|
{ user = "signald"; group = "signald"; path = "/var/lib/signald"; method = "bind"; }
|
||||||
];
|
];
|
||||||
|
@@ -29,6 +29,12 @@ in
|
|||||||
};
|
};
|
||||||
|
|
||||||
services.nginx.enable = true;
|
services.nginx.enable = true;
|
||||||
|
# nginxStable is one release behind nginxMainline.
|
||||||
|
# nginx itself recommends running mainline; nixos defaults to stable.
|
||||||
|
# services.nginx.package = pkgs.nginxMainline;
|
||||||
|
# XXX(2024-07-31): nixos defaults to zlib-ng -- supposedly more performant, but spams log with
|
||||||
|
# "gzip filter failed to use preallocated memory: ..."
|
||||||
|
services.nginx.package = pkgs.nginxMainline.override { zlib = pkgs.zlib; };
|
||||||
services.nginx.appendConfig = ''
|
services.nginx.appendConfig = ''
|
||||||
# use 1 process per core.
|
# use 1 process per core.
|
||||||
# may want to increase worker_connections too, but `ulimit -n` must be increased first.
|
# may want to increase worker_connections too, but `ulimit -n` must be increased first.
|
||||||
@@ -44,8 +50,10 @@ in
|
|||||||
log_format vcombined '$host:$server_port $remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referrer" "$http_user_agent"';
|
log_format vcombined '$host:$server_port $remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referrer" "$http_user_agent"';
|
||||||
access_log /var/log/nginx/private.log vcombined;
|
access_log /var/log/nginx/private.log vcombined;
|
||||||
'';
|
'';
|
||||||
# sets gzip_comp_level = 5
|
# enables gzip and sets gzip_comp_level = 5
|
||||||
services.nginx.recommendedGzipSettings = true;
|
services.nginx.recommendedGzipSettings = true;
|
||||||
|
# enables zstd and sets zstd_comp_level = 9
|
||||||
|
services.nginx.recommendedZstdSettings = true;
|
||||||
# enables OCSP stapling (so clients don't need contact the OCSP server -- i do instead)
|
# enables OCSP stapling (so clients don't need contact the OCSP server -- i do instead)
|
||||||
# - doesn't seem to, actually: <https://www.ssllabs.com/ssltest/analyze.html?d=uninsane.org>
|
# - doesn't seem to, actually: <https://www.ssllabs.com/ssltest/analyze.html?d=uninsane.org>
|
||||||
# caches TLS sessions for 10m
|
# caches TLS sessions for 10m
|
||||||
@@ -99,6 +107,16 @@ in
|
|||||||
disable_symlinks on;
|
disable_symlinks on;
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
locations."/share/Ubunchu/" = {
|
||||||
|
alias = "/var/media/Books/Visual/HiroshiSeo/Ubunchu/";
|
||||||
|
extraConfig = ''
|
||||||
|
# autoindex => render directory listings
|
||||||
|
autoindex on;
|
||||||
|
# don't follow any symlinks when serving files
|
||||||
|
# otherwise it allows a directory escape
|
||||||
|
disable_symlinks on;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
# allow matrix users to discover that @user:uninsane.org is reachable via matrix.uninsane.org
|
# allow matrix users to discover that @user:uninsane.org is reachable via matrix.uninsane.org
|
||||||
locations."= /.well-known/matrix/server".extraConfig =
|
locations."= /.well-known/matrix/server".extraConfig =
|
||||||
@@ -180,8 +198,15 @@ in
|
|||||||
|
|
||||||
sane.persist.sys.byStore.plaintext = [
|
sane.persist.sys.byStore.plaintext = [
|
||||||
{ user = "acme"; group = "acme"; path = "/var/lib/acme"; method = "bind"; }
|
{ user = "acme"; group = "acme"; path = "/var/lib/acme"; method = "bind"; }
|
||||||
|
];
|
||||||
|
sane.persist.sys.byStore.private = [
|
||||||
{ user = "colin"; group = "users"; path = "/var/www/sites"; method = "bind"; }
|
{ user = "colin"; group = "users"; path = "/var/www/sites"; method = "bind"; }
|
||||||
];
|
];
|
||||||
|
sane.persist.sys.byStore.ephemeral = [
|
||||||
|
# logs *could* be persisted to private storage, but then there's the issue of
|
||||||
|
# "what if servo boots, isn't unlocked, and the whole / tmpfs is consumed by logs"
|
||||||
|
{ user = "nginx"; group = "nginx"; path = "/var/log/nginx"; method = "bind"; }
|
||||||
|
];
|
||||||
|
|
||||||
# let's encrypt default chain looks like:
|
# let's encrypt default chain looks like:
|
||||||
# - End-entity certificate ← R3 ← ISRG Root X1 ← DST Root CA X3
|
# - End-entity certificate ← R3 ← ISRG Root X1 ← DST Root CA X3
|
||||||
|
@@ -30,7 +30,7 @@ let
|
|||||||
altPort = 2587;
|
altPort = 2587;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
sane.persist.sys.byStore.plaintext = [
|
sane.persist.sys.byStore.private = [
|
||||||
# not 100% necessary to persist this, but ntfy does keep a 12hr (by default) cache
|
# not 100% necessary to persist this, but ntfy does keep a 12hr (by default) cache
|
||||||
# for pushing notifications to users who become offline.
|
# for pushing notifications to users who become offline.
|
||||||
# ACLs also live here.
|
# ACLs also live here.
|
||||||
@@ -46,7 +46,7 @@ in
|
|||||||
# defaults to 45s.
|
# defaults to 45s.
|
||||||
# note that the client may still do its own TCP-level keepalives, typically every 30s
|
# note that the client may still do its own TCP-level keepalives, typically every 30s
|
||||||
keepalive-interval = "15m";
|
keepalive-interval = "15m";
|
||||||
log-level = "trace"; # trace, debug, info (default), warn, error
|
log-level = "info"; # trace, debug, info (default), warn, error
|
||||||
auth-default-access = "deny-all";
|
auth-default-access = "deny-all";
|
||||||
};
|
};
|
||||||
systemd.services.ntfy-sh.serviceConfig.DynamicUser = lib.mkForce false;
|
systemd.services.ntfy-sh.serviceConfig.DynamicUser = lib.mkForce false;
|
||||||
|
@@ -7,14 +7,15 @@
|
|||||||
# to run it in a oci-container: <https://github.com/barrucadu/nixfiles/blob/master/services/pleroma.nix>
|
# to run it in a oci-container: <https://github.com/barrucadu/nixfiles/blob/master/services/pleroma.nix>
|
||||||
#
|
#
|
||||||
# admin frontend: <https://fed.uninsane.org/pleroma/admin>
|
# admin frontend: <https://fed.uninsane.org/pleroma/admin>
|
||||||
{ config, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
let
|
let
|
||||||
logLevel = "warn";
|
logLevel = "warn";
|
||||||
# logLevel = "debug";
|
# logLevel = "debug";
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
sane.persist.sys.byStore.plaintext = [
|
sane.persist.sys.byStore.private = [
|
||||||
|
# contains media i've uploaded to the server
|
||||||
{ user = "pleroma"; group = "pleroma"; path = "/var/lib/pleroma"; method = "bind"; }
|
{ user = "pleroma"; group = "pleroma"; path = "/var/lib/pleroma"; method = "bind"; }
|
||||||
];
|
];
|
||||||
services.pleroma.enable = true;
|
services.pleroma.enable = true;
|
||||||
@@ -135,25 +136,52 @@ in
|
|||||||
# something inside pleroma invokes `sh` w/o specifying it by path, so this is needed to allow pleroma to start
|
# something inside pleroma invokes `sh` w/o specifying it by path, so this is needed to allow pleroma to start
|
||||||
pkgs.bash
|
pkgs.bash
|
||||||
# used by Pleroma to strip geo tags from uploads
|
# used by Pleroma to strip geo tags from uploads
|
||||||
pkgs.exiftool
|
config.sane.programs.exiftool.package
|
||||||
# i saw some errors when pleroma was shutting down about it not being able to find `awk`. probably not critical
|
# i saw some errors when pleroma was shutting down about it not being able to find `awk`. probably not critical
|
||||||
pkgs.gawk
|
config.sane.programs.gawk.package
|
||||||
# needed for email operations like password reset
|
# needed for email operations like password reset
|
||||||
pkgs.postfix
|
pkgs.postfix
|
||||||
];
|
];
|
||||||
|
|
||||||
systemd.services.pleroma.serviceConfig = {
|
systemd.services.pleroma = {
|
||||||
# postgres can be slow to service early requests, preventing pleroma from starting on the first try
|
# postgres can be slow to service early requests, preventing pleroma from starting on the first try
|
||||||
Restart = "on-failure";
|
serviceConfig.Restart = "on-failure";
|
||||||
RestartSec = "10s";
|
serviceConfig.RestartSec = "10s";
|
||||||
};
|
|
||||||
|
|
||||||
# systemd.services.pleroma.serviceConfig = {
|
# hardening (systemd-analyze security pleroma)
|
||||||
# # required for sendmail. see https://git.pleroma.social/pleroma/pleroma/-/issues/2259
|
# XXX(2024-07-28): this hasn't been rigorously tested:
|
||||||
# NoNewPrivileges = lib.mkForce false;
|
# possible that i've set something too strict and won't notice right away
|
||||||
# PrivateTmp = lib.mkForce false;
|
# make sure to test:
|
||||||
# CapabilityBoundingSet = lib.mkForce "~";
|
# - image/media uploading
|
||||||
# };
|
serviceConfig.CapabilityBoundingSet = "~CAP_SYS_ADMIN"; #< TODO: reduce this. try: CAP_SYS_NICE CAP_DAC_READ_SEARCH CAP_SYS_CHROOT CAP_SETGID CAP_SETUID
|
||||||
|
serviceConfig.LockPersonality = true;
|
||||||
|
serviceConfig.NoNewPrivileges = true;
|
||||||
|
serviceConfig.MemoryDenyWriteExecute = true;
|
||||||
|
serviceConfig.PrivateDevices = lib.mkForce true; #< dunno why nixpkgs has this set false; it seems to work as true
|
||||||
|
serviceConfig.PrivateMounts = true;
|
||||||
|
serviceConfig.PrivateTmp = true;
|
||||||
|
serviceConfig.PrivateUsers = true;
|
||||||
|
|
||||||
|
serviceConfig.ProtectProc = "invisible";
|
||||||
|
serviceConfig.ProcSubset = "all"; #< needs /proc/sys/kernel/overflowuid for bwrap
|
||||||
|
|
||||||
|
serviceConfig.ProtectClock = true;
|
||||||
|
serviceConfig.ProtectControlGroups = true;
|
||||||
|
serviceConfig.ProtectHome = true;
|
||||||
|
serviceConfig.ProtectKernelModules = true;
|
||||||
|
serviceConfig.ProtectSystem = lib.mkForce "strict";
|
||||||
|
serviceConfig.RemoveIPC = true;
|
||||||
|
serviceConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6 AF_NETLINK";
|
||||||
|
|
||||||
|
serviceConfig.RestrictSUIDSGID = true;
|
||||||
|
serviceConfig.SystemCallArchitectures = "native";
|
||||||
|
serviceConfig.SystemCallFilter = [ "@system-service" "@mount" "@sandbox" ]; #< "sandbox" might not actually be necessary
|
||||||
|
|
||||||
|
serviceConfig.ProtectHostname = false; #< else brap can't mount /proc
|
||||||
|
serviceConfig.ProtectKernelLogs = false; #< else breaks exiftool ("bwrap: Can't mount proc on /newroot/proc: Operation not permitted")
|
||||||
|
serviceConfig.ProtectKernelTunables = false; #< else breaks exiftool
|
||||||
|
serviceConfig.RestrictNamespaces = false; # media uploads require bwrap
|
||||||
|
};
|
||||||
|
|
||||||
# this is required to allow pleroma to send email.
|
# this is required to allow pleroma to send email.
|
||||||
# raw `sendmail` works, but i think pleroma's passing it some funny flags or something, idk.
|
# raw `sendmail` works, but i think pleroma's passing it some funny flags or something, idk.
|
||||||
|
@@ -6,9 +6,9 @@ let
|
|||||||
KiB = n: 1024*n;
|
KiB = n: 1024*n;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
sane.persist.sys.byStore.plaintext = [
|
sane.persist.sys.byStore.private = [
|
||||||
# TODO: mode?
|
{ user = "postgres"; group = "postgres"; mode = "0750"; path = "/var/lib/postgresql"; method = "bind"; }
|
||||||
{ user = "postgres"; group = "postgres"; path = "/var/lib/postgresql"; method = "bind"; }
|
{ user = "postgres"; group = "postgres"; mode = "0750"; path = "/var/backup/postgresql"; method = "bind"; }
|
||||||
];
|
];
|
||||||
services.postgresql.enable = true;
|
services.postgresql.enable = true;
|
||||||
|
|
||||||
|
@@ -56,7 +56,8 @@ let
|
|||||||
enableDebug = false;
|
enableDebug = false;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
sane.persist.sys.byStore.plaintext = [
|
sane.persist.sys.byStore.private = [
|
||||||
|
# TODO: mode?
|
||||||
{ user = "prosody"; group = "prosody"; path = "/var/lib/prosody"; method = "bind"; }
|
{ user = "prosody"; group = "prosody"; path = "/var/lib/prosody"; method = "bind"; }
|
||||||
];
|
];
|
||||||
sane.ports.ports."5000" = {
|
sane.ports.ports."5000" = {
|
||||||
|
@@ -10,7 +10,9 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
sane.persist.sys.byStore.plaintext = [
|
sane.persist.sys.byStore.ephemeral = [
|
||||||
|
# {data,downloads,incomplete,logs}: contains logs, search history, and downloads
|
||||||
|
# so, move the downloaded data to persistent storage regularly, or configure the downloads/incomplete dirs to point to persisted storage (in nixpkgs slskd config)
|
||||||
{ user = "slskd"; group = "media"; path = "/var/lib/slskd"; method = "bind"; }
|
{ user = "slskd"; group = "media"; path = "/var/lib/slskd"; method = "bind"; }
|
||||||
];
|
];
|
||||||
sops.secrets."slskd_env" = {
|
sops.secrets."slskd_env" = {
|
||||||
@@ -68,12 +70,20 @@
|
|||||||
# flags.volatile = true; # store searches and active transfers in RAM (completed transfers still go to disk). rec for btrfs/zfs
|
# flags.volatile = true; # store searches and active transfers in RAM (completed transfers still go to disk). rec for btrfs/zfs
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.services.slskd.serviceConfig = {
|
systemd.services.slskd = {
|
||||||
# run this behind the OVPN static VPN
|
# run this behind the OVPN static VPN
|
||||||
NetworkNamespacePath = "/run/netns/ovpns";
|
serviceConfig.NetworkNamespacePath = "/run/netns/ovpns";
|
||||||
ExecStartPre = [ "${lib.getExe pkgs.sane-scripts.ip-check} --no-upnp --expect ${config.sane.netns.ovpns.netnsPubIpv4}" ]; # abort if public IP is not as expected
|
serviceConfig.ExecStartPre = [ "${lib.getExe pkgs.sane-scripts.ip-check} --no-upnp --expect ${config.sane.netns.ovpns.netnsPubIpv4}" ]; # abort if public IP is not as expected
|
||||||
|
|
||||||
Restart = lib.mkForce "always"; # exits "success" when it fails to connect to soulseek server
|
serviceConfig.Restart = lib.mkForce "always"; # exits "success" when it fails to connect to soulseek server
|
||||||
RestartSec = "60s";
|
serviceConfig.RestartSec = "60s";
|
||||||
|
|
||||||
|
# hardening (systemd-analyze security slskd)
|
||||||
|
# upstream nixpkgs specifies moderate defaults; these are supplementary
|
||||||
|
# serviceConfig.MemoryDenyWriteExecute = true;
|
||||||
|
# serviceConfig.ProcSubset = "pid";
|
||||||
|
# serviceConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6";
|
||||||
|
# serviceConfig.SystemCallArchitectures = "native";
|
||||||
|
# serviceConfig.SystemCallFilter = [ "@system-service" ];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -31,14 +31,14 @@ let
|
|||||||
"coreutils"
|
"coreutils"
|
||||||
"findutils"
|
"findutils"
|
||||||
"rsync"
|
"rsync"
|
||||||
"util-linux"
|
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
sane.persist.sys.byStore.plaintext = [
|
sane.persist.sys.byStore.private = [
|
||||||
# TODO: mode? we need this specifically for the stats tracking in .config/
|
# TODO: mode? we need this specifically for the stats tracking in .config/
|
||||||
{ user = "transmission"; group = config.users.users.transmission.group; path = "/var/lib/transmission"; method = "bind"; }
|
{ user = "transmission"; group = config.users.users.transmission.group; path = "/var/lib/transmission"; method = "bind"; }
|
||||||
|
{ user = "transmission"; group = config.users.users.transmission.group; path = "/var/backup/torrents"; method = "bind"; }
|
||||||
];
|
];
|
||||||
users.users.transmission.extraGroups = [ "media" ];
|
users.users.transmission.extraGroups = [ "media" ];
|
||||||
|
|
||||||
@@ -107,16 +107,31 @@ in
|
|||||||
script-torrent-done-filename = "${torrent-done}/bin/torrent-done";
|
script-torrent-done-filename = "${torrent-done}/bin/torrent-done";
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.services.transmission.after = [ "wireguard-wg-ovpns.service" ];
|
systemd.services.transmission = {
|
||||||
systemd.services.transmission.partOf = [ "wireguard-wg-ovpns.service" ];
|
after = [ "wireguard-wg-ovpns.service" ];
|
||||||
systemd.services.transmission.serviceConfig = {
|
partOf = [ "wireguard-wg-ovpns.service" ];
|
||||||
|
environment.TR_DEBUG = "1";
|
||||||
# run this behind the OVPN static VPN
|
# run this behind the OVPN static VPN
|
||||||
NetworkNamespacePath = "/run/netns/ovpns";
|
serviceConfig.NetworkNamespacePath = "/run/netns/ovpns";
|
||||||
ExecStartPre = [ "${lib.getExe pkgs.sane-scripts.ip-check} --no-upnp --expect ${config.sane.netns.ovpns.netnsPubIpv4}" ]; # abort if public IP is not as expected
|
serviceConfig.ExecStartPre = [ "${lib.getExe pkgs.sane-scripts.ip-check} --no-upnp --expect ${config.sane.netns.ovpns.netnsPubIpv4}" ]; # abort if public IP is not as expected
|
||||||
|
|
||||||
Restart = "on-failure";
|
serviceConfig.Restart = "on-failure";
|
||||||
RestartSec = "30s";
|
serviceConfig.RestartSec = "30s";
|
||||||
BindPaths = [ "/var/media" ]; #< so it can move completed torrents into the media library
|
serviceConfig.BindPaths = [ "/var/media" ]; #< so it can move completed torrents into the media library
|
||||||
|
serviceConfig.SystemCallFilter = lib.mkForce [
|
||||||
|
# the torrent-done script does stuff which fails the nixos default syscall filter.
|
||||||
|
# allow a bunch of stuff, speculatively, to hopefully fix that:
|
||||||
|
"@aio"
|
||||||
|
"@basic-io"
|
||||||
|
"@chown"
|
||||||
|
"@file-system"
|
||||||
|
"@io-event"
|
||||||
|
"@process"
|
||||||
|
"@sandbox"
|
||||||
|
"@sync"
|
||||||
|
"@system-service"
|
||||||
|
"quotactl"
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
# service to automatically backup torrents i add to transmission
|
# service to automatically backup torrents i add to transmission
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env nix-shell
|
#!/usr/bin/env nix-shell
|
||||||
#!nix-shell -i bash -p acl -p bash -p coreutils -p findutils -p rsync -p util-linux
|
#!nix-shell -i bash -p acl -p bash -p coreutils -p findutils -p rsync
|
||||||
|
|
||||||
# transmission invokes this with no args, and the following env vars:
|
# transmission invokes this with no args, and the following env vars:
|
||||||
# - TR_TORRENT_DIR: full path to the folder i told transmission to download it to.
|
# - TR_TORRENT_DIR: full path to the folder i told transmission to download it to.
|
||||||
@@ -7,7 +7,6 @@
|
|||||||
# optionally:
|
# optionally:
|
||||||
# - TR_DRY_RUN=1
|
# - TR_DRY_RUN=1
|
||||||
# - TR_DEBUG=1
|
# - TR_DEBUG=1
|
||||||
# - TR_NO_HARDLINK=1
|
|
||||||
|
|
||||||
DOWNLOAD_DIR=/var/media/torrents
|
DOWNLOAD_DIR=/var/media/torrents
|
||||||
|
|
||||||
@@ -58,19 +57,13 @@ if [ ${#subdirs[@]} -eq 1 ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# remove noisy files:
|
# remove noisy files:
|
||||||
|
# -iname means "insensitive", but the syntax is NOT regex -- more similar to shell matching
|
||||||
destructive find "$MEDIA_DIR/" -type f \(\
|
destructive find "$MEDIA_DIR/" -type f \(\
|
||||||
-iname '.*downloaded.?from.*' \
|
-iname '*downloaded?from*' \
|
||||||
-o -iname 'source.txt' \
|
-o -iname 'source.txt' \
|
||||||
-o -iname 'upcoming.?releases.*' \
|
-o -iname '*upcoming?releases*' \
|
||||||
-o -iname 'www.YTS.*.jpg' \
|
-o -iname 'www.YTS*.jpg' \
|
||||||
-o -iname 'WWW.YIFY*.COM.jpg' \
|
-o -iname 'WWW.YIFY*.COM.jpg' \
|
||||||
-o -iname 'YIFY*.com.txt' \
|
-o -iname 'YIFY*.com.txt' \
|
||||||
-o -iname 'YTS*.com.txt' \
|
-o -iname 'YTS*.com.txt' \
|
||||||
\) -exec rm {} \;
|
\) -exec rm {} \;
|
||||||
|
|
||||||
if ! [ -n "${TR_NO_HARDLINK}" ]; then
|
|
||||||
# dedupe the whole media library.
|
|
||||||
# yeah, a bit excessive: move this to a cron job if that's problematic
|
|
||||||
# or make it run with only 1/N probability, etc.
|
|
||||||
destructive hardlink /var/media --reflink=always --ignore-time --verbose
|
|
||||||
fi
|
|
||||||
|
@@ -48,12 +48,10 @@ in
|
|||||||
# so, org. can specify ns2/ns3 as being to the VPN, with no mention of ns1. we provide ns1 here.
|
# so, org. can specify ns2/ns3 as being to the VPN, with no mention of ns1. we provide ns1 here.
|
||||||
A."ns1" = "%ANATIVE%";
|
A."ns1" = "%ANATIVE%";
|
||||||
A."ns2" = "%ADOOF%";
|
A."ns2" = "%ADOOF%";
|
||||||
A."ns3" = "%AOVPNS%";
|
|
||||||
A."ovpns" = "%AOVPNS%";
|
A."ovpns" = "%AOVPNS%";
|
||||||
NS."@" = [
|
NS."@" = [
|
||||||
"ns1.uninsane.org."
|
"ns1.uninsane.org."
|
||||||
"ns2.uninsane.org."
|
"ns2.uninsane.org."
|
||||||
"ns3.uninsane.org."
|
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -100,7 +98,9 @@ in
|
|||||||
substitutions = mkSubstitutions "doof";
|
substitutions = mkSubstitutions "doof";
|
||||||
listenAddrsIpv4 = [
|
listenAddrsIpv4 = [
|
||||||
config.sane.netns.doof.hostVethIpv4
|
config.sane.netns.doof.hostVethIpv4
|
||||||
config.sane.netns.ovpns.hostVethIpv4
|
config.sane.netns.doof.netnsPubIpv4
|
||||||
|
nativeAddrs."servo.lan"
|
||||||
|
# config.sane.netns.ovpns.hostVethIpv4
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
hn = {
|
hn = {
|
||||||
@@ -128,11 +128,11 @@ in
|
|||||||
# ];
|
# ];
|
||||||
# };
|
# };
|
||||||
};
|
};
|
||||||
lan = {
|
# lan = {
|
||||||
substitutions = mkSubstitutions "lan";
|
# substitutions = mkSubstitutions "lan";
|
||||||
listenAddrsIpv4 = [ nativeAddrs."servo.lan" ];
|
# listenAddrsIpv4 = [ nativeAddrs."servo.lan" ];
|
||||||
# port = 1053;
|
# # port = 1053;
|
||||||
};
|
# };
|
||||||
# wan = {
|
# wan = {
|
||||||
# substitutions = mkSubstitutions "wan";
|
# substitutions = mkSubstitutions "wan";
|
||||||
# listenAddrsIpv4 = [
|
# listenAddrsIpv4 = [
|
||||||
@@ -141,10 +141,5 @@ in
|
|||||||
# };
|
# };
|
||||||
};
|
};
|
||||||
|
|
||||||
sane.services.dyn-dns.restartOnChange = [
|
sane.services.dyn-dns.restartOnChange = lib.map (c: "${c.service}.service") (builtins.attrValues config.sane.services.trust-dns.instances);
|
||||||
"trust-dns-doof.service"
|
|
||||||
"trust-dns-hn.service"
|
|
||||||
"trust-dns-lan.service"
|
|
||||||
# "trust-dns-wan.service"
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
@@ -46,5 +46,6 @@
|
|||||||
# manifests as spurious "No space left on device" when trying to install watches,
|
# manifests as spurious "No space left on device" when trying to install watches,
|
||||||
# e.g. in dyn-dns by `systemctl start dyn-dns-watcher.path`.
|
# e.g. in dyn-dns by `systemctl start dyn-dns-watcher.path`.
|
||||||
# see: <https://askubuntu.com/questions/828779/failed-to-add-run-systemd-ask-password-to-directory-watch-no-space-left-on-dev>
|
# see: <https://askubuntu.com/questions/828779/failed-to-add-run-systemd-ask-password-to-directory-watch-no-space-left-on-dev>
|
||||||
boot.kernel.sysctl."fs.inotify.max_user_watches" = 1048576;
|
boot.kernel.sysctl."fs.inotify.max_user_watches" = 4194304;
|
||||||
|
boot.kernel.sysctl."fs.inotify.max_user_instances" = 4194304;
|
||||||
}
|
}
|
||||||
|
@@ -10,7 +10,6 @@
|
|||||||
./machine-id.nix
|
./machine-id.nix
|
||||||
./net
|
./net
|
||||||
./nix.nix
|
./nix.nix
|
||||||
./persist.nix
|
|
||||||
./polyunfill.nix
|
./polyunfill.nix
|
||||||
./programs
|
./programs
|
||||||
./quirks.nix
|
./quirks.nix
|
||||||
|
@@ -2,7 +2,9 @@
|
|||||||
# - universal search/directory: <https://podcastindex.org>
|
# - universal search/directory: <https://podcastindex.org>
|
||||||
# - list of lists: <https://en.wikipedia.org/wiki/Category:Lists_of_podcasts>
|
# - list of lists: <https://en.wikipedia.org/wiki/Category:Lists_of_podcasts>
|
||||||
# - podcasts w/ a community: <https://lemmyverse.net/communities?query=podcast>
|
# - podcasts w/ a community: <https://lemmyverse.net/communities?query=podcast>
|
||||||
# - podcast rec thread: <https://lemmy.ml/post/1565858>
|
# - podcast recs:
|
||||||
|
# - active lemmy: <https://slrpnk.net/c/podcasts>
|
||||||
|
# - old thread: <https://lemmy.ml/post/1565858>
|
||||||
#
|
#
|
||||||
{ lib, sane-data, ... }:
|
{ lib, sane-data, ... }:
|
||||||
let
|
let
|
||||||
@@ -70,16 +72,17 @@ let
|
|||||||
(fromDb "feeds.feedburner.com/radiolab" // pol) # Radiolab -- also available here, but ONLY OVER HTTP: <http://feeds.wnyc.org/radiolab>
|
(fromDb "feeds.feedburner.com/radiolab" // pol) # Radiolab -- also available here, but ONLY OVER HTTP: <http://feeds.wnyc.org/radiolab>
|
||||||
(fromDb "feeds.megaphone.fm/behindthebastards" // pol) # also Maggie Killjoy
|
(fromDb "feeds.megaphone.fm/behindthebastards" // pol) # also Maggie Killjoy
|
||||||
(fromDb "feeds.megaphone.fm/recodedecode" // tech) # The Verge - Decoder
|
(fromDb "feeds.megaphone.fm/recodedecode" // tech) # The Verge - Decoder
|
||||||
(fromDb "feeds.simplecast.com/54nAGcIl" // pol) # The Daily
|
|
||||||
(fromDb "feeds.simplecast.com/82FI35Px" // pol) # Ezra Klein Show
|
(fromDb "feeds.simplecast.com/82FI35Px" // pol) # Ezra Klein Show
|
||||||
(fromDb "feeds.simplecast.com/wgl4xEgL" // rat) # Econ Talk
|
(fromDb "feeds.simplecast.com/wgl4xEgL" // rat) # Econ Talk
|
||||||
(fromDb "feeds.simplecast.com/xKJ93w_w" // uncat) # Atlas Obscura
|
(fromDb "feeds.simplecast.com/xKJ93w_w" // uncat) # Atlas Obscura
|
||||||
(fromDb "feeds.transistor.fm/acquired" // tech)
|
(fromDb "feeds.transistor.fm/acquired" // tech)
|
||||||
|
(fromDb "feeds.transistor.fm/complex-systems-with-patrick-mckenzie-patio11" // tech) # Patrick Mackenzie (from Bits About Money)
|
||||||
(fromDb "feeds.twit.tv/floss.xml" // tech)
|
(fromDb "feeds.twit.tv/floss.xml" // tech)
|
||||||
(fromDb "fulltimenix.com" // tech)
|
(fromDb "fulltimenix.com" // tech)
|
||||||
(fromDb "futureofcoding.org/episodes" // tech)
|
(fromDb "futureofcoding.org/episodes" // tech)
|
||||||
(fromDb "hackerpublicradio.org" // tech)
|
(fromDb "hackerpublicradio.org" // tech)
|
||||||
(fromDb "lexfridman.com/podcast" // rat)
|
(fromDb "lexfridman.com/podcast" // rat)
|
||||||
|
(fromDb "linktr.ee/betteroffline" // pol)
|
||||||
(fromDb "mapspodcast.libsyn.com" // uncat) # Multidisciplinary Association for Psychedelic Studies
|
(fromDb "mapspodcast.libsyn.com" // uncat) # Multidisciplinary Association for Psychedelic Studies
|
||||||
(fromDb "microarch.club" // tech)
|
(fromDb "microarch.club" // tech)
|
||||||
(fromDb "mintcast.org" // tech)
|
(fromDb "mintcast.org" // tech)
|
||||||
@@ -88,7 +91,6 @@ let
|
|||||||
(fromDb "omny.fm/shows/money-stuff-the-podcast") # Matt Levine
|
(fromDb "omny.fm/shows/money-stuff-the-podcast") # Matt Levine
|
||||||
(fromDb "omny.fm/shows/the-dollop-with-dave-anthony-and-gareth-reynolds") # The Dollop history/comedy
|
(fromDb "omny.fm/shows/the-dollop-with-dave-anthony-and-gareth-reynolds") # The Dollop history/comedy
|
||||||
(fromDb "originstories.libsyn.com" // uncat)
|
(fromDb "originstories.libsyn.com" // uncat)
|
||||||
(fromDb "podcast.posttv.com/itunes/post-reports.xml" // pol)
|
|
||||||
(fromDb "politicalorphanage.libsyn.com" // pol)
|
(fromDb "politicalorphanage.libsyn.com" // pol)
|
||||||
(fromDb "reverseengineering.libsyn.com/rss" // tech) # UnNamed Reverse Engineering Podcast
|
(fromDb "reverseengineering.libsyn.com/rss" // tech) # UnNamed Reverse Engineering Podcast
|
||||||
(fromDb "rss.acast.com/deconstructed") # The Intercept - Deconstructed
|
(fromDb "rss.acast.com/deconstructed") # The Intercept - Deconstructed
|
||||||
@@ -111,7 +113,9 @@ let
|
|||||||
|
|
||||||
# (fromDb "feeds.libsyn.com/421877" // rat) # Less Wrong Curated
|
# (fromDb "feeds.libsyn.com/421877" // rat) # Less Wrong Curated
|
||||||
# (fromDb "feeds.megaphone.fm/hubermanlab" // uncat) # Daniel Huberman on sleep
|
# (fromDb "feeds.megaphone.fm/hubermanlab" // uncat) # Daniel Huberman on sleep
|
||||||
|
# (fromDb "feeds.simplecast.com/54nAGcIl" // pol) # The Daily
|
||||||
# (fromDb "feeds.simplecast.com/l2i9YnTd" // tech // pol) # Hard Fork (NYtimes tech)
|
# (fromDb "feeds.simplecast.com/l2i9YnTd" // tech // pol) # Hard Fork (NYtimes tech)
|
||||||
|
# (fromDb "podcast.posttv.com/itunes/post-reports.xml" // pol)
|
||||||
# (fromDb "podcast.thelinuxexp.com" // tech) # low-brow linux/foss PR announcements
|
# (fromDb "podcast.thelinuxexp.com" // tech) # low-brow linux/foss PR announcements
|
||||||
# (fromDb "rss.art19.com/your-welcome" // pol) # Michael Malice - Your Welcome -- also available here: <https://origin.podcastone.com/podcast?categoryID2=2232>
|
# (fromDb "rss.art19.com/your-welcome" // pol) # Michael Malice - Your Welcome -- also available here: <https://origin.podcastone.com/podcast?categoryID2=2232>
|
||||||
# (fromDb "rss.prod.firstlook.media/deconstructed/podcast.rss" // pol) #< possible URL rot
|
# (fromDb "rss.prod.firstlook.media/deconstructed/podcast.rss" // pol) #< possible URL rot
|
||||||
@@ -237,9 +241,9 @@ let
|
|||||||
(fromDb "youtube.com/@TheB1M")
|
(fromDb "youtube.com/@TheB1M")
|
||||||
(fromDb "youtube.com/@TomScottGo")
|
(fromDb "youtube.com/@TomScottGo")
|
||||||
(fromDb "youtube.com/@Vihart")
|
(fromDb "youtube.com/@Vihart")
|
||||||
(fromDb "youtube.com/@Vox")
|
|
||||||
# (fromDb "youtube.com/@Vsauce") # they're all like 1-minute long videos now? what happened @Vsauce?
|
|
||||||
|
|
||||||
|
# (fromDb "youtube.com/@Vox")
|
||||||
|
# (fromDb "youtube.com/@Vsauce") # they're all like 1-minute long videos now? what happened @Vsauce?
|
||||||
# (fromDb "youtube.com/@rossmanngroup" // pol // tech) # Louis Rossmann
|
# (fromDb "youtube.com/@rossmanngroup" // pol // tech) # Louis Rossmann
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@@ -121,14 +121,17 @@ let
|
|||||||
dir.acl.mode = "0700";
|
dir.acl.mode = "0700";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
remoteServo = subdir: {
|
remoteServo = subdir: let
|
||||||
|
localPath = "/mnt/servo/${subdir}";
|
||||||
|
systemdName = utils.escapeSystemdPath localPath;
|
||||||
|
in {
|
||||||
sane.programs.curlftpfs.enableFor.system = true;
|
sane.programs.curlftpfs.enableFor.system = true;
|
||||||
sane.fs."/mnt/servo/${subdir}" = sane-lib.fs.wanted {
|
sane.fs."${localPath}" = sane-lib.fs.wanted {
|
||||||
dir.acl.user = "colin";
|
dir.acl.user = "colin";
|
||||||
dir.acl.group = "users";
|
dir.acl.group = "users";
|
||||||
dir.acl.mode = "0750";
|
dir.acl.mode = "0750";
|
||||||
};
|
};
|
||||||
fileSystems."/mnt/servo/${subdir}" = {
|
fileSystems."${localPath}" = {
|
||||||
device = "ftp://servo-hn:/${subdir}";
|
device = "ftp://servo-hn:/${subdir}";
|
||||||
noCheck = true;
|
noCheck = true;
|
||||||
fsType = "fuse.curlftpfs";
|
fsType = "fuse.curlftpfs";
|
||||||
@@ -136,37 +139,43 @@ let
|
|||||||
# fsType = "nfs";
|
# fsType = "nfs";
|
||||||
# options = fsOpts.nfs ++ fsOpts.lazyMount;
|
# options = fsOpts.nfs ++ fsOpts.lazyMount;
|
||||||
};
|
};
|
||||||
systemd.services."automount-servo-${utils.escapeSystemdPath subdir}" = let
|
|
||||||
fs = config.fileSystems."/mnt/servo/${subdir}";
|
systemd.mounts = let
|
||||||
in {
|
fsEntry = config.fileSystems."${localPath}";
|
||||||
# this is a *flaky* network mount, especially on moby.
|
in [{
|
||||||
# if done as a normal autofs mount, access will eternally block when network is dropped.
|
#VVV repeat what systemd would ordinarily scrape from /etc/fstab
|
||||||
# notably, this would block *any* sandboxed app which allows media access, whether they actually try to use that media or not.
|
where = localPath;
|
||||||
# a practical solution is this: mount as a service -- instead of autofs -- and unmount on timeout error, in a restart loop.
|
what = fsEntry.device;
|
||||||
# until the ftp handshake succeeds, nothing is actually mounted to the vfs, so this doesn't slow down any I/O when network is down.
|
type = fsEntry.fsType;
|
||||||
description = "automount /mnt/servo/${subdir} in a fault-tolerant and non-blocking manner";
|
options = lib.concatStringsSep "," fsEntry.options;
|
||||||
after = [ "network-online.target" ];
|
after = [ "network-online.target" ];
|
||||||
requires = [ "network-online.target" ];
|
requires = [ "network-online.target" ];
|
||||||
wantedBy = [ "default.target" ];
|
wantedBy = [ "default.target" ]; #< TODO: move this into nixos fileSystems
|
||||||
|
#VVV patch so that when the mount fails, we start a timer to remount it.
|
||||||
serviceConfig.Type = "simple";
|
# and for a disconnection after a good mount (onSuccess), restart the timer to be more aggressive
|
||||||
serviceConfig.ExecStart = lib.escapeShellArgs [
|
onFailure = [ "${systemdName}.timer" ];
|
||||||
"/usr/bin/env"
|
onSuccess = [ "${systemdName}-restart-timer.target" ];
|
||||||
"PATH=/run/current-system/sw/bin"
|
}];
|
||||||
"mount.${fs.fsType}"
|
systemd.targets."${systemdName}-restart-timer" = {
|
||||||
"-f" # foreground (i.e. don't daemonize)
|
# hack unit which, when started, stops the timer (if running), and then starts it again.
|
||||||
"-s" # single-threaded (TODO: it's probably ok to disable this?)
|
after = [ "${systemdName}.timer" ];
|
||||||
"-o"
|
conflicts = [ "${systemdName}.timer" ];
|
||||||
(lib.concatStringsSep "," (lib.filter (o: !lib.hasPrefix "x-systemd." o) fs.options))
|
upholds = [ "${systemdName}.timer" ];
|
||||||
fs.device
|
unitConfig.StopWhenUnneeded = true;
|
||||||
"/mnt/servo/${subdir}"
|
};
|
||||||
|
systemd.timers."${systemdName}" = {
|
||||||
|
timerConfig.Unit = "${systemdName}.mount";
|
||||||
|
timerConfig.AccuracySec = "2s";
|
||||||
|
timerConfig.OnActiveSec = [
|
||||||
|
# try to remount at these timestamps, backing off gradually
|
||||||
|
# there seems to be an implicit mount attempt at t=0.
|
||||||
|
"10s"
|
||||||
|
"30s"
|
||||||
|
"60s"
|
||||||
|
"120s"
|
||||||
];
|
];
|
||||||
# not sure if this configures a linear, or exponential backoff.
|
# cap the backoff to a fixed interval.
|
||||||
# but the first restart will be after `RestartSec`, and the n'th restart (n = RestartSteps) will be RestartMaxDelaySec after the n-1'th exit.
|
timerConfig.OnUnitActiveSec = [ "120s" ];
|
||||||
serviceConfig.Restart = "always";
|
|
||||||
serviceConfig.RestartSec = "10s";
|
|
||||||
serviceConfig.RestartMaxDelaySec = "120s";
|
|
||||||
serviceConfig.RestartSteps = "5";
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
|
@@ -1,21 +1,13 @@
|
|||||||
{ config, lib, ... }:
|
{ config, lib, ... }:
|
||||||
{
|
{
|
||||||
sane.user.persist.byStore.plaintext = [
|
sane.user.persist.byStore.plaintext = [
|
||||||
"archive"
|
# TODO: some of ~/dev should be private too, but maybe not all 800+ GB of it
|
||||||
|
# perhaps i ought to rethink how it's organized
|
||||||
"dev"
|
"dev"
|
||||||
# TODO: records should be private
|
|
||||||
"records"
|
|
||||||
"ref"
|
"ref"
|
||||||
"tmp"
|
|
||||||
"use"
|
"use"
|
||||||
"Books/local"
|
"Books/local"
|
||||||
"Music"
|
"Music"
|
||||||
"Pictures/albums"
|
|
||||||
"Pictures/cat"
|
|
||||||
"Pictures/from"
|
|
||||||
"Pictures/Screenshots" #< XXX: something is case-sensitive about this?
|
|
||||||
"Pictures/Photos"
|
|
||||||
"Videos/local"
|
|
||||||
|
|
||||||
# these are persisted simply to save on RAM.
|
# these are persisted simply to save on RAM.
|
||||||
# ~/.cache/nix can become several GB.
|
# ~/.cache/nix can become several GB.
|
||||||
@@ -25,7 +17,17 @@
|
|||||||
".cache/nix"
|
".cache/nix"
|
||||||
];
|
];
|
||||||
sane.user.persist.byStore.private = [
|
sane.user.persist.byStore.private = [
|
||||||
|
"archive"
|
||||||
|
"Pictures/albums"
|
||||||
|
"Pictures/cat"
|
||||||
|
"Pictures/from"
|
||||||
|
"Pictures/Screenshots" #< XXX: something is case-sensitive about this?
|
||||||
|
"Pictures/Photos"
|
||||||
|
"records"
|
||||||
|
"tmp"
|
||||||
|
|
||||||
"knowledge"
|
"knowledge"
|
||||||
|
"Videos/local"
|
||||||
];
|
];
|
||||||
|
|
||||||
# convenience
|
# convenience
|
||||||
@@ -34,7 +36,7 @@
|
|||||||
in {
|
in {
|
||||||
".persist/private" = lib.mkIf persistEnabled { symlink.target = config.sane.persist.stores.private.origin; };
|
".persist/private" = lib.mkIf persistEnabled { symlink.target = config.sane.persist.stores.private.origin; };
|
||||||
".persist/plaintext" = lib.mkIf persistEnabled { symlink.target = config.sane.persist.stores.plaintext.origin; };
|
".persist/plaintext" = lib.mkIf persistEnabled { symlink.target = config.sane.persist.stores.plaintext.origin; };
|
||||||
".persist/ephemeral" = lib.mkIf persistEnabled { symlink.target = config.sane.persist.stores.cryptClearOnBoot.origin; };
|
".persist/ephemeral" = lib.mkIf persistEnabled { symlink.target = config.sane.persist.stores.ephemeral.origin; };
|
||||||
|
|
||||||
"nixos".symlink.target = "dev/nixos";
|
"nixos".symlink.target = "dev/nixos";
|
||||||
|
|
||||||
|
@@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
systemd.network.enable = true;
|
systemd.network.enable = true;
|
||||||
networking.useNetworkd = true;
|
networking.useNetworkd = true;
|
||||||
|
networking.usePredictableInterfaceNames = false; #< set false to get `eth0`, `wlan0`, etc instead of `enp3s0`/etc
|
||||||
|
|
||||||
# view refused/dropped packets with: `sudo journalctl -k`
|
# view refused/dropped packets with: `sudo journalctl -k`
|
||||||
# networking.firewall.logRefusedPackets = true;
|
# networking.firewall.logRefusedPackets = true;
|
||||||
|
@@ -14,7 +14,6 @@
|
|||||||
# after = [ "polkit.service" ];
|
# after = [ "polkit.service" ];
|
||||||
# requires = [ "polkit.service" ];
|
# requires = [ "polkit.service" ];
|
||||||
wantedBy = [ "network.target" ]; #< default is `multi-user.target`, somehow it doesn't auto-start with that...
|
wantedBy = [ "network.target" ]; #< default is `multi-user.target`, somehow it doesn't auto-start with that...
|
||||||
path = [ "/run/current-system/sw" ]; #< so it can find `sanebox`
|
|
||||||
|
|
||||||
# serviceConfig.Type = "dbus";
|
# serviceConfig.Type = "dbus";
|
||||||
# serviceConfig.BusName = "org.freedesktop.ModemManager1";
|
# serviceConfig.BusName = "org.freedesktop.ModemManager1";
|
||||||
|
@@ -2,21 +2,28 @@
|
|||||||
let
|
let
|
||||||
# networkmanager = pkgs.networkmanager;
|
# networkmanager = pkgs.networkmanager;
|
||||||
networkmanager = pkgs.networkmanager.overrideAttrs (upstream: {
|
networkmanager = pkgs.networkmanager.overrideAttrs (upstream: {
|
||||||
src = pkgs.fetchFromGitea {
|
# src = pkgs.fetchFromGitea {
|
||||||
domain = "git.uninsane.org";
|
# domain = "git.uninsane.org";
|
||||||
owner = "colin";
|
# owner = "colin";
|
||||||
repo = "NetworkManager";
|
# repo = "NetworkManager";
|
||||||
# patched to fix polkit permissions (with `nmcli`) when NetworkManager runs as user networkmanager
|
# # patched to fix polkit permissions (with `nmcli`) when NetworkManager runs as user networkmanager
|
||||||
rev = "dev-sane-1.48.0";
|
# rev = "dev-sane-1.48.0";
|
||||||
hash = "sha256-vGmOKtwVItxjYioZJlb1og3K6u9s4rcmDnjAPLBC3ao=";
|
# hash = "sha256-vGmOKtwVItxjYioZJlb1og3K6u9s4rcmDnjAPLBC3ao=";
|
||||||
};
|
# };
|
||||||
# patches = [];
|
patches = (upstream.patches or []) ++ [
|
||||||
|
(pkgs.fetchpatch {
|
||||||
|
name = "polkit: add owner annotations to all actions";
|
||||||
|
url = "https://git.uninsane.org/colin/NetworkManager/commit/a01293861fa24201ffaeb84c07f1c71136c49759.patch";
|
||||||
|
hash = "sha256-th1/M2slo7rjkVBwETZII53Lmhyw8OMS0aT9QYI5Uvk=";
|
||||||
|
})
|
||||||
|
];
|
||||||
});
|
});
|
||||||
# split the package into `daemon` and `nmcli` outputs, because the networkmanager *service*
|
# split the package into `daemon` and `nmcli` outputs, because the networkmanager *service*
|
||||||
# doesn't need `nmcli`/`nmtui` tooling
|
# doesn't need `nmcli`/`nmtui` tooling
|
||||||
networkmanager-split = pkgs.networkmanager-split.override { inherit networkmanager; };
|
networkmanager-split = pkgs.networkmanager-split.override { inherit networkmanager; };
|
||||||
in {
|
in {
|
||||||
networking.networkmanager.enable = true;
|
networking.networkmanager.enable = true;
|
||||||
|
systemd.network.wait-online.enable = false; # systemd-networkd-wait-online.service reliably fails on lappy. docs don't match behavior. shit software.
|
||||||
# plugins mostly add support for establishing different VPN connections.
|
# plugins mostly add support for establishing different VPN connections.
|
||||||
# the default plugin set includes mostly proprietary VPNs:
|
# the default plugin set includes mostly proprietary VPNs:
|
||||||
# - fortisslvpn (Fortinet)
|
# - fortisslvpn (Fortinet)
|
||||||
@@ -199,6 +206,12 @@ in {
|
|||||||
logging.level = "INFO";
|
logging.level = "INFO";
|
||||||
|
|
||||||
# main.dhcp = "internal"; #< default
|
# main.dhcp = "internal"; #< default
|
||||||
|
# main.dns controls what to do when NM gets a DNS server via DHCP
|
||||||
|
# - "none" (populate /run/NetworkManager/resolv.conf with DHCP settings)
|
||||||
|
# - "internal" (?)
|
||||||
|
# - "systemd-resolved" (tell systemd-resolved about it, and point /run/NetworkManager/resolv.conf -> systemd)
|
||||||
|
# without this, systemd-resolved won't be able to resolve anything (because it has no upstream servers)
|
||||||
|
# note that NM's resolv.conf isn't (necessarily) /etc/resolv.conf -- that is managed by nixos (via symlinking)
|
||||||
main.dns = if config.services.resolved.enable then
|
main.dns = if config.services.resolved.enable then
|
||||||
"systemd-resolved"
|
"systemd-resolved"
|
||||||
else if config.sane.services.trust-dns.enable && config.sane.services.trust-dns.asSystemResolver then
|
else if config.sane.services.trust-dns.enable && config.sane.services.trust-dns.asSystemResolver then
|
||||||
|
@@ -1,17 +0,0 @@
|
|||||||
{ ... }:
|
|
||||||
|
|
||||||
{
|
|
||||||
# store /home/colin/a/b in /mnt/persist/private/a/b instead of /mnt/persist/private/home/colin/a/b
|
|
||||||
sane.persist.stores.private.prefix = "/home/colin";
|
|
||||||
|
|
||||||
sane.persist.sys.byStore.initrd = [
|
|
||||||
"/var/log"
|
|
||||||
];
|
|
||||||
sane.persist.sys.byStore.plaintext = [
|
|
||||||
# TODO: these should be private.. somehow
|
|
||||||
"/var/backup" # for e.g. postgres dumps
|
|
||||||
];
|
|
||||||
sane.persist.sys.byStore.cryptClearOnBoot = [
|
|
||||||
"/var/lib/systemd/coredump"
|
|
||||||
];
|
|
||||||
}
|
|
@@ -1,6 +1,6 @@
|
|||||||
# strictly *decrease* the scope of the default nixos installation/config
|
# strictly *decrease* the scope of the default nixos installation/config
|
||||||
|
|
||||||
{ lib, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
let
|
let
|
||||||
suidlessPam = pkgs.pam.overrideAttrs (upstream: {
|
suidlessPam = pkgs.pam.overrideAttrs (upstream: {
|
||||||
# nixpkgs' pam hardcodes unix_chkpwd path to the /run/wrappers one,
|
# nixpkgs' pam hardcodes unix_chkpwd path to the /run/wrappers one,
|
||||||
@@ -111,7 +111,11 @@ in
|
|||||||
# pkgs.which
|
# pkgs.which
|
||||||
# pkgs.zstd
|
# pkgs.zstd
|
||||||
];
|
];
|
||||||
in lib.filter (p: ! builtins.elem p requiredPackages);
|
conveniencePackages = [
|
||||||
|
config.boot.kernelPackages.cpupower # <repo:nixos/nixpkgs:nixos/modules/tasks/cpu-freq.nix> places it on PATH for convenience if powerManagement.cpuFreqGovernor is set
|
||||||
|
pkgs.kbd # <repo:nixos/nixpkgs:nixos/modules/config/console.nix> places it on PATH as part of console/virtual TTYs, but probably not needed unless you want to set console fonts
|
||||||
|
];
|
||||||
|
in lib.filter (p: ! builtins.elem p (requiredPackages ++ conveniencePackages));
|
||||||
};
|
};
|
||||||
|
|
||||||
options.system.fsPackages = lib.mkOption {
|
options.system.fsPackages = lib.mkOption {
|
||||||
@@ -212,5 +216,14 @@ in
|
|||||||
|
|
||||||
# see: <repo:nixos/nixpkgs:nixos/modules/virtualisation/nixos-containers.nix>
|
# see: <repo:nixos/nixpkgs:nixos/modules/virtualisation/nixos-containers.nix>
|
||||||
boot.enableContainers = lib.mkDefault false;
|
boot.enableContainers = lib.mkDefault false;
|
||||||
|
|
||||||
|
# see: <repo:nixos/nixpkgs:nixos/modules/tasks/lvm.nix>
|
||||||
|
# lvm places `pkgs.lvm2` onto PATH, which has like 100 binaries.
|
||||||
|
# it is, actually, needed for some userspace tools (cryptsetup). probably just the udev rules. try to reduce this set?
|
||||||
|
services.lvm.enable = lib.mkDefault false;
|
||||||
|
services.udev.packages = [ pkgs.lvm2.out ]; #< N.B. `lvm2.out` != `lvm2`
|
||||||
|
# systemd.packages = [ pkgs.lvm2 ];
|
||||||
|
# systemd.tmpfiles.packages = [ pkgs.lvm2.out ];
|
||||||
|
# environment.systemPackages = [ pkgs.lvm2 ];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -39,6 +39,7 @@ in
|
|||||||
"btrfs-progs"
|
"btrfs-progs"
|
||||||
"cacert.unbundled" # some services require unbundled /etc/ssl/certs
|
"cacert.unbundled" # some services require unbundled /etc/ssl/certs
|
||||||
"cryptsetup"
|
"cryptsetup"
|
||||||
|
"curl"
|
||||||
"ddrescue"
|
"ddrescue"
|
||||||
"dig"
|
"dig"
|
||||||
"dtc" # device tree [de]compiler
|
"dtc" # device tree [de]compiler
|
||||||
@@ -79,6 +80,7 @@ in
|
|||||||
"neovim"
|
"neovim"
|
||||||
"netcat"
|
"netcat"
|
||||||
"nethogs"
|
"nethogs"
|
||||||
|
"nix"
|
||||||
"nmap"
|
"nmap"
|
||||||
"nmcli"
|
"nmcli"
|
||||||
"nvme-cli" # nvme
|
"nvme-cli" # nvme
|
||||||
@@ -125,6 +127,7 @@ in
|
|||||||
# "dmidecode"
|
# "dmidecode"
|
||||||
"dtrx" # `unar` alternative, "Do The Right eXtraction"
|
"dtrx" # `unar` alternative, "Do The Right eXtraction"
|
||||||
# "efivar"
|
# "efivar"
|
||||||
|
"exiftool"
|
||||||
"eza" # a better 'ls'
|
"eza" # a better 'ls'
|
||||||
# "flashrom"
|
# "flashrom"
|
||||||
"git" # needed as a user package, for config.
|
"git" # needed as a user package, for config.
|
||||||
@@ -155,8 +158,13 @@ in
|
|||||||
# "python3.pkgs.eyeD3" # music tagging
|
# "python3.pkgs.eyeD3" # music tagging
|
||||||
"ripgrep" # needed as a user package so that its user-level config file can be installed
|
"ripgrep" # needed as a user package so that its user-level config file can be installed
|
||||||
"rsync"
|
"rsync"
|
||||||
|
"rsyslog" # KEEP THIS HERE if you want persistent logging
|
||||||
|
"sane-deadlines"
|
||||||
"sane-scripts.bittorrent"
|
"sane-scripts.bittorrent"
|
||||||
"sane-scripts.cli"
|
"sane-scripts.cli"
|
||||||
|
"sane-secrets-unlock"
|
||||||
|
"sane-sysload"
|
||||||
|
"sc-im"
|
||||||
# "snapper"
|
# "snapper"
|
||||||
"sops" # for manually viewing secrets; outside `sane-secrets` (TODO: improve sane-secrets!)
|
"sops" # for manually viewing secrets; outside `sane-secrets` (TODO: improve sane-secrets!)
|
||||||
"speedtest-cli"
|
"speedtest-cli"
|
||||||
@@ -321,6 +329,7 @@ in
|
|||||||
"vulkan-tools" # vulkaninfo
|
"vulkan-tools" # vulkaninfo
|
||||||
# "whalebird" # pleroma client (Electron). input is broken on phosh.
|
# "whalebird" # pleroma client (Electron). input is broken on phosh.
|
||||||
"xdg-terminal-exec"
|
"xdg-terminal-exec"
|
||||||
|
"youtube-tui"
|
||||||
"zathura" # PDF/CBZ/ePUB viewer
|
"zathura" # PDF/CBZ/ePUB viewer
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -332,6 +341,7 @@ in
|
|||||||
# "iotas" # note taking app
|
# "iotas" # note taking app
|
||||||
"komikku"
|
"komikku"
|
||||||
"koreader"
|
"koreader"
|
||||||
|
"lgtrombetta-compass"
|
||||||
"megapixels" # camera app
|
"megapixels" # camera app
|
||||||
"notejot" # note taking, e.g. shopping list
|
"notejot" # note taking, e.g. shopping list
|
||||||
"planify" # todo-tracker/planner
|
"planify" # todo-tracker/planner
|
||||||
@@ -377,7 +387,7 @@ in
|
|||||||
# "monero-gui" # x86-only
|
# "monero-gui" # x86-only
|
||||||
# "mumble"
|
# "mumble"
|
||||||
# "nheko" # Matrix chat client
|
# "nheko" # Matrix chat client
|
||||||
# "nicotine-plus" # soulseek client. before re-enabling this make sure it's properly sandboxed!
|
"nicotine-plus" # soulseek client
|
||||||
# "obsidian"
|
# "obsidian"
|
||||||
# "openscad" # 3d modeling
|
# "openscad" # 3d modeling
|
||||||
# "rhythmbox" # local music player
|
# "rhythmbox" # local music player
|
||||||
@@ -400,12 +410,6 @@ in
|
|||||||
|
|
||||||
backblaze-b2 = {};
|
backblaze-b2 = {};
|
||||||
|
|
||||||
bitcoind.sandbox.method = "bwrap";
|
|
||||||
bitcoind.sandbox.extraHomePaths = [
|
|
||||||
".config/bitcoin/bitcoin.conf"
|
|
||||||
];
|
|
||||||
bitcoind.sandbox.net = "all"; # actually needs only localhost
|
|
||||||
|
|
||||||
blanket.buildCost = 1;
|
blanket.buildCost = 1;
|
||||||
blanket.sandbox.method = "bwrap";
|
blanket.sandbox.method = "bwrap";
|
||||||
blanket.sandbox.whitelistAudio = true;
|
blanket.sandbox.whitelistAudio = true;
|
||||||
@@ -434,11 +438,6 @@ in
|
|||||||
|
|
||||||
clang = {};
|
clang = {};
|
||||||
|
|
||||||
clightning.sandbox.method = "bwrap";
|
|
||||||
clightning.sandbox.extraHomePaths = [
|
|
||||||
".lightning/bitcoin/lightning-rpc"
|
|
||||||
];
|
|
||||||
|
|
||||||
clightning-sane.sandbox.method = "bwrap";
|
clightning-sane.sandbox.method = "bwrap";
|
||||||
clightning-sane.sandbox.extraPaths = [
|
clightning-sane.sandbox.extraPaths = [
|
||||||
"/var/lib/clightning/bitcoin/lightning-rpc"
|
"/var/lib/clightning/bitcoin/lightning-rpc"
|
||||||
@@ -513,7 +512,7 @@ in
|
|||||||
electrum.sandbox.method = "bwrap"; # TODO:sandbox: untested
|
electrum.sandbox.method = "bwrap"; # TODO:sandbox: untested
|
||||||
electrum.sandbox.net = "all"; # TODO: probably want to make this run behind a VPN, always
|
electrum.sandbox.net = "all"; # TODO: probably want to make this run behind a VPN, always
|
||||||
electrum.sandbox.whitelistWayland = true;
|
electrum.sandbox.whitelistWayland = true;
|
||||||
electrum.persist.byStore.cryptClearOnBoot = [ ".electrum" ]; #< TODO: use XDG dirs!
|
electrum.persist.byStore.ephemeral = [ ".electrum" ]; #< TODO: use XDG dirs!
|
||||||
|
|
||||||
endless-sky.buildCost = 1;
|
endless-sky.buildCost = 1;
|
||||||
endless-sky.persist.byStore.plaintext = [ ".local/share/endless-sky" ];
|
endless-sky.persist.byStore.plaintext = [ ".local/share/endless-sky" ];
|
||||||
@@ -531,8 +530,10 @@ in
|
|||||||
ethtool.sandbox.capabilities = [ "net_admin" ];
|
ethtool.sandbox.capabilities = [ "net_admin" ];
|
||||||
|
|
||||||
# eza `ls` replacement
|
# eza `ls` replacement
|
||||||
# eza.sandbox.method = "landlock";
|
# bwrap causes `/proc` files to be listed differently (e.g. `eza /proc/sys/net/ipv6/conf/`)
|
||||||
eza.sandbox.method = "bwrap"; #< note that bwrap causes `/proc` files to be listed differently (e.g. `eza /proc/sys/net/ipv6/conf/`)
|
# bwrap loses group info (so files owned by other users appear as owner "nobody")
|
||||||
|
eza.sandbox.method = "landlock";
|
||||||
|
# eza.sandbox.method = "bwrap";
|
||||||
eza.sandbox.autodetectCliPaths = "existing";
|
eza.sandbox.autodetectCliPaths = "existing";
|
||||||
eza.sandbox.whitelistPwd = true;
|
eza.sandbox.whitelistPwd = true;
|
||||||
eza.sandbox.extraHomePaths = [
|
eza.sandbox.extraHomePaths = [
|
||||||
@@ -677,7 +678,7 @@ in
|
|||||||
"Pictures/Screenshots"
|
"Pictures/Screenshots"
|
||||||
"Pictures/servo-macros"
|
"Pictures/servo-macros"
|
||||||
];
|
];
|
||||||
gnome-frog.persist.byStore.cryptClearOnBoot = [
|
gnome-frog.persist.byStore.ephemeral = [
|
||||||
".local/share/tessdata" # 15M; dunno what all it is.
|
".local/share/tessdata" # 15M; dunno what all it is.
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -815,6 +816,14 @@ in
|
|||||||
libnotify.sandbox.method = "bwrap";
|
libnotify.sandbox.method = "bwrap";
|
||||||
libnotify.sandbox.whitelistDbus = [ "user" ]; # notify-send
|
libnotify.sandbox.whitelistDbus = [ "user" ]; # notify-send
|
||||||
|
|
||||||
|
lightning-cli.packageUnwrapped = pkgs.linkBinIntoOwnPackage pkgs.clightning "lightning-cli";
|
||||||
|
lightning-cli.sandbox.method = "bwrap";
|
||||||
|
lightning-cli.sandbox.extraHomePaths = [
|
||||||
|
".lightning/bitcoin/lightning-rpc"
|
||||||
|
];
|
||||||
|
# `lightning-cli` finds its RPC file via `~/.lightning/bitcoin/lightning-rpc`, to message the daemon
|
||||||
|
lightning-cli.fs.".lightning".symlink.target = "/var/lib/clightning";
|
||||||
|
|
||||||
losslesscut-bin.buildCost = 1;
|
losslesscut-bin.buildCost = 1;
|
||||||
losslesscut-bin.sandbox.method = "bwrap";
|
losslesscut-bin.sandbox.method = "bwrap";
|
||||||
losslesscut-bin.sandbox.extraHomePaths = [
|
losslesscut-bin.sandbox.extraHomePaths = [
|
||||||
@@ -891,7 +900,7 @@ in
|
|||||||
nixpkgs-review.sandbox.extraPaths = [
|
nixpkgs-review.sandbox.extraPaths = [
|
||||||
"/nix"
|
"/nix"
|
||||||
];
|
];
|
||||||
nixpkgs-review.persist.byStore.cryptClearOnBoot = [
|
nixpkgs-review.persist.byStore.ephemeral = [
|
||||||
".cache/nixpkgs-review" #< help it not exhaust / tmpfs
|
".cache/nixpkgs-review" #< help it not exhaust / tmpfs
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -942,7 +951,7 @@ in
|
|||||||
"/sys/devices"
|
"/sys/devices"
|
||||||
];
|
];
|
||||||
|
|
||||||
"perlPackages.FileMimeInfo".sandbox.enable = false; #< TODO: sandbox `mimetype` but not `mimeopen`.
|
"perlPackages.FileMimeInfo" = {};
|
||||||
|
|
||||||
powertop.sandbox.method = "landlock";
|
powertop.sandbox.method = "landlock";
|
||||||
powertop.sandbox.capabilities = [ "ipc_lock" "sys_admin" ];
|
powertop.sandbox.capabilities = [ "ipc_lock" "sys_admin" ];
|
||||||
@@ -1005,9 +1014,17 @@ in
|
|||||||
sane-weather.sandbox.method = "bwrap";
|
sane-weather.sandbox.method = "bwrap";
|
||||||
sane-weather.sandbox.net = "clearnet";
|
sane-weather.sandbox.net = "clearnet";
|
||||||
|
|
||||||
|
sc-im.sandbox.method = "bwrap";
|
||||||
|
sc-im.sandbox.autodetectCliPaths = "existingFile";
|
||||||
|
|
||||||
screen.sandbox.enable = false; #< tty; needs to run anything
|
screen.sandbox.enable = false; #< tty; needs to run anything
|
||||||
|
|
||||||
sequoia.sandbox.method = "bwrap"; # TODO:sandbox: untested
|
sequoia.packageUnwrapped = pkgs.sequoia.overrideAttrs (_: {
|
||||||
|
# XXX(2024-07-30): sq_autocrypt_import test failure: "Warning: 9B7DD433F254904A is expired."
|
||||||
|
doCheck = false;
|
||||||
|
});
|
||||||
|
sequoia.buildCost = 1;
|
||||||
|
sequoia.sandbox.method = "bwrap";
|
||||||
sequoia.sandbox.whitelistPwd = true;
|
sequoia.sandbox.whitelistPwd = true;
|
||||||
sequoia.sandbox.autodetectCliPaths = "existingFileOrParent"; # supports `-o <file-to-create>`
|
sequoia.sandbox.autodetectCliPaths = "existingFileOrParent"; # supports `-o <file-to-create>`
|
||||||
|
|
||||||
@@ -1164,10 +1181,12 @@ in
|
|||||||
|
|
||||||
# `wg`, `wg-quick`
|
# `wg`, `wg-quick`
|
||||||
wireguard-tools.sandbox.method = "landlock";
|
wireguard-tools.sandbox.method = "landlock";
|
||||||
|
wireguard-tools.sandbox.net = "all";
|
||||||
wireguard-tools.sandbox.capabilities = [ "net_admin" ];
|
wireguard-tools.sandbox.capabilities = [ "net_admin" ];
|
||||||
|
|
||||||
# provides `iwconfig`, `iwlist`, `iwpriv`, ...
|
# provides `iwconfig`, `iwlist`, `iwpriv`, ...
|
||||||
wirelesstools.sandbox.method = "landlock";
|
wirelesstools.sandbox.method = "landlock";
|
||||||
|
wirelesstools.sandbox.net = "all";
|
||||||
wirelesstools.sandbox.capabilities = [ "net_admin" ];
|
wirelesstools.sandbox.capabilities = [ "net_admin" ];
|
||||||
|
|
||||||
wl-clipboard.sandbox.method = "bwrap";
|
wl-clipboard.sandbox.method = "bwrap";
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
{ pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
{
|
{
|
||||||
sane.programs.ausyscall = {
|
sane.programs.ausyscall = {
|
||||||
packageUnwrapped = pkgs.linkIntoOwnPackage pkgs.audit "bin/ausyscall";
|
packageUnwrapped = pkgs.linkBinIntoOwnPackage pkgs.audit "ausyscall";
|
||||||
|
|
||||||
sandbox.method = "landlock";
|
sandbox.method = "landlock";
|
||||||
};
|
};
|
||||||
|
@@ -32,6 +32,7 @@
|
|||||||
# particularly, the default config disallows loopback, which is kinda fucking retarded, right?
|
# particularly, the default config disallows loopback, which is kinda fucking retarded, right?
|
||||||
"ens1" #< servo
|
"ens1" #< servo
|
||||||
"enp5s0" #< desko
|
"enp5s0" #< desko
|
||||||
|
"eth0"
|
||||||
"lo"
|
"lo"
|
||||||
"wg-home"
|
"wg-home"
|
||||||
"wlan0" #< moby
|
"wlan0" #< moby
|
||||||
|
13
hosts/common/programs/bitcoin-cli.nix
Normal file
13
hosts/common/programs/bitcoin-cli.nix
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{ pkgs, ... }:
|
||||||
|
{
|
||||||
|
sane.programs.bitcoin-cli = {
|
||||||
|
packageUnwrapped = pkgs.linkBinIntoOwnPackage pkgs.bitcoind "bitcoin-cli";
|
||||||
|
sandbox.method = "bwrap";
|
||||||
|
sandbox.autodetectCliPaths = "existing"; #< for `bitcoin-cli -datadir=/var/lib/...`
|
||||||
|
sandbox.extraHomePaths = [
|
||||||
|
".bitcoin/bitcoin.conf"
|
||||||
|
];
|
||||||
|
sandbox.net = "all"; # actually needs only localhost
|
||||||
|
secrets.".bitcoin/bitcoin.conf" = ../../../secrets/servo/bitcoin.conf.bin;
|
||||||
|
};
|
||||||
|
}
|
@@ -21,7 +21,7 @@
|
|||||||
sandbox.whitelistDri = true;
|
sandbox.whitelistDri = true;
|
||||||
sandbox.whitelistWayland = true;
|
sandbox.whitelistWayland = true;
|
||||||
|
|
||||||
persist.byStore.cryptClearOnBoot = [
|
persist.byStore.ephemeral = [
|
||||||
".cache/BraveSoftware"
|
".cache/BraveSoftware"
|
||||||
".config/BraveSoftware"
|
".config/BraveSoftware"
|
||||||
];
|
];
|
||||||
|
8
hosts/common/programs/curl.nix
Normal file
8
hosts/common/programs/curl.nix
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{ ... }:
|
||||||
|
{
|
||||||
|
sane.programs.curl = {
|
||||||
|
sandbox.method = "bwrap";
|
||||||
|
sandbox.net = "all";
|
||||||
|
sandbox.autodetectCliPaths = "parent"; #< for `-o` option
|
||||||
|
};
|
||||||
|
}
|
@@ -12,6 +12,7 @@
|
|||||||
./ausyscall.nix
|
./ausyscall.nix
|
||||||
./avahi.nix
|
./avahi.nix
|
||||||
./bemenu.nix
|
./bemenu.nix
|
||||||
|
./bitcoin-cli.nix
|
||||||
./blast-ugjka
|
./blast-ugjka
|
||||||
./bonsai.nix
|
./bonsai.nix
|
||||||
./brave.nix
|
./brave.nix
|
||||||
@@ -26,6 +27,7 @@
|
|||||||
./conky
|
./conky
|
||||||
./cozy.nix
|
./cozy.nix
|
||||||
./cups.nix
|
./cups.nix
|
||||||
|
./curl.nix
|
||||||
./curlftpfs.nix
|
./curlftpfs.nix
|
||||||
./dbus.nix
|
./dbus.nix
|
||||||
./dconf.nix
|
./dconf.nix
|
||||||
@@ -40,6 +42,7 @@
|
|||||||
./epiphany.nix
|
./epiphany.nix
|
||||||
./errno.nix
|
./errno.nix
|
||||||
./evince.nix
|
./evince.nix
|
||||||
|
./exiftool.nix
|
||||||
./fcitx5.nix
|
./fcitx5.nix
|
||||||
./feedbackd.nix
|
./feedbackd.nix
|
||||||
./firefox.nix
|
./firefox.nix
|
||||||
@@ -82,6 +85,7 @@
|
|||||||
./koreader
|
./koreader
|
||||||
./less.nix
|
./less.nix
|
||||||
./lftp.nix
|
./lftp.nix
|
||||||
|
./lgtrombetta-compass.nix
|
||||||
./libreoffice.nix
|
./libreoffice.nix
|
||||||
./lemoa.nix
|
./lemoa.nix
|
||||||
./loupe.nix
|
./loupe.nix
|
||||||
@@ -89,6 +93,7 @@
|
|||||||
./megapixels.nix
|
./megapixels.nix
|
||||||
./mepo.nix
|
./mepo.nix
|
||||||
./mimeo
|
./mimeo
|
||||||
|
./mimetype.nix
|
||||||
./mmcli.nix
|
./mmcli.nix
|
||||||
./mopidy.nix
|
./mopidy.nix
|
||||||
./mpv
|
./mpv
|
||||||
@@ -100,6 +105,7 @@
|
|||||||
./nheko.nix
|
./nheko.nix
|
||||||
./nicotine-plus.nix
|
./nicotine-plus.nix
|
||||||
./nix-index.nix
|
./nix-index.nix
|
||||||
|
./nix.nix
|
||||||
./nmcli.nix
|
./nmcli.nix
|
||||||
./notejot.nix
|
./notejot.nix
|
||||||
./ntfy-sh.nix
|
./ntfy-sh.nix
|
||||||
@@ -111,7 +117,7 @@
|
|||||||
./open-in-mpv.nix
|
./open-in-mpv.nix
|
||||||
./pactl.nix
|
./pactl.nix
|
||||||
./pidof.nix
|
./pidof.nix
|
||||||
./pipewire.nix
|
./pipewire
|
||||||
./pkill.nix
|
./pkill.nix
|
||||||
./planify.nix
|
./planify.nix
|
||||||
./portfolio-filemanager.nix
|
./portfolio-filemanager.nix
|
||||||
@@ -121,12 +127,16 @@
|
|||||||
./rhythmbox.nix
|
./rhythmbox.nix
|
||||||
./ripgrep.nix
|
./ripgrep.nix
|
||||||
./rofi
|
./rofi
|
||||||
|
./rsyslog
|
||||||
./rtkit.nix
|
./rtkit.nix
|
||||||
./s6-rc.nix
|
./s6-rc.nix
|
||||||
|
./sane-deadlines.nix
|
||||||
./sane-input-handler
|
./sane-input-handler
|
||||||
./sane-open.nix
|
./sane-open.nix
|
||||||
|
./sane-private-unlock-remote.nix
|
||||||
./sane-screenshot.nix
|
./sane-screenshot.nix
|
||||||
./sane-scripts.nix
|
./sane-scripts.nix
|
||||||
|
./sane-secrets-unlock.nix
|
||||||
./sane-sysload.nix
|
./sane-sysload.nix
|
||||||
./sane-theme.nix
|
./sane-theme.nix
|
||||||
./sanebox.nix
|
./sanebox.nix
|
||||||
@@ -173,6 +183,7 @@
|
|||||||
./xdg-desktop-portal-wlr.nix
|
./xdg-desktop-portal-wlr.nix
|
||||||
./xdg-terminal-exec.nix
|
./xdg-terminal-exec.nix
|
||||||
./xdg-utils.nix
|
./xdg-utils.nix
|
||||||
|
./youtube-tui.nix
|
||||||
./zathura.nix
|
./zathura.nix
|
||||||
./zeal.nix
|
./zeal.nix
|
||||||
./zecwallet-lite.nix
|
./zecwallet-lite.nix
|
||||||
|
@@ -32,6 +32,7 @@ in
|
|||||||
startCommand = "eg25-control --enable-gps --dump-debug-info --verbose";
|
startCommand = "eg25-control --enable-gps --dump-debug-info --verbose";
|
||||||
cleanupCommand = "eg25-control --disable-gps --dump-debug-info --verbose";
|
cleanupCommand = "eg25-control --disable-gps --dump-debug-info --verbose";
|
||||||
depends = [ "eg25-control-powered" ];
|
depends = [ "eg25-control-powered" ];
|
||||||
|
partOf = [ "gps" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
persist.byStore.plaintext = [ ".cache/eg25-control" ]; #< for cached agps data
|
persist.byStore.plaintext = [ ".cache/eg25-control" ]; #< for cached agps data
|
||||||
|
@@ -45,6 +45,9 @@
|
|||||||
"Videos/servo"
|
"Videos/servo"
|
||||||
"tmp"
|
"tmp"
|
||||||
];
|
];
|
||||||
|
sandbox.extraPaths = [
|
||||||
|
"/dev/snd" #< needed only when playing embedded audio (not embedded video!)
|
||||||
|
];
|
||||||
|
|
||||||
# creds/session keys, etc
|
# creds/session keys, etc
|
||||||
persist.byStore.private = [ ".config/Element" ];
|
persist.byStore.private = [ ".config/Element" ];
|
||||||
|
@@ -1,19 +1,15 @@
|
|||||||
{ pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
{
|
{
|
||||||
sane.programs.errno = {
|
sane.programs.errno = {
|
||||||
# packageUnwrapped = pkgs.linkIntoOwnPackage pkgs.moreutils "bin/errno";
|
# packageUnwrapped = pkgs.linkBinIntoOwnPackage pkgs.moreutils "errno";
|
||||||
# actually, don't build all of moreutils because not all of it builds for cross targets.
|
# 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: {
|
packageUnwrapped = pkgs.moreutils.overrideAttrs (base: {
|
||||||
makeFlags = (base.makeFlags or []) ++ [
|
makeFlags = (base.makeFlags or []) ++ [
|
||||||
"BINS=errno"
|
"BINS=errno"
|
||||||
"MANS=errno.1"
|
"MANS=errno.1"
|
||||||
"PERLSCRIPTS=errno" #< Makefile errors if empty, but this works :)
|
"PERLSCRIPTS=errno" #< Makefile errors if empty, but this works :)
|
||||||
"INSTALL_BIN=install"
|
|
||||||
];
|
];
|
||||||
#v disable the perl-specific stuff
|
buildInputs = []; #< errno has no runtime perl deps, and they don't cross compile, so disable them.
|
||||||
propagatedBuildInputs = [];
|
|
||||||
postInstall = "";
|
|
||||||
});
|
});
|
||||||
|
|
||||||
sandbox.method = "landlock";
|
sandbox.method = "landlock";
|
||||||
|
7
hosts/common/programs/exiftool.nix
Normal file
7
hosts/common/programs/exiftool.nix
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{ ... }:
|
||||||
|
{
|
||||||
|
sane.programs.exiftool = {
|
||||||
|
sandbox.method = "bwrap";
|
||||||
|
sandbox.autodetectCliPaths = "existingFile";
|
||||||
|
};
|
||||||
|
}
|
@@ -105,6 +105,22 @@ let
|
|||||||
};
|
};
|
||||||
# extraPrefs = ...
|
# extraPrefs = ...
|
||||||
}).overrideAttrs (base: {
|
}).overrideAttrs (base: {
|
||||||
|
nativeBuildInputs = (base.nativeBuildInputs or []) ++ [
|
||||||
|
pkgs.copyDesktopItems
|
||||||
|
];
|
||||||
|
desktopItems = (base.desktopItems or []) ++ [
|
||||||
|
(pkgs.makeDesktopItem {
|
||||||
|
name = "${cfg.browser.libName}-in-vpn";
|
||||||
|
desktopName = "${cfg.browser.libName} (VPN)";
|
||||||
|
genericName = "Web Browser";
|
||||||
|
# N.B.: --new-instance ensures we don't reuse an existing non-vpn instance.
|
||||||
|
# OTOH, it may error about "only one instance can run at a time": close the non-VPN instance if you see that.
|
||||||
|
exec = "${lib.getExe pkgs.sane-scripts.vpn} do - -- ${cfg.browser.libName} --new-instance";
|
||||||
|
icon = cfg.browser.libName;
|
||||||
|
categories = [ "Network" "WebBrowser" ];
|
||||||
|
type = "Application";
|
||||||
|
})
|
||||||
|
];
|
||||||
# de-associate `ctrl+shift+c` from activating the devtools.
|
# de-associate `ctrl+shift+c` from activating the devtools.
|
||||||
# based on <https://stackoverflow.com/a/54260938>
|
# based on <https://stackoverflow.com/a/54260938>
|
||||||
# TODO: could use `zip -f` to only update the one changed file, instead of rezipping everything.
|
# TODO: could use `zip -f` to only update the one changed file, instead of rezipping everything.
|
||||||
@@ -130,7 +146,8 @@ let
|
|||||||
echo "omni.ja AFTER:"
|
echo "omni.ja AFTER:"
|
||||||
ls -l $out/lib/${cfg.browser.libName}/browser/omni.ja
|
ls -l $out/lib/${cfg.browser.libName}/browser/omni.ja
|
||||||
|
|
||||||
# runHook postFixup to allow sane.programs sandbox wrappers to wrap the binaries
|
runHook postBuild
|
||||||
|
runHook postInstall
|
||||||
runHook postFixup
|
runHook postFixup
|
||||||
'';
|
'';
|
||||||
});
|
});
|
||||||
@@ -160,7 +177,7 @@ let
|
|||||||
persistCache = mkOption {
|
persistCache = mkOption {
|
||||||
description = "optional store name to which persist browser cache";
|
description = "optional store name to which persist browser cache";
|
||||||
type = types.nullOr types.str;
|
type = types.nullOr types.str;
|
||||||
default = "cryptClearOnBoot";
|
default = "ephemeral";
|
||||||
};
|
};
|
||||||
addons = mkOption {
|
addons = mkOption {
|
||||||
type = types.attrsOf addonOpts;
|
type = types.attrsOf addonOpts;
|
||||||
@@ -263,7 +280,7 @@ in
|
|||||||
# TODO: find a way to not expose ~/.ssh to firefox
|
# TODO: find a way to not expose ~/.ssh to firefox
|
||||||
# - unlock sops at login (or before firefox launch)?
|
# - unlock sops at login (or before firefox launch)?
|
||||||
# - see if ssh has a more formal type of subkey system?
|
# - see if ssh has a more formal type of subkey system?
|
||||||
".ssh/id_ed25519"
|
# ".ssh/id_ed25519"
|
||||||
# ".config/sops"
|
# ".config/sops"
|
||||||
"knowledge/secrets/accounts"
|
"knowledge/secrets/accounts"
|
||||||
];
|
];
|
||||||
@@ -372,14 +389,14 @@ in
|
|||||||
if (cfg.persistData != null) then
|
if (cfg.persistData != null) then
|
||||||
cfg.persistData
|
cfg.persistData
|
||||||
else
|
else
|
||||||
"cryptClearOnBoot"
|
"ephemeral"
|
||||||
;
|
;
|
||||||
|
|
||||||
persist.byPath."${cfg.browser.dotDir}/default".store =
|
persist.byPath."${cfg.browser.dotDir}/default".store =
|
||||||
if (cfg.persistData != null) then
|
if (cfg.persistData != null) then
|
||||||
cfg.persistData
|
cfg.persistData
|
||||||
else
|
else
|
||||||
"cryptClearOnBoot"
|
"ephemeral"
|
||||||
;
|
;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
{ pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
{
|
{
|
||||||
sane.programs.free = {
|
sane.programs.free = {
|
||||||
packageUnwrapped = pkgs.linkIntoOwnPackage pkgs.procps "bin/free";
|
packageUnwrapped = pkgs.linkBinIntoOwnPackage pkgs.procps "free";
|
||||||
sandbox.method = "bwrap";
|
sandbox.method = "bwrap";
|
||||||
sandbox.isolatePids = false;
|
sandbox.isolatePids = false;
|
||||||
};
|
};
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
{ pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
{
|
{
|
||||||
sane.programs.gdbus = {
|
sane.programs.gdbus = {
|
||||||
packageUnwrapped = pkgs.linkIntoOwnPackage pkgs.glib "bin/gdbus";
|
packageUnwrapped = pkgs.linkBinIntoOwnPackage pkgs.glib "gdbus";
|
||||||
|
|
||||||
sandbox.method = "bwrap";
|
sandbox.method = "bwrap";
|
||||||
sandbox.whitelistDbus = [ "user" ]; #< XXX: maybe future users will also want system access
|
sandbox.whitelistDbus = [ "user" ]; #< XXX: maybe future users will also want system access
|
||||||
|
@@ -41,14 +41,15 @@ in
|
|||||||
echo "using $dev for GPS NMEA"
|
echo "using $dev for GPS NMEA"
|
||||||
gps-share "$dev"
|
gps-share "$dev"
|
||||||
'';
|
'';
|
||||||
# TODO: this should be `partOf = [ "gps" ]`:
|
# N.B.: it fails to launch if the NMEA device doesn't yet exist, so don't launch by default; only launch as part of GPS
|
||||||
# it fails to launch if the NMEA device doesn't yet exist, and so restart loop when modem is not booted
|
# dependencyOf = [ "geoclue-agent" ];
|
||||||
dependencyOf = [ "geoclue-agent" ];
|
partOf = [ "gps" ];
|
||||||
|
depends = [ "eg25-control-powered" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
sandbox.method = "bwrap";
|
sandbox.method = "bwrap";
|
||||||
sandbox.net = "all";
|
sandbox.net = "all";
|
||||||
sandbox.autodetectCliPaths = "existingFile";
|
sandbox.autodetectCliPaths = "existing"; #< N.B.: `test -f /dev/ttyUSB1` fails, we can't use `existingFile`
|
||||||
};
|
};
|
||||||
|
|
||||||
# TODO: restrict this to just LAN devices!!
|
# TODO: restrict this to just LAN devices!!
|
||||||
|
@@ -5,10 +5,9 @@
|
|||||||
{ pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
{
|
{
|
||||||
sane.programs.gst-device-monitor = {
|
sane.programs.gst-device-monitor = {
|
||||||
packageUnwrapped = (pkgs.linkIntoOwnPackage pkgs.gst_all_1.gst-plugins-base [
|
packageUnwrapped = (
|
||||||
"bin/gst-device-monitor-1.0"
|
pkgs.linkBinIntoOwnPackage pkgs.gst_all_1.gst-plugins-base "gst-device-monitor-1.0"
|
||||||
"share/man/man1/gst-device-monitor-1.0.1.gz"
|
).overrideAttrs (base: {
|
||||||
]).overrideAttrs (base: {
|
|
||||||
# XXX the binaries need `GST_PLUGIN_SYSTEM_PATH_1_0` set to function,
|
# XXX the binaries need `GST_PLUGIN_SYSTEM_PATH_1_0` set to function,
|
||||||
# but nixpkgs doesn't set those (TODO: upstream this!)
|
# but nixpkgs doesn't set those (TODO: upstream this!)
|
||||||
nativeBuildInputs = (base.nativeBuildInputs or []) ++ [
|
nativeBuildInputs = (base.nativeBuildInputs or []) ++ [
|
||||||
|
@@ -1,13 +1,6 @@
|
|||||||
{ pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
{
|
{
|
||||||
sane.programs.kdenlive = {
|
sane.programs.kdenlive = {
|
||||||
packageUnwrapped = pkgs.kdenlive.override {
|
|
||||||
ffmpeg-full = pkgs.ffmpeg-full.override {
|
|
||||||
# avoid expensive samba build for a feature i don't use
|
|
||||||
withSamba = false;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
buildCost = 1;
|
buildCost = 1;
|
||||||
|
|
||||||
sandbox.method = "bwrap";
|
sandbox.method = "bwrap";
|
||||||
|
@@ -3,10 +3,10 @@
|
|||||||
sane.programs.komikku = {
|
sane.programs.komikku = {
|
||||||
packageUnwrapped = pkgs.komikku.overrideAttrs (upstream: {
|
packageUnwrapped = pkgs.komikku.overrideAttrs (upstream: {
|
||||||
preFixup = ''
|
preFixup = ''
|
||||||
# 2024/02/21: render bug which affects only moby:
|
# 2024/07/25: Komikku uses XDG_SESSION_TYPE in the webkitgtk useragent, and errors if it's empty.
|
||||||
# large images render blank in several gtk applications.
|
# XDG_SESSION_DESKTOP is used similarly in debug_info.py.
|
||||||
# may resolve itself as gtk or mesa are updated.
|
# TODO: patch/upstream Komikku
|
||||||
gappsWrapperArgs+=(--set GSK_RENDERER cairo)
|
gappsWrapperArgs+=(--set-default XDG_SESSION_TYPE "unknown" --set-default XDG_SESSION_DESKTOP "unknown")
|
||||||
'' + (upstream.preFixup or "");
|
'' + (upstream.preFixup or "");
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -24,5 +24,8 @@
|
|||||||
# also writes to ~/.cache/komikku
|
# also writes to ~/.cache/komikku
|
||||||
".local/share/komikku"
|
".local/share/komikku"
|
||||||
];
|
];
|
||||||
|
persist.byStore.ephemeral = [
|
||||||
|
".cache/komikku"
|
||||||
|
];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -9,5 +9,6 @@
|
|||||||
"Videos/servo"
|
"Videos/servo"
|
||||||
"tmp"
|
"tmp"
|
||||||
];
|
];
|
||||||
|
sandbox.whitelistPwd = true; #< it's very common to upload/DL to/from the current folder
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
26
hosts/common/programs/lgtrombetta-compass.nix
Normal file
26
hosts/common/programs/lgtrombetta-compass.nix
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
{ ... }:
|
||||||
|
{
|
||||||
|
sane.programs.lgtrombetta-compass = {
|
||||||
|
# example compass.conf, calibrated well
|
||||||
|
# [settings]
|
||||||
|
# version = 0.4.0
|
||||||
|
# theme = dark
|
||||||
|
#
|
||||||
|
# [device]
|
||||||
|
# name = AF8133J
|
||||||
|
# magn_x_offset = 281
|
||||||
|
# magn_y_offset = -35
|
||||||
|
# magn_z_offset = 537
|
||||||
|
#
|
||||||
|
persist.byStore.plaintext = [
|
||||||
|
".config/compass"
|
||||||
|
];
|
||||||
|
fs.".config/compass.conf".symlink.target = "compass/compass.conf";
|
||||||
|
|
||||||
|
sandbox.method = "bwrap";
|
||||||
|
sandbox.extraPaths = [
|
||||||
|
"/sys/bus/iio/devices"
|
||||||
|
"/sys/devices"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
@@ -2,14 +2,15 @@
|
|||||||
{
|
{
|
||||||
sane.programs.loupe = {
|
sane.programs.loupe = {
|
||||||
# loupe is marked "dbus activatable", which does not seem to actually work (at least when launching from Firefox or Nautilus)
|
# loupe is marked "dbus activatable", which does not seem to actually work (at least when launching from Firefox or Nautilus)
|
||||||
packageUnwrapped = pkgs.rmDbusServicesInPlace (pkgs.loupe.overrideAttrs (upstream: {
|
packageUnwrapped = pkgs.rmDbusServicesInPlace pkgs.loupe;
|
||||||
preFixup = (upstream.preFixup or "") + ''
|
# .overrideAttrs (upstream: {
|
||||||
# 2024/02/21: render bug which affects only moby:
|
# preFixup = (upstream.preFixup or "") + ''
|
||||||
# large images render blank in several gtk applications.
|
# # 2024/02/21: render bug which affects only moby:
|
||||||
# may resolve itself as gtk or mesa are updated.
|
# # large images render blank in several gtk applications.
|
||||||
gappsWrapperArgs+=(--set GSK_RENDERER cairo)
|
# # may resolve itself as gtk or mesa are updated.
|
||||||
'';
|
# gappsWrapperArgs+=(--set GSK_RENDERER cairo)
|
||||||
}));
|
# '';
|
||||||
|
# }));
|
||||||
|
|
||||||
sandbox.method = "bwrap";
|
sandbox.method = "bwrap";
|
||||||
sandbox.whitelistWayland = true;
|
sandbox.whitelistWayland = true;
|
||||||
|
8
hosts/common/programs/mimetype.nix
Normal file
8
hosts/common/programs/mimetype.nix
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{ pkgs, ... }:
|
||||||
|
{
|
||||||
|
sane.programs.mimetype = {
|
||||||
|
packageUnwrapped = pkgs.linkBinIntoOwnPackage pkgs.perlPackages.FileMimeInfo "mimetype";
|
||||||
|
sandbox.method = "bwrap";
|
||||||
|
sandbox.autodetectCliPaths = "existing";
|
||||||
|
};
|
||||||
|
}
|
@@ -149,8 +149,9 @@ in
|
|||||||
pkgs.mpvScripts.mpris
|
pkgs.mpvScripts.mpris
|
||||||
pkgs.mpvScripts.mpv-playlistmanager
|
pkgs.mpvScripts.mpv-playlistmanager
|
||||||
pkgs.mpvScripts.mpv-webm
|
pkgs.mpvScripts.mpv-webm
|
||||||
|
pkgs.mpvScripts.sponsorblock
|
||||||
uosc
|
uosc
|
||||||
visualizer
|
# visualizer #< XXX(2024-07-23): `visualizer` breaks auto-play-next-track (only when visualizations are disabled)
|
||||||
# pkgs.mpv-uosc-latest
|
# pkgs.mpv-uosc-latest
|
||||||
];
|
];
|
||||||
# extraMakeWrapperArgs = lib.optionals (cfg.config.vo != null) [
|
# extraMakeWrapperArgs = lib.optionals (cfg.config.vo != null) [
|
||||||
@@ -223,12 +224,13 @@ in
|
|||||||
fs.".config/mpv/scripts/sane_sysvol/non_blocking_popen.lua".symlink.target = ./sane_sysvol/non_blocking_popen.lua;
|
fs.".config/mpv/scripts/sane_sysvol/non_blocking_popen.lua".symlink.target = ./sane_sysvol/non_blocking_popen.lua;
|
||||||
fs.".config/mpv/input.conf".symlink.target = ./input.conf;
|
fs.".config/mpv/input.conf".symlink.target = ./input.conf;
|
||||||
fs.".config/mpv/mpv.conf".symlink.target = ./mpv.conf;
|
fs.".config/mpv/mpv.conf".symlink.target = ./mpv.conf;
|
||||||
fs.".config/mpv/script-opts/osc.conf".symlink.target = ./osc.conf;
|
|
||||||
fs.".config/mpv/script-opts/console.conf".symlink.target = ./console.conf;
|
fs.".config/mpv/script-opts/console.conf".symlink.target = ./console.conf;
|
||||||
fs.".config/mpv/script-opts/uosc.conf".symlink.target = ./uosc.conf;
|
fs.".config/mpv/script-opts/osc.conf".symlink.target = ./osc.conf;
|
||||||
fs.".config/mpv/script-opts/playlistmanager.conf".symlink.target = ./playlistmanager.conf;
|
fs.".config/mpv/script-opts/playlistmanager.conf".symlink.target = ./playlistmanager.conf;
|
||||||
fs.".config/mpv/script-opts/webm.conf".symlink.target = ./webm.conf;
|
fs.".config/mpv/script-opts/sponsorblock.conf".symlink.target = ./sponsorblock.conf;
|
||||||
|
fs.".config/mpv/script-opts/uosc.conf".symlink.target = ./uosc.conf;
|
||||||
fs.".config/mpv/script-opts/visualizer.conf".symlink.target = ./visualizer.conf;
|
fs.".config/mpv/script-opts/visualizer.conf".symlink.target = ./visualizer.conf;
|
||||||
|
fs.".config/mpv/script-opts/webm.conf".symlink.target = ./webm.conf;
|
||||||
|
|
||||||
# mime.priority = 200; # default = 100; 200 means to yield to other apps
|
# mime.priority = 200; # default = 100; 200 means to yield to other apps
|
||||||
mime.priority = 50; # default = 100; 50 in order to take precedence over vlc.
|
mime.priority = 50; # default = 100; 50 in order to take precedence over vlc.
|
||||||
@@ -242,9 +244,12 @@ in
|
|||||||
mime.associations."video/x-flv" = "mpv.desktop";
|
mime.associations."video/x-flv" = "mpv.desktop";
|
||||||
mime.associations."video/x-matroska" = "mpv.desktop";
|
mime.associations."video/x-matroska" = "mpv.desktop";
|
||||||
mime.urlAssociations."^https?://(m\.)?(www\.)?youtu.be/.+" = "mpv.desktop";
|
mime.urlAssociations."^https?://(m\.)?(www\.)?youtu.be/.+" = "mpv.desktop";
|
||||||
|
mime.urlAssociations."^https?://(m\.)?(www\.)?youtube.com/embed/.+" = "mpv.desktop";
|
||||||
|
mime.urlAssociations."^https?://(m\.)?(www\.)?youtube.com/playlist\?.*list=.+" = "mpv.desktop";
|
||||||
mime.urlAssociations."^https?://(m\.)?(www\.)?youtube.com/shorts/.+" = "mpv.desktop";
|
mime.urlAssociations."^https?://(m\.)?(www\.)?youtube.com/shorts/.+" = "mpv.desktop";
|
||||||
mime.urlAssociations."^https?://(m\.)?(www\.)?youtube.com/v/" = "mpv.desktop";
|
mime.urlAssociations."^https?://(m\.)?(www\.)?youtube.com/v/.+" = "mpv.desktop";
|
||||||
mime.urlAssociations."^https?://(m\.)?(www\.)?youtube.com/watch\?.*v=" = "mpv.desktop";
|
mime.urlAssociations."^https?://(m\.)?(www\.)?youtube.com/watch\?.*v=.+" = "mpv.desktop";
|
||||||
|
#v Loupe image viewer can't open URIs, so use mpv instead
|
||||||
|
mime.urlAssociations."^https?://i\.imgur.com/.+" = "mpv.desktop";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -16,25 +16,27 @@ MBTN_LEFT_DBL ignore
|
|||||||
# text after the shebang is parsed by uosc to construct the menu and names
|
# text after the shebang is parsed by uosc to construct the menu and names
|
||||||
menu script-binding uosc/menu
|
menu script-binding uosc/menu
|
||||||
s script-binding uosc/subtitles #! Subtitles
|
s script-binding uosc/subtitles #! Subtitles
|
||||||
a script-binding uosc/audio #! Audio tracks
|
a script-binding uosc/audio #! Audio track
|
||||||
q script-binding uosc/stream-quality #! Stream quality
|
q script-binding uosc/stream-quality #! Stream quality
|
||||||
p script-binding uosc/items #! Playlist
|
# script-binding uosc/audio-device #! Audio device
|
||||||
# c script-binding uosc/chapters #! Chapters
|
ctrl+r script-binding sane_cast/blast #! Audiocast
|
||||||
> script-binding uosc/next #! Navigation > Next
|
ctrl+t script-binding sane_cast/sane-cast #! Cast
|
||||||
< script-binding uosc/prev #! Navigation > Prev
|
ctrl+s async screenshot #! Screenshot
|
||||||
o script-binding uosc/open-file #! Navigation > Open file
|
O script-binding uosc/show-in-directory #! Open folder
|
||||||
# set video-aspect-override "-1" #! Utils > Aspect ratio > Default
|
|
||||||
# set video-aspect-override "16:9" #! Utils > Aspect ratio > 16:9
|
|
||||||
# set video-aspect-override "4:3" #! Utils > Aspect ratio > 4:3
|
|
||||||
# set video-aspect-override "2.35:1" #! Utils > Aspect ratio > 2.35:1
|
|
||||||
# script-binding uosc/audio-device #! Utils > Audio devices
|
|
||||||
# script-binding uosc/editions #! Utils > Editions
|
|
||||||
ctrl+s async screenshot #! Utils > Screenshot
|
|
||||||
alt+i script-binding uosc/keybinds #! Utils > Key bindings
|
|
||||||
O script-binding uosc/show-in-directory #! Utils > Show in directory
|
|
||||||
# script-binding uosc/open-config-directory #! Utils > Open config directory
|
|
||||||
ctrl+r script-binding sane_cast/blast #! Audiocast
|
|
||||||
ctrl+t script-binding sane_cast/sane-cast #! Cast
|
|
||||||
|
|
||||||
# reserved: it uses this internally, isn't externally callable
|
# uosc defaults, kept here but unused
|
||||||
|
p script-binding uosc/items # Playlist
|
||||||
|
# script-binding uosc/chapters # Chapters
|
||||||
|
> script-binding uosc/next # Navigation > Next
|
||||||
|
< script-binding uosc/prev # Navigation > Prev
|
||||||
|
o script-binding uosc/open-file # Navigation > Open file
|
||||||
|
# set video-aspect-override "-1" # Utils > Aspect ratio > Default
|
||||||
|
# set video-aspect-override "16:9" # Utils > Aspect ratio > 16:9
|
||||||
|
# set video-aspect-override "4:3" # Utils > Aspect ratio > 4:3
|
||||||
|
# set video-aspect-override "2.35:1" # Utils > Aspect ratio > 2.35:1
|
||||||
|
# script-binding uosc/editions # Utils > Editions
|
||||||
|
# script-binding uosc/open-config-directory # Utils > Open config directory
|
||||||
|
alt+i script-binding uosc/keybinds # Utils > Key bindings
|
||||||
|
#
|
||||||
|
# mpv-visualizer: reserved: it uses this internally, isn't externally callable
|
||||||
# v script-binding cycle-visualizer
|
# v script-binding cycle-visualizer
|
||||||
|
19
hosts/common/programs/mpv/sponsorblock.conf
Normal file
19
hosts/common/programs/mpv/sponsorblock.conf
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
## options: <https://github.com/po5/mpv_sponsorblock/blob/master/sponsorblock.lua#L8>
|
||||||
|
audio_fade=yes
|
||||||
|
### audio_fade_step: 0 - 100
|
||||||
|
### how rapidly to fade the volume into/out of sponsor segments (%/100ms).
|
||||||
|
### note that this doesn't impact the time at which the fade starts: that's fixed to 1.0s before the transitions
|
||||||
|
# audio_fade_step=2
|
||||||
|
# local_pattern uses lua's string matching, an excepts to yield a 11 character ID: <https://www.lua.org/manual/5.3/manual.html#6.4.1>
|
||||||
|
# local_pattern=-([%w-_]+)%.[mw][kpe][v4b]m?$ #< default; broken
|
||||||
|
# local_pattern=%[([%w-_]+)%]%..* #< described by tomasklaen <https://github.com/po5/mpv_sponsorblock/issues/67>
|
||||||
|
# local_pattern=[ %p]([%w-_]+)%p.webm$ #< works; only webm
|
||||||
|
# local_pattern=[ %p]([%w-_]+)%p.[mw][kpe][v4b]m?$ #< works, by merging the above
|
||||||
|
local_pattern=%[([%w-_]+)%]%..*
|
||||||
|
min_duration=10
|
||||||
|
report_views=no
|
||||||
|
# XXX(2024-07-22) local_database/server_fallback are unmaintained <https://github.com/po5/mpv_sponsorblock/commit/d05c6e7a5675ef6582e60abe853e9aec535c3ea3>
|
||||||
|
# local_database=yes
|
||||||
|
# server_fallback=no
|
||||||
|
# skip_categories=sponsor,intro,outro,interaction,selfpromo,filler
|
||||||
|
skip_categories=sponsor,intro
|
@@ -5,14 +5,15 @@
|
|||||||
timeline_style=bar
|
timeline_style=bar
|
||||||
timeline_line_width=4
|
timeline_line_width=4
|
||||||
timeline_size=36
|
timeline_size=36
|
||||||
timeline_persistency=paused,audio
|
# persistency options (comma-separated): paused, audio, image, video, idle, windowed, fullscreen
|
||||||
controls_persistency=paused,audio
|
timeline_persistency=audio,paused
|
||||||
|
controls_persistency=audio,paused,windowed
|
||||||
volume_persistency=audio
|
volume_persistency=audio
|
||||||
|
|
||||||
# speed_persistency=paused,audio
|
# speed_persistency=paused,audio
|
||||||
# vvv want a close button?
|
# vvv want a close button?
|
||||||
top_bar=always
|
top_bar=always
|
||||||
top_bar_persistency=paused,audio
|
top_bar_persistency=paused,audio,windowed
|
||||||
|
|
||||||
controls=menu,<video>subtitles,<has_many_audio>audio,<has_many_video>video,<has_many_edition>editions,<stream>stream-quality,space,command:replay_10:seek -10,cycle:play_arrow:pause:no=pause/yes=play_arrow,command:forward_30:seek 30,space,speed:1.0,gap,<video>fullscreen
|
controls=menu,<video>subtitles,<has_many_audio>audio,<has_many_video>video,<has_many_edition>editions,<stream>stream-quality,space,command:replay_10:seek -10,cycle:play_arrow:pause:no=pause/yes=play_arrow,command:forward_30:seek 30,space,speed:1.0,gap,<video>fullscreen
|
||||||
|
|
||||||
@@ -30,3 +31,6 @@ color=foreground=ff968b,background_text=ff968b
|
|||||||
opacity=timeline=0.8,position=1,chapters=0.8,slider=0.8,slider_gauge=0.8,controls=0,speed=0.8,menu=1,submenu=0.4,border=1,title=0.8,tooltip=1,thumbnail=1,curtain=0.8,idle_indicator=0.8,audio_indicator=0.5,buffering_indicator=0.3,playlist_position=0.8
|
opacity=timeline=0.8,position=1,chapters=0.8,slider=0.8,slider_gauge=0.8,controls=0,speed=0.8,menu=1,submenu=0.4,border=1,title=0.8,tooltip=1,thumbnail=1,curtain=0.8,idle_indicator=0.8,audio_indicator=0.5,buffering_indicator=0.3,playlist_position=0.8
|
||||||
|
|
||||||
stream_quality_options=1440,1080,720,480,360,240,144
|
stream_quality_options=1440,1080,720,480,360,240,144
|
||||||
|
|
||||||
|
# default open-file menu directory
|
||||||
|
default_directory=~/Music
|
||||||
|
@@ -1,13 +1,35 @@
|
|||||||
# soulseek filesharing GUI app
|
# soulseek music sharing GUI app
|
||||||
{ pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
{
|
{
|
||||||
sane.programs.nicotine-plus = {
|
sane.programs.nicotine-plus = {
|
||||||
|
packageUnwrapped = pkgs.nicotine-plus.overrideAttrs (upstream: {
|
||||||
|
# nicotine gets confused by permissions. it needs a *writeable* config or config.old to use either.
|
||||||
|
# but the secrets are not writable.
|
||||||
|
# so, copy config (the secret) to config.old on launch & make it writeable.
|
||||||
|
postInstall = ''
|
||||||
|
wrapProgramShell $out/bin/nicotine \
|
||||||
|
--run "cp --update=none ~/.config/nicotine/config ~/.config/nicotine/config.old" \
|
||||||
|
--run "chmod u+w ~/.config/nicotine/config.old"
|
||||||
|
${upstream.postInstall}
|
||||||
|
'';
|
||||||
|
});
|
||||||
sandbox.method = "bwrap";
|
sandbox.method = "bwrap";
|
||||||
|
sandbox.whitelistDri = true; #< required, else it fails to launch the gui
|
||||||
sandbox.whitelistWayland = true;
|
sandbox.whitelistWayland = true;
|
||||||
sandbox.net = "vpn";
|
sandbox.net = "vpn";
|
||||||
|
sandbox.extraHomePaths = [
|
||||||
|
"Music"
|
||||||
|
# on run, nicotine will try to move the initial config to `config.old`
|
||||||
|
# and then update the config on disk. it errors if it can't `mv` it like that.
|
||||||
|
".config/nicotine"
|
||||||
|
];
|
||||||
|
|
||||||
# ".config/nicotine": contains the config file, with plaintext creds.
|
# the config has loooads of options, but the only critical one is auth/creds.
|
||||||
# TODO: define this as a secret instead of persisting it.
|
# run with ~/.config/nicotine in the sandbox and nicotine will derive the whole config
|
||||||
persist.byStore.private = [ ".config/nicotine" ];
|
# and write back *all* options for you to then edit further.
|
||||||
|
secrets.".config/nicotine/config" = ../../../secrets/common/nicotine-config.bin;
|
||||||
|
persist.byStore.plaintext = [
|
||||||
|
".local/share/nicotine/downloads"
|
||||||
|
];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
6
hosts/common/programs/nix.nix
Normal file
6
hosts/common/programs/nix.nix
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{ ... }:
|
||||||
|
{
|
||||||
|
sane.programs.nix = {
|
||||||
|
env.NIXPKGS_ALLOW_UNFREE = "1"; #< FUCK OFF YOU'RE SO ANNOYING
|
||||||
|
};
|
||||||
|
}
|
@@ -147,7 +147,6 @@ in
|
|||||||
suggestedPrograms = [
|
suggestedPrograms = [
|
||||||
"brightnessctl"
|
"brightnessctl"
|
||||||
"pactl" # pactl required by `per-app-volume` component.
|
"pactl" # pactl required by `per-app-volume` component.
|
||||||
"sane-die-with-parent"
|
|
||||||
] ++ lib.optionals (cfg.config.torch != null) [
|
] ++ lib.optionals (cfg.config.torch != null) [
|
||||||
"torch-toggle"
|
"torch-toggle"
|
||||||
];
|
];
|
||||||
@@ -205,6 +204,7 @@ in
|
|||||||
"/sys/devices"
|
"/sys/devices"
|
||||||
];
|
];
|
||||||
sandbox.extraRuntimePaths = [ "sway" ];
|
sandbox.extraRuntimePaths = [ "sway" ];
|
||||||
|
sandbox.isolatePids = false; #< nwg-panel restarts itself on display dis/connect, by killing all other instances.
|
||||||
|
|
||||||
services.nwg-panel = {
|
services.nwg-panel = {
|
||||||
description = "nwg-panel status/topbar for wayland";
|
description = "nwg-panel status/topbar for wayland";
|
||||||
@@ -214,7 +214,7 @@ in
|
|||||||
# N.B.: G_MESSAGES_DEBUG=all causes the swaync icon to not render
|
# N.B.: G_MESSAGES_DEBUG=all causes the swaync icon to not render
|
||||||
# command = "env G_MESSAGES_DEBUG=all nwg-panel";
|
# command = "env G_MESSAGES_DEBUG=all nwg-panel";
|
||||||
# XXX: try `nwg-panel & ; kill $$`. the inner nwg-panel doesn't die (without sane-die-with-parent), and hence the service would be prone to maintaining _multiple_ bars.
|
# XXX: try `nwg-panel & ; kill $$`. the inner nwg-panel doesn't die (without sane-die-with-parent), and hence the service would be prone to maintaining _multiple_ bars.
|
||||||
command = "sane-die-with-parent --descendants --signal SIGKILL nwg-panel";
|
command = "nwg-panel";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
sane.programs.objdump = {
|
sane.programs.objdump = {
|
||||||
# binutils-unwrapped is like 80 MiB, just for this one binary;
|
# binutils-unwrapped is like 80 MiB, just for this one binary;
|
||||||
# dynamic linking means copying the binary doesn't reduce the closure much at all compared to just symlinking it.
|
# dynamic linking means copying the binary doesn't reduce the closure much at all compared to just symlinking it.
|
||||||
packageUnwrapped = pkgs.linkIntoOwnPackage pkgs.binutils-unwrapped "bin/objdump";
|
packageUnwrapped = pkgs.linkBinIntoOwnPackage pkgs.binutils-unwrapped "objdump";
|
||||||
sandbox.method = "bwrap";
|
sandbox.method = "bwrap";
|
||||||
sandbox.autodetectCliPaths = "existingFile";
|
sandbox.autodetectCliPaths = "existingFile";
|
||||||
};
|
};
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
{ pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
{
|
{
|
||||||
sane.programs.pactl = {
|
sane.programs.pactl = {
|
||||||
packageUnwrapped = pkgs.linkIntoOwnPackage pkgs.pulseaudio "bin/pactl";
|
packageUnwrapped = pkgs.linkBinIntoOwnPackage pkgs.pulseaudio "pactl";
|
||||||
sandbox.method = "bwrap";
|
sandbox.method = "bwrap";
|
||||||
sandbox.whitelistAudio = true;
|
sandbox.whitelistAudio = true;
|
||||||
};
|
};
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
{ pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
{
|
{
|
||||||
sane.programs.pidof = {
|
sane.programs.pidof = {
|
||||||
packageUnwrapped = pkgs.linkIntoOwnPackage pkgs.procps "bin/pidof";
|
packageUnwrapped = pkgs.linkBinIntoOwnPackage pkgs.procps "pidof";
|
||||||
sandbox.method = "bwrap";
|
sandbox.method = "bwrap";
|
||||||
sandbox.isolatePids = false;
|
sandbox.isolatePids = false;
|
||||||
};
|
};
|
||||||
|
191
hosts/common/programs/pipewire/20-spatializer-7.1.conf
Normal file
191
hosts/common/programs/pipewire/20-spatializer-7.1.conf
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
# Headphone surround sink
|
||||||
|
#
|
||||||
|
# source: <repo:pipewire/pipewire:src/daemon/filter-chain/spatializer-7.1.conf>
|
||||||
|
# but modified:
|
||||||
|
# - applied a gain to the mixer.
|
||||||
|
context.modules = [
|
||||||
|
{ name = libpipewire-module-filter-chain
|
||||||
|
flags = [ nofail ]
|
||||||
|
args = {
|
||||||
|
node.description = "Spatial Sink"
|
||||||
|
media.name = "Spatial Sink"
|
||||||
|
filter.graph = {
|
||||||
|
nodes = [
|
||||||
|
{
|
||||||
|
type = sofa
|
||||||
|
label = spatializer
|
||||||
|
name = spFL
|
||||||
|
config = {
|
||||||
|
filename = "/etc/profiles/per-user/colin/share/libmysofa/default.sofa"
|
||||||
|
}
|
||||||
|
control = {
|
||||||
|
"Azimuth" = 30.0
|
||||||
|
"Elevation" = 0.0
|
||||||
|
"Radius" = 3.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
type = sofa
|
||||||
|
label = spatializer
|
||||||
|
name = spFR
|
||||||
|
config = {
|
||||||
|
filename = "/etc/profiles/per-user/colin/share/libmysofa/default.sofa"
|
||||||
|
}
|
||||||
|
control = {
|
||||||
|
"Azimuth" = 330.0
|
||||||
|
"Elevation" = 0.0
|
||||||
|
"Radius" = 3.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
type = sofa
|
||||||
|
label = spatializer
|
||||||
|
name = spFC
|
||||||
|
config = {
|
||||||
|
filename = "/etc/profiles/per-user/colin/share/libmysofa/default.sofa"
|
||||||
|
}
|
||||||
|
control = {
|
||||||
|
"Azimuth" = 0.0
|
||||||
|
"Elevation" = 0.0
|
||||||
|
"Radius" = 3.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
type = sofa
|
||||||
|
label = spatializer
|
||||||
|
name = spRL
|
||||||
|
config = {
|
||||||
|
filename = "/etc/profiles/per-user/colin/share/libmysofa/default.sofa"
|
||||||
|
}
|
||||||
|
control = {
|
||||||
|
"Azimuth" = 150.0
|
||||||
|
"Elevation" = 0.0
|
||||||
|
"Radius" = 3.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
type = sofa
|
||||||
|
label = spatializer
|
||||||
|
name = spRR
|
||||||
|
config = {
|
||||||
|
filename = "/etc/profiles/per-user/colin/share/libmysofa/default.sofa"
|
||||||
|
}
|
||||||
|
control = {
|
||||||
|
"Azimuth" = 210.0
|
||||||
|
"Elevation" = 0.0
|
||||||
|
"Radius" = 3.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
type = sofa
|
||||||
|
label = spatializer
|
||||||
|
name = spSL
|
||||||
|
config = {
|
||||||
|
filename = "/etc/profiles/per-user/colin/share/libmysofa/default.sofa"
|
||||||
|
}
|
||||||
|
control = {
|
||||||
|
"Azimuth" = 90.0
|
||||||
|
"Elevation" = 0.0
|
||||||
|
"Radius" = 3.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
type = sofa
|
||||||
|
label = spatializer
|
||||||
|
name = spSR
|
||||||
|
config = {
|
||||||
|
filename = "/etc/profiles/per-user/colin/share/libmysofa/default.sofa"
|
||||||
|
}
|
||||||
|
control = {
|
||||||
|
"Azimuth" = 270.0
|
||||||
|
"Elevation" = 0.0
|
||||||
|
"Radius" = 3.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
type = sofa
|
||||||
|
label = spatializer
|
||||||
|
name = spLFE
|
||||||
|
config = {
|
||||||
|
filename = "/etc/profiles/per-user/colin/share/libmysofa/default.sofa"
|
||||||
|
}
|
||||||
|
control = {
|
||||||
|
"Azimuth" = 0.0
|
||||||
|
"Elevation" = -60.0
|
||||||
|
"Radius" = 3.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
type = builtin
|
||||||
|
label = mixer
|
||||||
|
name = mixL
|
||||||
|
control = {
|
||||||
|
# gains are derived experimentally:
|
||||||
|
# - find a source mixed for stereo, and also 5.1
|
||||||
|
# - tune these gains until the mix sounds about equally loud
|
||||||
|
# i expect this gain should actually be lower (e.g. 0.33 instead of 0.50), since i define a 7.1 stage here
|
||||||
|
# so my 5.1 test probably left 1/3 of the virtual speakers "silent"
|
||||||
|
"Gain 1" = 0.50
|
||||||
|
"Gain 2" = 0.50
|
||||||
|
"Gain 3" = 0.50
|
||||||
|
"Gain 4" = 0.50
|
||||||
|
"Gain 5" = 0.50
|
||||||
|
"Gain 6" = 0.50
|
||||||
|
"Gain 7" = 0.50
|
||||||
|
"Gain 8" = 0.50
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
type = builtin
|
||||||
|
label = mixer
|
||||||
|
name = mixR
|
||||||
|
control = {
|
||||||
|
"Gain 1" = 0.50
|
||||||
|
"Gain 2" = 0.50
|
||||||
|
"Gain 3" = 0.50
|
||||||
|
"Gain 4" = 0.50
|
||||||
|
"Gain 5" = 0.50
|
||||||
|
"Gain 6" = 0.50
|
||||||
|
"Gain 7" = 0.50
|
||||||
|
"Gain 8" = 0.50
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
links = [
|
||||||
|
# output
|
||||||
|
{ output = "spFL:Out L" input="mixL:In 1" }
|
||||||
|
{ output = "spFL:Out R" input="mixR:In 1" }
|
||||||
|
{ output = "spFR:Out L" input="mixL:In 2" }
|
||||||
|
{ output = "spFR:Out R" input="mixR:In 2" }
|
||||||
|
{ output = "spFC:Out L" input="mixL:In 3" }
|
||||||
|
{ output = "spFC:Out R" input="mixR:In 3" }
|
||||||
|
{ output = "spRL:Out L" input="mixL:In 4" }
|
||||||
|
{ output = "spRL:Out R" input="mixR:In 4" }
|
||||||
|
{ output = "spRR:Out L" input="mixL:In 5" }
|
||||||
|
{ output = "spRR:Out R" input="mixR:In 5" }
|
||||||
|
{ output = "spSL:Out L" input="mixL:In 6" }
|
||||||
|
{ output = "spSL:Out R" input="mixR:In 6" }
|
||||||
|
{ output = "spSR:Out L" input="mixL:In 7" }
|
||||||
|
{ output = "spSR:Out R" input="mixR:In 7" }
|
||||||
|
{ output = "spLFE:Out L" input="mixL:In 8" }
|
||||||
|
{ output = "spLFE:Out R" input="mixR:In 8" }
|
||||||
|
]
|
||||||
|
inputs = [ "spFL:In" "spFR:In" "spFC:In" "spLFE:In" "spRL:In" "spRR:In", "spSL:In", "spSR:In" ]
|
||||||
|
outputs = [ "mixL:Out" "mixR:Out" ]
|
||||||
|
}
|
||||||
|
capture.props = {
|
||||||
|
node.name = "effect_input.spatializer"
|
||||||
|
media.class = Audio/Sink
|
||||||
|
audio.channels = 8
|
||||||
|
audio.position = [ FL FR FC LFE RL RR SL SR ]
|
||||||
|
}
|
||||||
|
playback.props = {
|
||||||
|
node.name = "effect_output.spatializer"
|
||||||
|
node.passive = true
|
||||||
|
audio.channels = 2
|
||||||
|
audio.position = [ FL FR ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
@@ -26,6 +26,10 @@ let
|
|||||||
cfg = config.sane.programs.pipewire;
|
cfg = config.sane.programs.pipewire;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
imports = [
|
||||||
|
./sofa-default.nix
|
||||||
|
];
|
||||||
|
|
||||||
sane.programs.pipewire = {
|
sane.programs.pipewire = {
|
||||||
configOption = with lib; mkOption {
|
configOption = with lib; mkOption {
|
||||||
default = {};
|
default = {};
|
||||||
@@ -46,6 +50,7 @@ in
|
|||||||
|
|
||||||
suggestedPrograms = [
|
suggestedPrograms = [
|
||||||
# "rtkit"
|
# "rtkit"
|
||||||
|
"sofa-default"
|
||||||
"wireplumber"
|
"wireplumber"
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -104,6 +109,8 @@ in
|
|||||||
default.clock.max-quantum = ${builtins.toString cfg.config.max-quantum}
|
default.clock.max-quantum = ${builtins.toString cfg.config.max-quantum}
|
||||||
}
|
}
|
||||||
'';
|
'';
|
||||||
|
fs.".config/pipewire/pipewire.conf.d/20-spatializer-7.1.conf".symlink.target = ./20-spatializer-7.1.conf;
|
||||||
|
|
||||||
# reduce realtime scheduling priority to prevent GPU instability,
|
# reduce realtime scheduling priority to prevent GPU instability,
|
||||||
# but see the top of this file for other solutions.
|
# but see the top of this file for other solutions.
|
||||||
# fs.".config/pipewire/pipewire.conf.d/20-sane-rtkit.conf".symlink.text = ''
|
# fs.".config/pipewire/pipewire.conf.d/20-sane-rtkit.conf".symlink.text = ''
|
||||||
@@ -158,7 +165,7 @@ in
|
|||||||
command = pkgs.writeShellScript "pipewire-start" ''
|
command = pkgs.writeShellScript "pipewire-start" ''
|
||||||
mkdir -p $PIPEWIRE_RUNTIME_DIR
|
mkdir -p $PIPEWIRE_RUNTIME_DIR
|
||||||
# nice -n -21 comes from pipewire defaults (niceness: -11)
|
# nice -n -21 comes from pipewire defaults (niceness: -11)
|
||||||
exec nice -n -21 pipewire
|
PIPEWIRE_DEBUG=3 exec nice -n -21 pipewire
|
||||||
'';
|
'';
|
||||||
readiness.waitExists = [
|
readiness.waitExists = [
|
||||||
"$PIPEWIRE_RUNTIME_DIR/pipewire-0"
|
"$PIPEWIRE_RUNTIME_DIR/pipewire-0"
|
19
hosts/common/programs/pipewire/sofa-default.nix
Normal file
19
hosts/common/programs/pipewire/sofa-default.nix
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# libmysofa Head Related Transfer Function file to use to downmix surround -> stereo.
|
||||||
|
# use a HRTF tuned for my skull/ears, and i can get 5.1 or 7.1 sources to still
|
||||||
|
# sound real, when played over headphones.
|
||||||
|
#
|
||||||
|
# file is installed to /etc/profiles/per-user/colin/share/libmysofa/default.sofa
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
let
|
||||||
|
cfg = config.sane.programs.sofa-default;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
sane.programs.sofa-default = {
|
||||||
|
packageUnwrapped = pkgs.sofacoustics.listen.irc_1052.asDefault;
|
||||||
|
sandbox.enable = false; #< data only
|
||||||
|
};
|
||||||
|
|
||||||
|
environment.pathsToLink = lib.mkIf cfg.enabled [
|
||||||
|
"/share/libmysofa"
|
||||||
|
];
|
||||||
|
}
|
@@ -1,7 +1,7 @@
|
|||||||
{ pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
{
|
{
|
||||||
sane.programs.pkill = {
|
sane.programs.pkill = {
|
||||||
packageUnwrapped = pkgs.linkIntoOwnPackage pkgs.procps "bin/pkill";
|
packageUnwrapped = pkgs.linkBinIntoOwnPackage pkgs.procps "pkill";
|
||||||
sandbox.method = "bwrap";
|
sandbox.method = "bwrap";
|
||||||
sandbox.isolatePids = false;
|
sandbox.isolatePids = false;
|
||||||
};
|
};
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
{ pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
{
|
{
|
||||||
sane.programs.ps = {
|
sane.programs.ps = {
|
||||||
packageUnwrapped = pkgs.linkIntoOwnPackage pkgs.procps "bin/ps";
|
packageUnwrapped = pkgs.linkBinIntoOwnPackage pkgs.procps "ps";
|
||||||
sandbox.method = "bwrap";
|
sandbox.method = "bwrap";
|
||||||
sandbox.isolatePids = false;
|
sandbox.isolatePids = false;
|
||||||
};
|
};
|
||||||
|
@@ -56,6 +56,7 @@ configuration {
|
|||||||
}
|
}
|
||||||
/* launch applications via my own launcher, which directs them through to xdg-desktop-portal */
|
/* launch applications via my own launcher, which directs them through to xdg-desktop-portal */
|
||||||
run-command: "rofi-run-command '{app_id}.desktop' {cmd}";
|
run-command: "rofi-run-command '{app_id}.desktop' {cmd}";
|
||||||
|
run-shell-command: "rofi-run-command '{app_id}.desktop' {cmd}";
|
||||||
}
|
}
|
||||||
|
|
||||||
/* theme */
|
/* theme */
|
||||||
|
@@ -78,7 +78,8 @@ in
|
|||||||
# it's actively maintained though, and more of an overlay than a true fork.
|
# it's actively maintained though, and more of an overlay than a true fork.
|
||||||
packageUnwrapped = pkgs.rofi-wayland.override {
|
packageUnwrapped = pkgs.rofi-wayland.override {
|
||||||
inherit rofi-unwrapped;
|
inherit rofi-unwrapped;
|
||||||
plugins = [
|
plugins = with pkgs; [
|
||||||
|
# rofi-calc # not compatible with my rofi <https://github.com/svenstaro/rofi-calc>
|
||||||
# rofi-[extended-]-file-browser: <https://github.com/marvinkreis/rofi-file-browser-extended>
|
# rofi-[extended-]-file-browser: <https://github.com/marvinkreis/rofi-file-browser-extended>
|
||||||
# because the builtin rofi filebrowser only partially lists ~/Videos/servo/Shows, seemingly at random.
|
# because the builtin rofi filebrowser only partially lists ~/Videos/servo/Shows, seemingly at random.
|
||||||
# but rofi-file-browser doesn't compile against my patched rofi (oops)
|
# but rofi-file-browser doesn't compile against my patched rofi (oops)
|
||||||
@@ -124,7 +125,7 @@ in
|
|||||||
fs."Apps".symlink.target = ".local/share/applications/rofi-applications.desktop";
|
fs."Apps".symlink.target = ".local/share/applications/rofi-applications.desktop";
|
||||||
fs."WiFi".symlink.target = ".local/share/applications/networkmanager_dmenu.desktop";
|
fs."WiFi".symlink.target = ".local/share/applications/networkmanager_dmenu.desktop";
|
||||||
fs."close".symlink.target = ".local/share/applications/close.desktop"; #< provide an escape from the file browser
|
fs."close".symlink.target = ".local/share/applications/close.desktop"; #< provide an escape from the file browser
|
||||||
persist.byStore.cryptClearOnBoot = [
|
persist.byStore.ephemeral = [
|
||||||
# this gets us a few things:
|
# this gets us a few things:
|
||||||
# - file browser remembers its last directory
|
# - file browser remembers its last directory
|
||||||
# - caching of .desktop files (perf)
|
# - caching of .desktop files (perf)
|
||||||
|
29
hosts/common/programs/rsyslog/default.nix
Normal file
29
hosts/common/programs/rsyslog/default.nix
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
# docs: <https://www.rsyslog.com/doc/index.html>
|
||||||
|
# docs: `man rsyslogd`
|
||||||
|
# i have systemd-journald -> rsyslogd
|
||||||
|
# this escapes issues i'd otherwise have persisting journald itself to disk
|
||||||
|
# since that component needs to run in initrd and before service setup.
|
||||||
|
#
|
||||||
|
# TODO: log rotation / retention policy. don't want to eat the whole HDD.
|
||||||
|
{ config, lib, ... }:
|
||||||
|
{
|
||||||
|
sane.programs.rsyslog = {
|
||||||
|
persist.byStore.private = [
|
||||||
|
".local/share/rsyslog/logs"
|
||||||
|
];
|
||||||
|
# rsyslogd can't handle $HOME or ~ or anything like that,
|
||||||
|
# so assume a single-user install and just substitute the default user:
|
||||||
|
fs.".config/rsyslog/rsyslog.conf".symlink.text = lib.replaceStrings
|
||||||
|
[ "$HOME" ]
|
||||||
|
[ "/home/${config.sane.defaultUser}" ]
|
||||||
|
(builtins.readFile ./rsyslog.conf);
|
||||||
|
|
||||||
|
services.rsyslogd = {
|
||||||
|
description = "rsyslogd: ingests journald (system log) messages into persistent storage";
|
||||||
|
partOf = [ "default" ];
|
||||||
|
# XXX(2024-07-27): rsyslog tends to be launched early, before the logs dir has been created.
|
||||||
|
# that's a problem all my programs are susceptible to, but hack rsyslog to wait for its log dir else it'll create it on non-persisted storage
|
||||||
|
command = "test -L ~/.local/share/rsyslog/logs && rsyslogd -f ~/.config/rsyslog/rsyslog.conf -i ~/.local/share/rsyslog/rsyslogd.pid -n";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
48
hosts/common/programs/rsyslog/rsyslog.conf
Normal file
48
hosts/common/programs/rsyslog/rsyslog.conf
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
# docs: `man rsyslog.conf`
|
||||||
|
# docs: <https://www.rsyslog.com/doc/index.html>
|
||||||
|
|
||||||
|
### INPUTS/SOURCES
|
||||||
|
# imjournal: pull from systemd-journald.
|
||||||
|
# - use a StateFile, so that we can read the whole journal the first time we start,
|
||||||
|
# and then survive restarts by picking up where we left off
|
||||||
|
# - example: <https://www.rsyslog.com/doc/configuration/modules/imjournal.html#example-1>
|
||||||
|
# XXX: the recommended alternative is to have journald forward events to /run/systemd/journal/syslog
|
||||||
|
# and rsyslogd slurps that. unfortunately, that results in many lost messages --
|
||||||
|
# and especially if the gap between launching journald and unlocking the private store is lengthy.
|
||||||
|
#
|
||||||
|
module(load="imjournal" StateFile="$HOME/.local/share/rsyslog/journal.state")
|
||||||
|
|
||||||
|
### OUTPUTS
|
||||||
|
# selector format is `<facility>.<priority>`
|
||||||
|
# valid facilities are:
|
||||||
|
# - auth
|
||||||
|
# - authpriv
|
||||||
|
# - cron
|
||||||
|
# - daemon
|
||||||
|
# - kern
|
||||||
|
# - lpr
|
||||||
|
# - mail
|
||||||
|
# - mark
|
||||||
|
# - news
|
||||||
|
# - syslog
|
||||||
|
# - user
|
||||||
|
# - uucp
|
||||||
|
# - local0 through local7
|
||||||
|
# valid priorities are:
|
||||||
|
# - debug
|
||||||
|
# - info
|
||||||
|
# - notice
|
||||||
|
# - warning
|
||||||
|
# - err
|
||||||
|
# - crit
|
||||||
|
# - alert
|
||||||
|
# - emerg
|
||||||
|
# *.info matches priority `info` or greater
|
||||||
|
# *.=info matches only priotity `info`
|
||||||
|
# *.!info matches priority `info` or *lower*
|
||||||
|
#
|
||||||
|
# each rule matches in parallel; logs can be sent multiple places
|
||||||
|
|
||||||
|
# send warning/higher to a special place
|
||||||
|
*.warning $HOME/.local/share/rsyslog/logs/warn
|
||||||
|
*.* $HOME/.local/share/rsyslog/logs/all
|
@@ -16,7 +16,9 @@
|
|||||||
'';
|
'';
|
||||||
});
|
});
|
||||||
|
|
||||||
persist.byStore.private = [
|
# N.B.: we can't persist anything to `private` storage at this point,
|
||||||
|
# because mounting the private storage generally relies on having a service manager running.
|
||||||
|
persist.byStore.ephemeral = [
|
||||||
".local/share/s6/logs"
|
".local/share/s6/logs"
|
||||||
];
|
];
|
||||||
|
|
||||||
|
27
hosts/common/programs/sane-deadlines.nix
Normal file
27
hosts/common/programs/sane-deadlines.nix
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
let
|
||||||
|
cfg = config.sane.programs.sane-deadlines;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
sane.programs.sane-deadlines = {
|
||||||
|
configOption = with lib; mkOption {
|
||||||
|
default = {};
|
||||||
|
type = types.submodule {
|
||||||
|
options.showOnLogin = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
packageUnwrapped = pkgs.sane-scripts.deadlines;
|
||||||
|
|
||||||
|
sandbox.method = "bwrap";
|
||||||
|
sandbox.extraHomePaths = [ "knowledge/planner/deadlines.tsv" ];
|
||||||
|
|
||||||
|
fs.".profile".symlink.text = lib.mkIf cfg.config.showOnLogin ''
|
||||||
|
if [ -z "$SSH_TTY" ]; then
|
||||||
|
sane-deadlines
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
56
hosts/common/programs/sane-private-unlock-remote.nix
Normal file
56
hosts/common/programs/sane-private-unlock-remote.nix
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
let
|
||||||
|
cfg = config.sane.programs.sane-private-unlock-remote;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
sane.programs."sane-private-unlock-remote" = {
|
||||||
|
packageUnwrapped = pkgs.sane-scripts.private-unlock-remote;
|
||||||
|
sandbox.method = "bwrap";
|
||||||
|
sandbox.net = "all";
|
||||||
|
sandbox.extraHomePaths = [
|
||||||
|
".config/sops"
|
||||||
|
".ssh/id_ed25519"
|
||||||
|
".ssh/id_ed25519.pub"
|
||||||
|
"knowledge/secrets"
|
||||||
|
];
|
||||||
|
suggestedPrograms = [
|
||||||
|
"sane-scripts.secrets-dump"
|
||||||
|
];
|
||||||
|
|
||||||
|
configOption = with lib; mkOption {
|
||||||
|
default = {};
|
||||||
|
type = types.submodule {
|
||||||
|
options.interval = mkOption {
|
||||||
|
type = types.int;
|
||||||
|
default = 60;
|
||||||
|
description = ''
|
||||||
|
how frequently to check in on the remote hosts (in seconds)
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
options.hosts = mkOption {
|
||||||
|
type = types.listOf types.str;
|
||||||
|
default = [];
|
||||||
|
description = ''
|
||||||
|
list of hosts which should be remotely unlocked automatically
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.sane-private-unlock-remote = {
|
||||||
|
description = "private-unlock-remote: unlock the 'private' store of trusted remote machines";
|
||||||
|
partOf = lib.mkIf (cfg.config.hosts != []) [ "default" ];
|
||||||
|
command = pkgs.writeShellScript "private-unlock-remote-loop" ''
|
||||||
|
hosts=(${lib.escapeShellArgs cfg.config.hosts})
|
||||||
|
interval=${builtins.toString cfg.config.interval}
|
||||||
|
while true; do
|
||||||
|
for host in "''${hosts[@]}"; do
|
||||||
|
echo "attempting to unlock $host"
|
||||||
|
sane-private-unlock-remote "$host"
|
||||||
|
done
|
||||||
|
sleep "$interval"
|
||||||
|
done
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
@@ -22,10 +22,8 @@ in
|
|||||||
"sane-scripts.dev-cargo-loop"
|
"sane-scripts.dev-cargo-loop"
|
||||||
];
|
];
|
||||||
"sane-scripts.cli" = declPackageSet [
|
"sane-scripts.cli" = declPackageSet [
|
||||||
"sane-scripts.deadlines"
|
|
||||||
"sane-scripts.find-dotfiles"
|
"sane-scripts.find-dotfiles"
|
||||||
"sane-scripts.ip-check"
|
"sane-scripts.ip-check"
|
||||||
"sane-scripts.private-change-passwd"
|
|
||||||
"sane-scripts.private-do"
|
"sane-scripts.private-do"
|
||||||
"sane-scripts.private-init"
|
"sane-scripts.private-init"
|
||||||
"sane-scripts.private-lock"
|
"sane-scripts.private-lock"
|
||||||
@@ -35,11 +33,10 @@ in
|
|||||||
"sane-scripts.reclaim-boot-space"
|
"sane-scripts.reclaim-boot-space"
|
||||||
"sane-scripts.reclaim-disk-space"
|
"sane-scripts.reclaim-disk-space"
|
||||||
"sane-scripts.secrets-dump"
|
"sane-scripts.secrets-dump"
|
||||||
"sane-scripts.secrets-unlock"
|
|
||||||
"sane-scripts.secrets-update-keys"
|
"sane-scripts.secrets-update-keys"
|
||||||
"sane-scripts.shutdown"
|
"sane-scripts.shutdown"
|
||||||
"sane-scripts.sudo-redirect"
|
"sane-scripts.sudo-redirect"
|
||||||
"sane-scripts.tag-music"
|
"sane-scripts.tag-media"
|
||||||
"sane-scripts.vpn"
|
"sane-scripts.vpn"
|
||||||
"sane-scripts.which"
|
"sane-scripts.which"
|
||||||
"sane-scripts.wipe"
|
"sane-scripts.wipe"
|
||||||
@@ -85,11 +82,6 @@ in
|
|||||||
# but that's an ephemeral operation that would be lost when the sandbox closes.
|
# but that's an ephemeral operation that would be lost when the sandbox closes.
|
||||||
"sane-scripts.clone".sandbox.enable = false;
|
"sane-scripts.clone".sandbox.enable = false;
|
||||||
|
|
||||||
"sane-scripts.deadlines".sandbox = {
|
|
||||||
method = "bwrap";
|
|
||||||
extraHomePaths = [ "knowledge/planner/deadlines.tsv" ];
|
|
||||||
};
|
|
||||||
|
|
||||||
"sane-scripts.dev-cargo-loop".sandbox = {
|
"sane-scripts.dev-cargo-loop".sandbox = {
|
||||||
method = "bwrap";
|
method = "bwrap";
|
||||||
net = "clearnet";
|
net = "clearnet";
|
||||||
@@ -119,14 +111,6 @@ in
|
|||||||
|
|
||||||
"sane-scripts.ip-port-forward" = {};
|
"sane-scripts.ip-port-forward" = {};
|
||||||
|
|
||||||
"sane-scripts.private-change-passwd".sandbox = {
|
|
||||||
method = "bwrap";
|
|
||||||
autodetectCliPaths = "existing"; #< for the new `private` location
|
|
||||||
capabilities = [ "sys_admin" ]; # it needs to mount the new store
|
|
||||||
extraHomePaths = [
|
|
||||||
".persist/private"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
"sane-scripts.private-do".sandbox = {
|
"sane-scripts.private-do".sandbox = {
|
||||||
# because `mount` is a cap_sys_admin syscall, there's no great way to mount stuff dynamically like this.
|
# because `mount` is a cap_sys_admin syscall, there's no great way to mount stuff dynamically like this.
|
||||||
# instead, we put ourselves in a mount namespace, do the mount, and drop into a shell or run a command.
|
# instead, we put ourselves in a mount namespace, do the mount, and drop into a shell or run a command.
|
||||||
@@ -175,19 +159,11 @@ in
|
|||||||
extraPaths = [ "/nix/var/nix" ];
|
extraPaths = [ "/nix/var/nix" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
"sane-scripts.secrets-unlock".sandbox = {
|
"sane-scripts.secrets-dump".sandbox.method = "bwrap";
|
||||||
method = "bwrap";
|
"sane-scripts.secrets-dump".sandbox.extraHomePaths = [
|
||||||
extraHomePaths = [
|
".config/sops"
|
||||||
".ssh/id_ed25519"
|
"knowledge/secrets"
|
||||||
".ssh/id_ed25519.pub"
|
];
|
||||||
".config/sops"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
"sane-scripts.secrets-unlock".fs.".config/sops".dir = {};
|
|
||||||
|
|
||||||
# sane-secrets-dump is a thin wrapper around sops + some utilities.
|
|
||||||
# really i should sandbox just the utilities
|
|
||||||
"sane-scripts.secrets-dump".sandbox.enable = false;
|
|
||||||
"sane-scripts.secrets-dump".suggestedPrograms = [
|
"sane-scripts.secrets-dump".suggestedPrograms = [
|
||||||
"gnugrep"
|
"gnugrep"
|
||||||
"oath-toolkit"
|
"oath-toolkit"
|
||||||
@@ -227,9 +203,13 @@ in
|
|||||||
"sane-scripts.sync-music" = {};
|
"sane-scripts.sync-music" = {};
|
||||||
"sane-scripts.sync-from-iphone" = {};
|
"sane-scripts.sync-from-iphone" = {};
|
||||||
|
|
||||||
"sane-scripts.tag-music".sandbox = {
|
"sane-scripts.tag-media".suggestedPrograms = [
|
||||||
|
"exiftool" #< for (slightly) better sandboxing than default exiftool
|
||||||
|
];
|
||||||
|
"sane-scripts.tag-media".sandbox = {
|
||||||
method = "bwrap";
|
method = "bwrap";
|
||||||
autodetectCliPaths = "existing";
|
autodetectCliPaths = "existing";
|
||||||
|
whitelistPwd = true; # for music renaming
|
||||||
};
|
};
|
||||||
|
|
||||||
"sane-scripts.vpn".fs = lib.foldl'
|
"sane-scripts.vpn".fs = lib.foldl'
|
||||||
@@ -259,6 +239,13 @@ in
|
|||||||
# capabilities = [ "net_admin" ];
|
# capabilities = [ "net_admin" ];
|
||||||
# extraHomePaths = [ ".config/sane-vpn" ];
|
# extraHomePaths = [ ".config/sane-vpn" ];
|
||||||
};
|
};
|
||||||
|
"sane-scripts.vpn".suggestedPrograms = [
|
||||||
|
"gnugrep"
|
||||||
|
"gnused"
|
||||||
|
"iproute2"
|
||||||
|
"nmcli"
|
||||||
|
"sane-scripts.ip-check"
|
||||||
|
];
|
||||||
|
|
||||||
"sane-scripts.which".sandbox.method = "bwrap";
|
"sane-scripts.which".sandbox.method = "bwrap";
|
||||||
|
|
||||||
|
22
hosts/common/programs/sane-secrets-unlock.nix
Normal file
22
hosts/common/programs/sane-secrets-unlock.nix
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
{ pkgs, ... }:
|
||||||
|
{
|
||||||
|
sane.programs."sane-secrets-unlock" = {
|
||||||
|
packageUnwrapped = pkgs.sane-scripts.secrets-unlock;
|
||||||
|
sandbox.method = "bwrap";
|
||||||
|
sandbox.extraHomePaths = [
|
||||||
|
".ssh/id_ed25519"
|
||||||
|
".ssh/id_ed25519.pub"
|
||||||
|
".config/sops"
|
||||||
|
];
|
||||||
|
fs.".config/sops".dir = {};
|
||||||
|
|
||||||
|
# automatically unlock the secrets at login.
|
||||||
|
services.sane-secrets-unlock = {
|
||||||
|
description = "sane-secrets-unlock: make secrets in ~/knowledge readable";
|
||||||
|
startCommand = "sane-secrets-unlock";
|
||||||
|
cleanupCommand = "rm -f ~/.config/sops/age/keys.txt";
|
||||||
|
depends = [ "gocryptfs-private" ];
|
||||||
|
partOf = [ "private-storage" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
@@ -6,5 +6,12 @@
|
|||||||
"/sys/class/power_supply"
|
"/sys/class/power_supply"
|
||||||
"/sys/devices"
|
"/sys/devices"
|
||||||
];
|
];
|
||||||
|
fs.".profile".symlink.text = ''
|
||||||
|
# show ssh users the current resource usage.
|
||||||
|
# especially useful for moby (to see battery)
|
||||||
|
if [ -n "$SSH_TTY" ]; then
|
||||||
|
sane-sysload
|
||||||
|
fi
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -16,20 +16,31 @@ let
|
|||||||
in
|
in
|
||||||
{
|
{
|
||||||
sane.programs.sanebox = {
|
sane.programs.sanebox = {
|
||||||
packageUnwrapped = pkgs.sanebox.override {
|
packageUnwrapped = (pkgs.sanebox.override {
|
||||||
bubblewrap = cfg.bubblewrap.package;
|
bubblewrap = cfg.bubblewrap.package;
|
||||||
passt = cfg.passt.package;
|
iproute2 = cfg.iproute2.package;
|
||||||
|
iptables = cfg.iptables.package;
|
||||||
libcap = cfg.libcap.package;
|
libcap = cfg.libcap.package;
|
||||||
|
passt = cfg.passt.package;
|
||||||
landlock-sandboxer = pkgs.landlock-sandboxer.override {
|
landlock-sandboxer = pkgs.landlock-sandboxer.override {
|
||||||
# not strictly necessary (landlock ABI is versioned), however when sandboxer version != kernel version,
|
# not strictly necessary (landlock ABI is versioned), however when sandboxer version != kernel version,
|
||||||
# the sandboxer may nag about one or the other wanting to be updated.
|
# the sandboxer may nag about one or the other wanting to be updated.
|
||||||
linux = config.boot.kernelPackages.kernel;
|
linux = config.boot.kernelPackages.kernel;
|
||||||
};
|
};
|
||||||
};
|
}).overrideAttrs (base: {
|
||||||
|
# create a directory which holds just the `sanebox` so that we
|
||||||
|
# can add sanebox as a dependency to binaries via `PATH=/run/current-system/libexec/sanebox` without forcing rebuild every time sanebox changes
|
||||||
|
postInstall = ''
|
||||||
|
mkdir -p $out/libexec/sanebox
|
||||||
|
ln -s $out/bin/sanebox $out/libexec/sanebox/sanebox
|
||||||
|
'';
|
||||||
|
});
|
||||||
|
|
||||||
sandbox.enable = false;
|
sandbox.enable = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
environment.pathsToLink = lib.mkIf cfg.sanebox.enabled [ "/libexec/sanebox" ];
|
||||||
|
|
||||||
environment.etc = lib.mkIf cfg.sanebox.enabled {
|
environment.etc = lib.mkIf cfg.sanebox.enabled {
|
||||||
"sanebox/symlink-cache".text = lib.concatStringsSep "\n" (
|
"sanebox/symlink-cache".text = lib.concatStringsSep "\n" (
|
||||||
lib.mapAttrsToList
|
lib.mapAttrsToList
|
||||||
|
@@ -39,8 +39,6 @@ lib.mkMerge [
|
|||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
restartIfChanged = false;
|
restartIfChanged = false;
|
||||||
|
|
||||||
path = [ "/run/current-system/sw" ]; #< so `sanebox` works
|
|
||||||
|
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
Type = "simple";
|
Type = "simple";
|
||||||
ExecStart = "${cfg.package}/bin/seatd -g seat";
|
ExecStart = "${cfg.package}/bin/seatd -g seat";
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
sane.programs.strings = {
|
sane.programs.strings = {
|
||||||
# binutils-unwrapped is like 80 MiB, just for this one binary;
|
# binutils-unwrapped is like 80 MiB, just for this one binary;
|
||||||
# dynamic linking means copying the binary doesn't reduce the closure much at all compared to just symlinking it.
|
# dynamic linking means copying the binary doesn't reduce the closure much at all compared to just symlinking it.
|
||||||
packageUnwrapped = pkgs.linkIntoOwnPackage pkgs.binutils-unwrapped "bin/strings";
|
packageUnwrapped = pkgs.linkBinIntoOwnPackage pkgs.binutils-unwrapped "strings";
|
||||||
|
|
||||||
sandbox.method = "landlock";
|
sandbox.method = "landlock";
|
||||||
sandbox.wrapperType = "inplace"; # trivial package; cheaper to wrap in place
|
sandbox.wrapperType = "inplace"; # trivial package; cheaper to wrap in place
|
||||||
|
@@ -85,6 +85,7 @@ bindsym $mod+s exec sane-open --application rofi-snippets.desktop
|
|||||||
# bindsym $mod+slash exec sane-open splatmoji.desktop
|
# bindsym $mod+slash exec sane-open splatmoji.desktop
|
||||||
bindsym $mod+d exec sane-open --application rofi.desktop
|
bindsym $mod+d exec sane-open --application rofi.desktop
|
||||||
bindsym $mod+Return exec sane-open --application xdg-terminal-exec.desktop
|
bindsym $mod+Return exec sane-open --application xdg-terminal-exec.desktop
|
||||||
|
bindsym $mod+b exec sane-open --uri "https://uninsane.org/places"
|
||||||
|
|
||||||
bindsym $mod+Shift+q kill
|
bindsym $mod+Shift+q kill
|
||||||
# bindsym $mod+Shift+e exec swaynag -t warning -m 'You pressed the exit shortcut. Do you really want to exit sway? This will end your Wayland session.' -b 'Yes, exit sway' 'swaymsg exit'
|
# bindsym $mod+Shift+e exec swaynag -t warning -m 'You pressed the exit shortcut. Do you really want to exit sway? This will end your Wayland session.' -b 'Yes, exit sway' 'swaymsg exit'
|
||||||
@@ -194,10 +195,15 @@ for_window [app_id="Celeste64|mpv"] {
|
|||||||
|
|
||||||
### displays & inputs
|
### displays & inputs
|
||||||
input type:touchpad {
|
input type:touchpad {
|
||||||
|
# see also: accel_profile, scroll_factor, tap_button_map, clickfinger_button_map
|
||||||
tap enabled
|
tap enabled
|
||||||
|
middle_emulation disabled
|
||||||
natural_scroll enabled
|
natural_scroll enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# caps as escape key
|
||||||
|
input "type:keyboard" xkb_options caps:escape
|
||||||
|
|
||||||
## SHARED
|
## SHARED
|
||||||
# TV
|
# TV
|
||||||
output $out_tv {
|
output $out_tv {
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user