Compare commits
187 Commits
wip-secure
...
2024-08-14
Author | SHA1 | Date | |
---|---|---|---|
d2f3a066fb | |||
50b1d82b38 | |||
60a4eb0bde | |||
a96e83f4e1 | |||
0d685f406e | |||
a16e33d7a6 | |||
f38d351869 | |||
e245164da3 | |||
7df8f45e97 | |||
e1ba371838 | |||
467283989f | |||
db39dc209f | |||
7cf860a071 | |||
77a753b0d6 | |||
e2a4f4d63e | |||
31fc072bce | |||
144afd8171 | |||
7d97355d2a | |||
7827f6c584 | |||
e1899495a0 | |||
a56ad56a4f | |||
da551b8b97 | |||
ca412d08bd | |||
e7a1bb6ec0 | |||
74acfeadd5 | |||
e7d5a61014 | |||
6f47708624 | |||
fc826a3503 | |||
ccb2b7b8b6 | |||
78169d50f2 | |||
33a7d3536d | |||
7899c8d033 | |||
82b662a733 | |||
d4290588bf | |||
bd97fb9ec9 | |||
4dbff9c18f | |||
bfe278c17a | |||
295e07d535 | |||
d39459d8b5 | |||
4d5e60756b | |||
119afcf393 | |||
d3d970eb3e | |||
c0d5004926 | |||
d9a876e49a | |||
5a9dd89475 | |||
5e71e5a067 | |||
f0b0d15ad7 | |||
8aebc1fe87 | |||
764c2a3276 | |||
a2f34be9d6 | |||
bda172bc2d | |||
a91a2d8a7f | |||
875d919fa8 | |||
a323f321b5 | |||
f986936bbd | |||
3d773fe375 | |||
055ad222e3 | |||
3aafcb0aa8 | |||
c85f02ca68 | |||
eeafc34ccf | |||
039ffcdcd4 | |||
2a35cb5379 | |||
3db009bc98 | |||
1e840e72b3 | |||
ce1c3ec804 | |||
09dd69a855 | |||
cbe71868ef | |||
7b043d0c87 | |||
fd0188025d | |||
1c57ffa798 | |||
1d205a89bc | |||
5ff643aa2f | |||
bfdf63e641 | |||
c695f7a979 | |||
b3b38451b5 | |||
1ee81db537 | |||
b9947c05ca | |||
2de6491583 | |||
4525df58e0 | |||
9d1ffc7c43 | |||
a69af91b7b | |||
7b5d655c91 | |||
de6ffe6b75 | |||
f8aea34e96 | |||
49efb94a0a | |||
9b1e053ead | |||
235dc86155 | |||
6dad290cd5 | |||
cc6ed6c0ec | |||
cc3aba3cc2 | |||
41f08125bb | |||
27487fe870 | |||
d45ea622d1 | |||
247fd3f807 | |||
816e2a7065 | |||
be842d5c5e | |||
fa6ec981e0 | |||
52b4c1542a | |||
3ff59247da | |||
d9c0855c4e | |||
1a67a05238 | |||
1cdeedd9ec | |||
6830bb7097 | |||
316b0bee3a | |||
638655ff83 | |||
5e57e78411 | |||
3859619ae0 | |||
646c2dd85a | |||
0655b6906c | |||
3019f90f5d | |||
020e5f8c6e | |||
809c3af7fa | |||
93cb1bc546 | |||
53acab834c | |||
3a0610b029 | |||
9cee460d7e | |||
e657507a76 | |||
c706a19836 | |||
566e15286b | |||
d1b4e9c923 | |||
5eca45891b | |||
722fe8f368 | |||
e25dd98f6c | |||
54e9d4a0ae | |||
9f3a13eeb8 | |||
5605ffda4b | |||
9165925469 | |||
f65bf2b433 | |||
0f60a86ed4 | |||
b488b6748d | |||
ef6b7cf175 | |||
0906d76f83 | |||
90c495e74c | |||
74662df720 | |||
2b3278eb7f | |||
9b4e91fbd9 | |||
734627232a | |||
3adbbe5fa7 | |||
b4a244df7a | |||
97268e9b26 | |||
bebf6bdaeb | |||
04fc601c9c | |||
ee062d61d0 | |||
0dba9987c5 | |||
4761690b6d | |||
604782c3a6 | |||
365d33c357 | |||
a39ad8a508 | |||
c49e9a4c2b | |||
36491842cc | |||
81ea2210c9 | |||
f678508b33 | |||
6135be5f72 | |||
c8989ca1a8 | |||
1d665f8ecc | |||
7c284ad8da | |||
1c26674da7 | |||
dae8481176 | |||
42b27f0433 | |||
84be0cae5a | |||
fbfd0afca4 | |||
e586b7b449 | |||
222c37b056 | |||
53b17ec230 | |||
7697704aff | |||
c490b6e6ad | |||
89d678c729 | |||
c64163290c | |||
eaeb8380dc | |||
05a9e8e819 | |||
cf20230d96 | |||
9dbb2a6266 | |||
113b107d73 | |||
96dfe79a8c | |||
6e5bde17aa | |||
3eb66c098b | |||
515aab5370 | |||
f925dd9a20 | |||
cbe6bdf158 | |||
949a52dee1 | |||
2ee1fb17c4 | |||
48cc718700 | |||
6a7dd31755 | |||
2197951e12 | |||
883db3e9ba | |||
312b0a5554 | |||
07de46c616 |
46
TODO.md
46
TODO.md
@@ -2,18 +2,22 @@
|
|||||||
- `rmDbusServices` may break sandboxing
|
- `rmDbusServices` may break sandboxing
|
||||||
- e.g. if the package ships a systemd unit which references $out, then make-sandboxed won't properly update that unit.
|
- e.g. if the package ships a systemd unit which references $out, then make-sandboxed won't properly update that unit.
|
||||||
- `rmDbusServicesInPlace` is not affected
|
- `rmDbusServicesInPlace` is not affected
|
||||||
- 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/hickory-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 resolve `abs.twimg.com`
|
- hickory-dns can't resolve `abs.twimg.com`
|
||||||
- trust-dns can't resolve `social.kernel.org`
|
- hickory-dns can't resolve `social.kernel.org`
|
||||||
|
- hickory-dns can't resolve `pe.usps.com`
|
||||||
|
- hickory-dns can't resolve `social.seattle.wa.us`
|
||||||
|
- hickory-dns can't resolve `support.mozilla.org`
|
||||||
- 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: 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
|
|
||||||
- uosc hides controls on FS, and touch doesn't support unhiding
|
|
||||||
- `ssh` access doesn't grant same linux capabilities as login
|
- `ssh` access doesn't grant same linux capabilities as login
|
||||||
- syshud (volume overlay): when casting with `blast`, syshud doesn't react to volume changes
|
- syshud (volume overlay): when casting with `blast`, syshud doesn't react to volume changes
|
||||||
|
- moby: after bringing the modem up, powering it down loses *complete* net connectivity (i.e. wlan is gone as well)
|
||||||
|
- dissent: if i launch it without net connectivity, it gets stuck at the login, and never tries again
|
||||||
|
- calls: seems that it starts before net access, and then is forever disconnected (until i manually restart it)
|
||||||
- moby: kaslr is effectively disabled
|
- moby: kaslr is effectively disabled
|
||||||
- `dmesg | grep "KASLR disabled due to lack of seed"`
|
- `dmesg | grep "KASLR disabled due to lack of seed"`
|
||||||
- fix by adding `kaslrseed` to uboot script before `booti`
|
- fix by adding `kaslrseed` to uboot script before `booti`
|
||||||
@@ -24,6 +28,14 @@
|
|||||||
- `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
|
||||||
|
- newflash on moby can't play videos
|
||||||
|
- "open in browser" works though -- in mpv
|
||||||
|
- gnome-maps can't use geoclue *and* openstreetmap at the same time
|
||||||
|
- get gnome-maps to speak xdg-desktop-portal, and this will be fixed
|
||||||
|
- epiphany can't save cookies
|
||||||
|
- see under "preferences", cookies are disabled
|
||||||
|
- prevents logging into websites (OpenStreetMap)
|
||||||
|
- works when sandbox is disabled
|
||||||
|
|
||||||
## REFACTORING:
|
## REFACTORING:
|
||||||
- add import checks to my Python nix-shell scripts
|
- add import checks to my Python nix-shell scripts
|
||||||
@@ -50,8 +62,6 @@
|
|||||||
|
|
||||||
|
|
||||||
## IMPROVEMENTS:
|
## IMPROVEMENTS:
|
||||||
- systemd/journalctl: use a less shit pager
|
|
||||||
- there's an env var for it: SYSTEMD_PAGER? and a flag for journalctl
|
|
||||||
- kernels: ship the same kernel on every machine
|
- kernels: ship the same kernel on every machine
|
||||||
- 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
|
||||||
@@ -60,17 +70,18 @@
|
|||||||
- safer (rust? actively maintained? sandboxable?)
|
- safer (rust? actively maintained? sandboxable?)
|
||||||
- handles spaces/symbols in filenames
|
- handles spaces/symbols in filenames
|
||||||
- has better multi-stream perf (e.g. `sane-sync-music` should be able to copy N items in parallel)
|
- has better multi-stream perf (e.g. `sane-sync-music` should be able to copy N items in parallel)
|
||||||
|
- firefox: open *all* links (http, https, ...) with system handler
|
||||||
|
- removes the need for open-in-mpv, firefox-xdg-open, etc.
|
||||||
|
- matrix room links *just work*.
|
||||||
|
- `network.protocol-handler.external.https = true` in about:config *seems* to do this,
|
||||||
|
but breaks some webpages (e.g. Pleroma)
|
||||||
|
|
||||||
### security/resilience
|
### security/resilience
|
||||||
- validate duplicity backups!
|
- enable `snapper` btrfs snapshots (`services.snapper`)
|
||||||
- encrypt more ~ dirs (~/archives, ~/records, ..?)
|
|
||||||
- best to do this after i know for sure i have good backups
|
|
||||||
- /mnt/desko/home, etc, shouldn't include secrets (~/private)
|
- /mnt/desko/home, etc, shouldn't include secrets (~/private)
|
||||||
- 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 `nix`
|
- sandbox `nix`
|
||||||
- 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
|
||||||
- LL_FS_RW=/ isn't enough -- need all mount points like `=/:/proc:/sys:...`.
|
- LL_FS_RW=/ isn't enough -- need all mount points like `=/:/proc:/sys:...`.
|
||||||
@@ -116,18 +127,17 @@
|
|||||||
|
|
||||||
#### moby
|
#### moby
|
||||||
- fix cpuidle (gets better power consumption): <https://xnux.eu/log/077.html>
|
- fix cpuidle (gets better power consumption): <https://xnux.eu/log/077.html>
|
||||||
|
- fix cpupower for better power/perf
|
||||||
|
- `journalctl -u cpupower --boot` (problem is present on lappy, at least)
|
||||||
- moby: tune keyboard layout
|
- moby: tune keyboard layout
|
||||||
- SwayNC:
|
- SwayNC: add option to change audio output
|
||||||
- don't show MPRIS if no players detected
|
|
||||||
- this is a problem of playerctld, i guess
|
|
||||||
- add option to change audio output
|
|
||||||
- moby: tune GPS
|
- moby: tune GPS
|
||||||
- fix iio-sensor-proxy magnetometer scaling
|
- fix iio-sensor-proxy magnetometer scaling
|
||||||
- tune QGPS setting in eg25-control, for less jitter?
|
- tune QGPS setting in eg25-control, for less jitter?
|
||||||
- configure geoclue to do some smoothing?
|
- configure geoclue to do some smoothing?
|
||||||
- manually do smoothing, as some layer between mepo and geoclue?
|
- manually do smoothing, as some layer between mepo and geoclue?
|
||||||
|
- email wigle.net people to unlock API access
|
||||||
- moby: port `freshen-agps` timer service to s6 (maybe i want some `s6-cron` or something)
|
- moby: port `freshen-agps` timer service to s6 (maybe i want some `s6-cron` or something)
|
||||||
- moby: show battery state on ssh login
|
|
||||||
- moby: improve gPodder launch time
|
- moby: improve gPodder launch time
|
||||||
- moby: theme GTK apps (i.e. non-adwaita styles)
|
- moby: theme GTK apps (i.e. non-adwaita styles)
|
||||||
- especially, make the menubar collapsible
|
- especially, make the menubar collapsible
|
||||||
@@ -136,6 +146,8 @@
|
|||||||
#### non-moby
|
#### non-moby
|
||||||
- RSS: integrate a paywall bypass
|
- RSS: integrate a paywall bypass
|
||||||
- e.g. self-hosted [ladder](https://github.com/everywall/ladder) (like 12ft.io)
|
- e.g. self-hosted [ladder](https://github.com/everywall/ladder) (like 12ft.io)
|
||||||
|
- RSS: have podcasts get downloaded straight into ~/Videos/...
|
||||||
|
- and strip the ads out using Whisper transcription + asking a LLM where the ad breaks are
|
||||||
- neovim: set up language server (lsp; rnix-lsp; nvim-lspconfig)
|
- neovim: set up language server (lsp; rnix-lsp; nvim-lspconfig)
|
||||||
- neovim: integrate LLMs
|
- neovim: integrate LLMs
|
||||||
- Helix: make copy-to-system clipboard be the default
|
- Helix: make copy-to-system clipboard be the default
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
./fs.nix
|
./fs.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
sane.services.trust-dns.asSystemResolver = false; # TEMPORARY: TODO: re-enable trust-dns
|
sane.services.hickory-dns.asSystemResolver = false; # TEMPORARY: TODO: re-enable hickory-dns
|
||||||
# sane.programs.devPkgs.enableFor.user.colin = true;
|
# sane.programs.devPkgs.enableFor.user.colin = true;
|
||||||
# sane.guest.enable = true;
|
# sane.guest.enable = true;
|
||||||
|
|
||||||
@@ -28,7 +28,6 @@
|
|||||||
sane.services.wg-home.ip = config.sane.hosts.by-name."desko".wg-home.ip;
|
sane.services.wg-home.ip = config.sane.hosts.by-name."desko".wg-home.ip;
|
||||||
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.rsync-net.enable = true;
|
sane.services.rsync-net.enable = true;
|
||||||
|
|
||||||
sane.nixcache.remote-builders.desko = false;
|
sane.nixcache.remote-builders.desko = false;
|
||||||
@@ -53,15 +52,18 @@
|
|||||||
# needed to use libimobiledevice/ifuse, for iphone sync
|
# needed to use libimobiledevice/ifuse, for iphone sync
|
||||||
services.usbmuxd.enable = true;
|
services.usbmuxd.enable = true;
|
||||||
|
|
||||||
|
# TODO: enable snapper (need to make `/nix` or `/nix/persist` a subvolume, somehow).
|
||||||
# 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
|
||||||
# - auto cleanup; keep the last 10 hourlies, last 10 daylies, last 10 monthlys.
|
# - auto cleanup; keep the last 10 hourlies, last 10 daylies, last 10 monthlys.
|
||||||
services.snapper.configs.nix = {
|
# to list snapshots: `sudo snapper --config nix list`
|
||||||
# TODO: for the impermanent setup, we'd prefer to just do /nix/persist,
|
# to take a snapshot: `sudo snapper --config nix create`
|
||||||
# but that also requires setting up the persist dir as a subvol
|
# services.snapper.configs.nix = {
|
||||||
SUBVOLUME = "/nix";
|
# # TODO: for the impermanent setup, we'd prefer to just do /nix/persist,
|
||||||
# TODO: ALLOW_USERS doesn't seem to work. still need `sudo snapper -c nix list`
|
# # but that also requires setting up the persist dir as a subvol
|
||||||
ALLOW_USERS = [ "colin" ];
|
# SUBVOLUME = "/nix";
|
||||||
};
|
# # TODO: ALLOW_USERS doesn't seem to work. still need `sudo snapper -c nix list`
|
||||||
|
# ALLOW_USERS = [ "colin" ];
|
||||||
|
# };
|
||||||
}
|
}
|
||||||
|
@@ -28,14 +28,18 @@
|
|||||||
|
|
||||||
sane.services.rsync-net.enable = true;
|
sane.services.rsync-net.enable = true;
|
||||||
|
|
||||||
|
# TODO: enable snapper (need to make `/nix` or `/nix/persist` a subvolume, somehow).
|
||||||
# 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
|
||||||
# - auto cleanup; keep the last 10 hourlies, last 10 daylies, last 10 monthlys.
|
# - auto cleanup; keep the last 10 hourlies, last 10 daylies, last 10 monthlys.
|
||||||
services.snapper.configs.nix = {
|
# to list snapshots: `sudo snapper --config nix list`
|
||||||
# TODO: for the impermanent setup, we'd prefer to just do /nix/persist,
|
# to take a snapshot: `sudo snapper --config nix create`
|
||||||
# but that also requires setting up the persist dir as a subvol
|
# services.snapper.configs.nix = {
|
||||||
SUBVOLUME = "/nix";
|
# # TODO: for the impermanent setup, we'd prefer to just do /nix/persist,
|
||||||
ALLOW_USERS = [ "colin" ];
|
# # but that also requires setting up the persist dir as a subvol
|
||||||
};
|
# SUBVOLUME = "/nix";
|
||||||
|
# # TODO: ALLOW_USERS doesn't seem to work. still need `sudo snapper -c nix list`
|
||||||
|
# ALLOW_USERS = [ "colin" ];
|
||||||
|
# };
|
||||||
}
|
}
|
||||||
|
@@ -21,7 +21,7 @@
|
|||||||
"sane-scripts.stop-all-servo"
|
"sane-scripts.stop-all-servo"
|
||||||
];
|
];
|
||||||
sane.services.dyn-dns.enable = true;
|
sane.services.dyn-dns.enable = true;
|
||||||
sane.services.trust-dns.asSystemResolver = false; # TODO: enable once it's all working well
|
sane.services.hickory-dns.asSystemResolver = false; # TODO: enable once it's all working well
|
||||||
sane.services.wg-home.enable = true;
|
sane.services.wg-home.enable = true;
|
||||||
sane.services.wg-home.visibleToWan = true;
|
sane.services.wg-home.visibleToWan = true;
|
||||||
sane.services.wg-home.forwardToWan = true;
|
sane.services.wg-home.forwardToWan = true;
|
||||||
@@ -31,7 +31,6 @@
|
|||||||
# sane.ovpn.addrV6 = "fd00:0000:1337:cafe:1111:1111:8df3:14b0";
|
# sane.ovpn.addrV6 = "fd00:0000:1337:cafe:1111:1111:8df3:14b0";
|
||||||
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.rsync-net.enable = true;
|
sane.services.rsync-net.enable = true;
|
||||||
|
|
||||||
# automatically log in at the virtual consoles.
|
# automatically log in at the virtual consoles.
|
||||||
|
@@ -7,6 +7,7 @@
|
|||||||
./ejabberd.nix
|
./ejabberd.nix
|
||||||
./freshrss.nix
|
./freshrss.nix
|
||||||
./export
|
./export
|
||||||
|
./hickory-dns.nix
|
||||||
./gitea.nix
|
./gitea.nix
|
||||||
./goaccess.nix
|
./goaccess.nix
|
||||||
./ipfs.nix
|
./ipfs.nix
|
||||||
@@ -20,13 +21,13 @@
|
|||||||
./nginx.nix
|
./nginx.nix
|
||||||
./nixos-prebuild.nix
|
./nixos-prebuild.nix
|
||||||
./ntfy
|
./ntfy
|
||||||
|
./ollama.nix
|
||||||
./pict-rs.nix
|
./pict-rs.nix
|
||||||
./pleroma.nix
|
./pleroma.nix
|
||||||
./postgres.nix
|
./postgres.nix
|
||||||
./prosody
|
./prosody
|
||||||
./slskd.nix
|
./slskd.nix
|
||||||
./transmission
|
./transmission
|
||||||
./trust-dns.nix
|
|
||||||
./wikipedia.nix
|
./wikipedia.nix
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,11 @@
|
|||||||
# postfix config options: <https://www.postfix.org/postconf.5.html>
|
# postfix config options: <https://www.postfix.org/postconf.5.html>
|
||||||
|
# config files:
|
||||||
|
# - /etc/postfix/main.cf
|
||||||
|
# - /etc/postfix/master.cf
|
||||||
|
#
|
||||||
|
# logs:
|
||||||
|
# - postfix logs directly to *syslog*,
|
||||||
|
# so check e.g. ~/.local/share/rsyslog
|
||||||
|
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
@@ -20,12 +27,12 @@ in
|
|||||||
{
|
{
|
||||||
sane.persist.sys.byStore.private = [
|
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"; } #< TODO: migrate to secrets
|
||||||
{ 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
|
||||||
# "/var/lib/dovecot"
|
# "/var/lib/dovecot"
|
||||||
|
# "/var/lib/postfix"
|
||||||
];
|
];
|
||||||
|
|
||||||
# XXX(2023/10/20): opening these ports in the firewall has the OPPOSITE effect as intended.
|
# XXX(2023/10/20): opening these ports in the firewall has the OPPOSITE effect as intended.
|
||||||
@@ -95,6 +102,7 @@ in
|
|||||||
services.postfix.sslCert = "/var/lib/acme/mx.uninsane.org/fullchain.pem";
|
services.postfix.sslCert = "/var/lib/acme/mx.uninsane.org/fullchain.pem";
|
||||||
services.postfix.sslKey = "/var/lib/acme/mx.uninsane.org/key.pem";
|
services.postfix.sslKey = "/var/lib/acme/mx.uninsane.org/key.pem";
|
||||||
|
|
||||||
|
# see: `man 5 virtual`
|
||||||
services.postfix.virtual = ''
|
services.postfix.virtual = ''
|
||||||
notify.matrix@uninsane.org matrix-synapse
|
notify.matrix@uninsane.org matrix-synapse
|
||||||
@uninsane.org colin
|
@uninsane.org colin
|
||||||
@@ -135,6 +143,20 @@ in
|
|||||||
# smtpd_sender_restrictions = reject_unknown_sender_domain
|
# smtpd_sender_restrictions = reject_unknown_sender_domain
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# debugging options:
|
||||||
|
# services.postfix.masterConfig = {
|
||||||
|
# "proxymap".args = [ "-v" ];
|
||||||
|
# "proxywrite".args = [ "-v" ];
|
||||||
|
# "relay".args = [ "-v" ];
|
||||||
|
# "smtp".args = [ "-v" ];
|
||||||
|
# "smtp_inet".args = [ "-v" ];
|
||||||
|
# "submission".args = [ "-v" ];
|
||||||
|
# "submissions".args = [ "-v" ];
|
||||||
|
# "submissions".chroot = false;
|
||||||
|
# "submissions".private = false;
|
||||||
|
# "submissions".privileged = true;
|
||||||
|
# };
|
||||||
|
|
||||||
services.postfix.enableSubmission = true;
|
services.postfix.enableSubmission = true;
|
||||||
services.postfix.submissionOptions = submissionOptions;
|
services.postfix.submissionOptions = submissionOptions;
|
||||||
services.postfix.enableSubmissions = true;
|
services.postfix.enableSubmissions = true;
|
||||||
@@ -142,6 +164,10 @@ in
|
|||||||
|
|
||||||
systemd.services.postfix.after = [ "wireguard-wg-ovpns.service" ];
|
systemd.services.postfix.after = [ "wireguard-wg-ovpns.service" ];
|
||||||
systemd.services.postfix.partOf = [ "wireguard-wg-ovpns.service" ];
|
systemd.services.postfix.partOf = [ "wireguard-wg-ovpns.service" ];
|
||||||
|
systemd.services.postfix.unitConfig.RequiresMountsFor = [
|
||||||
|
"/var/spool/mail" # spooky errors when postfix is run w/o this: `warning: connect #1 to subsystem private/proxymap: Connection refused`
|
||||||
|
"/var/lib/opendkim"
|
||||||
|
];
|
||||||
systemd.services.postfix.serviceConfig = {
|
systemd.services.postfix.serviceConfig = {
|
||||||
# run this behind the OVPN static VPN
|
# run this behind the OVPN static VPN
|
||||||
NetworkNamespacePath = "/run/netns/ovpns";
|
NetworkNamespacePath = "/run/netns/ovpns";
|
||||||
@@ -175,23 +201,30 @@ in
|
|||||||
|
|
||||||
|
|
||||||
#### OUTGOING MESSAGE REWRITING:
|
#### OUTGOING MESSAGE REWRITING:
|
||||||
services.postfix.enableHeaderChecks = true;
|
# - `man 5 header_checks`
|
||||||
services.postfix.headerChecks = [
|
# - <https://www.postfix.org/header_checks.5.html>
|
||||||
# intercept gitea registration confirmations and manually screen them
|
# - populates `/var/lib/postfix/conf/header_checks`
|
||||||
{
|
# XXX(2024-08-06): registration gating via email matches is AWFUL:
|
||||||
# headerChecks are somehow ignorant of alias rules: have to redirect to a real user
|
# 1. bypassed if the service offers localization.
|
||||||
action = "REDIRECT colin@uninsane.org";
|
# 2. if i try to forward the registration request, it may match the filter again and get sent back to my inbox.
|
||||||
pattern = "/^Subject: Please activate your account/";
|
# 3. header checks are possibly under-used in the ecosystem, and may break postfix config.
|
||||||
}
|
# services.postfix.enableHeaderChecks = true;
|
||||||
# intercept Matrix registration confirmations
|
# services.postfix.headerChecks = [
|
||||||
{
|
# # intercept gitea registration confirmations and manually screen them
|
||||||
action = "REDIRECT colin@uninsane.org";
|
# {
|
||||||
pattern = "/^Subject:.*Validate your email/";
|
# # headerChecks are somehow ignorant of alias rules: have to redirect to a real user
|
||||||
}
|
# action = "REDIRECT colin@uninsane.org";
|
||||||
# XXX postfix only supports performing ONE action per header.
|
# pattern = "/^Subject: Please activate your account/";
|
||||||
# {
|
# }
|
||||||
# action = "REPLACE Subject: git application: Please activate your account";
|
# # intercept Matrix registration confirmations
|
||||||
# pattern = "/^Subject:.*activate your account/";
|
# {
|
||||||
# }
|
# action = "REDIRECT colin@uninsane.org";
|
||||||
];
|
# pattern = "/^Subject:.*Validate your email/";
|
||||||
|
# }
|
||||||
|
# # XXX postfix only supports performing ONE action per header.
|
||||||
|
# # {
|
||||||
|
# # action = "REPLACE Subject: git application: Please activate your account";
|
||||||
|
# # pattern = "/^Subject:.*activate your account/";
|
||||||
|
# # }
|
||||||
|
# ];
|
||||||
}
|
}
|
||||||
|
@@ -1,10 +1,14 @@
|
|||||||
# config options: <https://docs.gitea.io/en-us/administration/config-cheat-sheet/>
|
# config options: <https://docs.gitea.io/en-us/administration/config-cheat-sheet/>
|
||||||
|
# TODO: service shouldn't run as `git` user, but as `gitea`
|
||||||
{ config, pkgs, lib, ... }:
|
{ config, pkgs, lib, ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
sane.persist.sys.byStore.private = [
|
sane.persist.sys.byStore.private = [
|
||||||
{ user = "git"; group = "gitea"; mode = "0750"; path = "/var/lib/gitea"; method = "bind"; }
|
{ user = "git"; group = "gitea"; mode = "0750"; path = "/var/lib/gitea"; method = "bind"; }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
sane.programs.gitea.enableFor.user.colin = true; # for admin, and monitoring
|
||||||
|
|
||||||
services.gitea.enable = true;
|
services.gitea.enable = true;
|
||||||
services.gitea.user = "git"; # default is 'gitea'
|
services.gitea.user = "git"; # default is 'gitea'
|
||||||
services.gitea.database.type = "postgres";
|
services.gitea.database.type = "postgres";
|
||||||
@@ -40,14 +44,21 @@
|
|||||||
# timeout for email approval. 5760 = 4 days. 10080 = 7 days
|
# timeout for email approval. 5760 = 4 days. 10080 = 7 days
|
||||||
ACTIVE_CODE_LIVE_MINUTES = 10080;
|
ACTIVE_CODE_LIVE_MINUTES = 10080;
|
||||||
# REGISTER_EMAIL_CONFIRM = false;
|
# REGISTER_EMAIL_CONFIRM = false;
|
||||||
# REGISTER_MANUAL_CONFIRM = true;
|
# REGISTER_EMAIL_CONFIRM = true; #< override REGISTER_MANUAL_CONFIRM
|
||||||
REGISTER_EMAIL_CONFIRM = true;
|
REGISTER_MANUAL_CONFIRM = true;
|
||||||
# not sure what this notifies *on*...
|
# not sure what this notifies *on*...
|
||||||
ENABLE_NOTIFY_MAIL = true;
|
ENABLE_NOTIFY_MAIL = true;
|
||||||
# defaults to image-based captcha.
|
# defaults to image-based captcha.
|
||||||
# also supports recaptcha (with custom URLs) or hCaptcha.
|
# also supports recaptcha (with custom URLs) or hCaptcha.
|
||||||
ENABLE_CAPTCHA = true;
|
ENABLE_CAPTCHA = true;
|
||||||
NOREPLY_ADDRESS = "noreply.anonymous.git@uninsane.org";
|
NOREPLY_ADDRESS = "noreply.anonymous.git@uninsane.org";
|
||||||
|
EMAIL_DOMAIN_BLOCKLIST = lib.concatStringsSep ", " [
|
||||||
|
"*.claychoen.top"
|
||||||
|
"*.gemmasmith.co.uk"
|
||||||
|
"*.jenniferlawrence.uk"
|
||||||
|
"*.sarahconnor.co.uk"
|
||||||
|
"*.marymarshall.co.uk"
|
||||||
|
];
|
||||||
};
|
};
|
||||||
session = {
|
session = {
|
||||||
COOKIE_SECURE = true;
|
COOKIE_SECURE = true;
|
||||||
|
@@ -55,7 +55,7 @@ in
|
|||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
services.trust-dns.settings.zones = [ "uninsane.org" ];
|
services.hickory-dns.settings.zones = [ "uninsane.org" ];
|
||||||
|
|
||||||
|
|
||||||
networking.nat.enable = true; #< TODO: try removing this?
|
networking.nat.enable = true; #< TODO: try removing this?
|
||||||
@@ -83,8 +83,8 @@ in
|
|||||||
# };
|
# };
|
||||||
|
|
||||||
|
|
||||||
sane.services.trust-dns.enable = true;
|
sane.services.hickory-dns.enable = true;
|
||||||
sane.services.trust-dns.instances = let
|
sane.services.hickory-dns.instances = let
|
||||||
mkSubstitutions = flavor: {
|
mkSubstitutions = flavor: {
|
||||||
"%ADOOF%" = config.sane.netns.doof.netnsPubIpv4;
|
"%ADOOF%" = config.sane.netns.doof.netnsPubIpv4;
|
||||||
"%ANATIVE%" = nativeAddrs."servo.${flavor}";
|
"%ANATIVE%" = nativeAddrs."servo.${flavor}";
|
||||||
@@ -141,5 +141,5 @@ in
|
|||||||
# };
|
# };
|
||||||
};
|
};
|
||||||
|
|
||||||
sane.services.dyn-dns.restartOnChange = lib.map (c: "${c.service}.service") (builtins.attrValues config.sane.services.trust-dns.instances);
|
sane.services.dyn-dns.restartOnChange = lib.map (c: "${c.service}.service") (builtins.attrValues config.sane.services.hickory-dns.instances);
|
||||||
}
|
}
|
@@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
# services.matrix-synapse.enable_registration_captcha = true;
|
# services.matrix-synapse.enable_registration_captcha = true;
|
||||||
# services.matrix-synapse.enable_registration_without_verification = true;
|
# services.matrix-synapse.enable_registration_without_verification = true;
|
||||||
enable_registration = true;
|
# enable_registration = true;
|
||||||
# services.matrix-synapse.registration_shared_secret = "<shared key goes here>";
|
# services.matrix-synapse.registration_shared_secret = "<shared key goes here>";
|
||||||
|
|
||||||
# default for listeners is port = 8448, tls = true, x_forwarded = false.
|
# default for listeners is port = 8448, tls = true, x_forwarded = false.
|
||||||
|
23
hosts/by-name/servo/services/ollama.nix
Normal file
23
hosts/by-name/servo/services/ollama.nix
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# ollama: <https://github.com/ollama/ollama>
|
||||||
|
# use: `ollama run llama3.1`
|
||||||
|
# or: `ollama run llama3.1:70b`
|
||||||
|
# or use a remote session: <https://github.com/ggozad/oterm>
|
||||||
|
{ lib, ... }:
|
||||||
|
lib.mkIf false #< WIP
|
||||||
|
{
|
||||||
|
sane.persist.sys.byStore.plaintext = [
|
||||||
|
{ user = "ollama"; group = "ollama"; path = "/var/lib/ollama"; method = "bind"; }
|
||||||
|
];
|
||||||
|
services.ollama.enable = true;
|
||||||
|
services.ollama.user = "ollama";
|
||||||
|
services.ollama.group = "ollama";
|
||||||
|
|
||||||
|
users.groups.ollama = {};
|
||||||
|
|
||||||
|
users.users.ollama = {
|
||||||
|
group = "ollama";
|
||||||
|
isSystemUser = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.ollama.serviceConfig.DynamicUser = lib.mkForce false;
|
||||||
|
}
|
@@ -40,10 +40,11 @@ REL_DIR="${TR_TORRENT_DIR#$DOWNLOAD_DIR/}"
|
|||||||
MEDIA_DIR="/var/media/$REL_DIR"
|
MEDIA_DIR="/var/media/$REL_DIR"
|
||||||
|
|
||||||
destructive mkdir -p "$(dirname "$MEDIA_DIR")"
|
destructive mkdir -p "$(dirname "$MEDIA_DIR")"
|
||||||
destructive rsync -arv "$TR_TORRENT_DIR/" "$MEDIA_DIR/"
|
destructive rsync -rlv "$TR_TORRENT_DIR/" "$MEDIA_DIR/"
|
||||||
# make the media rwx by anyone in the group
|
# make the media rwx by anyone in the group
|
||||||
destructive find "$MEDIA_DIR" -type d -exec setfacl --recursive --modify d:g::rwx,o::rx {} \;
|
destructive find "$MEDIA_DIR" -type d -exec setfacl --recursive --modify d:g::rwx,o::rx {} \;
|
||||||
destructive find "$MEDIA_DIR" -type d -exec chmod g+rw,a+rx {} \;
|
destructive find "$MEDIA_DIR" -type d -exec chmod g+rw,a+rx {} \;
|
||||||
|
destructive find "$MEDIA_DIR" -type f -exec chmod g+rw,a+r {} \;
|
||||||
|
|
||||||
# if there's a single directory inside the media dir, then inline that
|
# if there's a single directory inside the media dir, then inline that
|
||||||
subdirs=("$MEDIA_DIR"/*)
|
subdirs=("$MEDIA_DIR"/*)
|
||||||
|
@@ -59,6 +59,7 @@ let
|
|||||||
podcasts = [
|
podcasts = [
|
||||||
(fromDb "acquiredlpbonussecretsecret.libsyn.com" // tech) # ACQ2 - more "Acquired" episodes
|
(fromDb "acquiredlpbonussecretsecret.libsyn.com" // tech) # ACQ2 - more "Acquired" episodes
|
||||||
(fromDb "allinchamathjason.libsyn.com" // pol)
|
(fromDb "allinchamathjason.libsyn.com" // pol)
|
||||||
|
(fromDb "api.oyez.org/podcasts/oral-arguments/2015" // pol) # Supreme Court Oral Arguments ("2015" in URL means nothing -- it's still updated)
|
||||||
(fromDb "anchor.fm/s/34c7232c/podcast/rss" // tech) # Civboot -- https://anchor.fm/civboot
|
(fromDb "anchor.fm/s/34c7232c/podcast/rss" // tech) # Civboot -- https://anchor.fm/civboot
|
||||||
(fromDb "anchor.fm/s/2da69154/podcast/rss" // tech) # POD OF JAKE -- https://podofjake.com/
|
(fromDb "anchor.fm/s/2da69154/podcast/rss" // tech) # POD OF JAKE -- https://podofjake.com/
|
||||||
(fromDb "cast.postmarketos.org" // tech)
|
(fromDb "cast.postmarketos.org" // tech)
|
||||||
@@ -90,6 +91,7 @@ let
|
|||||||
(fromDb "omny.fm/shows/cool-people-who-did-cool-stuff" // pol) # Maggie Killjoy -- referenced by Cory Doctorow
|
(fromDb "omny.fm/shows/cool-people-who-did-cool-stuff" // pol) # Maggie Killjoy -- referenced by Cory Doctorow
|
||||||
(fromDb "omny.fm/shows/money-stuff-the-podcast") # Matt Levine
|
(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 "omny.fm/shows/weird-little-guys") # Cool Zone Media
|
||||||
(fromDb "originstories.libsyn.com" // uncat)
|
(fromDb "originstories.libsyn.com" // uncat)
|
||||||
(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
|
||||||
|
@@ -45,7 +45,7 @@ let
|
|||||||
"gid=100"
|
"gid=100"
|
||||||
];
|
];
|
||||||
|
|
||||||
ssh = common ++ fuse ++ [
|
ssh = common ++ fuseColin ++ [
|
||||||
"identityfile=/home/colin/.ssh/id_ed25519"
|
"identityfile=/home/colin/.ssh/id_ed25519"
|
||||||
# i *think* idmap=user means that `colin` on `localhost` and `colin` on the remote are actually treated as the same user, even if their uid/gid differs?
|
# i *think* idmap=user means that `colin` on `localhost` and `colin` on the remote are actually treated as the same user, even if their uid/gid differs?
|
||||||
# i.e., local colin's id is translated to/from remote colin's id on every operation?
|
# i.e., local colin's id is translated to/from remote colin's id on every operation?
|
||||||
@@ -107,18 +107,64 @@ let
|
|||||||
"connect_timeout=20"
|
"connect_timeout=20"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ifSshAuthorized = lib.mkIf config.sane.hosts.by-name."${config.networking.hostName}".ssh.authorized;
|
||||||
|
|
||||||
remoteHome = host: {
|
remoteHome = host: {
|
||||||
sane.programs.sshfs-fuse.enableFor.system = true;
|
sane.programs.sshfs-fuse.enableFor.system = true;
|
||||||
|
system.fsPackages = [
|
||||||
|
config.sane.programs.sshfs-fuse.package
|
||||||
|
];
|
||||||
fileSystems."/mnt/${host}/home" = {
|
fileSystems."/mnt/${host}/home" = {
|
||||||
device = "colin@${host}:/home/colin";
|
device = "sshfs#colin@${host}:/home/colin";
|
||||||
fsType = "fuse.sshfs";
|
fsType = "fuse3";
|
||||||
options = fsOpts.sshColin ++ fsOpts.lazyMount;
|
options = fsOpts.sshColin ++ fsOpts.lazyMount ++ [
|
||||||
|
# drop_privileges: after `mount.fuse3` opens /dev/fuse, it will drop all capabilities before invoking sshfs
|
||||||
|
"drop_privileges"
|
||||||
|
"auto_unmount" #< ensures that when the fs exits, it releases its mountpoint. then systemd can recognize it as failed.
|
||||||
|
];
|
||||||
noCheck = true;
|
noCheck = true;
|
||||||
};
|
};
|
||||||
sane.fs."/mnt/${host}/home" = sane-lib.fs.wanted {
|
sane.fs."/mnt/${host}/home" = {
|
||||||
dir.acl.user = "colin";
|
dir.acl.user = "colin";
|
||||||
dir.acl.group = "users";
|
dir.acl.group = "users";
|
||||||
dir.acl.mode = "0700";
|
dir.acl.mode = "0700";
|
||||||
|
wantedBy = [ "default.target" ];
|
||||||
|
mount.depends = [ "network-online.target" ];
|
||||||
|
mount.mountConfig.ExecSearchPath = [ "/run/current-system/sw/bin" ];
|
||||||
|
mount.mountConfig.User = "colin";
|
||||||
|
mount.mountConfig.AmbientCapabilities = "CAP_SETPCAP CAP_SYS_ADMIN";
|
||||||
|
# hardening (systemd-analyze security mnt-desko-home.mount):
|
||||||
|
# TODO: i can't use ProtectSystem=full here, because i can't create a new mount space; but...
|
||||||
|
# with drop_privileges, i *could* sandbox the actual `sshfs` program using e.g. bwrap
|
||||||
|
mount.mountConfig.CapabilityBoundingSet = "CAP_SETPCAP CAP_SYS_ADMIN";
|
||||||
|
mount.mountConfig.LockPersonality = true;
|
||||||
|
mount.mountConfig.MemoryDenyWriteExecute = true;
|
||||||
|
mount.mountConfig.NoNewPrivileges = true;
|
||||||
|
mount.mountConfig.ProtectClock = true;
|
||||||
|
mount.mountConfig.ProtectHostname = true;
|
||||||
|
mount.mountConfig.RemoveIPC = true;
|
||||||
|
mount.mountConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6";
|
||||||
|
#VVV this includes anything it reads from, e.g. /bin/sh; /nix/store/...
|
||||||
|
# see `systemd-analyze filesystems` for a full list
|
||||||
|
mount.mountConfig.RestrictFileSystems = "@common-block @basic-api fuse";
|
||||||
|
mount.mountConfig.RestrictRealtime = true;
|
||||||
|
mount.mountConfig.RestrictSUIDSGID = true;
|
||||||
|
mount.mountConfig.SystemCallArchitectures = "native";
|
||||||
|
mount.mountConfig.SystemCallFilter = [
|
||||||
|
"@system-service"
|
||||||
|
"@mount"
|
||||||
|
"~@chown"
|
||||||
|
"~@cpu-emulation"
|
||||||
|
"~@keyring"
|
||||||
|
# could remove almost all io calls, however one has to keep `open`, and `write`, to communicate with the fuse device.
|
||||||
|
# so that's pretty useless as a way to prevent write access
|
||||||
|
];
|
||||||
|
mount.mountConfig.IPAddressDeny = "any";
|
||||||
|
mount.mountConfig.IPAddressAllow = "10.0.0.0/8";
|
||||||
|
mount.mountConfig.DevicePolicy = "closed"; # only allow /dev/{null,zero,full,random,urandom}
|
||||||
|
mount.mountConfig.DeviceAllow = "/dev/fuse";
|
||||||
|
# mount.mountConfig.RestrictNamespaces = true; #< my sshfs sandboxing uses bwrap
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
remoteServo = subdir: let
|
remoteServo = subdir: let
|
||||||
@@ -126,36 +172,122 @@ let
|
|||||||
systemdName = utils.escapeSystemdPath localPath;
|
systemdName = utils.escapeSystemdPath localPath;
|
||||||
in {
|
in {
|
||||||
sane.programs.curlftpfs.enableFor.system = true;
|
sane.programs.curlftpfs.enableFor.system = true;
|
||||||
sane.fs."${localPath}" = sane-lib.fs.wanted {
|
system.fsPackages = [
|
||||||
dir.acl.user = "colin";
|
config.sane.programs.curlftpfs.package
|
||||||
dir.acl.group = "users";
|
];
|
||||||
dir.acl.mode = "0750";
|
|
||||||
};
|
|
||||||
fileSystems."${localPath}" = {
|
fileSystems."${localPath}" = {
|
||||||
device = "ftp://servo-hn:/${subdir}";
|
device = "curlftpfs#ftp://servo-hn:/${subdir}";
|
||||||
noCheck = true;
|
noCheck = true;
|
||||||
fsType = "fuse.curlftpfs";
|
fsType = "fuse3";
|
||||||
options = fsOpts.ftp ++ fsOpts.noauto;
|
options = fsOpts.ftp ++ fsOpts.noauto ++ [
|
||||||
|
# drop_privileges: after `mount.fuse3` opens /dev/fuse, it will drop all capabilities before invoking sshfs
|
||||||
|
"drop_privileges"
|
||||||
|
"auto_unmount" #< ensures that when the fs exits, it releases its mountpoint. then systemd can recognize it as failed.
|
||||||
|
];
|
||||||
# fsType = "nfs";
|
# fsType = "nfs";
|
||||||
# options = fsOpts.nfs ++ fsOpts.lazyMount;
|
# options = fsOpts.nfs ++ fsOpts.lazyMount;
|
||||||
};
|
};
|
||||||
|
sane.fs."${localPath}" = {
|
||||||
systemd.mounts = let
|
dir.acl.user = "colin";
|
||||||
fsEntry = config.fileSystems."${localPath}";
|
dir.acl.group = "users";
|
||||||
in [{
|
dir.acl.mode = "0750";
|
||||||
#VVV repeat what systemd would ordinarily scrape from /etc/fstab
|
wantedBy = [ "default.target" ];
|
||||||
where = localPath;
|
mount.depends = [ "network-online.target" "${systemdName}-reachable.service" ];
|
||||||
what = fsEntry.device;
|
|
||||||
type = fsEntry.fsType;
|
|
||||||
options = lib.concatStringsSep "," fsEntry.options;
|
|
||||||
after = [ "network-online.target" ];
|
|
||||||
requires = [ "network-online.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.
|
#VVV patch so that when the mount fails, we start a timer to remount it.
|
||||||
# and for a disconnection after a good mount (onSuccess), restart the timer to be more aggressive
|
# and for a disconnection after a good mount (onSuccess), restart the timer to be more aggressive
|
||||||
onFailure = [ "${systemdName}.timer" ];
|
mount.unitConfig.OnFailure = [ "${systemdName}.timer" ];
|
||||||
onSuccess = [ "${systemdName}-restart-timer.target" ];
|
mount.unitConfig.OnSuccess = [ "${systemdName}-restart-timer.target" ];
|
||||||
}];
|
|
||||||
|
mount.mountConfig.TimeoutSec = "10s";
|
||||||
|
mount.mountConfig.ExecSearchPath = [ "/run/current-system/sw/bin" ];
|
||||||
|
mount.mountConfig.User = "colin";
|
||||||
|
mount.mountConfig.AmbientCapabilities = "CAP_SETPCAP CAP_SYS_ADMIN";
|
||||||
|
# hardening (systemd-analyze security mnt-servo-playground.mount)
|
||||||
|
mount.mountConfig.CapabilityBoundingSet = "CAP_SETPCAP CAP_SYS_ADMIN";
|
||||||
|
mount.mountConfig.LockPersonality = true;
|
||||||
|
mount.mountConfig.MemoryDenyWriteExecute = true;
|
||||||
|
mount.mountConfig.NoNewPrivileges = true;
|
||||||
|
mount.mountConfig.ProtectClock = true;
|
||||||
|
mount.mountConfig.ProtectHostname = true;
|
||||||
|
mount.mountConfig.RemoveIPC = true;
|
||||||
|
mount.mountConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6";
|
||||||
|
#VVV this includes anything it reads from, e.g. /bin/sh; /nix/store/...
|
||||||
|
# see `systemd-analyze filesystems` for a full list
|
||||||
|
mount.mountConfig.RestrictFileSystems = "@common-block @basic-api fuse";
|
||||||
|
mount.mountConfig.RestrictRealtime = true;
|
||||||
|
mount.mountConfig.RestrictSUIDSGID = true;
|
||||||
|
mount.mountConfig.SystemCallArchitectures = "native";
|
||||||
|
mount.mountConfig.SystemCallFilter = [
|
||||||
|
"@system-service"
|
||||||
|
"@mount"
|
||||||
|
"~@chown"
|
||||||
|
"~@cpu-emulation"
|
||||||
|
"~@keyring"
|
||||||
|
# could remove almost all io calls, however one has to keep `open`, and `write`, to communicate with the fuse device.
|
||||||
|
# so that's pretty useless as a way to prevent write access
|
||||||
|
];
|
||||||
|
mount.mountConfig.IPAddressDeny = "any";
|
||||||
|
mount.mountConfig.IPAddressAllow = "10.0.10.5";
|
||||||
|
mount.mountConfig.DevicePolicy = "closed"; # only allow /dev/{null,zero,full,random,urandom}
|
||||||
|
mount.mountConfig.DeviceAllow = "/dev/fuse";
|
||||||
|
# mount.mountConfig.RestrictNamespaces = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services."${systemdName}-reachable" = {
|
||||||
|
serviceConfig.ExecSearchPath = [ "/run/current-system/sw/bin" ];
|
||||||
|
serviceConfig.ExecStart = lib.escapeShellArgs [
|
||||||
|
"curlftpfs"
|
||||||
|
"ftp://servo-hn:/${subdir}"
|
||||||
|
"/dev/null"
|
||||||
|
"-o"
|
||||||
|
(lib.concatStringsSep "," ([ "exit_after_connect" ] ++ config.fileSystems."${localPath}".options))
|
||||||
|
];
|
||||||
|
serviceConfig.RemainAfterExit = true;
|
||||||
|
serviceConfig.Type = "oneshot";
|
||||||
|
unitConfig.BindsTo = [ "${systemdName}.mount" ];
|
||||||
|
# hardening (systemd-analyze security mnt-servo-playground-reachable.service)
|
||||||
|
serviceConfig.AmbientCapabilities = "";
|
||||||
|
serviceConfig.CapabilityBoundingSet = "";
|
||||||
|
serviceConfig.DynamicUser = true;
|
||||||
|
serviceConfig.LockPersonality = true;
|
||||||
|
serviceConfig.MemoryDenyWriteExecute = true;
|
||||||
|
serviceConfig.NoNewPrivileges = true;
|
||||||
|
serviceConfig.PrivateDevices = true;
|
||||||
|
serviceConfig.PrivateMounts = true;
|
||||||
|
serviceConfig.PrivateTmp = true;
|
||||||
|
serviceConfig.PrivateUsers = true;
|
||||||
|
serviceConfig.ProcSubset = "all";
|
||||||
|
serviceConfig.ProtectClock = true;
|
||||||
|
serviceConfig.ProtectControlGroups = true;
|
||||||
|
serviceConfig.ProtectHome = true;
|
||||||
|
serviceConfig.ProtectKernelModules = true;
|
||||||
|
serviceConfig.ProtectProc = "invisible";
|
||||||
|
serviceConfig.ProtectSystem = "strict";
|
||||||
|
serviceConfig.RemoveIPC = true;
|
||||||
|
serviceConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6";
|
||||||
|
# serviceConfig.RestrictFileSystems = "@common-block @basic-api"; #< NOPE
|
||||||
|
serviceConfig.RestrictRealtime = true;
|
||||||
|
serviceConfig.RestrictSUIDSGID = true;
|
||||||
|
serviceConfig.SystemCallArchitectures = "native";
|
||||||
|
serviceConfig.SystemCallFilter = [
|
||||||
|
"@system-service"
|
||||||
|
"@mount"
|
||||||
|
"~@chown"
|
||||||
|
"~@cpu-emulation"
|
||||||
|
"~@keyring"
|
||||||
|
# "~@privileged" #< NOPE
|
||||||
|
"~@resources"
|
||||||
|
# could remove some more probably
|
||||||
|
];
|
||||||
|
serviceConfig.IPAddressDeny = "any";
|
||||||
|
serviceConfig.IPAddressAllow = "10.0.10.5";
|
||||||
|
serviceConfig.DevicePolicy = "closed";
|
||||||
|
# exceptions
|
||||||
|
serviceConfig.ProtectHostname = false;
|
||||||
|
serviceConfig.ProtectKernelLogs = false;
|
||||||
|
serviceConfig.ProtectKernelTunables = false;
|
||||||
|
};
|
||||||
|
|
||||||
systemd.targets."${systemdName}-restart-timer" = {
|
systemd.targets."${systemdName}-restart-timer" = {
|
||||||
# hack unit which, when started, stops the timer (if running), and then starts it again.
|
# hack unit which, when started, stops the timer (if running), and then starts it again.
|
||||||
after = [ "${systemdName}.timer" ];
|
after = [ "${systemdName}.timer" ];
|
||||||
@@ -221,10 +353,11 @@ lib.mkMerge [
|
|||||||
programs.fuse.userAllowOther = true; #< necessary for `allow_other` or `allow_root` options.
|
programs.fuse.userAllowOther = true; #< necessary for `allow_other` or `allow_root` options.
|
||||||
}
|
}
|
||||||
|
|
||||||
(remoteHome "crappy")
|
(ifSshAuthorized (remoteHome "crappy"))
|
||||||
(remoteHome "desko")
|
(ifSshAuthorized (remoteHome "desko"))
|
||||||
(remoteHome "lappy")
|
(ifSshAuthorized (remoteHome "lappy"))
|
||||||
(remoteHome "moby")
|
(ifSshAuthorized (remoteHome "moby"))
|
||||||
|
(ifSshAuthorized (remoteHome "servo"))
|
||||||
# this granularity of servo media mounts is necessary to support sandboxing:
|
# this granularity of servo media mounts is necessary to support sandboxing:
|
||||||
# for flaky mounts, we can only bind the mountpoint itself into the sandbox,
|
# for flaky mounts, we can only bind the mountpoint itself into the sandbox,
|
||||||
# so it's either this or unconditionally bind all of media/.
|
# so it's either this or unconditionally bind all of media/.
|
||||||
|
@@ -9,12 +9,9 @@
|
|||||||
"Books/local"
|
"Books/local"
|
||||||
"Music"
|
"Music"
|
||||||
|
|
||||||
# these are persisted simply to save on RAM.
|
# this is persisted simply to save on RAM. mesa_shader_cache is < 10 MB.
|
||||||
# ~/.cache/nix can become several GB.
|
|
||||||
# mesa_shader_cache is < 10 MB.
|
|
||||||
# TODO: integrate with sane.programs.sandbox?
|
# TODO: integrate with sane.programs.sandbox?
|
||||||
".cache/mesa_shader_cache"
|
".cache/mesa_shader_cache"
|
||||||
".cache/nix"
|
|
||||||
];
|
];
|
||||||
sane.user.persist.byStore.private = [
|
sane.user.persist.byStore.private = [
|
||||||
"archive"
|
"archive"
|
||||||
|
@@ -45,8 +45,8 @@
|
|||||||
sane.ids.pict-rs.gid = 2409;
|
sane.ids.pict-rs.gid = 2409;
|
||||||
sane.ids.sftpgo.uid = 2410;
|
sane.ids.sftpgo.uid = 2410;
|
||||||
sane.ids.sftpgo.gid = 2410;
|
sane.ids.sftpgo.gid = 2410;
|
||||||
sane.ids.trust-dns.uid = 2411;
|
sane.ids.hickory-dns.uid = 2411; #< previously "trust-dns"
|
||||||
sane.ids.trust-dns.gid = 2411;
|
sane.ids.hickory-dns.gid = 2411; #< previously "trust-dns"
|
||||||
sane.ids.export.gid = 2412;
|
sane.ids.export.gid = 2412;
|
||||||
sane.ids.nfsuser.uid = 2413;
|
sane.ids.nfsuser.uid = 2413;
|
||||||
sane.ids.media.gid = 2414;
|
sane.ids.media.gid = 2414;
|
||||||
@@ -63,6 +63,8 @@
|
|||||||
sane.ids.nix-serve.uid = 2420;
|
sane.ids.nix-serve.uid = 2420;
|
||||||
sane.ids.nix-serve.gid = 2420;
|
sane.ids.nix-serve.gid = 2420;
|
||||||
sane.ids.plugdev.gid = 2421;
|
sane.ids.plugdev.gid = 2421;
|
||||||
|
sane.ids.ollama.uid = 2422;
|
||||||
|
sane.ids.ollama.gid = 2422;
|
||||||
|
|
||||||
sane.ids.colin.uid = 1000;
|
sane.ids.colin.uid = 1000;
|
||||||
sane.ids.guest.uid = 1100;
|
sane.ids.guest.uid = 1100;
|
||||||
|
@@ -23,16 +23,16 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
lib.mkMerge [
|
lib.mkMerge [
|
||||||
{
|
{
|
||||||
sane.services.trust-dns.enable = lib.mkDefault config.sane.services.trust-dns.asSystemResolver;
|
sane.services.hickory-dns.enable = lib.mkDefault config.sane.services.hickory-dns.asSystemResolver;
|
||||||
sane.services.trust-dns.asSystemResolver = lib.mkDefault true;
|
sane.services.hickory-dns.asSystemResolver = lib.mkDefault true;
|
||||||
}
|
}
|
||||||
(lib.mkIf (!config.sane.services.trust-dns.asSystemResolver) {
|
(lib.mkIf (!config.sane.services.hickory-dns.asSystemResolver) {
|
||||||
# use systemd's stub resolver.
|
# use systemd's stub resolver.
|
||||||
# /etc/resolv.conf isn't sophisticated enough to use different servers per net namespace (or link).
|
# /etc/resolv.conf isn't sophisticated enough to use different servers per net namespace (or link).
|
||||||
# instead, running the stub resolver on a known address in the root ns lets us rewrite packets
|
# instead, running the stub resolver on a known address in the root ns lets us rewrite packets
|
||||||
# in servo's ovnps namespace to use the provider's DNS resolvers.
|
# in servo's ovnps namespace to use the provider's DNS resolvers.
|
||||||
# a weakness is we can only query 1 NS at a time (unless we were to clone the packets?)
|
# a weakness is we can only query 1 NS at a time (unless we were to clone the packets?)
|
||||||
# TODO: improve trust-dns recursive resolver and then remove this
|
# TODO: improve hickory-dns recursive resolver and then remove this
|
||||||
services.resolved.enable = true; #< to disable, set ` = lib.mkForce false`, as other systemd features default to enabling `resolved`.
|
services.resolved.enable = true; #< to disable, set ` = lib.mkForce false`, as other systemd features default to enabling `resolved`.
|
||||||
# without DNSSEC:
|
# without DNSSEC:
|
||||||
# - dig matrix.org => works
|
# - dig matrix.org => works
|
||||||
@@ -40,7 +40,7 @@ lib.mkMerge [
|
|||||||
# with default DNSSEC:
|
# with default DNSSEC:
|
||||||
# - dig matrix.org => works
|
# - dig matrix.org => works
|
||||||
# - curl https://matrix.org => fails
|
# - curl https://matrix.org => fails
|
||||||
# i don't know why. this might somehow be interfering with the DNS run on this device (trust-dns)
|
# i don't know why. this might somehow be interfering with the DNS run on this device (hickory-dns)
|
||||||
services.resolved.dnssec = "false";
|
services.resolved.dnssec = "false";
|
||||||
networking.nameservers = [
|
networking.nameservers = [
|
||||||
# use systemd-resolved resolver
|
# use systemd-resolved resolver
|
||||||
@@ -74,7 +74,7 @@ lib.mkMerge [
|
|||||||
sane.silencedAssertions = [''.*Loading NSS modules from system.nssModules.*requires services.nscd.enable being set to true.*''];
|
sane.silencedAssertions = [''.*Loading NSS modules from system.nssModules.*requires services.nscd.enable being set to true.*''];
|
||||||
# add NSS modules into their own subdirectory.
|
# add NSS modules into their own subdirectory.
|
||||||
# then i can add just the NSS modules library path to the global LD_LIBRARY_PATH, rather than ALL of /run/current-system/sw/lib.
|
# then i can add just the NSS modules library path to the global LD_LIBRARY_PATH, rather than ALL of /run/current-system/sw/lib.
|
||||||
# TODO: i'm doing this so as to achieve mdns DNS resolution (avahi). it would be better to just have trust-dns delegate .local to avahi
|
# TODO: i'm doing this so as to achieve mdns DNS resolution (avahi). it would be better to just have hickory-dns delegate .local to avahi
|
||||||
# (except avahi doesn't act as a local resolver over DNS protocol -- only dbus).
|
# (except avahi doesn't act as a local resolver over DNS protocol -- only dbus).
|
||||||
environment.systemPackages = [(pkgs.symlinkJoin {
|
environment.systemPackages = [(pkgs.symlinkJoin {
|
||||||
name = "nss-modules";
|
name = "nss-modules";
|
||||||
|
@@ -37,7 +37,11 @@
|
|||||||
# serviceConfig.RestrictAddressFamilies = "AF_NETLINK AF_UNIX AF_QIPCRTR";
|
# serviceConfig.RestrictAddressFamilies = "AF_NETLINK AF_UNIX AF_QIPCRTR";
|
||||||
# serviceConfig.NoNewPrivileges = true;
|
# serviceConfig.NoNewPrivileges = true;
|
||||||
|
|
||||||
serviceConfig.CapabilityBoundingSet = [ "CAP_NET_ADMIN" ]; #< TODO: make sure this is *really* taking effect, and isn't supplemental to upstream's `CAP_SYS_ADMIN` setting
|
serviceConfig.CapabilityBoundingSet = [
|
||||||
|
"" #< reset upstream capabilities
|
||||||
|
"CAP_NET_ADMIN"
|
||||||
|
"CAP_SYS_ADMIN" #< TODO: remove CAP_SYS_ADMIN!
|
||||||
|
];
|
||||||
serviceConfig.LockPersonality = true;
|
serviceConfig.LockPersonality = true;
|
||||||
# serviceConfig.PrivateUsers = true; #< untried, not likely to work since it needs capabilities
|
# serviceConfig.PrivateUsers = true; #< untried, not likely to work since it needs capabilities
|
||||||
serviceConfig.PrivateTmp = true;
|
serviceConfig.PrivateTmp = true;
|
||||||
|
@@ -66,6 +66,11 @@ in {
|
|||||||
serviceConfig.User = "networkmanager";
|
serviceConfig.User = "networkmanager";
|
||||||
serviceConfig.Group = "networkmanager";
|
serviceConfig.Group = "networkmanager";
|
||||||
serviceConfig.AmbientCapabilities = [
|
serviceConfig.AmbientCapabilities = [
|
||||||
|
"CAP_NET_ADMIN"
|
||||||
|
"CAP_NET_RAW"
|
||||||
|
"CAP_NET_BIND_SERVICE"
|
||||||
|
];
|
||||||
|
serviceConfig.CapabilityBoundingSet = [
|
||||||
# "CAP_DAC_OVERRIDE"
|
# "CAP_DAC_OVERRIDE"
|
||||||
"CAP_NET_ADMIN"
|
"CAP_NET_ADMIN"
|
||||||
"CAP_NET_RAW" #< required, else `libndp: ndp_sock_open: Failed to create ICMP6 socket.`
|
"CAP_NET_RAW" #< required, else `libndp: ndp_sock_open: Failed to create ICMP6 socket.`
|
||||||
@@ -76,6 +81,7 @@ in {
|
|||||||
];
|
];
|
||||||
serviceConfig.LockPersonality = true;
|
serviceConfig.LockPersonality = true;
|
||||||
serviceConfig.NoNewPrivileges = true;
|
serviceConfig.NoNewPrivileges = true;
|
||||||
|
serviceConfig.MemoryDenyWriteExecute = true;
|
||||||
serviceConfig.PrivateDevices = true; # remount /dev with just the basics, syscall filter to block @raw-io
|
serviceConfig.PrivateDevices = true; # remount /dev with just the basics, syscall filter to block @raw-io
|
||||||
serviceConfig.PrivateIPC = true;
|
serviceConfig.PrivateIPC = true;
|
||||||
serviceConfig.PrivateTmp = true;
|
serviceConfig.PrivateTmp = true;
|
||||||
@@ -87,7 +93,10 @@ in {
|
|||||||
serviceConfig.ProtectKernelLogs = true; # disable /proc/kmsg, /dev/kmsg
|
serviceConfig.ProtectKernelLogs = true; # disable /proc/kmsg, /dev/kmsg
|
||||||
serviceConfig.ProtectKernelModules = true; # syscall filter to prevent module calls (probably not upstreamable: NM will want to load modules like `ppp`)
|
serviceConfig.ProtectKernelModules = true; # syscall filter to prevent module calls (probably not upstreamable: NM will want to load modules like `ppp`)
|
||||||
serviceConfig.ProtectKernelTunables = true; # but NM might need to write /proc/sys/net/...
|
serviceConfig.ProtectKernelTunables = true; # but NM might need to write /proc/sys/net/...
|
||||||
|
serviceConfig.ProtectProc = "invisible";
|
||||||
|
serviceConfig.ProcSubset = "pid";
|
||||||
serviceConfig.ProtectSystem = "strict"; # makes read-only: all but /dev, /proc, /sys.
|
serviceConfig.ProtectSystem = "strict"; # makes read-only: all but /dev, /proc, /sys.
|
||||||
|
serviceConfig.RemoveIPC = true;
|
||||||
serviceConfig.RestrictAddressFamilies = [
|
serviceConfig.RestrictAddressFamilies = [
|
||||||
"AF_INET"
|
"AF_INET"
|
||||||
"AF_INET6"
|
"AF_INET6"
|
||||||
@@ -98,19 +107,25 @@ in {
|
|||||||
# AF_BLUETOOTH ?
|
# AF_BLUETOOTH ?
|
||||||
# AF_BRIDGE ?
|
# AF_BRIDGE ?
|
||||||
];
|
];
|
||||||
|
serviceConfig.RestrictNamespaces = true;
|
||||||
serviceConfig.RestrictSUIDSGID = true;
|
serviceConfig.RestrictSUIDSGID = true;
|
||||||
serviceConfig.SystemCallArchitectures = "native"; # prevents e.g. aarch64 syscalls in the event that the kernel is multi-architecture.
|
serviceConfig.SystemCallArchitectures = "native"; # prevents e.g. aarch64 syscalls in the event that the kernel is multi-architecture.
|
||||||
|
serviceConfig.SystemCallFilter = [
|
||||||
|
"@system-service"
|
||||||
|
# TODO: restrict SystemCallFilter more aggressively
|
||||||
|
];
|
||||||
|
# TODO: restrict `DeviceAllow`
|
||||||
# from earlier `landlock` sandboxing, i know it needs these directories:
|
# from earlier `landlock` sandboxing, i know it needs these directories:
|
||||||
# - "/proc/net"
|
# - "/proc/net"
|
||||||
# - "/proc/sys/net"
|
# - "/proc/sys/net"
|
||||||
# - "/run/NetworkManager"
|
# - "/run/NetworkManager"
|
||||||
# - "/run/systemd" # for trust-dns-nmhook
|
# - "/run/systemd" # for hickory-dns-nmhook
|
||||||
# - "/run/udev"
|
# - "/run/udev"
|
||||||
# - # "/run/wg-home.priv"
|
# - # "/run/wg-home.priv"
|
||||||
# - "/sys/class"
|
# - "/sys/class"
|
||||||
# - "/sys/devices"
|
# - "/sys/devices"
|
||||||
# - "/var/lib/NetworkManager"
|
# - "/var/lib/NetworkManager"
|
||||||
# - "/var/lib/trust-dns" #< for trust-dns-nmhook
|
# - "/var/lib/hickory-dns" #< for hickory-dns-nmhook
|
||||||
# - "/run/systemd"
|
# - "/run/systemd"
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -122,7 +137,12 @@ in {
|
|||||||
# fix NetworkManager-dispatcher to actually run as a daemon,
|
# fix NetworkManager-dispatcher to actually run as a daemon,
|
||||||
# and sandbox it a bit
|
# and sandbox it a bit
|
||||||
systemd.services.NetworkManager-dispatcher = {
|
systemd.services.NetworkManager-dispatcher = {
|
||||||
after = [ "trust-dns-localhost.service" ]; #< so that /var/lib/trust-dns will exist
|
#VVV so that /var/lib/hickory-dns will exist (the hook needs to write here).
|
||||||
|
# but this creates a cycle: hickory-dns-localhost > network.target > NetworkManager-dispatcher > hickory-dns-localhost.
|
||||||
|
# (seemingly) impossible to remove the network.target dep on NetworkManager-dispatcher.
|
||||||
|
# beffore would be to have the dispatcher not write hickory-dns files
|
||||||
|
# but rather just its own, and create a .path unit which restarts hickory-dns appropriately.
|
||||||
|
# after = [ "hickory-dns-localhost.service" ];
|
||||||
# serviceConfig.ExecStart = [
|
# serviceConfig.ExecStart = [
|
||||||
# "" # first blank line is to clear the upstream `ExecStart` field.
|
# "" # first blank line is to clear the upstream `ExecStart` field.
|
||||||
# "${cfg.package}/libexec/nm-dispatcher --persist" # --persist is needed for it to actually run as a daemon
|
# "${cfg.package}/libexec/nm-dispatcher --persist" # --persist is needed for it to actually run as a daemon
|
||||||
@@ -130,7 +150,7 @@ in {
|
|||||||
# serviceConfig.Restart = "always";
|
# serviceConfig.Restart = "always";
|
||||||
# serviceConfig.RestartSec = "1s";
|
# serviceConfig.RestartSec = "1s";
|
||||||
|
|
||||||
# serviceConfig.DynamicUser = true; #< not possible, else we lose group perms (so can't write to `trust-dns`'s files in the nm hook)
|
# serviceConfig.DynamicUser = true; #< not possible, else we lose group perms (so can't write to `hickory-dns`'s files in the nm hook)
|
||||||
serviceConfig.User = "networkmanager"; # TODO: should arguably use `DynamicUser`
|
serviceConfig.User = "networkmanager"; # TODO: should arguably use `DynamicUser`
|
||||||
serviceConfig.Group = "networkmanager";
|
serviceConfig.Group = "networkmanager";
|
||||||
serviceConfig.LockPersonality = true;
|
serviceConfig.LockPersonality = true;
|
||||||
@@ -146,7 +166,7 @@ in {
|
|||||||
serviceConfig.ProtectKernelLogs = true; # disable /proc/kmsg, /dev/kmsg
|
serviceConfig.ProtectKernelLogs = true; # disable /proc/kmsg, /dev/kmsg
|
||||||
serviceConfig.ProtectKernelModules = true; # syscall filter to prevent module calls
|
serviceConfig.ProtectKernelModules = true; # syscall filter to prevent module calls
|
||||||
serviceConfig.ProtectKernelTunables = true;
|
serviceConfig.ProtectKernelTunables = true;
|
||||||
serviceConfig.ProtectSystem = "full"; # makes read-only: /boot, /etc/, /usr. `strict` isn't possible due to trust-dns hook
|
serviceConfig.ProtectSystem = "full"; # makes read-only: /boot, /etc/, /usr. `strict` isn't possible due to hickory-dns hook
|
||||||
serviceConfig.RestrictAddressFamilies = [
|
serviceConfig.RestrictAddressFamilies = [
|
||||||
"AF_UNIX" # required, probably for dbus or systemd connectivity
|
"AF_UNIX" # required, probably for dbus or systemd connectivity
|
||||||
];
|
];
|
||||||
@@ -214,7 +234,7 @@ in {
|
|||||||
# note that NM's resolv.conf isn't (necessarily) /etc/resolv.conf -- that is managed by nixos (via symlinking)
|
# 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.hickory-dns.enable && config.sane.services.hickory-dns.asSystemResolver then
|
||||||
"none"
|
"none"
|
||||||
else
|
else
|
||||||
"internal"
|
"internal"
|
||||||
@@ -256,7 +276,7 @@ in {
|
|||||||
users.users.networkmanager = {
|
users.users.networkmanager = {
|
||||||
isSystemUser = true;
|
isSystemUser = true;
|
||||||
group = "networkmanager";
|
group = "networkmanager";
|
||||||
extraGroups = [ "trust-dns" ];
|
extraGroups = [ "hickory-dns" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
# there is, unfortunately, no proper interface by which to plumb wpa_supplicant into the NixOS service, except by overlay.
|
# there is, unfortunately, no proper interface by which to plumb wpa_supplicant into the NixOS service, except by overlay.
|
||||||
|
@@ -6,7 +6,6 @@ let
|
|||||||
# nixpkgs' pam hardcodes unix_chkpwd path to the /run/wrappers one,
|
# nixpkgs' pam hardcodes unix_chkpwd path to the /run/wrappers one,
|
||||||
# but i don't want the wrapper, so undo that.
|
# but i don't want the wrapper, so undo that.
|
||||||
# ideally i would patch this via an overlay, but pam is in the bootstrap so that forces a full rebuild.
|
# ideally i would patch this via an overlay, but pam is in the bootstrap so that forces a full rebuild.
|
||||||
# TODO: add a `package` option to the nixos' pam module and substitute it that way.
|
|
||||||
postPatch = (if upstream.postPatch != null then upstream.postPatch else "") + ''
|
postPatch = (if upstream.postPatch != null then upstream.postPatch else "") + ''
|
||||||
substituteInPlace modules/pam_unix/Makefile.am --replace-fail \
|
substituteInPlace modules/pam_unix/Makefile.am --replace-fail \
|
||||||
"/run/wrappers/bin/unix_chkpwd" "$out/bin/unix_chkpwd"
|
"/run/wrappers/bin/unix_chkpwd" "$out/bin/unix_chkpwd"
|
||||||
@@ -39,36 +38,29 @@ in
|
|||||||
]));
|
]));
|
||||||
};
|
};
|
||||||
options.security.pam.services = lib.mkOption {
|
options.security.pam.services = lib.mkOption {
|
||||||
apply = services: let
|
apply = lib.filterAttrs (name: _: !(builtins.elem name [
|
||||||
filtered = lib.filterAttrs (name: _: !(builtins.elem name [
|
# from <repo:nixos/nixpkgs:nixos/modules/security/pam.nix>
|
||||||
# from <repo:nixos/nixpkgs:nixos/modules/security/pam.nix>
|
"i3lock"
|
||||||
"i3lock"
|
"i3lock-color"
|
||||||
"i3lock-color"
|
"vlock"
|
||||||
"vlock"
|
"xlock"
|
||||||
"xlock"
|
"xscreensaver"
|
||||||
"xscreensaver"
|
"runuser"
|
||||||
"runuser"
|
"runuser-l"
|
||||||
"runuser-l"
|
# from ??
|
||||||
# from ??
|
"chfn"
|
||||||
"chfn"
|
"chpasswd"
|
||||||
"chpasswd"
|
"chsh"
|
||||||
"chsh"
|
"groupadd"
|
||||||
"groupadd"
|
"groupdel"
|
||||||
"groupdel"
|
"groupmems"
|
||||||
"groupmems"
|
"groupmod"
|
||||||
"groupmod"
|
"useradd"
|
||||||
"useradd"
|
"userdel"
|
||||||
"userdel"
|
"usermod"
|
||||||
"usermod"
|
# from <repo:nixos/nixpkgs:nixos/modules/system/boot/systemd/user.nix>
|
||||||
# from <repo:nixos/nixpkgs:nixos/modules/system/boot/systemd/user.nix>
|
"systemd-user" #< N.B.: this causes the `systemd --user` service manager to not be started!
|
||||||
"systemd-user" #< N.B.: this causes the `systemd --user` service manager to not be started!
|
]));
|
||||||
])) services;
|
|
||||||
in lib.mapAttrs (_serviceName: service: service // {
|
|
||||||
# replace references with the old pam_unix, which calls into /run/wrappers/bin/unix_chkpwd,
|
|
||||||
# with a pam_unix that calls into unix_chkpwd via the nix store.
|
|
||||||
# TODO: use `security.pam.package` instead once <https://github.com/NixOS/nixpkgs/pull/314791> lands.
|
|
||||||
text = lib.replaceStrings [" pam_unix.so" ] [ " ${suidlessPam}/lib/security/pam_unix.so" ] service.text;
|
|
||||||
}) filtered;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
options.environment.systemPackages = lib.mkOption {
|
options.environment.systemPackages = lib.mkOption {
|
||||||
@@ -225,5 +217,7 @@ in
|
|||||||
# systemd.packages = [ pkgs.lvm2 ];
|
# systemd.packages = [ pkgs.lvm2 ];
|
||||||
# systemd.tmpfiles.packages = [ pkgs.lvm2.out ];
|
# systemd.tmpfiles.packages = [ pkgs.lvm2.out ];
|
||||||
# environment.systemPackages = [ pkgs.lvm2 ];
|
# environment.systemPackages = [ pkgs.lvm2 ];
|
||||||
|
|
||||||
|
security.pam.package = suidlessPam;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -38,6 +38,7 @@ in
|
|||||||
"bridge-utils" # for brctl; debug linux "bridge" inet devices
|
"bridge-utils" # for brctl; debug linux "bridge" inet devices
|
||||||
"btrfs-progs"
|
"btrfs-progs"
|
||||||
"cacert.unbundled" # some services require unbundled /etc/ssl/certs
|
"cacert.unbundled" # some services require unbundled /etc/ssl/certs
|
||||||
|
"captree"
|
||||||
"cryptsetup"
|
"cryptsetup"
|
||||||
"curl"
|
"curl"
|
||||||
"ddrescue"
|
"ddrescue"
|
||||||
@@ -47,6 +48,7 @@ in
|
|||||||
"efibootmgr"
|
"efibootmgr"
|
||||||
"errno"
|
"errno"
|
||||||
"ethtool"
|
"ethtool"
|
||||||
|
"evtest"
|
||||||
"fatresize"
|
"fatresize"
|
||||||
"fd"
|
"fd"
|
||||||
"file"
|
"file"
|
||||||
@@ -69,7 +71,7 @@ in
|
|||||||
"killall"
|
"killall"
|
||||||
"less"
|
"less"
|
||||||
"lftp"
|
"lftp"
|
||||||
# "libcap_ng" # for `netcap`
|
"libcap_ng" # for `netcap`, `pscap`, `captest`
|
||||||
"lsof"
|
"lsof"
|
||||||
"man-pages"
|
"man-pages"
|
||||||
"man-pages-posix"
|
"man-pages-posix"
|
||||||
@@ -109,9 +111,6 @@ in
|
|||||||
# "zfs" # doesn't cross-compile (requires samba)
|
# "zfs" # doesn't cross-compile (requires samba)
|
||||||
];
|
];
|
||||||
sysadminExtraUtils = declPackageSet [
|
sysadminExtraUtils = declPackageSet [
|
||||||
"backblaze-b2"
|
|
||||||
"duplicity"
|
|
||||||
"sane-scripts.backup"
|
|
||||||
"sqlite" # to debug sqlite3 databases
|
"sqlite" # to debug sqlite3 databases
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -158,7 +157,7 @@ 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
|
# "rsyslog" # KEEP THIS HERE if you want persistent logging (TODO: port to systemd, store in /var/log/...)
|
||||||
"sane-deadlines"
|
"sane-deadlines"
|
||||||
"sane-scripts.bittorrent"
|
"sane-scripts.bittorrent"
|
||||||
"sane-scripts.cli"
|
"sane-scripts.cli"
|
||||||
@@ -283,7 +282,6 @@ in
|
|||||||
# "emote"
|
# "emote"
|
||||||
# "evince" # PDF viewer
|
# "evince" # PDF viewer
|
||||||
# "flare-signal" # gtk4 signal client
|
# "flare-signal" # gtk4 signal client
|
||||||
# "foliate" # e-book reader
|
|
||||||
"fractal" # matrix client
|
"fractal" # matrix client
|
||||||
"g4music" # local music player
|
"g4music" # local music player
|
||||||
# "gnome.cheese"
|
# "gnome.cheese"
|
||||||
@@ -314,14 +312,14 @@ in
|
|||||||
"mpv"
|
"mpv"
|
||||||
"networkmanagerapplet" # for nm-connection-editor: it's better than not having any gui!
|
"networkmanagerapplet" # for nm-connection-editor: it's better than not having any gui!
|
||||||
"ntfy-sh" # notification service
|
"ntfy-sh" # notification service
|
||||||
# "newsflash" # RSS viewer
|
"newsflash" # RSS viewer
|
||||||
"pavucontrol"
|
"pavucontrol"
|
||||||
"pwvucontrol" # pipewire version of pavu
|
"pwvucontrol" # pipewire version of pavu
|
||||||
# "picard" # music tagging
|
# "picard" # music tagging
|
||||||
# "libsForQt5.plasmatube" # Youtube player
|
# "libsForQt5.plasmatube" # Youtube player
|
||||||
"signal-desktop"
|
"signal-desktop"
|
||||||
# "snapshot" # camera app
|
# "snapshot" # camera app
|
||||||
"spot" # Gnome Spotify client
|
# "spot" # Gnome Spotify client
|
||||||
# "sublime-music"
|
# "sublime-music"
|
||||||
# "tdesktop" # broken on phosh
|
# "tdesktop" # broken on phosh
|
||||||
# "tokodon"
|
# "tokodon"
|
||||||
@@ -338,6 +336,7 @@ in
|
|||||||
# "chatty" # matrix/xmpp/irc client (2023/12/29: disabled because broken cross build)
|
# "chatty" # matrix/xmpp/irc client (2023/12/29: disabled because broken cross build)
|
||||||
# "cozy" # audiobook player
|
# "cozy" # audiobook player
|
||||||
"epiphany" # gnome's web browser
|
"epiphany" # gnome's web browser
|
||||||
|
"foliate" # e-book reader
|
||||||
# "iotas" # note taking app
|
# "iotas" # note taking app
|
||||||
"komikku"
|
"komikku"
|
||||||
"koreader"
|
"koreader"
|
||||||
@@ -393,7 +392,7 @@ in
|
|||||||
# "rhythmbox" # local music player
|
# "rhythmbox" # local music player
|
||||||
# "slic3r"
|
# "slic3r"
|
||||||
"soundconverter"
|
"soundconverter"
|
||||||
"spotify" # x86-only
|
# "spotify" # x86-only
|
||||||
"tor-browser" # x86-only
|
"tor-browser" # x86-only
|
||||||
# "vlc"
|
# "vlc"
|
||||||
"wireshark" # could maybe ship the cli as sysadmin pkg
|
"wireshark" # could maybe ship the cli as sysadmin pkg
|
||||||
@@ -432,7 +431,7 @@ in
|
|||||||
btrfs-progs.sandbox.method = "bwrap"; #< bwrap, landlock: both work
|
btrfs-progs.sandbox.method = "bwrap"; #< bwrap, landlock: both work
|
||||||
btrfs-progs.sandbox.autodetectCliPaths = "existing"; # e.g. `btrfs filesystem df /my/fs`
|
btrfs-progs.sandbox.autodetectCliPaths = "existing"; # e.g. `btrfs filesystem df /my/fs`
|
||||||
|
|
||||||
"cacert.unbundled".sandbox.enable = false;
|
"cacert.unbundled".sandbox.enable = false; #< data only
|
||||||
|
|
||||||
cargo.persist.byStore.plaintext = [ ".cargo" ];
|
cargo.persist.byStore.plaintext = [ ".cargo" ];
|
||||||
|
|
||||||
@@ -529,6 +528,12 @@ in
|
|||||||
ethtool.sandbox.method = "landlock";
|
ethtool.sandbox.method = "landlock";
|
||||||
ethtool.sandbox.capabilities = [ "net_admin" ];
|
ethtool.sandbox.capabilities = [ "net_admin" ];
|
||||||
|
|
||||||
|
evtest.sandbox.method = "bwrap";
|
||||||
|
evtest.sandbox.autodetectCliPaths = "existingFile"; # `evtest /dev/foo` to monitor events for a specific device
|
||||||
|
evtest.sandbox.extraPaths = [
|
||||||
|
"/dev/input"
|
||||||
|
];
|
||||||
|
|
||||||
# eza `ls` replacement
|
# eza `ls` replacement
|
||||||
# bwrap causes `/proc` files to be listed differently (e.g. `eza /proc/sys/net/ipv6/conf/`)
|
# 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")
|
# bwrap loses group info (so files owned by other users appear as owner "nobody")
|
||||||
@@ -623,6 +628,8 @@ in
|
|||||||
"/tmp" # "Cannot open display:" if it can't mount /tmp 👀
|
"/tmp" # "Cannot open display:" if it can't mount /tmp 👀
|
||||||
];
|
];
|
||||||
|
|
||||||
|
gitea = {};
|
||||||
|
|
||||||
gnome-calculator.buildCost = 1;
|
gnome-calculator.buildCost = 1;
|
||||||
gnome-calculator.sandbox.method = "bwrap";
|
gnome-calculator.sandbox.method = "bwrap";
|
||||||
gnome-calculator.sandbox.whitelistWayland = true;
|
gnome-calculator.sandbox.whitelistWayland = true;
|
||||||
@@ -760,7 +767,7 @@ in
|
|||||||
iotop.sandbox.capabilities = [ "net_admin" ];
|
iotop.sandbox.capabilities = [ "net_admin" ];
|
||||||
|
|
||||||
# provides `ip`, `routel`, `bridge`, others.
|
# provides `ip`, `routel`, `bridge`, others.
|
||||||
# landlock works fine for most of these, but `ip netns exec` wants to attach to an existing namespace
|
# landlock works fine for most of these, but `ip netns exec` wants to attach to an existing namespace (which requires sudo)
|
||||||
# and that means we can't use ANY sandboxer for it.
|
# and that means we can't use ANY sandboxer for it.
|
||||||
iproute2.sandbox.enable = false;
|
iproute2.sandbox.enable = false;
|
||||||
# iproute2.sandbox.net = "all";
|
# iproute2.sandbox.net = "all";
|
||||||
@@ -808,10 +815,11 @@ in
|
|||||||
"tmp"
|
"tmp"
|
||||||
];
|
];
|
||||||
|
|
||||||
|
landlock-sandboxer.sandbox.enable = false; #< sandbox helper
|
||||||
|
|
||||||
libcamera = {};
|
libcamera = {};
|
||||||
|
|
||||||
libcap.sandbox.enable = false; #< for `capsh`, which i use as a sandboxer
|
libcap_ng.sandbox.enable = false; # TODO: `pscap` can sandbox with bwrap, `captest` and `netcap` with landlock
|
||||||
libcap_ng.sandbox.enable = false; # there's something about /proc/$pid/fd which breaks `readlink`/stat with every sandbox technique (except capsh-only)
|
|
||||||
|
|
||||||
libnotify.sandbox.method = "bwrap";
|
libnotify.sandbox.method = "bwrap";
|
||||||
libnotify.sandbox.whitelistDbus = [ "user" ]; # notify-send
|
libnotify.sandbox.whitelistDbus = [ "user" ]; # notify-send
|
||||||
@@ -844,8 +852,8 @@ in
|
|||||||
|
|
||||||
lua = {};
|
lua = {};
|
||||||
|
|
||||||
man-pages.sandbox.enable = false;
|
man-pages.sandbox.enable = false; #< data only
|
||||||
man-pages-posix.sandbox.enable = false;
|
man-pages-posix.sandbox.enable = false; #< data only
|
||||||
|
|
||||||
mercurial.sandbox.method = "bwrap"; # TODO:sandbox: untested
|
mercurial.sandbox.method = "bwrap"; # TODO:sandbox: untested
|
||||||
mercurial.sandbox.net = "clearnet";
|
mercurial.sandbox.net = "clearnet";
|
||||||
@@ -1052,7 +1060,7 @@ in
|
|||||||
# TODO: enable dma heaps for more efficient buffer sharing: <https://gitlab.com/postmarketOS/pmaports/-/issues/2789>
|
# TODO: enable dma heaps for more efficient buffer sharing: <https://gitlab.com/postmarketOS/pmaports/-/issues/2789>
|
||||||
snapshot = {};
|
snapshot = {};
|
||||||
|
|
||||||
sops.sandbox.method = "bwrap"; # TODO:sandbox: untested
|
sops.sandbox.method = "bwrap";
|
||||||
sops.sandbox.extraHomePaths = [
|
sops.sandbox.extraHomePaths = [
|
||||||
".config/sops"
|
".config/sops"
|
||||||
"nixos"
|
"nixos"
|
||||||
@@ -1093,7 +1101,16 @@ in
|
|||||||
|
|
||||||
sqlite = {};
|
sqlite = {};
|
||||||
|
|
||||||
sshfs-fuse = {}; # used by fs.nix
|
sshfs-fuse.sandbox.method = "bwrap"; #< N.B. if you call this from the CLI -- without `mount.fuse` -- set this to `none`
|
||||||
|
sshfs-fuse.sandbox.net = "all";
|
||||||
|
sshfs-fuse.sandbox.autodetectCliPaths = "parent";
|
||||||
|
# sshfs-fuse.sandbox.extraPaths = [
|
||||||
|
# "/dev/fd" # fuse.mount3 -o drop_privileges passes us data over /dev/fd/3
|
||||||
|
# "/mnt" # XXX: not sure why i need all this, instead of just /mnt/desko, or /mnt/desko/home, etc
|
||||||
|
# ];
|
||||||
|
sshfs-fuse.sandbox.extraHomePaths = [
|
||||||
|
".ssh/id_ed25519" #< TODO: add -o foo,bar=path/to/thing style arguments to autodetection
|
||||||
|
];
|
||||||
|
|
||||||
strace.sandbox.enable = false; #< needs to `exec` its args, and therefore support *anything*
|
strace.sandbox.enable = false; #< needs to `exec` its args, and therefore support *anything*
|
||||||
|
|
||||||
@@ -1135,7 +1152,7 @@ in
|
|||||||
tumiki-fighters.sandbox.whitelistWayland = true;
|
tumiki-fighters.sandbox.whitelistWayland = true;
|
||||||
tumiki-fighters.sandbox.whitelistX = true;
|
tumiki-fighters.sandbox.whitelistX = true;
|
||||||
|
|
||||||
util-linux.sandbox.enable = false; #< TODO: possible to sandbox if i specific a different profile for each of its ~50 binaries
|
util-linux.sandbox.enable = false; #< TODO: possible to sandbox if i specify a different profile for each of its ~50 binaries
|
||||||
|
|
||||||
unzip.sandbox.method = "bwrap";
|
unzip.sandbox.method = "bwrap";
|
||||||
unzip.sandbox.autodetectCliPaths = "existingOrParent";
|
unzip.sandbox.autodetectCliPaths = "existingOrParent";
|
||||||
@@ -1206,7 +1223,7 @@ in
|
|||||||
|
|
||||||
yarn.persist.byStore.plaintext = [ ".cache/yarn" ];
|
yarn.persist.byStore.plaintext = [ ".cache/yarn" ];
|
||||||
|
|
||||||
yt-dlp.sandbox.method = "bwrap"; # TODO:sandbox: untested
|
yt-dlp.sandbox.method = "bwrap";
|
||||||
yt-dlp.sandbox.net = "all";
|
yt-dlp.sandbox.net = "all";
|
||||||
yt-dlp.sandbox.whitelistPwd = true; # saves to pwd by default
|
yt-dlp.sandbox.whitelistPwd = true; # saves to pwd by default
|
||||||
};
|
};
|
||||||
@@ -1238,7 +1255,7 @@ in
|
|||||||
''
|
''
|
||||||
tryNotifyUser() {
|
tryNotifyUser() {
|
||||||
local user="$1"
|
local user="$1"
|
||||||
local new_path="$PATH:${pkgs.sudo}/bin:${pkgs.libnotify}/bin"
|
local new_path="$PATH:/etc/profiles/per-user/$user/bin:${pkgs.sudo}/bin:${pkgs.libnotify}/bin"
|
||||||
local version="$(cat $systemConfig/nixos-version)"
|
local version="$(cat $systemConfig/nixos-version)"
|
||||||
PATH="$new_path" sudo -u "$user" \
|
PATH="$new_path" sudo -u "$user" \
|
||||||
env PATH="$new_path" NIXOS_VERSION="$version" /bin/sh -c \
|
env PATH="$new_path" NIXOS_VERSION="$version" /bin/sh -c \
|
||||||
@@ -1246,7 +1263,7 @@ in
|
|||||||
}
|
}
|
||||||
''
|
''
|
||||||
] ++ lib.mapAttrsToList
|
] ++ lib.mapAttrsToList
|
||||||
(user: en: lib.optionalString en "tryNotifyUser ${user}")
|
(user: en: lib.optionalString en "tryNotifyUser ${user} > /dev/null")
|
||||||
config.sane.programs.guiApps.enableFor.user
|
config.sane.programs.guiApps.enableFor.user
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@@ -10,14 +10,26 @@
|
|||||||
# - `LD_LIBRARY_PATH=/nix/store/ngwj3jqmxh8k4qji2z0lj7y1f8vzqrn2-nss-mdns-0.15.1/lib getent hosts desko.local`
|
# - `LD_LIBRARY_PATH=/nix/store/ngwj3jqmxh8k4qji2z0lj7y1f8vzqrn2-nss-mdns-0.15.1/lib getent hosts desko.local`
|
||||||
# nss-mdns goes through avahi-daemon, so there IS caching here
|
# nss-mdns goes through avahi-daemon, so there IS caching here
|
||||||
#
|
#
|
||||||
{ config, lib, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
{
|
{
|
||||||
sane.programs.avahi = {
|
sane.programs.avahi = {
|
||||||
|
packageUnwrapped = pkgs.avahi.overrideAttrs (upstream: {
|
||||||
|
# avahi wants to do its own sandboxing opaque to systemd & maybe in conflict with my bwrap.
|
||||||
|
# --no-drop-root disables that, so that i can e.g. run it as User=avahi, etc.
|
||||||
|
# do this here, because the service isn't so easily patched.
|
||||||
|
postInstall = (upstream.postInstall or "") + ''
|
||||||
|
wrapProgram "$out/sbin/avahi-daemon" \
|
||||||
|
--add-flags --no-drop-root
|
||||||
|
'';
|
||||||
|
nativeBuildInputs = upstream.nativeBuildInputs ++ [
|
||||||
|
pkgs.makeBinaryWrapper
|
||||||
|
];
|
||||||
|
});
|
||||||
sandbox.method = "bwrap";
|
sandbox.method = "bwrap";
|
||||||
sandbox.whitelistDbus = [ "system" ];
|
sandbox.whitelistDbus = [ "system" ];
|
||||||
sandbox.net = "all"; #< otherwise it will show 'null' in place of each interface name.
|
sandbox.net = "all"; #< otherwise it will show 'null' in place of each interface name.
|
||||||
sandbox.extraPaths = [
|
sandbox.extraPaths = [
|
||||||
"/" #< else the daemon exits immediately. TODO: decrease this scope.
|
"/" #< TODO: decrease this, but be weary that the daemon might exit immediately
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
services.avahi = lib.mkIf config.sane.programs.avahi.enabled {
|
services.avahi = lib.mkIf config.sane.programs.avahi.enabled {
|
||||||
@@ -40,4 +52,40 @@
|
|||||||
"wlp4s0" #< desko
|
"wlp4s0" #< desko
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
systemd.services.avahi-daemon = lib.mkIf config.sane.programs.avahi.enabled {
|
||||||
|
# hardening: see `systemd-analyze security avahi-daemon`
|
||||||
|
serviceConfig.User = "avahi";
|
||||||
|
serviceConfig.Group = "avahi";
|
||||||
|
serviceConfig.AmbientCapabilities = "";
|
||||||
|
serviceConfig.CapabilityBoundingSet = "";
|
||||||
|
serviceConfig.LockPersonality = true;
|
||||||
|
serviceConfig.MemoryDenyWriteExecute = true;
|
||||||
|
serviceConfig.NoNewPrivileges = true;
|
||||||
|
serviceConfig.PrivateDevices = true;
|
||||||
|
serviceConfig.PrivateMounts = true;
|
||||||
|
serviceConfig.PrivateTmp = true;
|
||||||
|
serviceConfig.PrivateUsers = true;
|
||||||
|
serviceConfig.ProcSubset = "all";
|
||||||
|
serviceConfig.ProtectClock = true;
|
||||||
|
serviceConfig.ProtectControlGroups = true;
|
||||||
|
serviceConfig.ProtectHome = true;
|
||||||
|
serviceConfig.ProtectHostname = true;
|
||||||
|
serviceConfig.ProtectKernelLogs = true;
|
||||||
|
serviceConfig.ProtectKernelModules = true;
|
||||||
|
serviceConfig.ProtectKernelTunables = true;
|
||||||
|
serviceConfig.ProtectProc = "noaccess";
|
||||||
|
serviceConfig.ProtectSystem = "strict";
|
||||||
|
serviceConfig.RemoveIPC = true; #< this *might* slow down the initial connection?
|
||||||
|
serviceConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6 AF_NETLINK";
|
||||||
|
serviceConfig.RestrictRealtime = true;
|
||||||
|
serviceConfig.RestrictSUIDSGID = true;
|
||||||
|
serviceConfig.SystemCallArchitectures = "native";
|
||||||
|
serviceConfig.SystemCallFilter = [
|
||||||
|
"@system-service"
|
||||||
|
"@mount"
|
||||||
|
"~@resources"
|
||||||
|
# "~@privileged"
|
||||||
|
];
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@@ -8,6 +8,10 @@
|
|||||||
# - the bot will reply with auto-generated username/password plus a SIP server endpoint.
|
# - the bot will reply with auto-generated username/password plus a SIP server endpoint.
|
||||||
# just copy those into gnome-calls' GUI configurator
|
# just copy those into gnome-calls' GUI configurator
|
||||||
# - now gnome-calls can do outbound calls. inbound calls can be routed by messaging the bot: "configure calls"
|
# - now gnome-calls can do outbound calls. inbound calls can be routed by messaging the bot: "configure calls"
|
||||||
|
#
|
||||||
|
# user guide:
|
||||||
|
# - "Use for Calls" means, "when i click a tel: URI, use this account": <https://gitlab.gnome.org/GNOME/calls/-/issues/513>
|
||||||
|
# - `calls -vvv` for verbosity
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
let
|
let
|
||||||
cfg = config.sane.programs.calls;
|
cfg = config.sane.programs.calls;
|
||||||
@@ -24,7 +28,23 @@ in
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
packageUnwrapped = pkgs.rmDbusServicesInPlace (pkgs.calls.overrideAttrs (upstream: {
|
packageUnwrapped = pkgs.rmDbusServicesInPlace ((pkgs.calls.override {
|
||||||
|
gtk3 = pkgs.gtk4;
|
||||||
|
libpeas = pkgs.libpeas2;
|
||||||
|
wrapGAppsHook3 = pkgs.wrapGAppsHook4;
|
||||||
|
}).overrideAttrs (upstream: {
|
||||||
|
# XXX(2024-08-08): v46.3 has a bug where if it has no network connection on launch, it forever stays disconnected & never retries
|
||||||
|
version = "47_beta.0-unstable-2024-08-08";
|
||||||
|
src = lib.warnIf (lib.versionOlder "47.0" upstream.version) "gnome-calls outdated; remove src override? (keep UI patches though!)" pkgs.fetchFromGitLab {
|
||||||
|
domain = "gitlab.gnome.org";
|
||||||
|
owner = "GNOME";
|
||||||
|
repo = "calls";
|
||||||
|
fetchSubmodules = true;
|
||||||
|
# rev = "main";
|
||||||
|
rev = "ff213579a52222e7c95e585843d97b5b817b2a8b";
|
||||||
|
hash = "sha256-0QYC8FJpfg/X2lIjBDooba2idUfpJNQhcpv8Z5I/B4k=";
|
||||||
|
};
|
||||||
|
|
||||||
patches = (upstream.patches or []) ++ [
|
patches = (upstream.patches or []) ++ [
|
||||||
(pkgs.fetchpatch {
|
(pkgs.fetchpatch {
|
||||||
# usability improvement... if the UI is visible, then i can receive calls. otherwise, i can't!
|
# usability improvement... if the UI is visible, then i can receive calls. otherwise, i can't!
|
||||||
@@ -33,6 +53,14 @@ in
|
|||||||
hash = "sha256-NoVQV2TlkCcsBt0uwSyK82hBKySUW4pADrJVfLFvWgU=";
|
hash = "sha256-NoVQV2TlkCcsBt0uwSyK82hBKySUW4pADrJVfLFvWgU=";
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
|
|
||||||
|
nativeBuildInputs = upstream.nativeBuildInputs ++ [
|
||||||
|
pkgs.dbus #< for dbus-run-session (should be test only, but it's not)
|
||||||
|
];
|
||||||
|
|
||||||
|
buildInputs = upstream.buildInputs ++ [
|
||||||
|
pkgs.libadwaita
|
||||||
|
];
|
||||||
}));
|
}));
|
||||||
|
|
||||||
sandbox.method = "bwrap";
|
sandbox.method = "bwrap";
|
||||||
@@ -55,6 +83,10 @@ in
|
|||||||
"gnome-keyring" # to remember the password
|
"gnome-keyring" # to remember the password
|
||||||
];
|
];
|
||||||
|
|
||||||
|
mime.associations."x-scheme-handler/tel" = "org.gnome.Calls.desktop";
|
||||||
|
mime.associations."x-scheme-handler/sip" = "org.gnome.Calls.desktop";
|
||||||
|
mime.associations."x-scheme-handler/sips" = "org.gnome.Calls.desktop";
|
||||||
|
|
||||||
services.gnome-calls = {
|
services.gnome-calls = {
|
||||||
description = "gnome-calls daemon to monitor incoming SIP calls";
|
description = "gnome-calls daemon to monitor incoming SIP calls";
|
||||||
partOf = lib.mkIf cfg.config.autostart [ "graphical-session" ];
|
partOf = lib.mkIf cfg.config.autostart [ "graphical-session" ];
|
||||||
|
7
hosts/common/programs/capsh.nix
Normal file
7
hosts/common/programs/capsh.nix
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{ pkgs, ... }:
|
||||||
|
{
|
||||||
|
sane.programs.capsh = {
|
||||||
|
packageUnwrapped = pkgs.linkBinIntoOwnPackage pkgs.libcap "capsh";
|
||||||
|
sandbox.enable = false; #< i use `capsh` as a sandboxer.
|
||||||
|
};
|
||||||
|
}
|
8
hosts/common/programs/captree.nix
Normal file
8
hosts/common/programs/captree.nix
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{ pkgs, ... }:
|
||||||
|
{
|
||||||
|
sane.programs.captree = {
|
||||||
|
packageUnwrapped = pkgs.linkBinIntoOwnPackage pkgs.libcap-with-captree "captree";
|
||||||
|
sandbox.method = "bwrap";
|
||||||
|
sandbox.isolatePids = false;
|
||||||
|
};
|
||||||
|
}
|
@@ -1,35 +1,8 @@
|
|||||||
{ pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
{
|
{
|
||||||
sane.programs.curlftpfs = {
|
sane.programs.curlftpfs = {
|
||||||
packageUnwrapped = pkgs.curlftpfs.overrideAttrs (upstream: {
|
packageUnwrapped = pkgs.curlftpfs-sane;
|
||||||
# my fork includes:
|
sandbox.method = "bwrap";
|
||||||
# - per-operation timeouts (CURLOPT_TIMEOUT; would use CURLOPT_LOW_SPEED_TIME/CURLOPT_LOW_SPEED_LIMIT but they don't apply)
|
sandbox.net = "all";
|
||||||
# - exit on timeout (so that one knows to abort the mount, instead of waiting indefinitely)
|
|
||||||
# - support for "meta" keys found in /etc/fstab
|
|
||||||
src = pkgs.fetchFromGitea {
|
|
||||||
domain = "git.uninsane.org";
|
|
||||||
owner = "colin";
|
|
||||||
repo = "curlftpfs";
|
|
||||||
rev = "0890d32e709b5a01153f00d29ed4c00299744f5d";
|
|
||||||
hash = "sha256-M28PzHqEAkezQdtPeL16z56prwl3BfMZqry0dlpXJls=";
|
|
||||||
};
|
|
||||||
# `mount` clears PATH before calling the mount helper (see util-linux/lib/env.c),
|
|
||||||
# so the traditional /etc/fstab approach of fstype=fuse and device = curlftpfs#URI doesn't work.
|
|
||||||
# instead, install a `mount.curlftpfs` mount helper. this is what programs like `gocryptfs` do.
|
|
||||||
postInstall = (upstream.postInstall or "") + ''
|
|
||||||
ln -s curlftpfs $out/bin/mount.fuse.curlftpfs
|
|
||||||
ln -s curlftpfs $out/bin/mount.curlftpfs
|
|
||||||
'';
|
|
||||||
});
|
|
||||||
|
|
||||||
# TODO: try to sandbox this better? maybe i can have fuse (unsandboxed) invoke curlftpfs (sandboxed)?
|
|
||||||
# - landlock gives EPERM
|
|
||||||
# - bwrap just silently doesn't mount it, maybe because of setuid stuff around fuse?
|
|
||||||
# sandbox.method = "capshonly";
|
|
||||||
# sandbox.net = "all";
|
|
||||||
# sandbox.capabilities = [
|
|
||||||
# "sys_admin"
|
|
||||||
# "sys_module"
|
|
||||||
# ];
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -21,6 +21,8 @@
|
|||||||
./callaudiod.nix
|
./callaudiod.nix
|
||||||
./calls.nix
|
./calls.nix
|
||||||
./cantata.nix
|
./cantata.nix
|
||||||
|
./capsh.nix
|
||||||
|
./captree.nix
|
||||||
./catt.nix
|
./catt.nix
|
||||||
./celeste64.nix
|
./celeste64.nix
|
||||||
./chatty.nix
|
./chatty.nix
|
||||||
@@ -46,7 +48,9 @@
|
|||||||
./fcitx5.nix
|
./fcitx5.nix
|
||||||
./feedbackd.nix
|
./feedbackd.nix
|
||||||
./firefox.nix
|
./firefox.nix
|
||||||
|
./firefox-xdg-open.nix
|
||||||
./flare-signal.nix
|
./flare-signal.nix
|
||||||
|
./foliate.nix
|
||||||
./fontconfig.nix
|
./fontconfig.nix
|
||||||
./fractal.nix
|
./fractal.nix
|
||||||
./free.nix
|
./free.nix
|
||||||
@@ -66,6 +70,7 @@
|
|||||||
./gnome-maps.nix
|
./gnome-maps.nix
|
||||||
./gnome-weather.nix
|
./gnome-weather.nix
|
||||||
./go2tv.nix
|
./go2tv.nix
|
||||||
|
./gocryptfs.nix
|
||||||
./gpodder.nix
|
./gpodder.nix
|
||||||
./gpsd.nix
|
./gpsd.nix
|
||||||
./gps-share.nix
|
./gps-share.nix
|
||||||
@@ -179,6 +184,7 @@
|
|||||||
./wvkbd.nix
|
./wvkbd.nix
|
||||||
./xarchiver.nix
|
./xarchiver.nix
|
||||||
./xdg-desktop-portal.nix
|
./xdg-desktop-portal.nix
|
||||||
|
./xdg-desktop-portal-gnome
|
||||||
./xdg-desktop-portal-gtk.nix
|
./xdg-desktop-portal-gtk.nix
|
||||||
./xdg-desktop-portal-wlr.nix
|
./xdg-desktop-portal-wlr.nix
|
||||||
./xdg-terminal-exec.nix
|
./xdg-terminal-exec.nix
|
||||||
|
13
hosts/common/programs/firefox-xdg-open.nix
Normal file
13
hosts/common/programs/firefox-xdg-open.nix
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{ pkgs, ... }:
|
||||||
|
{
|
||||||
|
sane.programs.firefox-xdg-open = {
|
||||||
|
packageUnwrapped = pkgs.firefox-extensions.firefox-xdg-open.systemComponent;
|
||||||
|
|
||||||
|
sandbox.method = "bwrap";
|
||||||
|
sandbox.whitelistDbus = [ "user" ]; # for xdg-open/portals
|
||||||
|
|
||||||
|
mime.associations."x-scheme-handler/xdg-open" = "xdg-open.desktop";
|
||||||
|
|
||||||
|
suggestedPrograms = [ "xdg-utils" ];
|
||||||
|
};
|
||||||
|
}
|
@@ -113,9 +113,20 @@ let
|
|||||||
name = "${cfg.browser.libName}-in-vpn";
|
name = "${cfg.browser.libName}-in-vpn";
|
||||||
desktopName = "${cfg.browser.libName} (VPN)";
|
desktopName = "${cfg.browser.libName} (VPN)";
|
||||||
genericName = "Web Browser";
|
genericName = "Web Browser";
|
||||||
# N.B.: --new-instance ensures we don't reuse an existing non-vpn instance.
|
# N.B.: --new-instance ensures we don't reuse an existing differenty-namespaced instance.
|
||||||
# OTOH, it may error about "only one instance can run at a time": close the non-VPN instance if you see that.
|
# OTOH, it may error about "only one instance can run at a time": close the other instance if you see that.
|
||||||
exec = "${lib.getExe pkgs.sane-scripts.vpn} do - -- ${cfg.browser.libName} --new-instance";
|
exec = "${lib.getExe pkgs.sane-scripts.vpn} do default -- ${cfg.browser.libName} --new-instance";
|
||||||
|
icon = cfg.browser.libName;
|
||||||
|
categories = [ "Network" "WebBrowser" ];
|
||||||
|
type = "Application";
|
||||||
|
})
|
||||||
|
(pkgs.makeDesktopItem {
|
||||||
|
name = "${cfg.browser.libName}-stub-dns";
|
||||||
|
desktopName = "${cfg.browser.libName} (stub DNS)";
|
||||||
|
genericName = "Web Browser";
|
||||||
|
# N.B.: --new-instance ensures we don't reuse an existing differently-namespaced instance.
|
||||||
|
# OTOH, it may error about "only one instance can run at a time": close the other instance if you see that.
|
||||||
|
exec = "${lib.getExe pkgs.sane-scripts.vpn} do none -- ${cfg.browser.libName} --new-instance";
|
||||||
icon = cfg.browser.libName;
|
icon = cfg.browser.libName;
|
||||||
categories = [ "Network" "WebBrowser" ];
|
categories = [ "Network" "WebBrowser" ];
|
||||||
type = "Application";
|
type = "Application";
|
||||||
@@ -220,6 +231,11 @@ in
|
|||||||
package = pkgs.firefox-extensions.ether-metamask;
|
package = pkgs.firefox-extensions.ether-metamask;
|
||||||
enable = lib.mkDefault false; # until i can disable the first-run notification
|
enable = lib.mkDefault false; # until i can disable the first-run notification
|
||||||
};
|
};
|
||||||
|
firefox-xdg-open = {
|
||||||
|
# test: `xdg-open xdg-open:https://uninsane.org`
|
||||||
|
package = pkgs.firefox-extensions.firefox-xdg-open;
|
||||||
|
enable = lib.mkDefault true;
|
||||||
|
};
|
||||||
i2p-in-private-browsing = {
|
i2p-in-private-browsing = {
|
||||||
package = pkgs.firefox-extensions.i2p-in-private-browsing;
|
package = pkgs.firefox-extensions.i2p-in-private-browsing;
|
||||||
enable = lib.mkDefault config.services.i2p.enable;
|
enable = lib.mkDefault config.services.i2p.enable;
|
||||||
@@ -231,7 +247,7 @@ in
|
|||||||
open-in-mpv = {
|
open-in-mpv = {
|
||||||
# test: `open-in-mpv 'mpv:///open?url=https://www.youtube.com/watch?v=dQw4w9WgXcQ'`
|
# test: `open-in-mpv 'mpv:///open?url=https://www.youtube.com/watch?v=dQw4w9WgXcQ'`
|
||||||
package = pkgs.firefox-extensions.open-in-mpv;
|
package = pkgs.firefox-extensions.open-in-mpv;
|
||||||
enable = lib.mkDefault config.sane.programs.open-in-mpv.enabled;
|
enable = lib.mkDefault false;
|
||||||
};
|
};
|
||||||
sidebery = {
|
sidebery = {
|
||||||
package = pkgs.firefox-extensions.sidebery;
|
package = pkgs.firefox-extensions.sidebery;
|
||||||
@@ -286,7 +302,9 @@ in
|
|||||||
];
|
];
|
||||||
fs.".config/sops".dir = lib.mkIf cfg.addons.browserpass-extension.enable {}; #< needs to be created, not *just* added to the sandbox
|
fs.".config/sops".dir = lib.mkIf cfg.addons.browserpass-extension.enable {}; #< needs to be created, not *just* added to the sandbox
|
||||||
|
|
||||||
suggestedPrograms = [
|
suggestedPrograms = lib.optionals cfg.addons.firefox-xdg-open.enable [
|
||||||
|
"firefox-xdg-open"
|
||||||
|
] ++ lib.optionals cfg.addons.open-in-mpv.enable [
|
||||||
"open-in-mpv"
|
"open-in-mpv"
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -358,13 +376,11 @@ in
|
|||||||
// configure which extensions are visible by default (TODO: requires a lot of trial and error)
|
// configure which extensions are visible by default (TODO: requires a lot of trial and error)
|
||||||
// defaultPref("browser.uiCustomization.state", ...);
|
// defaultPref("browser.uiCustomization.state", ...);
|
||||||
|
|
||||||
// auto-open mpv:// URIs without prompting.
|
// auto-open specific URI schemes without prompting:
|
||||||
// can do this with other protocols too (e.g. matrix?). see about:config for common handlers.
|
defaultPref("network.protocol-handler.external.xdg-open", true); // for firefox-xdg-open extension
|
||||||
defaultPref("network.protocol-handler.external.mpv", true);
|
defaultPref("network.protocol-handler.external.mpv", true); // for open-in-mpv extension
|
||||||
// element:// for Element matrix client
|
defaultPref("network.protocol-handler.external.element", true); // for Element matrix client
|
||||||
defaultPref("network.protocol-handler.external.element", true);
|
defaultPref("network.protocol-handler.external.matrix", true); // for Nheko matrix client
|
||||||
// matrix: for Nheko matrix client
|
|
||||||
defaultPref("network.protocol-handler.external.matrix", true);
|
|
||||||
'';
|
'';
|
||||||
# instruct Firefox to put the profile in a predictable directory (so we can do things like persist just it).
|
# instruct Firefox to put the profile in a predictable directory (so we can do things like persist just it).
|
||||||
# XXX: the directory *must* exist, even if empty; Firefox will not create the directory itself.
|
# XXX: the directory *must* exist, even if empty; Firefox will not create the directory itself.
|
||||||
|
@@ -1,12 +1,16 @@
|
|||||||
# Flare is a 3rd-party GTK4 Signal app.
|
# Flare is a 3rd-party GTK4 Signal app.
|
||||||
# UI is effectively a clone of Fractal.
|
# UI is effectively a clone of Fractal.
|
||||||
#
|
#
|
||||||
### compatibility:
|
### compatibility (2023-10-30):
|
||||||
# - desko: works fine. pairs, and exchanges contact list (but not message history) with the paired device. exchanges future messages fine.
|
# - desko: works fine. pairs, and exchanges contact list (but not message history) with the paired device. exchanges future messages fine.
|
||||||
# - moby (cross compiled flare-signal-nixified): nope. it pairs, but can only *receive* messages and never *send* them.
|
# - moby (cross compiled flare-signal-nixified): nope. it pairs, but can only *receive* messages and never *send* them.
|
||||||
# - even `rsync`ing the data and keyrings from desko -> moby, still fails in that same manner.
|
# - even `rsync`ing the data and keyrings from desko -> moby, still fails in that same manner.
|
||||||
# - console shows error messages. quite possibly an endianness mismatch somewhere
|
# - console shows error messages. quite possibly an endianness mismatch somewhere
|
||||||
# - moby (partially-emulated flare-signal): works! pairs and can send/receive messages, same as desko.
|
# - moby (partially-emulated flare-signal): works! pairs and can send/receive messages, same as desko.
|
||||||
|
### compatibility (2024-08-07):
|
||||||
|
# - linking flare to iOS signal "works", but neither side can exchange messages nor contacts
|
||||||
|
# in iOS i see "A message from Colin could not be delivered"
|
||||||
|
# - registering as primary device does not work ("you are not authorized", or some such)
|
||||||
#
|
#
|
||||||
### debugging:
|
### debugging:
|
||||||
# - `RUST_LOG=flare=trace flare`
|
# - `RUST_LOG=flare=trace flare`
|
||||||
@@ -18,7 +22,7 @@
|
|||||||
# ERROR presage::manager] Error opening envelope: ProtobufDecodeError(DecodeError { description: "invalid tag value: 0", stack: [("Content", "data_message")] }), message will be skipped!
|
# ERROR presage::manager] Error opening envelope: ProtobufDecodeError(DecodeError { description: "invalid tag value: 0", stack: [("Content", "data_message")] }), message will be skipped!
|
||||||
# ERROR presage::manager] Error opening envelope: ProtobufDecodeError(DecodeError { description: "invalid tag value: 0", stack: [("Content", "data_message")] }), message will be skipped!
|
# ERROR presage::manager] Error opening envelope: ProtobufDecodeError(DecodeError { description: "invalid tag value: 0", stack: [("Content", "data_message")] }), message will be skipped!
|
||||||
# ```
|
# ```
|
||||||
# - this occurs on moby, desko, `flare-signal` and `flare-signal-nixified`
|
# - this occurs on moby, desko, `flare-signal` and `flare-signal-nixified` (2023-12-14)
|
||||||
# - the Websocket error seems to be unrelated, occurs during normal/good operation
|
# - the Websocket error seems to be unrelated, occurs during normal/good operation
|
||||||
# - related issues: <https://github.com/whisperfish/presage/issues/152>
|
# - related issues: <https://github.com/whisperfish/presage/issues/152>
|
||||||
#
|
#
|
||||||
@@ -28,7 +32,7 @@
|
|||||||
# No current session
|
# No current session
|
||||||
# ERROR presage::manager] Error opening envelope: SignalProtocolError(InvalidKyberPreKeyId), message will be skipped!
|
# ERROR presage::manager] Error opening envelope: SignalProtocolError(InvalidKyberPreKeyId), message will be skipped!
|
||||||
# ```
|
# ```
|
||||||
# - but signal iOS will still read it.
|
# - but signal iOS will still read it (2023-12-14).
|
||||||
#
|
#
|
||||||
#### HTTP 405 when linking flare to iOS signal:
|
#### HTTP 405 when linking flare to iOS signal:
|
||||||
# [DEBUG libsignal_service_hyper::push_service] HTTP request PUT https://chat.signal.org/v1/devices/{uuid}.{timestamp?}:{b64-string}
|
# [DEBUG libsignal_service_hyper::push_service] HTTP request PUT https://chat.signal.org/v1/devices/{uuid}.{timestamp?}:{b64-string}
|
||||||
@@ -43,7 +47,7 @@
|
|||||||
# ),
|
# ),
|
||||||
# ),
|
# ),
|
||||||
# )
|
# )
|
||||||
# flare matrix suggests the signal endpoint has changed:
|
# flare matrix suggests the signal endpoint has changed (2023-12-14):
|
||||||
# - "/v1/device/link instead of confirming via /v1/devices/{I'd}"
|
# - "/v1/device/link instead of confirming via /v1/devices/{I'd}"
|
||||||
# - this endpoint is declared in libsignal-service-rs (used both by flare and presage)
|
# - this endpoint is declared in libsignal-service-rs (used both by flare and presage)
|
||||||
# - libsignal-service/src/provisioning/manager.rs
|
# - libsignal-service/src/provisioning/manager.rs
|
||||||
@@ -73,5 +77,13 @@
|
|||||||
# and it persists some dconf settings (e.g. device name). reset with:
|
# and it persists some dconf settings (e.g. device name). reset with:
|
||||||
# - `dconf reset -f /de/schmidhuberj/Flare/`.
|
# - `dconf reset -f /de/schmidhuberj/Flare/`.
|
||||||
];
|
];
|
||||||
|
#VVV flare complains if its data directory is a symlink, so put it in a subdirectory behind my persistence symlink.
|
||||||
|
env.FLARE_DATA_PATH = "$HOME/.local/share/flare/data";
|
||||||
|
# sandbox.method = "bwrap";
|
||||||
|
# sandbox.net = "clearnet";
|
||||||
|
# sandbox.whitelistWayland = true;
|
||||||
|
# sandbox.whitelistDbus = [
|
||||||
|
# "user" # so i can click on links, at least
|
||||||
|
# ];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
42
hosts/common/programs/foliate.nix
Normal file
42
hosts/common/programs/foliate.nix
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
# foliate: <https://johnfactotum.github.io/foliate/>
|
||||||
|
{ ... }:
|
||||||
|
{
|
||||||
|
sane.programs.foliate = {
|
||||||
|
sandbox.method = "bwrap";
|
||||||
|
sandbox.net = "clearnet"; #< for dictionary, wikipedia, online book libraries
|
||||||
|
sandbox.whitelistDbus = [ "user" ]; #< when clicking on links
|
||||||
|
sandbox.whitelistDri = true; # reduces startup time and subjective page flip time
|
||||||
|
sandbox.whitelistWayland = true;
|
||||||
|
sandbox.extraHomePaths = [
|
||||||
|
"Books/local"
|
||||||
|
"Books/servo"
|
||||||
|
"tmp" #< for downloaded files
|
||||||
|
];
|
||||||
|
sandbox.extraPaths = [
|
||||||
|
# foliate sandboxes itself with bwrap, which needs these.
|
||||||
|
# but it actually only cares that /sys/{block,bus,class/block} *exist*: it doesn't care if there's anything in them.
|
||||||
|
# so bind empty (sub)directories
|
||||||
|
# and it looks like i might need to keep IPC namespace if i want TTS.
|
||||||
|
"/sys/block/loop7"
|
||||||
|
"/sys/bus/container/devices"
|
||||||
|
"/sys/class/block/loop7"
|
||||||
|
];
|
||||||
|
sandbox.autodetectCliPaths = "existing";
|
||||||
|
|
||||||
|
persist.byStore.plaintext = [
|
||||||
|
".local/share/com.github.johnfactotum.Foliate" #< books added, reading position
|
||||||
|
".cache/com.github.johnfactotum.Foliate" #< webkit cache
|
||||||
|
];
|
||||||
|
|
||||||
|
buildCost = 2; #< webkitgtk 6.0
|
||||||
|
# these associations were taken from its .desktop file
|
||||||
|
mime.associations."application/epub+zip" = "com.github.johnfactotum.Foliate.desktop";
|
||||||
|
mime.associations."application/x-mobipocket-ebook" = "com.github.johnfactotum.Foliate.desktop";
|
||||||
|
mime.associations."application/vnd.amazon.mobi8-ebook" = "com.github.johnfactotum.Foliate.desktop";
|
||||||
|
mime.associations."application/x-fictionbook+xml" = "com.github.johnfactotum.Foliate.desktop";
|
||||||
|
mime.associations."application/x-zip-compressed-fb2" = "com.github.johnfactotum.Foliate.desktop";
|
||||||
|
mime.associations."application/vnd.comicbook+zip" = "com.github.johnfactotum.Foliate.desktop"; # .cbz
|
||||||
|
mime.associations."x-scheme-handler/opds" = "com.github.johnfactotum.Foliate.desktop";
|
||||||
|
mime.priority = 120; #< default is 100; fallback to more specialized cbz handlers, e.g., but keep specializations for epub
|
||||||
|
};
|
||||||
|
}
|
@@ -65,6 +65,9 @@ in
|
|||||||
|
|
||||||
suggestedPrograms = [ "gnome-keyring" ];
|
suggestedPrograms = [ "gnome-keyring" ];
|
||||||
|
|
||||||
|
# direct room links opened from other programs, to fractal.
|
||||||
|
mime.urlAssociations."^https?://matrix.to/#/.+$" = "org.gnome.Fractal.desktop";
|
||||||
|
|
||||||
services.fractal = {
|
services.fractal = {
|
||||||
description = "fractal Matrix client";
|
description = "fractal Matrix client";
|
||||||
partOf = lib.mkIf cfg.config.autostart [ "graphical-session" ];
|
partOf = lib.mkIf cfg.config.autostart [ "graphical-session" ];
|
||||||
|
@@ -23,6 +23,13 @@ in
|
|||||||
sandbox.net = "clearnet";
|
sandbox.net = "clearnet";
|
||||||
sandbox.whitelistDbus = [ "user" ]; # notifications
|
sandbox.whitelistDbus = [ "user" ]; # notifications
|
||||||
sandbox.whitelistWayland = true;
|
sandbox.whitelistWayland = true;
|
||||||
|
sandbox.extraHomePaths = [
|
||||||
|
# it shouldn't need these, but portal integration seems incomplete?
|
||||||
|
"tmp"
|
||||||
|
"Pictures/from"
|
||||||
|
"Pictures/Photos"
|
||||||
|
"Pictures/Screenshots"
|
||||||
|
];
|
||||||
sandbox.extraPaths = [
|
sandbox.extraPaths = [
|
||||||
# geary sandboxes *itself* with bwrap, and dbus-proxy which, confusingly, causes it to *require* these paths.
|
# geary sandboxes *itself* with bwrap, and dbus-proxy which, confusingly, causes it to *require* these paths.
|
||||||
# TODO: these could maybe be mounted empty. or maybe there's an env-var to disable geary's dbus-proxy.
|
# TODO: these could maybe be mounted empty. or maybe there's an env-var to disable geary's dbus-proxy.
|
||||||
|
@@ -10,7 +10,7 @@
|
|||||||
];
|
];
|
||||||
sandbox.capabilities = [
|
sandbox.capabilities = [
|
||||||
# ipc_lock: used to `mlock` the secrets so they don't get swapped out.
|
# ipc_lock: used to `mlock` the secrets so they don't get swapped out.
|
||||||
# this is optional, and systemd likely doesn't propagate it anyway
|
# this is optional, and user namespacing (bwrap) likely doesn't propagate it anyway
|
||||||
"ipc_lock"
|
"ipc_lock"
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@@ -10,6 +10,12 @@
|
|||||||
# TIPS:
|
# TIPS:
|
||||||
# - use "Northwest" instead of "NW", and "Street" instead of "St", etc.
|
# - use "Northwest" instead of "NW", and "Street" instead of "St", etc.
|
||||||
# otherwise, it might not find your destination!
|
# otherwise, it might not find your destination!
|
||||||
|
#
|
||||||
|
# TODO:
|
||||||
|
# - get gnome-maps to access location services via the xdg-desktop-portal.
|
||||||
|
# with it not using the portal, it can't open links via the web browser.
|
||||||
|
# additionally, that prevents OpenStreetMap sign-in.
|
||||||
|
# even temporarily enabling the portal for OSM doesn't work *after* the portal has been disabled -- because then gnome-maps can't access its passwords (?)
|
||||||
{ pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
{
|
{
|
||||||
sane.programs."gnome.gnome-maps" = {
|
sane.programs."gnome.gnome-maps" = {
|
||||||
|
23
hosts/common/programs/gocryptfs.nix
Normal file
23
hosts/common/programs/gocryptfs.nix
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{ ... }:
|
||||||
|
{
|
||||||
|
sane.programs.gocryptfs = {
|
||||||
|
sandbox.method = "landlock";
|
||||||
|
sandbox.autodetectCliPaths = "existing";
|
||||||
|
sandbox.capabilities = [
|
||||||
|
# CAP_SYS_ADMIN is only required if directly invoking gocryptfs
|
||||||
|
# i.e. not leverage a mount helper like `mount.fuse3-sane`.
|
||||||
|
"sys_admin"
|
||||||
|
"chown"
|
||||||
|
"dac_override"
|
||||||
|
"dac_read_search"
|
||||||
|
"fowner"
|
||||||
|
"lease"
|
||||||
|
"mknod"
|
||||||
|
"setgid"
|
||||||
|
"setuid"
|
||||||
|
];
|
||||||
|
suggestedPrograms = [
|
||||||
|
"util-linux" #< gocryptfs complains that it can't exec `logger`, otherwise
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
@@ -25,6 +25,12 @@ in
|
|||||||
"jq"
|
"jq"
|
||||||
# and systemd, for udevadm
|
# and systemd, for udevadm
|
||||||
];
|
];
|
||||||
|
|
||||||
|
sandbox.method = "bwrap";
|
||||||
|
sandbox.net = "all";
|
||||||
|
sandbox.autodetectCliPaths = "existing"; #< N.B.: `test -f /dev/ttyUSB1` fails, we can't use `existingFile`
|
||||||
|
sandbox.whitelistDbus = [ "system" ]; #< to register with Avahi
|
||||||
|
|
||||||
services.gps-share = {
|
services.gps-share = {
|
||||||
description = "gps-share: make local GPS serial readings available over Avahi";
|
description = "gps-share: make local GPS serial readings available over Avahi";
|
||||||
# usage:
|
# usage:
|
||||||
@@ -46,10 +52,6 @@ in
|
|||||||
partOf = [ "gps" ];
|
partOf = [ "gps" ];
|
||||||
depends = [ "eg25-control-powered" ];
|
depends = [ "eg25-control-powered" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
sandbox.method = "bwrap";
|
|
||||||
sandbox.net = "all";
|
|
||||||
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!!
|
||||||
|
@@ -16,7 +16,7 @@
|
|||||||
sandbox.whitelistDri = true; #< required
|
sandbox.whitelistDri = true; #< required
|
||||||
sandbox.whitelistWayland = true;
|
sandbox.whitelistWayland = true;
|
||||||
|
|
||||||
buildCost = 2;
|
buildCost = 2; # webkitgtk
|
||||||
|
|
||||||
secrets.".local/share/komikku/keyrings/plaintext.keyring" = ../../../secrets/common/komikku_accounts.json.bin;
|
secrets.".local/share/komikku/keyrings/plaintext.keyring" = ../../../secrets/common/komikku_accounts.json.bin;
|
||||||
# downloads end up here, and without the toplevel database komikku doesn't know they exist.
|
# downloads end up here, and without the toplevel database komikku doesn't know they exist.
|
||||||
@@ -27,5 +27,8 @@
|
|||||||
persist.byStore.ephemeral = [
|
persist.byStore.ephemeral = [
|
||||||
".cache/komikku"
|
".cache/komikku"
|
||||||
];
|
];
|
||||||
|
|
||||||
|
# XXX(2024-08-08): komikku can handle URLs from sources it understands (maybe), but not files (even if encoded as file:// URI)
|
||||||
|
# mime.associations."application/vnd.comicbook+zip" = "info.febvre.Komikku.desktop"; # .cbz
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -4,5 +4,15 @@
|
|||||||
sandbox.method = "bwrap";
|
sandbox.method = "bwrap";
|
||||||
sandbox.autodetectCliPaths = "existingFile";
|
sandbox.autodetectCliPaths = "existingFile";
|
||||||
env.PAGER = "less";
|
env.PAGER = "less";
|
||||||
|
# LESS flags:
|
||||||
|
# - F = quit if output fits on one screen
|
||||||
|
# - K = exit on ctrl+c
|
||||||
|
# - M = "long prompt"
|
||||||
|
# - R = output raw control characters
|
||||||
|
# - S = chop long lines instead of wrapping
|
||||||
|
# - X = Don't use termcap init/deinit strings (hence, `less` output is visible on the terminal even after exiting)
|
||||||
|
# SYSTEMD_LESS defaults to FRSXMK
|
||||||
|
env.LESS = "FRMK";
|
||||||
|
env.SYSTEMD_LESS = "FRMK"; #< used by journalctl
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -243,13 +243,16 @@ in
|
|||||||
mime.associations."video/webm" = "mpv.desktop";
|
mime.associations."video/webm" = "mpv.desktop";
|
||||||
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";
|
#v be the opener for YouTube videos
|
||||||
mime.urlAssociations."^https?://(m\.)?(www\.)?youtube.com/embed/.+" = "mpv.desktop";
|
mime.urlAssociations."^https?://(m\.)?(www\.)?youtu.be/.+$" = "mpv.desktop";
|
||||||
mime.urlAssociations."^https?://(m\.)?(www\.)?youtube.com/playlist\?.*list=.+" = "mpv.desktop";
|
mime.urlAssociations."^https?://(m\.)?(www\.)?youtube.com/embed/.+$" = "mpv.desktop";
|
||||||
mime.urlAssociations."^https?://(m\.)?(www\.)?youtube.com/shorts/.+" = "mpv.desktop";
|
mime.urlAssociations."^https?://(m\.)?(www\.)?youtube.com/playlist\?.*list=.+$" = "mpv.desktop";
|
||||||
mime.urlAssociations."^https?://(m\.)?(www\.)?youtube.com/v/.+" = "mpv.desktop";
|
mime.urlAssociations."^https?://(m\.)?(www\.)?youtube.com/shorts/.+$" = "mpv.desktop";
|
||||||
mime.urlAssociations."^https?://(m\.)?(www\.)?youtube.com/watch\?.*v=.+" = "mpv.desktop";
|
mime.urlAssociations."^https?://(m\.)?(www\.)?youtube.com/v/.+$" = "mpv.desktop";
|
||||||
|
mime.urlAssociations."^https?://(m\.)?(www\.)?youtube.com/watch\?.*v=.+$" = "mpv.desktop";
|
||||||
|
#v be the opener for A/V, generally. useful for e.g. feed readers like News Flash which open content through the portal
|
||||||
|
mime.urlAssociations."^https?://.*\.(mp3|mp4|ogg|ogv|opus|webm)(\\?.*)?$" = "mpv.desktop";
|
||||||
#v Loupe image viewer can't open URIs, so use mpv instead
|
#v Loupe image viewer can't open URIs, so use mpv instead
|
||||||
mime.urlAssociations."^https?://i\.imgur.com/.+" = "mpv.desktop";
|
mime.urlAssociations."^https?://i\.imgur.com/.+$" = "mpv.desktop";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -22,8 +22,17 @@
|
|||||||
"/"
|
"/"
|
||||||
".persist/ephemeral"
|
".persist/ephemeral"
|
||||||
".persist/plaintext"
|
".persist/plaintext"
|
||||||
|
"Pictures/Photos"
|
||||||
|
"Pictures/Screenshots"
|
||||||
|
"Pictures/albums"
|
||||||
|
"Pictures/cat"
|
||||||
|
"Pictures/from"
|
||||||
|
"Videos/local"
|
||||||
|
"archive"
|
||||||
"knowledge"
|
"knowledge"
|
||||||
"nixos"
|
"nixos"
|
||||||
|
"records"
|
||||||
|
"tmp"
|
||||||
];
|
];
|
||||||
sandbox.extraPaths = [
|
sandbox.extraPaths = [
|
||||||
"/boot"
|
"/boot"
|
||||||
|
@@ -1,8 +1,10 @@
|
|||||||
# news-flash RSS viewer
|
# news-flash RSS viewer (exe: `io.gitlab.news_flash.NewsFlash`)
|
||||||
# - feeds have to be manually imported:
|
# - feeds have to be manually imported:
|
||||||
# - Local RSS -> Import OPML -> ~/.config/newsflashFeeds.opml
|
# - Local RSS -> Import OPML -> ~/.config/newsflashFeeds.opml
|
||||||
# - clicking article-embedded links doesn't work because of xdg portal stuff
|
# option may be greyed out on first run: just restart it.
|
||||||
# - need to either run unsandboxed, or install a org.freedesktop.portal.OpenURI handler
|
# takes about 20 minutes to import results from scratch.
|
||||||
|
# TODO: auto-import feeds
|
||||||
|
# - `newsflash -s` might allow importing individual feeds; not removing them, though
|
||||||
{ config, sane-lib, ... }:
|
{ config, sane-lib, ... }:
|
||||||
|
|
||||||
let
|
let
|
||||||
@@ -13,8 +15,31 @@ let
|
|||||||
wanted-feeds = feeds.filterByFormat [ "text" "image" "podcast" "video" ] all-feeds;
|
wanted-feeds = feeds.filterByFormat [ "text" "image" "podcast" "video" ] all-feeds;
|
||||||
in {
|
in {
|
||||||
sane.programs.newsflash = {
|
sane.programs.newsflash = {
|
||||||
|
sandbox.method = "bwrap";
|
||||||
|
sandbox.net = "clearnet";
|
||||||
|
sandbox.whitelistAudio = true; #< for embedded videos
|
||||||
|
sandbox.whitelistDbus = [ "user" ];
|
||||||
|
sandbox.whitelistDri = true;
|
||||||
|
sandbox.whitelistWayland = true;
|
||||||
|
sandbox.extraPaths = [
|
||||||
|
# the app sandboxes itself with bwrap, which needs these.
|
||||||
|
# but it actually only cares that /sys/{block,bus,class/block} *exist*: it doesn't care if there's anything in them.
|
||||||
|
# so bind empty (sub)directories
|
||||||
|
"/sys/block/loop7"
|
||||||
|
"/sys/bus/container/devices"
|
||||||
|
"/sys/class/block/loop7"
|
||||||
|
];
|
||||||
|
|
||||||
buildCost = 2; # mainly for desktop: webkitgtk-6.0
|
buildCost = 2; # mainly for desktop: webkitgtk-6.0
|
||||||
persist.byStore.plaintext = [ ".local/share/news-flash" ];
|
persist.byStore.plaintext = [
|
||||||
|
".local/share/news-flash" #< sqlite database, the actually important stuff
|
||||||
|
# ".local/share/news_flash" #< device IDs (?)
|
||||||
|
".config/news-flash" #< includes `"backend": "local_rss"`
|
||||||
|
];
|
||||||
|
persist.byStore.ephemeral = [
|
||||||
|
".cache/news_flash" #< WebKit cache
|
||||||
|
];
|
||||||
|
#v for *manual* use:
|
||||||
fs.".config/newsflashFeeds.opml".symlink.text =
|
fs.".config/newsflashFeeds.opml".symlink.text =
|
||||||
feeds.feedsToOpml wanted-feeds
|
feeds.feedsToOpml wanted-feeds
|
||||||
;
|
;
|
||||||
|
@@ -2,5 +2,9 @@
|
|||||||
{
|
{
|
||||||
sane.programs.nix = {
|
sane.programs.nix = {
|
||||||
env.NIXPKGS_ALLOW_UNFREE = "1"; #< FUCK OFF YOU'RE SO ANNOYING
|
env.NIXPKGS_ALLOW_UNFREE = "1"; #< FUCK OFF YOU'RE SO ANNOYING
|
||||||
|
persist.byStore.plaintext = [
|
||||||
|
# ~/.cache/nix can become several GB; persisted to save RAM
|
||||||
|
".cache/nix"
|
||||||
|
];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -5,6 +5,9 @@
|
|||||||
# since that component needs to run in initrd and before service setup.
|
# 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.
|
# TODO: log rotation / retention policy. don't want to eat the whole HDD.
|
||||||
|
# TODO: store these logs in /var/log/...
|
||||||
|
# and at that point it makes more sense to use a systemd service.
|
||||||
|
# i.e. revert `3a6a5ffe014761ff23220f5b4ecb74d8a9fdb8fd`
|
||||||
{ config, lib, ... }:
|
{ config, lib, ... }:
|
||||||
{
|
{
|
||||||
sane.programs.rsyslog = {
|
sane.programs.rsyslog = {
|
||||||
|
@@ -19,9 +19,12 @@ in
|
|||||||
sandbox.extraHomePaths = [ "knowledge/planner/deadlines.tsv" ];
|
sandbox.extraHomePaths = [ "knowledge/planner/deadlines.tsv" ];
|
||||||
|
|
||||||
fs.".profile".symlink.text = lib.mkIf cfg.config.showOnLogin ''
|
fs.".profile".symlink.text = lib.mkIf cfg.config.showOnLogin ''
|
||||||
if [ -z "$SSH_TTY" ]; then
|
maybeShowDeadlines() {
|
||||||
sane-deadlines
|
if [ -z "$SSH_TTY" ]; then
|
||||||
fi
|
sane-deadlines
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
sessionCommands+=('maybeShowDeadlines')
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -7,10 +7,6 @@ let
|
|||||||
in
|
in
|
||||||
{
|
{
|
||||||
sane.programs = {
|
sane.programs = {
|
||||||
"sane-scripts.backup" = declPackageSet [
|
|
||||||
"sane-scripts.backup-ls"
|
|
||||||
"sane-scripts.backup-restore"
|
|
||||||
];
|
|
||||||
"sane-scripts.bittorrent" = declPackageSet [
|
"sane-scripts.bittorrent" = declPackageSet [
|
||||||
"sane-scripts.bt-add"
|
"sane-scripts.bt-add"
|
||||||
"sane-scripts.bt-rm"
|
"sane-scripts.bt-rm"
|
||||||
@@ -46,9 +42,6 @@ in
|
|||||||
"sane-scripts.sync-music"
|
"sane-scripts.sync-music"
|
||||||
];
|
];
|
||||||
|
|
||||||
"sane-scripts.backup-ls" = {};
|
|
||||||
"sane-scripts.backup-restore" = {};
|
|
||||||
|
|
||||||
"sane-scripts.bt-add".sandbox = {
|
"sane-scripts.bt-add".sandbox = {
|
||||||
method = "bwrap";
|
method = "bwrap";
|
||||||
autodetectCliPaths = "existing"; #< for adding a .torrent from disk
|
autodetectCliPaths = "existing"; #< for adding a .torrent from disk
|
||||||
|
@@ -7,11 +7,14 @@
|
|||||||
"/sys/devices"
|
"/sys/devices"
|
||||||
];
|
];
|
||||||
fs.".profile".symlink.text = ''
|
fs.".profile".symlink.text = ''
|
||||||
# show ssh users the current resource usage.
|
maybeShowSysload() {
|
||||||
# especially useful for moby (to see battery)
|
# show ssh users the current resource usage.
|
||||||
if [ -n "$SSH_TTY" ]; then
|
# especially useful for moby (to see battery)
|
||||||
sane-sysload
|
if [ -n "$SSH_TTY" ]; then
|
||||||
fi
|
sane-sysload
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
sessionCommands+=('maybeShowSysload')
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -20,13 +20,14 @@ in
|
|||||||
bubblewrap = cfg.bubblewrap.package;
|
bubblewrap = cfg.bubblewrap.package;
|
||||||
iproute2 = cfg.iproute2.package;
|
iproute2 = cfg.iproute2.package;
|
||||||
iptables = cfg.iptables.package;
|
iptables = cfg.iptables.package;
|
||||||
libcap = cfg.libcap.package;
|
libcap = cfg.capsh.package; #< the sandboxer doesn't use any other libcap binaries
|
||||||
passt = cfg.passt.package;
|
passt = cfg.passt.package;
|
||||||
landlock-sandboxer = pkgs.landlock-sandboxer.override {
|
landlock-sandboxer = cfg.landlock-sandboxer.package;
|
||||||
# not strictly necessary (landlock ABI is versioned), however when sandboxer version != kernel version,
|
# landlock-sandboxer = pkgs.landlock-sandboxer.override {
|
||||||
# the sandboxer may nag about one or the other wanting to be updated.
|
# # not strictly necessary (landlock ABI is versioned), however when sandboxer version != kernel version,
|
||||||
linux = config.boot.kernelPackages.kernel;
|
# # the sandboxer may nag about one or the other wanting to be updated.
|
||||||
};
|
# linux = config.boot.kernelPackages.kernel;
|
||||||
|
# };
|
||||||
}).overrideAttrs (base: {
|
}).overrideAttrs (base: {
|
||||||
# create a directory which holds just the `sanebox` so that we
|
# 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
|
# can add sanebox as a dependency to binaries via `PATH=/run/current-system/libexec/sanebox` without forcing rebuild every time sanebox changes
|
||||||
|
@@ -1,16 +1,26 @@
|
|||||||
{ config, lib, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
let
|
let
|
||||||
cfg = config.sane.programs.seatd;
|
cfg = config.sane.programs.seatd;
|
||||||
|
seatdDir = "/run/seatd";
|
||||||
|
seatdSock = "${seatdDir}/seatd.sock";
|
||||||
in
|
in
|
||||||
lib.mkMerge [
|
lib.mkMerge [
|
||||||
{
|
{
|
||||||
sane.programs.seatd = {
|
sane.programs.seatd = {
|
||||||
|
packageUnwrapped = pkgs.seatd.overrideAttrs (base: {
|
||||||
|
# patch so seatd places its socket in a place that's easier to sandbox
|
||||||
|
mesonFlags = base.mesonFlags ++ [
|
||||||
|
"-Ddefaultpath=${seatdSock}"
|
||||||
|
];
|
||||||
|
});
|
||||||
sandbox.method = "bwrap";
|
sandbox.method = "bwrap";
|
||||||
sandbox.capabilities = [
|
sandbox.capabilities = [
|
||||||
"sys_tty_config" "sys_admin"
|
# "chown"
|
||||||
"chown"
|
"dac_override" #< TODO: is there no way to get rid of this? (use the `tty` group?)
|
||||||
"dac_override" #< TODO: is there no way to get rid of this?
|
# "sys_admin"
|
||||||
|
"sys_tty_config"
|
||||||
];
|
];
|
||||||
|
sandbox.isolateUsers = false;
|
||||||
sandbox.extraPaths = [
|
sandbox.extraPaths = [
|
||||||
"/dev" #< TODO: this can be removed if i have seatd restart on client error such that seatd can discover devices as they appear
|
"/dev" #< TODO: this can be removed if i have seatd restart on client error such that seatd can discover devices as they appear
|
||||||
# "/dev/dri"
|
# "/dev/dri"
|
||||||
@@ -23,28 +33,48 @@ lib.mkMerge [
|
|||||||
# "/dev/tty0"
|
# "/dev/tty0"
|
||||||
# "/dev/tty1"
|
# "/dev/tty1"
|
||||||
# "/proc"
|
# "/proc"
|
||||||
"/run" #< TODO: confine this to some subdirectory
|
seatdDir
|
||||||
# "/sys"
|
# "/sys"
|
||||||
];
|
];
|
||||||
|
env.SEATD_SOCK = seatdSock; #< client side configuration (i.e. tells sway where to look)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
(lib.mkIf cfg.enabled {
|
(lib.mkIf cfg.enabled {
|
||||||
users.groups.seat = {};
|
users.groups.seat = {};
|
||||||
|
|
||||||
# TODO: /run/seatd.sock location can be configured, but only via compile-time flag
|
sane.fs."${seatdDir}".dir.acl = {
|
||||||
|
user = "root";
|
||||||
|
group = "seat";
|
||||||
|
mode = "0770";
|
||||||
|
};
|
||||||
|
|
||||||
systemd.services.seatd = {
|
systemd.services.seatd = {
|
||||||
description = "Seat management daemon";
|
description = "Seat management daemon";
|
||||||
documentation = [ "man:seatd(1)" ];
|
documentation = [ "man:seatd(1)" ];
|
||||||
|
|
||||||
|
after = [ config.sane.fs."${seatdDir}".unit ];
|
||||||
|
wants = [ config.sane.fs."${seatdDir}".unit ];
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
restartIfChanged = false;
|
restartIfChanged = false;
|
||||||
|
|
||||||
serviceConfig = {
|
serviceConfig.Type = "simple";
|
||||||
Type = "simple";
|
serviceConfig.ExecStart = "${cfg.package}/bin/seatd -g seat";
|
||||||
ExecStart = "${cfg.package}/bin/seatd -g seat";
|
serviceConfig.Group = "seat";
|
||||||
Group = "seat";
|
# serviceConfig.AmbientCapabilities = [
|
||||||
# AmbientCapabilities = [ "CAP_SYS_TTY_CONFIG" "CAP_SYS_ADMIN" ];
|
# "CAP_DAC_OVERRIDE"
|
||||||
};
|
# "CAP_NET_ADMIN"
|
||||||
|
# "CAP_SYS_ADMIN"
|
||||||
|
# "CAP_SYS_TTY_CONFIG"
|
||||||
|
# ];
|
||||||
|
serviceConfig.CapabilityBoundingSet = [
|
||||||
|
# TODO: these can probably be reduced if i switch to landlock for sandboxing,
|
||||||
|
# or run as a user other than root
|
||||||
|
# "CAP_CHOWN"
|
||||||
|
"CAP_DAC_OVERRIDE" #< needed, to access /dev/tty
|
||||||
|
"CAP_NET_ADMIN" #< needed by bwrap, for some reason??
|
||||||
|
"CAP_SYS_ADMIN" #< needed by bwrap
|
||||||
|
"CAP_SYS_TTY_CONFIG"
|
||||||
|
];
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
]
|
]
|
||||||
|
@@ -165,7 +165,8 @@ for_window [workspace="TV"] fullscreen enable
|
|||||||
# mostly, messengers belong on WS 1
|
# mostly, messengers belong on WS 1
|
||||||
assign [app_id="abaddon"] workspace number 1
|
assign [app_id="abaddon"] workspace number 1
|
||||||
assign [app_id="geary"] workspace number 1
|
assign [app_id="geary"] workspace number 1
|
||||||
assign [app_id="gnome-calls"] workspace number 1
|
assign [app_id="gnome-calls"] workspace number 1 # gnome-calls <= 46.3
|
||||||
|
assign [app_id="org.gnome.Calls"] workspace number 1 # gnome-calls >= 47.0-beta
|
||||||
assign [app_id="im.dino.Dino"] workspace number 1
|
assign [app_id="im.dino.Dino"] workspace number 1
|
||||||
assign [app_id="org.gnome.Fractal"] workspace number 1
|
assign [app_id="org.gnome.Fractal"] workspace number 1
|
||||||
assign [app_id="signal"] workspace number 1
|
assign [app_id="signal"] workspace number 1
|
||||||
|
@@ -16,7 +16,10 @@ let
|
|||||||
|
|
||||||
# delete DISPLAY-related vars from env before launch, else sway will try to connect to a remote display.
|
# delete DISPLAY-related vars from env before launch, else sway will try to connect to a remote display.
|
||||||
# (consider: nested sway sessions, where sway actually has a reason to read these)
|
# (consider: nested sway sessions, where sway actually has a reason to read these)
|
||||||
exec env -u DISPLAY -u WAYLAND_DISPLAY "DESIRED_WAYLAND_DISPLAY=$WAYLAND_DISPLAY" ${configuredSway}/bin/sway 2>&1
|
exec env -u DISPLAY -u WAYLAND_DISPLAY \
|
||||||
|
"DESIRED_WAYLAND_DISPLAY=$WAYLAND_DISPLAY" \
|
||||||
|
${configuredSway}/bin/sway \
|
||||||
|
2>&1
|
||||||
'';
|
'';
|
||||||
in
|
in
|
||||||
pkgs.symlinkJoin {
|
pkgs.symlinkJoin {
|
||||||
@@ -38,7 +41,7 @@ let
|
|||||||
# - test: run dino, receive a message while tabbed away, click the desktop notification.
|
# - test: run dino, receive a message while tabbed away, click the desktop notification.
|
||||||
# - if sway activates the dino window (i.e. colors the workspace and tab), then all good
|
# - if sway activates the dino window (i.e. colors the workspace and tab), then all good
|
||||||
# - do all of this with only a touchscreen (e.g. on mobile phone) -- NOT a mouse/pointer
|
# - do all of this with only a touchscreen (e.g. on mobile phone) -- NOT a mouse/pointer
|
||||||
# 2023/12/17: this patch is still necessary
|
# 2024/08/12: this patch is still necessary (for moby)
|
||||||
## what this patch does:
|
## what this patch does:
|
||||||
# - allows any wayland window to request activation, at any time.
|
# - allows any wayland window to request activation, at any time.
|
||||||
# - traditionally, wayland only allows windows to request activation if
|
# - traditionally, wayland only allows windows to request activation if
|
||||||
@@ -172,6 +175,7 @@ in
|
|||||||
"wireplumber" # used by sway config
|
"wireplumber" # used by sway config
|
||||||
"wl-clipboard"
|
"wl-clipboard"
|
||||||
"xdg-desktop-portal"
|
"xdg-desktop-portal"
|
||||||
|
"xdg-desktop-portal-gnome"
|
||||||
# xdg-desktop-portal-gtk provides portals for:
|
# xdg-desktop-portal-gtk provides portals for:
|
||||||
# - org.freedesktop.impl.portal.Access
|
# - org.freedesktop.impl.portal.Access
|
||||||
# - org.freedesktop.impl.portal.Account
|
# - org.freedesktop.impl.portal.Account
|
||||||
@@ -186,7 +190,7 @@ in
|
|||||||
# - org.freedesktop.impl.portal.Lockdown (@lockdown_iface@)
|
# - org.freedesktop.impl.portal.Lockdown (@lockdown_iface@)
|
||||||
# - org.freedesktop.impl.portal.Settings (@settings_iface@)
|
# - org.freedesktop.impl.portal.Settings (@settings_iface@)
|
||||||
# - org.freedesktop.impl.portal.Wallpaper (@wallpaper_iface@)
|
# - org.freedesktop.impl.portal.Wallpaper (@wallpaper_iface@)
|
||||||
"xdg-desktop-portal-gtk"
|
# "xdg-desktop-portal-gtk"
|
||||||
# xdg-desktop-portal-wlr provides portals for screenshots/screen sharing
|
# xdg-desktop-portal-wlr provides portals for screenshots/screen sharing
|
||||||
"xdg-desktop-portal-wlr"
|
"xdg-desktop-portal-wlr"
|
||||||
"xdg-terminal-exec" # used by sway config
|
"xdg-terminal-exec" # used by sway config
|
||||||
@@ -208,7 +212,7 @@ in
|
|||||||
];
|
];
|
||||||
sandbox.extraPaths = [
|
sandbox.extraPaths = [
|
||||||
# "/dev/input"
|
# "/dev/input"
|
||||||
"/run/seatd.sock" #< required if not using `logind` systemd login manager
|
"/run/seatd" #< required if not using `logind` systemd login manager
|
||||||
# "/run/systemd/sessions"
|
# "/run/systemd/sessions"
|
||||||
"/run/udev"
|
"/run/udev"
|
||||||
"/sys/class/backlight"
|
"/sys/class/backlight"
|
||||||
@@ -226,7 +230,7 @@ in
|
|||||||
fs.".config/xdg-desktop-portal/sway-portals.conf".symlink.text = ''
|
fs.".config/xdg-desktop-portal/sway-portals.conf".symlink.text = ''
|
||||||
# portals.conf docs: <https://flatpak.github.io/xdg-desktop-portal/docs/portals.conf.html>
|
# portals.conf docs: <https://flatpak.github.io/xdg-desktop-portal/docs/portals.conf.html>
|
||||||
[preferred]
|
[preferred]
|
||||||
default=wlr;gtk
|
default=wlr;gnome;gtk
|
||||||
'';
|
'';
|
||||||
|
|
||||||
fs.".config/sway/config".symlink.target = pkgs.substituteAll {
|
fs.".config/sway/config".symlink.target = pkgs.substituteAll {
|
||||||
|
@@ -18,6 +18,6 @@
|
|||||||
persist.byStore.ephemeral = [
|
persist.byStore.ephemeral = [
|
||||||
".local/share/tor-browser"
|
".local/share/tor-browser"
|
||||||
];
|
];
|
||||||
mime.urlAssociations."^https?://.+\.onion" = "torbrowser.desktop";
|
mime.urlAssociations."^https?://.+\.onion$" = "torbrowser.desktop";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
56
hosts/common/programs/xdg-desktop-portal-gnome/default.nix
Normal file
56
hosts/common/programs/xdg-desktop-portal-gnome/default.nix
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
# XXX(2024-08-07): xdg-desktop-portal-gnome has a nicer filechooser than xdg-desktop-portal-gtk.
|
||||||
|
# especially, mobile friendly.
|
||||||
|
# but starting with 47.0 (unreleased), it will switch to Nautilus. so expect some work in porting.
|
||||||
|
{ config, pkgs, ... }:
|
||||||
|
let
|
||||||
|
cfg = config.sane.programs.xdg-desktop-portal-gnome;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
sane.programs.xdg-desktop-portal-gnome = {
|
||||||
|
packageUnwrapped = pkgs.xdg-desktop-portal-gnome.overrideAttrs (base: {
|
||||||
|
patches = (base.patches or []) ++ [
|
||||||
|
./init_display_no_mutter.diff
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
sandbox.method = "bwrap";
|
||||||
|
sandbox.whitelistDbus = [ "user" ]; # speak to main xdg-desktop-portal
|
||||||
|
sandbox.whitelistWayland = true;
|
||||||
|
sandbox.extraHomePaths = [
|
||||||
|
".local/share/applications" # file opener needs to find .desktop files, for their icon/name.
|
||||||
|
# for file-chooser portal users (fractal, firefox, ...), need to provide anything they might want.
|
||||||
|
# i think (?) portal users can only access the files here interactively, i.e. by me interacting with the portal's visual filechooser,
|
||||||
|
# so shoving stuff here is trusting the portal but not granting any trust to the portal user.
|
||||||
|
"Books/local"
|
||||||
|
"Books/servo"
|
||||||
|
"Music"
|
||||||
|
"Pictures/albums"
|
||||||
|
"Pictures/cat"
|
||||||
|
"Pictures/from"
|
||||||
|
"Pictures/Photos"
|
||||||
|
"Pictures/Screenshots"
|
||||||
|
"Pictures/servo-macros"
|
||||||
|
"Videos/local"
|
||||||
|
"Videos/servo"
|
||||||
|
"archive"
|
||||||
|
"dev"
|
||||||
|
"ref"
|
||||||
|
"tmp"
|
||||||
|
"use"
|
||||||
|
];
|
||||||
|
|
||||||
|
fs.".config/xdg-desktop-portal/portals/gnome.portal".symlink.target =
|
||||||
|
"${cfg.packageUnwrapped}/share/xdg-desktop-portal/portals/gnome.portal";
|
||||||
|
# XXX: overcome bug when manually setting `$XDG_DESKTOP_PORTAL_DIR`
|
||||||
|
# which causes *.portal files to be looked for in the toplevel instead of under `portals/`
|
||||||
|
fs.".config/xdg-desktop-portal/gnome.portal".symlink.target = "portals/gnome.portal";
|
||||||
|
|
||||||
|
services.xdg-desktop-portal-gnome = {
|
||||||
|
description = "xdg-desktop-portal-gnome backend (provides file chooser and other functionality for xdg-desktop-portal)";
|
||||||
|
dependencyOf = [ "xdg-desktop-portal" ];
|
||||||
|
|
||||||
|
command = "XDG_SESSION_TYPE=wayland ${cfg.package}/libexec/xdg-desktop-portal-gnome";
|
||||||
|
readiness.waitDbus = "org.freedesktop.impl.portal.desktop.gnome";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
@@ -0,0 +1,38 @@
|
|||||||
|
diff --git a/src/externalwindow-wayland.c b/src/externalwindow-wayland.c
|
||||||
|
index 4ed62c7..329b9a8 100644
|
||||||
|
--- a/src/externalwindow-wayland.c
|
||||||
|
+++ b/src/externalwindow-wayland.c
|
||||||
|
@@ -259,33 +259,6 @@ init_external_window_wayland_display (GError **error)
|
||||||
|
g_autofree char *fd_str = NULL;
|
||||||
|
GdkDisplay *display;
|
||||||
|
|
||||||
|
- proxy = org_gnome_mutter_service_channel_proxy_new_for_bus_sync (
|
||||||
|
- G_BUS_TYPE_SESSION,
|
||||||
|
- (G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START |
|
||||||
|
- G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
|
||||||
|
- G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS),
|
||||||
|
- "org.gnome.Mutter.ServiceChannel",
|
||||||
|
- "/org/gnome/Mutter/ServiceChannel",
|
||||||
|
- NULL, error);
|
||||||
|
- if (!proxy)
|
||||||
|
- return NULL;
|
||||||
|
-
|
||||||
|
- if (!org_gnome_mutter_service_channel_call_open_wayland_service_connection_sync (
|
||||||
|
- proxy,
|
||||||
|
- SERVICE_CLIENT_TYPE_PORTAL_BACKEND,
|
||||||
|
- NULL,
|
||||||
|
- &fd_variant,
|
||||||
|
- &fd_list,
|
||||||
|
- NULL, error))
|
||||||
|
- return NULL;
|
||||||
|
-
|
||||||
|
- fd = g_unix_fd_list_get (fd_list, g_variant_get_handle (fd_variant), error);
|
||||||
|
- if (fd < 0)
|
||||||
|
- return NULL;
|
||||||
|
-
|
||||||
|
- fd_str = g_strdup_printf ("%d", fd);
|
||||||
|
-
|
||||||
|
- g_setenv ("WAYLAND_SOCKET", fd_str, TRUE);
|
||||||
|
gdk_set_allowed_backends ("wayland");
|
||||||
|
display = gdk_display_open (NULL);
|
||||||
|
g_assert (display);
|
@@ -12,6 +12,7 @@
|
|||||||
".local/share/zathura"
|
".local/share/zathura"
|
||||||
];
|
];
|
||||||
|
|
||||||
|
mime.priority = 150; #< default is 100; fallback to more specialized cbz handlers, e.g.
|
||||||
mime.associations."application/pdf" = "org.pwmt.zathura.desktop";
|
mime.associations."application/pdf" = "org.pwmt.zathura.desktop";
|
||||||
mime.associations."application/vnd.comicbook+zip" = "org.pwmt.zathura.desktop"; # .cbz
|
mime.associations."application/vnd.comicbook+zip" = "org.pwmt.zathura.desktop"; # .cbz
|
||||||
mime.associations."application/vnd.comicbook-rar" = "org.pwmt.zathura.desktop"; # .cbr
|
mime.associations."application/vnd.comicbook-rar" = "org.pwmt.zathura.desktop"; # .cbr
|
||||||
|
@@ -74,4 +74,38 @@ in
|
|||||||
# DefaultTimeoutStopSec defaults to 90s, and frequently blocks overall system shutdown.
|
# DefaultTimeoutStopSec defaults to 90s, and frequently blocks overall system shutdown.
|
||||||
DefaultTimeoutStopSec=${builtins.toString haltTimeout}
|
DefaultTimeoutStopSec=${builtins.toString haltTimeout}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
# hard base systemd services
|
||||||
|
# see: `systemd-analyze security`
|
||||||
|
systemd.services.systemd-rfkill.serviceConfig = {
|
||||||
|
AmbientCapabilities = "";
|
||||||
|
CapabilityBoundingSet = "";
|
||||||
|
DevicePolicy = "closed";
|
||||||
|
IPAddressDeny = "any";
|
||||||
|
LockPersonality = true;
|
||||||
|
MemoryDenyWriteExecute = true;
|
||||||
|
NoNewPrivileges = true;
|
||||||
|
PrivateDevices = true;
|
||||||
|
PrivateMounts = true;
|
||||||
|
PrivateNetwork = true;
|
||||||
|
PrivateTmp = true;
|
||||||
|
PrivateUsers = true;
|
||||||
|
ProcSubset = "pid";
|
||||||
|
ProtectClock = true;
|
||||||
|
ProtectControlGroups = true;
|
||||||
|
ProtectHome = true;
|
||||||
|
ProtectHostname = true;
|
||||||
|
ProtectKernelLogs = true;
|
||||||
|
ProtectKernelModules = true;
|
||||||
|
ProtectKernelTunables = true;
|
||||||
|
ProtectProc = "invisible";
|
||||||
|
ProtectSystem = "strict";
|
||||||
|
RemoveIPC = true;
|
||||||
|
RestrictAddressFamilies = "AF_UNIX";
|
||||||
|
RestrictNamespaces = true;
|
||||||
|
RestrictRealtime = true;
|
||||||
|
RestrictSUIDSGID = true;
|
||||||
|
SystemCallArchitectures = "native";
|
||||||
|
SystemCallFilter = [ "@system-service" "~@privileged" "~@resources" ];
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@@ -118,4 +118,8 @@
|
|||||||
|
|
||||||
sane.users.colin.default = true;
|
sane.users.colin.default = true;
|
||||||
services.getty.autologinUser = lib.mkDefault "colin";
|
services.getty.autologinUser = lib.mkDefault "colin";
|
||||||
|
security.pam.services.login.startSession = lib.mkForce false; #< disable systemd integration
|
||||||
|
|
||||||
|
# systemd-user-sessions depends on remote-fs, causing login to take stupidly long
|
||||||
|
systemd.services."systemd-user-sessions".enable = false;
|
||||||
}
|
}
|
||||||
|
@@ -249,14 +249,13 @@ in
|
|||||||
# rtl_bt (bluetooth)
|
# rtl_bt (bluetooth)
|
||||||
# anx7688-fw.bin (USB-C chip: power negotiation, HDMI/dock)
|
# anx7688-fw.bin (USB-C chip: power negotiation, HDMI/dock)
|
||||||
# ov5640_af.bin (camera module)
|
# ov5640_af.bin (camera module)
|
||||||
# hardware.firmware = [ config.mobile.device.firmware ];
|
|
||||||
# hardware.firmware = [ pkgs.rtl8723cs-firmware ];
|
# hardware.firmware = [ pkgs.rtl8723cs-firmware ];
|
||||||
hardware.firmware = [
|
hardware.firmware = [
|
||||||
(pkgs.linux-firmware-megous.override {
|
(pkgs.linux-firmware-megous.override {
|
||||||
# rtl_bt = false probably means no bluetooth connectivity.
|
# rtl_bt = false probably means no bluetooth connectivity.
|
||||||
# N.B.: DON'T RE-ENABLE without first confirming that wake-on-lan works during suspend (rtcwake).
|
# N.B.: DON'T RE-ENABLE without first confirming that wake-on-lan works during suspend (rtcwake).
|
||||||
# it seems the rtl_bt stuff ("bluetooth coexist") might make wake-on-LAN radically more flaky.
|
# it seems the rtl_bt stuff ("bluetooth coexist") might make wake-on-LAN radically more flaky.
|
||||||
rtl_bt = false;
|
# rtl_bt = false;
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
{ ... }:
|
{ ... }:
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
./duplicity.nix
|
|
||||||
./rsync-net
|
./rsync-net
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@@ -1,98 +0,0 @@
|
|||||||
# docs: https://search.nixos.org/options?channel=21.11&query=duplicity
|
|
||||||
{ config, lib, pkgs, ... }:
|
|
||||||
|
|
||||||
with lib;
|
|
||||||
let
|
|
||||||
cfg = config.sane.services.duplicity;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
options = {
|
|
||||||
sane.services.duplicity.enable = mkOption {
|
|
||||||
default = false;
|
|
||||||
type = types.bool;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
|
||||||
# we need this mostly because of the size of duplicity's cache
|
|
||||||
sane.persist.sys.byStore.ephemeral = [{
|
|
||||||
path = "/var/lib/duplicity";
|
|
||||||
user = "root";
|
|
||||||
group = "root";
|
|
||||||
mode = "0700";
|
|
||||||
}];
|
|
||||||
|
|
||||||
services.duplicity.enable = true;
|
|
||||||
services.duplicity.targetUrl = "$DUPLICITY_URL";
|
|
||||||
# format: PASSPHRASE=<cleartext> \n DUPLICITY_URL=b2://...
|
|
||||||
# two sisters
|
|
||||||
# PASSPHRASE: remote backups will be encrypted using this passphrase (using gpg)
|
|
||||||
# DUPLICITY_URL: b2://$key_id:$app_key@$bucket
|
|
||||||
# create key with: backblaze-b2 create-key --bucket uninsane-host-duplicity uninsane-host-duplicity-safe listBuckets,listFiles,readBuckets,readFiles,writeFiles
|
|
||||||
# ^ run this until you get a key with no forward slashes :upside_down:
|
|
||||||
# web-created keys are allowed to delete files, which you probably don't want for an incremental backup program
|
|
||||||
# you need to create a new application key from the web in order to first get a key which can create new keys (use env vars in the above command)
|
|
||||||
# TODO: s/duplicity_passphrase/duplicity_env/
|
|
||||||
services.duplicity.secretFile = config.sops.secrets."duplicity_passphrase.env".path;
|
|
||||||
# NB: manually trigger with `systemctl start duplicity`
|
|
||||||
services.duplicity.frequency = "daily";
|
|
||||||
|
|
||||||
services.duplicity.extraFlags = [
|
|
||||||
# without --allow-source-mismatch, duplicity will abort if you change the hostname between backups
|
|
||||||
"--allow-source-mismatch"
|
|
||||||
|
|
||||||
# includes/exclude ordering matters, so we explicitly control it here.
|
|
||||||
# the first match decides a file's treatment. so here:
|
|
||||||
# - /nix/persist/home/colin/tmp is excluded
|
|
||||||
# - *other* /nix/persist/ files are included by default
|
|
||||||
# - anything else under `/` are excluded by default
|
|
||||||
"--exclude" "/nix/persist/home/colin/dev/home-logic/coremem/out" # this can reach > 1 TB
|
|
||||||
"--exclude" "/nix/persist/home/colin/use/iso" # might want to re-enable... but not critical
|
|
||||||
"--exclude" "/nix/persist/home/colin/.local/share/sublime-music" # music cache. better to just keep the HQ sources
|
|
||||||
"--exclude" "/nix/persist/home/colin/.local/share/Steam" # can just re-download games
|
|
||||||
"--exclude" "/nix/persist/home/colin/.bitmonero/lmdb" # monero blockchain
|
|
||||||
"--exclude" "/nix/persist/home/colin/.rustup"
|
|
||||||
"--exclude" "/nix/persist/home/colin/ref" # publicly available data: no point in duplicating it
|
|
||||||
"--exclude" "/nix/persist/home/colin/tmp"
|
|
||||||
"--exclude" "/nix/persist/home/colin/Videos"
|
|
||||||
"--exclude" "/nix/persist/var/lib/duplicity" # don't back up our own backup state!
|
|
||||||
"--include" "/nix/persist"
|
|
||||||
"--exclude" "/"
|
|
||||||
];
|
|
||||||
|
|
||||||
# set this for the FIRST backup, then remove it to enable incremental backups
|
|
||||||
# (that the first backup *isn't* full i think is a defect)
|
|
||||||
# services.duplicity.fullIfOlderThan = "always";
|
|
||||||
|
|
||||||
systemd.services.duplicity.serviceConfig = {
|
|
||||||
# rate-limit the read bandwidth in an effort to thereby prevent net upload saturation
|
|
||||||
# this could perhaps be done better by adding a duplicity config option to replace the binary with `trickle`
|
|
||||||
IOReadBandwidthMax = [
|
|
||||||
"/dev/sda1 5M"
|
|
||||||
"/dev/nvme0n1 5M"
|
|
||||||
"/dev/mmc0 5M"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
# based on <nixpkgs:nixos/modules/services/backup/duplicity.nix> with changes:
|
|
||||||
# - remove the cleanup step: API key doesn't have delete perms
|
|
||||||
# - don't escape the targetUrl: it comes from an env var set in the secret file
|
|
||||||
systemd.services.duplicity.script = let
|
|
||||||
cfg = config.services.duplicity;
|
|
||||||
target = cfg.targetUrl;
|
|
||||||
extra = escapeShellArgs ([ "--archive-dir" "/var/lib/duplicity" ] ++ cfg.extraFlags);
|
|
||||||
dup = "${pkgs.duplicity}/bin/duplicity";
|
|
||||||
in lib.mkForce ''
|
|
||||||
set -x
|
|
||||||
# ${dup} cleanup ${target} --force ${extra}
|
|
||||||
# ${lib.optionalString (cfg.cleanup.maxAge != null) "${dup} remove-older-than ${lib.escapeShellArg cfg.cleanup.maxAge} ${target} --force ${extra}"}
|
|
||||||
# ${lib.optionalString (cfg.cleanup.maxFull != null) "${dup} remove-all-but-n-full ${builtins.toString cfg.cleanup.maxFull} ${target} --force ${extra}"}
|
|
||||||
# ${lib.optionalString (cfg.cleanup.maxIncr != null) "${dup} remove-all-inc-of-but-n-full ${toString cfg.cleanup.maxIncr} ${target} --force ${extra}"}
|
|
||||||
exec ${dup} ${if cfg.fullIfOlderThan == "always" then "full" else "incr"} ${lib.escapeShellArg cfg.root} ${target} ${lib.escapeShellArgs ([]
|
|
||||||
++ concatMap (p: [ "--include" p ]) cfg.include
|
|
||||||
++ concatMap (p: [ "--exclude" p ]) cfg.exclude
|
|
||||||
++ (lib.optionals (cfg.fullIfOlderThan != "never" && cfg.fullIfOlderThan != "always") [ "--full-if-older-than" cfg.fullIfOlderThan ])
|
|
||||||
)} ${extra}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
}
|
|
@@ -25,8 +25,8 @@ in
|
|||||||
list of directories to upload to rsync.net.
|
list of directories to upload to rsync.net.
|
||||||
note that this module does NOT add any encryption to the files (layer that yourself).
|
note that this module does NOT add any encryption to the files (layer that yourself).
|
||||||
'';
|
'';
|
||||||
default = [
|
default = lib.optionals config.sane.persist.enable [
|
||||||
"/nix/persist/private"
|
"/nix/persist/private" #< XXX: make sure to do the encrypted version, not /mnt/persist/private!
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -39,22 +39,33 @@ in
|
|||||||
serviceConfig.Restart = "no";
|
serviceConfig.Restart = "no";
|
||||||
serviceConfig.User = "colin";
|
serviceConfig.User = "colin";
|
||||||
|
|
||||||
# hardening
|
|
||||||
serviceConfig.AmbientCapabilities = [
|
serviceConfig.AmbientCapabilities = [
|
||||||
# needs to be able to read files owned by any user
|
# needs to be able to read files owned by any user
|
||||||
"CAP_DAC_READ_SEARCH"
|
"CAP_DAC_READ_SEARCH"
|
||||||
];
|
];
|
||||||
|
serviceConfig.RestrictNetworkInterfaces = [
|
||||||
|
# strictly forbid sending traffic over any non ethernet/wifi interface,
|
||||||
|
# because i don't want this e.g. consuming all my cellular data.
|
||||||
|
# TODO: test this. i don't know that the moby kernel/systemd actually supports these options
|
||||||
|
"lo" # for DNS
|
||||||
|
"eth0"
|
||||||
|
"wlan0"
|
||||||
|
];
|
||||||
|
|
||||||
|
# hardening
|
||||||
serviceConfig.CapabilityBoundingSet = [ "CAP_DAC_READ_SEARCH" ];
|
serviceConfig.CapabilityBoundingSet = [ "CAP_DAC_READ_SEARCH" ];
|
||||||
serviceConfig.ReadWritePaths = builtins.map (d: "${d}/zzz-rsync-net") cfg.dirs;
|
serviceConfig.ReadWritePaths = builtins.map (d: "${d}/zzz-rsync-net") cfg.dirs;
|
||||||
serviceConfig.ReadOnlyPaths = "/nix/persist/private";
|
serviceConfig.ReadOnlyPaths = cfg.dirs;
|
||||||
serviceConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6 AF_NETLINK";
|
serviceConfig.RestrictAddressFamilies = "AF_INET AF_INET6";
|
||||||
|
|
||||||
serviceConfig.LockPersonality = true;
|
serviceConfig.LockPersonality = true;
|
||||||
serviceConfig.MemoryDenyWriteExecute = true;
|
serviceConfig.MemoryDenyWriteExecute = true;
|
||||||
|
serviceConfig.NoNewPrivileges = true;
|
||||||
|
serviceConfig.PrivateDevices = true;
|
||||||
serviceConfig.PrivateMounts = true;
|
serviceConfig.PrivateMounts = true;
|
||||||
serviceConfig.PrivateUsers = true;
|
serviceConfig.PrivateTmp = true;
|
||||||
serviceConfig.ProcSubset = "pid";
|
serviceConfig.ProcSubset = "pid";
|
||||||
serviceConfig.ProtectClock = "true";
|
serviceConfig.ProtectClock = true;
|
||||||
serviceConfig.ProtectControlGroups = true;
|
serviceConfig.ProtectControlGroups = true;
|
||||||
serviceConfig.ProtectHome = true;
|
serviceConfig.ProtectHome = true;
|
||||||
serviceConfig.ProtectHostname = true;
|
serviceConfig.ProtectHostname = true;
|
||||||
@@ -64,13 +75,23 @@ in
|
|||||||
serviceConfig.ProtectProc = "invisible";
|
serviceConfig.ProtectProc = "invisible";
|
||||||
serviceConfig.ProtectSystem = "strict";
|
serviceConfig.ProtectSystem = "strict";
|
||||||
serviceConfig.RemoveIPC = true;
|
serviceConfig.RemoveIPC = true;
|
||||||
|
serviceConfig.RestrictFileSystems = "@basic-api @common-block @temporary";
|
||||||
|
serviceConfig.RestrictNamespaces = true;
|
||||||
serviceConfig.RestrictSUIDSGID = true;
|
serviceConfig.RestrictSUIDSGID = true;
|
||||||
serviceConfig.SystemCallArchitectures = "native";
|
serviceConfig.SystemCallArchitectures = "native";
|
||||||
serviceConfig.SystemCallFilter = "@system-service @mount";
|
serviceConfig.SystemCallFilter = [
|
||||||
|
"@system-service"
|
||||||
|
"~@chown"
|
||||||
|
"~@cpu-emulation"
|
||||||
|
"~@keyring"
|
||||||
|
"~@setuid"
|
||||||
|
];
|
||||||
# hardening exceptions:
|
# hardening exceptions:
|
||||||
serviceConfig.NoNewPrivileges = false; #< bwrap'd dac_read_search
|
serviceConfig.PrivateUsers = false; #< CAP_DAC_READ_SEARCH in the root namespace means we can't do any user namespacing
|
||||||
serviceConfig.PrivateDevices = false; #< passt/pasta
|
# serviceConfig.NoNewPrivileges = false; #< bwrap'd dac_read_search
|
||||||
serviceConfig.RestrictNamespaces = false; #< bwrap
|
# serviceConfig.PrivateDevices = false; #< passt/pasta
|
||||||
|
# serviceConfig.RestrictNamespaces = false; #< bwrap
|
||||||
|
# serviceConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6 AF_NETLINK"; #< AF_NETLINK is for passt/pasta
|
||||||
};
|
};
|
||||||
systemd.timers.rsync-net = {
|
systemd.timers.rsync-net = {
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
@@ -26,9 +26,9 @@ for dir in "$@"; do
|
|||||||
echo "syncing '$dir' to '$remote_dir'"
|
echo "syncing '$dir' to '$remote_dir'"
|
||||||
echo "$now" > "$dir"/zzz-rsync-net/last-attempted
|
echo "$now" > "$dir"/zzz-rsync-net/last-attempted
|
||||||
# N.B.: manual flags instead of `-a -> -rlptgoD` because device files have a max path length which is too restricted
|
# N.B.: manual flags instead of `-a -> -rlptgoD` because device files have a max path length which is too restricted
|
||||||
# if SANEBOX_PREPEND="--sanebox-disable" \
|
# TODO: add `sane-vpn do unmetered --`, after fixing pasta/sane-vpn to preserve capabilities + not create a new user namespace unconditionally.
|
||||||
if SANEBOX_PREPEND="--sanebox-cap dac_read_search --sanebox-path $RN_ID" \
|
# until then, don't run over cellular!
|
||||||
sane-vpn do unmetered -- \
|
if SANEBOX_PREPEND="--sanebox-method landlock --sanebox-cap dac_read_search --sanebox-path $RN_ID" \
|
||||||
rsync --exclude="$RN_ID" -e "ssh -i $RN_ID" --mkpath -rlptgov --delete "$dir" "$remote_dir"; \
|
rsync --exclude="$RN_ID" -e "ssh -i $RN_ID" --mkpath -rlptgov --delete "$dir" "$remote_dir"; \
|
||||||
then
|
then
|
||||||
echo "$now" > "$dir"/zzz-rsync-net/last-completed
|
echo "$now" > "$dir"/zzz-rsync-net/last-completed
|
||||||
|
@@ -2,4 +2,7 @@
|
|||||||
# it works by using stock upstream `nixpkgs`
|
# it works by using stock upstream `nixpkgs`
|
||||||
# and putting NIX_PATH=nixpkgs-overlays=/path/to/here on the nixbld environment.
|
# and putting NIX_PATH=nixpkgs-overlays=/path/to/here on the nixbld environment.
|
||||||
#
|
#
|
||||||
[(import ../../overlays/all.nix)]
|
# XXX(2024-08-12): DON'T import `all.nix`, as that makes upstreaming cross patches more difficult (impurity)!
|
||||||
|
# i only really need to grant access to my additional packages, here.
|
||||||
|
# [(import ../../overlays/all.nix)]
|
||||||
|
[(import ../../overlays/pkgs.nix)]
|
||||||
|
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"description": "Oral arguments before the Supreme Court of the United States, from Oyez.org.",
|
||||||
|
"is_podcast": true,
|
||||||
|
"site_name": "User account | Oyez Backend",
|
||||||
|
"site_url": "https://api.oyez.org",
|
||||||
|
"title": "U.S. Supreme Court Oral Arguments",
|
||||||
|
"url": "https://api.oyez.org/podcasts/oral-arguments/2015",
|
||||||
|
"velocity": 0.123
|
||||||
|
}
|
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"description": "<p>Weird Little Guys is a weekly show about the worst people you\u2019ve never heard of, taking you beyond the headlines to get to know the race warriors and aspiring terrorists trying to unravel the fabric of our society. Weaving together the origin stories of modern American white supremacist groups and the crimes that land their members in court, independent journalist Molly Conger exposes the monsters for what they really are - some weird guy. Whether they\u2019re conspiring to build bombs or serving swastika shaped cookies at a dinner party, the weird little guys trying to destroy America are a little less scary with their masks off.\u00a0</p>",
|
||||||
|
"is_podcast": true,
|
||||||
|
"site_name": "",
|
||||||
|
"site_url": "",
|
||||||
|
"title": "Weird Little Guys",
|
||||||
|
"url": "https://www.omnycontent.com/d/playlist/e73c998e-6e60-432f-8610-ae210140c5b1/62ce32da-c3ea-45e9-a31c-b1b00134dbcd/9543cfef-9641-4bf0-9ce1-b1b001351bbe/podcast.rss",
|
||||||
|
"velocity": 0.259
|
||||||
|
}
|
@@ -11,7 +11,7 @@ let
|
|||||||
# - any character may be encoded by `\DDD`, where `DDD` represents its ascii value in base 8.
|
# - any character may be encoded by `\DDD`, where `DDD` represents its ascii value in base 8.
|
||||||
# - any non-digit `X` may be encoded by `\X`.
|
# - any non-digit `X` may be encoded by `\X`.
|
||||||
# - stated in: <https://www.ietf.org/rfc/rfc1035.txt>: 5.1 Format
|
# - stated in: <https://www.ietf.org/rfc/rfc1035.txt>: 5.1 Format
|
||||||
# - visible in <trust-dns:crates/proto/src/serialize/txt/zone_lex.rs:escape_seq>
|
# - visible in <hickory-dns:crates/proto/src/serialize/txt/zone_lex.rs:escape_seq>
|
||||||
# for us, we can just replace `\` => `\\ and `"` -> `\"`
|
# for us, we can just replace `\` => `\\ and `"` -> `\"`
|
||||||
TXT = value: "\"" + (lib.escape [ "\\" "\"" ] value) + "\"";
|
TXT = value: "\"" + (lib.escape [ "\\" "\"" ] value) + "\"";
|
||||||
};
|
};
|
||||||
|
@@ -234,6 +234,20 @@ let
|
|||||||
description = "name of the systemd unit which mounts this path";
|
description = "name of the systemd unit which mounts this path";
|
||||||
default = mountNameFor path;
|
default = mountNameFor path;
|
||||||
};
|
};
|
||||||
|
mountConfig = mkOption {
|
||||||
|
type = types.attrs;
|
||||||
|
description = ''
|
||||||
|
attrset to add to the [Mount] section of the systemd unit file.
|
||||||
|
'';
|
||||||
|
default = {};
|
||||||
|
};
|
||||||
|
unitConfig = mkOption {
|
||||||
|
type = types.attrs;
|
||||||
|
description = ''
|
||||||
|
attrset to add to the [Unit] section of the systemd unit file.
|
||||||
|
'';
|
||||||
|
default = {};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -268,9 +282,9 @@ let
|
|||||||
};
|
};
|
||||||
|
|
||||||
# given a mountEntry definition, evaluate its toplevel `config` output.
|
# given a mountEntry definition, evaluate its toplevel `config` output.
|
||||||
mkMountConfig = path: opt: (let
|
mkMountConfig = path: opt: let
|
||||||
device = config.fileSystems."${path}".device;
|
fsEntry = config.fileSystems."${path}";
|
||||||
underlying = cfg."${device}";
|
underlying = cfg."${fsEntry.device}";
|
||||||
isBind = opt.mount.bind != null;
|
isBind = opt.mount.bind != null;
|
||||||
ifBind = lib.mkIf isBind;
|
ifBind = lib.mkIf isBind;
|
||||||
# before mounting:
|
# before mounting:
|
||||||
@@ -278,12 +292,12 @@ let
|
|||||||
# - prepare the source directory -- assuming it's not an external device
|
# - prepare the source directory -- assuming it's not an external device
|
||||||
# - satisfy any user-specified prerequisites ("depends")
|
# - satisfy any user-specified prerequisites ("depends")
|
||||||
requires = [ opt.generated.unit ]
|
requires = [ opt.generated.unit ]
|
||||||
++ (if lib.hasPrefix "/dev/disk/" device then [] else [ underlying.unit ])
|
++ (if lib.hasPrefix "/dev/disk/" fsEntry.device || lib.hasPrefix "fuse" (fsEntry.fsType or "unknown") then [] else [ underlying.unit ])
|
||||||
++ opt.mount.depends;
|
++ opt.mount.depends;
|
||||||
in {
|
in {
|
||||||
fileSystems."${path}" = {
|
fileSystems."${path}" = {
|
||||||
device = ifBind opt.mount.bind;
|
device = ifBind opt.mount.bind;
|
||||||
options = (if isBind then ["bind"] else [])
|
options = (lib.optionals isBind [ "bind" ])
|
||||||
++ [
|
++ [
|
||||||
# disable defaults: don't require this to be mount as part of local-fs.target
|
# disable defaults: don't require this to be mount as part of local-fs.target
|
||||||
# we'll handle that stuff precisely.
|
# we'll handle that stuff precisely.
|
||||||
@@ -298,13 +312,24 @@ let
|
|||||||
++ (builtins.map (unit: "x-systemd.wanted-by=${unit}") (opt.wantedBy ++ opt.wantedBeforeBy));
|
++ (builtins.map (unit: "x-systemd.wanted-by=${unit}") (opt.wantedBy ++ opt.wantedBeforeBy));
|
||||||
noCheck = ifBind true;
|
noCheck = ifBind true;
|
||||||
};
|
};
|
||||||
});
|
systemd.mounts = [{
|
||||||
|
where = path;
|
||||||
|
what = if fsEntry.device != null then fsEntry.device else "";
|
||||||
|
type = fsEntry.fsType;
|
||||||
|
options = lib.concatStringsSep "," fsEntry.options;
|
||||||
|
after = requires;
|
||||||
|
requires = requires;
|
||||||
|
before = opt.wantedBeforeBy;
|
||||||
|
wantedBy = opt.wantedBeforeBy;
|
||||||
|
inherit (opt.mount) mountConfig unitConfig;
|
||||||
|
}];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
mkFsConfig = path: opt: lib.mkMerge [
|
mkFsConfig = path: opt: lib.mkMerge (
|
||||||
(mkGeneratedConfig path opt)
|
[ (mkGeneratedConfig path opt) ] ++
|
||||||
(lib.mkIf (opt.mount != null) (mkMountConfig path opt))
|
lib.optional (opt.mount != null) (mkMountConfig path opt)
|
||||||
];
|
);
|
||||||
|
|
||||||
# return all ancestors of this path.
|
# return all ancestors of this path.
|
||||||
# e.g. ancestorsOf "/foo/bar/baz" => [ "/" "/foo" "/foo/bar" ]
|
# e.g. ancestorsOf "/foo/bar/baz" => [ "/" "/foo" "/foo/bar" ]
|
||||||
@@ -358,6 +383,7 @@ in {
|
|||||||
let
|
let
|
||||||
configs = lib.mapAttrsToList mkFsConfig cfg;
|
configs = lib.mapAttrsToList mkFsConfig cfg;
|
||||||
take = f: {
|
take = f: {
|
||||||
|
systemd.mounts = f.systemd.mounts;
|
||||||
systemd.services = f.systemd.services;
|
systemd.services = f.systemd.services;
|
||||||
fileSystems = f.fileSystems;
|
fileSystems = f.fileSystems;
|
||||||
};
|
};
|
||||||
|
@@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
./ephemeral.nix
|
./ephemeral
|
||||||
./initrd.nix
|
./initrd.nix
|
||||||
./plaintext.nix
|
./plaintext.nix
|
||||||
./private.nix
|
./private
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@@ -1,96 +0,0 @@
|
|||||||
{ config, lib, pkgs, sane-lib, utils, ... }:
|
|
||||||
|
|
||||||
let
|
|
||||||
persist-base = "/nix/persist";
|
|
||||||
origin = config.sane.persist.stores."ephemeral".origin;
|
|
||||||
backing = sane-lib.path.concat [ persist-base "ephemeral" ];
|
|
||||||
|
|
||||||
gocryptfs-ephemeral = pkgs.writeShellApplication {
|
|
||||||
name = "mount.fuse.gocryptfs-ephemeral";
|
|
||||||
runtimeInputs = with pkgs; [
|
|
||||||
coreutils-full
|
|
||||||
gocryptfs
|
|
||||||
];
|
|
||||||
text = ''
|
|
||||||
# mount invokes us like this. not sure if that's a guarantee or not:
|
|
||||||
# <exe> <device> <mountpt> -o <flags>
|
|
||||||
backing=$1
|
|
||||||
# facing=$2
|
|
||||||
|
|
||||||
# backing might exist from the last boot, so wipe it:
|
|
||||||
rm -fr "$backing"
|
|
||||||
mkdir -p "$backing"
|
|
||||||
|
|
||||||
# the password shows up in /proc/.../env, briefly.
|
|
||||||
# that's inconsequential: we just care that it's not *persisted*.
|
|
||||||
pw=$(dd if=/dev/random bs=128 count=1 | base64 --wrap=0)
|
|
||||||
echo "$pw" | gocryptfs -quiet -passfile /dev/stdin -init "$backing"
|
|
||||||
echo "$pw" | gocryptfs -quiet -passfile /dev/stdin "$@"
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
in
|
|
||||||
lib.mkIf config.sane.persist.enable
|
|
||||||
{
|
|
||||||
sane.persist.stores."ephemeral" = {
|
|
||||||
storeDescription = ''
|
|
||||||
stored to disk, but encrypted to an in-memory key and cleared on every boot
|
|
||||||
so that it's unreadable after power-off
|
|
||||||
'';
|
|
||||||
origin = lib.mkDefault "/mnt/persist/ephemeral";
|
|
||||||
};
|
|
||||||
|
|
||||||
fileSystems."${origin}" = {
|
|
||||||
device = backing;
|
|
||||||
fsType = "fuse.gocryptfs-ephemeral";
|
|
||||||
options = [
|
|
||||||
# "nodev" # "Unknown parameter 'nodev'". gocryptfs requires this be passed as `-ko nodev`
|
|
||||||
# "nosuid" # "Unknown parameter 'nosuid'". gocryptfs requires this be passed as `-ko nosuid` (also, nosuid is default)
|
|
||||||
"allow_other" # root ends up being the user that mounts this, so need to make it visible to other users.
|
|
||||||
# "defaults" # "unknown flag: --defaults. Try 'gocryptfs -help'"
|
|
||||||
];
|
|
||||||
noCheck = true;
|
|
||||||
};
|
|
||||||
# let sane.fs know about our fileSystem and automatically add the appropriate dependencies
|
|
||||||
sane.fs."${origin}".mount = { };
|
|
||||||
sane.fs."${backing}" = sane-lib.fs.wantedDir;
|
|
||||||
|
|
||||||
systemd.mounts = let
|
|
||||||
fsEntry = config.fileSystems."${origin}";
|
|
||||||
in [{
|
|
||||||
#VVV repeat what systemd would ordinarily scrape from /etc/fstab
|
|
||||||
where = origin;
|
|
||||||
what = fsEntry.device;
|
|
||||||
type = fsEntry.fsType;
|
|
||||||
options = lib.concatStringsSep "," fsEntry.options;
|
|
||||||
|
|
||||||
# sandbox options
|
|
||||||
mountConfig.AmbientCapabilities = "";
|
|
||||||
# CAP_LEASE is probably not necessary -- does any fs user use leases?
|
|
||||||
mountConfig.CapabilityBoundingSet = "CAP_SYS_ADMIN CAP_DAC_OVERRIDE CAP_DAC_READ_SEARCH CAP_CHOWN CAP_MKNOD CAP_LEASE CAP_SETGID CAP_SETUID CAP_FOWNER";
|
|
||||||
mountConfig.LockPersonality = true;
|
|
||||||
mountConfig.MemoryDenyWriteExecute = true;
|
|
||||||
mountConfig.NoNewPrivileges = true;
|
|
||||||
mountConfig.ProtectClock = true;
|
|
||||||
mountConfig.ProtectHostname = true;
|
|
||||||
mountConfig.RemoveIPC = true;
|
|
||||||
mountConfig.RestrictAddressFamilies = "AF_UNIX"; # "none" works, but then it can't connect to the logger
|
|
||||||
#VVV this includes anything it reads from, e.g. /bin/sh; /nix/store/...
|
|
||||||
# see `systemd-analyze filesystems` for a full list
|
|
||||||
mountConfig.RestrictFileSystems = "@common-block devtmpfs fuse pipefs";
|
|
||||||
mountConfig.RestrictNamespaces = true;
|
|
||||||
mountConfig.RestrictNetworkInterfaces = "";
|
|
||||||
mountConfig.RestrictRealtime = true;
|
|
||||||
mountConfig.RestrictSUIDSGID = true;
|
|
||||||
mountConfig.SystemCallArchitectures = "native";
|
|
||||||
mountConfig.SystemCallFilter = [
|
|
||||||
# unfortunately, i need to keep @network-io (accept, bind, connect, listen, recv, send, socket, ...). not sure why (daemon control socket?).
|
|
||||||
# TODO: @module?
|
|
||||||
"@system-service" "@mount" "~@cpu-emulation" "~@keyring"
|
|
||||||
];
|
|
||||||
# note that anything which requires mount namespaces (ProtectHome, ReadWritePaths, ...) does NOT work.
|
|
||||||
# it's in theory possible, via mount propagation, but systemd provides no way for that.
|
|
||||||
# PrivateNetwork = true BREAKS the mount action; i think systemd or udev needs that internally to communicate with the service manager?
|
|
||||||
}];
|
|
||||||
|
|
||||||
system.fsPackages = [ gocryptfs-ephemeral ]; # fuse needs to find gocryptfs
|
|
||||||
}
|
|
97
modules/persist/stores/ephemeral/default.nix
Normal file
97
modules/persist/stores/ephemeral/default.nix
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
{ config, lib, pkgs, sane-lib, utils, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
persist-base = "/nix/persist";
|
||||||
|
origin = config.sane.persist.stores."ephemeral".origin;
|
||||||
|
backing = sane-lib.path.concat [ persist-base "ephemeral" ];
|
||||||
|
in
|
||||||
|
lib.mkIf config.sane.persist.enable
|
||||||
|
{
|
||||||
|
|
||||||
|
sane.programs.gocryptfs-ephemeral = {
|
||||||
|
packageUnwrapped = pkgs.static-nix-shell.mkBash {
|
||||||
|
pname = "gocryptfs-ephemeral";
|
||||||
|
srcRoot = ./.;
|
||||||
|
pkgs = [
|
||||||
|
"coreutils-full"
|
||||||
|
"gocryptfs"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
sandbox.method = "landlock";
|
||||||
|
sandbox.autodetectCliPaths = "existing";
|
||||||
|
sandbox.capabilities = [
|
||||||
|
# "sys_admin" #< omitted: not required if using fuse3-sane with -o pass_fuse_fd
|
||||||
|
"chown"
|
||||||
|
"dac_override"
|
||||||
|
"dac_read_search"
|
||||||
|
"fowner"
|
||||||
|
"lease"
|
||||||
|
"mknod"
|
||||||
|
"setgid"
|
||||||
|
"setuid"
|
||||||
|
];
|
||||||
|
suggestedPrograms = [ "gocryptfs" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
sane.persist.stores."ephemeral" = {
|
||||||
|
storeDescription = ''
|
||||||
|
stored to disk, but encrypted to an in-memory key and cleared on every boot
|
||||||
|
so that it's unreadable after power-off
|
||||||
|
'';
|
||||||
|
origin = lib.mkDefault "/mnt/persist/ephemeral";
|
||||||
|
};
|
||||||
|
|
||||||
|
fileSystems."${origin}" = {
|
||||||
|
device = "gocryptfs-ephemeral#${backing}";
|
||||||
|
fsType = "fuse3.sane";
|
||||||
|
options = [
|
||||||
|
"nodev" # only works via mount.fuse; gocryptfs requires this be passed as `-ko nodev`
|
||||||
|
"nosuid" # only works via mount.fuse; gocryptfs requires this be passed as `-ko nosuid` (also, nosuid is default)
|
||||||
|
"allow_other" # root ends up being the user that mounts this, so need to make it visible to other users.
|
||||||
|
# "defaults" # "unknown flag: --defaults. Try 'gocryptfs -help'"
|
||||||
|
"pass_fuse_fd"
|
||||||
|
];
|
||||||
|
noCheck = true;
|
||||||
|
};
|
||||||
|
# let sane.fs know about our fileSystem and automatically add the appropriate dependencies
|
||||||
|
sane.fs."${origin}" = {
|
||||||
|
wantedBeforeBy = [ "local-fs.target" ];
|
||||||
|
mount.depends = [
|
||||||
|
config.sane.fs."${backing}".unit
|
||||||
|
];
|
||||||
|
# hardening (systemd-analyze security mnt-persist-ephemeral.mount)
|
||||||
|
mount.mountConfig.AmbientCapabilities = "CAP_SYS_ADMIN CAP_DAC_OVERRIDE CAP_DAC_READ_SEARCH CAP_CHOWN CAP_MKNOD CAP_LEASE CAP_SETGID CAP_SETUID CAP_FOWNER";
|
||||||
|
# CAP_LEASE is probably not necessary -- does any fs user use leases?
|
||||||
|
mount.mountConfig.CapabilityBoundingSet = "CAP_SYS_ADMIN CAP_DAC_OVERRIDE CAP_DAC_READ_SEARCH CAP_CHOWN CAP_MKNOD CAP_LEASE CAP_SETGID CAP_SETUID CAP_FOWNER";
|
||||||
|
mount.mountConfig.LockPersonality = true;
|
||||||
|
mount.mountConfig.MemoryDenyWriteExecute = true;
|
||||||
|
mount.mountConfig.NoNewPrivileges = true;
|
||||||
|
mount.mountConfig.ProtectClock = true;
|
||||||
|
mount.mountConfig.ProtectHostname = true;
|
||||||
|
mount.mountConfig.RemoveIPC = true;
|
||||||
|
mount.mountConfig.RestrictAddressFamilies = "AF_UNIX"; # "none" works, but then it can't connect to the logger
|
||||||
|
#VVV this includes anything it reads from, e.g. /bin/sh; /nix/store/...
|
||||||
|
# see `systemd-analyze filesystems` for a full list
|
||||||
|
mount.mountConfig.RestrictFileSystems = "@common-block @basic-api fuse pipefs";
|
||||||
|
mount.mountConfig.RestrictNamespaces = true;
|
||||||
|
mount.mountConfig.RestrictNetworkInterfaces = "";
|
||||||
|
mount.mountConfig.RestrictRealtime = true;
|
||||||
|
mount.mountConfig.RestrictSUIDSGID = true;
|
||||||
|
mount.mountConfig.SystemCallArchitectures = "native";
|
||||||
|
mount.mountConfig.SystemCallFilter = [
|
||||||
|
# unfortunately, i need to keep @network-io (accept, bind, connect, listen, recv, send, socket, ...). not sure why (daemon control socket?).
|
||||||
|
"@system-service" "@mount" "@sandbox" "~@cpu-emulation" "~@keyring"
|
||||||
|
];
|
||||||
|
mount.mountConfig.IPAddressDeny = "any";
|
||||||
|
mount.mountConfig.DevicePolicy = "closed"; # only allow /dev/{null,zero,full,random,urandom}
|
||||||
|
mount.mountConfig.DeviceAllow = "/dev/fuse";
|
||||||
|
mount.mountConfig.SocketBindDeny = "any";
|
||||||
|
# note that anything which requires mount namespaces (ProtectHome, ReadWritePaths, ...) does NOT work.
|
||||||
|
# it's in theory possible, via mount propagation, but systemd provides no way for that.
|
||||||
|
# PrivateNetwork = true BREAKS the mount action; i think systemd or udev needs that internally to communicate with the service manager?
|
||||||
|
};
|
||||||
|
sane.fs."${backing}".dir = {};
|
||||||
|
|
||||||
|
sane.programs.gocryptfs-ephemeral.enableFor.system = true;
|
||||||
|
system.fsPackages = [ pkgs.libfuse-sane ];
|
||||||
|
}
|
17
modules/persist/stores/ephemeral/gocryptfs-ephemeral
Executable file
17
modules/persist/stores/ephemeral/gocryptfs-ephemeral
Executable file
@@ -0,0 +1,17 @@
|
|||||||
|
#!/usr/bin/env nix-shell
|
||||||
|
#!nix-shell -i bash -p bash -p coreutils-full -p gocryptfs
|
||||||
|
|
||||||
|
# mount invokes us like this. not sure if that's a guarantee or not:
|
||||||
|
# <exe> <device> <mountpt> -o <flags>
|
||||||
|
backing=$1
|
||||||
|
# facing=$2
|
||||||
|
|
||||||
|
# backing might exist from the last boot, so wipe it:
|
||||||
|
rm -fr "$backing"
|
||||||
|
mkdir -p "$backing"
|
||||||
|
|
||||||
|
# the password shows up in /proc/.../env, briefly.
|
||||||
|
# that's inconsequential: we just care that it's not *persisted*.
|
||||||
|
pw=$(dd if=/dev/random bs=128 count=1 | base64 --wrap=0)
|
||||||
|
echo "$pw" | gocryptfs -quiet -passfile /dev/fd/0 -init "$backing"
|
||||||
|
echo "$pw" | exec gocryptfs -quiet -passfile /dev/fd/0 "$@"
|
@@ -1,143 +0,0 @@
|
|||||||
{ config, lib, pkgs, sane-lib, utils, ... }:
|
|
||||||
|
|
||||||
let
|
|
||||||
# TODO: parameterize!
|
|
||||||
persist-base = "/nix/persist";
|
|
||||||
origin = config.sane.persist.stores."private".origin;
|
|
||||||
backing = sane-lib.path.concat [ persist-base "private" ];
|
|
||||||
|
|
||||||
gocryptfs-private = pkgs.writeShellApplication {
|
|
||||||
name = "mount.fuse.gocryptfs-private";
|
|
||||||
runtimeInputs = with pkgs; [
|
|
||||||
coreutils-full
|
|
||||||
gocryptfs
|
|
||||||
inotify-tools
|
|
||||||
];
|
|
||||||
text = ''
|
|
||||||
# backing=$1
|
|
||||||
# facing=$2
|
|
||||||
mountArgs=("$@")
|
|
||||||
passdir=/run/gocryptfs
|
|
||||||
passfile="$passdir/private.key"
|
|
||||||
|
|
||||||
waitForPassfileOnce() {
|
|
||||||
local timeout=$1
|
|
||||||
if [ -f "$passfile" ]; then
|
|
||||||
return 0
|
|
||||||
else
|
|
||||||
# wait for some file to be created inside the directory.
|
|
||||||
# inotifywait returns 0 if the file was created. 1 or 2 if timeout was hit or it was interrupted by a different event.
|
|
||||||
inotifywait --timeout "$timeout" --event create "$passdir"
|
|
||||||
return 1 #< maybe it was created; we'll pick that up immediately, on next check
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
waitForPassfile() {
|
|
||||||
# there's a race condition between testing the path and starting `inotifywait`.
|
|
||||||
# therefore, use a retry loop. exponential backoff to decrease the impact of the race condition,
|
|
||||||
# especially near the start of boot to allow for quick reboots even if/when i hit the race.
|
|
||||||
for timeout in 4 4 8 8 8 8 16 16 16 16 16 16 16 16; do
|
|
||||||
if waitForPassfileOnce "$timeout"; then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
while true; do
|
|
||||||
if waitForPassfileOnce 30; then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
}
|
|
||||||
tryOpenStore() {
|
|
||||||
# try to open the store (blocking), if it fails, then delete the passfile because the user probably entered the wrong password
|
|
||||||
echo "mounting with ''${mountArgs[*]}"
|
|
||||||
# gocryptfs will unlock the store, and *then* fork into the background.
|
|
||||||
# so when it returns, the files are either immediately accessible, or the mount failed (likely due to a bad password
|
|
||||||
if ! gocryptfs "''${mountArgs[@]}"; then
|
|
||||||
echo "failed mount (transient failure)"
|
|
||||||
rm -f "$passfile"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
waitForPassfile
|
|
||||||
while ! tryOpenStore; do
|
|
||||||
waitForPassfile
|
|
||||||
done
|
|
||||||
echo "mounted"
|
|
||||||
# mount is complete (successful), and backgrounded.
|
|
||||||
# remove the passfile even on successful mount, for vague safety reasons (particularly if the user were to explicitly unmount the private store).
|
|
||||||
rm -f "$passfile"
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
in
|
|
||||||
lib.mkIf config.sane.persist.enable
|
|
||||||
{
|
|
||||||
sane.persist.stores."private" = {
|
|
||||||
storeDescription = ''
|
|
||||||
encrypted store which persists across boots.
|
|
||||||
typical use case is for the user to encrypt this store using their login password so that it
|
|
||||||
can be auto-unlocked at login.
|
|
||||||
'';
|
|
||||||
origin = lib.mkDefault "/mnt/persist/private";
|
|
||||||
defaultOrdering = let
|
|
||||||
private-unit = config.sane.fs."${origin}".unit;
|
|
||||||
in {
|
|
||||||
# auto create only after the store is mounted
|
|
||||||
wantedBy = [ private-unit ];
|
|
||||||
# we can't create things in private before local-fs.target
|
|
||||||
wantedBeforeBy = [ ];
|
|
||||||
};
|
|
||||||
defaultMethod = "symlink";
|
|
||||||
};
|
|
||||||
|
|
||||||
fileSystems."${origin}" = {
|
|
||||||
device = backing;
|
|
||||||
fsType = "fuse.gocryptfs-private";
|
|
||||||
options = [
|
|
||||||
"auto"
|
|
||||||
"nofail"
|
|
||||||
# "nodev" # "Unknown parameter 'nodev'". gocryptfs requires this be passed as `-ko nodev`
|
|
||||||
# "noexec" # handful of scripts in ~/knowledge that are executable
|
|
||||||
# "nosuid" # "Unknown parameter 'nosuid'". gocryptfs requires this be passed as `-ko nosuid` (also nosuid is default)
|
|
||||||
"allow_other" # root ends up being the user that mounts this, so need to make it visible to other users.
|
|
||||||
# "quiet"
|
|
||||||
# "defaults" # "unknown flag: --defaults. Try 'gocryptfs -help'"
|
|
||||||
"passfile=/run/gocryptfs/private.key"
|
|
||||||
# options so that we can block for the password file *without* systemd killing us.
|
|
||||||
# see: <https://bbs.archlinux.org/viewtopic.php?pid=1906174#p1906174>
|
|
||||||
"x-systemd.mount-timeout=infinity"
|
|
||||||
# "retry=10000"
|
|
||||||
# "fg"
|
|
||||||
];
|
|
||||||
noCheck = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
# let sane.fs know about the mount
|
|
||||||
sane.fs."${origin}".mount = {};
|
|
||||||
# it also needs to know that the underlying device is an ordinary folder
|
|
||||||
sane.fs."${backing}" = sane-lib.fs.wanted {
|
|
||||||
dir.acl.user = config.sane.defaultUser;
|
|
||||||
};
|
|
||||||
|
|
||||||
sane.fs."/run/gocryptfs" = sane-lib.fs.wanted {
|
|
||||||
dir.acl.user = config.sane.defaultUser;
|
|
||||||
dir.acl.mode = "0700";
|
|
||||||
};
|
|
||||||
|
|
||||||
# in order for non-systemd `mount` to work, the mount point has to already be created, so make that a default target
|
|
||||||
systemd.units = let
|
|
||||||
originUnit = config.sane.fs."${origin}".generated.unit;
|
|
||||||
in {
|
|
||||||
"${originUnit}".wantedBy = [ "local-fs.target" ];
|
|
||||||
};
|
|
||||||
|
|
||||||
system.fsPackages = [ gocryptfs-private ];
|
|
||||||
|
|
||||||
sane.user.services.gocryptfs-private = {
|
|
||||||
description = "wait for /mnt/persist/private to be mounted";
|
|
||||||
startCommand = "${lib.getExe' pkgs.systemd "systemctl"} start mnt-persist-private.mount";
|
|
||||||
# command = "sleep infinity";
|
|
||||||
# readiness.waitExists = [ "/mnt/persist/private/init" ];
|
|
||||||
partOf = [ "private-storage" ];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
149
modules/persist/stores/private/default.nix
Normal file
149
modules/persist/stores/private/default.nix
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
{ config, lib, pkgs, sane-lib, utils, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
persist-base = "/nix/persist";
|
||||||
|
origin = config.sane.persist.stores."private".origin;
|
||||||
|
backing = sane-lib.path.concat [ persist-base "private" ];
|
||||||
|
in
|
||||||
|
lib.mkIf config.sane.persist.enable
|
||||||
|
{
|
||||||
|
sane.programs."provision-private-key" = {
|
||||||
|
packageUnwrapped = pkgs.static-nix-shell.mkBash {
|
||||||
|
pname = "provision-private-key";
|
||||||
|
srcRoot = ./.;
|
||||||
|
pkgs = [
|
||||||
|
"coreutils-full"
|
||||||
|
"gocryptfs"
|
||||||
|
"inotify-tools"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
sandbox.method = "bwrap";
|
||||||
|
sandbox.autodetectCliPaths = "parent";
|
||||||
|
};
|
||||||
|
sane.programs.gocryptfs-private = {
|
||||||
|
packageUnwrapped = pkgs.static-nix-shell.mkBash {
|
||||||
|
pname = "gocryptfs-private";
|
||||||
|
srcRoot = ./.;
|
||||||
|
pkgs = [ "gocryptfs" ];
|
||||||
|
};
|
||||||
|
sandbox.method = "landlock";
|
||||||
|
sandbox.autodetectCliPaths = "existing";
|
||||||
|
sandbox.capabilities = [
|
||||||
|
# "sys_admin" #< omitted: not required if using fuse3-sane with -o pass_fuse_fd
|
||||||
|
"chown"
|
||||||
|
"dac_override"
|
||||||
|
"dac_read_search"
|
||||||
|
"fowner"
|
||||||
|
"lease"
|
||||||
|
"mknod"
|
||||||
|
"setgid"
|
||||||
|
"setuid"
|
||||||
|
];
|
||||||
|
sandbox.extraPaths = [
|
||||||
|
"/run/gocryptfs" #< TODO: teach sanebox about `-o FLAG1=VALUE1,FLAG2=VALUE2` style of argument passing, then use `existingOrParent` autodetect, and remove this
|
||||||
|
];
|
||||||
|
suggestedPrograms = [ "gocryptfs" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
sane.persist.stores."private" = {
|
||||||
|
storeDescription = ''
|
||||||
|
encrypted store which persists across boots.
|
||||||
|
typical use case is for the user to encrypt this store using their login password so that it
|
||||||
|
can be auto-unlocked at login.
|
||||||
|
'';
|
||||||
|
origin = lib.mkDefault "/mnt/persist/private";
|
||||||
|
defaultOrdering = let
|
||||||
|
private-unit = config.sane.fs."${origin}".unit;
|
||||||
|
in {
|
||||||
|
# auto create only after the store is mounted
|
||||||
|
wantedBy = [ private-unit ];
|
||||||
|
# we can't create things in private before local-fs.target
|
||||||
|
wantedBeforeBy = [ ];
|
||||||
|
};
|
||||||
|
defaultMethod = "symlink";
|
||||||
|
};
|
||||||
|
|
||||||
|
fileSystems."${origin}" = {
|
||||||
|
device = "gocryptfs-private#${backing}";
|
||||||
|
fsType = "fuse3.sane";
|
||||||
|
options = [
|
||||||
|
# "auto"
|
||||||
|
"nofail"
|
||||||
|
# "noexec" # handful of scripts in ~/knowledge that are executable
|
||||||
|
"nodev" # only works via mount.fuse; gocryptfs requires this be passed as `-ko nodev`
|
||||||
|
"nosuid" # only works via mount.fuse; gocryptfs requires this be passed as `-ko nosuid` (also, nosuid is default)
|
||||||
|
"allow_other" # root ends up being the user that mounts this, so need to make it visible to other users.
|
||||||
|
# "quiet"
|
||||||
|
# "defaults" # "unknown flag: --defaults. Try 'gocryptfs -help'"
|
||||||
|
"passfile=/run/gocryptfs/private.key"
|
||||||
|
# options so that we can block for the password file *without* systemd killing us.
|
||||||
|
# see: <https://bbs.archlinux.org/viewtopic.php?pid=1906174#p1906174>
|
||||||
|
"x-systemd.mount-timeout=infinity"
|
||||||
|
# "retry=10000"
|
||||||
|
# "fg"
|
||||||
|
"pass_fuse_fd"
|
||||||
|
];
|
||||||
|
noCheck = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
# let sane.fs know about the mount
|
||||||
|
sane.fs."${origin}" = {
|
||||||
|
wantedBy = [ "local-fs.target" ];
|
||||||
|
mount.depends = [
|
||||||
|
config.sane.fs."${backing}".unit
|
||||||
|
config.sane.fs."/run/gocryptfs/private.key".unit
|
||||||
|
];
|
||||||
|
# unitConfig.DefaultDependencies = "no";
|
||||||
|
mount.mountConfig.TimeoutSec = "infinity";
|
||||||
|
|
||||||
|
# hardening (systemd-analyze security mnt-persist-private.mount)
|
||||||
|
mount.mountConfig.AmbientCapabilities = "CAP_SYS_ADMIN CAP_DAC_OVERRIDE CAP_DAC_READ_SEARCH CAP_CHOWN CAP_MKNOD CAP_LEASE CAP_SETGID CAP_SETUID CAP_FOWNER";
|
||||||
|
# CAP_LEASE is probably not necessary -- does any fs user use leases?
|
||||||
|
mount.mountConfig.CapabilityBoundingSet = "CAP_SYS_ADMIN CAP_DAC_OVERRIDE CAP_DAC_READ_SEARCH CAP_CHOWN CAP_MKNOD CAP_LEASE CAP_SETGID CAP_SETUID CAP_FOWNER";
|
||||||
|
mount.mountConfig.LockPersonality = true;
|
||||||
|
mount.mountConfig.MemoryDenyWriteExecute = true;
|
||||||
|
mount.mountConfig.NoNewPrivileges = true;
|
||||||
|
mount.mountConfig.ProtectClock = true;
|
||||||
|
mount.mountConfig.ProtectHostname = true;
|
||||||
|
mount.mountConfig.RemoveIPC = true;
|
||||||
|
mount.mountConfig.RestrictAddressFamilies = "AF_UNIX"; # "none" works, but then it can't connect to the logger
|
||||||
|
mount.mountConfig.RestrictFileSystems = "@common-block @basic-api fuse pipefs";
|
||||||
|
mount.mountConfig.RestrictNamespaces = true;
|
||||||
|
mount.mountConfig.RestrictNetworkInterfaces = "";
|
||||||
|
mount.mountConfig.RestrictRealtime = true;
|
||||||
|
mount.mountConfig.RestrictSUIDSGID = true;
|
||||||
|
mount.mountConfig.SystemCallArchitectures = "native";
|
||||||
|
mount.mountConfig.SystemCallFilter = [
|
||||||
|
# unfortunately, i need to keep @network-io (accept, bind, connect, listen, recv, send, socket, ...). not sure why (daemon control socket?).
|
||||||
|
"@system-service" "@mount" "@sandbox" "~@cpu-emulation" "~@keyring"
|
||||||
|
];
|
||||||
|
mount.mountConfig.IPAddressDeny = "any";
|
||||||
|
mount.mountConfig.DevicePolicy = "closed"; # only allow /dev/{null,zero,full,random,urandom}
|
||||||
|
mount.mountConfig.DeviceAllow = "/dev/fuse";
|
||||||
|
mount.mountConfig.SocketBindDeny = "any";
|
||||||
|
};
|
||||||
|
# it also needs to know that the underlying device is an ordinary folder
|
||||||
|
sane.fs."${backing}".dir = {};
|
||||||
|
sane.fs."/run/gocryptfs".dir.acl = {
|
||||||
|
user = config.sane.defaultUser; #< must be user-writable so i can unlock it.
|
||||||
|
mode = "0770";
|
||||||
|
};
|
||||||
|
sane.fs."/run/gocryptfs/private.key".generated.command = [
|
||||||
|
"${lib.getExe config.sane.programs.provision-private-key.package}"
|
||||||
|
"/run/gocryptfs/private.key"
|
||||||
|
"${backing}/gocryptfs.conf"
|
||||||
|
];
|
||||||
|
|
||||||
|
sane.programs."gocryptfs-private".enableFor.system = true;
|
||||||
|
sane.programs."provision-private-key".enableFor.system = true;
|
||||||
|
system.fsPackages = [ pkgs.libfuse-sane ];
|
||||||
|
|
||||||
|
sane.user.services.gocryptfs-private = {
|
||||||
|
description = "wait for /mnt/persist/private to be mounted";
|
||||||
|
startCommand = "${lib.getExe' pkgs.systemd "systemctl"} start mnt-persist-private.mount";
|
||||||
|
# command = "sleep infinity";
|
||||||
|
# readiness.waitExists = [ "/mnt/persist/private/init" ];
|
||||||
|
partOf = [ "private-storage" ];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
6
modules/persist/stores/private/gocryptfs-private
Executable file
6
modules/persist/stores/private/gocryptfs-private
Executable file
@@ -0,0 +1,6 @@
|
|||||||
|
#!/usr/bin/env nix-shell
|
||||||
|
#!nix-shell -i bash -p bash -p gocryptfs
|
||||||
|
|
||||||
|
passfile=/run/gocryptfs/private.key
|
||||||
|
gocryptfs --sanebox-path "$passfile" "$@"
|
||||||
|
rm "$passfile"
|
46
modules/persist/stores/private/provision-private-key
Executable file
46
modules/persist/stores/private/provision-private-key
Executable file
@@ -0,0 +1,46 @@
|
|||||||
|
#!/usr/bin/env nix-shell
|
||||||
|
#!nix-shell -i bash -p bash -p coreutils-full -p gocryptfs -p inotify-tools
|
||||||
|
|
||||||
|
passfile="$1" # e.g. /run/gocryptfs/private.key
|
||||||
|
conffile="$2" # e.g. /nix/persist/private/gocryptfs.conf
|
||||||
|
passdir=$(dirname "$passfile")
|
||||||
|
|
||||||
|
waitForPassfileOnce() {
|
||||||
|
local timeout=$1
|
||||||
|
if [ -f "$passfile" ]; then
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
# wait for some file to be created inside the directory.
|
||||||
|
# inotifywait returns 0 if the file was created. 1 or 2 if timeout was hit or it was interrupted by a different event.
|
||||||
|
inotifywait --timeout "$timeout" --event create "$passdir"
|
||||||
|
return 1 #< maybe it was created; we'll pick that up immediately, on next check
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
waitForPassfile() {
|
||||||
|
# there's a race condition between testing the path and starting `inotifywait`.
|
||||||
|
# therefore, use a retry loop. exponential backoff to decrease the impact of the race condition,
|
||||||
|
# especially near the start of boot to allow for quick reboots even if/when i hit the race.
|
||||||
|
for timeout in 4 4 8 8 8 8 16 16 16 16 16 16 16 16; do
|
||||||
|
if waitForPassfileOnce "$timeout"; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
while true; do
|
||||||
|
if waitForPassfileOnce 30; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
validatePassword() {
|
||||||
|
if ! cat "$passfile" | gocryptfs-xray -dumpmasterkey "$conffile" > /dev/null; then
|
||||||
|
echo "failed key validation"
|
||||||
|
rm -f "$passfile"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
waitForPassfile
|
||||||
|
while ! validatePassword; do
|
||||||
|
waitForPassfile
|
||||||
|
done
|
||||||
|
echo "key provisioned"
|
@@ -347,6 +347,13 @@ let
|
|||||||
whether to place the process in a new PID namespace, if the sandboxer supports that.
|
whether to place the process in a new PID namespace, if the sandboxer supports that.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
sandbox.isolateUsers = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description = ''
|
||||||
|
whether to place the process in a new user namespace, if the sandboxer supports that.
|
||||||
|
'';
|
||||||
|
};
|
||||||
sandbox.whitelistAudio = mkOption {
|
sandbox.whitelistAudio = mkOption {
|
||||||
type = types.bool;
|
type = types.bool;
|
||||||
default = false;
|
default = false;
|
||||||
@@ -472,10 +479,12 @@ let
|
|||||||
;
|
;
|
||||||
suggestedPrograms = lib.optionals (config.sandbox.method == "bwrap") [
|
suggestedPrograms = lib.optionals (config.sandbox.method == "bwrap") [
|
||||||
"bubblewrap" "passt" "iproute2" "iptables"
|
"bubblewrap" "passt" "iproute2" "iptables"
|
||||||
|
] ++ lib.optionals (config.sandbox.method == "landlock") [
|
||||||
|
"landlock-sandboxer" "capsh"
|
||||||
] ++ lib.optionals (config.sandbox.method == "pastaonly") [
|
] ++ lib.optionals (config.sandbox.method == "pastaonly") [
|
||||||
"passt" "iproute2" "iptables"
|
"passt" "iproute2" "iptables" "capsh"
|
||||||
] ++ lib.optionals (config.sandbox.method == "capshonly") [
|
] ++ lib.optionals (config.sandbox.method == "capshonly") [
|
||||||
"libcap"
|
"capsh"
|
||||||
];
|
];
|
||||||
# declare a fs dependency for each secret, but don't specify how to populate it yet.
|
# declare a fs dependency for each secret, but don't specify how to populate it yet.
|
||||||
# can't populate it here because it varies per-user.
|
# can't populate it here because it varies per-user.
|
||||||
@@ -517,6 +526,8 @@ let
|
|||||||
"--sanebox-portal"
|
"--sanebox-portal"
|
||||||
] ++ lib.optionals (!config.sandbox.isolatePids) [
|
] ++ lib.optionals (!config.sandbox.isolatePids) [
|
||||||
"--sanebox-keep-namespace" "pid"
|
"--sanebox-keep-namespace" "pid"
|
||||||
|
] ++ lib.optionals (!config.sandbox.isolateUsers) [
|
||||||
|
"--sanebox-keep-namespace" "user"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
@@ -4,6 +4,7 @@
|
|||||||
buildPackages,
|
buildPackages,
|
||||||
file,
|
file,
|
||||||
gnugrep,
|
gnugrep,
|
||||||
|
gnused,
|
||||||
makeBinaryWrapper,
|
makeBinaryWrapper,
|
||||||
runCommandLocal,
|
runCommandLocal,
|
||||||
runtimeShell,
|
runtimeShell,
|
||||||
@@ -11,6 +12,7 @@
|
|||||||
symlinkJoin,
|
symlinkJoin,
|
||||||
writeShellScriptBin,
|
writeShellScriptBin,
|
||||||
writeTextFile,
|
writeTextFile,
|
||||||
|
xorg,
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
fakeSaneSandboxed = writeShellScriptBin "sanebox" ''
|
fakeSaneSandboxed = writeShellScriptBin "sanebox" ''
|
||||||
@@ -60,6 +62,7 @@ let
|
|||||||
# the ordering here is specific: inject our deps BEFORE the unwrapped program's
|
# the ordering here is specific: inject our deps BEFORE the unwrapped program's
|
||||||
# so that the unwrapped's take precendence and we limit interference (e.g. makeWrapper impl)
|
# so that the unwrapped's take precendence and we limit interference (e.g. makeWrapper impl)
|
||||||
fakeSaneSandboxed
|
fakeSaneSandboxed
|
||||||
|
gnugrep
|
||||||
makeBinaryWrapper
|
makeBinaryWrapper
|
||||||
] ++ (unwrapped.nativeBuildInputs or []);
|
] ++ (unwrapped.nativeBuildInputs or []);
|
||||||
disallowedReferences = (unwrapped.disallowedReferences or []) ++ [
|
disallowedReferences = (unwrapped.disallowedReferences or []) ++ [
|
||||||
@@ -70,8 +73,7 @@ let
|
|||||||
|
|
||||||
postFixup = (unwrapped.postFixup or "") + ''
|
postFixup = (unwrapped.postFixup or "") + ''
|
||||||
assertExecutable() {
|
assertExecutable() {
|
||||||
# my programs refer to sanebox by name, not path, which triggers an over-eager assertion in nixpkgs (so, mask that)
|
: # my programs refer to sanebox by name, not path, which triggers an over-eager assertion in nixpkgs (so, mask that)
|
||||||
:
|
|
||||||
}
|
}
|
||||||
makeDocumentedCWrapper() {
|
makeDocumentedCWrapper() {
|
||||||
# this is identical to nixpkgs' implementation, only replace execv with execvp, the latter which looks for the executable on PATH.
|
# this is identical to nixpkgs' implementation, only replace execv with execvp, the latter which looks for the executable on PATH.
|
||||||
@@ -93,26 +95,68 @@ let
|
|||||||
# if desired, makeWrapper-style naming could be achieved by leveraging `exec -a <original_name>`
|
# if desired, makeWrapper-style naming could be achieved by leveraging `exec -a <original_name>`
|
||||||
# or `make-wrapper --inherit-argv0`
|
# or `make-wrapper --inherit-argv0`
|
||||||
mkdir -p "$_dir/.sandboxed"
|
mkdir -p "$_dir/.sandboxed"
|
||||||
if [[ "$(readlink $_dir/$_name)" =~ ^\.\./ ]]; then
|
mv "$_dir/$_name" "$_dir/.sandboxed/"
|
||||||
# relative links which ascend a directory (into a non-bin/ directory)
|
|
||||||
# won't point to the right place if we naively move them
|
|
||||||
ln -s "../$(readlink $_dir/$_name)" "$_dir/.sandboxed/$_name"
|
|
||||||
rm "$_dir/$_name"
|
|
||||||
else
|
|
||||||
mv "$_dir/$_name" "$_dir/.sandboxed/"
|
|
||||||
fi
|
|
||||||
makeBinaryWrapper ${sanebox'} "$_dir/$_name" --suffix PATH : /run/current-system/sw/libexec/sanebox ${lib.escapeShellArgs (lib.flatten (builtins.map (f: [ "--add-flags" f ]) extraSandboxArgs))} --add-flags "$_dir/.sandboxed/$_name"
|
makeBinaryWrapper ${sanebox'} "$_dir/$_name" --suffix PATH : /run/current-system/sw/libexec/sanebox ${lib.escapeShellArgs (lib.flatten (builtins.map (f: [ "--add-flags" f ]) extraSandboxArgs))} --add-flags "$_dir/.sandboxed/$_name"
|
||||||
}
|
}
|
||||||
|
|
||||||
crawlAndWrap() {
|
derefWhileInSameOutput() {
|
||||||
local _dir="$1"
|
local output="$1"
|
||||||
for _p in $(ls "$_dir/"); do
|
local item="$2"
|
||||||
if [ -x "$_dir/$_p" ] && ! [ -d "$_dir/$_p" ]; then
|
if [ -L "$item" ]; then
|
||||||
sandboxWrap "$_dir" "$_p"
|
local target=$(readlink "$item")
|
||||||
elif [ -d "$_dir/$_p" ]; then
|
if [[ "$target" =~ ^"$output"/ ]]; then
|
||||||
crawlAndWrap "$_dir/$_p"
|
# absolute link back into the same package
|
||||||
|
item=$(derefWhileInSameOutput "$output" "$target")
|
||||||
|
elif [[ "$target" =~ ^/nix/store/ ]]; then
|
||||||
|
: # absolute link to another package: we're done
|
||||||
|
else
|
||||||
|
# relative link
|
||||||
|
local parent=$(dirname "$item")
|
||||||
|
target="$parent/$target"
|
||||||
|
item=$(derefWhileInSameOutput "$output" "$target")
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
echo "$item"
|
||||||
|
}
|
||||||
|
findUnwrapped() {
|
||||||
|
if [ -L "$1" ]; then
|
||||||
|
echo "$1"
|
||||||
|
else
|
||||||
|
local dir_=$(dirname "$1")
|
||||||
|
local file_=$(basename "$1")
|
||||||
|
local sandboxed="$dir_/.sandboxed/$file_"
|
||||||
|
local unwrapped="$dir_/.''${file_}-unwrapped"
|
||||||
|
if grep -q "$sandboxed" "$1"; then
|
||||||
|
echo "/dev/null" #< already sandboxed
|
||||||
|
elif grep -q "$unwrapped" "$1"; then
|
||||||
|
echo $(findUnwrapped "$unwrapped")
|
||||||
|
else
|
||||||
|
echo "$1"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
crawlAndWrap() {
|
||||||
|
local output="$1"
|
||||||
|
local _dir="$2"
|
||||||
|
local item
|
||||||
|
for item in $(ls -a "$_dir/"); do
|
||||||
|
if [ "$item" != . ] && [ "$item" != .. ]; then
|
||||||
|
local target="$_dir/$item"
|
||||||
|
if [ -x "$target" ] && ! [ -d "$target" ]; then
|
||||||
|
# in the case of symlinks, deref until we find the real file, or the symlink points outside the package
|
||||||
|
target=$(derefWhileInSameOutput "$output" "$target")
|
||||||
|
target=$(findUnwrapped "$target")
|
||||||
|
if [ "$target" != /dev/null ]; then
|
||||||
|
local parent=$(dirname "$target")
|
||||||
|
local bin=$(basename "$target")
|
||||||
|
sandboxWrap "$parent" "$bin"
|
||||||
|
fi
|
||||||
|
elif [ -d "$_dir/$item" ]; then
|
||||||
|
crawlAndWrap "$_dir/$item"
|
||||||
|
fi
|
||||||
|
# ignore all non-binaries
|
||||||
fi
|
fi
|
||||||
# ignore all non-binaries
|
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,10 +164,10 @@ let
|
|||||||
local outdir=''${!output}
|
local outdir=''${!output}
|
||||||
echo "scanning output '$output' at $outdir for binaries to sandbox"
|
echo "scanning output '$output' at $outdir for binaries to sandbox"
|
||||||
if [ -e "$outdir/bin" ]; then
|
if [ -e "$outdir/bin" ]; then
|
||||||
crawlAndWrap "$outdir/bin"
|
crawlAndWrap "$outdir" "$outdir/bin"
|
||||||
fi
|
fi
|
||||||
if [ -e "$outdir/libexec" ]; then
|
if [ -e "$outdir/libexec" ]; then
|
||||||
crawlAndWrap "$outdir/libexec"
|
crawlAndWrap "$outdir" "$outdir/libexec"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
'';
|
'';
|
||||||
@@ -139,20 +183,57 @@ let
|
|||||||
;
|
;
|
||||||
|
|
||||||
# helper used for `wrapperType == "wrappedDerivation"` which simply symlinks all a package's binaries into a new derivation
|
# helper used for `wrapperType == "wrappedDerivation"` which simply symlinks all a package's binaries into a new derivation
|
||||||
symlinkBinaries = pkgName: package: (runCommandLocal "${pkgName}-bin-only" {} ''
|
symlinkBinaries = pkgName: package: (runCommandLocal "${pkgName}-bin-only" {
|
||||||
|
nativeBuildInputs = [ gnused ];
|
||||||
|
} ''
|
||||||
set -e
|
set -e
|
||||||
if [ -e "${package}/bin" ]; then
|
symlinkPath() {
|
||||||
mkdir -p "$out/bin"
|
if [ -e "$out/$1" ]; then
|
||||||
${buildPackages.xorg.lndir}/bin/lndir "${package}/bin" "$out/bin"
|
: # already linked. may happen when e.g. the package has bin/foo, and sbin -> bin.
|
||||||
fi
|
elif ! [ -x "${package}/$1" ]; then
|
||||||
if [ "$(readlink ${package}/sbin)" == "bin" ]; then
|
: # not a binary, nor a directory (-x) which could contain binaries
|
||||||
# weird packages like wpa_supplicant depend on a sbin/ -> bin symlink in their service files
|
elif [ -L "${package}/$1" ]; then
|
||||||
ln -s bin "$out/sbin"
|
local target=$(readlink "${package}/$1")
|
||||||
fi
|
if [[ "$target" =~ ^${package}/ ]]; then
|
||||||
if [ -e "${package}/libexec" ]; then
|
# absolute link back into the same package
|
||||||
mkdir -p "$out/libexec"
|
echo "handling $1: descending into absolute symlink to same package: $target"
|
||||||
${buildPackages.xorg.lndir}/bin/lndir "${package}/libexec" "$out/libexec"
|
target=$(echo "$target" | sed 's:${package}/::')
|
||||||
fi
|
ln -s "$out/$target" "$out/$1"
|
||||||
|
# create/link the backing path
|
||||||
|
# N.B.: if some leading component of the backing path is also a symlink... this might not work as expected.
|
||||||
|
local parent=$(dirname "$out/$target")
|
||||||
|
mkdir -p "$parent"
|
||||||
|
symlinkPath "$target"
|
||||||
|
elif [[ "$target" =~ ^/nix/store/ ]]; then
|
||||||
|
# absolute link to another package
|
||||||
|
echo "handling $1: symlinking absolute store path: $target"
|
||||||
|
ln -s "$target" "$out/$1"
|
||||||
|
else
|
||||||
|
# relative link
|
||||||
|
echo "handling $1: descending into relative symlink: $target"
|
||||||
|
ln -s "$target" "$out/$1"
|
||||||
|
local parent=$(dirname "$1")
|
||||||
|
local derefParent=$(dirname "$out/$parent/$target")
|
||||||
|
$(set -x && mkdir -p "$derefParent")
|
||||||
|
symlinkPath "$parent/$target"
|
||||||
|
fi
|
||||||
|
elif [ -d "${package}/$1" ]; then
|
||||||
|
echo "handling $1: descending into directory"
|
||||||
|
mkdir -p "$out/$1"
|
||||||
|
items=($(ls -a "${package}/$1"))
|
||||||
|
for item in "''${items[@]}"; do
|
||||||
|
if [ "$item" != . ] && [ "$item" != .. ]; then
|
||||||
|
symlinkPath "$1/$item"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
elif [ -e "${package}/$1" ]; then
|
||||||
|
echo "handling $1: symlinking ordinary file"
|
||||||
|
ln -s "${package}/$1" "$out/$1"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
symlinkPath bin
|
||||||
|
symlinkPath sbin
|
||||||
|
symlinkPath libexec
|
||||||
# allow downstream wrapping to hook this (and thereby actually wrap the binaries)
|
# allow downstream wrapping to hook this (and thereby actually wrap the binaries)
|
||||||
runHook postFixup
|
runHook postFixup
|
||||||
'').overrideAttrs (_: {
|
'').overrideAttrs (_: {
|
||||||
@@ -185,6 +266,28 @@ let
|
|||||||
mv ./substituteResult "$_outPath"
|
mv ./substituteResult "$_outPath"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# remove any files which exist in sandoxedBin (makes it possible to sandbox /opt-style packages)
|
||||||
|
# also remove any files which would be "hidden". mostly useful for /opt-style packages which contain nix-wrapped binaries.
|
||||||
|
removeUnwanted() {
|
||||||
|
local file_=$(basename "$1")
|
||||||
|
if [[ "$file_" == .* ]]; then
|
||||||
|
rm -r "$out/$1"
|
||||||
|
elif [ -f "$out/$1" ] || [ -L "$out/$1" ]; then
|
||||||
|
if [ -e "${sandboxedBin}/$1" ]; then
|
||||||
|
rm "$out/$1"
|
||||||
|
fi
|
||||||
|
elif [ -d "$out/$1" ]; then
|
||||||
|
local files=($(ls -a "$out/$1"))
|
||||||
|
for item in "''${files[@]}"; do
|
||||||
|
if [ "$item" != . ] && [ "$item" != .. ]; then
|
||||||
|
removeUnwanted "$1/$item"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
removeUnwanted ""
|
||||||
|
|
||||||
# fixup a few files i understand well enough
|
# fixup a few files i understand well enough
|
||||||
for d in \
|
for d in \
|
||||||
$out/etc/xdg/autostart/*.desktop \
|
$out/etc/xdg/autostart/*.desktop \
|
||||||
@@ -207,13 +310,15 @@ let
|
|||||||
# further, since the sandboxed binaries intentionally reference the unsandboxed binaries,
|
# further, since the sandboxed binaries intentionally reference the unsandboxed binaries,
|
||||||
# we have to patch those out as a way to whitelist them.
|
# we have to patch those out as a way to whitelist them.
|
||||||
checkSandboxed = let
|
checkSandboxed = let
|
||||||
sandboxedNonBin = fixHardcodedRefs unsandboxed "/dev/null" unsandboxedNonBin;
|
sandboxedNonBin = fixHardcodedRefs unsandboxed sandboxedBin unsandboxedNonBin;
|
||||||
in runCommandLocal "${sandboxedNonBin.name}-check-sandboxed"
|
in runCommandLocal "${sandboxedNonBin.name}-check-sandboxed"
|
||||||
{ disallowedReferences = [ unsandboxed ]; }
|
{ disallowedReferences = [ unsandboxed ]; }
|
||||||
|
# dereference every symlink, ensuring that whatever data is behind it does not reference non-sandboxed binaries.
|
||||||
|
# the dereference *can* fail, in case it's a relative symlink that refers to a part of the non-binaries we don't patch.
|
||||||
|
# in such case, this could lead to weird brokenness (e.g. no icons/images), so failing is reasonable.
|
||||||
|
# N.B.: this `checkSandboxed` protects against accidentally referencing unsandboxed binaries from data files (.deskop, .service, etc).
|
||||||
|
# there's an *additional* `checkSandboxed` further below which invokes every executable in the final package to make sure the binaries are truly sandboxed.
|
||||||
''
|
''
|
||||||
# dereference every symlink, ensuring that whatever data is behind it does not reference non-sandboxed binaries.
|
|
||||||
# the dereference *can* fail, in case it's a relative symlink that refers to a part of the non-binaries we don't patch.
|
|
||||||
# in such case, this could lead to weird brokenness (e.g. no icons/images), so failing is reasonable.
|
|
||||||
cp -R --dereference "${sandboxedNonBin}" "$out" # IF YOUR BUILD FAILS HERE, TRY SANDBOXING WITH "inplace"
|
cp -R --dereference "${sandboxedNonBin}" "$out" # IF YOUR BUILD FAILS HERE, TRY SANDBOXING WITH "inplace"
|
||||||
''
|
''
|
||||||
;
|
;
|
||||||
@@ -224,7 +329,9 @@ let
|
|||||||
# patch them to use the sandboxed binaries,
|
# patch them to use the sandboxed binaries,
|
||||||
# and add some passthru metadata to enforce no lingering references to the unsandboxed binaries.
|
# and add some passthru metadata to enforce no lingering references to the unsandboxed binaries.
|
||||||
sandboxNonBinaries = pkgName: unsandboxed: sandboxedBin: let
|
sandboxNonBinaries = pkgName: unsandboxed: sandboxedBin: let
|
||||||
sandboxedWithoutFixedRefs = (runCommandLocal "${pkgName}-sandboxed-non-binary" {} ''
|
sandboxedWithoutFixedRefs = (runCommandLocal "${pkgName}-sandboxed-non-binary" {
|
||||||
|
nativeBuildInputs = [ xorg.lndir ];
|
||||||
|
} ''
|
||||||
set -e
|
set -e
|
||||||
mkdir "$out"
|
mkdir "$out"
|
||||||
# link in a limited subset of the directories.
|
# link in a limited subset of the directories.
|
||||||
@@ -233,7 +340,7 @@ let
|
|||||||
for dir in etc share; do
|
for dir in etc share; do
|
||||||
if [ -e "${unsandboxed}/$dir" ]; then
|
if [ -e "${unsandboxed}/$dir" ]; then
|
||||||
mkdir "$out/$dir"
|
mkdir "$out/$dir"
|
||||||
${buildPackages.xorg.lndir}/bin/lndir "${unsandboxed}/$dir" "$out/$dir"
|
lndir "${unsandboxed}/$dir" "$out/$dir"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
runHook postInstall
|
runHook postInstall
|
||||||
@@ -243,7 +350,7 @@ let
|
|||||||
});
|
});
|
||||||
in fixHardcodedRefs unsandboxed sandboxedBin sandboxedWithoutFixedRefs;
|
in fixHardcodedRefs unsandboxed sandboxedBin sandboxedWithoutFixedRefs;
|
||||||
|
|
||||||
# take the nearly-final sandboxed package, with binaries and and else, and
|
# take the nearly-final sandboxed package, with binaries and all else, and
|
||||||
# populate passthru attributes the caller expects, like `checkSandboxed`.
|
# populate passthru attributes the caller expects, like `checkSandboxed`.
|
||||||
fixupMetaAndPassthru = pkgName: pkg: extraPassthru: pkg.overrideAttrs (finalAttrs: prevAttrs: let
|
fixupMetaAndPassthru = pkgName: pkg: extraPassthru: pkg.overrideAttrs (finalAttrs: prevAttrs: let
|
||||||
nonBin = (prevAttrs.passthru or {}).sandboxedNonBin or {};
|
nonBin = (prevAttrs.passthru or {}).sandboxedNonBin or {};
|
||||||
|
@@ -5,7 +5,7 @@
|
|||||||
./clightning.nix
|
./clightning.nix
|
||||||
./dyn-dns.nix
|
./dyn-dns.nix
|
||||||
./eg25-manager.nix
|
./eg25-manager.nix
|
||||||
|
./hickory-dns
|
||||||
./kiwix-serve.nix
|
./kiwix-serve.nix
|
||||||
./trust-dns
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@@ -1,20 +1,20 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
let
|
let
|
||||||
trust-dns-nmhook = pkgs.static-nix-shell.mkPython3 {
|
hickory-dns-nmhook = pkgs.static-nix-shell.mkPython3 {
|
||||||
pname = "trust-dns-nmhook";
|
pname = "hickory-dns-nmhook";
|
||||||
srcRoot = ./.;
|
srcRoot = ./.;
|
||||||
pkgs = [
|
pkgs = [
|
||||||
"systemd"
|
"systemd"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
cfg = config.sane.services.trust-dns;
|
cfg = config.sane.services.hickory-dns;
|
||||||
dns = config.sane.dns;
|
dns = config.sane.dns;
|
||||||
toml = pkgs.formats.toml { };
|
toml = pkgs.formats.toml { };
|
||||||
instanceModule = with lib; types.submodule ({ config, name, ...}: {
|
instanceModule = with lib; types.submodule ({ config, name, ...}: {
|
||||||
options = {
|
options = {
|
||||||
service = mkOption {
|
service = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
default = "trust-dns-${name}";
|
default = "hickory-dns-${name}";
|
||||||
description = ''
|
description = ''
|
||||||
systemd service name corresponding to this instance (used internally and automatically set).
|
systemd service name corresponding to this instance (used internally and automatically set).
|
||||||
'';
|
'';
|
||||||
@@ -41,7 +41,7 @@ let
|
|||||||
type = types.attrsOf types.str;
|
type = types.attrsOf types.str;
|
||||||
default = {};
|
default = {};
|
||||||
description = ''
|
description = ''
|
||||||
text substitutions to make on the config and zone file before starting trust-dns.
|
text substitutions to make on the config and zone file before starting hickory-dns.
|
||||||
'';
|
'';
|
||||||
example = {
|
example = {
|
||||||
"%CNAMESELF%" = "lappy";
|
"%CNAMESELF%" = "lappy";
|
||||||
@@ -98,12 +98,12 @@ let
|
|||||||
mkSystemdService = flavor: { includes, listenAddrsIpv4, listenAddrsIpv6, port, substitutions, extraConfig, ... }: let
|
mkSystemdService = flavor: { includes, listenAddrsIpv4, listenAddrsIpv6, port, substitutions, extraConfig, ... }: let
|
||||||
sed = "${pkgs.gnused}/bin/sed";
|
sed = "${pkgs.gnused}/bin/sed";
|
||||||
baseConfig = (
|
baseConfig = (
|
||||||
lib.filterAttrsRecursive (_: v: v != null) config.services.trust-dns.settings
|
lib.filterAttrsRecursive (_: v: v != null) config.services.hickory-dns.settings
|
||||||
) // {
|
) // {
|
||||||
listen_addrs_ipv4 = listenAddrsIpv4;
|
listen_addrs_ipv4 = listenAddrsIpv4;
|
||||||
listen_addrs_ipv6 = listenAddrsIpv6;
|
listen_addrs_ipv6 = listenAddrsIpv6;
|
||||||
};
|
};
|
||||||
configTemplate = toml.generate "trust-dns-${flavor}.toml" (baseConfig //
|
configTemplate = toml.generate "hickory-dns-${flavor}.toml" (baseConfig //
|
||||||
(lib.mapAttrs (k: v:
|
(lib.mapAttrs (k: v:
|
||||||
if k == "zones" then
|
if k == "zones" then
|
||||||
# append to the baseConfig instead of overriding it
|
# append to the baseConfig instead of overriding it
|
||||||
@@ -113,7 +113,7 @@ let
|
|||||||
)
|
)
|
||||||
extraConfig
|
extraConfig
|
||||||
));
|
));
|
||||||
configPath = "/var/lib/trust-dns/${flavor}-config.toml";
|
configPath = "/var/lib/hickory-dns/${flavor}-config.toml";
|
||||||
sedArgs = builtins.map (key: ''-e "s/${key}/${substitutions."${key}"}/g"'') (
|
sedArgs = builtins.map (key: ''-e "s/${key}/${substitutions."${key}"}/g"'') (
|
||||||
# HACK: %ANATIVE% often expands to one of the other subtitutions (e.g. %AWAN%)
|
# HACK: %ANATIVE% often expands to one of the other subtitutions (e.g. %AWAN%)
|
||||||
# so we must expand it *first*.
|
# so we must expand it *first*.
|
||||||
@@ -123,33 +123,34 @@ let
|
|||||||
);
|
);
|
||||||
subs = lib.concatStringsSep " " sedArgs;
|
subs = lib.concatStringsSep " " sedArgs;
|
||||||
in {
|
in {
|
||||||
description = "trust-dns Domain Name Server (serving ${flavor})";
|
description = "hickory-dns Domain Name Server (serving ${flavor})";
|
||||||
unitConfig.Documentation = "https://trust-dns.org/";
|
unitConfig.Documentation = "https://hickory-dns.org/";
|
||||||
after = [ "network.target" ];
|
after = [ "network.target" ];
|
||||||
|
before = [ "network-online.target" ]; # most things assume they'll have DNS services alongside routability
|
||||||
wantedBy = [ "network.target" ];
|
wantedBy = [ "network.target" ];
|
||||||
|
|
||||||
preStart = lib.concatStringsSep "\n" (
|
preStart = lib.concatStringsSep "\n" (
|
||||||
[''
|
[''
|
||||||
mkdir -p "/var/lib/trust-dns/${flavor}"
|
mkdir -p "/var/lib/hickory-dns/${flavor}"
|
||||||
${sed} ${subs} -e "" "${configTemplate}" \
|
${sed} ${subs} -e "" "${configTemplate}" \
|
||||||
| cat - \
|
| cat - \
|
||||||
${lib.concatStringsSep " " includes} \
|
${lib.concatStringsSep " " includes} \
|
||||||
> "${configPath}" || true
|
> "${configPath}" || true
|
||||||
''] ++ lib.mapAttrsToList (zone: { rendered, ... }: ''
|
''] ++ lib.mapAttrsToList (zone: { rendered, ... }: ''
|
||||||
${sed} ${subs} -e "" ${pkgs.writeText "${zone}.zone.in" rendered} \
|
${sed} ${subs} -e "" ${pkgs.writeText "${zone}.zone.in" rendered} \
|
||||||
> "/var/lib/trust-dns/${flavor}/${zone}.zone"
|
> "/var/lib/hickory-dns/${flavor}/${zone}.zone"
|
||||||
'') dns.zones
|
'') dns.zones
|
||||||
);
|
);
|
||||||
|
|
||||||
serviceConfig = (config.systemd.services.hickory-dns or config.systemd.services.trust-dns).serviceConfig // {
|
serviceConfig = config.systemd.services.hickory-dns.serviceConfig // {
|
||||||
ExecStart = lib.escapeShellArgs ([
|
ExecStart = lib.escapeShellArgs ([
|
||||||
"${lib.getExe config.services.trust-dns.package}"
|
"${lib.getExe config.services.hickory-dns.package}"
|
||||||
"--port" (builtins.toString port)
|
"--port" (builtins.toString port)
|
||||||
"--zonedir" "/var/lib/trust-dns/${flavor}"
|
"--zonedir" "/var/lib/hickory-dns/${flavor}"
|
||||||
"--config" "${configPath}"
|
"--config" "${configPath}"
|
||||||
] ++ lib.optionals config.services.trust-dns.debug [
|
] ++ lib.optionals config.services.hickory-dns.debug [
|
||||||
"--debug"
|
"--debug"
|
||||||
] ++ lib.optionals config.services.trust-dns.quiet [
|
] ++ lib.optionals config.services.hickory-dns.quiet [
|
||||||
"--quiet"
|
"--quiet"
|
||||||
]);
|
]);
|
||||||
# servo/dyn-dns needs /var/lib/uninsane/wan.txt.
|
# servo/dyn-dns needs /var/lib/uninsane/wan.txt.
|
||||||
@@ -157,14 +158,14 @@ let
|
|||||||
# so just bind the deepest path which is guaranteed to exist.
|
# so just bind the deepest path which is guaranteed to exist.
|
||||||
ReadOnlyPaths = [ "/var/lib" ]; #< TODO: scope this down!
|
ReadOnlyPaths = [ "/var/lib" ]; #< TODO: scope this down!
|
||||||
} // lib.optionalAttrs cfg.asSystemResolver {
|
} // lib.optionalAttrs cfg.asSystemResolver {
|
||||||
# allow the group to write trust-dns state (needed by NetworkManager hook)
|
# allow the group to write hickory-dns state (needed by NetworkManager hook)
|
||||||
StateDirectoryMode = "775";
|
StateDirectoryMode = "775";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
options = with lib; {
|
options = with lib; {
|
||||||
sane.services.trust-dns = {
|
sane.services.hickory-dns = {
|
||||||
enable = mkOption {
|
enable = mkOption {
|
||||||
default = false;
|
default = false;
|
||||||
type = types.bool;
|
type = types.bool;
|
||||||
@@ -181,19 +182,19 @@ in
|
|||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
# enable nixpkgs' trust-dns so that i get its config generation
|
# enable nixpkgs' hickory-dns so that i get its config generation
|
||||||
# but don't actually enable the systemd service... i'll instantiate *multiple* instances per interface further below
|
# but don't actually enable the systemd service... i'll instantiate *multiple* instances per interface further below
|
||||||
services.trust-dns.enable = true;
|
services.hickory-dns.enable = true;
|
||||||
services.trust-dns.settings.zones = []; #< TODO: remove once upstreamed (bad default)
|
services.hickory-dns.settings.zones = []; #< TODO: remove once upstreamed (bad default)
|
||||||
|
|
||||||
# don't bind to IPv6 until i explicitly test that stack
|
# don't bind to IPv6 until i explicitly test that stack
|
||||||
services.trust-dns.settings.listen_addrs_ipv6 = [];
|
services.hickory-dns.settings.listen_addrs_ipv6 = [];
|
||||||
services.trust-dns.quiet = true;
|
services.hickory-dns.quiet = true;
|
||||||
# FIXME(2023/11/26): services.trust-dns.debug doesn't log requests: use RUST_LOG=debug env for that.
|
# FIXME(2023/11/26): services.hickory-dns.debug doesn't log requests: use RUST_LOG=debug env for that.
|
||||||
# - see: <https://github.com/hickory-dns/hickory-dns/issues/2082>
|
# - see: <https://github.com/hickory-dns/hickory-dns/issues/2082>
|
||||||
# services.trust-dns.debug = true;
|
# services.hickory-dns.debug = true;
|
||||||
|
|
||||||
services.trust-dns.package = pkgs.trust-dns.override {
|
services.hickory-dns.package = pkgs.hickory-dns.override {
|
||||||
rustPlatform.buildRustPackage = args: pkgs.rustPlatform.buildRustPackage (args // {
|
rustPlatform.buildRustPackage = args: pkgs.rustPlatform.buildRustPackage (args // {
|
||||||
buildFeatures = [
|
buildFeatures = [
|
||||||
"recursor"
|
"recursor"
|
||||||
@@ -213,11 +214,11 @@ in
|
|||||||
cargoHash = "sha256-6Es5/gRqgsteWUHICdgcNlujJE9vrdr3tj/EKKyFsrY=";
|
cargoHash = "sha256-6Es5/gRqgsteWUHICdgcNlujJE9vrdr3tj/EKKyFsrY=";
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
services.trust-dns.settings.directory = "/var/lib/trust-dns";
|
services.hickory-dns.settings.directory = "/var/lib/hickory-dns";
|
||||||
|
|
||||||
users.groups.trust-dns = {};
|
users.groups.hickory-dns = {};
|
||||||
users.users.trust-dns = {
|
users.users.hickory-dns = {
|
||||||
group = "trust-dns";
|
group = "hickory-dns";
|
||||||
isSystemUser = true;
|
isSystemUser = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -226,27 +227,15 @@ in
|
|||||||
hickory-dns.enable = false;
|
hickory-dns.enable = false;
|
||||||
hickory-dns.serviceConfig = {
|
hickory-dns.serviceConfig = {
|
||||||
DynamicUser = lib.mkForce false;
|
DynamicUser = lib.mkForce false;
|
||||||
User = "trust-dns";
|
User = "hickory-dns";
|
||||||
Group = "trust-dns";
|
Group = "hickory-dns";
|
||||||
wantedBy = lib.mkForce [];
|
wantedBy = lib.mkForce [];
|
||||||
# there can be a lot of restarts as interfaces toggle,
|
# there can be a lot of restarts as interfaces toggle,
|
||||||
# particularly around the DHCP/NetworkManager stuff.
|
# particularly around the DHCP/NetworkManager stuff.
|
||||||
StartLimitBurst = 60;
|
StartLimitBurst = 60;
|
||||||
StateDirectory = lib.mkForce "trust-dns";
|
StateDirectory = lib.mkForce "hickory-dns";
|
||||||
};
|
};
|
||||||
|
# hickory-dns.unitConfig.StartLimitIntervalSec = 60;
|
||||||
trust-dns.enable = false;
|
|
||||||
trust-dns.serviceConfig = {
|
|
||||||
DynamicUser = lib.mkForce false;
|
|
||||||
User = "trust-dns";
|
|
||||||
Group = "trust-dns";
|
|
||||||
wantedBy = lib.mkForce [];
|
|
||||||
# there can be a lot of restarts as interfaces toggle,
|
|
||||||
# particularly around the DHCP/NetworkManager stuff.
|
|
||||||
StartLimitBurst = 60;
|
|
||||||
StateDirectory = lib.mkForce "trust-dns";
|
|
||||||
};
|
|
||||||
# trust-dns.unitConfig.StartLimitIntervalSec = 60;
|
|
||||||
}
|
}
|
||||||
(lib.mapAttrs'
|
(lib.mapAttrs'
|
||||||
(flavor: instanceConfig: {
|
(flavor: instanceConfig: {
|
||||||
@@ -258,28 +247,28 @@ in
|
|||||||
];
|
];
|
||||||
|
|
||||||
# run a hook whenever networking details change, so the DNS zone can be updated to reflect this
|
# run a hook whenever networking details change, so the DNS zone can be updated to reflect this
|
||||||
environment.etc."NetworkManager/dispatcher.d/60-trust-dns-nmhook" = lib.mkIf cfg.asSystemResolver {
|
environment.etc."NetworkManager/dispatcher.d/60-hickory-dns-nmhook" = lib.mkIf cfg.asSystemResolver {
|
||||||
source = "${trust-dns-nmhook}/bin/trust-dns-nmhook";
|
source = "${hickory-dns-nmhook}/bin/hickory-dns-nmhook";
|
||||||
};
|
};
|
||||||
|
|
||||||
# allow NetworkManager (via trust-dns-nmhook) to restart trust-dns when necessary
|
# allow NetworkManager (via hickory-dns-nmhook) to restart hickory-dns when necessary
|
||||||
# - source: <https://stackoverflow.com/questions/61480914/using-policykit-to-allow-non-root-users-to-start-and-stop-a-service>
|
# - source: <https://stackoverflow.com/questions/61480914/using-policykit-to-allow-non-root-users-to-start-and-stop-a-service>
|
||||||
security.polkit.extraConfig = lib.mkIf cfg.asSystemResolver ''
|
security.polkit.extraConfig = lib.mkIf cfg.asSystemResolver ''
|
||||||
polkit.addRule(function(action, subject) {
|
polkit.addRule(function(action, subject) {
|
||||||
if (subject.isInGroup("trust-dns") &&
|
if (subject.isInGroup("hickory-dns") &&
|
||||||
action.id == "org.freedesktop.systemd1.manage-units" &&
|
action.id == "org.freedesktop.systemd1.manage-units" &&
|
||||||
action.lookup("unit") == "trust-dns-localhost.service") {
|
action.lookup("unit") == "hickory-dns-localhost.service") {
|
||||||
return polkit.Result.YES;
|
return polkit.Result.YES;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
'';
|
'';
|
||||||
|
|
||||||
sane.services.trust-dns.instances.localhost = lib.mkIf cfg.asSystemResolver {
|
sane.services.hickory-dns.instances.localhost = lib.mkIf cfg.asSystemResolver {
|
||||||
listenAddrsIpv4 = [ "127.0.0.1" ];
|
listenAddrsIpv4 = [ "127.0.0.1" ];
|
||||||
listenAddrsIpv6 = [ "::1" ];
|
listenAddrsIpv6 = [ "::1" ];
|
||||||
enableRecursiveResolver = true;
|
enableRecursiveResolver = true;
|
||||||
# append zones discovered via DHCP to the resolver config.
|
# append zones discovered via DHCP to the resolver config.
|
||||||
includes = [ "/var/lib/trust-dns/dhcp-configs/*" ];
|
includes = [ "/var/lib/hickory-dns/dhcp-configs/*" ];
|
||||||
};
|
};
|
||||||
networking.nameservers = lib.mkIf cfg.asSystemResolver [
|
networking.nameservers = lib.mkIf cfg.asSystemResolver [
|
||||||
"127.0.0.1"
|
"127.0.0.1"
|
@@ -2,7 +2,7 @@
|
|||||||
#!nix-shell -i python3 -p python3 -p systemd
|
#!nix-shell -i python3 -p python3 -p systemd
|
||||||
# vim: set filetype=python :
|
# vim: set filetype=python :
|
||||||
|
|
||||||
# /etc/NetworkManager/dispatcher.d/trust-dns-nmhook:
|
# /etc/NetworkManager/dispatcher.d/hickory-dns-nmhook:
|
||||||
# NetworkManager-dispatcher.service calls this script whenever any network changes state.
|
# NetworkManager-dispatcher.service calls this script whenever any network changes state.
|
||||||
# this includes when we activate a new network and receive DHCP info.
|
# this includes when we activate a new network and receive DHCP info.
|
||||||
# specifically, this script propagates DHCP info to my DNS setup,
|
# specifically, this script propagates DHCP info to my DNS setup,
|
||||||
@@ -23,7 +23,7 @@ import subprocess
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
DNS_DIR = "/var/lib/trust-dns"
|
DNS_DIR = "/var/lib/hickory-dns"
|
||||||
DHCP_CONFIGS = "dhcp-configs"
|
DHCP_CONFIGS = "dhcp-configs"
|
||||||
|
|
||||||
class Ops:
|
class Ops:
|
||||||
@@ -103,6 +103,12 @@ stores = {{ type = "forward", name_servers = [
|
|||||||
return lines
|
return lines
|
||||||
|
|
||||||
def apply_zone(nm_config: NmConfig, ops: Ops) -> None:
|
def apply_zone(nm_config: NmConfig, ops: Ops) -> None:
|
||||||
|
# if we want to write /var/lib/hickory-dns here, then we have to make sure the service is started, so systemd can create the directory.
|
||||||
|
# ops.exec_([
|
||||||
|
# "systemctl",
|
||||||
|
# "start",
|
||||||
|
# "hickory-dns-localhost",
|
||||||
|
# ])
|
||||||
specialized_config = ""
|
specialized_config = ""
|
||||||
for domain in nm_config.search_domains:
|
for domain in nm_config.search_domains:
|
||||||
if is_valid_search_domain(domain) and nm_config.nameservers:
|
if is_valid_search_domain(domain) and nm_config.nameservers:
|
||||||
@@ -119,7 +125,7 @@ def apply_zone(nm_config: NmConfig, ops: Ops) -> None:
|
|||||||
ops.exec_([
|
ops.exec_([
|
||||||
"systemctl",
|
"systemctl",
|
||||||
"restart",
|
"restart",
|
||||||
"trust-dns-localhost",
|
"hickory-dns-localhost",
|
||||||
])
|
])
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
@@ -128,7 +134,7 @@ def main():
|
|||||||
|
|
||||||
logger.info('invoked')
|
logger.info('invoked')
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(description='update trust-dns config in response to NetworkManager event')
|
parser = argparse.ArgumentParser(description='update hickory-dns config in response to NetworkManager event')
|
||||||
parser.add_argument('--dns-dir', default=DNS_DIR)
|
parser.add_argument('--dns-dir', default=DNS_DIR)
|
||||||
parser.add_argument('--verbose', action='store_true')
|
parser.add_argument('--verbose', action='store_true')
|
||||||
parser.add_argument('--dry-run', action='store_true')
|
parser.add_argument('--dry-run', action='store_true')
|
@@ -154,7 +154,7 @@ let
|
|||||||
systemd.network.networks."50-${name}" = {
|
systemd.network.networks."50-${name}" = {
|
||||||
# see: `man 5 systemd.network`
|
# see: `man 5 systemd.network`
|
||||||
matchConfig.Name = name;
|
matchConfig.Name = name;
|
||||||
networkConfig.Address = [ addrV4 ];
|
networkConfig.Address = [ "${addrV4}/32" ];
|
||||||
networkConfig.DNS = dns;
|
networkConfig.DNS = dns;
|
||||||
# TODO: `sane-vpn up <vpn>` should configure DNS to be sent over the VPN
|
# TODO: `sane-vpn up <vpn>` should configure DNS to be sent over the VPN
|
||||||
# DNSDefaultRoute: system DNS queries are sent to this link's DNS server
|
# DNSDefaultRoute: system DNS queries are sent to this link's DNS server
|
||||||
@@ -185,7 +185,7 @@ let
|
|||||||
# periodically re-apply peers, to ensure DNS mappings stay fresh
|
# periodically re-apply peers, to ensure DNS mappings stay fresh
|
||||||
# borrowed from <repo:nixos/nixpkgs:nixos/modules/services/networking/wireguard.nix>
|
# borrowed from <repo:nixos/nixpkgs:nixos/modules/services/networking/wireguard.nix>
|
||||||
wantedBy = [ "network.target" ];
|
wantedBy = [ "network.target" ];
|
||||||
path = with pkgs; [ wireguard-tools ];
|
path = [ config.sane.programs.wireguard-tools.package ];
|
||||||
serviceConfig.Restart = "always";
|
serviceConfig.Restart = "always";
|
||||||
serviceConfig.RestartSec = "60"; #< retry delay when we fail (because e.g. there's no network)
|
serviceConfig.RestartSec = "60"; #< retry delay when we fail (because e.g. there's no network)
|
||||||
serviceConfig.Type = "simple";
|
serviceConfig.Type = "simple";
|
||||||
@@ -197,6 +197,32 @@ let
|
|||||||
sleep 180
|
sleep 180
|
||||||
done
|
done
|
||||||
'';
|
'';
|
||||||
|
# systemd hardening (systemd-analyze security wg-home-refresh.service)
|
||||||
|
serviceConfig.AmbientCapabilities = "CAP_NET_ADMIN";
|
||||||
|
serviceConfig.CapabilityBoundingSet = "CAP_NET_ADMIN";
|
||||||
|
serviceConfig.LockPersonality = true;
|
||||||
|
serviceConfig.MemoryDenyWriteExecute = true;
|
||||||
|
serviceConfig.NoNewPrivileges = true;
|
||||||
|
serviceConfig.ProtectClock = true;
|
||||||
|
serviceConfig.ProtectHostname = true;
|
||||||
|
serviceConfig.RemoveIPC = true;
|
||||||
|
serviceConfig.RestrictAddressFamilies = "AF_INET AF_INET6 AF_NETLINK";
|
||||||
|
#VVV this includes anything it reads from, e.g. /bin/sh; /nix/store/...
|
||||||
|
# see `systemd-analyze filesystems` for a full list
|
||||||
|
serviceConfig.RestrictFileSystems = "@common-block @basic-api";
|
||||||
|
serviceConfig.RestrictRealtime = true;
|
||||||
|
serviceConfig.RestrictSUIDSGID = true;
|
||||||
|
serviceConfig.SystemCallArchitectures = "native";
|
||||||
|
serviceConfig.SystemCallFilter = [
|
||||||
|
"@system-service"
|
||||||
|
"@sandbox"
|
||||||
|
"~@chown"
|
||||||
|
"~@cpu-emulation"
|
||||||
|
"~@keyring"
|
||||||
|
];
|
||||||
|
serviceConfig.DevicePolicy = "closed"; # only allow /dev/{null,zero,full,random,urandom}
|
||||||
|
# serviceConfig.DeviceAllow = "/dev/...";
|
||||||
|
serviceConfig.RestrictNamespaces = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
# networking.firewall.extraCommands = with pkgs; ''
|
# networking.firewall.extraCommands = with pkgs; ''
|
||||||
|
@@ -115,21 +115,6 @@ in with final; {
|
|||||||
# });
|
# });
|
||||||
# };
|
# };
|
||||||
|
|
||||||
# 2024/05/13: upstreaming is unblocked; out for review: <https://github.com/NixOS/nixpkgs/pull/305241>
|
|
||||||
appstream = prev.appstream.overrideAttrs (upstream: {
|
|
||||||
# fixes: "Message: Native appstream required for cross-building"
|
|
||||||
# error introduced in:
|
|
||||||
# - <https://github.com/ximion/appstream/pull/510>
|
|
||||||
# - <https://github.com/NixOS/nixpkgs/pull/273297>
|
|
||||||
postPatch = (upstream.postPatch or "") + ''
|
|
||||||
substituteInPlace data/meson.build \
|
|
||||||
--replace-fail 'meson.is_cross_build()' 'false'
|
|
||||||
'';
|
|
||||||
# nativeBuildInputs = upstream.nativeBuildInputs ++ [
|
|
||||||
# prev.appstream
|
|
||||||
# ];
|
|
||||||
});
|
|
||||||
|
|
||||||
# bamf: required via pantheon.switchboard -> wingpanel -> gala
|
# bamf: required via pantheon.switchboard -> wingpanel -> gala
|
||||||
# bamf = prev.bamf.overrideAttrs (upstream: {
|
# bamf = prev.bamf.overrideAttrs (upstream: {
|
||||||
# # "You must have gtk-doc >= 1.0 installed to build documentation"
|
# # "You must have gtk-doc >= 1.0 installed to build documentation"
|
||||||
@@ -186,7 +171,7 @@ in with final; {
|
|||||||
# shell = runtimeShell;
|
# shell = runtimeShell;
|
||||||
# };
|
# };
|
||||||
|
|
||||||
# 2024/05/31: upstreaming blocked by appstream, qtsvg
|
# 2024/08/12: upstreaming is blocked on libgweather, via evolution-data-server
|
||||||
# fixes: "Exec format error: './calls-scan'"
|
# fixes: "Exec format error: './calls-scan'"
|
||||||
calls = prev.calls.overrideAttrs (upstream: {
|
calls = prev.calls.overrideAttrs (upstream: {
|
||||||
# TODO: try building with mesonEmulatorHook when i upstream this
|
# TODO: try building with mesonEmulatorHook when i upstream this
|
||||||
@@ -197,16 +182,7 @@ in with final; {
|
|||||||
mesonFlags = lib.remove "-Dgtk_doc=true" upstream.mesonFlags;
|
mesonFlags = lib.remove "-Dgtk_doc=true" upstream.mesonFlags;
|
||||||
});
|
});
|
||||||
|
|
||||||
# 2024/05/31: upstreaming is blocked by qtsvg, appstream
|
# 2024/08/12: upstreaming is unblocked
|
||||||
# clapper = prev.clapper.overrideAttrs (upstream: {
|
|
||||||
# # use the host gjs (meson's find_program expects it to be executable)
|
|
||||||
# postPatch = (upstream.postPatch or "") + ''
|
|
||||||
# substituteInPlace bin/meson.build \
|
|
||||||
# --replace "find_program('gjs').path()" "'${gjs}/bin/gjs'"
|
|
||||||
# '';
|
|
||||||
# });
|
|
||||||
|
|
||||||
# 2024/05/31: upstreaming is blocked by qtsvg, appstream
|
|
||||||
delfin = prev.delfin.overrideAttrs (upstream: {
|
delfin = prev.delfin.overrideAttrs (upstream: {
|
||||||
nativeBuildInputs = upstream.nativeBuildInputs ++ [
|
nativeBuildInputs = upstream.nativeBuildInputs ++ [
|
||||||
# fixes: loaders/meson.build:72:7: ERROR: Program 'msgfmt' not found or not executable
|
# fixes: loaders/meson.build:72:7: ERROR: Program 'msgfmt' not found or not executable
|
||||||
@@ -219,7 +195,7 @@ in with final; {
|
|||||||
'';
|
'';
|
||||||
});
|
});
|
||||||
|
|
||||||
# 2024/05/31: upstreaming is blocked by qtsvg, appstream
|
# 2024/08/12: upstreaming is unblocked
|
||||||
dialect = prev.dialect.overrideAttrs (upstream: {
|
dialect = prev.dialect.overrideAttrs (upstream: {
|
||||||
# blueprint-compiler runs on the build machine, but tries to load gobject-introspection types meant for the host.
|
# blueprint-compiler runs on the build machine, but tries to load gobject-introspection types meant for the host.
|
||||||
postPatch = (upstream.postPatch or "") + ''
|
postPatch = (upstream.postPatch or "") + ''
|
||||||
@@ -253,6 +229,7 @@ in with final; {
|
|||||||
# binutils = binutils-unwrapped;
|
# binutils = binutils-unwrapped;
|
||||||
# };
|
# };
|
||||||
|
|
||||||
|
# 2024/08/12: upstreaming is unblocked
|
||||||
# emacs = prev.emacs.override {
|
# emacs = prev.emacs.override {
|
||||||
# nativeComp = false; # will be renamed to `withNativeCompilation` in future
|
# nativeComp = false; # will be renamed to `withNativeCompilation` in future
|
||||||
# # future: we can specify 'action-if-cross-compiling' to actually invoke the test programs:
|
# # future: we can specify 'action-if-cross-compiling' to actually invoke the test programs:
|
||||||
@@ -292,15 +269,11 @@ in with final; {
|
|||||||
# ];
|
# ];
|
||||||
});
|
});
|
||||||
|
|
||||||
fd = prev.fd.overrideAttrs (base: {
|
# 2024/08/12: upstreaming is blocked on gnome-user-share (apache-httpd)
|
||||||
# fix that shell completion installation wants to run host fd
|
# fixes: "src/meson.build:106:0: ERROR: Program 'glib-compile-resources' not found or not executable"
|
||||||
postInstall = lib.replaceStrings
|
# file-roller = mvToNativeInputs [ glib ] prev.file-roller;
|
||||||
[ "$out/bin/fd" ]
|
|
||||||
[ "${stdenv.hostPlatform.emulator buildPackages} $out/bin/fd" ]
|
|
||||||
base.postInstall;
|
|
||||||
});
|
|
||||||
|
|
||||||
# 2024/05/31: upstreaming is unblocked
|
# 2024/08/12: upstreaming is unblocked
|
||||||
# firejail = prev.firejail.overrideAttrs (upstream: {
|
# firejail = prev.firejail.overrideAttrs (upstream: {
|
||||||
# # firejail executes its build outputs to produce the default filter list.
|
# # firejail executes its build outputs to produce the default filter list.
|
||||||
# # i think we *could* copy the default filters from pkgsBuildBuild, but that doesn't seem future proof
|
# # i think we *could* copy the default filters from pkgsBuildBuild, but that doesn't seem future proof
|
||||||
@@ -314,33 +287,40 @@ in with final; {
|
|||||||
# '');
|
# '');
|
||||||
# });
|
# });
|
||||||
|
|
||||||
# 2024/05/31: upstreaming is blocked by qtsvg, appstream
|
# 2024/08/12: upstreaming is unblocked
|
||||||
flare-signal = prev.flare-signal.overrideAttrs (upstream: {
|
# flare-signal = prev.flare-signal.overrideAttrs (upstream: {
|
||||||
# blueprint-compiler runs on the build machine, but tries to load gobject-introspection types meant for the host.
|
# # blueprint-compiler runs on the build machine, but tries to load gobject-introspection types meant for the host.
|
||||||
postPatch = (upstream.postPatch or "") + ''
|
# postPatch = (upstream.postPatch or "") + ''
|
||||||
substituteInPlace data/resources/meson.build --replace-fail \
|
# substituteInPlace data/resources/meson.build --replace-fail \
|
||||||
"find_program('blueprint-compiler')" \
|
# "find_program('blueprint-compiler')" \
|
||||||
"'env', 'GI_TYPELIB_PATH=${buildPackages.gdk-pixbuf.out}/lib/girepository-1.0:${buildPackages.harfbuzz.out}/lib/girepository-1.0:${buildPackages.gtk4.out}/lib/girepository-1.0:${buildPackages.graphene}/lib/girepository-1.0:${buildPackages.libadwaita}/lib/girepository-1.0:${buildPackages.pango.out}/lib/girepository-1.0', find_program('blueprint-compiler')"
|
# "'env', 'GI_TYPELIB_PATH=${typelibPath [
|
||||||
'';
|
# buildPackages.gdk-pixbuf
|
||||||
env = let
|
# buildPackages.harfbuzz
|
||||||
inherit buildPackages stdenv rust;
|
# buildPackages.gtk4
|
||||||
ccForBuild = "${buildPackages.stdenv.cc}/bin/${buildPackages.stdenv.cc.targetPrefix}cc";
|
# buildPackages.libadwaita
|
||||||
cxxForBuild = "${buildPackages.stdenv.cc}/bin/${buildPackages.stdenv.cc.targetPrefix}c++";
|
# buildPackages.pango
|
||||||
ccForHost = "${stdenv.cc}/bin/${stdenv.cc.targetPrefix}cc";
|
# buildPackages.graphene
|
||||||
cxxForHost = "${stdenv.cc}/bin/${stdenv.cc.targetPrefix}c++";
|
# ]}', find_program('blueprint-compiler')"
|
||||||
rustBuildPlatform = rust.toRustTarget stdenv.buildPlatform;
|
# '';
|
||||||
rustTargetPlatform = rust.toRustTarget stdenv.hostPlatform;
|
# env = let
|
||||||
rustTargetPlatformSpec = rust.toRustTargetSpec stdenv.hostPlatform;
|
# inherit buildPackages stdenv rust;
|
||||||
in {
|
# ccForBuild = "${buildPackages.stdenv.cc}/bin/${buildPackages.stdenv.cc.targetPrefix}cc";
|
||||||
# taken from <pkgs/build-support/rust/hooks/default.nix>
|
# cxxForBuild = "${buildPackages.stdenv.cc}/bin/${buildPackages.stdenv.cc.targetPrefix}c++";
|
||||||
# fixes "cargo:warning=aarch64-unknown-linux-gnu-gcc: error: unrecognized command-line option ‘-m64’"
|
# ccForHost = "${stdenv.cc}/bin/${stdenv.cc.targetPrefix}cc";
|
||||||
# XXX: these aren't necessarily valid environment variables: the referenced nix file is more clever to get them to work.
|
# cxxForHost = "${stdenv.cc}/bin/${stdenv.cc.targetPrefix}c++";
|
||||||
"CC_${rustBuildPlatform}" = "${ccForBuild}";
|
# rustBuildPlatform = rust.toRustTarget stdenv.buildPlatform;
|
||||||
"CXX_${rustBuildPlatform}" = "${cxxForBuild}";
|
# rustTargetPlatform = rust.toRustTarget stdenv.hostPlatform;
|
||||||
"CC_${rustTargetPlatform}" = "${ccForHost}";
|
# rustTargetPlatformSpec = rust.toRustTargetSpec stdenv.hostPlatform;
|
||||||
"CXX_${rustTargetPlatform}" = "${cxxForHost}";
|
# in {
|
||||||
};
|
# # taken from <pkgs/build-support/rust/hooks/default.nix>
|
||||||
});
|
# # fixes "cargo:warning=aarch64-unknown-linux-gnu-gcc: error: unrecognized command-line option ‘-m64’"
|
||||||
|
# # XXX: these aren't necessarily valid environment variables: the referenced nix file is more clever to get them to work.
|
||||||
|
# "CC_${rustBuildPlatform}" = "${ccForBuild}";
|
||||||
|
# "CXX_${rustBuildPlatform}" = "${cxxForBuild}";
|
||||||
|
# "CC_${rustTargetPlatform}" = "${ccForHost}";
|
||||||
|
# "CXX_${rustTargetPlatform}" = "${cxxForHost}";
|
||||||
|
# };
|
||||||
|
# });
|
||||||
|
|
||||||
flare-signal-nixified = prev.flare-signal-nixified.overrideAttrs (upstream: {
|
flare-signal-nixified = prev.flare-signal-nixified.overrideAttrs (upstream: {
|
||||||
# blueprint-compiler runs on the build machine, but tries to load gobject-introspection types meant for the host.
|
# blueprint-compiler runs on the build machine, but tries to load gobject-introspection types meant for the host.
|
||||||
@@ -359,31 +339,31 @@ in with final; {
|
|||||||
'';
|
'';
|
||||||
});
|
});
|
||||||
|
|
||||||
# 2024/05/31: upstreaming is blocked on appstream
|
# 2024/08/12: upstreaming is unblocked, implemented on `pr-flatpak-cross`, out for PR: <https://github.com/NixOS/nixpkgs/pull/334324>
|
||||||
flatpak = prev.flatpak.overrideAttrs (upstream: {
|
# flatpak = prev.flatpak.overrideAttrs (upstream: {
|
||||||
# fixes "No package 'libxml-2.0' found"
|
# # fixes "No package 'libxml-2.0' found"
|
||||||
buildInputs = upstream.buildInputs ++ [ libxml2 ];
|
# buildInputs = upstream.buildInputs ++ [ libxml2 ];
|
||||||
configureFlags = upstream.configureFlags ++ [
|
# configureFlags = upstream.configureFlags ++ [
|
||||||
"--enable-selinux-module=no" # fixes "checking for /usr/share/selinux/devel/Makefile... configure: error: cannot check for file existence when cross compiling"
|
# "--enable-selinux-module=no" # fixes "checking for /usr/share/selinux/devel/Makefile... configure: error: cannot check for file existence when cross compiling"
|
||||||
"--disable-gtk-doc" # fixes "You must have gtk-doc >= 1.20 installed to build documentation for Flatpak"
|
# "--disable-gtk-doc" # fixes "You must have gtk-doc >= 1.20 installed to build documentation for Flatpak"
|
||||||
];
|
# ];
|
||||||
|
|
||||||
postPatch = let
|
# postPatch = let
|
||||||
# copied from nixpkgs flatpak and modified to use buildPackages python
|
# # copied from nixpkgs flatpak and modified to use buildPackages python
|
||||||
vsc-py = buildPackages.python3.withPackages (pp: [
|
# vsc-py = buildPackages.python3.withPackages (pp: [
|
||||||
pp.pyparsing
|
# pp.pyparsing
|
||||||
]);
|
# ]);
|
||||||
in ''
|
# in ''
|
||||||
patchShebangs buildutil
|
# patchShebangs buildutil
|
||||||
patchShebangs tests
|
# patchShebangs tests
|
||||||
PATH=${lib.makeBinPath [vsc-py]}:$PATH patchShebangs --build subprojects/variant-schema-compiler/variant-schema-compiler
|
# PATH=${lib.makeBinPath [vsc-py]}:$PATH patchShebangs --build subprojects/variant-schema-compiler/variant-schema-compiler
|
||||||
'' + ''
|
# '' + ''
|
||||||
sed -i s:'\$BWRAP --version:${stdenv.hostPlatform.emulator buildPackages} \$BWRAP --version:' configure.ac
|
# sed -i s:'\$BWRAP --version:${stdenv.hostPlatform.emulator buildPackages} \$BWRAP --version:' configure.ac
|
||||||
sed -i s:'\$DBUS_PROXY --version:${stdenv.hostPlatform.emulator buildPackages} \$DBUS_PROXY --version:' configure.ac
|
# sed -i s:'\$DBUS_PROXY --version:${stdenv.hostPlatform.emulator buildPackages} \$DBUS_PROXY --version:' configure.ac
|
||||||
'';
|
# '';
|
||||||
});
|
# });
|
||||||
|
|
||||||
# 2024/05/31: upstreaming is blocked by qtsvg, appstream
|
# 2024/08/12: upstreaming is blocked by xdg-desktop-portal
|
||||||
fractal = prev.fractal.overrideAttrs (upstream: {
|
fractal = prev.fractal.overrideAttrs (upstream: {
|
||||||
postPatch = (upstream.postPatch or "") + ''
|
postPatch = (upstream.postPatch or "") + ''
|
||||||
substituteInPlace src/meson.build \
|
substituteInPlace src/meson.build \
|
||||||
@@ -393,7 +373,7 @@ in with final; {
|
|||||||
});
|
});
|
||||||
|
|
||||||
# solves (meson) "Run-time dependency libgcab-1.0 found: NO (tried pkgconfig and cmake)", and others.
|
# solves (meson) "Run-time dependency libgcab-1.0 found: NO (tried pkgconfig and cmake)", and others.
|
||||||
# 2024/05/31: upstreaming is unblocked
|
# 2024/08/12: upstreaming is unblocked
|
||||||
# fwupd = (addBuildInputs
|
# fwupd = (addBuildInputs
|
||||||
# [ gcab ]
|
# [ gcab ]
|
||||||
# (mvToBuildInputs [ gnutls ] prev.fwupd)
|
# (mvToBuildInputs [ gnutls ] prev.fwupd)
|
||||||
@@ -405,17 +385,7 @@ in with final; {
|
|||||||
# outputs = lib.remove "devdoc" upstream.outputs;
|
# outputs = lib.remove "devdoc" upstream.outputs;
|
||||||
# });
|
# });
|
||||||
|
|
||||||
# 2024/05/31: upstreaming is blocked on qtsvg (via pipewire)
|
# 2024/08/12: upstreaming is blocked by libgweather (out for review) via evolution-data-server
|
||||||
# required by epiphany, gnome-settings-daemon
|
|
||||||
# N.B.: should be able to remove gnupg/ssh from {native}buildInputs when upstreaming
|
|
||||||
gcr_4 = prev.gcr_4.overrideAttrs (upstream: {
|
|
||||||
# fixes (meson): "ERROR: Program 'gpg2 gpg' not found or not executable"
|
|
||||||
mesonFlags = (upstream.mesonFlags or []) ++ [
|
|
||||||
"-Dgpg_path=${gnupg}/bin/gpg"
|
|
||||||
];
|
|
||||||
});
|
|
||||||
|
|
||||||
# 2024/05/31: upstreaming is blocked by qtsvg, appstream (out for review), libgweather (out for review)
|
|
||||||
geary = prev.geary.overrideAttrs (upstream: {
|
geary = prev.geary.overrideAttrs (upstream: {
|
||||||
buildInputs = upstream.buildInputs ++ [
|
buildInputs = upstream.buildInputs ++ [
|
||||||
# glib
|
# glib
|
||||||
@@ -465,27 +435,34 @@ in with final; {
|
|||||||
'';
|
'';
|
||||||
});
|
});
|
||||||
|
|
||||||
|
# 2024/08/12: upstreaming is blocked on gnome-user-share (apache-httpd)
|
||||||
|
# gnome-terminal = prev.gnome-terminal.overrideAttrs (orig: {
|
||||||
|
# # fixes "meson.build:343:0: ERROR: Dependency "libpcre2-8" not found, tried pkgconfig"
|
||||||
|
# buildInputs = orig.buildInputs ++ [ pcre2 ];
|
||||||
|
# });
|
||||||
|
|
||||||
# 2024/05/08: fix: "meson.build:85:11: ERROR: Dependency "dbus-1" not found, tried pkgconfig".
|
# 2024/05/08: fix: "meson.build:85:11: ERROR: Dependency "dbus-1" not found, tried pkgconfig".
|
||||||
# 2024/05/31: upstreaming is blocked by qtsvg, appstream
|
# 2024/08/12: upstreaming is unblocked
|
||||||
gnome-online-accounts = mvToBuildInputs [ dbus ] prev.gnome-online-accounts;
|
gnome-online-accounts = mvToBuildInputs [ dbus ] prev.gnome-online-accounts;
|
||||||
|
|
||||||
gnome = prev.gnome.overrideScope (self: super: {
|
# 2024/08/12: upstreaming is blocked on apache-httpd (via mod_dnssd)
|
||||||
# 2024/05/31: upstreaming is blocked on appstream (out for review), gnome-user-share (apache-httpd, webp-pixbuf-loader), qtsvg
|
# fixes: meson.build:111:6: ERROR: Program 'glib-compile-schemas' not found or not executable
|
||||||
# fixes: "src/meson.build:106:0: ERROR: Program 'glib-compile-resources' not found or not executable"
|
# gnome-user-share = addNativeInputs [ glib ] prev.gnome-user-share;
|
||||||
# file-roller = mvToNativeInputs [ glib ] super.file-roller;
|
|
||||||
|
|
||||||
|
gnome = prev.gnome.overrideScope (self: super: {
|
||||||
# 2024/05/31: upstreaming is blocked by a LOT: qtbase, qtsvg, webp-pixbuf-loader, libgweather, gnome-color-manager, appstream, apache-httpd, ibus
|
# 2024/05/31: upstreaming is blocked by a LOT: qtbase, qtsvg, webp-pixbuf-loader, libgweather, gnome-color-manager, appstream, apache-httpd, ibus
|
||||||
# fixes "subprojects/gvc/meson.build:30:0: ERROR: Program 'glib-mkenums mkenums' not found or not executable"
|
# fixes "subprojects/gvc/meson.build:30:0: ERROR: Program 'glib-mkenums mkenums' not found or not executable"
|
||||||
# gnome-control-center = mvToNativeInputs [ glib ] super.gnome-control-center;
|
# gnome-control-center = mvToNativeInputs [ glib ] super.gnome-control-center;
|
||||||
|
|
||||||
gnome-maps = super.gnome-maps.overrideAttrs (upstream: {
|
gnome-maps = super.gnome-maps.overrideAttrs (upstream: {
|
||||||
# 2024/05/31: upstreaming is blocked by libgweather, appstream, qtsvg (via pipewire/ffado)
|
# 2024/08/12: upstreaming is blocked by libgweather (direct dependency)
|
||||||
postPatch = (upstream.postPatch or "") + ''
|
postPatch = (upstream.postPatch or "") + ''
|
||||||
# fixes: "ERROR: Program 'gjs' not found or not executable"
|
# fixes: "ERROR: Program 'gjs' not found or not executable"
|
||||||
substituteInPlace meson.build \
|
substituteInPlace meson.build \
|
||||||
--replace-fail "find_program('gjs')" "find_program('${gjs}/bin/gjs')"
|
--replace-fail "find_program('gjs')" "find_program('${gjs}/bin/gjs')"
|
||||||
'';
|
'';
|
||||||
});
|
});
|
||||||
|
# 2024/08/12: upstreaming is blocked on ibus, libgweather
|
||||||
# gnome-shell = super.gnome-shell.overrideAttrs (orig: {
|
# gnome-shell = super.gnome-shell.overrideAttrs (orig: {
|
||||||
# # fixes "meson.build:128:0: ERROR: Program 'gjs' not found or not executable"
|
# # fixes "meson.build:128:0: ERROR: Program 'gjs' not found or not executable"
|
||||||
# # does not fix "_giscanner.cpython-310-x86_64-linux-gnu.so: cannot open shared object file: No such file or directory" (python import failure)
|
# # does not fix "_giscanner.cpython-310-x86_64-linux-gnu.so: cannot open shared object file: No such file or directory" (python import failure)
|
||||||
@@ -505,13 +482,12 @@ in with final; {
|
|||||||
# # ];
|
# # ];
|
||||||
# });
|
# });
|
||||||
# gnome-shell = super.gnome-shell.overrideAttrs (upstream: {
|
# gnome-shell = super.gnome-shell.overrideAttrs (upstream: {
|
||||||
# # 2024/05/31: upstreaming is blocked on qtsvg, appstream, webp-pixbuf-loader, libgweather, ibus
|
|
||||||
# nativeBuildInputs = upstream.nativeBuildInputs ++ [
|
# nativeBuildInputs = upstream.nativeBuildInputs ++ [
|
||||||
# gjs # fixes "meson.build:128:0: ERROR: Program 'gjs' not found or not executable"
|
# gjs # fixes "meson.build:128:0: ERROR: Program 'gjs' not found or not executable"
|
||||||
# ];
|
# ];
|
||||||
# });
|
# });
|
||||||
gnome-settings-daemon = super.gnome-settings-daemon.overrideAttrs (orig: {
|
gnome-settings-daemon = super.gnome-settings-daemon.overrideAttrs (orig: {
|
||||||
# 2024/05/31: upstreaming is blocked on qtsvg (ffado), libgweather
|
# 2024/08/11: upstreaming is blocked on libgweather
|
||||||
# gsd is required by xdg-desktop-portal-gtk
|
# gsd is required by xdg-desktop-portal-gtk
|
||||||
# pkg-config solves: "plugins/power/meson.build:22:0: ERROR: Dependency lookup for glib-2.0 with method 'pkgconfig' failed: Pkg-config binary for machine build machine not found."
|
# pkg-config solves: "plugins/power/meson.build:22:0: ERROR: Dependency lookup for glib-2.0 with method 'pkgconfig' failed: Pkg-config binary for machine build machine not found."
|
||||||
# stdenv.cc fixes: "plugins/power/meson.build:60:0: ERROR: No build machine compiler for 'plugins/power/gsd-power-enums-update.c'"
|
# stdenv.cc fixes: "plugins/power/meson.build:60:0: ERROR: No build machine compiler for 'plugins/power/gsd-power-enums-update.c'"
|
||||||
@@ -530,20 +506,12 @@ in with final; {
|
|||||||
# '';
|
# '';
|
||||||
# });
|
# });
|
||||||
|
|
||||||
# 2023/08/01: upstreaming is blocked on argyllcms, gnome-keyring, gnome-clocks, ibus, libavif, webp-pixbuf-loader (gnome-shell)
|
# 2024/08/12: upstreaming is blocked on gnome-shell (ibus, libgweather)
|
||||||
# fixes: "gdbus-codegen not found or executable"
|
# fixes: "gdbus-codegen not found or executable"
|
||||||
# gnome-session = mvToNativeInputs [ glib ] super.gnome-session;
|
# gnome-session = mvToNativeInputs [ glib ] super.gnome-session;
|
||||||
# gnome-terminal = super.gnome-terminal.overrideAttrs (orig: {
|
|
||||||
# # 2023/07/31: upstreaming is blocked on argyllcms, apache-httpd, gnome-keyring, libavif, gnome-clocks, ibus, webp-pixbuf-loader
|
|
||||||
# # fixes "meson.build:343:0: ERROR: Dependency "libpcre2-8" not found, tried pkgconfig"
|
|
||||||
# buildInputs = orig.buildInputs ++ [ pcre2 ];
|
|
||||||
# });
|
|
||||||
# 2023/07/31: upstreaming is blocked on apache-httpd
|
|
||||||
# fixes: meson.build:111:6: ERROR: Program 'glib-compile-schemas' not found or not executable
|
|
||||||
# gnome-user-share = addNativeInputs [ glib ] super.gnome-user-share;
|
|
||||||
|
|
||||||
# mutter = super.mutter.overrideAttrs (orig: {
|
# mutter = super.mutter.overrideAttrs (orig: {
|
||||||
# # 2024/02/27: upstreaming is blocked on appstream, possibly others
|
# # 2024/08/12: upstreaming is blocked on libgweather (via gnome-settings-daemon)
|
||||||
# # N.B.: not all of this suitable to upstreaming, as-is.
|
# # N.B.: not all of this suitable to upstreaming, as-is.
|
||||||
# # mesa and xorgserver are removed here because they *themselves* don't build for `buildPackages` (temporarily: 2023/10/26)
|
# # mesa and xorgserver are removed here because they *themselves* don't build for `buildPackages` (temporarily: 2023/10/26)
|
||||||
# nativeBuildInputs = lib.subtractLists [ mesa xorg.xorgserver ] orig.nativeBuildInputs;
|
# nativeBuildInputs = lib.subtractLists [ mesa xorg.xorgserver ] orig.nativeBuildInputs;
|
||||||
@@ -556,15 +524,6 @@ in with final; {
|
|||||||
# outputs = lib.remove "devdoc" orig.outputs;
|
# outputs = lib.remove "devdoc" orig.outputs;
|
||||||
# postInstall = lib.replaceStrings [ "${glib.dev}" ] [ "${buildPackages.glib.dev}" ] orig.postInstall;
|
# postInstall = lib.replaceStrings [ "${glib.dev}" ] [ "${buildPackages.glib.dev}" ] orig.postInstall;
|
||||||
# });
|
# });
|
||||||
# nautilus = (
|
|
||||||
# # 2023/11/21: upstreaming is blocked on apache-httpd, webp-pixbuf-loader, qtsvg
|
|
||||||
# addInputs {
|
|
||||||
# # fixes: "meson.build:123:0: ERROR: Dependency "libxml-2.0" not found, tried pkgconfig"
|
|
||||||
# buildInputs = [ libxml2 ];
|
|
||||||
# # fixes: "meson.build:226:6: ERROR: Program 'gtk-update-icon-cache' not found or not executable"
|
|
||||||
# nativeBuildInputs = [ gtk4 ];
|
|
||||||
# }
|
|
||||||
# );
|
|
||||||
});
|
});
|
||||||
|
|
||||||
# gnome2 = prev.gnome2.overrideScope (self: super: {
|
# gnome2 = prev.gnome2.overrideScope (self: super: {
|
||||||
@@ -576,9 +535,6 @@ in with final; {
|
|||||||
# # );
|
# # );
|
||||||
# });
|
# });
|
||||||
|
|
||||||
# 2024-07-28: out for PR: <https://github.com/NixOS/nixpkgs/pull/330681>
|
|
||||||
hiredis = mvToBuildInputs [ openssl ] prev.hiredis;
|
|
||||||
|
|
||||||
# out for PR: <https://github.com/NixOS/nixpkgs/pull/263182>
|
# out for PR: <https://github.com/NixOS/nixpkgs/pull/263182>
|
||||||
# hspell = prev.hspell.overrideAttrs (upstream: {
|
# hspell = prev.hspell.overrideAttrs (upstream: {
|
||||||
# # build perl is needed by the Makefile,
|
# # build perl is needed by the Makefile,
|
||||||
@@ -589,7 +545,7 @@ in with final; {
|
|||||||
# '';
|
# '';
|
||||||
# });
|
# });
|
||||||
|
|
||||||
# 2024/05/31: upstreaming is unblocked
|
# 2024/08/12: upstreaming is unblocked
|
||||||
# hyprland = mvToNativeInputs [ hwdata ] prev.hyprland;
|
# hyprland = mvToNativeInputs [ hwdata ] prev.hyprland;
|
||||||
# hyprland = prev.hyprland.overrideAttrs (_: {
|
# hyprland = prev.hyprland.overrideAttrs (_: {
|
||||||
# depsBuildBuild = [ pkg-config ];
|
# depsBuildBuild = [ pkg-config ];
|
||||||
@@ -599,7 +555,7 @@ in with final; {
|
|||||||
# "setup: line 1595: ant: command not found"
|
# "setup: line 1595: ant: command not found"
|
||||||
# i2p = mvToNativeInputs [ ant gettext ] prev.i2p;
|
# i2p = mvToNativeInputs [ ant gettext ] prev.i2p;
|
||||||
|
|
||||||
# 2024/05/31: upstreaming is unblocked (see `pkgs/patched/ibus`)
|
# 2024/08/12: upstreaming is unblocked (see `pkgs/patched/ibus`)
|
||||||
# ibus = prev.ibus.overrideAttrs (upstream: {
|
# ibus = prev.ibus.overrideAttrs (upstream: {
|
||||||
# nativeBuildInputs = upstream.nativeBuildInputs or [] ++ [
|
# nativeBuildInputs = upstream.nativeBuildInputs or [] ++ [
|
||||||
# glib # fixes: ImportError: /nix/store/fi1rsalr11xg00dqwgzbf91jpl3zwygi-gobject-introspection-aarch64-unknown-linux-gnu-1.74.0/lib/gobject-introspection/giscanner/_giscanner.cpython-310-x86_64-linux-gnu.so: cannot open shared object file: No such file or directory
|
# glib # fixes: ImportError: /nix/store/fi1rsalr11xg00dqwgzbf91jpl3zwygi-gobject-introspection-aarch64-unknown-linux-gnu-1.74.0/lib/gobject-introspection/giscanner/_giscanner.cpython-310-x86_64-linux-gnu.so: cannot open shared object file: No such file or directory
|
||||||
@@ -610,7 +566,7 @@ in with final; {
|
|||||||
# ];
|
# ];
|
||||||
# });
|
# });
|
||||||
|
|
||||||
# 2024/05/31: upstreaming is blocked on appstream, qtsvg, lua, unicode-collation, etc
|
# 2024/08/12: upstreaming is blocked on lua, lpeg, pandoc, unicode-collation, etc
|
||||||
iotas = prev.iotas.overrideAttrs (_: {
|
iotas = prev.iotas.overrideAttrs (_: {
|
||||||
# error: "<iotas> is not allowed to refer to the following paths: <build python>"
|
# error: "<iotas> is not allowed to refer to the following paths: <build python>"
|
||||||
# disallowedReferences = [];
|
# disallowedReferences = [];
|
||||||
@@ -638,7 +594,7 @@ in with final; {
|
|||||||
# nativeBuildInputs = lib.remove [ qt6.wrapQtAppsHook ] upstream.nativeBuildInputs;
|
# nativeBuildInputs = lib.remove [ qt6.wrapQtAppsHook ] upstream.nativeBuildInputs;
|
||||||
# });
|
# });
|
||||||
|
|
||||||
# 2024/05/31: upstreaming is blocked by qtsvg, appstream
|
# 2024/08/12: upstreaming is unblocked
|
||||||
komikku = prev.komikku.overrideAttrs (upstream: {
|
komikku = prev.komikku.overrideAttrs (upstream: {
|
||||||
# blueprint-compiler runs on the build machine, but tries to load gobject-introspection types meant for the host.
|
# blueprint-compiler runs on the build machine, but tries to load gobject-introspection types meant for the host.
|
||||||
postPatch = (upstream.postPatch or "") + ''
|
postPatch = (upstream.postPatch or "") + ''
|
||||||
@@ -656,26 +612,20 @@ in with final; {
|
|||||||
'';
|
'';
|
||||||
});
|
});
|
||||||
|
|
||||||
|
# 2024/08/12: upstreaming is unblocked -- but is this necessary?
|
||||||
# koreader = prev.koreader.overrideAttrs (upstream: {
|
# koreader = prev.koreader.overrideAttrs (upstream: {
|
||||||
# nativeBuildInputs = upstream.nativeBuildInputs ++ [
|
# nativeBuildInputs = upstream.nativeBuildInputs ++ [
|
||||||
# autoPatchelfHook
|
# autoPatchelfHook
|
||||||
# ];
|
# ];
|
||||||
# });
|
# });
|
||||||
|
|
||||||
lemoa = prev.lemoa.overrideAttrs (upstream:
|
lemoa = (prev.lemoa.override { cargo = crossCargo; }).overrideAttrs (upstream:
|
||||||
let
|
let
|
||||||
rustTargetPlatform = rust.toRustTarget stdenv.hostPlatform;
|
rustTargetPlatform = rust.toRustTarget stdenv.hostPlatform;
|
||||||
in {
|
in {
|
||||||
# nixpkgs sets CARGO_BUILD_TARGET to the build platform target, so correct that.
|
preBuild = ''
|
||||||
buildPhase = ''
|
|
||||||
runHook preBuild
|
|
||||||
|
|
||||||
mkdir -p target/release
|
mkdir -p target/release
|
||||||
ln -s ../${rustTargetPlatform}/release/lemoa target/release/lemoa
|
ln -s ../${rustTargetPlatform}/release/lemoa target/release/lemoa
|
||||||
|
|
||||||
${rust.envVars.setEnv} "CARGO_BUILD_TARGET=${rustTargetPlatform}" ninja -j$NIX_BUILD_CORES
|
|
||||||
|
|
||||||
runHook postBuild
|
|
||||||
'';
|
'';
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -711,22 +661,12 @@ in with final; {
|
|||||||
# '';
|
# '';
|
||||||
# });
|
# });
|
||||||
|
|
||||||
# 2024/05/31: upstreaming is blocked on appstream
|
# 2024/08/12: upstreaming is unblocked
|
||||||
# libpanel = prev.libpanel.overrideAttrs (upstream: {
|
libpeas2 = prev.libpeas2.overrideAttrs (upstream: {
|
||||||
# doCheck = false;
|
mesonFlags = upstream.mesonFlags ++ [
|
||||||
# # depsBuildBuild = (upstream.depsBuildBuild or []) ++ [
|
"-Dlua51=false" #< fails to find lua (probably it incorrectly checks the build machine)
|
||||||
# # # fixes "Build-time dependency gi-docgen found: NO (tried pkgconfig and cmake)"
|
];
|
||||||
# # pkg-config
|
});
|
||||||
# # ];
|
|
||||||
# nativeBuildInputs = upstream.nativeBuildInputs ++ [
|
|
||||||
# buildPackages.gtk4 # fixes "ERROR: Program 'gtk-update-icon-cache' not found or not executable"
|
|
||||||
# ];
|
|
||||||
# # it can't figure out where gi-docgen lives
|
|
||||||
# mesonFlags = (upstream.mesonFlags or []) ++ [
|
|
||||||
# "-Ddocs=disabled"
|
|
||||||
# ];
|
|
||||||
# outputs = lib.remove "devdoc" upstream.outputs;
|
|
||||||
# });
|
|
||||||
|
|
||||||
# libsForQt5 = prev.libsForQt5.overrideScope (self: super: {
|
# libsForQt5 = prev.libsForQt5.overrideScope (self: super: {
|
||||||
# phonon = super.phonon.overrideAttrs (orig: {
|
# phonon = super.phonon.overrideAttrs (orig: {
|
||||||
@@ -741,33 +681,7 @@ in with final; {
|
|||||||
# callPackage = self.newScope { inherit (self) qtCompatVersion qtModule srcs; inherit stdenv; };
|
# callPackage = self.newScope { inherit (self) qtCompatVersion qtModule srcs; inherit stdenv; };
|
||||||
# });
|
# });
|
||||||
|
|
||||||
# 2024/05/31: better fix is to use CMAKE_CROSSCOMPILING_EMULATOR
|
# 2024/08/12: upstreaming blocked on libgweather
|
||||||
# - <https://github.com/uninsane/nixpkgs/pull/new/pr-libphonenumber-cross>
|
|
||||||
# libphonenumber = prev.libphonenumber.overrideAttrs (upstream: {
|
|
||||||
# # fix that phone number geolocation binary doesn't cross compile.
|
|
||||||
# # it's CMAKE, and a google project, so the fix to cross compile is unlikely to *ever* make it upstream.
|
|
||||||
# # see: <https://github.com/google/libphonenumber/pull/2604>
|
|
||||||
# #
|
|
||||||
# # the main (only?) user of this library is evolution-data-server,
|
|
||||||
# # which is consumed by gnome-calender, calls, planify.
|
|
||||||
# # maybe i can purge EDS from my system somehow.
|
|
||||||
# # - geary: package doesn't even have EDS as an input; it speaks to it over dbus.
|
|
||||||
# # - calls: package has EDS as input (unused?); speaks to it over dbus.
|
|
||||||
# # - it actually needs EDS though, for its `libebook-contacts` library: <https://gnome.pages.gitlab.gnome.org/evolution-data-server/libebook-contacts/>
|
|
||||||
# # - gnome-calendar: package has EDS as input (unused?); speaks to it over dbus.
|
|
||||||
# # - it actually needs EDS though, for its `libedataserverui4` library: <https://gnome.pages.gitlab.gnome.org/evolution-data-server/libedataserverui4/>
|
|
||||||
# # - planify: package has EDS as input (unused?); speaks to it over dbus.
|
|
||||||
# # - it actually needs EDS though, for its `libecal` library: <https://gnome.pages.gitlab.gnome.org/evolution-data-server/libecal/>
|
|
||||||
# # - it could be using evolution-data-server-gtk4 instead of EDS gtk3 though
|
|
||||||
# #
|
|
||||||
# # or build EDS with `-DWITH_PHONENUMBER=OFF`
|
|
||||||
# cmakeFlags = (upstream.cmakeFlags or []) ++ [
|
|
||||||
# "-DPROTOC_BIN=${lib.getExe buildPackages.protobuf}"
|
|
||||||
# "-DBUILD_GEOCODER=OFF"
|
|
||||||
# ];
|
|
||||||
# });
|
|
||||||
|
|
||||||
# 2024/05/31: upstreaming blocked on qtsvg, libgweather, appstream, glycin-loaders
|
|
||||||
loupe = prev.loupe.overrideAttrs (upstream: {
|
loupe = prev.loupe.overrideAttrs (upstream: {
|
||||||
postPatch = (upstream.postPatch or "") + ''
|
postPatch = (upstream.postPatch or "") + ''
|
||||||
substituteInPlace src/meson.build \
|
substituteInPlace src/meson.build \
|
||||||
@@ -776,7 +690,7 @@ in with final; {
|
|||||||
'';
|
'';
|
||||||
});
|
});
|
||||||
|
|
||||||
# 2024/05/31: upstreaming blocked on qtsvg, appstream, maybe others
|
# 2024/08/12: upstreaming is unblocked
|
||||||
mepo = (prev.mepo.override {
|
mepo = (prev.mepo.override {
|
||||||
# nixpkgs mepo correctly puts `zig_0_12.hook` in nativeBuildInputs,
|
# nixpkgs mepo correctly puts `zig_0_12.hook` in nativeBuildInputs,
|
||||||
# but for some reason that tries to use the host zig instead of the build zig.
|
# but for some reason that tries to use the host zig instead of the build zig.
|
||||||
@@ -812,6 +726,16 @@ in with final; {
|
|||||||
zigBuildFlags = [ "-Dtarget=aarch64-linux-gnu" ];
|
zigBuildFlags = [ "-Dtarget=aarch64-linux-gnu" ];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
# nautilus = (
|
||||||
|
# # 2024/08/12: upstreaming is blocked on apache-httpd (via gnome-user-share)
|
||||||
|
# addInputs {
|
||||||
|
# # fixes: "meson.build:123:0: ERROR: Dependency "libxml-2.0" not found, tried pkgconfig"
|
||||||
|
# buildInputs = [ libxml2 ];
|
||||||
|
# # fixes: "meson.build:226:6: ERROR: Program 'gtk-update-icon-cache' not found or not executable"
|
||||||
|
# nativeBuildInputs = [ gtk4 ];
|
||||||
|
# }
|
||||||
|
# );
|
||||||
|
|
||||||
# fixes: "ar: command not found"
|
# fixes: "ar: command not found"
|
||||||
# `ar` is provided by bintools
|
# `ar` is provided by bintools
|
||||||
# 2024/05/31: upstreaming is unblocked by deps; but turns out to not be this simple
|
# 2024/05/31: upstreaming is unblocked by deps; but turns out to not be this simple
|
||||||
@@ -857,6 +781,68 @@ in with final; {
|
|||||||
# );
|
# );
|
||||||
# 2023/07/31: upstreaming is blocked on vpnc cross compilation
|
# 2023/07/31: upstreaming is blocked on vpnc cross compilation
|
||||||
# networkmanager-vpnc = mvToNativeInputs [ glib ] prev.networkmanager-vpnc;
|
# networkmanager-vpnc = mvToNativeInputs [ glib ] prev.networkmanager-vpnc;
|
||||||
|
|
||||||
|
# 2024/08/12: upstreaming is unblocked
|
||||||
|
newsflash = (prev.newsflash.override {
|
||||||
|
blueprint-compiler = buildPackages.writeShellScriptBin "blueprint-compiler" ''
|
||||||
|
export GI_TYPELIB_PATH=${typelibPath [
|
||||||
|
buildPackages.clapper
|
||||||
|
buildPackages.glib
|
||||||
|
buildPackages.gtk4
|
||||||
|
buildPackages.gst_all_1.gstreamer
|
||||||
|
buildPackages.gst_all_1.gst-plugins-base
|
||||||
|
buildPackages.gdk-pixbuf
|
||||||
|
buildPackages.pango
|
||||||
|
buildPackages.graphene
|
||||||
|
buildPackages.harfbuzz
|
||||||
|
buildPackages.libadwaita
|
||||||
|
]}
|
||||||
|
exec ${lib.getExe buildPackages.blueprint-compiler} "$@"
|
||||||
|
'';
|
||||||
|
cargo = crossCargo; #< fixes openssl not being able to find its library
|
||||||
|
}).overrideAttrs (upstream: {
|
||||||
|
postPatch = (upstream.postPatch or "") + ''
|
||||||
|
substituteInPlace src/meson.build --replace-fail \
|
||||||
|
"'src' / rust_target" \
|
||||||
|
"'src' / '${rust.toRustTarget stdenv.hostPlatform}' / rust_target"
|
||||||
|
|
||||||
|
rm build.rs
|
||||||
|
|
||||||
|
export OUT_DIR=$(pwd)
|
||||||
|
|
||||||
|
# from build.rs:
|
||||||
|
glib-compile-resources --sourcedir=data/resources --target=icons.gresource data/resources/icons.gresource.xml
|
||||||
|
glib-compile-resources --sourcedir=data/resources --target=styles.gresource data/resources/styles.gresource.xml
|
||||||
|
substitute data/io.gitlab.news_flash.NewsFlash.appdata.xml.in.in \
|
||||||
|
data/resources/io.gitlab.news_flash.NewsFlash.appdata.xml \
|
||||||
|
--replace-fail '@appid@' 'io.gitlab.news_flash.NewsFlash'
|
||||||
|
glib-compile-resources --sourcedir=data/resources --target=appdata.gresource data/resources/appdata.gresource.xml
|
||||||
|
'';
|
||||||
|
|
||||||
|
env = let
|
||||||
|
inherit buildPackages stdenv rust;
|
||||||
|
ccForBuild = "${buildPackages.stdenv.cc}/bin/${buildPackages.stdenv.cc.targetPrefix}cc";
|
||||||
|
cxxForBuild = "${buildPackages.stdenv.cc}/bin/${buildPackages.stdenv.cc.targetPrefix}c++";
|
||||||
|
ccForHost = "${stdenv.cc}/bin/${stdenv.cc.targetPrefix}cc";
|
||||||
|
cxxForHost = "${stdenv.cc}/bin/${stdenv.cc.targetPrefix}c++";
|
||||||
|
rustBuildPlatform = rust.toRustTarget stdenv.buildPlatform;
|
||||||
|
rustTargetPlatform = rust.toRustTarget stdenv.hostPlatform;
|
||||||
|
rustTargetPlatformSpec = rust.toRustTargetSpec stdenv.hostPlatform;
|
||||||
|
in (upstream.env or {}) // {
|
||||||
|
# taken from <pkgs/build-support/rust/hooks/default.nix>
|
||||||
|
# fixes "cargo:warning=aarch64-unknown-linux-gnu-gcc: error: unrecognized command-line option ‘-m64’"
|
||||||
|
# XXX: these aren't necessarily valid environment variables: the referenced nix file is more clever to get them to work.
|
||||||
|
"CC_${rustBuildPlatform}" = "${ccForBuild}";
|
||||||
|
"CXX_${rustBuildPlatform}" = "${cxxForBuild}";
|
||||||
|
"CC_${rustTargetPlatform}" = "${ccForHost}";
|
||||||
|
"CXX_${rustTargetPlatform}" = "${cxxForHost}";
|
||||||
|
# fails to fix "Failed to find OpenSSL development headers."
|
||||||
|
# OPENSSL_NO_VENDOR = 1;
|
||||||
|
# OPENSSL_LIB_DIR = "${lib.getLib openssl}/lib";
|
||||||
|
# OPENSSL_DIR = "${lib.getDev openssl}";
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
# fixes "properties/gresource.xml: Permission denied"
|
# fixes "properties/gresource.xml: Permission denied"
|
||||||
# - by providing glib-compile-resources
|
# - by providing glib-compile-resources
|
||||||
# 2024/05/31: upstreaming is blocked on qtsvg, qtimageformats, qtx11extras
|
# 2024/05/31: upstreaming is blocked on qtsvg, qtimageformats, qtx11extras
|
||||||
@@ -927,7 +913,7 @@ in with final; {
|
|||||||
# });
|
# });
|
||||||
|
|
||||||
pantheon = prev.pantheon.overrideScope (self: super: {
|
pantheon = prev.pantheon.overrideScope (self: super: {
|
||||||
# 2024/06/13: upstreaming is blocked by qtsvg/ffado
|
# 2024/08/11: upstreaming is unblocked
|
||||||
switchboard-plug-network = super.switchboard-plug-network.overrideAttrs (upstream: {
|
switchboard-plug-network = super.switchboard-plug-network.overrideAttrs (upstream: {
|
||||||
nativeBuildInputs = upstream.nativeBuildInputs ++ [
|
nativeBuildInputs = upstream.nativeBuildInputs ++ [
|
||||||
buildPackages.gettext # <for msgfmt
|
buildPackages.gettext # <for msgfmt
|
||||||
@@ -951,8 +937,9 @@ in with final; {
|
|||||||
});
|
});
|
||||||
|
|
||||||
# fixes (meson) "Program 'glib-mkenums mkenums' not found or not executable"
|
# fixes (meson) "Program 'glib-mkenums mkenums' not found or not executable"
|
||||||
# 2024/05/31: upstreaming is blocked on appstream, libgweather, qtsvg
|
# 2024/08/12: upstreaming is unblocked
|
||||||
# phoc = mvToNativeInputs [ wayland-scanner glib ] prev.phoc;
|
# phoc = mvToNativeInputs [ wayland-scanner glib ] prev.phoc;
|
||||||
|
# 2024/08/12: upstreaming is blocked on gnome-control-center, evolution-data-server, , ibus, libgweather, gnom-user-share, others
|
||||||
# phosh = prev.phosh.overrideAttrs (upstream: {
|
# phosh = prev.phosh.overrideAttrs (upstream: {
|
||||||
# buildInputs = upstream.buildInputs ++ [
|
# buildInputs = upstream.buildInputs ++ [
|
||||||
# libadwaita # "plugins/meson.build:41:2: ERROR: Dependency "libadwaita-1" not found, tried pkgconfig"
|
# libadwaita # "plugins/meson.build:41:2: ERROR: Dependency "libadwaita-1" not found, tried pkgconfig"
|
||||||
@@ -979,7 +966,9 @@ in with final; {
|
|||||||
# } prev.phosh-mobile-settings;
|
# } prev.phosh-mobile-settings;
|
||||||
|
|
||||||
# 2024/05/31: upstreaming is blocked on qtsvg, appstream
|
# 2024/05/31: upstreaming is blocked on qtsvg, appstream
|
||||||
pwvucontrol = prev.pwvucontrol.overrideAttrs (upstream:
|
pwvucontrol = (prev.pwvucontrol.override {
|
||||||
|
cargo = crossCargo;
|
||||||
|
}).overrideAttrs (upstream:
|
||||||
let
|
let
|
||||||
rustTargetPlatform = rust.toRustTarget stdenv.hostPlatform;
|
rustTargetPlatform = rust.toRustTarget stdenv.hostPlatform;
|
||||||
in {
|
in {
|
||||||
@@ -988,21 +977,8 @@ in with final; {
|
|||||||
"'src' / rust_target" \
|
"'src' / rust_target" \
|
||||||
"'src' / '${rustTargetPlatform}' / rust_target"
|
"'src' / '${rustTargetPlatform}' / rust_target"
|
||||||
'';
|
'';
|
||||||
# nixpkgs sets CARGO_BUILD_TARGET to the build platform target, so correct that.
|
|
||||||
buildPhase = ''
|
|
||||||
runHook preBuild
|
|
||||||
|
|
||||||
${rust.envVars.setEnv} "CARGO_BUILD_TARGET=${rustTargetPlatform}" ninja -j$NIX_BUILD_CORES
|
|
||||||
|
|
||||||
runHook postBuild
|
|
||||||
'';
|
|
||||||
});
|
});
|
||||||
|
|
||||||
# libsForQt5 = prev.libsForQt5.overrideScope (self: super: {
|
|
||||||
# inherit stdenv;
|
|
||||||
# inherit (self.stdenv) mkderivation;
|
|
||||||
# });
|
|
||||||
|
|
||||||
# qt6 = prev.qt6.overrideScope (self: super: {
|
# qt6 = prev.qt6.overrideScope (self: super: {
|
||||||
# # qtbase = super.qtbase.overrideAttrs (upstream: {
|
# # qtbase = super.qtbase.overrideAttrs (upstream: {
|
||||||
# # # cmakeFlags = upstream.cmakeFlags ++ lib.optionals (stdenv.buildPlatform != stdenv.hostPlatform) [
|
# # # cmakeFlags = upstream.cmakeFlags ++ lib.optionals (stdenv.buildPlatform != stdenv.hostPlatform) [
|
||||||
@@ -1104,7 +1080,7 @@ in with final; {
|
|||||||
# };
|
# };
|
||||||
# });
|
# });
|
||||||
|
|
||||||
# 2024/05/31: upstreaming is blocked by qtsvg, appstream
|
# 2024/08/12: upstreaming is unblocked
|
||||||
snapshot = prev.snapshot.overrideAttrs (upstream: {
|
snapshot = prev.snapshot.overrideAttrs (upstream: {
|
||||||
# fixes "error: linker `cc` not found"
|
# fixes "error: linker `cc` not found"
|
||||||
postPatch = (upstream.postPatch or "") + ''
|
postPatch = (upstream.postPatch or "") + ''
|
||||||
@@ -1114,41 +1090,29 @@ in with final; {
|
|||||||
'';
|
'';
|
||||||
});
|
});
|
||||||
|
|
||||||
# 2024/05/31: upstreaming is blocked by qtsvg, appstream
|
# 2024/08/12: upstreaming is unblocked
|
||||||
spot = prev.spot.overrideAttrs (upstream:
|
spot = (prev.spot.override { cargo = crossCargo; }).overrideAttrs (upstream: {
|
||||||
let
|
# blueprint-compiler runs on the build machine, but tries to load gobject-introspection types meant for the host.
|
||||||
rustTargetPlatform = rust.toRustTarget stdenv.hostPlatform;
|
postPatch = (upstream.postPatch or "") + ''
|
||||||
in {
|
substituteInPlace src/meson.build \
|
||||||
# blueprint-compiler runs on the build machine, but tries to load gobject-introspection types meant for the host.
|
--replace-fail \
|
||||||
postPatch = (upstream.postPatch or "") + ''
|
"find_program('blueprint-compiler')" \
|
||||||
substituteInPlace src/meson.build \
|
"'env', 'GI_TYPELIB_PATH=${typelibPath [
|
||||||
--replace-fail \
|
buildPackages.gdk-pixbuf
|
||||||
"find_program('blueprint-compiler')" \
|
buildPackages.glib
|
||||||
"'env', 'GI_TYPELIB_PATH=${typelibPath [
|
buildPackages.graphene
|
||||||
buildPackages.gdk-pixbuf
|
buildPackages.gtk4
|
||||||
buildPackages.glib
|
buildPackages.harfbuzz
|
||||||
buildPackages.graphene
|
buildPackages.libadwaita
|
||||||
buildPackages.gtk4
|
buildPackages.pango
|
||||||
buildPackages.harfbuzz
|
]}', find_program('blueprint-compiler')" \
|
||||||
buildPackages.libadwaita
|
--replace-fail \
|
||||||
buildPackages.pango
|
"meson.project_build_root() / cargo_output" \
|
||||||
]}', find_program('blueprint-compiler')" \
|
"meson.project_build_root() / 'src' / '${rust.envVars.rustHostPlatformSpec}' / rust_target / meson.project_name()"
|
||||||
--replace-fail \
|
'';
|
||||||
"meson.project_build_root() / cargo_output" \
|
});
|
||||||
"meson.project_build_root() / 'src' / '${rust.envVars.rustHostPlatformSpec}' / rust_target / meson.project_name()"
|
|
||||||
'';
|
|
||||||
# nixpkgs sets CARGO_BUILD_TARGET to the build platform target, so correct that.
|
|
||||||
buildPhase = ''
|
|
||||||
runHook preBuild
|
|
||||||
|
|
||||||
${rust.envVars.setEnv} "CARGO_BUILD_TARGET=${rustTargetPlatform}" ninja -j$NIX_BUILD_CORES
|
# 2024/08/12: upstreaming is unblocked
|
||||||
|
|
||||||
runHook postBuild
|
|
||||||
'';
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
# 2024/05/31: upstreaming is unblocked
|
|
||||||
# squeekboard = prev.squeekboard.overrideAttrs (upstream: {
|
# squeekboard = prev.squeekboard.overrideAttrs (upstream: {
|
||||||
# # fixes: "meson.build:1:0: ERROR: 'rust' compiler binary not defined in cross or native file"
|
# # fixes: "meson.build:1:0: ERROR: 'rust' compiler binary not defined in cross or native file"
|
||||||
# # new error: "meson.build:1:0: ERROR: Rust compiler rustc --target aarch64-unknown-linux-gnu -C linker=aarch64-unknown-linux-gnu-gcc can not compile programs."
|
# # new error: "meson.build:1:0: ERROR: Rust compiler rustc --target aarch64-unknown-linux-gnu -C linker=aarch64-unknown-linux-gnu-gcc can not compile programs."
|
||||||
@@ -1192,15 +1156,7 @@ in with final; {
|
|||||||
# ];
|
# ];
|
||||||
# });
|
# });
|
||||||
|
|
||||||
starship = prev.starship.overrideAttrs (base: {
|
# 2024/08/12: upstreaming is unblocked
|
||||||
# fix that shell completion installation wants to run host starship
|
|
||||||
postInstall = lib.replaceStrings
|
|
||||||
[ "$out/bin/starship" ]
|
|
||||||
[ "${stdenv.hostPlatform.emulator buildPackages} $out/bin/starship" ]
|
|
||||||
base.postInstall;
|
|
||||||
});
|
|
||||||
|
|
||||||
# 2024/05/31: upstreaming is blocked by qtsvg, appstream
|
|
||||||
tangram = prev.tangram.overrideAttrs (upstream: {
|
tangram = prev.tangram.overrideAttrs (upstream: {
|
||||||
# blueprint-compiler runs on the build machine, but tries to load gobject-introspection types meant for the host.
|
# blueprint-compiler runs on the build machine, but tries to load gobject-introspection types meant for the host.
|
||||||
# additionally, gsjpack has a shebang for the host gjs. patchShebangs --build doesn't fix that: just manually specify the build gjs
|
# additionally, gsjpack has a shebang for the host gjs. patchShebangs --build doesn't fix that: just manually specify the build gjs
|
||||||
@@ -1237,13 +1193,13 @@ in with final; {
|
|||||||
# });
|
# });
|
||||||
# };
|
# };
|
||||||
|
|
||||||
# 2024/05/31: upstreaming is blocked on hdf5, thrift, others
|
# 2024/08/12: upstreaming is blocked on arrow-cpp, python-pyarrow, python-contourpy, python-matplotlib, python-hypy, etc
|
||||||
# visidata = prev.visidata.override {
|
# visidata = prev.visidata.override {
|
||||||
# # hdf5 / h5py don't cross-compile, but i don't use that file format anyway.
|
# # hdf5 / h5py don't cross-compile, but i don't use that file format anyway.
|
||||||
# # setting this to null means visidata will work as normal but not be able to load hdf files.
|
# # setting this to null means visidata will work as normal but not be able to load hdf files.
|
||||||
# h5py = null;
|
# h5py = null;
|
||||||
# };
|
# };
|
||||||
# 2024/05/31: upstreaming is blocked on qtsvg, qtx11extras
|
# 2024/08/12: upstreaming is blocked on qtsvg, qtx11extras, samba
|
||||||
# vlc = prev.vlc.overrideAttrs (orig: {
|
# vlc = prev.vlc.overrideAttrs (orig: {
|
||||||
# # fixes: "configure: error: could not find the LUA byte compiler"
|
# # fixes: "configure: error: could not find the LUA byte compiler"
|
||||||
# # fixes: "configure: error: protoc compiler needed for chromecast was not found"
|
# # fixes: "configure: error: protoc compiler needed for chromecast was not found"
|
||||||
@@ -1256,11 +1212,11 @@ in with final; {
|
|||||||
# });
|
# });
|
||||||
|
|
||||||
# fixes "perl: command not found"
|
# fixes "perl: command not found"
|
||||||
# 2024/05/31: upstreaming is unblocked, but requires alternative fix
|
# 2024/08/12: upstreaming is unblocked, but requires alternative fix
|
||||||
# - i think the build script tries to run the generated binary?
|
# - i think the build script tries to run the generated binary?
|
||||||
# vpnc = mvToNativeInputs [ perl ] prev.vpnc;
|
# vpnc = mvToNativeInputs [ perl ] prev.vpnc;
|
||||||
|
|
||||||
# 2024/05/31: upstreaming is blocked on appstream
|
# 2024/08/12: upstreaming is blocked on flatpak
|
||||||
xdg-desktop-portal = prev.xdg-desktop-portal.overrideAttrs (upstream: {
|
xdg-desktop-portal = prev.xdg-desktop-portal.overrideAttrs (upstream: {
|
||||||
nativeBuildInputs = upstream.nativeBuildInputs ++ [
|
nativeBuildInputs = upstream.nativeBuildInputs ++ [
|
||||||
# fixes "meson.build:117:8: ERROR: Program 'bwrap' not found or not executable"
|
# fixes "meson.build:117:8: ERROR: Program 'bwrap' not found or not executable"
|
||||||
@@ -1272,20 +1228,25 @@ in with final; {
|
|||||||
"-Dpytest=disabled"
|
"-Dpytest=disabled"
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
# fixes "No package 'xdg-desktop-portal' found"
|
|
||||||
# 2023/12/08: upstreaming is blocked on argyllcms, flatpak, qtsvg (via pipewire/ffado)
|
|
||||||
xdg-desktop-portal-gtk = mvToBuildInputs [ xdg-desktop-portal ] prev.xdg-desktop-portal-gtk;
|
|
||||||
|
|
||||||
# fixes: "data/meson.build:33:5: ERROR: Program 'msgfmt' not found or not executable"
|
# fixes: "data/meson.build:33:5: ERROR: Program 'msgfmt' not found or not executable"
|
||||||
# fixes: "src/meson.build:25:0: ERROR: Program 'gdbus-codegen' not found or not executable"
|
# fixes: "src/meson.build:25:0: ERROR: Program 'gdbus-codegen' not found or not executable"
|
||||||
# 2023/07/27: upstreaming is blocked on p11-kit cross compilation
|
# 2024/08/12: upstreaming is blocked on xdg-desktop-portal
|
||||||
# xdg-desktop-portal-gnome = (
|
# xdg-desktop-portal-gnome = (
|
||||||
# addNativeInputs [ wayland-scanner ] (
|
# addNativeInputs [ wayland-scanner ] (
|
||||||
# mvToNativeInputs [ gettext glib ] prev.xdg-desktop-portal-gnome
|
# mvToNativeInputs [ gettext glib ] prev.xdg-desktop-portal-gnome
|
||||||
# )
|
# )
|
||||||
# );
|
# );
|
||||||
|
xdg-desktop-portal-gnome = prev.xdg-desktop-portal-gnome.override {
|
||||||
|
# xdp-gnome uses libjxl as a gdk pixbuf loader,
|
||||||
|
# but nixpkgs' libjxl disables the pixbuf loader when cross compiling,
|
||||||
|
# so xdp-gnome fails, expecting a pixbuf loader where there is none.
|
||||||
|
# solution: disable the libjxl pixbuf loader (by replacing it with a working pixbuf, already used by xdp-gnome).
|
||||||
|
# this means no jpeg thumbnailing.
|
||||||
|
libjxl = webp-pixbuf-loader;
|
||||||
|
};
|
||||||
|
|
||||||
# 2024/02/27: upstreaming is blocked on hyprland
|
# 2024/08/12: upstreaming is blocked on hyprland
|
||||||
# waybar = (prev.waybar.override {
|
# waybar = (prev.waybar.override {
|
||||||
# runTests = false; #< upstream expects `catch2_3` as a runtime requirement
|
# runTests = false; #< upstream expects `catch2_3` as a runtime requirement
|
||||||
# hyprlandSupport = false; # doesn't cross compile
|
# hyprlandSupport = false; # doesn't cross compile
|
||||||
@@ -1312,17 +1273,6 @@ in with final; {
|
|||||||
# strictDeps = true;
|
# strictDeps = true;
|
||||||
# });
|
# });
|
||||||
|
|
||||||
# 2024/05/31: upstreaming is unblocked
|
|
||||||
# implemented: <https://github.com/NixOS/nixpkgs/pull/315119>
|
|
||||||
webp-pixbuf-loader = prev.webp-pixbuf-loader.overrideAttrs (upstream: {
|
|
||||||
# fixes: "Builder called die: Cannot wrap '/nix/store/kpp8qhzdjqgvw73llka5gpnsj0l4jlg8-gdk-pixbuf-aarch64-unknown-linux-gnu-2.42.10/bin/gdk-pixbuf-thumbnailer' because it is not an executable file"
|
|
||||||
# gdk-pixbuf doesn't create a `bin/` directory when cross-compiling, breaks some thumbnailing stuff.
|
|
||||||
# - gnome's gdk-pixbuf *explicitly* doesn't build thumbnailer on cross builds
|
|
||||||
# see `librsvg` for a more bullet-proof cross-compilation approach
|
|
||||||
postInstall = "";
|
|
||||||
});
|
|
||||||
# XXX: aarch64 webp-pixbuf-loader wanted by gdk-pixbuf-loaders.cache.drv, wanted by aarch64 gnome-control-center
|
|
||||||
|
|
||||||
# 2024/05/31: upstreaming is blocked by qtsvg, appstream
|
# 2024/05/31: upstreaming is blocked by qtsvg, appstream
|
||||||
wike = prev.wike.overrideAttrs (upstream: {
|
wike = prev.wike.overrideAttrs (upstream: {
|
||||||
# error: "<wike> is not allowed to refer to the following paths: <build python>"
|
# error: "<wike> is not allowed to refer to the following paths: <build python>"
|
||||||
@@ -1333,19 +1283,7 @@ in with final; {
|
|||||||
'';
|
'';
|
||||||
});
|
});
|
||||||
|
|
||||||
# wrapFirefox = prev.wrapFirefox.override {
|
# 2024/08/12: upstreaming is unblocked
|
||||||
# buildPackages = buildPackages // {
|
|
||||||
# # fixes "extract-binary-wrapper-cmd: line 2: strings: command not found"
|
|
||||||
# # ^- in the `nix log` output of cross-compiled `firefox` (it's non-fatal)
|
|
||||||
# makeBinaryWrapper = bpkgs.makeBinaryWrapper.overrideAttrs (upstream: {
|
|
||||||
# passthru.extractCmd = bpkgs.writeShellScript "extract-binary-wrapper-cmd" ''
|
|
||||||
# ${stdenv.cc.targetPrefix}strings -dw "$1" | sed -n '/^makeCWrapper/,/^$/ p'
|
|
||||||
# '';
|
|
||||||
# });
|
|
||||||
# };
|
|
||||||
# };
|
|
||||||
|
|
||||||
# 2024/05/31: upstreaming is unblocked
|
|
||||||
# fixes `hostPrograms.moby.neovim` (but breaks eval of `hostPkgs.moby.neovim` :o)
|
# fixes `hostPrograms.moby.neovim` (but breaks eval of `hostPkgs.moby.neovim` :o)
|
||||||
# wrapNeovimUnstable = neovim: config: (prev.wrapNeovimUnstable neovim config).overrideAttrs (upstream: {
|
# wrapNeovimUnstable = neovim: config: (prev.wrapNeovimUnstable neovim config).overrideAttrs (upstream: {
|
||||||
# # nvim wrapper has a sanity check that the plugins will load correctly.
|
# # nvim wrapper has a sanity check that the plugins will load correctly.
|
||||||
|
29
pkgs/additional/curlftpfs-sane/default.nix
Normal file
29
pkgs/additional/curlftpfs-sane/default.nix
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
curlftpfs,
|
||||||
|
fetchFromGitea,
|
||||||
|
fuse3,
|
||||||
|
}:
|
||||||
|
(curlftpfs.override {
|
||||||
|
fuse = fuse3;
|
||||||
|
}).overrideAttrs (upstream: {
|
||||||
|
# my (master branch) fork includes:
|
||||||
|
# - per-operation timeouts (CURLOPT_TIMEOUT; would use CURLOPT_LOW_SPEED_TIME/CURLOPT_LOW_SPEED_LIMIT but they don't apply)
|
||||||
|
# - exit on timeout (so that one knows to abort the mount, instead of waiting indefinitely)
|
||||||
|
# - support for "meta" keys found in /etc/fstab
|
||||||
|
# my (fuse3 branch) fork includes the above plus:
|
||||||
|
# - implements the fuse3 API. this means it also supports `-o drop_privileges`
|
||||||
|
src = fetchFromGitea {
|
||||||
|
domain = "git.uninsane.org";
|
||||||
|
owner = "colin";
|
||||||
|
repo = "curlftpfs";
|
||||||
|
rev = "fuse3";
|
||||||
|
hash = "sha256-QwGbQuriNwnZscnYBEVp3Td6/ifiA8rtQcvtvmTnpbU=";
|
||||||
|
};
|
||||||
|
# `mount` clears PATH before calling the mount helper (see util-linux/lib/env.c),
|
||||||
|
# so the traditional /etc/fstab approach of fstype=fuse and device = curlftpfs#URI doesn't work.
|
||||||
|
# instead, install a `mount.curlftpfs` mount helper. this is what programs like `gocryptfs` do.
|
||||||
|
postInstall = (upstream.postInstall or "") + ''
|
||||||
|
ln -s curlftpfs $out/bin/mount.fuse.curlftpfs
|
||||||
|
ln -s curlftpfs $out/bin/mount.curlftpfs
|
||||||
|
'';
|
||||||
|
})
|
@@ -34,10 +34,7 @@ let
|
|||||||
extid = addon.passthru.extid;
|
extid = addon.passthru.extid;
|
||||||
# merge our requirements into the derivation args
|
# merge our requirements into the derivation args
|
||||||
args' = args // {
|
args' = args // {
|
||||||
passthru = {
|
passthru = addon.passthru // (args.passthru or {});
|
||||||
inherit extid;
|
|
||||||
original = addon;
|
|
||||||
} // (args.passthru or {});
|
|
||||||
nativeBuildInputs = [
|
nativeBuildInputs = [
|
||||||
jq
|
jq
|
||||||
strip-nondeterminism
|
strip-nondeterminism
|
||||||
@@ -137,6 +134,7 @@ in (lib.makeScope newScope (self: with self; {
|
|||||||
browserpass-extension = callPackage ./browserpass-extension { };
|
browserpass-extension = callPackage ./browserpass-extension { };
|
||||||
bypass-paywalls-clean = callPackage ./bypass-paywalls-clean { };
|
bypass-paywalls-clean = callPackage ./bypass-paywalls-clean { };
|
||||||
ctrl-shift-c-should-copy = callPackage ./ctrl-shift-c-should-copy { };
|
ctrl-shift-c-should-copy = callPackage ./ctrl-shift-c-should-copy { };
|
||||||
|
firefox-xdg-open = callPackage ./firefox-xdg-open { };
|
||||||
i-still-dont-care-about-cookies = callPackage ./i-still-dont-care-about-cookies { };
|
i-still-dont-care-about-cookies = callPackage ./i-still-dont-care-about-cookies { };
|
||||||
open-in-mpv = callPackage ./open-in-mpv { };
|
open-in-mpv = callPackage ./open-in-mpv { };
|
||||||
sidebery = callPackage ./sidebery { };
|
sidebery = callPackage ./sidebery { };
|
||||||
|
@@ -0,0 +1,16 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
|
<title>Document</title>
|
||||||
|
<script src="background.js" type="module"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
|
|
@@ -0,0 +1,22 @@
|
|||||||
|
//! largely copied from OpenInMPV browser extension
|
||||||
|
|
||||||
|
function xdgOpen(tabId, url) {
|
||||||
|
const code = `
|
||||||
|
var link = document.createElement('a')
|
||||||
|
link.href='xdg-open:${url}'
|
||||||
|
document.body.appendChild(link)
|
||||||
|
link.click()`
|
||||||
|
console.log(code)
|
||||||
|
chrome.tabs.executeScript(tabId, { code })
|
||||||
|
}
|
||||||
|
|
||||||
|
[["page", "pageUrl"], ["link", "linkUrl"], ["video", "srcUrl"], ["audio", "srcUrl"]].forEach(([item, linkType]) => {
|
||||||
|
chrome.contextMenus.create({
|
||||||
|
title: "xdg-open",
|
||||||
|
id: `open${item}inmpv`,
|
||||||
|
contexts: [item],
|
||||||
|
onclick: (info, tab) => {
|
||||||
|
xdgOpen(tab.id, info[linkType]);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
@@ -0,0 +1,47 @@
|
|||||||
|
{
|
||||||
|
copyDesktopItems,
|
||||||
|
makeDesktopItem,
|
||||||
|
static-nix-shell,
|
||||||
|
stdenvNoCC,
|
||||||
|
zip,
|
||||||
|
}:
|
||||||
|
stdenvNoCC.mkDerivation {
|
||||||
|
pname = "firefox-xdg-open";
|
||||||
|
version = "0.1";
|
||||||
|
src = ./.;
|
||||||
|
|
||||||
|
nativeBuildInputs = [ zip ];
|
||||||
|
|
||||||
|
buildPhase = ''
|
||||||
|
runHook preBuild
|
||||||
|
zip -j firefox.zip \
|
||||||
|
background.html background.js manifest.json
|
||||||
|
runHook postBuild
|
||||||
|
'';
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
runHook preInstall
|
||||||
|
install firefox.zip $out
|
||||||
|
runHook postInstall
|
||||||
|
'';
|
||||||
|
|
||||||
|
passthru.extid = "@firefox-xdg-open";
|
||||||
|
passthru.systemComponent = static-nix-shell.mkBash {
|
||||||
|
pname = "xdg-open-scheme-handler";
|
||||||
|
src = ./.;
|
||||||
|
pkgs = [ "xdg-utils" ];
|
||||||
|
|
||||||
|
nativeBuildInputs = [
|
||||||
|
copyDesktopItems
|
||||||
|
];
|
||||||
|
desktopItems = [
|
||||||
|
(makeDesktopItem {
|
||||||
|
name = "xdg-open";
|
||||||
|
exec = "xdg-open-scheme-handler %U";
|
||||||
|
desktopName = "xdg-open";
|
||||||
|
comment = "Decodes xdg-open:... URIs, used to force applications to open links via the system handler";
|
||||||
|
noDisplay = true;
|
||||||
|
})
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"manifest_version": 2,
|
||||||
|
"browser_specific_settings": {
|
||||||
|
"gecko": {
|
||||||
|
"id": "@firefox-xdg-open"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name": "Firefox XDG Open",
|
||||||
|
"description": "Open URIs with the system handler.",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"background": {
|
||||||
|
"page": "background.html"
|
||||||
|
},
|
||||||
|
"permissions": [
|
||||||
|
"tabs",
|
||||||
|
"activeTab",
|
||||||
|
"contextMenus"
|
||||||
|
]
|
||||||
|
}
|
@@ -0,0 +1,9 @@
|
|||||||
|
#!/usr/bin/env nix-shell
|
||||||
|
#!nix-shell -i bash -p bash -p xdg-utils
|
||||||
|
|
||||||
|
uris=()
|
||||||
|
for u in "$@"; do
|
||||||
|
uris+=("${u/xdg-open:/}")
|
||||||
|
done
|
||||||
|
|
||||||
|
xdg-open "${uris[@]}"
|
File diff suppressed because it is too large
Load Diff
@@ -1,26 +1,20 @@
|
|||||||
{
|
{
|
||||||
"git+https://github.com/matrix-org/matrix-authentication-service?rev=099eabd1371d2840a2f025a6372d6428039eb511#mas-http@0.8.0": "0zpykj45889vgvcay0qkcfby0pa5qczmbp6zybkrzz4kv8bk29i2",
|
"git+https://github.com/matrix-org/matrix-rust-sdk.git?rev=92b4c2a469f507696fa9db3d6bdb000a761e2694#matrix-sdk-base@0.7.0": "0bqgg2y8mfayxqlx21w0a2ldq5q47fq67m2y84arz6dbf4ck2nb6",
|
||||||
"git+https://github.com/matrix-org/matrix-authentication-service?rev=099eabd1371d2840a2f025a6372d6428039eb511#mas-iana@0.8.0": "0zpykj45889vgvcay0qkcfby0pa5qczmbp6zybkrzz4kv8bk29i2",
|
"git+https://github.com/matrix-org/matrix-rust-sdk.git?rev=92b4c2a469f507696fa9db3d6bdb000a761e2694#matrix-sdk-common@0.7.0": "0bqgg2y8mfayxqlx21w0a2ldq5q47fq67m2y84arz6dbf4ck2nb6",
|
||||||
"git+https://github.com/matrix-org/matrix-authentication-service?rev=099eabd1371d2840a2f025a6372d6428039eb511#mas-jose@0.8.0": "0zpykj45889vgvcay0qkcfby0pa5qczmbp6zybkrzz4kv8bk29i2",
|
"git+https://github.com/matrix-org/matrix-rust-sdk.git?rev=92b4c2a469f507696fa9db3d6bdb000a761e2694#matrix-sdk-crypto@0.7.1": "0bqgg2y8mfayxqlx21w0a2ldq5q47fq67m2y84arz6dbf4ck2nb6",
|
||||||
"git+https://github.com/matrix-org/matrix-authentication-service?rev=099eabd1371d2840a2f025a6372d6428039eb511#mas-oidc-client@0.8.0": "0zpykj45889vgvcay0qkcfby0pa5qczmbp6zybkrzz4kv8bk29i2",
|
"git+https://github.com/matrix-org/matrix-rust-sdk.git?rev=92b4c2a469f507696fa9db3d6bdb000a761e2694#matrix-sdk-indexeddb@0.7.0": "0bqgg2y8mfayxqlx21w0a2ldq5q47fq67m2y84arz6dbf4ck2nb6",
|
||||||
"git+https://github.com/matrix-org/matrix-authentication-service?rev=099eabd1371d2840a2f025a6372d6428039eb511#oauth2-types@0.8.0": "0zpykj45889vgvcay0qkcfby0pa5qczmbp6zybkrzz4kv8bk29i2",
|
"git+https://github.com/matrix-org/matrix-rust-sdk.git?rev=92b4c2a469f507696fa9db3d6bdb000a761e2694#matrix-sdk-qrcode@0.7.0": "0bqgg2y8mfayxqlx21w0a2ldq5q47fq67m2y84arz6dbf4ck2nb6",
|
||||||
"git+https://github.com/matrix-org/matrix-rust-sdk.git?rev=88c4dec35f05ae295e0f2bf0362d6f5d72606d92#matrix-sdk-base@0.7.0": "0x2k85v4bzp8fk0596pr7kvkjjfq76bqmh816g1s4avl7ks2vv5a",
|
"git+https://github.com/matrix-org/matrix-rust-sdk.git?rev=92b4c2a469f507696fa9db3d6bdb000a761e2694#matrix-sdk-sqlite@0.7.0": "0bqgg2y8mfayxqlx21w0a2ldq5q47fq67m2y84arz6dbf4ck2nb6",
|
||||||
"git+https://github.com/matrix-org/matrix-rust-sdk.git?rev=88c4dec35f05ae295e0f2bf0362d6f5d72606d92#matrix-sdk-common@0.7.0": "0x2k85v4bzp8fk0596pr7kvkjjfq76bqmh816g1s4avl7ks2vv5a",
|
"git+https://github.com/matrix-org/matrix-rust-sdk.git?rev=92b4c2a469f507696fa9db3d6bdb000a761e2694#matrix-sdk-store-encryption@0.7.0": "0bqgg2y8mfayxqlx21w0a2ldq5q47fq67m2y84arz6dbf4ck2nb6",
|
||||||
"git+https://github.com/matrix-org/matrix-rust-sdk.git?rev=88c4dec35f05ae295e0f2bf0362d6f5d72606d92#matrix-sdk-crypto@0.7.0": "0x2k85v4bzp8fk0596pr7kvkjjfq76bqmh816g1s4avl7ks2vv5a",
|
"git+https://github.com/matrix-org/matrix-rust-sdk.git?rev=92b4c2a469f507696fa9db3d6bdb000a761e2694#matrix-sdk-ui@0.7.0": "0bqgg2y8mfayxqlx21w0a2ldq5q47fq67m2y84arz6dbf4ck2nb6",
|
||||||
"git+https://github.com/matrix-org/matrix-rust-sdk.git?rev=88c4dec35f05ae295e0f2bf0362d6f5d72606d92#matrix-sdk-indexeddb@0.7.0": "0x2k85v4bzp8fk0596pr7kvkjjfq76bqmh816g1s4avl7ks2vv5a",
|
"git+https://github.com/matrix-org/matrix-rust-sdk.git?rev=92b4c2a469f507696fa9db3d6bdb000a761e2694#matrix-sdk@0.7.1": "0bqgg2y8mfayxqlx21w0a2ldq5q47fq67m2y84arz6dbf4ck2nb6",
|
||||||
"git+https://github.com/matrix-org/matrix-rust-sdk.git?rev=88c4dec35f05ae295e0f2bf0362d6f5d72606d92#matrix-sdk-qrcode@0.7.0": "0x2k85v4bzp8fk0596pr7kvkjjfq76bqmh816g1s4avl7ks2vv5a",
|
"git+https://github.com/matrix-org/ruma.git?rev=4d3d8b46fd519012e4585ccf00dbea1eb602c028#ruma-client-api@0.18.0": "1a2s2hlh202h8bqlhmv4nm5bd6mlkbsbik7qmphdy9yn2398kw8b",
|
||||||
"git+https://github.com/matrix-org/matrix-rust-sdk.git?rev=88c4dec35f05ae295e0f2bf0362d6f5d72606d92#matrix-sdk-sqlite@0.7.0": "0x2k85v4bzp8fk0596pr7kvkjjfq76bqmh816g1s4avl7ks2vv5a",
|
"git+https://github.com/matrix-org/ruma.git?rev=4d3d8b46fd519012e4585ccf00dbea1eb602c028#ruma-common@0.13.0": "1a2s2hlh202h8bqlhmv4nm5bd6mlkbsbik7qmphdy9yn2398kw8b",
|
||||||
"git+https://github.com/matrix-org/matrix-rust-sdk.git?rev=88c4dec35f05ae295e0f2bf0362d6f5d72606d92#matrix-sdk-store-encryption@0.7.0": "0x2k85v4bzp8fk0596pr7kvkjjfq76bqmh816g1s4avl7ks2vv5a",
|
"git+https://github.com/matrix-org/ruma.git?rev=4d3d8b46fd519012e4585ccf00dbea1eb602c028#ruma-events@0.28.1": "1a2s2hlh202h8bqlhmv4nm5bd6mlkbsbik7qmphdy9yn2398kw8b",
|
||||||
"git+https://github.com/matrix-org/matrix-rust-sdk.git?rev=88c4dec35f05ae295e0f2bf0362d6f5d72606d92#matrix-sdk-ui@0.7.0": "0x2k85v4bzp8fk0596pr7kvkjjfq76bqmh816g1s4avl7ks2vv5a",
|
"git+https://github.com/matrix-org/ruma.git?rev=4d3d8b46fd519012e4585ccf00dbea1eb602c028#ruma-federation-api@0.9.0": "1a2s2hlh202h8bqlhmv4nm5bd6mlkbsbik7qmphdy9yn2398kw8b",
|
||||||
"git+https://github.com/matrix-org/matrix-rust-sdk.git?rev=88c4dec35f05ae295e0f2bf0362d6f5d72606d92#matrix-sdk@0.7.1": "0x2k85v4bzp8fk0596pr7kvkjjfq76bqmh816g1s4avl7ks2vv5a",
|
"git+https://github.com/matrix-org/ruma.git?rev=4d3d8b46fd519012e4585ccf00dbea1eb602c028#ruma-html@0.2.0": "1a2s2hlh202h8bqlhmv4nm5bd6mlkbsbik7qmphdy9yn2398kw8b",
|
||||||
"git+https://github.com/matrix-org/vodozemac?rev=0c75746fc8a5eda4a0e490d345d1798b4c6cbd67#0.5.1": "10rqywmw1f14fsrjp5ibn1sykj18lhdglwajkzxdb64ivvmh4v8y",
|
"git+https://github.com/matrix-org/ruma.git?rev=4d3d8b46fd519012e4585ccf00dbea1eb602c028#ruma-identifiers-validation@0.9.5": "1a2s2hlh202h8bqlhmv4nm5bd6mlkbsbik7qmphdy9yn2398kw8b",
|
||||||
"git+https://github.com/ruma/ruma.git?rev=4c00bd010dbdca6005bd599b52e90a0b7015d056#ruma-client-api@0.17.4": "12252g7yhqq5ha2kq2qc7g1zq5lbj0vhxm034pckalgx5lah97dn",
|
"git+https://github.com/matrix-org/ruma.git?rev=4d3d8b46fd519012e4585ccf00dbea1eb602c028#ruma-macros@0.13.0": "1a2s2hlh202h8bqlhmv4nm5bd6mlkbsbik7qmphdy9yn2398kw8b",
|
||||||
"git+https://github.com/ruma/ruma.git?rev=4c00bd010dbdca6005bd599b52e90a0b7015d056#ruma-common@0.12.1": "12252g7yhqq5ha2kq2qc7g1zq5lbj0vhxm034pckalgx5lah97dn",
|
"git+https://github.com/matrix-org/ruma.git?rev=4d3d8b46fd519012e4585ccf00dbea1eb602c028#ruma-push-gateway-api@0.9.0": "1a2s2hlh202h8bqlhmv4nm5bd6mlkbsbik7qmphdy9yn2398kw8b",
|
||||||
"git+https://github.com/ruma/ruma.git?rev=4c00bd010dbdca6005bd599b52e90a0b7015d056#ruma-events@0.27.11": "12252g7yhqq5ha2kq2qc7g1zq5lbj0vhxm034pckalgx5lah97dn",
|
"git+https://github.com/matrix-org/ruma.git?rev=4d3d8b46fd519012e4585ccf00dbea1eb602c028#ruma@0.10.1": "1a2s2hlh202h8bqlhmv4nm5bd6mlkbsbik7qmphdy9yn2398kw8b"
|
||||||
"git+https://github.com/ruma/ruma.git?rev=4c00bd010dbdca6005bd599b52e90a0b7015d056#ruma-federation-api@0.8.0": "12252g7yhqq5ha2kq2qc7g1zq5lbj0vhxm034pckalgx5lah97dn",
|
|
||||||
"git+https://github.com/ruma/ruma.git?rev=4c00bd010dbdca6005bd599b52e90a0b7015d056#ruma-html@0.1.0": "12252g7yhqq5ha2kq2qc7g1zq5lbj0vhxm034pckalgx5lah97dn",
|
|
||||||
"git+https://github.com/ruma/ruma.git?rev=4c00bd010dbdca6005bd599b52e90a0b7015d056#ruma-identifiers-validation@0.9.3": "12252g7yhqq5ha2kq2qc7g1zq5lbj0vhxm034pckalgx5lah97dn",
|
|
||||||
"git+https://github.com/ruma/ruma.git?rev=4c00bd010dbdca6005bd599b52e90a0b7015d056#ruma-macros@0.12.0": "12252g7yhqq5ha2kq2qc7g1zq5lbj0vhxm034pckalgx5lah97dn",
|
|
||||||
"git+https://github.com/ruma/ruma.git?rev=4c00bd010dbdca6005bd599b52e90a0b7015d056#ruma-push-gateway-api@0.8.0": "12252g7yhqq5ha2kq2qc7g1zq5lbj0vhxm034pckalgx5lah97dn",
|
|
||||||
"git+https://github.com/ruma/ruma.git?rev=4c00bd010dbdca6005bd599b52e90a0b7015d056#ruma@0.9.4": "12252g7yhqq5ha2kq2qc7g1zq5lbj0vhxm034pckalgx5lah97dn"
|
|
||||||
}
|
}
|
@@ -57,8 +57,8 @@ let
|
|||||||
domain = "gitlab.gnome.org";
|
domain = "gitlab.gnome.org";
|
||||||
owner = "GNOME";
|
owner = "GNOME";
|
||||||
repo = "fractal";
|
repo = "fractal";
|
||||||
rev = "7";
|
rev = "8";
|
||||||
hash = "sha256-IfcThpsGATMD3Uj9tvw/aK7IVbiVT8sdZ088gRUqnlg=";
|
hash = "sha256-a77+lPH2eqWTLFrYfcBXSvbyyYC52zSo+Rh/diqKYx4=";
|
||||||
};
|
};
|
||||||
codegenUnits = 256; #< this does get plumbed, but doesn't seem to affect build speed
|
codegenUnits = 256; #< this does get plumbed, but doesn't seem to affect build speed
|
||||||
outputs = [ "out" ]; # default is "out" and "lib", but that somehow causes cycles
|
outputs = [ "out" ]; # default is "out" and "lib", but that somehow causes cycles
|
||||||
|
@@ -71,135 +71,142 @@
|
|||||||
, zsync
|
, zsync
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
version = "2024.04";
|
sourcesFor = pins: rec {
|
||||||
src = fetchFromGitHub {
|
koreader = fetchFromGitHub {
|
||||||
owner = "koreader";
|
owner = "koreader";
|
||||||
repo = "koreader";
|
repo = "koreader";
|
||||||
name = "koreader"; # needed because `srcs = ` in the outer derivation is a list
|
name = "koreader"; # needed because `srcs = ` in the outer derivation is a list
|
||||||
fetchSubmodules = true;
|
fetchSubmodules = true;
|
||||||
rev = "v${version}";
|
rev = "v${pins.version}";
|
||||||
hash = "sha256-BQnKoTj90wWZNxGn1C9iL8y1tozqdEHMgQDfQZo2axg=";
|
inherit (pins.koreader) hash;
|
||||||
|
};
|
||||||
|
|
||||||
|
fbink-src-ko = fetchFromGitHub {
|
||||||
|
owner = "NiLuJe";
|
||||||
|
repo = "FBInk";
|
||||||
|
name = "fbink"; # where to unpack this in `srcs`
|
||||||
|
inherit (pins.fbink) rev hash;
|
||||||
|
};
|
||||||
|
|
||||||
|
kobo-usbms-src-ko = fetchFromGitHub {
|
||||||
|
owner = "koreader";
|
||||||
|
repo = "KoboUSBMS";
|
||||||
|
name = "kobo-usbms"; # where to unpack this in `srcs`
|
||||||
|
inherit (pins.kobo-usbms) rev hash;
|
||||||
|
};
|
||||||
|
|
||||||
|
leptonica-src-ko = fetchFromGitHub {
|
||||||
|
# k2pdf needs leptonica src, because it actually patches it and builds it itself:
|
||||||
|
# - `cp -f $(LEPTONICA_MOD)/dewarp2.c $(LEPTONICA_DIR)/src/dewarp2.c`
|
||||||
|
# - i.e. cp -f /build/koreader/base/thirdparty/libk2pdfopt/build/aarch64-unknown-linux-gnu/libk2pdfopt-prefix/src/libk2pdfopt/leptonica_mod/dewarp2.c ...
|
||||||
|
# k2pdf uses an old leptonica -- like 2015-2017-ish (1.74.1).
|
||||||
|
# seems it can be at least partially updated, by replacing `numaGetMedianVariation` with `numaGetMedianDevFromMedian` (drop-in replacement)
|
||||||
|
# and replacing references to `liblept.so` with `libleptonica.so`,
|
||||||
|
# but eventually this requires patching the tesseract Makefiles. could get intense, idk.
|
||||||
|
owner = "DanBloomberg";
|
||||||
|
repo = "leptonica";
|
||||||
|
name = "leptonica"; # where to unpack this in `srcs`
|
||||||
|
inherit (pins.leptonica) rev hash;
|
||||||
|
};
|
||||||
|
|
||||||
|
libk2pdfopt-src-ko = fetchFromGitHub {
|
||||||
|
owner = "koreader";
|
||||||
|
repo = "libk2pdfopt";
|
||||||
|
name = "libk2pdfopt"; # where to unpack this in `srcs`
|
||||||
|
inherit (pins.libk2pdfopt) rev hash;
|
||||||
|
};
|
||||||
|
|
||||||
|
lodepng-src-ko = fetchFromGitHub {
|
||||||
|
owner = "lvandeve";
|
||||||
|
repo = "lodepng";
|
||||||
|
name = "lodepng"; # where to unpack this in `srcs`
|
||||||
|
inherit (pins.lodepng) rev hash;
|
||||||
|
};
|
||||||
|
|
||||||
|
lunasvg-src-ko = fetchFromGitHub {
|
||||||
|
owner = "sammycage";
|
||||||
|
repo = "lunasvg";
|
||||||
|
name = "lunasvg"; # where to unpack this in `srcs`
|
||||||
|
inherit (pins.lunasvg) rev hash;
|
||||||
|
};
|
||||||
|
|
||||||
|
minizip-src-ko = fetchFromGitHub {
|
||||||
|
# this is actually just a very old version (2015) of `minizip-ng`
|
||||||
|
owner = "nmoinvaz";
|
||||||
|
repo = "minizip";
|
||||||
|
name = "minizip"; # where to unpack this in `srcs`
|
||||||
|
inherit (pins.minizip) rev hash;
|
||||||
|
};
|
||||||
|
|
||||||
|
mupdf-src-ko = fetchFromGitHub {
|
||||||
|
owner = "ArtifexSoftware";
|
||||||
|
repo = "mupdf";
|
||||||
|
name = "mupdf"; # where to unpack this in `srcs`
|
||||||
|
fetchSubmodules = true; # specifically for jbig2dec, mujs, openjpeg
|
||||||
|
inherit (pins.mupdf) rev hash;
|
||||||
|
};
|
||||||
|
|
||||||
|
nanosvg-headers-ko = symlinkJoin {
|
||||||
|
# koreader's heavily-patched mupdf is dependent on a koreader-specific `stb_image_write` extension to nanosvg.
|
||||||
|
# nanosvg is used as a header-only library, so just patch that extension straight into the src.
|
||||||
|
name = "nanosvg-headers-ko";
|
||||||
|
paths = [
|
||||||
|
"${nanosvg.src}/src"
|
||||||
|
"${koreader}/base/thirdparty/nanosvg"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
popen-noshell-src-ko = fetchFromGitHub {
|
||||||
|
owner = "famzah";
|
||||||
|
repo = "popen-noshell";
|
||||||
|
name = "popen-noshell";
|
||||||
|
inherit (pins.popen-noshell) rev hash;
|
||||||
|
};
|
||||||
|
|
||||||
|
tesseract-src-ko = fetchFromGitHub {
|
||||||
|
# TODO: try using nixpkgs' tesseract.src (i doubt it will work)
|
||||||
|
owner = "tesseract-ocr";
|
||||||
|
repo = "tesseract";
|
||||||
|
name = "tesseract";
|
||||||
|
inherit (pins.tesseract) rev hash;
|
||||||
|
};
|
||||||
|
|
||||||
|
turbo-src-ko = fetchFromGitHub {
|
||||||
|
owner = "kernelsauce";
|
||||||
|
repo = "turbo";
|
||||||
|
name = "turbo";
|
||||||
|
inherit (pins.turbo) rev hash;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
fbink-src-ko = fetchFromGitHub {
|
thirdparty = [
|
||||||
owner = "NiLuJe";
|
curl
|
||||||
repo = "FBInk";
|
czmq
|
||||||
name = "fbink"; # where to unpack this in `srcs`
|
djvulibre
|
||||||
rev = "1a989b30a195ca240a3cf37f9de61b4b3c7e891c";
|
dropbear
|
||||||
hash = "sha256-lXjAX0BoHW3L1E54d5J+wiAlAZXVmj9Y1Un8yaCwO8w=";
|
freetype
|
||||||
};
|
fribidi
|
||||||
|
gettext
|
||||||
kobo-usbms-src-ko = fetchFromGitHub {
|
giflib
|
||||||
owner = "koreader";
|
glib
|
||||||
repo = "KoboUSBMS";
|
gnutar
|
||||||
name = "kobo-usbms"; # where to unpack this in `srcs`
|
harfbuzz
|
||||||
rev = "v1.3.9";
|
libiconvReal
|
||||||
hash = "sha256-91B0FUnmpE6TP4Lg5mj6z/U1DZQTKiPhG3ccCSgY4mQ=";
|
libjpeg_turbo
|
||||||
};
|
libpng
|
||||||
|
libunibreak
|
||||||
leptonica-src-ko = fetchFromGitHub {
|
libwebp
|
||||||
# k2pdf needs leptonica src, because it actually patches it and builds it itself:
|
openssl
|
||||||
# - `cp -f $(LEPTONICA_MOD)/dewarp2.c $(LEPTONICA_DIR)/src/dewarp2.c`
|
openssh
|
||||||
# - i.e. cp -f /build/koreader/base/thirdparty/libk2pdfopt/build/aarch64-unknown-linux-gnu/libk2pdfopt-prefix/src/libk2pdfopt/leptonica_mod/dewarp2.c ...
|
sdcv
|
||||||
# k2pdf uses an old leptonica -- like 2015-2017-ish (1.74.1).
|
SDL2
|
||||||
# seems it can be at least partially updated, by replacing `numaGetMedianVariation` with `numaGetMedianDevFromMedian` (drop-in replacement)
|
sqlite
|
||||||
# and replacing references to `liblept.so` with `libleptonica.so`,
|
utf8proc
|
||||||
# but eventually this requires patching the tesseract Makefiles. could get intense, idk.
|
zlib
|
||||||
owner = "DanBloomberg";
|
zeromq4
|
||||||
repo = "leptonica";
|
zstd
|
||||||
name = "leptonica"; # where to unpack this in `srcs`
|
zsync
|
||||||
rev = "1.74.1";
|
];
|
||||||
hash = "sha256-SDXKam768xvZZvTbXe3sssvZyeLEEiY97Vrzx8hoc6g=";
|
|
||||||
};
|
|
||||||
|
|
||||||
libk2pdfopt-src-ko = fetchFromGitHub {
|
|
||||||
owner = "koreader";
|
|
||||||
repo = "libk2pdfopt";
|
|
||||||
name = "libk2pdfopt"; # where to unpack this in `srcs`
|
|
||||||
rev = "47caea57aaf6200fc2b24669b6417fe6919926b7";
|
|
||||||
hash = "sha256-8Em4neXTovhrTb+GBhs6kDFEdsQSt5KiYoHURwdtjPQ=";
|
|
||||||
};
|
|
||||||
|
|
||||||
lodepng-src-ko = fetchFromGitHub {
|
|
||||||
owner = "lvandeve";
|
|
||||||
repo = "lodepng";
|
|
||||||
name = "lodepng"; # where to unpack this in `srcs`
|
|
||||||
rev = "d398e0f10d152a5d17fa30463474dc9f56523f9c";
|
|
||||||
hash = "sha256-ApOHUgU6X1rHwyjAHA/0Nt+buDFqY2ttXEnEvdrRl3A=";
|
|
||||||
};
|
|
||||||
|
|
||||||
lunasvg-src-ko = fetchFromGitHub {
|
|
||||||
owner = "sammycage";
|
|
||||||
repo = "lunasvg";
|
|
||||||
name = "lunasvg"; # where to unpack this in `srcs`
|
|
||||||
rev = "59d6f6ba835c1b7c7a0f9d4ea540ec3981777885";
|
|
||||||
hash = "sha256-gW2ikakS6Omz5upmy26nAo/jkGHYO2kjlB3UmKJBh1k=";
|
|
||||||
};
|
|
||||||
|
|
||||||
minizip-src-ko = fetchFromGitHub {
|
|
||||||
# this is actually just a very old version (2015) of `minizip-ng`
|
|
||||||
owner = "nmoinvaz";
|
|
||||||
repo = "minizip";
|
|
||||||
name = "minizip"; # where to unpack this in `srcs`
|
|
||||||
rev = "0b46a2b4ca317b80bc53594688883f7188ac4d08";
|
|
||||||
hash = "sha256-P/3MMMGYDqD9NmkYvw/thKpUNa3wNOSlBBjANHSonAg=";
|
|
||||||
};
|
|
||||||
|
|
||||||
mupdf-src-ko = fetchFromGitHub {
|
|
||||||
owner = "ArtifexSoftware";
|
|
||||||
repo = "mupdf";
|
|
||||||
name = "mupdf"; # where to unpack this in `srcs`
|
|
||||||
fetchSubmodules = true; # specifically for jbig2dec, mujs, openjpeg
|
|
||||||
rev = "1.13.0";
|
|
||||||
hash = "sha256-pQejRon9fO9A1mhz3oLjBr1j4HveDLcQIWjR1/Rpy5Q=";
|
|
||||||
};
|
|
||||||
|
|
||||||
nanosvg-headers-ko = symlinkJoin {
|
|
||||||
# koreader's heavily-patched mupdf is dependent on a koreader-specific `stb_image_write` extension to nanosvg.
|
|
||||||
# nanosvg is used as a header-only library, so just patch that extension straight into the src.
|
|
||||||
name = "nanosvg-headers-ko";
|
|
||||||
paths = [
|
|
||||||
"${nanosvg.src}/src"
|
|
||||||
"${src}/base/thirdparty/nanosvg"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
popen-noshell-src-ko = fetchFromGitHub {
|
|
||||||
owner = "famzah";
|
|
||||||
repo = "popen-noshell";
|
|
||||||
name = "popen-noshell";
|
|
||||||
rev = "e715396a4951ee91c40a98d2824a130f158268bb";
|
|
||||||
hash = "sha256-JeBZMsg6ZUGSnyZ4eds4w63gM/L73EsAnLaHOPpL6iM=";
|
|
||||||
};
|
|
||||||
|
|
||||||
tesseract-src-ko = fetchFromGitHub {
|
|
||||||
# TODO: try using nixpkgs' tesseract.src (i doubt it will work)
|
|
||||||
owner = "tesseract-ocr";
|
|
||||||
repo = "tesseract";
|
|
||||||
name = "tesseract";
|
|
||||||
rev = "60176fc5ae5e7f6bdef60c926a4b5ea03de2bfa7";
|
|
||||||
hash = "sha256-FQvlrJ+Uy7+wtUxBuS5NdoToUwNRhYw2ju8Ya8MLyQw=";
|
|
||||||
};
|
|
||||||
|
|
||||||
turbo-src-ko = fetchFromGitHub {
|
|
||||||
owner = "kernelsauce";
|
|
||||||
repo = "turbo";
|
|
||||||
name = "turbo";
|
|
||||||
rev = "v2.1.3";
|
|
||||||
hash = "sha256-vBRkFdc5a0FIt15HBz3TnqMZ+GGsqjEefnfJEpuVTBs=";
|
|
||||||
};
|
|
||||||
|
|
||||||
# XXX: for some inscrutable reason, `enable52Compat` is *partially* broken, only when cross compiling.
|
|
||||||
# `table.unpack` is non-nil, but `table.pack` is nil.
|
|
||||||
# the normal path is for `enable52Compat` to set `env.NIX_CFLAGS_COMPILE = "-DLUAJIT_ENABLE_LUA52COMPAT";`
|
|
||||||
# which in turn sets `#define LJ_52 1`, and gates functions like `table.pack`, `table.unpack`.
|
|
||||||
# instead, koreader just removes the `#if LJ_52` gates. doing the same in nixpkgs seems to work.
|
|
||||||
# luajit52 = luajit.override { enable52Compat = true; self = luajit52; };
|
|
||||||
luajit52 = (luajit.override { self = luajit52; }).overrideAttrs (super: {
|
|
||||||
patches = (super.patches or []) ++ [
|
|
||||||
"${src}/base/thirdparty/luajit/koreader-luajit-enable-table_pack.patch"
|
|
||||||
];
|
|
||||||
});
|
|
||||||
|
|
||||||
overlayedLuaPkgs = luaPkgs: let
|
overlayedLuaPkgs = luaPkgs: let
|
||||||
ps = with ps; {
|
ps = with ps; {
|
||||||
@@ -257,21 +264,6 @@ let
|
|||||||
} // luaPkgs;
|
} // luaPkgs;
|
||||||
in ps;
|
in ps;
|
||||||
|
|
||||||
luaEnv = luajit52.withPackages (ps: with (overlayedLuaPkgs ps); [
|
|
||||||
luajson
|
|
||||||
htmlparser
|
|
||||||
lua-spore
|
|
||||||
lpeg
|
|
||||||
luasec
|
|
||||||
luasocket
|
|
||||||
rapidjson
|
|
||||||
]);
|
|
||||||
|
|
||||||
rockspecFor = luaPkgName: let
|
|
||||||
pkg = (overlayedLuaPkgs luaEnv.pkgs)."${luaPkgName}";
|
|
||||||
in
|
|
||||||
"${luaEnv}/${pkg.rocksSubdir}/${luaPkgName}/${pkg.rockspecVersion}/${luaPkgName}-${pkg.rockspecVersion}.rockspec";
|
|
||||||
|
|
||||||
crossTargets = {
|
crossTargets = {
|
||||||
# koreader-base Makefile targets to use when compiling for the given host platform
|
# koreader-base Makefile targets to use when compiling for the given host platform
|
||||||
# only used when cross compiling
|
# only used when cross compiling
|
||||||
@@ -310,6 +302,37 @@ let
|
|||||||
|
|
||||||
# mostly for k2pdf, which expects lib/ and include/ for each dep to live side-by-side
|
# mostly for k2pdf, which expects lib/ and include/ for each dep to live side-by-side
|
||||||
libAndDev = pkg: fhsLib pkg { lib = true; include = true; };
|
libAndDev = pkg: fhsLib pkg { lib = true; include = true; };
|
||||||
|
in
|
||||||
|
stdenv.mkDerivation (finalAttrs: with finalAttrs; let
|
||||||
|
pins = lib.importJSON ./versions.json;
|
||||||
|
sources = sourcesFor pins;
|
||||||
|
|
||||||
|
# XXX: for some inscrutable reason, `enable52Compat` is *partially* broken, only when cross compiling.
|
||||||
|
# `table.unpack` is non-nil, but `table.pack` is nil.
|
||||||
|
# the normal path is for `enable52Compat` to set `env.NIX_CFLAGS_COMPILE = "-DLUAJIT_ENABLE_LUA52COMPAT";`
|
||||||
|
# which in turn sets `#define LJ_52 1`, and gates functions like `table.pack`, `table.unpack`.
|
||||||
|
# instead, koreader just removes the `#if LJ_52` gates. doing the same in nixpkgs seems to work.
|
||||||
|
# luajit52 = luajit.override { enable52Compat = true; self = luajit52; };
|
||||||
|
luajit52 = (luajit.override { self = luajit52; }).overrideAttrs (super: {
|
||||||
|
patches = (super.patches or []) ++ [
|
||||||
|
"${sources.koreader}/base/thirdparty/luajit/koreader-luajit-enable-table_pack.patch"
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
luaEnv = luajit52.withPackages (ps: with (overlayedLuaPkgs ps); [
|
||||||
|
luajson
|
||||||
|
htmlparser
|
||||||
|
lua-spore
|
||||||
|
lpeg
|
||||||
|
luasec
|
||||||
|
luasocket
|
||||||
|
rapidjson
|
||||||
|
]);
|
||||||
|
|
||||||
|
rockspecFor = luaPkgName: let
|
||||||
|
pkg = (overlayedLuaPkgs luaEnv.pkgs)."${luaPkgName}";
|
||||||
|
in
|
||||||
|
"${luaEnv}/${pkg.rocksSubdir}/${luaPkgName}/${pkg.rockspecVersion}/${luaPkgName}-${pkg.rockspecVersion}.rockspec";
|
||||||
|
|
||||||
# these probably have more dirs than they really need.
|
# these probably have more dirs than they really need.
|
||||||
djvulibreAll = fhsLib djvulibre { lib=true; include=true; flatInclude=true; };
|
djvulibreAll = fhsLib djvulibre { lib=true; include=true; flatInclude=true; };
|
||||||
@@ -323,7 +346,7 @@ let
|
|||||||
|
|
||||||
# values to provide to koreader/base/Makefile.defs.
|
# values to provide to koreader/base/Makefile.defs.
|
||||||
# should be ok to put this in `makeFlags` array, but i can't get that to work!
|
# should be ok to put this in `makeFlags` array, but i can't get that to work!
|
||||||
makefileDefs = ''
|
makefileDefs = with sources; ''
|
||||||
CURL_LIB="${lib.getLib curl}/lib/libcurl.so" \
|
CURL_LIB="${lib.getLib curl}/lib/libcurl.so" \
|
||||||
CURL_DIR="${lib.getDev curl}" \
|
CURL_DIR="${lib.getDev curl}" \
|
||||||
CZMQ_LIB="${lib.getLib czmq}/lib/libczmq.so" \
|
CZMQ_LIB="${lib.getLib czmq}/lib/libczmq.so" \
|
||||||
@@ -419,52 +442,22 @@ let
|
|||||||
ln -sf "${lib.getBin sdcv}/bin/sdcv" "${outdir}/sdcv"
|
ln -sf "${lib.getBin sdcv}/bin/sdcv" "${outdir}/sdcv"
|
||||||
ln -sf "${lib.getBin zsync}/bin/zsync" "${outdir}/zsync2"
|
ln -sf "${lib.getBin zsync}/bin/zsync" "${outdir}/zsync2"
|
||||||
'';
|
'';
|
||||||
|
in {
|
||||||
thirdparty = [
|
|
||||||
curl
|
|
||||||
czmq
|
|
||||||
djvulibre
|
|
||||||
dropbear
|
|
||||||
freetype
|
|
||||||
fribidi
|
|
||||||
gettext
|
|
||||||
giflib
|
|
||||||
glib
|
|
||||||
gnutar
|
|
||||||
harfbuzz
|
|
||||||
libiconvReal
|
|
||||||
libjpeg_turbo
|
|
||||||
libpng
|
|
||||||
libunibreak
|
|
||||||
libwebp
|
|
||||||
openssl
|
|
||||||
openssh
|
|
||||||
sdcv
|
|
||||||
SDL2
|
|
||||||
sqlite
|
|
||||||
utf8proc
|
|
||||||
zlib
|
|
||||||
zeromq4
|
|
||||||
zstd
|
|
||||||
zsync
|
|
||||||
];
|
|
||||||
in
|
|
||||||
stdenv.mkDerivation rec {
|
|
||||||
pname = "koreader-from-src";
|
pname = "koreader-from-src";
|
||||||
inherit version;
|
inherit (pins) version;
|
||||||
srcs = [
|
srcs = [
|
||||||
src
|
sources.koreader
|
||||||
fbink-src-ko
|
sources.fbink-src-ko
|
||||||
kobo-usbms-src-ko
|
sources.kobo-usbms-src-ko
|
||||||
leptonica-src-ko
|
sources.leptonica-src-ko
|
||||||
libk2pdfopt-src-ko
|
sources.libk2pdfopt-src-ko
|
||||||
lodepng-src-ko
|
sources.lodepng-src-ko
|
||||||
lunasvg-src-ko
|
sources.lunasvg-src-ko
|
||||||
minizip-src-ko
|
sources.minizip-src-ko
|
||||||
mupdf-src-ko
|
sources.mupdf-src-ko
|
||||||
popen-noshell-src-ko
|
sources.popen-noshell-src-ko
|
||||||
tesseract-src-ko
|
sources.tesseract-src-ko
|
||||||
turbo-src-ko
|
sources.turbo-src-ko
|
||||||
];
|
];
|
||||||
|
|
||||||
patches = [
|
patches = [
|
||||||
@@ -569,6 +562,8 @@ stdenv.mkDerivation rec {
|
|||||||
htmlparser
|
htmlparser
|
||||||
lua-spore
|
lua-spore
|
||||||
;
|
;
|
||||||
|
# XXX: `update` doesn't update everything -- just the toplevel version/hash
|
||||||
|
updateScript = [ ./update ];
|
||||||
};
|
};
|
||||||
|
|
||||||
meta = with lib; {
|
meta = with lib; {
|
||||||
@@ -580,4 +575,4 @@ stdenv.mkDerivation rec {
|
|||||||
license = licenses.agpl3Only;
|
license = licenses.agpl3Only;
|
||||||
maintainers = with maintainers; [ colinsane contrun neonfuz];
|
maintainers = with maintainers; [ colinsane contrun neonfuz];
|
||||||
};
|
};
|
||||||
}
|
})
|
||||||
|
50
pkgs/additional/koreader-from-src/update
Executable file
50
pkgs/additional/koreader-from-src/update
Executable file
@@ -0,0 +1,50 @@
|
|||||||
|
#!/usr/bin/env nix-shell
|
||||||
|
#!nix-shell -i bash -p bash curl jq moreutils nix-prefetch
|
||||||
|
# shellcheck shell=bash
|
||||||
|
#
|
||||||
|
# inspired by <repo:nixos/nixpkgs:pkgs/development/libraries/duckdb/update.sh>
|
||||||
|
|
||||||
|
cd /home/colin/nixos
|
||||||
|
# cd "$(dirname "${BASH_SOURCE[0]}")"
|
||||||
|
# nixpkgs=$(while [[ ! -e .git ]]; do [[ ${PWD} != / ]] || exit 1; cd ..; done; echo "${PWD}")
|
||||||
|
|
||||||
|
repo=koreader
|
||||||
|
owner=koreader
|
||||||
|
|
||||||
|
msg() {
|
||||||
|
echo "$*" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
get_latest() {
|
||||||
|
curl ${GITHUB_TOKEN:+" -u \":$GITHUB_TOKEN\""} -s \
|
||||||
|
"https://api.github.com/repos/${owner}/${repo}/releases/latest" | jq -r .tag_name
|
||||||
|
}
|
||||||
|
|
||||||
|
get_sha() {
|
||||||
|
curl ${GITHUB_TOKEN:+" -u \":$GITHUB_TOKEN\""} -s \
|
||||||
|
"https://api.github.com/repos/${owner}/${repo}/git/ref/tags/$1" | jq -r .object.sha
|
||||||
|
}
|
||||||
|
|
||||||
|
json_get() {
|
||||||
|
jq -r "$1" < 'versions.json'
|
||||||
|
}
|
||||||
|
|
||||||
|
json_set() {
|
||||||
|
jq --arg x "$2" "$1 = \$x" < 'versions.json' | sponge 'versions.json'
|
||||||
|
}
|
||||||
|
|
||||||
|
tag=$(get_latest)
|
||||||
|
version=${tag/v/}
|
||||||
|
|
||||||
|
msg "tag: $tag, version: $version"
|
||||||
|
|
||||||
|
[[ ${version} = $(json_get .version) ]] && { msg "${version} is up to date"; exit 0; }
|
||||||
|
sha=$(get_sha "${tag}")
|
||||||
|
sri=$(nix-prefetch --index 0 -E "koreader-from-src.overrideAttrs { version = \"${version}\"; }")
|
||||||
|
|
||||||
|
msg "sha: $sha, sri: $sri"
|
||||||
|
|
||||||
|
cd pkgs/additional/koreader-from-src
|
||||||
|
json_set ".version" "${version}"
|
||||||
|
json_set ".koreader.hash" "${sri}"
|
||||||
|
|
50
pkgs/additional/koreader-from-src/versions.json
Normal file
50
pkgs/additional/koreader-from-src/versions.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"version": "2024.04",
|
||||||
|
"koreader": {
|
||||||
|
"hash": "sha256-BQnKoTj90wWZNxGn1C9iL8y1tozqdEHMgQDfQZo2axg="
|
||||||
|
},
|
||||||
|
"fbink": {
|
||||||
|
"rev": "1a989b30a195ca240a3cf37f9de61b4b3c7e891c",
|
||||||
|
"hash": "sha256-lXjAX0BoHW3L1E54d5J+wiAlAZXVmj9Y1Un8yaCwO8w="
|
||||||
|
},
|
||||||
|
"kobo-usbms": {
|
||||||
|
"rev": "v1.3.9",
|
||||||
|
"hash": "sha256-91B0FUnmpE6TP4Lg5mj6z/U1DZQTKiPhG3ccCSgY4mQ="
|
||||||
|
},
|
||||||
|
"leptonica": {
|
||||||
|
"rev": "1.74.1",
|
||||||
|
"hash": "sha256-SDXKam768xvZZvTbXe3sssvZyeLEEiY97Vrzx8hoc6g="
|
||||||
|
},
|
||||||
|
"libk2pdfopt": {
|
||||||
|
"rev": "47caea57aaf6200fc2b24669b6417fe6919926b7",
|
||||||
|
"hash": "sha256-8Em4neXTovhrTb+GBhs6kDFEdsQSt5KiYoHURwdtjPQ="
|
||||||
|
},
|
||||||
|
"lodepng": {
|
||||||
|
"rev": "d398e0f10d152a5d17fa30463474dc9f56523f9c",
|
||||||
|
"hash": "sha256-ApOHUgU6X1rHwyjAHA/0Nt+buDFqY2ttXEnEvdrRl3A="
|
||||||
|
},
|
||||||
|
"lunasvg": {
|
||||||
|
"rev": "59d6f6ba835c1b7c7a0f9d4ea540ec3981777885",
|
||||||
|
"hash": "sha256-gW2ikakS6Omz5upmy26nAo/jkGHYO2kjlB3UmKJBh1k="
|
||||||
|
},
|
||||||
|
"minizip": {
|
||||||
|
"rev": "0b46a2b4ca317b80bc53594688883f7188ac4d08",
|
||||||
|
"hash": "sha256-P/3MMMGYDqD9NmkYvw/thKpUNa3wNOSlBBjANHSonAg="
|
||||||
|
},
|
||||||
|
"mupdf": {
|
||||||
|
"rev": "1.13.0",
|
||||||
|
"hash": "sha256-pQejRon9fO9A1mhz3oLjBr1j4HveDLcQIWjR1/Rpy5Q="
|
||||||
|
},
|
||||||
|
"popen-noshell": {
|
||||||
|
"rev": "e715396a4951ee91c40a98d2824a130f158268bb",
|
||||||
|
"hash": "sha256-JeBZMsg6ZUGSnyZ4eds4w63gM/L73EsAnLaHOPpL6iM="
|
||||||
|
},
|
||||||
|
"tesseract": {
|
||||||
|
"rev": "60176fc5ae5e7f6bdef60c926a4b5ea03de2bfa7",
|
||||||
|
"hash": "sha256-FQvlrJ+Uy7+wtUxBuS5NdoToUwNRhYw2ju8Ya8MLyQw="
|
||||||
|
},
|
||||||
|
"turbo": {
|
||||||
|
"rev": "v2.1.3",
|
||||||
|
"hash": "sha256-vBRkFdc5a0FIt15HBz3TnqMZ+GGsqjEefnfJEpuVTBs="
|
||||||
|
}
|
||||||
|
}
|
@@ -1,24 +1,30 @@
|
|||||||
# N.B.: landlock is a relatively new thing as of 2024/01, and undergoing ABI revisions.
|
# N.B.: landlock is a relatively new thing as of 2024/01, and undergoing ABI revisions.
|
||||||
# the ABI is versioned, and the sandboxer will work when run against either a newer or older kernel than it was built from,
|
# the ABI is versioned, and the sandboxer will work when run against either a newer or older kernel than it was built from,
|
||||||
# but it will complain (stderr) about an update being available if kernel max ABI != sandbox max ABI.
|
# but it will complain (stderr) about an update being available if kernel max ABI != sandbox max ABI.
|
||||||
{ stdenv
|
{
|
||||||
, linux
|
linux_latest,
|
||||||
, makeLinuxHeaders
|
makeLinuxHeaders,
|
||||||
|
stdenv,
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
|
|
||||||
linuxHeaders = makeLinuxHeaders {
|
linuxHeaders = makeLinuxHeaders {
|
||||||
inherit (linux) src version;
|
inherit (linux_latest) src version;
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
stdenv.mkDerivation rec {
|
stdenv.mkDerivation rec {
|
||||||
pname = "landlock-sandboxer";
|
pname = "landlock-sandboxer";
|
||||||
version = linux.version;
|
version = linux_latest.version;
|
||||||
src = linux.src;
|
src = linux_latest.src;
|
||||||
|
|
||||||
buildInputs = [
|
buildInputs = [
|
||||||
linuxHeaders # to get the right linux headers!
|
linuxHeaders # to get the right linux headers!
|
||||||
];
|
];
|
||||||
|
|
||||||
|
patches = [
|
||||||
|
./no-warn-old-kernel.diff
|
||||||
|
];
|
||||||
|
|
||||||
# starting in 6.9, the sandboxer prints diagnostics on startup,
|
# starting in 6.9, the sandboxer prints diagnostics on startup,
|
||||||
# which is annoying, and also risks breaking some users
|
# which is annoying, and also risks breaking some users
|
||||||
postPatch = ''
|
postPatch = ''
|
||||||
@@ -34,7 +40,7 @@ stdenv.mkDerivation rec {
|
|||||||
makeFlags = [ "sandboxer" ];
|
makeFlags = [ "sandboxer" ];
|
||||||
installPhase = ''
|
installPhase = ''
|
||||||
mkdir -p $out/bin
|
mkdir -p $out/bin
|
||||||
install -m755 sandboxer $out/bin
|
install -m755 sandboxer $out/bin/landlock-sandboxer
|
||||||
'';
|
'';
|
||||||
|
|
||||||
passthru = {
|
passthru = {
|
||||||
@@ -46,7 +52,7 @@ stdenv.mkDerivation rec {
|
|||||||
The goal of Landlock is to enable to restrict ambient rights (e.g. global filesystem access) for a set of processes.
|
The goal of Landlock is to enable to restrict ambient rights (e.g. global filesystem access) for a set of processes.
|
||||||
'';
|
'';
|
||||||
homepage = "https://landlock.io";
|
homepage = "https://landlock.io";
|
||||||
mainProgram = "sandboxer";
|
mainProgram = "landlock-sandboxer";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
17
pkgs/additional/landlock-sandboxer/no-warn-old-kernel.diff
Normal file
17
pkgs/additional/landlock-sandboxer/no-warn-old-kernel.diff
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
diff --git a/samples/landlock/sandboxer.c b/samples/landlock/sandboxer.c
|
||||||
|
index e8223c3e781a..e4583b8447a1 100644
|
||||||
|
--- a/samples/landlock/sandboxer.c
|
||||||
|
+++ b/samples/landlock/sandboxer.c
|
||||||
|
@@ -326,12 +326,6 @@ int main(const int argc, char *const argv[], char *const *const envp)
|
||||||
|
case 4:
|
||||||
|
/* Removes LANDLOCK_ACCESS_FS_IOCTL_DEV for ABI < 5 */
|
||||||
|
ruleset_attr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_IOCTL_DEV;
|
||||||
|
-
|
||||||
|
- fprintf(stderr,
|
||||||
|
- "Hint: You should update the running kernel "
|
||||||
|
- "to leverage Landlock features "
|
||||||
|
- "provided by ABI version %d (instead of %d).\n",
|
||||||
|
- LANDLOCK_ABI_LAST, abi);
|
||||||
|
__attribute__((fallthrough));
|
||||||
|
case LANDLOCK_ABI_LAST:
|
||||||
|
break;
|
22
pkgs/additional/libcap-with-captree/default.nix
Normal file
22
pkgs/additional/libcap-with-captree/default.nix
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# libcap nix package should eventually ship `captree`, but until then, patch it.
|
||||||
|
# this is a re-implementation of an outstanding PR, but in a way that doesn't force mass-rebuilds:
|
||||||
|
# - <https://github.com/NixOS/nixpkgs/pull/332399>
|
||||||
|
{
|
||||||
|
libcap,
|
||||||
|
go,
|
||||||
|
}: libcap.overrideAttrs (base: {
|
||||||
|
depsBuildBuild = base.depsBuildBuild ++ [ go ];
|
||||||
|
|
||||||
|
makeFlags = base.makeFlags ++ [
|
||||||
|
"GOLANG=yes"
|
||||||
|
''GOCACHE=''${TMPDIR}/go-cache''
|
||||||
|
"GOARCH=${go.GOARCH}"
|
||||||
|
"GOOS=${go.GOOS}"
|
||||||
|
];
|
||||||
|
|
||||||
|
postPatch = base.postPatch + ''
|
||||||
|
# disable cross compilation for artifacts which are run as part of the build
|
||||||
|
substituteInPlace go/Makefile \
|
||||||
|
--replace-fail '$(GO) run' 'GOOS= GOARCH= $(GO) run'
|
||||||
|
'';
|
||||||
|
})
|
41
pkgs/additional/libfuse-sane/default.nix
Normal file
41
pkgs/additional/libfuse-sane/default.nix
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
fuse3,
|
||||||
|
makeBinaryWrapper,
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
patched = fuse3.overrideAttrs (upstream: {
|
||||||
|
outputs = upstream.outputs ++ [ "sane" ];
|
||||||
|
defaultOutput = "sane";
|
||||||
|
patches = (upstream.patches or []) ++ [
|
||||||
|
./pass_fuse_fd.patch
|
||||||
|
];
|
||||||
|
nativeBuildInputs = (upstream.nativeBuildInputs or []) ++ [
|
||||||
|
makeBinaryWrapper
|
||||||
|
];
|
||||||
|
# wrap so that it looks for mount helpers in /run/current-system/sw/bin,
|
||||||
|
# and furthermore so that those mount helpers inherit the sandboxed wrappers in /run/current-system/sw/bin
|
||||||
|
postInstall = (upstream.postInstall or "") + ''
|
||||||
|
wrapProgram $out/sbin/mount.fuse3 \
|
||||||
|
--suffix PATH : /run/current-system/sw/bin
|
||||||
|
'';
|
||||||
|
postFixup = (upstream.postFixup or "") + ''
|
||||||
|
ln -s $out/bin/mount.fuse3 $out/bin/mount.fuse3.sane
|
||||||
|
moveToOutput bin/mount.fuse3.sane "$sane"
|
||||||
|
'';
|
||||||
|
meta = (upstream.meta or {}) // {
|
||||||
|
mainProgram = "mount.fuse3.sane";
|
||||||
|
description = ''
|
||||||
|
provides `mount.fuse3.sane`, which behaves identically to `mount.fuse3` except
|
||||||
|
it supports an additional mount flag, `-o pass_fuse_fd`.
|
||||||
|
|
||||||
|
when mounting with `-o pass_fuse_fd`, `mount.fuse3.sane` opens the `/dev/fuse` device (which requires CAP_SYS_ADMIN),
|
||||||
|
and then `exec`s the userspace implementation, which inherits this file descriptor.
|
||||||
|
`mount.fuse3.sane` invokes the userspace implementation with the device argument set to something like `/dev/fd/3`, indicating which fd holds the fuse device.
|
||||||
|
|
||||||
|
the aim of this flag is to provide a clear handoff point at which the filesystem may drop CAP_SYS_ADMIN.
|
||||||
|
in this regard, it's much like `-o drop_privileges`, only it leaves the responsibility for that to the fs impl,
|
||||||
|
in case the fs needs to preserve _other_ privileges besides CAP_SYS_ADMIN.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
});
|
||||||
|
in patched.sane
|
15
pkgs/additional/libfuse-sane/pass_fuse_fd.patch
Normal file
15
pkgs/additional/libfuse-sane/pass_fuse_fd.patch
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
diff --git a/util/mount.fuse.c b/util/mount.fuse.c
|
||||||
|
index b98fb2a..f46c4f7 100644
|
||||||
|
--- a/util/mount.fuse.c
|
||||||
|
+++ b/util/mount.fuse.c
|
||||||
|
@@ -327,6 +327,10 @@ int main(int argc, char *argv[])
|
||||||
|
if (strncmp(opt, "setuid=", 7) == 0) {
|
||||||
|
setuid_name = xstrdup(opt + 7);
|
||||||
|
ignore = 1;
|
||||||
|
+ } else if (strcmp(opt,
|
||||||
|
+ "pass_fuse_fd") == 0) {
|
||||||
|
+ pass_fuse_fd = 1;
|
||||||
|
+ ignore = 1;
|
||||||
|
} else if (strcmp(opt,
|
||||||
|
"drop_privileges") == 0) {
|
||||||
|
pass_fuse_fd = 1;
|
17645
pkgs/additional/newsflash-nixified/Cargo.nix
Normal file
17645
pkgs/additional/newsflash-nixified/Cargo.nix
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user