Compare commits
1 Commits
dev
...
wip-nm-sys
Author | SHA1 | Date | |
---|---|---|---|
5ec159bbf5 |
@@ -3,7 +3,6 @@ keys:
|
|||||||
- &user_lappy_colin age1j2pqnl8j0krdzk6npe93s4nnqrzwx978qrc0u570gzlamqpnje9sc8le2g
|
- &user_lappy_colin age1j2pqnl8j0krdzk6npe93s4nnqrzwx978qrc0u570gzlamqpnje9sc8le2g
|
||||||
- &user_servo_colin age1z8fauff34cdecr6sjkre260luzxcca05kpcwvhx988d306tpcejsp63znu
|
- &user_servo_colin age1z8fauff34cdecr6sjkre260luzxcca05kpcwvhx988d306tpcejsp63znu
|
||||||
- &user_moby_colin age1zsrsvd7j6l62fjxpfd2qnhqlk8wk4p8r0dtxpe4sdgnh2474095qdu7xj9
|
- &user_moby_colin age1zsrsvd7j6l62fjxpfd2qnhqlk8wk4p8r0dtxpe4sdgnh2474095qdu7xj9
|
||||||
- &host_crappy age1hl50ufuxnqy0jnk8fqeu4tclh4vte2xn2d59pxff0gun20vsmv5sp78chj
|
|
||||||
- &host_desko age1vnw7lnfpdpjn62l3u5nyv5xt2c965k96p98kc43mcnyzpetrts9q54mc9v
|
- &host_desko age1vnw7lnfpdpjn62l3u5nyv5xt2c965k96p98kc43mcnyzpetrts9q54mc9v
|
||||||
- &host_lappy age1w7mectcjku6x3sd8plm8wkn2qfrhv9n6zhzlf329e2r2uycgke8qkf9dyn
|
- &host_lappy age1w7mectcjku6x3sd8plm8wkn2qfrhv9n6zhzlf329e2r2uycgke8qkf9dyn
|
||||||
- &host_servo age1tzlyex2z6t88tg9h82943e39shxhmqeyr7ywhlwpdjmyqsndv3qq27x0rf
|
- &host_servo age1tzlyex2z6t88tg9h82943e39shxhmqeyr7ywhlwpdjmyqsndv3qq27x0rf
|
||||||
@@ -16,7 +15,6 @@ creation_rules:
|
|||||||
- *user_lappy_colin
|
- *user_lappy_colin
|
||||||
- *user_servo_colin
|
- *user_servo_colin
|
||||||
- *user_moby_colin
|
- *user_moby_colin
|
||||||
- *host_crappy
|
|
||||||
- *host_desko
|
- *host_desko
|
||||||
- *host_lappy
|
- *host_lappy
|
||||||
- *host_servo
|
- *host_servo
|
||||||
|
25
README.md
25
README.md
@@ -2,8 +2,6 @@
|
|||||||
|
|
||||||
# .❄️≡We|_c0m3 7o m`/ f14k≡❄️.
|
# .❄️≡We|_c0m3 7o m`/ f14k≡❄️.
|
||||||
|
|
||||||
(er, it's not a flake anymore. welcome to my nix files.)
|
|
||||||
|
|
||||||
## What's Here
|
## What's Here
|
||||||
|
|
||||||
this is the top-level repo from which i configure/deploy all my NixOS machines:
|
this is the top-level repo from which i configure/deploy all my NixOS machines:
|
||||||
@@ -31,7 +29,11 @@ you might specifically be interested in these files (elaborated further in #key-
|
|||||||
|
|
||||||
## Using This Repo In Your Own Config
|
## Using This Repo In Your Own Config
|
||||||
|
|
||||||
follow the instructions [here][NUR] to access my packages through the Nix User Repositories.
|
this should be a pretty "standard" flake. just reference it, and import either
|
||||||
|
- `nixosModules.sane` (for the modules)
|
||||||
|
- `overlays.pkgs` (for the packages)
|
||||||
|
|
||||||
|
or follow the instructions [here][NUR] to use it via the Nix User Repositories.
|
||||||
|
|
||||||
[NUR]: https://nur.nix-community.org/
|
[NUR]: https://nur.nix-community.org/
|
||||||
|
|
||||||
@@ -39,15 +41,19 @@ follow the instructions [here][NUR] to access my packages through the Nix User R
|
|||||||
- `doc/`
|
- `doc/`
|
||||||
- instructions for tasks i find myself doing semi-occasionally in this repo.
|
- instructions for tasks i find myself doing semi-occasionally in this repo.
|
||||||
- `hosts/`
|
- `hosts/`
|
||||||
- configs which aren't factored with external use in mind.
|
- the bulk of config which isn't factored with external use in mind.
|
||||||
- that is, if you were to add this repo to a flake.nix for your own use,
|
- that is, if you were to add this repo to a flake.nix for your own use,
|
||||||
you won't likely be depending on anything in this directory.
|
you won't likely be depending on anything in this directory.
|
||||||
- `integrations/`
|
- `integrations/`
|
||||||
- code intended for consumption by external tools (e.g. the Nix User Repos).
|
- code intended for consumption by external tools (e.g. the Nix User Repos)
|
||||||
- `modules/`
|
- `modules/`
|
||||||
- config which is gated behind `enable` flags, in similar style to nixpkgs' `nixos/` directory.
|
- config which is gated behind `enable` flags, in similar style to nixpkgs'
|
||||||
- if you depend on this repo for anything besides packages, it's most likely for something in this directory.
|
`nixos/` directory.
|
||||||
|
- if you depend on this repo, it's most likely for something in this directory.
|
||||||
|
- `nixpatches/`
|
||||||
|
- literally, diffs i apply atop upstream nixpkgs before performing further eval.
|
||||||
- `overlays/`
|
- `overlays/`
|
||||||
|
- exposed via the `overlays` output in `flake.nix`.
|
||||||
- predominantly a list of `callPackage` directives.
|
- predominantly a list of `callPackage` directives.
|
||||||
- `pkgs/`
|
- `pkgs/`
|
||||||
- derivations for things not yet packaged in nixpkgs.
|
- derivations for things not yet packaged in nixpkgs.
|
||||||
@@ -55,12 +61,13 @@ follow the instructions [here][NUR] to access my packages through the Nix User R
|
|||||||
- inline code for wholly custom packages (e.g. `pkgs/additional/sane-scripts/` for CLI tools
|
- inline code for wholly custom packages (e.g. `pkgs/additional/sane-scripts/` for CLI tools
|
||||||
that are highly specific to my setup).
|
that are highly specific to my setup).
|
||||||
- `scripts/`
|
- `scripts/`
|
||||||
- scripts which aren't reachable on a deployed system, but may aid manual deployments.
|
- scripts which aren't reachable on a deployed system, but may aid manual deployments
|
||||||
- `secrets/`
|
- `secrets/`
|
||||||
- encrypted keys, API tokens, anything which one or more of my machines needs
|
- encrypted keys, API tokens, anything which one or more of my machines needs
|
||||||
read access to but shouldn't be world-readable.
|
read access to but shouldn't be world-readable.
|
||||||
- not much to see here.
|
- not much to see here
|
||||||
- `templates/`
|
- `templates/`
|
||||||
|
- exposed via the `templates` output in `flake.nix`.
|
||||||
- used to instantiate short-lived environments.
|
- used to instantiate short-lived environments.
|
||||||
- used to auto-fill the boiler-plate portions of new packages.
|
- used to auto-fill the boiler-plate portions of new packages.
|
||||||
|
|
||||||
|
43
TODO.md
43
TODO.md
@@ -2,18 +2,21 @@
|
|||||||
- `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
|
||||||
|
- moby: touchscreen input is still enabled when screen is off
|
||||||
- when moby wlan is explicitly set down (via ip link set wlan0 down), /var/lib/trust-dns/dhcp-configs doesn't get reset
|
- when moby wlan is explicitly set down (via ip link set wlan0 down), /var/lib/trust-dns/dhcp-configs doesn't get reset
|
||||||
- `ip monitor` can detect those manual link state changes (NM-dispatcher it seems cannot)
|
- `ip monitor` can detect those manual link state changes (NM-dispatcher it seems cannot)
|
||||||
- or try dnsmasq?
|
- or try dnsmasq?
|
||||||
- trust-dns: can't recursively resolve api.mangadex.org
|
- trust-dns: can't recursively resolve api.mangadex.org
|
||||||
- nor `m.wikipedia.org` (`dyna.wikipedia.org`)
|
|
||||||
- and *sometimes* apple.com fails
|
- and *sometimes* apple.com fails
|
||||||
- sandbox: link cache means that if i update ~/.config/... files inline, sandboxed programs still see the old version
|
- sandbox: link cache means that if i update ~/.config/... files inline, sandboxed programs still see the old version
|
||||||
- mpv: audiocast has mpv sending its output to the builtin speakers unless manually changed
|
- mpv: audiocast has mpv sending its output to the builtin speakers unless manually changed
|
||||||
- mpv: no way to exit fullscreen video on moby
|
- mpv: no way to exit fullscreen video on moby
|
||||||
- uosc hides controls on FS, and touch doesn't support unhiding
|
- uosc hides controls on FS, and touch doesn't support unhiding
|
||||||
|
- Signal restart loop drains battery
|
||||||
|
- decrease s6 restart time?
|
||||||
- `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
|
- ringer (i.e. dino incoming call) doesn't prevent moby from sleeping
|
||||||
|
- sysvol (volume overlay): when casting with `blast`, sysvol doesn't react to volume changes
|
||||||
- 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`
|
||||||
@@ -22,12 +25,6 @@
|
|||||||
- moby: bpf is effectively disabled?
|
- moby: bpf is effectively disabled?
|
||||||
- `dmesg | grep 'systemd[1]: bpf-lsm: Failed to load BPF object: No such process'`
|
- `dmesg | grep 'systemd[1]: bpf-lsm: Failed to load BPF object: No such process'`
|
||||||
- `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
|
|
||||||
- so if the desktop crashes, the login process from `unl0kr` fails to re-launch the GUI
|
|
||||||
- nwg-panel will sometimes create nested bars (happens maybe when i turn an external display off, then on?)
|
|
||||||
- wg-home is unreachable for a couple minutes when switching between LAN/WAN/3G
|
|
||||||
- because the endpoint DNS changes.
|
|
||||||
- causes calls to not transfer from WiFi -> cellular.
|
|
||||||
|
|
||||||
## REFACTORING:
|
## REFACTORING:
|
||||||
- add import checks to my Python nix-shell scripts
|
- add import checks to my Python nix-shell scripts
|
||||||
@@ -67,8 +64,6 @@
|
|||||||
- /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 `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:...`.
|
||||||
@@ -83,16 +78,23 @@
|
|||||||
- it adds like 50-70ms launch time _on my laptop_. i'd hate to know how much that is on the pinephone.
|
- it adds like 50-70ms launch time _on my laptop_. i'd hate to know how much that is on the pinephone.
|
||||||
- make dconf stuff less monolithic
|
- make dconf stuff less monolithic
|
||||||
- i.e. per-app dconf profiles for those which need it. possible static config.
|
- i.e. per-app dconf profiles for those which need it. possible static config.
|
||||||
- flatpak/spectrum has some stuff to proxy dconf per-app
|
- canaries for important services
|
||||||
|
- e.g. daily email checks; daily backup checks
|
||||||
|
- integrate `nix check` into Gitea actions?
|
||||||
|
|
||||||
|
#### sudo-free world
|
||||||
|
- `systemctl restart FOO`: needs `sudo`
|
||||||
|
- `systemctl daemon-reload`: needs sudo
|
||||||
|
- `watch ifconfig`: needs `SANEBOX_DISABLE=1`
|
||||||
|
|
||||||
### user experience
|
### user experience
|
||||||
- rofi: sort items case-insensitively
|
- rofi: sort items case-insensitively
|
||||||
|
- xdg-desktop-portal shouldn't kill children on exit
|
||||||
|
- *maybe* a job for `setsid -f`?
|
||||||
- replace starship prompt with something more efficient
|
- replace starship prompt with something more efficient
|
||||||
- watch `forkstat`: it does way too much
|
- watch `forkstat`: it does way too much
|
||||||
- cleanup waybar/nwg-panel so that it's not invoking playerctl every 2 seconds
|
- cleanup waybar so that it's not invoking playerctl every 2 seconds
|
||||||
- nwg-panel: doesn't know that virtual-desktop 10/TV exists
|
|
||||||
- install apps:
|
- install apps:
|
||||||
- compass viewer (moby)
|
|
||||||
- display QR codes for WiFi endpoints: <https://linuxphoneapps.org/apps/noappid.wisperwind.wifi2qr/>
|
- display QR codes for WiFi endpoints: <https://linuxphoneapps.org/apps/noappid.wisperwind.wifi2qr/>
|
||||||
- shopping list (not in nixpkgs): <https://linuxphoneapps.org/apps/ro.hume.cosmin.shoppinglist/>
|
- shopping list (not in nixpkgs): <https://linuxphoneapps.org/apps/ro.hume.cosmin.shoppinglist/>
|
||||||
- offline Wikipedia (or, add to `wike`)
|
- offline Wikipedia (or, add to `wike`)
|
||||||
@@ -101,7 +103,6 @@
|
|||||||
- Gnome Highscore (retro games)?: <https://gitlab.gnome.org/World/highscore>
|
- Gnome Highscore (retro games)?: <https://gitlab.gnome.org/World/highscore>
|
||||||
- better maps for mobile (Osmin (QtQuick)? Pure Maps (Qt/Kirigami)?
|
- better maps for mobile (Osmin (QtQuick)? Pure Maps (Qt/Kirigami)?
|
||||||
- note-taking app: <https://linuxphoneapps.org/categories/note-taking/>
|
- note-taking app: <https://linuxphoneapps.org/categories/note-taking/>
|
||||||
- Folio is nice, uses standard markdown, though it only supports flat repos
|
|
||||||
- OSK overlay specifically for mobile gaming
|
- OSK overlay specifically for mobile gaming
|
||||||
- i.e. mock joysticks, for use with SuperTux and SuperTuxKart
|
- i.e. mock joysticks, for use with SuperTux and SuperTuxKart
|
||||||
- install mobile-friendly games:
|
- install mobile-friendly games:
|
||||||
@@ -122,11 +123,13 @@
|
|||||||
- don't show MPRIS if no players detected
|
- don't show MPRIS if no players detected
|
||||||
- this is a problem of playerctld, i guess
|
- this is a problem of playerctld, i guess
|
||||||
- add option to change audio output
|
- add option to change audio output
|
||||||
|
- fix colors (red alert) to match overall theme
|
||||||
- moby: tune GPS
|
- moby: tune GPS
|
||||||
- fix iio-sensor-proxy magnetometer scaling
|
- run only geoclue, and not gpsd, to save power?
|
||||||
- tune QGPS setting in eg25-control, for less jitter?
|
- tune QGPS setting in eg25-control, for less jitter?
|
||||||
|
- direct mepo to prefer gpsd, with fallback to geoclue, for better accuracy?
|
||||||
- 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/gpsd?
|
||||||
- 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: show battery state on ssh login
|
||||||
- moby: improve gPodder launch time
|
- moby: improve gPodder launch time
|
||||||
@@ -153,9 +156,13 @@
|
|||||||
- email: fix so that local mail doesn't go to junk
|
- email: fix so that local mail doesn't go to junk
|
||||||
- git sendmail flow adds the DKIM signatures, but gets delivered locally w/o having the sig checked, so goes into Junk
|
- git sendmail flow adds the DKIM signatures, but gets delivered locally w/o having the sig checked, so goes into Junk
|
||||||
- could change junk filter from "no DKIM success" to explicit "DKIM failed"
|
- could change junk filter from "no DKIM success" to explicit "DKIM failed"
|
||||||
- add an auto-reply address (e.g. `reply-test@uninsane.org`) which reflects all incoming mail; use this (or a friend running this) for liveness checks
|
|
||||||
|
|
||||||
### perf
|
### perf
|
||||||
|
- debug nixos-rebuild times
|
||||||
|
- use `systemctl list-jobs` to show what's being waited on
|
||||||
|
- i think it's `systemd-networkd-wait-online.service` that's blocking this?
|
||||||
|
- i wonder what interface it's waiting for. i should use `--ignore=...` to ignore interfaces i don't care about.
|
||||||
|
- also `wireguard-wg-home.target` when net is offline
|
||||||
- add `pkgs.impure-cached.<foo>` package set to build things with ccache enabled
|
- add `pkgs.impure-cached.<foo>` package set to build things with ccache enabled
|
||||||
- every package here can be auto-generated, and marked with some env var so that it doesn't pollute the pure package set
|
- every package here can be auto-generated, and marked with some env var so that it doesn't pollute the pure package set
|
||||||
- would be super handy for package prototyping!
|
- would be super handy for package prototyping!
|
||||||
|
14
default.nix
14
default.nix
@@ -1,5 +1,9 @@
|
|||||||
{ ... }@args:
|
# limited, non-flake interface to this repo.
|
||||||
let
|
# this file exposes the same view into `pkgs` which the flake would see when evaluated.
|
||||||
sane-nix-files = import ./pkgs/additional/sane-nix-files { };
|
#
|
||||||
in
|
# the primary purpose of this file is so i can run `updateScript`s which expect
|
||||||
import "${sane-nix-files}/impure.nix" args
|
# the root to be `default.nix`
|
||||||
|
{ pkgs ? import <nixpkgs> {} }:
|
||||||
|
pkgs.appendOverlays [
|
||||||
|
(import ./overlays/all.nix)
|
||||||
|
]
|
||||||
|
@@ -1,25 +0,0 @@
|
|||||||
to add a host:
|
|
||||||
- create the new nix targets
|
|
||||||
- hosts/by-name/HOST
|
|
||||||
- let the toplevel (flake.nix) know about HOST
|
|
||||||
- build and flash an image
|
|
||||||
- optionally expand the rootfs
|
|
||||||
- `cfdisk /dev/sda2` -> resize partition
|
|
||||||
- `mount /dev/sda2 boot`
|
|
||||||
- `btrfs filesystem resize max root`
|
|
||||||
- setup required persistent directories
|
|
||||||
- `mkdir -p root/persist/private`
|
|
||||||
- `gocryptfs -init root/persist/private`
|
|
||||||
- then boot the device, and for every dangling symlink in ~/.local/share, ~/.cache, do `mkdir -p` on it
|
|
||||||
- setup host ssh
|
|
||||||
- `mkdir -p root/persist/plaintext/etc/ssh/host_keys`
|
|
||||||
- boot the machine and let it create its own ssh keys
|
|
||||||
- add the pubkey to `hosts/common/hosts.nix`
|
|
||||||
- setup user ssh
|
|
||||||
- `ssh-keygen`. don't enter any password; it's stored in a password-encrypted fs.
|
|
||||||
- add the pubkey to `hosts/common/hosts.nix`
|
|
||||||
- allow the new host to view secrets
|
|
||||||
- instructions in hosts/common/secrets.nix
|
|
||||||
- run `ssh-to-age` on user/host pubkeys
|
|
||||||
- add age key to .sops.yaml
|
|
||||||
- update encrypted secrets: `sops updatekeys path/to/secret.yaml`
|
|
@@ -1,12 +0,0 @@
|
|||||||
## deploying to SD card
|
|
||||||
- build a toplevel config: `nix build '.#hostSystems.moby'`
|
|
||||||
- mount a system:
|
|
||||||
- `mkdir -p root/{nix,boot}`
|
|
||||||
- `mount /dev/sdX1 root/boot`
|
|
||||||
- `mount /dev/sdX2 root/nix`
|
|
||||||
- copy the config:
|
|
||||||
- `sudo nix copy --no-check-sigs --to root/ $(readlink result)`
|
|
||||||
- nix will copy stuff to `root/nix/store`
|
|
||||||
- install the boot files:
|
|
||||||
- `sudo /nix/store/sbwpwngjlgw4f736ay9hgi69pj3fdwk5-extlinux-conf-builder.sh -d ./root/boot -t 5 -c $(readlink ./result)`
|
|
||||||
- extlinux-conf-builder can be found in `/run/current-system/bin/switch-to-configuration`
|
|
330
flake.lock
generated
Normal file
330
flake.lock
generated
Normal file
@@ -0,0 +1,330 @@
|
|||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"flake-compat": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1688025799,
|
||||||
|
"narHash": "sha256-ktpB4dRtnksm9F5WawoIkEneh1nrEvuxb5lJFt1iOyw=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "flake-compat",
|
||||||
|
"rev": "8bf105319d44f6b9f0d764efa4fdef9f1cc9ba1c",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "flake-compat",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flake-parts": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs-lib": [
|
||||||
|
"nixpkgs-wayland",
|
||||||
|
"nix-eval-jobs",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1712014858,
|
||||||
|
"narHash": "sha256-sB4SWl2lX95bExY2gMFG5HIzvva5AVMJd4Igm+GpZNw=",
|
||||||
|
"owner": "hercules-ci",
|
||||||
|
"repo": "flake-parts",
|
||||||
|
"rev": "9126214d0a59633752a136528f5f3b9aa8565b7d",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hercules-ci",
|
||||||
|
"repo": "flake-parts",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flake-utils": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1710146030,
|
||||||
|
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lib-aggregate": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils",
|
||||||
|
"nixpkgs-lib": "nixpkgs-lib"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1716725378,
|
||||||
|
"narHash": "sha256-bNTVDAVBLFSSTU+q54cJnntmFKBi+F/D8sSqlZwBGiM=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "lib-aggregate",
|
||||||
|
"rev": "dbc9130fe1455e0f6ee4d8f5f799f9be551f866b",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "lib-aggregate",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mobile-nixos": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1694749521,
|
||||||
|
"narHash": "sha256-MiVokKlpcJmfoGuWAMeW1En7gZ5hk0rCQArYm6P9XCc=",
|
||||||
|
"owner": "nixos",
|
||||||
|
"repo": "mobile-nixos",
|
||||||
|
"rev": "d25d3b87e7f300d8066e31d792337d9cd7ecd23b",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nixos",
|
||||||
|
"ref": "d25d3b87e7f300d8066e31d792337d9cd7ecd23b",
|
||||||
|
"repo": "mobile-nixos",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nix-eval-jobs": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-parts": "flake-parts",
|
||||||
|
"nix-github-actions": "nix-github-actions",
|
||||||
|
"nixpkgs": "nixpkgs",
|
||||||
|
"treefmt-nix": "treefmt-nix"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1715804156,
|
||||||
|
"narHash": "sha256-GtIHP86Cz1kD9xZO/cKbNQACHKdoT9WFbLJAq6W2EDY=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nix-eval-jobs",
|
||||||
|
"rev": "bb95091f6c6f38f6cfc215a1797a2dd466312c8b",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nix-eval-jobs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nix-github-actions": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs-wayland",
|
||||||
|
"nix-eval-jobs",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1703863825,
|
||||||
|
"narHash": "sha256-rXwqjtwiGKJheXB43ybM8NwWB8rO2dSRrEqes0S7F5Y=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nix-github-actions",
|
||||||
|
"rev": "5163432afc817cf8bd1f031418d1869e4c9d5547",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nix-github-actions",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1715037484,
|
||||||
|
"narHash": "sha256-OUt8xQFmBU96Hmm4T9tOWTu4oCswCzoVl+pxSq/kiFc=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "ad7efee13e0d216bf29992311536fce1d3eefbef",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixpkgs-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs-lib": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1716684580,
|
||||||
|
"narHash": "sha256-sIbMJWJr4hl2PWd9/iWlh89QfVzBn1NJ3u5RjeZADuM=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nixpkgs.lib",
|
||||||
|
"rev": "d0d27192931680482081aa1c38389da2af84a651",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nixpkgs.lib",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs-next-unpatched": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1717372940,
|
||||||
|
"narHash": "sha256-fK1PJqC8kQOy8rD7B+qmJOTx9IV8AOmFtH5Z/ip7340=",
|
||||||
|
"owner": "nixos",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "c987c730bbf2121264ebd68921b443db5bb28543",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nixos",
|
||||||
|
"ref": "staging-next",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs-stable": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1717265169,
|
||||||
|
"narHash": "sha256-IITcGd6xpNoyq9SZBigCkv4+qMHSqot0RDPR4xsZ2CA=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "3b1b4895b2c5f9f5544d02132896aeb9ceea77bc",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "release-23.11",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs-unpatched": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1717392304,
|
||||||
|
"narHash": "sha256-i9Kh2ty++/xMj4GPTMI7vQrpH4jopjT4BUq2GKX1zug=",
|
||||||
|
"owner": "nixos",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "77a51024c0f953d503eb3ed364aa4bff378649f8",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nixos",
|
||||||
|
"ref": "master",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs-wayland": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-compat": "flake-compat",
|
||||||
|
"lib-aggregate": "lib-aggregate",
|
||||||
|
"nix-eval-jobs": "nix-eval-jobs",
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs-unpatched"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1717175759,
|
||||||
|
"narHash": "sha256-KiM5ue/UNQt8ktoqCV4yFqhHxM31U94Mf/piKW9dZ4c=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nixpkgs-wayland",
|
||||||
|
"rev": "93b225ddba91179248b378913a91defbc6aeb899",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nixpkgs-wayland",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"mobile-nixos": "mobile-nixos",
|
||||||
|
"nixpkgs-next-unpatched": "nixpkgs-next-unpatched",
|
||||||
|
"nixpkgs-unpatched": "nixpkgs-unpatched",
|
||||||
|
"nixpkgs-wayland": "nixpkgs-wayland",
|
||||||
|
"sops-nix": "sops-nix",
|
||||||
|
"uninsane-dot-org": "uninsane-dot-org"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sops-nix": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs-unpatched"
|
||||||
|
],
|
||||||
|
"nixpkgs-stable": "nixpkgs-stable"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1717297459,
|
||||||
|
"narHash": "sha256-cZC2f68w5UrJ1f+2NWGV9Gx0dEYmxwomWN2B0lx0QRA=",
|
||||||
|
"owner": "Mic92",
|
||||||
|
"repo": "sops-nix",
|
||||||
|
"rev": "ab2a43b0d21d1d37d4d5726a892f714eaeb4b075",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "Mic92",
|
||||||
|
"repo": "sops-nix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"treefmt-nix": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs-wayland",
|
||||||
|
"nix-eval-jobs",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1711963903,
|
||||||
|
"narHash": "sha256-N3QDhoaX+paWXHbEXZapqd1r95mdshxToGowtjtYkGI=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "treefmt-nix",
|
||||||
|
"rev": "49dc4a92b02b8e68798abd99184f228243b6e3ac",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "treefmt-nix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uninsane-dot-org": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs-unpatched"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1715894399,
|
||||||
|
"narHash": "sha256-h1EdA/h74zgNPNEYbH+0mgOMlJgLVcxuZ8/ewsZlgEc=",
|
||||||
|
"ref": "refs/heads/master",
|
||||||
|
"rev": "e6f88f563bdd1700c04018951de4f69862646dd1",
|
||||||
|
"revCount": 240,
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://git.uninsane.org/colin/uninsane"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://git.uninsane.org/colin/uninsane"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
655
flake.nix
Normal file
655
flake.nix
Normal file
@@ -0,0 +1,655 @@
|
|||||||
|
# FLAKE FEEDBACK:
|
||||||
|
# - if flake inputs are meant to be human-readable, a human should be able to easily track them down given the URL.
|
||||||
|
# - this is not the case with registry URLs, like `nixpkgs/nixos-22.11`.
|
||||||
|
# - this is marginally the case with schemes like `github:nixos/nixpkgs`.
|
||||||
|
# - given the *existing* `git+https://` scheme, i propose expressing github URLs similarly:
|
||||||
|
# - `github+https://github.com/nixos/nixpkgs/tree/nixos-22.11`
|
||||||
|
# - this would allow for the same optimizations as today's `github:nixos/nixpkgs`, but without obscuring the source.
|
||||||
|
# a code reader could view the source being referenced simply by clicking the https:// portion of that URI.
|
||||||
|
# - need some way to apply local patches to inputs.
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# DEVELOPMENT DOCS:
|
||||||
|
# - Flake docs: <https://nixos.wiki/wiki/Flakes>
|
||||||
|
# - Flake RFC: <https://github.com/tweag/rfcs/blob/flakes/rfcs/0049-flakes.md>
|
||||||
|
# - Discussion: <https://github.com/NixOS/rfcs/pull/49>
|
||||||
|
# - <https://serokell.io/blog/practical-nix-flakes>
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# COMMON OPERATIONS:
|
||||||
|
# - update a specific flake input:
|
||||||
|
# - `nix flake lock --update-input nixpkgs`
|
||||||
|
|
||||||
|
{
|
||||||
|
# XXX: use the `github:` scheme instead of the more readable git+https: because it's *way* more efficient
|
||||||
|
# preferably, i would rewrite the human-readable https URLs to nix-specific github: URLs with a helper,
|
||||||
|
# but `inputs` is required to be a strict attrset: not an expression.
|
||||||
|
inputs = {
|
||||||
|
# branch workflow:
|
||||||
|
# - daily:
|
||||||
|
# - nixos-unstable cut from master after enough packages have been built in caches.
|
||||||
|
# - every 6 hours:
|
||||||
|
# - master auto-merged into staging and staging-next
|
||||||
|
# - staging-next auto-merged into staging.
|
||||||
|
# - manually, approximately once per month:
|
||||||
|
# - staging-next is cut from staging.
|
||||||
|
# - staging-next merged into master.
|
||||||
|
#
|
||||||
|
# which branch to source from?
|
||||||
|
# - nixos-unstable: for everyday development; it provides good caching
|
||||||
|
# - master: temporarily if i'm otherwise cherry-picking lots of already-applied patches
|
||||||
|
# - staging-next: if testing stuff that's been PR'd into staging, i.e. base library updates.
|
||||||
|
# - staging: maybe if no staging-next -> master PR has been cut yet?
|
||||||
|
#
|
||||||
|
# <https://github.com/nixos/nixpkgs/tree/nixos-unstable>
|
||||||
|
# nixpkgs-unpatched.url = "github:nixos/nixpkgs?ref=nixos-unstable";
|
||||||
|
nixpkgs-unpatched.url = "github:nixos/nixpkgs?ref=master";
|
||||||
|
# nixpkgs-unpatched.url = "github:nixos/nixpkgs?ref=nixos-staging";
|
||||||
|
# nixpkgs-unpatched.url = "github:nixos/nixpkgs?ref=nixos-staging-next";
|
||||||
|
nixpkgs-next-unpatched.url = "github:nixos/nixpkgs?ref=staging-next";
|
||||||
|
|
||||||
|
nixpkgs-wayland = {
|
||||||
|
url = "github:nix-community/nixpkgs-wayland";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs-unpatched";
|
||||||
|
};
|
||||||
|
|
||||||
|
mobile-nixos = {
|
||||||
|
# <https://github.com/nixos/mobile-nixos>
|
||||||
|
# only used for building disk images, not relevant after deployment
|
||||||
|
# TODO: replace with something else. commit `0f3ac0bef1aea70254a3bae35e3cc2561623f4c1`
|
||||||
|
# replaces the imageBuilder with a "new implementation from celun" and wildly breaks my use.
|
||||||
|
# pinning to d25d3b... is equivalent to holding at 2023-09-15
|
||||||
|
url = "github:nixos/mobile-nixos?ref=d25d3b87e7f300d8066e31d792337d9cd7ecd23b";
|
||||||
|
flake = false;
|
||||||
|
};
|
||||||
|
sops-nix = {
|
||||||
|
# <https://github.com/Mic92/sops-nix>
|
||||||
|
# used to distribute secrets to my hosts
|
||||||
|
url = "github:Mic92/sops-nix";
|
||||||
|
# inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs-unpatched";
|
||||||
|
};
|
||||||
|
uninsane-dot-org = {
|
||||||
|
# provides the package to deploy <https://uninsane.org>, used only when building the servo host
|
||||||
|
url = "git+https://git.uninsane.org/colin/uninsane";
|
||||||
|
# inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs-unpatched";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = {
|
||||||
|
self,
|
||||||
|
nixpkgs-unpatched,
|
||||||
|
nixpkgs-next-unpatched ? nixpkgs-unpatched,
|
||||||
|
nixpkgs-wayland,
|
||||||
|
mobile-nixos,
|
||||||
|
sops-nix,
|
||||||
|
uninsane-dot-org,
|
||||||
|
...
|
||||||
|
}@inputs:
|
||||||
|
let
|
||||||
|
inherit (builtins) attrNames elem listToAttrs map mapAttrs;
|
||||||
|
# redefine some nixpkgs `lib` functions to avoid the infinite recursion
|
||||||
|
# of if we tried to use patched `nixpkgs.lib` as part of the patching process.
|
||||||
|
mapAttrs' = f: set:
|
||||||
|
listToAttrs (map (attr: f attr set.${attr}) (attrNames set));
|
||||||
|
optionalAttrs = cond: attrs: if cond then attrs else {};
|
||||||
|
# mapAttrs but without the `name` argument
|
||||||
|
mapAttrValues = f: mapAttrs (_: f);
|
||||||
|
|
||||||
|
# rather than apply our nixpkgs patches as a flake input, do that here instead.
|
||||||
|
# this (temporarily?) resolves the bad UX wherein a subflake residing in the same git
|
||||||
|
# repo as the main flake causes the main flake to have an unstable hash.
|
||||||
|
patchNixpkgs = variant: nixpkgs: (import ./nixpatches/flake.nix).outputs {
|
||||||
|
inherit variant nixpkgs;
|
||||||
|
self = patchNixpkgs variant nixpkgs;
|
||||||
|
};
|
||||||
|
|
||||||
|
nixpkgs' = patchNixpkgs "master" nixpkgs-unpatched;
|
||||||
|
nixpkgsCompiledBy = system: nixpkgs'.legacyPackages."${system}";
|
||||||
|
|
||||||
|
evalHost = { name, local, target, variant ? null, nixpkgs ? nixpkgs' }: nixpkgs.lib.nixosSystem {
|
||||||
|
system = target;
|
||||||
|
modules = [
|
||||||
|
{
|
||||||
|
nixpkgs.buildPlatform.system = local;
|
||||||
|
}
|
||||||
|
(optionalAttrs (local != target) {
|
||||||
|
# XXX(2023/12/11): cache.nixos.org uses `system = ...` instead of `hostPlatform.system`, and that choice impacts the closure of every package.
|
||||||
|
# so avoid specifying hostPlatform.system on non-cross builds, so i can use upstream caches.
|
||||||
|
nixpkgs.hostPlatform.system = target;
|
||||||
|
})
|
||||||
|
(optionalAttrs (variant == "light") {
|
||||||
|
sane.maxBuildCost = 2;
|
||||||
|
})
|
||||||
|
(optionalAttrs (variant == "min") {
|
||||||
|
sane.maxBuildCost = 0;
|
||||||
|
})
|
||||||
|
(import ./hosts/instantiate.nix { hostName = name; })
|
||||||
|
self.nixosModules.default
|
||||||
|
self.nixosModules.passthru
|
||||||
|
{
|
||||||
|
nixpkgs.overlays = [
|
||||||
|
self.overlays.passthru
|
||||||
|
self.overlays.sane-all
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
in {
|
||||||
|
nixosConfigurations = let
|
||||||
|
hosts = {
|
||||||
|
servo = { name = "servo"; local = "x86_64-linux"; target = "x86_64-linux"; };
|
||||||
|
desko = { name = "desko"; local = "x86_64-linux"; target = "x86_64-linux"; };
|
||||||
|
desko-light = { name = "desko"; local = "x86_64-linux"; target = "x86_64-linux"; variant = "light"; };
|
||||||
|
lappy = { name = "lappy"; local = "x86_64-linux"; target = "x86_64-linux"; };
|
||||||
|
lappy-light = { name = "lappy"; local = "x86_64-linux"; target = "x86_64-linux"; variant = "light"; };
|
||||||
|
lappy-min = { name = "lappy"; local = "x86_64-linux"; target = "x86_64-linux"; variant = "min"; };
|
||||||
|
moby = { name = "moby"; local = "x86_64-linux"; target = "aarch64-linux"; };
|
||||||
|
moby-light = { name = "moby"; local = "x86_64-linux"; target = "aarch64-linux"; variant = "light"; };
|
||||||
|
moby-min = { name = "moby"; local = "x86_64-linux"; target = "aarch64-linux"; variant = "min"; };
|
||||||
|
rescue = { name = "rescue"; local = "x86_64-linux"; target = "x86_64-linux"; };
|
||||||
|
};
|
||||||
|
hostsNext = mapAttrs' (h: v: {
|
||||||
|
name = "${h}-next";
|
||||||
|
value = v // { nixpkgs = patchNixpkgs "staging-next" nixpkgs-next-unpatched; };
|
||||||
|
}) hosts;
|
||||||
|
in mapAttrValues evalHost (
|
||||||
|
hosts // hostsNext
|
||||||
|
);
|
||||||
|
|
||||||
|
# unofficial output
|
||||||
|
# this produces a EFI-bootable .img file (GPT with a /boot partition and a system (/ or /nix) partition).
|
||||||
|
# after building this:
|
||||||
|
# - flash it to a bootable medium (SD card, flash drive, HDD)
|
||||||
|
# - resize the root partition (use cfdisk)
|
||||||
|
# - mount the part
|
||||||
|
# - chown root:nixbld <part>/nix/store
|
||||||
|
# - chown root:root -R <part>/nix/store/*
|
||||||
|
# - chown root:root -R <part>/persist # if using impermanence
|
||||||
|
# - populate any important things (persist/, home/colin/.ssh, etc)
|
||||||
|
# - boot
|
||||||
|
# - if fs wasn't resized automatically, then `sudo btrfs filesystem resize max /`
|
||||||
|
# - checkout this flake into /etc/nixos AND UPDATE THE FS UUIDS.
|
||||||
|
# - `nixos-rebuild --flake './#<host>' switch`
|
||||||
|
imgs = mapAttrValues (host: host.config.system.build.img) self.nixosConfigurations;
|
||||||
|
|
||||||
|
# unofficial output
|
||||||
|
hostConfigs = mapAttrValues (host: host.config) self.nixosConfigurations;
|
||||||
|
hostSystems = mapAttrValues (host: host.config.system.build.toplevel) self.nixosConfigurations;
|
||||||
|
hostPkgs = mapAttrValues (host: host.config.system.build.pkgs) self.nixosConfigurations;
|
||||||
|
hostPrograms = mapAttrValues (host: mapAttrValues (p: p.package) host.config.sane.programs) self.nixosConfigurations;
|
||||||
|
|
||||||
|
patched.nixpkgs = nixpkgs';
|
||||||
|
|
||||||
|
overlays = {
|
||||||
|
# N.B.: `nix flake check` requires every overlay to take `final: prev:` at defn site,
|
||||||
|
# hence the weird redundancy.
|
||||||
|
default = final: prev: self.overlays.pkgs final prev;
|
||||||
|
sane-all = final: prev: import ./overlays/all.nix final prev;
|
||||||
|
pkgs = final: prev: import ./overlays/pkgs.nix final prev;
|
||||||
|
pins = final: prev: import ./overlays/pins.nix final prev;
|
||||||
|
preferences = final: prev: import ./overlays/preferences.nix final prev;
|
||||||
|
passthru = final: prev:
|
||||||
|
let
|
||||||
|
mobile = (import "${mobile-nixos}/overlay/overlay.nix");
|
||||||
|
uninsane = uninsane-dot-org.overlays.default;
|
||||||
|
wayland = final: prev: {
|
||||||
|
# default is to dump the packages into `waylandPkgs` *and* the toplevel.
|
||||||
|
# but i just want the `waylandPkgs` set
|
||||||
|
inherit (nixpkgs-wayland.overlays.default final prev)
|
||||||
|
waylandPkgs
|
||||||
|
new-wayland-protocols #< 2024/03/10: nixpkgs-wayland assumes this will be in the toplevel
|
||||||
|
;
|
||||||
|
};
|
||||||
|
in
|
||||||
|
(mobile final prev)
|
||||||
|
// (uninsane final prev)
|
||||||
|
// (wayland final prev)
|
||||||
|
;
|
||||||
|
};
|
||||||
|
|
||||||
|
nixosModules = rec {
|
||||||
|
default = sane;
|
||||||
|
sane = import ./modules;
|
||||||
|
passthru = { ... }: {
|
||||||
|
imports = [
|
||||||
|
sops-nix.nixosModules.sops
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# this includes both our native packages and all the nixpkgs packages.
|
||||||
|
legacyPackages =
|
||||||
|
let
|
||||||
|
allPkgsFor = sys: (nixpkgsCompiledBy sys).appendOverlays [
|
||||||
|
self.overlays.passthru self.overlays.pkgs
|
||||||
|
];
|
||||||
|
in {
|
||||||
|
x86_64-linux = allPkgsFor "x86_64-linux";
|
||||||
|
aarch64-linux = allPkgsFor "aarch64-linux";
|
||||||
|
};
|
||||||
|
|
||||||
|
# extract only our own packages from the full set.
|
||||||
|
# because of `nix flake check`, we flatten the package set and only surface x86_64-linux packages.
|
||||||
|
packages = mapAttrs
|
||||||
|
(system: passthruPkgs: passthruPkgs.lib.filterAttrs
|
||||||
|
(name: pkg:
|
||||||
|
# keep only packages which will pass `nix flake check`, i.e. keep only:
|
||||||
|
# - derivations (not package sets)
|
||||||
|
# - packages that build for the given platform
|
||||||
|
(! elem name [ "feeds" "pythonPackagesExtensions" ])
|
||||||
|
&& (passthruPkgs.lib.meta.availableOn passthruPkgs.stdenv.hostPlatform pkg)
|
||||||
|
)
|
||||||
|
(
|
||||||
|
# expose sane packages and chosen inputs (uninsane.org)
|
||||||
|
(import ./pkgs { pkgs = passthruPkgs; }) // {
|
||||||
|
inherit (passthruPkgs) uninsane-dot-org;
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
# self.legacyPackages;
|
||||||
|
{
|
||||||
|
x86_64-linux = (nixpkgsCompiledBy "x86_64-linux").appendOverlays [
|
||||||
|
self.overlays.passthru
|
||||||
|
];
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
apps."x86_64-linux" =
|
||||||
|
let
|
||||||
|
pkgs = self.legacyPackages."x86_64-linux";
|
||||||
|
sanePkgs = import ./pkgs { inherit pkgs; };
|
||||||
|
deployScript = host: addr: action: pkgs.writeShellScript "deploy-${host}" ''
|
||||||
|
set -e
|
||||||
|
|
||||||
|
host="${host}"
|
||||||
|
addr="${addr}"
|
||||||
|
action="${if action != null then action else ""}"
|
||||||
|
runOnTarget() {
|
||||||
|
# run the command ($@) on the machine we're deploying to.
|
||||||
|
# if that's a remote machine, then do it via ssh, else local shell.
|
||||||
|
if [ -n "$addr" ]; then
|
||||||
|
ssh "$addr" "$@"
|
||||||
|
else
|
||||||
|
"$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
nix build ".#nixosConfigurations.$host.config.system.build.toplevel" --out-link "./build/result-$host" "$@"
|
||||||
|
storePath="$(readlink ./build/result-$host)"
|
||||||
|
|
||||||
|
# mimic `nixos-rebuild --target-host`, in effect:
|
||||||
|
# - nix-copy-closure ...
|
||||||
|
# - nix-env --set ...
|
||||||
|
# - switch-to-configuration <boot|dry-activate|switch|test|>
|
||||||
|
# avoid the actual `nixos-rebuild` for a few reasons:
|
||||||
|
# - fewer nix evals
|
||||||
|
# - more introspectability and debuggability
|
||||||
|
# - sandbox friendliness (especially: `git` doesn't have to be run as root)
|
||||||
|
|
||||||
|
if [ -n "$addr" ]; then
|
||||||
|
sudo nix store sign -r -k /run/secrets/nix_signing_key "$storePath"
|
||||||
|
# add more `-v` for more verbosity (up to 5).
|
||||||
|
# builders-use-substitutes false: optimizes so that the remote machine doesn't try to get paths from its substituters.
|
||||||
|
# we already have all paths here, and the remote substitution is slow to check and SERIOUSLY flaky on moby in particular.
|
||||||
|
nix copy -vv --option builders-use-substitutes false --to "ssh-ng://$addr" "$storePath"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$action" ]; then
|
||||||
|
runOnTarget sudo nix-env -p /nix/var/nix/profiles/system --set "$storePath"
|
||||||
|
runOnTarget sudo "$storePath/bin/switch-to-configuration" "$action"
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
deployApp = host: addr: action: {
|
||||||
|
type = "app";
|
||||||
|
program = ''${deployScript host addr action}'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# pkg updating.
|
||||||
|
# a cleaner alternative lives here: <https://discourse.nixos.org/t/how-can-i-run-the-updatescript-of-personal-packages/25274/2>
|
||||||
|
# mkUpdater :: [ String ] -> { type = "app"; program = path; }
|
||||||
|
mkUpdater = attrPath: {
|
||||||
|
type = "app";
|
||||||
|
program = let
|
||||||
|
pkg = pkgs.lib.getAttrFromPath attrPath sanePkgs;
|
||||||
|
strAttrPath = pkgs.lib.concatStringsSep "." attrPath;
|
||||||
|
commandArgv = pkg.updateScript.command or pkg.updateScript;
|
||||||
|
command = pkgs.lib.escapeShellArgs commandArgv;
|
||||||
|
in builtins.toString (pkgs.writeShellScript "update-${strAttrPath}" ''
|
||||||
|
set -x
|
||||||
|
env UPDATE_NIX_NAME=${pkg.name} UPDATE_NIX_PNAME=${pkg.pname} UPDATE_NIX_OLD_VERSION=${pkg.version} UPDATE_NIX_ATTR_PATH=${strAttrPath} ${command}
|
||||||
|
'');
|
||||||
|
};
|
||||||
|
mkUpdatersNoAliases = opts: basePath: pkgs.lib.concatMapAttrs
|
||||||
|
(name: pkg:
|
||||||
|
if pkg.recurseForDerivations or false then {
|
||||||
|
"${name}" = mkUpdaters opts (basePath ++ [ name ]);
|
||||||
|
} else if pkg.updateScript or null != null then {
|
||||||
|
"${name}" = mkUpdater (basePath ++ [ name ]);
|
||||||
|
} else {}
|
||||||
|
)
|
||||||
|
(pkgs.lib.getAttrFromPath basePath sanePkgs);
|
||||||
|
mkUpdaters = { ignore ? [], flakePrefix ? [] }@opts: basePath:
|
||||||
|
let
|
||||||
|
updaters = mkUpdatersNoAliases opts basePath;
|
||||||
|
invokeUpdater = name: pkg:
|
||||||
|
let
|
||||||
|
fullPath = basePath ++ [ name ];
|
||||||
|
doUpdateByDefault = !builtins.elem fullPath ignore;
|
||||||
|
|
||||||
|
# in case `name` has a `.` in it, we have to quote it
|
||||||
|
escapedPath = builtins.map (p: ''"${p}"'') fullPath;
|
||||||
|
updatePath = builtins.concatStringsSep "." (flakePrefix ++ escapedPath);
|
||||||
|
in pkgs.lib.optionalString doUpdateByDefault (
|
||||||
|
pkgs.lib.escapeShellArgs [
|
||||||
|
"nix" "run" ".#${updatePath}"
|
||||||
|
]
|
||||||
|
);
|
||||||
|
in {
|
||||||
|
type = "app";
|
||||||
|
# top-level app just invokes the updater of everything one layer below it
|
||||||
|
program = builtins.toString (pkgs.writeShellScript
|
||||||
|
(builtins.concatStringsSep "-" (flakePrefix ++ basePath))
|
||||||
|
(builtins.concatStringsSep
|
||||||
|
"\n"
|
||||||
|
(pkgs.lib.mapAttrsToList invokeUpdater updaters)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} // updaters;
|
||||||
|
in {
|
||||||
|
help = {
|
||||||
|
type = "app";
|
||||||
|
program = let
|
||||||
|
helpMsg = builtins.toFile "nixos-config-help-message" ''
|
||||||
|
commands:
|
||||||
|
- `nix run '.#help'`
|
||||||
|
- show this message
|
||||||
|
- `nix run '.#update.pkgs'`
|
||||||
|
- updates every package
|
||||||
|
- `nix run '.#update.feeds'`
|
||||||
|
- updates metadata for all feeds
|
||||||
|
- `nix run '.#init-feed' <url>`
|
||||||
|
- `nix run '.#deploy.{desko,lappy,moby,servo}[-light|-test]' [nix args ...]`
|
||||||
|
- build and deploy the host
|
||||||
|
- `nix run '.#preDeploy.{desko,lappy,moby,servo}[-light]' [nix args ...]`
|
||||||
|
- copy closures to a host, but don't activate it
|
||||||
|
- or `nix run '.#preDeploy'` to target all hosts
|
||||||
|
- `nix run '.#check'`
|
||||||
|
- make sure all systems build; NUR evaluates
|
||||||
|
- `nix run '.#bench'`
|
||||||
|
- benchmark the eval time of common targets this flake provides
|
||||||
|
|
||||||
|
specific build targets of interest:
|
||||||
|
- `nix build '.#imgs.rescue'`
|
||||||
|
'';
|
||||||
|
in builtins.toString (pkgs.writeShellScript "nixos-config-help" ''
|
||||||
|
cat ${helpMsg}
|
||||||
|
echo ""
|
||||||
|
echo "complete flake structure:"
|
||||||
|
nix flake show --option allow-import-from-derivation true
|
||||||
|
'');
|
||||||
|
};
|
||||||
|
# wrangle some names to get package updaters which refer back into the flake, but also conditionally ignore certain paths (e.g. sane.feeds).
|
||||||
|
# TODO: better design
|
||||||
|
update = rec {
|
||||||
|
_impl.pkgs.sane = mkUpdaters { flakePrefix = [ "update" "_impl" "pkgs" ]; ignore = [ [ "sane" "feeds" ] ]; } [ "sane" ];
|
||||||
|
pkgs = _impl.pkgs.sane;
|
||||||
|
_impl.feeds.sane.feeds = mkUpdaters { flakePrefix = [ "update" "_impl" "feeds" ]; } [ "sane" "feeds" ];
|
||||||
|
feeds = _impl.feeds.sane.feeds;
|
||||||
|
};
|
||||||
|
|
||||||
|
init-feed = {
|
||||||
|
type = "app";
|
||||||
|
program = "${pkgs.feeds.init-feed}";
|
||||||
|
};
|
||||||
|
|
||||||
|
deploy = {
|
||||||
|
desko = deployApp "desko" "desko" "switch";
|
||||||
|
desko-light = deployApp "desko-light" "desko" "switch";
|
||||||
|
lappy = deployApp "lappy" "lappy" "switch";
|
||||||
|
lappy-light = deployApp "lappy-light" "lappy" "switch";
|
||||||
|
lappy-min = deployApp "lappy-min" "lappy" "switch";
|
||||||
|
moby = deployApp "moby" "moby" "switch";
|
||||||
|
moby-light = deployApp "moby-light" "moby" "switch";
|
||||||
|
moby-min = deployApp "moby-min" "moby" "switch";
|
||||||
|
moby-test = deployApp "moby" "moby" "test";
|
||||||
|
servo = deployApp "servo" "servo" "switch";
|
||||||
|
|
||||||
|
# like `nixos-rebuild --flake . switch`
|
||||||
|
self = deployApp "$(hostname)" "" "switch";
|
||||||
|
self-light = deployApp "$(hostname)-light" "" "switch";
|
||||||
|
self-min = deployApp "$(hostname)-min" "" "switch";
|
||||||
|
|
||||||
|
type = "app";
|
||||||
|
program = builtins.toString (pkgs.writeShellScript "deploy-all" ''
|
||||||
|
nix run '.#deploy.lappy'
|
||||||
|
nix run '.#deploy.moby'
|
||||||
|
nix run '.#deploy.desko'
|
||||||
|
nix run '.#deploy.servo'
|
||||||
|
'');
|
||||||
|
};
|
||||||
|
preDeploy = {
|
||||||
|
# build the host and copy the runtime closure to that host, but don't activate it.
|
||||||
|
desko = deployApp "desko" "desko" null;
|
||||||
|
desko-light = deployApp "desko-light" "desko" null;
|
||||||
|
lappy = deployApp "lappy" "lappy" null;
|
||||||
|
lappy-light = deployApp "lappy-light" "lappy" null;
|
||||||
|
lappy-min = deployApp "lappy-min" "lappy" null;
|
||||||
|
moby = deployApp "moby" "moby" null;
|
||||||
|
moby-light = deployApp "moby-light" "moby" null;
|
||||||
|
moby-min = deployApp "moby-min" "moby" null;
|
||||||
|
servo = deployApp "servo" "servo" null;
|
||||||
|
type = "app";
|
||||||
|
program = builtins.toString (pkgs.writeShellScript "predeploy-all" ''
|
||||||
|
# copy the -min/-light variants first; this might be run while waiting on a full build. or the full build failed.
|
||||||
|
nix run '.#preDeploy.moby-min' -- "$@"
|
||||||
|
nix run '.#preDeploy.lappy-min' -- "$@"
|
||||||
|
nix run '.#preDeploy.moby-light' -- "$@"
|
||||||
|
nix run '.#preDeploy.lappy-light' -- "$@"
|
||||||
|
nix run '.#preDeploy.desko-light' -- "$@"
|
||||||
|
nix run '.#preDeploy.lappy' -- "$@"
|
||||||
|
nix run '.#preDeploy.servo' -- "$@"
|
||||||
|
nix run '.#preDeploy.moby' -- "$@"
|
||||||
|
nix run '.#preDeploy.desko' -- "$@"
|
||||||
|
'');
|
||||||
|
};
|
||||||
|
|
||||||
|
sync = {
|
||||||
|
type = "app";
|
||||||
|
program = builtins.toString (pkgs.writeShellScript "sync-all" ''
|
||||||
|
RC_lappy=$(nix run '.#sync.lappy' -- "$@")
|
||||||
|
RC_moby=$(nix run '.#sync.moby' -- "$@")
|
||||||
|
RC_desko=$(nix run '.#sync.desko' -- "$@")
|
||||||
|
|
||||||
|
echo "lappy: $RC_lappy"
|
||||||
|
echo "moby: $RC_moby"
|
||||||
|
echo "desko: $RC_desko"
|
||||||
|
'');
|
||||||
|
};
|
||||||
|
|
||||||
|
sync.desko = {
|
||||||
|
# copy music from servo to desko
|
||||||
|
# can run this from any device that has ssh access to desko and servo
|
||||||
|
type = "app";
|
||||||
|
program = builtins.toString (pkgs.writeShellScript "sync-to-desko" ''
|
||||||
|
sudo mount /mnt/desko/home
|
||||||
|
${pkgs.sane-scripts.sync-music}/bin/sane-sync-music --compat /mnt/servo/media/Music /mnt/desko/home/Music "$@"
|
||||||
|
'');
|
||||||
|
};
|
||||||
|
|
||||||
|
sync.lappy = {
|
||||||
|
# copy music from servo to lappy
|
||||||
|
# can run this from any device that has ssh access to lappy and servo
|
||||||
|
type = "app";
|
||||||
|
program = builtins.toString (pkgs.writeShellScript "sync-to-lappy" ''
|
||||||
|
sudo mount /mnt/lappy/home
|
||||||
|
${pkgs.sane-scripts.sync-music}/bin/sane-sync-music --compress --compat /mnt/servo/media/Music /mnt/lappy/home/Music "$@"
|
||||||
|
'');
|
||||||
|
};
|
||||||
|
|
||||||
|
sync.moby = {
|
||||||
|
# copy music from servo to moby
|
||||||
|
# can run this from any device that has ssh access to moby and servo
|
||||||
|
type = "app";
|
||||||
|
program = builtins.toString (pkgs.writeShellScript "sync-to-moby" ''
|
||||||
|
sudo mount /mnt/moby/home
|
||||||
|
sudo mount /mnt/desko/home
|
||||||
|
${pkgs.rsync}/bin/rsync -arv --exclude servo-macros /mnt/moby/home/Pictures/ /mnt/desko/home/Pictures/moby/
|
||||||
|
# N.B.: limited by network/disk -> reduce job count to improve pause/resume behavior
|
||||||
|
${pkgs.sane-scripts.sync-music}/bin/sane-sync-music --compress --compat --jobs 4 /mnt/servo/media/Music /mnt/moby/home/Music "$@"
|
||||||
|
'');
|
||||||
|
};
|
||||||
|
|
||||||
|
check = {
|
||||||
|
type = "app";
|
||||||
|
program = builtins.toString (pkgs.writeShellScript "check-all" ''
|
||||||
|
nix run '.#check.nur'
|
||||||
|
RC0=$?
|
||||||
|
nix run '.#check.hostConfigs'
|
||||||
|
RC1=$?
|
||||||
|
nix run '.#check.rescue'
|
||||||
|
RC2=$?
|
||||||
|
echo "nur: $RC0"
|
||||||
|
echo "hostConfigs: $RC1"
|
||||||
|
echo "rescue: $RC2"
|
||||||
|
exit $(($RC0 | $RC1 | $RC2))
|
||||||
|
'');
|
||||||
|
};
|
||||||
|
|
||||||
|
check.nur = {
|
||||||
|
# `nix run '.#check-nur'`
|
||||||
|
# validates that my repo can be included in the Nix User Repository
|
||||||
|
type = "app";
|
||||||
|
program = builtins.toString (pkgs.writeShellScript "check-nur" ''
|
||||||
|
cd ${./.}/integrations/nur
|
||||||
|
NIX_PATH= NIXPKGS_ALLOW_UNSUPPORTED_SYSTEM=1 nix-env -f . -qa \* --meta --xml \
|
||||||
|
--allowed-uris https://static.rust-lang.org \
|
||||||
|
--option restrict-eval true \
|
||||||
|
--option allow-import-from-derivation true \
|
||||||
|
--drv-path --show-trace \
|
||||||
|
-I nixpkgs=${nixpkgs-unpatched} \
|
||||||
|
-I nixpkgs-overlays=${./.}/hosts/common/nix/overlay \
|
||||||
|
-I ../../ \
|
||||||
|
| tee # tee to prevent interactive mode
|
||||||
|
'');
|
||||||
|
};
|
||||||
|
|
||||||
|
check.hostConfigs = {
|
||||||
|
type = "app";
|
||||||
|
program = let
|
||||||
|
checkHost = host: let
|
||||||
|
shellHost = pkgs.lib.replaceStrings [ "-" ] [ "_" ] host;
|
||||||
|
in ''
|
||||||
|
nix build -v '.#nixosConfigurations.${host}.config.system.build.toplevel' --out-link ./build/result-${host} -j2 "$@"
|
||||||
|
RC_${shellHost}=$?
|
||||||
|
'';
|
||||||
|
in builtins.toString (pkgs.writeShellScript
|
||||||
|
"check-host-configs"
|
||||||
|
''
|
||||||
|
# build minimally-usable hosts first, then their full image.
|
||||||
|
# this gives me a minimal image i can deploy or copy over, early.
|
||||||
|
${checkHost "lappy-min"}
|
||||||
|
${checkHost "moby-min"}
|
||||||
|
|
||||||
|
${checkHost "desko-light"}
|
||||||
|
${checkHost "moby-light"}
|
||||||
|
${checkHost "lappy-light"}
|
||||||
|
|
||||||
|
${checkHost "desko"}
|
||||||
|
${checkHost "lappy"}
|
||||||
|
${checkHost "servo"}
|
||||||
|
${checkHost "moby"}
|
||||||
|
${checkHost "rescue"}
|
||||||
|
|
||||||
|
# still want to build the -light variants first so as to avoid multiple simultaneous webkitgtk builds
|
||||||
|
${checkHost "desko-light-next"}
|
||||||
|
${checkHost "moby-light-next"}
|
||||||
|
|
||||||
|
${checkHost "desko-next"}
|
||||||
|
${checkHost "lappy-next"}
|
||||||
|
${checkHost "servo-next"}
|
||||||
|
${checkHost "moby-next"}
|
||||||
|
${checkHost "rescue-next"}
|
||||||
|
|
||||||
|
echo "desko: $RC_desko"
|
||||||
|
echo "lappy: $RC_lappy"
|
||||||
|
echo "servo: $RC_servo"
|
||||||
|
echo "moby: $RC_moby"
|
||||||
|
echo "rescue: $RC_rescue"
|
||||||
|
|
||||||
|
echo "desko-next: $RC_desko_next"
|
||||||
|
echo "lappy-next: $RC_lappy_next"
|
||||||
|
echo "servo-next: $RC_servo_next"
|
||||||
|
echo "moby-next: $RC_moby_next"
|
||||||
|
echo "rescue-next: $RC_rescue_next"
|
||||||
|
|
||||||
|
# i don't really care if the -next hosts fail. i build them mostly to keep the cache fresh/ready
|
||||||
|
exit $(($RC_desko | $RC_lappy | $RC_servo | $RC_moby | $RC_rescue))
|
||||||
|
''
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
check.rescue = {
|
||||||
|
type = "app";
|
||||||
|
program = builtins.toString (pkgs.writeShellScript "check-rescue" ''
|
||||||
|
nix build -v '.#imgs.rescue' --out-link ./build/result-rescue-img -j2
|
||||||
|
'');
|
||||||
|
};
|
||||||
|
|
||||||
|
bench = {
|
||||||
|
type = "app";
|
||||||
|
program = builtins.toString (pkgs.writeShellScript "bench" ''
|
||||||
|
doBench() {
|
||||||
|
attrPath="$1"
|
||||||
|
shift
|
||||||
|
echo -n "benchmarking eval of '$attrPath'... "
|
||||||
|
/run/current-system/sw/bin/time -f "%e sec" -o /dev/stdout \
|
||||||
|
nix eval --no-eval-cache --quiet --raw ".#$attrPath" --apply 'result: if result != null then "" else "unexpected null"' $@ 2> /dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ -n "$1" ]; then
|
||||||
|
doBench "$@"
|
||||||
|
else
|
||||||
|
doBench hostConfigs
|
||||||
|
doBench hostConfigs.lappy
|
||||||
|
doBench hostConfigs.lappy.sane.programs
|
||||||
|
doBench hostConfigs.lappy.sane.users.colin
|
||||||
|
doBench hostConfigs.lappy.sane.fs
|
||||||
|
doBench hostConfigs.lappy.environment.systemPackages
|
||||||
|
fi
|
||||||
|
'');
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
templates = {
|
||||||
|
env.python-data = {
|
||||||
|
# initialize with:
|
||||||
|
# - `nix flake init -t '/home/colin/dev/nixos/#env.python-data'`
|
||||||
|
# then enter with:
|
||||||
|
# - `nix develop`
|
||||||
|
path = ./templates/env/python-data;
|
||||||
|
description = "python environment for data processing";
|
||||||
|
};
|
||||||
|
pkgs.rust-inline = {
|
||||||
|
# initialize with:
|
||||||
|
# - `nix flake init -t '/home/colin/dev/nixos/#pkgs.rust-inline'`
|
||||||
|
path = ./templates/pkgs/rust-inline;
|
||||||
|
description = "rust package and development environment (inline rust sources)";
|
||||||
|
};
|
||||||
|
pkgs.rust = {
|
||||||
|
# initialize with:
|
||||||
|
# - `nix flake init -t '/home/colin/dev/nixos/#pkgs.rust'`
|
||||||
|
path = ./templates/pkgs/rust;
|
||||||
|
description = "rust package fit to ship in nixpkgs";
|
||||||
|
};
|
||||||
|
pkgs.make = {
|
||||||
|
# initialize with:
|
||||||
|
# - `nix flake init -t '/home/colin/dev/nixos/#pkgs.make'`
|
||||||
|
path = ./templates/pkgs/make;
|
||||||
|
description = "default Makefile-based derivation";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@@ -1,45 +0,0 @@
|
|||||||
# Samsung chromebook XE303C12
|
|
||||||
# - <https://wiki.postmarketos.org/wiki/Samsung_Chromebook_(google-snow)>
|
|
||||||
{ ... }:
|
|
||||||
{
|
|
||||||
imports = [
|
|
||||||
./fs.nix
|
|
||||||
];
|
|
||||||
|
|
||||||
sane.hal.samsung.enable = true;
|
|
||||||
sane.roles.client = true;
|
|
||||||
# sane.roles.pc = true;
|
|
||||||
|
|
||||||
users.users.colin.initialPassword = "147147";
|
|
||||||
sane.programs.sway.enableFor.user.colin = true;
|
|
||||||
|
|
||||||
sane.programs.calls.enableFor.user.colin = false;
|
|
||||||
sane.programs.consoleMediaUtils.enableFor.user.colin = true;
|
|
||||||
sane.programs.epiphany.enableFor.user.colin = true;
|
|
||||||
sane.programs.geary.enableFor.user.colin = false;
|
|
||||||
# sane.programs.firefox.enableFor.user.colin = true;
|
|
||||||
sane.programs.portfolio-filemanager.enableFor.user.colin = true;
|
|
||||||
sane.programs.signal-desktop.enableFor.user.colin = false;
|
|
||||||
sane.programs.wike.enableFor.user.colin = true;
|
|
||||||
|
|
||||||
sane.programs.dino.config.autostart = false;
|
|
||||||
sane.programs.dissent.config.autostart = false;
|
|
||||||
sane.programs.fractal.config.autostart = false;
|
|
||||||
sane.programs.sway.config.mod = "Mod1"; #< alt key instead of Super
|
|
||||||
|
|
||||||
# sane.programs.guiApps.enableFor.user.colin = false;
|
|
||||||
|
|
||||||
# sane.programs.pcGuiApps.enableFor.user.colin = false; #< errors!
|
|
||||||
|
|
||||||
sane.programs.blueberry.enableFor.user.colin = false; # bluetooth manager: doesn't cross compile!
|
|
||||||
# sane.programs.brave.enableFor.user.colin = false; # 2024/06/03: fails eval if enabled on cross
|
|
||||||
# sane.programs.firefox.enableFor.user.colin = false; # 2024/06/03: this triggers an eval error in yarn stuff -- i'm doing IFD somewhere!!?
|
|
||||||
sane.programs.mepo.enableFor.user.colin = false; # 2024/06/04: doesn't cross compile (nodejs)
|
|
||||||
sane.programs.mercurial.enableFor.user.colin = false; # 2024/06/03: does not cross compile
|
|
||||||
sane.programs.nixpkgs-review.enableFor.user.colin = false; # 2024/06/03: OOMs when cross compiling
|
|
||||||
sane.programs.ntfy-sh.enableFor.user.colin = false; # 2024/06/04: doesn't cross compile (nodejs)
|
|
||||||
sane.programs.pwvucontrol.enableFor.user.colin = false; # 2024/06/03: doesn't cross compile (libspa-sys)
|
|
||||||
sane.programs."sane-scripts.bt-search".enableFor.user.colin = false; # 2024/06/03: does not cross compile
|
|
||||||
sane.programs.sequoia.enableFor.user.colin = false; # 2024/06/03: does not cross compile
|
|
||||||
sane.programs.zathura.enableFor.user.colin = false; # 2024/06/03: does not cross compile
|
|
||||||
}
|
|
@@ -1,16 +0,0 @@
|
|||||||
{ ... }:
|
|
||||||
{
|
|
||||||
fileSystems."/nix" = {
|
|
||||||
device = "/dev/disk/by-uuid/55555555-0303-0c12-86df-eda9e9311526";
|
|
||||||
fsType = "btrfs";
|
|
||||||
options = [
|
|
||||||
"compress=zstd"
|
|
||||||
"defaults"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
fileSystems."/boot" = {
|
|
||||||
device = "/dev/disk/by-uuid/303C-5A37";
|
|
||||||
fsType = "vfat";
|
|
||||||
};
|
|
||||||
}
|
|
@@ -32,14 +32,10 @@
|
|||||||
sane.programs.iphoneUtils.enableFor.user.colin = true;
|
sane.programs.iphoneUtils.enableFor.user.colin = true;
|
||||||
sane.programs.steam.enableFor.user.colin = true;
|
sane.programs.steam.enableFor.user.colin = true;
|
||||||
|
|
||||||
sane.programs.geary.config.autostart = true;
|
sane.programs."gnome.geary".config.autostart = true;
|
||||||
sane.programs.signal-desktop.config.autostart = true;
|
sane.programs.signal-desktop.config.autostart = true;
|
||||||
|
|
||||||
sane.programs.nwg-panel.config = {
|
boot.loader.efi.canTouchEfiVariables = false;
|
||||||
battery = false;
|
|
||||||
brightness = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
sane.image.extraBootFiles = [ pkgs.bootpart-uefi-x86_64 ];
|
sane.image.extraBootFiles = [ pkgs.bootpart-uefi-x86_64 ];
|
||||||
|
|
||||||
# needed to use libimobiledevice/ifuse, for iphone sync
|
# needed to use libimobiledevice/ifuse, for iphone sync
|
||||||
@@ -56,4 +52,7 @@
|
|||||||
# TODO: ALLOW_USERS doesn't seem to work. still need `sudo snapper -c nix list`
|
# TODO: ALLOW_USERS doesn't seem to work. still need `sudo snapper -c nix list`
|
||||||
ALLOW_USERS = [ "colin" ];
|
ALLOW_USERS = [ "colin" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# docs: https://nixos.org/manual/nixos/stable/options.html#opt-system.stateVersion
|
||||||
|
system.stateVersion = "21.05";
|
||||||
}
|
}
|
||||||
|
@@ -13,12 +13,13 @@
|
|||||||
# sane.ovpn.addrV6 = "fd00:0000:1337:cafe:1111:1111:0332:aa96/128";
|
# sane.ovpn.addrV6 = "fd00:0000:1337:cafe:1111:1111:0332:aa96/128";
|
||||||
|
|
||||||
# sane.guest.enable = true;
|
# sane.guest.enable = true;
|
||||||
|
boot.loader.efi.canTouchEfiVariables = false;
|
||||||
sane.image.extraBootFiles = [ pkgs.bootpart-uefi-x86_64 ];
|
sane.image.extraBootFiles = [ pkgs.bootpart-uefi-x86_64 ];
|
||||||
|
|
||||||
sane.programs.stepmania.enableFor.user.colin = true;
|
sane.programs.stepmania.enableFor.user.colin = true;
|
||||||
sane.programs.sway.enableFor.user.colin = true;
|
sane.programs.sway.enableFor.user.colin = true;
|
||||||
|
|
||||||
sane.programs.geary.config.autostart = true;
|
sane.programs."gnome.geary".config.autostart = true;
|
||||||
sane.programs.signal-desktop.config.autostart = true;
|
sane.programs.signal-desktop.config.autostart = true;
|
||||||
|
|
||||||
sops.secrets.colin-passwd.neededForUsers = true;
|
sops.secrets.colin-passwd.neededForUsers = true;
|
||||||
@@ -33,4 +34,7 @@
|
|||||||
SUBVOLUME = "/nix";
|
SUBVOLUME = "/nix";
|
||||||
ALLOW_USERS = [ "colin" ];
|
ALLOW_USERS = [ "colin" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# docs: https://nixos.org/manual/nixos/stable/options.html#opt-system.stateVersion
|
||||||
|
system.stateVersion = "21.05";
|
||||||
}
|
}
|
||||||
|
7
hosts/by-name/lappy/xkb_mobile_normal_buttons
Normal file
7
hosts/by-name/lappy/xkb_mobile_normal_buttons
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
xkb_keymap {
|
||||||
|
xkb_keycodes { include "evdev+aliases(qwerty)" };
|
||||||
|
xkb_types { include "complete" };
|
||||||
|
xkb_compat { include "complete" };
|
||||||
|
xkb_symbols { include "pc+us+inet(evdev)" };
|
||||||
|
xkb_geometry { include "pc(pc105)" };
|
||||||
|
};
|
22
hosts/by-name/moby/bootloader.nix
Normal file
22
hosts/by-name/moby/bootloader.nix
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# tow-boot: <https://tow-boot.org>
|
||||||
|
# docs (pinephone specific): <https://github.com/Tow-Boot/Tow-Boot/tree/development/boards/pine64-pinephoneA64>
|
||||||
|
# LED and button behavior is defined here: <https://github.com/Tow-Boot/Tow-Boot/blob/development/modules/tow-boot/phone-ux.nix>
|
||||||
|
# - hold VOLDOWN: enter recovery mode
|
||||||
|
# - LED will turn aqua instead of yellow
|
||||||
|
# - recovery mode would ordinarily allow a selection of entries, but for pinephone i guess it doesn't do anything?
|
||||||
|
# - hold VOLUP: force it to load the OS from eMMC?
|
||||||
|
# - LED will turn blue instead of yellow
|
||||||
|
# boot LEDs:
|
||||||
|
# - yellow = entered tow-boot
|
||||||
|
# - 10 red flashes => poweroff means tow-boot couldn't boot into the next stage (i.e. distroboot)
|
||||||
|
# - distroboot: <https://source.denx.de/u-boot/u-boot/-/blob/v2022.04/doc/develop/distro.rst>)
|
||||||
|
{ config, pkgs, ... }:
|
||||||
|
{
|
||||||
|
# we need space in the GPT header to place tow-boot.
|
||||||
|
# only actually need 1 MB, but better to over-allocate than under-allocate
|
||||||
|
sane.image.extraGPTPadding = 16 * 1024 * 1024;
|
||||||
|
sane.image.firstPartGap = 0;
|
||||||
|
sane.image.installBootloader = ''
|
||||||
|
dd if=${pkgs.tow-boot-pinephone}/Tow-Boot.noenv.bin of=$out/nixos.img bs=1024 seek=8 conv=notrunc
|
||||||
|
'';
|
||||||
|
}
|
@@ -9,12 +9,16 @@
|
|||||||
{ config, pkgs, lib, ... }:
|
{ config, pkgs, lib, ... }:
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
|
./bootloader.nix
|
||||||
./fs.nix
|
./fs.nix
|
||||||
|
./gps.nix
|
||||||
|
./kernel.nix
|
||||||
|
./polyfill.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
sane.hal.pine64.enable = true;
|
|
||||||
sane.roles.client = true;
|
sane.roles.client = true;
|
||||||
sane.roles.handheld = true;
|
sane.roles.handheld = true;
|
||||||
|
sane.programs.zsh.config.showDeadlines = false; # unlikely to act on them when in shell
|
||||||
sane.services.wg-home.enable = true;
|
sane.services.wg-home.enable = true;
|
||||||
sane.services.wg-home.ip = config.sane.hosts.by-name."moby".wg-home.ip;
|
sane.services.wg-home.ip = config.sane.hosts.by-name."moby".wg-home.ip;
|
||||||
sane.ovpn.addrV4 = "172.24.87.255";
|
sane.ovpn.addrV4 = "172.24.87.255";
|
||||||
@@ -28,7 +32,11 @@
|
|||||||
sops.secrets.colin-passwd.neededForUsers = true;
|
sops.secrets.colin-passwd.neededForUsers = true;
|
||||||
|
|
||||||
sane.programs.sway.enableFor.user.colin = true;
|
sane.programs.sway.enableFor.user.colin = true;
|
||||||
sane.programs.sway.config.mod = "Mod1"; #< alt key instead of Super
|
sane.programs.swaylock.enableFor.user.colin = false; #< not usable on touch
|
||||||
|
sane.programs.schlock.enableFor.user.colin = true;
|
||||||
|
sane.programs.swayidle.config.actions.screenoff.delay = 300;
|
||||||
|
sane.programs.swayidle.config.actions.screenoff.enable = true;
|
||||||
|
sane.programs.sane-input-handler.enableFor.user.colin = true;
|
||||||
sane.programs.blueberry.enableFor.user.colin = false; # bluetooth manager: doesn't cross compile!
|
sane.programs.blueberry.enableFor.user.colin = false; # bluetooth manager: doesn't cross compile!
|
||||||
sane.programs.fcitx5.enableFor.user.colin = false; # does not cross compile
|
sane.programs.fcitx5.enableFor.user.colin = false; # does not cross compile
|
||||||
sane.programs.mercurial.enableFor.user.colin = false; # does not cross compile
|
sane.programs.mercurial.enableFor.user.colin = false; # does not cross compile
|
||||||
@@ -36,14 +44,18 @@
|
|||||||
|
|
||||||
# enabled for easier debugging
|
# enabled for easier debugging
|
||||||
sane.programs.eg25-control.enableFor.user.colin = true;
|
sane.programs.eg25-control.enableFor.user.colin = true;
|
||||||
# sane.programs.rtl8723cs-wowlan.enableFor.user.colin = true;
|
sane.programs.rtl8723cs-wowlan.enableFor.user.colin = true;
|
||||||
|
|
||||||
# sane.programs.ntfy-sh.config.autostart = true;
|
# sane.programs.ntfy-sh.config.autostart = true;
|
||||||
sane.programs.dino.config.autostart = true;
|
sane.programs.dino.config.autostart = true;
|
||||||
sane.programs.signal-desktop.config.autostart = true;
|
# sane.programs.signal-desktop.config.autostart = true; # TODO: enable once electron stops derping.
|
||||||
# sane.programs.geary.config.autostart = true;
|
# sane.programs."gnome.geary".config.autostart = true;
|
||||||
# sane.programs.calls.config.autostart = true;
|
# sane.programs.calls.config.autostart = true;
|
||||||
|
|
||||||
|
sane.programs.firefox.mime.priority = 300; # prefer other browsers when possible
|
||||||
|
# HACK/TODO: make `programs.P.env.VAR` behave according to `mime.priority`
|
||||||
|
sane.programs.firefox.env = lib.mkForce {};
|
||||||
|
sane.programs.epiphany.env.BROWSER = "epiphany";
|
||||||
sane.programs.pipewire.config = {
|
sane.programs.pipewire.config = {
|
||||||
# tune so Dino doesn't drop audio
|
# tune so Dino doesn't drop audio
|
||||||
# there's seemingly two buffers for the mic (see: <https://gitlab.freedesktop.org/pipewire/pipewire/-/wikis/FAQ#pipewire-buffering-explained>)
|
# there's seemingly two buffers for the mic (see: <https://gitlab.freedesktop.org/pipewire/pipewire/-/wikis/FAQ#pipewire-buffering-explained>)
|
||||||
@@ -60,7 +72,53 @@
|
|||||||
max-quantum = 8192;
|
max-quantum = 8192;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
boot.loader.efi.canTouchEfiVariables = false;
|
||||||
# /boot space is at a premium. default was 20.
|
# /boot space is at a premium. default was 20.
|
||||||
# even 10 can be too much
|
# even 10 can be too much
|
||||||
boot.loader.generic-extlinux-compatible.configurationLimit = 8;
|
boot.loader.generic-extlinux-compatible.configurationLimit = 8;
|
||||||
|
# mobile.bootloader.enable = false;
|
||||||
|
# mobile.boot.stage-1.enable = false;
|
||||||
|
# boot.initrd.systemd.enable = false;
|
||||||
|
# boot.initrd.services.swraid.enable = false; # attempt to fix dm_mod stuff
|
||||||
|
|
||||||
|
# hardware.firmware makes the referenced files visible to the kernel, for whenever a driver explicitly asks for them.
|
||||||
|
# these files are visible from userspace by following `/sys/module/firmware_class/parameters/path`
|
||||||
|
#
|
||||||
|
# mobile-nixos' /lib/firmware includes:
|
||||||
|
# rtl_bt (bluetooth)
|
||||||
|
# anx7688-fw.bin (USB-C chip: power negotiation, HDMI/dock)
|
||||||
|
# ov5640_af.bin (camera module)
|
||||||
|
# hardware.firmware = [ config.mobile.device.firmware ];
|
||||||
|
# hardware.firmware = [ pkgs.rtl8723cs-firmware ];
|
||||||
|
hardware.firmware = [
|
||||||
|
(pkgs.linux-firmware-megous.override {
|
||||||
|
# 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).
|
||||||
|
# it seems the rtl_bt stuff ("bluetooth coexist") might make wake-on-LAN radically more flaky.
|
||||||
|
rtl_bt = false;
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
|
system.stateVersion = "21.11";
|
||||||
|
|
||||||
|
# defined: https://www.freedesktop.org/software/systemd/man/machine-info.html
|
||||||
|
# XXX colin: not sure which, if any, software makes use of this
|
||||||
|
environment.etc."machine-info".text = ''
|
||||||
|
CHASSIS="handset"
|
||||||
|
'';
|
||||||
|
|
||||||
|
# enable rotation sensor
|
||||||
|
# hardware.sensor.iio.enable = true;
|
||||||
|
|
||||||
|
services.udev.extraRules = let
|
||||||
|
chmod = "${pkgs.coreutils}/bin/chmod";
|
||||||
|
chown = "${pkgs.coreutils}/bin/chown";
|
||||||
|
in ''
|
||||||
|
# make Pinephone flashlight writable by user.
|
||||||
|
# taken from postmarketOS: <repo:postmarketOS/pmaports:device/main/device-pine64-pinephone/60-flashlight.rules>
|
||||||
|
SUBSYSTEM=="leds", DEVPATH=="*/*:flash", RUN+="${chmod} g+w /sys%p/brightness /sys%p/flash_strobe", RUN+="${chown} :video /sys%p/brightness /sys%p/flash_strobe"
|
||||||
|
|
||||||
|
# make Pinephone front LEDs writable by user.
|
||||||
|
SUBSYSTEM=="leds", DEVPATH=="*/*:indicator", RUN+="${chmod} g+w /sys%p/brightness", RUN+="${chown} :video /sys%p/brightness"
|
||||||
|
'';
|
||||||
}
|
}
|
||||||
|
68
hosts/by-name/moby/gps.nix
Normal file
68
hosts/by-name/moby/gps.nix
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
# pinephone GPS happens in EG25 modem
|
||||||
|
# serial control interface to modem is /dev/ttyUSB2
|
||||||
|
# after enabling GPS, readout is /dev/ttyUSB1
|
||||||
|
#
|
||||||
|
# minimal process to enable modem and GPS:
|
||||||
|
# - `echo 1 > /sys/class/modem-power/modem-power/device/powered`
|
||||||
|
# - `screen /dev/ttyUSB2 115200`
|
||||||
|
# - `AT+QGPSCFG="nmeasrc",1`
|
||||||
|
# - `AT+QGPS=1`
|
||||||
|
# this process is automated by my `eg25-control` program and services (`eg25-control-powered`, `eg25-control-gps`)
|
||||||
|
# - see the `modules/` directory further up this repository.
|
||||||
|
#
|
||||||
|
# now, something like `gpsd` can directly read from /dev/ttyUSB1,
|
||||||
|
# or geoclue can query the GPS directly through modem-manager
|
||||||
|
#
|
||||||
|
# initial GPS fix can take 15+ minutes.
|
||||||
|
# meanwhile, services like eg25-manager or eg25-control-freshen-agps can speed this up by uploading assisted GPS data to the modem.
|
||||||
|
#
|
||||||
|
# support/help:
|
||||||
|
# - geoclue, gnome-maps
|
||||||
|
# - irc: #gnome-maps on irc.gimp.org
|
||||||
|
# - Matrix: #gnome-maps:gnome.org (unclear if bridged to IRC)
|
||||||
|
#
|
||||||
|
# programs to pair this with:
|
||||||
|
# - `satellite-gtk`: <https://codeberg.org/tpikonen/satellite>
|
||||||
|
# - shows/tracks which satellites the GPS is connected to; useful to understand fix characteristics
|
||||||
|
# - `gnome-maps`: uses geoclue, has route planning
|
||||||
|
# - `mepo`: uses gpsd, minimalist, flaky, and buttons are kinda hard to activate on mobile
|
||||||
|
# - puremaps?
|
||||||
|
# - osmin?
|
||||||
|
#
|
||||||
|
# known/outstanding bugs:
|
||||||
|
# - `systemctl start eg25-control-gps` can the hang the whole system (2023/10/06)
|
||||||
|
# - i think it's actually `eg25-control-powered` which does this (started by the gps)
|
||||||
|
# - best guess is modem draws so much power at launch that other parts of the system see undervoltage
|
||||||
|
# - workaround is to hard power-cycle the system. the modem may not bring up after reboot: leave unpowered for 60s and boot again.
|
||||||
|
#
|
||||||
|
# future work:
|
||||||
|
# - integrate with [wigle](https://www.wigle.net/) for offline equivalent to Mozilla Location Services
|
||||||
|
|
||||||
|
{ config, lib, ... }:
|
||||||
|
{
|
||||||
|
# test gpsd with `gpspipe -w -n 10 2> /dev/null | grep -m 1 TPV | jq '.lat, .lon' | tr '\n' ' '`
|
||||||
|
# ^ should return <lat> <long>
|
||||||
|
services.gpsd.enable = true;
|
||||||
|
services.gpsd.devices = [ "/dev/ttyUSB1" ];
|
||||||
|
|
||||||
|
# test geoclue2 by building `geoclue2-with-demo-agent`
|
||||||
|
# and running "${geoclue2-with-demo-agent}/libexec/geoclue-2.0/demos/where-am-i"
|
||||||
|
# note that geoclue is dbus-activated, and auto-stops after 60s with no caller
|
||||||
|
services.geoclue2.enable = true;
|
||||||
|
services.geoclue2.appConfig.where-am-i = {
|
||||||
|
# this is the default "agent", shipped by geoclue package: allow it to use location
|
||||||
|
isAllowed = true;
|
||||||
|
isSystem = false;
|
||||||
|
# XXX: setting users != [] might be causing `where-am-i` to time out
|
||||||
|
users = [
|
||||||
|
# restrict to only one set of users. empty array (default) means "allow any user to access geolocation".
|
||||||
|
(builtins.toString config.users.users.colin.uid)
|
||||||
|
];
|
||||||
|
};
|
||||||
|
systemd.services.geoclue.after = lib.mkForce []; #< defaults to network-online, but not all my sources require network
|
||||||
|
users.users.geoclue.extraGroups = [
|
||||||
|
"dialout" # TODO: figure out if dialout is required. that's for /dev/ttyUSB1, but geoclue probably doesn't read that?
|
||||||
|
];
|
||||||
|
|
||||||
|
sane.programs.where-am-i.enableFor.user.colin = true;
|
||||||
|
}
|
271
hosts/by-name/moby/kernel.nix
Normal file
271
hosts/by-name/moby/kernel.nix
Normal file
@@ -0,0 +1,271 @@
|
|||||||
|
{ pkgs, ... }:
|
||||||
|
let
|
||||||
|
dmesg = "${pkgs.util-linux}/bin/dmesg";
|
||||||
|
grep = "${pkgs.gnugrep}/bin/grep";
|
||||||
|
modprobe = "${pkgs.kmod}/bin/modprobe";
|
||||||
|
ensureHWReady = ''
|
||||||
|
# common boot failure:
|
||||||
|
# blank screen (no backlight even), with the following log:
|
||||||
|
# ```syslog
|
||||||
|
# sun8i-dw-hdmi 1ee0000.hdmi: Couldn't get the HDMI PHY
|
||||||
|
# ...
|
||||||
|
# sun4i-drm display-engine: Couldn't bind all pipelines components
|
||||||
|
# ...
|
||||||
|
# sun8i-dw-hdmi: probe of 1ee0000.hdmi failed with error -17
|
||||||
|
# ```
|
||||||
|
#
|
||||||
|
# in particular, that `probe ... failed` occurs *only* on failed boots
|
||||||
|
# (the other messages might sometimes occur even on successful runs?)
|
||||||
|
#
|
||||||
|
# reloading the sun8i hdmi driver usually gets the screen on, showing boot text.
|
||||||
|
# then restarting display-manager.service gets us to the login.
|
||||||
|
#
|
||||||
|
# NB: the above log is default level. though less specific, there's a `err` level message that also signals this:
|
||||||
|
# sun4i-drm display-engine: failed to bind 1ee0000.hdmi (ops sun8i_dw_hdmi_ops [sun8i_drm_hdmi]): -17
|
||||||
|
# NB: this is the most common, but not the only, failure mode for `display-manager`.
|
||||||
|
# another error seems characterized by these dmesg logs, in which reprobing sun8i_drm_hdmi does not fix:
|
||||||
|
# ```syslog
|
||||||
|
# sun6i-mipi-dsi 1ca0000.dsi: Couldn't get the MIPI D-PHY
|
||||||
|
# sun4i-drm display-engine: Couldn't bind all pipelines components
|
||||||
|
# sun6i-mipi-dsi 1ca0000.dsi: Couldn't register our component
|
||||||
|
# ```
|
||||||
|
|
||||||
|
if (${dmesg} --kernel --level err --color=never --notime | ${grep} -q 'sun4i-drm display-engine: failed to bind 1ee0000.hdmi')
|
||||||
|
then
|
||||||
|
echo "reprobing sun8i_drm_hdmi"
|
||||||
|
# if a command here fails it errors the whole service, so prefer to log instead
|
||||||
|
${modprobe} -r sun8i_drm_hdmi || echo "failed to unload sun8i_drm_hdmi"
|
||||||
|
${modprobe} sun8i_drm_hdmi || echo "failed to load sub8i_drm_hdmi"
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
{
|
||||||
|
# kernel compatibility (2024/05/22: 03dab630)
|
||||||
|
# - linux-megous: boots to ssh, desktop
|
||||||
|
# - camera apps: megapixels (no cameras found), snapshot (no cameras found)
|
||||||
|
# - linux-postmarketos: boots to ssh. desktop ONLY if "anx7688" is in the initrd.availableKernelModules.
|
||||||
|
# - camera apps: megapixels (both rear and front cameras work), `cam -l` (finds only the rear camera), snapshot (no cameras found)
|
||||||
|
# - linux-megous.override { withMegiPinephoneConfig = true; }: NO SSH, NO SIGNS OF LIFE
|
||||||
|
# - linux-megous.override { withFullConfig = false; }: boots to ssh, no desktop
|
||||||
|
#
|
||||||
|
boot.kernelPackages = pkgs.linuxPackagesFor (pkgs.linux-postmarketos.override {
|
||||||
|
withModemPower = true;
|
||||||
|
});
|
||||||
|
# boot.kernelPackages = pkgs.linuxPackagesFor pkgs.linux-megous;
|
||||||
|
# boot.kernelPackages = pkgs.linuxPackagesFor (pkgs.linux-megous.override {
|
||||||
|
# withFullConfig = false;
|
||||||
|
# });
|
||||||
|
# boot.kernelPackages = pkgs.linuxPackagesFor (pkgs.linux-megous.override {
|
||||||
|
# withMegiPinephoneConfig = true; #< N.B.: does not boot as of 2024/05/22!
|
||||||
|
# });
|
||||||
|
# boot.kernelPackages = pkgs.linuxPackagesFor pkgs.linux-manjaro;
|
||||||
|
# boot.kernelPackages = pkgs.linuxPackagesFor pkgs.linux_latest;
|
||||||
|
|
||||||
|
# nixpkgs.hostPlatform.linux-kernel becomes stdenv.hostPlatform.linux-kernel
|
||||||
|
nixpkgs.hostPlatform.linux-kernel = {
|
||||||
|
# defaults:
|
||||||
|
name = "aarch64-multiplatform";
|
||||||
|
# baseConfig: defaults to "defconfig";
|
||||||
|
# baseConfig = "pinephone_defconfig"; #< N.B.: ignored by `pkgs.linux-megous`
|
||||||
|
DTB = true; #< DTB: compile device tree blobs
|
||||||
|
# autoModules (default: true): for config options not manually specified, answer `m` to anything which supports it.
|
||||||
|
# - this effectively builds EVERY MODULE SUPPORTED.
|
||||||
|
autoModules = true; #< N.B.: ignored by `pkgs.linux-megous`
|
||||||
|
# preferBuiltin (default: false; true for rpi): for config options which default to `Y` upstream, build them as `Y` (overriding `autoModules`)
|
||||||
|
# preferBuiltin = false;
|
||||||
|
|
||||||
|
# build a compressed kernel image: without this i run out of /boot space in < 10 generations
|
||||||
|
# target = "Image"; # <-- default
|
||||||
|
target = "Image.gz"; # <-- compress the kernel image
|
||||||
|
# target = "zImage"; # <-- confuses other parts of nixos :-(
|
||||||
|
};
|
||||||
|
|
||||||
|
# boot.initrd.kernelModules = [
|
||||||
|
# "drm" #< force drm to be plugged
|
||||||
|
# ];
|
||||||
|
boot.initrd.availableKernelModules = [
|
||||||
|
# see <repo:postmarketOS/pmaports:device/main/device-pine64-pinephone/modules-initfs>
|
||||||
|
# - they include sun6i_mipi_dsi sun4i_drm pwm_sun4i sun8i_mixer anx7688 gpio_vibra pinephone_keyboard
|
||||||
|
"anx7688" #< required for display initialization and functional cameras
|
||||||
|
# full list of modules active post-boot with the linux-megous kernel + autoModules=true:
|
||||||
|
# - `lsmod | sort | cut -d ' ' -f 1`
|
||||||
|
# "8723cs"
|
||||||
|
# "axp20x_adc" #< NOT FOUND in megous-no-autoModules
|
||||||
|
# "axp20x_battery"
|
||||||
|
# "axp20x_pek"
|
||||||
|
# "axp20x_usb_power"
|
||||||
|
# "backlight"
|
||||||
|
# "blake2b_generic"
|
||||||
|
# "bluetooth"
|
||||||
|
# "bridge"
|
||||||
|
# "btbcm"
|
||||||
|
# "btqca"
|
||||||
|
# "btrfs"
|
||||||
|
# "btrtl"
|
||||||
|
# "cec"
|
||||||
|
# "cfg80211"
|
||||||
|
# "chacha_neon"
|
||||||
|
# "crc_ccitt"
|
||||||
|
# "crct10dif_ce"
|
||||||
|
# "crypto_engine"
|
||||||
|
# "display_connector" #< NOT FOUND in pmos
|
||||||
|
# "drm"
|
||||||
|
# "drm_display_helper"
|
||||||
|
# "drm_dma_helper"
|
||||||
|
# "drm_kms_helper"
|
||||||
|
# "drm_shmem_helper"
|
||||||
|
# "dw_hdmi"
|
||||||
|
# "dw_hdmi_cec" #< NOT FOUND in pmos
|
||||||
|
# "dw_hdmi_i2s_audio"
|
||||||
|
# "ecc"
|
||||||
|
# "ecdh_generic"
|
||||||
|
# "fuse"
|
||||||
|
# "gc2145" #< NOT FOUND in megous-no-autoModules
|
||||||
|
# "goodix_ts"
|
||||||
|
# "gpio_vibra" #< NOT FOUND in megous-no-autoModules
|
||||||
|
# "gpu_sched"
|
||||||
|
# "hci_uart"
|
||||||
|
# "i2c_gpio"
|
||||||
|
# "inv_mpu6050" #< NOT FOUND in megous-no-autoModules
|
||||||
|
# "inv_mpu6050_i2c" #< NOT FOUND in megous-no-autoModules
|
||||||
|
# "inv_sensors_timestamp" #< NOT FOUND in megous-no-autoModules
|
||||||
|
# "ip6t_rpfilter"
|
||||||
|
# "ip6_udp_tunnel"
|
||||||
|
# "ip_set"
|
||||||
|
# "ip_set_hash_ipport"
|
||||||
|
# "ip_tables"
|
||||||
|
# "ipt_rpfilter"
|
||||||
|
# "joydev"
|
||||||
|
# "led_class_flash" #< NOT FOUND in megous-no-autoModules
|
||||||
|
# "leds_sgm3140" #< NOT FOUND in megous-no-autoModules
|
||||||
|
# "ledtrig_pattern" #< NOT FOUND in megous-no-autoModules
|
||||||
|
# "libarc4"
|
||||||
|
# "libchacha"
|
||||||
|
# "libchacha20poly1305"
|
||||||
|
# "libcrc32c"
|
||||||
|
# "libcurve25519_generic"
|
||||||
|
# "lima"
|
||||||
|
# "llc"
|
||||||
|
# "mac80211"
|
||||||
|
# "macvlan"
|
||||||
|
# "mc"
|
||||||
|
# "modem_power"
|
||||||
|
# "mousedev"
|
||||||
|
# "nf_conntrack"
|
||||||
|
# "nf_defrag_ipv4"
|
||||||
|
# "nf_defrag_ipv6"
|
||||||
|
# "nf_log_syslog"
|
||||||
|
# "nf_nat"
|
||||||
|
# "nfnetlink"
|
||||||
|
# "nf_tables"
|
||||||
|
# "nft_chain_nat"
|
||||||
|
# "nft_compat"
|
||||||
|
# "nls_cp437"
|
||||||
|
# "nls_iso8859_1"
|
||||||
|
# "nvmem_reboot_mode"
|
||||||
|
# "ov5640"
|
||||||
|
# "panel_sitronix_st7703"
|
||||||
|
# "phy_sun6i_mipi_dphy"
|
||||||
|
# "pinctrl_axp209" #< NOT FOUND in pmos
|
||||||
|
# "pinephone_keyboard" #< NOT FOUND in megous-no-autoModules
|
||||||
|
# "poly1305_neon"
|
||||||
|
# "polyval_ce"
|
||||||
|
# "polyval_generic"
|
||||||
|
# "ppkb_manager" #< NOT FOUND in megous-no-autoModules
|
||||||
|
# "pwm_bl"
|
||||||
|
# "pwm_sun4i"
|
||||||
|
# "qrtr"
|
||||||
|
# "raid6_pq"
|
||||||
|
# "rfkill"
|
||||||
|
# "rtw88_8703b"
|
||||||
|
# "rtw88_8723cs"
|
||||||
|
# "rtw88_8723x"
|
||||||
|
# "rtw88_core"
|
||||||
|
# "rtw88_sdio"
|
||||||
|
# "sch_fq_codel"
|
||||||
|
# "sm4"
|
||||||
|
# "snd_soc_bt_sco"
|
||||||
|
# "snd_soc_ec25" #< NOT FOUND in megous-no-autoModules
|
||||||
|
# "snd_soc_hdmi_codec"
|
||||||
|
# "snd_soc_simple_amplifier"
|
||||||
|
# "snd_soc_simple_card"
|
||||||
|
# "snd_soc_simple_card_utils"
|
||||||
|
# "stk3310" #< NOT FOUND in megous-no-autoModules
|
||||||
|
# "st_magn"
|
||||||
|
# "st_magn_i2c"
|
||||||
|
# "st_magn_spi" #< NOT FOUND in pmos
|
||||||
|
# "stp"
|
||||||
|
# "st_sensors"
|
||||||
|
# "st_sensors_i2c"
|
||||||
|
# "st_sensors_spi" #< NOT FOUND in pmos
|
||||||
|
# "sun4i_drm"
|
||||||
|
# "sun4i_i2s"
|
||||||
|
# "sun4i_lradc_keys" #< NOT FOUND in megous-no-autoModules
|
||||||
|
# "sun4i_tcon"
|
||||||
|
# "sun50i_codec_analog"
|
||||||
|
# "sun6i_csi"
|
||||||
|
# "sun6i_dma"
|
||||||
|
# "sun6i_mipi_dsi"
|
||||||
|
# "sun8i_a33_mbus" #< NOT FOUND in megous-no-autoModules
|
||||||
|
# "sun8i_adda_pr_regmap"
|
||||||
|
# "sun8i_ce" #< NOT FOUND in pmos
|
||||||
|
# "sun8i_codec" #< NOT FOUND in megous-no-autoModules
|
||||||
|
# "sun8i_di" #< NOT FOUND in megous-no-autoModules
|
||||||
|
# "sun8i_drm_hdmi"
|
||||||
|
# "sun8i_mixer"
|
||||||
|
# "sun8i_rotate" #< NOT FOUND in megous-no-autoModules
|
||||||
|
# "sun8i_tcon_top"
|
||||||
|
# "sun9i_hdmi_audio" #< NOT FOUND in megous-no-autoModules
|
||||||
|
# "sunxi_wdt" #< NOT FOUND in pmos
|
||||||
|
# "tap"
|
||||||
|
# "typec" #< NOT FOUND in pmos
|
||||||
|
# "udp_tunnel"
|
||||||
|
# "uio" #< NOT FOUND in pmos
|
||||||
|
# "uio_pdrv_genirq"
|
||||||
|
# "v4l2_async"
|
||||||
|
# "v4l2_cci" #< NOT FOUND in pmos
|
||||||
|
# "v4l2_flash_led_class" #< NOT FOUND in megous-no-autoModules
|
||||||
|
# "v4l2_fwnode"
|
||||||
|
# "v4l2_mem2mem"
|
||||||
|
# "videobuf2_common"
|
||||||
|
# "videobuf2_dma_contig"
|
||||||
|
# "videobuf2_memops"
|
||||||
|
# "videobuf2_v4l2"
|
||||||
|
# "videodev"
|
||||||
|
# "wireguard"
|
||||||
|
# "xor"
|
||||||
|
# "x_tables"
|
||||||
|
# "xt_conntrack"
|
||||||
|
# "xt_LOG"
|
||||||
|
# "xt_nat"
|
||||||
|
# "xt_pkttype"
|
||||||
|
# "xt_set"
|
||||||
|
# "xt_tcpudp"
|
||||||
|
# "zram"
|
||||||
|
];
|
||||||
|
|
||||||
|
# disable proximity sensor.
|
||||||
|
# the filtering/calibration is bad that it causes the screen to go fully dark at times.
|
||||||
|
# boot.blacklistedKernelModules = [ "stk3310" ];
|
||||||
|
|
||||||
|
boot.kernelParams = [
|
||||||
|
# without this some GUI apps fail: `DRM_IOCTL_MODE_CREATE_DUMB failed: Cannot allocate memory`
|
||||||
|
# this is because they can't allocate enough video ram.
|
||||||
|
# see related nixpkgs issue: <https://github.com/NixOS/nixpkgs/issues/260222>
|
||||||
|
# TODO(2023/12/03): remove once mesa 23.3.1 lands: <https://github.com/NixOS/nixpkgs/pull/265740>
|
||||||
|
#
|
||||||
|
# the default CMA seems to be 32M.
|
||||||
|
# i was running fine with 256MB from 2022/07-ish through 2022/12-ish, but then the phone quit reliably coming back from sleep (phosh): maybe a memory leak?
|
||||||
|
# bumped to 512M on 2023/01
|
||||||
|
# bumped to 1536M on 2024/05
|
||||||
|
# `cat /proc/meminfo` to see CmaTotal/CmaFree if interested in tuning this.
|
||||||
|
# kernel param mentioned here: <https://cateee.net/lkddb/web-lkddb/CMA_SIZE_PERCENTAGE.html>
|
||||||
|
# i think cma mem isn't exclusive -- it can be used as ordinary `malloc`, still. i heard someone suggest the OS default should just be 50% memory to CMA.
|
||||||
|
"cma=1536M"
|
||||||
|
# 2023/10/20: potential fix for the lima (GPU) timeout bugs:
|
||||||
|
# - <https://gitlab.com/postmarketOS/pmaports/-/issues/805#note_890467824>
|
||||||
|
"lima.sched_timeout_ms=2000"
|
||||||
|
];
|
||||||
|
|
||||||
|
systemd.services.unl0kr.preStart = ensureHWReady;
|
||||||
|
}
|
45
hosts/by-name/moby/polyfill.nix
Normal file
45
hosts/by-name/moby/polyfill.nix
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
# this file configures preferences per program, without actually enabling any programs.
|
||||||
|
# the goal is to separate the place where we decide *what* to use (i.e. `sane.programs.firefox.enable = true` -- at the toplevel)
|
||||||
|
# from where we specific how that thing should behave *if* it's in use.
|
||||||
|
#
|
||||||
|
# NixOS backgrounds:
|
||||||
|
# - <https://github.com/NixOS/nixos-artwork>
|
||||||
|
# - <https://github.com/NixOS/nixos-artwork/issues/50> (colorful; unmerged)
|
||||||
|
# - <https://github.com/NixOS/nixos-artwork/pull/60/files> (desktop-oriented; clean; unmerged)
|
||||||
|
# - <https://itsfoss.com/content/images/2023/04/nixos-tutorials.png>
|
||||||
|
|
||||||
|
{ lib, pkgs, sane-lib, ... }:
|
||||||
|
{
|
||||||
|
sane.programs.firefox.config = {
|
||||||
|
# compromise impermanence for the sake of usability
|
||||||
|
persistCache = "private";
|
||||||
|
persistData = "private";
|
||||||
|
|
||||||
|
# i don't do crypto stuff on moby
|
||||||
|
addons.ether-metamask.enable = false;
|
||||||
|
# sidebery UX doesn't make sense on small screen
|
||||||
|
addons.sidebery.enable = false;
|
||||||
|
};
|
||||||
|
sane.programs.swaynotificationcenter.config = {
|
||||||
|
backlight = "backlight"; # /sys/class/backlight/*backlight*/brightness
|
||||||
|
};
|
||||||
|
|
||||||
|
sane.programs.alacritty.config.fontSize = 9;
|
||||||
|
|
||||||
|
sane.programs.sway.config = {
|
||||||
|
font = "pango:monospace 10";
|
||||||
|
mod = "Mod1"; # prefer Alt
|
||||||
|
workspace_layout = "tabbed";
|
||||||
|
};
|
||||||
|
|
||||||
|
sane.programs.waybar.config = {
|
||||||
|
fontSize = 14;
|
||||||
|
height = 26;
|
||||||
|
persistWorkspaces = [ "1" "2" "3" "4" "5" ];
|
||||||
|
modules.media = false;
|
||||||
|
modules.network = false;
|
||||||
|
modules.perf = false;
|
||||||
|
modules.windowTitle = false;
|
||||||
|
# TODO: show modem state
|
||||||
|
};
|
||||||
|
}
|
@@ -4,6 +4,7 @@
|
|||||||
./fs.nix
|
./fs.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
|
boot.loader.efi.canTouchEfiVariables = false;
|
||||||
sane.image.extraBootFiles = [ pkgs.bootpart-uefi-x86_64 ];
|
sane.image.extraBootFiles = [ pkgs.bootpart-uefi-x86_64 ];
|
||||||
sane.persist.enable = false; # what we mean here is that the image is immutable; `/` is still tmpfs.
|
sane.persist.enable = false; # what we mean here is that the image is immutable; `/` is still tmpfs.
|
||||||
sane.nixcache.enable = false; # don't want to be calling out to dead machines that we're *trying* to rescue
|
sane.nixcache.enable = false; # don't want to be calling out to dead machines that we're *trying* to rescue
|
||||||
@@ -11,4 +12,7 @@
|
|||||||
# auto-login at shell
|
# auto-login at shell
|
||||||
services.getty.autologinUser = "colin";
|
services.getty.autologinUser = "colin";
|
||||||
# users.users.colin.initialPassword = "colin";
|
# users.users.colin.initialPassword = "colin";
|
||||||
|
|
||||||
|
# docs: https://nixos.org/manual/nixos/stable/options.html#opt-system.stateVersion
|
||||||
|
system.stateVersion = "21.05";
|
||||||
}
|
}
|
||||||
|
@@ -7,11 +7,12 @@
|
|||||||
./services
|
./services
|
||||||
];
|
];
|
||||||
|
|
||||||
# for administering services
|
sane.programs = {
|
||||||
sane.programs.clightning-sane.enableFor.user.colin = true;
|
# for administering services
|
||||||
# sane.programs.freshrss.enableFor.user.colin = true;
|
freshrss.enableFor.user.colin = true;
|
||||||
# sane.programs.signaldctl.enableFor.user.colin = true;
|
matrix-synapse.enableFor.user.colin = true;
|
||||||
# sane.programs.matrix-synapse.enableFor.user.colin = true;
|
signaldctl.enableFor.user.colin = true;
|
||||||
|
};
|
||||||
|
|
||||||
sane.roles.build-machine.enable = true;
|
sane.roles.build-machine.enable = true;
|
||||||
sane.programs.zsh.config.showDeadlines = false; # ~/knowledge doesn't always exist
|
sane.programs.zsh.config.showDeadlines = false; # ~/knowledge doesn't always exist
|
||||||
@@ -37,6 +38,7 @@
|
|||||||
# using root here makes sure we always have an escape hatch
|
# using root here makes sure we always have an escape hatch
|
||||||
services.getty.autologinUser = "root";
|
services.getty.autologinUser = "root";
|
||||||
|
|
||||||
|
boot.loader.efi.canTouchEfiVariables = false;
|
||||||
sane.image.extraBootFiles = [ pkgs.bootpart-uefi-x86_64 ];
|
sane.image.extraBootFiles = [ pkgs.bootpart-uefi-x86_64 ];
|
||||||
|
|
||||||
# both transmission and ipfs try to set different net defaults.
|
# both transmission and ipfs try to set different net defaults.
|
||||||
@@ -44,5 +46,13 @@
|
|||||||
boot.kernel.sysctl = {
|
boot.kernel.sysctl = {
|
||||||
"net.core.rmem_max" = 4194304; # 4MB
|
"net.core.rmem_max" = 4194304; # 4MB
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# This value determines the NixOS release from which the default
|
||||||
|
# settings for stateful data, like file locations and database versions
|
||||||
|
# on your system were taken. It‘s perfectly fine and recommended to leave
|
||||||
|
# this value at the release version of the first install of this system.
|
||||||
|
# Before changing this value read the documentation for this option
|
||||||
|
# (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).
|
||||||
|
system.stateVersion = "21.11";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -54,7 +54,7 @@
|
|||||||
options = [ "acl" ]; #< not sure if this `acl` flag is actually necessary. it mounts without it.
|
options = [ "acl" ]; #< not sure if this `acl` flag is actually necessary. it mounts without it.
|
||||||
};
|
};
|
||||||
# services.zfs.zed = ... # TODO: zfs can send me emails when disks fail
|
# services.zfs.zed = ... # TODO: zfs can send me emails when disks fail
|
||||||
sane.programs.sysadminUtils.suggestedPrograms = [ "zfs-tools" ];
|
sane.programs.sysadminUtils.suggestedPrograms = [ "zfs" ];
|
||||||
|
|
||||||
sane.persist.stores."ext" = {
|
sane.persist.stores."ext" = {
|
||||||
origin = "/mnt/pool/persist";
|
origin = "/mnt/pool/persist";
|
||||||
|
@@ -3,19 +3,9 @@
|
|||||||
let
|
let
|
||||||
portOpts = with lib; types.submodule {
|
portOpts = with lib; types.submodule {
|
||||||
options = {
|
options = {
|
||||||
visibleTo.ovpns = mkOption {
|
visibleTo.ovpn = mkOption {
|
||||||
type = types.bool;
|
type = types.bool;
|
||||||
default = false;
|
default = false;
|
||||||
description = ''
|
|
||||||
whether to forward inbound traffic on the OVPN vpn port to the corresponding localhost port.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
visibleTo.doof = mkOption {
|
|
||||||
type = types.bool;
|
|
||||||
default = false;
|
|
||||||
description = ''
|
|
||||||
whether to forward inbound traffic on the doofnet vpn port to the corresponding localhost port.
|
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -23,7 +13,7 @@ in
|
|||||||
{
|
{
|
||||||
options = with lib; {
|
options = with lib; {
|
||||||
sane.ports.ports = mkOption {
|
sane.ports.ports = mkOption {
|
||||||
# add the `visibleTo.{doof,ovpns}` options
|
# add the `visibleTo.ovpn` option
|
||||||
type = types.attrsOf portOpts;
|
type = types.attrsOf portOpts;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -50,16 +40,18 @@ in
|
|||||||
|
|
||||||
# tun-sea config
|
# tun-sea config
|
||||||
sane.dns.zones."uninsane.org".inet.A."doof.tunnel" = "205.201.63.12";
|
sane.dns.zones."uninsane.org".inet.A."doof.tunnel" = "205.201.63.12";
|
||||||
# sane.dns.zones."uninsane.org".inet.AAAA."doof.tunnel" = "2602:fce8:106::51"; #< TODO: enable IPv6
|
sane.dns.zones."uninsane.org".inet.AAAA."doof.tunnel" = "2602:fce8:106::51";
|
||||||
networking.wireguard.interfaces.wg-doof = {
|
networking.wireguard.interfaces.wg-doof = let
|
||||||
|
ip = "${pkgs.iproute2}/bin/ip";
|
||||||
|
in {
|
||||||
privateKeyFile = config.sops.secrets.wg_doof_privkey.path;
|
privateKeyFile = config.sops.secrets.wg_doof_privkey.path;
|
||||||
# wg is active only in this namespace.
|
# wg is active only in this namespace.
|
||||||
# run e.g. ip netns exec doof <some command like ping/curl/etc, it'll go through wg>
|
# run e.g. ip netns exec doof <some command like ping/curl/etc, it'll go through wg>
|
||||||
# sudo ip netns exec doof ping www.google.com
|
# sudo ip netns exec doof ping www.google.com
|
||||||
interfaceNamespace = "doof";
|
interfaceNamespace = "doof";
|
||||||
ips = [
|
ips = [
|
||||||
"205.201.63.12"
|
"205.201.63.12/32"
|
||||||
# "2602:fce8:106::51/128" #< TODO: enable IPv6
|
"2602:fce8:106::51/128"
|
||||||
];
|
];
|
||||||
peers = [
|
peers = [
|
||||||
{
|
{
|
||||||
@@ -71,24 +63,45 @@ in
|
|||||||
persistentKeepalive = 25; #< keep the NAT alive
|
persistentKeepalive = 25; #< keep the NAT alive
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
preSetup = ''
|
||||||
|
${ip} netns add doof || (test -e /run/netns/doof && echo "doof already exists")
|
||||||
|
'';
|
||||||
|
postShutdown = ''
|
||||||
|
${ip} netns delete doof || echo "couldn't delete doof"
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
sane.netns.doof.hostVethIpv4 = "10.0.2.5";
|
|
||||||
sane.netns.doof.netnsVethIpv4 = "10.0.2.6";
|
|
||||||
sane.netns.doof.netnsPubIpv4 = "205.201.63.12";
|
|
||||||
sane.netns.doof.routeTable = 12;
|
|
||||||
|
|
||||||
# OVPN CONFIG (https://www.ovpn.com):
|
# OVPN CONFIG (https://www.ovpn.com):
|
||||||
# DOCS: https://nixos.wiki/wiki/WireGuard
|
# DOCS: https://nixos.wiki/wiki/WireGuard
|
||||||
# if you `systemctl restart wireguard-wg-ovpns`, make sure to also restart any other services in `NetworkNamespacePath = .../ovpns`.
|
# if you `systemctl restart wireguard-wg-ovpns`, make sure to also restart any other services in `NetworkNamespacePath = .../ovpns`.
|
||||||
# TODO: why not create the namespace as a seperate operation (nix config for that?)
|
# TODO: why not create the namespace as a seperate operation (nix config for that?)
|
||||||
networking.wireguard.enable = true;
|
networking.wireguard.enable = true;
|
||||||
networking.wireguard.interfaces.wg-ovpns = {
|
networking.wireguard.interfaces.wg-ovpns = let
|
||||||
|
ip = "${pkgs.iproute2}/bin/ip";
|
||||||
|
in-ns = "${ip} netns exec ovpns";
|
||||||
|
iptables = "${pkgs.iptables}/bin/iptables";
|
||||||
|
veth-host-ip = "10.0.1.5";
|
||||||
|
veth-local-ip = "10.0.1.6";
|
||||||
|
vpn-ip = "185.157.162.178";
|
||||||
|
# DNS = 46.227.67.134, 192.165.9.158, 2a07:a880:4601:10f0:cd45::1, 2001:67c:750:1:cafe:cd45::1
|
||||||
|
vpn-dns = "46.227.67.134";
|
||||||
|
bridgePort = port: proto: ''
|
||||||
|
${in-ns} ${iptables} -A PREROUTING -t nat -p ${proto} --dport ${port} -m iprange --dst-range ${vpn-ip} \
|
||||||
|
-j DNAT --to-destination ${veth-host-ip}
|
||||||
|
'';
|
||||||
|
bridgeStatements = lib.foldlAttrs
|
||||||
|
(acc: port: portCfg: acc ++ (builtins.map (bridgePort port) portCfg.protocol))
|
||||||
|
[]
|
||||||
|
config.sane.ports.ports;
|
||||||
|
in {
|
||||||
privateKeyFile = config.sops.secrets.wg_ovpns_privkey.path;
|
privateKeyFile = config.sops.secrets.wg_ovpns_privkey.path;
|
||||||
# wg is active only in this namespace.
|
# wg is active only in this namespace.
|
||||||
# run e.g. ip netns exec ovpns <some command like ping/curl/etc, it'll go through wg>
|
# run e.g. ip netns exec ovpns <some command like ping/curl/etc, it'll go through wg>
|
||||||
# sudo ip netns exec ovpns ping www.google.com
|
# sudo ip netns exec ovpns ping www.google.com
|
||||||
interfaceNamespace = "ovpns";
|
interfaceNamespace = "ovpns";
|
||||||
ips = [ "185.157.162.178" ];
|
ips = [
|
||||||
|
"185.157.162.178/32"
|
||||||
|
];
|
||||||
peers = [
|
peers = [
|
||||||
{
|
{
|
||||||
publicKey = "SkkEZDCBde22KTs/Hc7FWvDBfdOCQA4YtBEuC3n5KGs=";
|
publicKey = "SkkEZDCBde22KTs/Hc7FWvDBfdOCQA4YtBEuC3n5KGs=";
|
||||||
@@ -106,11 +119,99 @@ in
|
|||||||
# dynamicEndpointRefreshRestartSeconds = 5;
|
# dynamicEndpointRefreshRestartSeconds = 5;
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
preSetup = ''
|
||||||
|
${ip} netns add ovpns || (test -e /run/netns/ovpns && echo "ovpns already exists")
|
||||||
|
'';
|
||||||
|
postShutdown = ''
|
||||||
|
${in-ns} ip link del ovpns-veth-b || echo "couldn't delete ovpns-veth-b"
|
||||||
|
${ip} link del ovpns-veth-a || echo "couldn't delete ovpns-veth-a"
|
||||||
|
${ip} netns delete ovpns || echo "couldn't delete ovpns"
|
||||||
|
# restore rules/routes
|
||||||
|
${ip} rule del from ${veth-host-ip} lookup ovpns pref 50 || echo "couldn't delete init -> ovpns rule"
|
||||||
|
${ip} route del default via ${veth-local-ip} dev ovpns-veth-a proto kernel src ${veth-host-ip} metric 1002 table ovpns || echo "couldn't delete init -> ovpns route"
|
||||||
|
${ip} rule add from all lookup local pref 0
|
||||||
|
${ip} rule del from all lookup local pref 100
|
||||||
|
'';
|
||||||
|
postSetup = ''
|
||||||
|
# DOCS:
|
||||||
|
# - some of this approach is described here: <https://josephmuia.ca/2018-05-16-net-namespaces-veth-nat/>
|
||||||
|
# - iptables primer: <https://danielmiessler.com/study/iptables/>
|
||||||
|
# create veth pair
|
||||||
|
${ip} link add ovpns-veth-a type veth peer name ovpns-veth-b
|
||||||
|
${ip} addr add ${veth-host-ip}/24 dev ovpns-veth-a
|
||||||
|
${ip} link set ovpns-veth-a up
|
||||||
|
|
||||||
|
# mv veth-b into the ovpns namespace
|
||||||
|
${ip} link set ovpns-veth-b netns ovpns
|
||||||
|
${in-ns} ip addr add ${veth-local-ip}/24 dev ovpns-veth-b
|
||||||
|
${in-ns} ip link set ovpns-veth-b up
|
||||||
|
|
||||||
|
# make it so traffic originating from the host side of the veth
|
||||||
|
# is sent over the veth no matter its destination.
|
||||||
|
${ip} rule add from ${veth-host-ip} lookup ovpns pref 50
|
||||||
|
# for traffic originating at the host veth to the WAN, use the veth as our gateway
|
||||||
|
# not sure if the metric 1002 matters.
|
||||||
|
${ip} route add default via ${veth-local-ip} dev ovpns-veth-a proto kernel src ${veth-host-ip} metric 1002 table ovpns
|
||||||
|
# give the default route lower priority
|
||||||
|
${ip} rule add from all lookup local pref 100
|
||||||
|
${ip} rule del from all lookup local pref 0
|
||||||
|
|
||||||
|
# in order to access DNS in this netns, we need to route it to the VPN's nameservers
|
||||||
|
# - alternatively, we could fix DNS servers like 1.1.1.1.
|
||||||
|
${in-ns} ${iptables} -A OUTPUT -t nat -p udp --dport 53 -m iprange --dst-range 127.0.0.53 \
|
||||||
|
-j DNAT --to-destination ${vpn-dns}:53
|
||||||
|
'' + (lib.concatStringsSep "\n" bridgeStatements);
|
||||||
};
|
};
|
||||||
sane.netns.ovpns.hostVethIpv4 = "10.0.1.5";
|
|
||||||
sane.netns.ovpns.netnsVethIpv4 = "10.0.1.6";
|
# create a new routing table that we can use to proxy traffic out of the root namespace
|
||||||
sane.netns.ovpns.netnsPubIpv4 = "185.157.162.178";
|
# through the ovpns namespace, and to the WAN via VPN.
|
||||||
sane.netns.ovpns.routeTable = 11;
|
networking.iproute2.rttablesExtraConfig = ''
|
||||||
sane.netns.ovpns.dns = "46.227.67.134"; #< DNS requests inside the namespace are forwarded here
|
5 ovpns
|
||||||
|
'';
|
||||||
|
networking.iproute2.enable = true;
|
||||||
|
|
||||||
|
|
||||||
|
# HURRICANE ELECTRIC CONFIG:
|
||||||
|
# networking.sits = {
|
||||||
|
# hurricane = {
|
||||||
|
# remote = "216.218.226.238";
|
||||||
|
# local = "192.168.0.5";
|
||||||
|
# # local = "10.0.0.5";
|
||||||
|
# # remote = "10.0.0.1";
|
||||||
|
# # local = "10.0.0.22";
|
||||||
|
# dev = "eth0";
|
||||||
|
# ttl = 255;
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
# networking.interfaces."hurricane".ipv6 = {
|
||||||
|
# addresses = [
|
||||||
|
# # mx.uninsane.org (publically routed /64)
|
||||||
|
# {
|
||||||
|
# address = "2001:470:b:465::1";
|
||||||
|
# prefixLength = 128;
|
||||||
|
# }
|
||||||
|
# # client addr
|
||||||
|
# # {
|
||||||
|
# # address = "2001:470:a:466::2";
|
||||||
|
# # prefixLength = 64;
|
||||||
|
# # }
|
||||||
|
# ];
|
||||||
|
# routes = [
|
||||||
|
# {
|
||||||
|
# address = "::";
|
||||||
|
# prefixLength = 0;
|
||||||
|
# # via = "2001:470:a:466::1";
|
||||||
|
# }
|
||||||
|
# ];
|
||||||
|
# };
|
||||||
|
|
||||||
|
# # after configuration, we want the hurricane device to look like this:
|
||||||
|
# # hurricane: flags=209<UP,POINTOPOINT,RUNNING,NOARP> mtu 1480
|
||||||
|
# # inet6 2001:470:a:450::2 prefixlen 64 scopeid 0x0<global>
|
||||||
|
# # inet6 fe80::c0a8:16 prefixlen 64 scopeid 0x20<link>
|
||||||
|
# # sit txqueuelen 1000 (IPv6-in-IPv4)
|
||||||
|
# # test with:
|
||||||
|
# # curl --interface hurricane http://[2607:f8b0:400a:80b::2004]
|
||||||
|
# # ping 2607:f8b0:400a:80b::2004
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
34
hosts/by-name/servo/services/calibre.nix
Normal file
34
hosts/by-name/servo/services/calibre.nix
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{ config, lib, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
cweb-cfg = config.services.calibre-web;
|
||||||
|
inherit (cweb-cfg) user group;
|
||||||
|
inherit (cweb-cfg.listen) ip port;
|
||||||
|
svc-dir = "/var/lib/${cweb-cfg.dataDir}";
|
||||||
|
in
|
||||||
|
# XXX: disabled because of runtime errors like:
|
||||||
|
# > File "/nix/store/c7jqvx980nlg9xhxi065cba61r2ain9y-calibre-web-0.6.19/lib/python3.10/site-packages/calibreweb/cps/db.py", line 926, in speaking_language
|
||||||
|
# > languages = self.session.query(Languages) \
|
||||||
|
# > AttributeError: 'NoneType' object has no attribute 'query'
|
||||||
|
lib.mkIf false
|
||||||
|
{
|
||||||
|
sane.persist.sys.byStore.plaintext = [
|
||||||
|
{ inherit user group; mode = "0700"; path = svc-dir; method = "bind"; }
|
||||||
|
];
|
||||||
|
|
||||||
|
services.calibre-web.enable = true;
|
||||||
|
services.calibre-web.listen.ip = "127.0.0.1";
|
||||||
|
# XXX: externally populate `${svc-dir}/metadata.db` (once) from
|
||||||
|
# <https://github.com/janeczku/calibre-web/blob/master/library/metadata.db>
|
||||||
|
# i don't know why you have to do this??
|
||||||
|
# services.calibre-web.options.calibreLibrary = svc-dir;
|
||||||
|
|
||||||
|
services.nginx.virtualHosts."calibre.uninsane.org" = {
|
||||||
|
forceSSL = true;
|
||||||
|
enableACME = true;
|
||||||
|
locations."/" = {
|
||||||
|
proxyPass = "http://${ip}:${builtins.toString port}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
sane.dns.zones."uninsane.org".inet.CNAME."calibre" = "native";
|
||||||
|
}
|
@@ -36,8 +36,7 @@
|
|||||||
# - rb = received bytes
|
# - rb = received bytes
|
||||||
# - sp = sent packets
|
# - sp = sent packets
|
||||||
# - sb = sent bytes
|
# - sb = sent bytes
|
||||||
|
{ lib, ... }:
|
||||||
{ config, lib, ... }:
|
|
||||||
let
|
let
|
||||||
# TURN port range (inclusive).
|
# TURN port range (inclusive).
|
||||||
# default coturn behavior is to use the upper quarter of all ports. i.e. 49152 - 65535.
|
# default coturn behavior is to use the upper quarter of all ports. i.e. 49152 - 65535.
|
||||||
@@ -56,7 +55,7 @@ in
|
|||||||
# protocol = [ "tcp" "udp" ];
|
# protocol = [ "tcp" "udp" ];
|
||||||
# # visibleTo.lan = true;
|
# # visibleTo.lan = true;
|
||||||
# # visibleTo.wan = true;
|
# # visibleTo.wan = true;
|
||||||
# visibleTo.ovpns = true; # forward traffic from the VPN to the root NS
|
# visibleTo.ovpn = true; # forward traffic from the VPN to the root NS
|
||||||
# description = "colin-stun-turn";
|
# description = "colin-stun-turn";
|
||||||
# };
|
# };
|
||||||
# "5349" = {
|
# "5349" = {
|
||||||
@@ -64,7 +63,7 @@ in
|
|||||||
# protocol = [ "tcp" ];
|
# protocol = [ "tcp" ];
|
||||||
# # visibleTo.lan = true;
|
# # visibleTo.lan = true;
|
||||||
# # visibleTo.wan = true;
|
# # visibleTo.wan = true;
|
||||||
# visibleTo.ovpns = true;
|
# visibleTo.ovpn = true;
|
||||||
# description = "colin-stun-turn-over-tls";
|
# description = "colin-stun-turn-over-tls";
|
||||||
# };
|
# };
|
||||||
# }
|
# }
|
||||||
@@ -77,7 +76,7 @@ in
|
|||||||
# protocol = [ "tcp" "udp" ];
|
# protocol = [ "tcp" "udp" ];
|
||||||
# # visibleTo.lan = true;
|
# # visibleTo.lan = true;
|
||||||
# # visibleTo.wan = true;
|
# # visibleTo.wan = true;
|
||||||
# visibleTo.ovpns = true;
|
# visibleTo.ovpn = true;
|
||||||
# description = "colin-turn-${builtins.toString count}-of-${builtins.toString numPorts}";
|
# description = "colin-turn-${builtins.toString count}-of-${builtins.toString numPorts}";
|
||||||
# };
|
# };
|
||||||
# })
|
# })
|
||||||
@@ -131,11 +130,11 @@ in
|
|||||||
"verbose"
|
"verbose"
|
||||||
# "Verbose" #< even MORE verbosity than "verbose" (it's TOO MUCH verbosity really)
|
# "Verbose" #< even MORE verbosity than "verbose" (it's TOO MUCH verbosity really)
|
||||||
"no-multicast-peers" # disables sending to IPv4 broadcast addresses (e.g. 224.0.0.0/3)
|
"no-multicast-peers" # disables sending to IPv4 broadcast addresses (e.g. 224.0.0.0/3)
|
||||||
# "listening-ip=${config.sane.netns.ovpns.hostVethIpv4}" "external-ip=${config.sane.netns.ovpns.netnsPubIpv4}" #< 2024/04/25: works, if running in root namespace
|
# "listening-ip=10.0.1.5" "external-ip=185.157.162.178" #< 2024/04/25: works, if running in root namespace
|
||||||
"listening-ip=${config.sane.netns.ovpns.netnsPubIpv4}" "external-ip=${config.sane.netns.ovpns.netnsPubIpv4}"
|
"listening-ip=185.157.162.178" "external-ip=185.157.162.178"
|
||||||
|
|
||||||
# old attempts:
|
# old attempts:
|
||||||
# "external-ip=${config.sane.netns.ovpns.netnsPubIpv4}/${config.sane.netns.ovpns.hostVethIpv4}"
|
# "external-ip=185.157.162.178/10.0.1.5"
|
||||||
# "listening-ip=10.78.79.51" # can be specified multiple times; omit for *
|
# "listening-ip=10.78.79.51" # can be specified multiple times; omit for *
|
||||||
# "external-ip=97.113.128.229/10.78.79.51"
|
# "external-ip=97.113.128.229/10.78.79.51"
|
||||||
# "external-ip=97.113.128.229"
|
# "external-ip=97.113.128.229"
|
||||||
|
@@ -16,16 +16,14 @@
|
|||||||
# - validate with `bitcoin-cli -netinfo`
|
# - validate with `bitcoin-cli -netinfo`
|
||||||
{ config, lib, pkgs, sane-lib, ... }:
|
{ config, lib, pkgs, sane-lib, ... }:
|
||||||
let
|
let
|
||||||
# bitcoind = config.sane.programs.bitcoind.packageUnwrapped;
|
|
||||||
bitcoind = pkgs.bitcoind;
|
|
||||||
# wrapper to run bitcoind with the tor onion address as externalip (computed at runtime)
|
# wrapper to run bitcoind with the tor onion address as externalip (computed at runtime)
|
||||||
_bitcoindWithExternalIp = pkgs.writeShellScriptBin "bitcoind" ''
|
_bitcoindWithExternalIp = with pkgs; writeShellScriptBin "bitcoind" ''
|
||||||
externalip="$(cat /var/lib/tor/onion/bitcoind/hostname)"
|
externalip="$(cat /var/lib/tor/onion/bitcoind/hostname)"
|
||||||
exec ${bitcoind}/bin/bitcoind "-externalip=$externalip" "$@"
|
exec ${bitcoind}/bin/bitcoind "-externalip=$externalip" "$@"
|
||||||
'';
|
'';
|
||||||
# the package i provide to services.bitcoind ends up on system PATH, and used by other tools like clightning.
|
# the package i provide to services.bitcoind ends up on system PATH, and used by other tools like clightning.
|
||||||
# therefore, even though services.bitcoind only needs `bitcoind` binary, provide all the other bitcoin-related binaries (notably `bitcoin-cli`) as well:
|
# therefore, even though services.bitcoind only needs `bitcoind` binary, provide all the other bitcoin-related binaries (notably `bitcoin-cli`) as well:
|
||||||
bitcoindWithExternalIp = pkgs.symlinkJoin {
|
bitcoindWithExternalIp = with pkgs; symlinkJoin {
|
||||||
name = "bitcoind-with-external-ip";
|
name = "bitcoind-with-external-ip";
|
||||||
paths = [ _bitcoindWithExternalIp bitcoind ];
|
paths = [ _bitcoindWithExternalIp bitcoind ];
|
||||||
};
|
};
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env nix-shell
|
#!/usr/bin/env nix-shell
|
||||||
#!nix-shell -i python3 -p pyln-client -p python3
|
#!nix-shell -i python3 -p "python3.withPackages (ps: [ ps.pyln-client ])"
|
||||||
|
|
||||||
"""
|
"""
|
||||||
clightning-sane: helper to perform common Lightning node admin operations:
|
clightning-sane: helper to perform common Lightning node admin operations:
|
@@ -116,10 +116,7 @@
|
|||||||
# - fee-per-satoshi=<ppm>
|
# - fee-per-satoshi=<ppm>
|
||||||
# - feature configs (i.e. experimental-xyz options)
|
# - feature configs (i.e. experimental-xyz options)
|
||||||
sane.services.clightning.extraConfig = ''
|
sane.services.clightning.extraConfig = ''
|
||||||
# log levels: "io", "debug", "info", "unusual", "broken"
|
log-level=debug:lightningd
|
||||||
log-level=info:lightningd
|
|
||||||
# log-level=debug:lightningd
|
|
||||||
|
|
||||||
# peerswap:
|
# peerswap:
|
||||||
# - config example: <https://github.com/fort-nix/nix-bitcoin/pull/462/files#diff-b357d832705b8ce8df1f41934d613f79adb77c4cd5cd9e9eb12a163fca3e16c6>
|
# - config example: <https://github.com/fort-nix/nix-bitcoin/pull/462/files#diff-b357d832705b8ce8df1f41934d613f79adb77c4cd5cd9e9eb12a163fca3e16c6>
|
||||||
# XXX: peerswap crashes clightning on launch. stacktrace is useless.
|
# XXX: peerswap crashes clightning on launch. stacktrace is useless.
|
||||||
@@ -135,5 +132,4 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
sane.programs.clightning.enableFor.user.colin = true; # for debugging/admin: `lightning-cli`
|
sane.programs.clightning.enableFor.user.colin = true; # for debugging/admin: `lightning-cli`
|
||||||
sane.programs.clightning.packageUnwrapped = config.sane.services.clightning.package;
|
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
{ ... }:
|
{ ... }:
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
|
./calibre.nix
|
||||||
./coturn.nix
|
./coturn.nix
|
||||||
./cryptocurrencies
|
./cryptocurrencies
|
||||||
./email
|
./email
|
||||||
@@ -25,7 +26,7 @@
|
|||||||
./postgres.nix
|
./postgres.nix
|
||||||
./prosody
|
./prosody
|
||||||
./slskd.nix
|
./slskd.nix
|
||||||
./transmission
|
./transmission.nix
|
||||||
./trust-dns.nix
|
./trust-dns.nix
|
||||||
./wikipedia.nix
|
./wikipedia.nix
|
||||||
];
|
];
|
||||||
|
@@ -51,54 +51,54 @@ lib.mkIf false
|
|||||||
{
|
{
|
||||||
"3478" = {
|
"3478" = {
|
||||||
protocol = [ "tcp" "udp" ];
|
protocol = [ "tcp" "udp" ];
|
||||||
visibleTo.doof = true;
|
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
|
visibleTo.wan = true;
|
||||||
description = "colin-xmpp-stun-turn";
|
description = "colin-xmpp-stun-turn";
|
||||||
};
|
};
|
||||||
"5222" = {
|
"5222" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
visibleTo.doof = true;
|
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
|
visibleTo.wan = true;
|
||||||
description = "colin-xmpp-client-to-server";
|
description = "colin-xmpp-client-to-server";
|
||||||
};
|
};
|
||||||
"5223" = {
|
"5223" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
visibleTo.doof = true;
|
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
|
visibleTo.wan = true;
|
||||||
description = "colin-xmpps-client-to-server"; # XMPP over TLS
|
description = "colin-xmpps-client-to-server"; # XMPP over TLS
|
||||||
};
|
};
|
||||||
"5269" = {
|
"5269" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
visibleTo.doof = true;
|
visibleTo.wan = true;
|
||||||
description = "colin-xmpp-server-to-server";
|
description = "colin-xmpp-server-to-server";
|
||||||
};
|
};
|
||||||
"5270" = {
|
"5270" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
visibleTo.doof = true;
|
visibleTo.wan = true;
|
||||||
description = "colin-xmpps-server-to-server"; # XMPP over TLS
|
description = "colin-xmpps-server-to-server"; # XMPP over TLS
|
||||||
};
|
};
|
||||||
"5280" = {
|
"5280" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
visibleTo.doof = true;
|
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
|
visibleTo.wan = true;
|
||||||
description = "colin-xmpp-bosh";
|
description = "colin-xmpp-bosh";
|
||||||
};
|
};
|
||||||
"5281" = {
|
"5281" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
visibleTo.doof = true;
|
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
|
visibleTo.wan = true;
|
||||||
description = "colin-xmpp-bosh-https";
|
description = "colin-xmpp-bosh-https";
|
||||||
};
|
};
|
||||||
"5349" = {
|
"5349" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
visibleTo.doof = true;
|
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
|
visibleTo.wan = true;
|
||||||
description = "colin-xmpp-stun-turn-over-tls";
|
description = "colin-xmpp-stun-turn-over-tls";
|
||||||
};
|
};
|
||||||
"5443" = {
|
"5443" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
visibleTo.doof = true;
|
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
|
visibleTo.wan = true;
|
||||||
description = "colin-xmpp-web-services"; # file uploads, websockets, admin
|
description = "colin-xmpp-web-services"; # file uploads, websockets, admin
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -109,8 +109,8 @@ lib.mkIf false
|
|||||||
numPorts = turnPortHigh - turnPortLow + 1;
|
numPorts = turnPortHigh - turnPortLow + 1;
|
||||||
in {
|
in {
|
||||||
protocol = [ "tcp" "udp" ];
|
protocol = [ "tcp" "udp" ];
|
||||||
visibleTo.doof = true;
|
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
|
visibleTo.wan = true;
|
||||||
description = "colin-xmpp-turn-${builtins.toString count}-of-${builtins.toString numPorts}";
|
description = "colin-xmpp-turn-${builtins.toString count}-of-${builtins.toString numPorts}";
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
|
@@ -8,14 +8,14 @@
|
|||||||
{
|
{
|
||||||
sane.ports.ports."143" = {
|
sane.ports.ports."143" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
visibleTo.doof = true;
|
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
|
visibleTo.wan = true;
|
||||||
description = "colin-imap-imap.uninsane.org";
|
description = "colin-imap-imap.uninsane.org";
|
||||||
};
|
};
|
||||||
sane.ports.ports."993" = {
|
sane.ports.ports."993" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
visibleTo.doof = true;
|
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
|
visibleTo.wan = true;
|
||||||
description = "colin-imaps-imap.uninsane.org";
|
description = "colin-imaps-imap.uninsane.org";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# postfix config options: <https://www.postfix.org/postconf.5.html>
|
# postfix config options: <https://www.postfix.org/postconf.5.html>
|
||||||
|
|
||||||
{ config, lib, pkgs, ... }:
|
{ lib, pkgs, ... }:
|
||||||
|
|
||||||
let
|
let
|
||||||
submissionOptions = {
|
submissionOptions = {
|
||||||
@@ -56,7 +56,8 @@ in
|
|||||||
|
|
||||||
sane.dns.zones."uninsane.org".inet = {
|
sane.dns.zones."uninsane.org".inet = {
|
||||||
MX."@" = "10 mx.uninsane.org.";
|
MX."@" = "10 mx.uninsane.org.";
|
||||||
A."mx" = "%AOVPNS%"; #< XXX: RFC's specify that the MX record CANNOT BE A CNAME. TODO: use "%AOVPNS%?
|
# XXX: RFC's specify that the MX record CANNOT BE A CNAME
|
||||||
|
A."mx" = "185.157.162.178";
|
||||||
|
|
||||||
# Sender Policy Framework:
|
# Sender Policy Framework:
|
||||||
# +mx => mail passes if it originated from the MX
|
# +mx => mail passes if it originated from the MX
|
||||||
|
@@ -12,10 +12,6 @@
|
|||||||
device = "/var/media";
|
device = "/var/media";
|
||||||
options = [ "rbind" ];
|
options = [ "rbind" ];
|
||||||
};
|
};
|
||||||
fileSystems."/var/export/pub" = {
|
|
||||||
device = "/var/www/sites/uninsane.org/share";
|
|
||||||
options = [ "rbind" ];
|
|
||||||
};
|
|
||||||
# fileSystems."/var/export/playground" = {
|
# fileSystems."/var/export/playground" = {
|
||||||
# device = config.fileSystems."/mnt/persist/ext".device;
|
# device = config.fileSystems."/mnt/persist/ext".device;
|
||||||
# fsType = "btrfs";
|
# fsType = "btrfs";
|
||||||
@@ -41,8 +37,7 @@
|
|||||||
wantedBy = [ "nfs.service" "sftpgo.service" ];
|
wantedBy = [ "nfs.service" "sftpgo.service" ];
|
||||||
file.text = ''
|
file.text = ''
|
||||||
- media/ read-only: Videos, Music, Books, etc
|
- media/ read-only: Videos, Music, Books, etc
|
||||||
- playground/ read-write: use it to share files with other users of this server, inaccessible from the www
|
- playground/ read-write: use it to share files with other users of this server
|
||||||
- pub/ read-only: content made to be shared with the www
|
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -9,10 +9,10 @@
|
|||||||
|
|
||||||
{ config, lib, pkgs, sane-lib, ... }:
|
{ config, lib, pkgs, sane-lib, ... }:
|
||||||
let
|
let
|
||||||
external_auth_hook = pkgs.static-nix-shell.mkPython3 {
|
external_auth_hook = pkgs.static-nix-shell.mkPython3Bin {
|
||||||
pname = "external_auth_hook";
|
pname = "external_auth_hook";
|
||||||
srcRoot = ./.;
|
srcRoot = ./.;
|
||||||
pkgs = [ "python3.pkgs.passlib" ];
|
pyPkgs = [ "passlib" ];
|
||||||
};
|
};
|
||||||
# Client initiates a FTP "control connection" on port 21.
|
# Client initiates a FTP "control connection" on port 21.
|
||||||
# - this handles the client -> server commands, and the server -> client status, but not the actual data
|
# - this handles the client -> server commands, and the server -> client status, but not the actual data
|
||||||
@@ -27,12 +27,13 @@ in
|
|||||||
"21" = {
|
"21" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
|
# visibleTo.wan = true;
|
||||||
description = "colin-FTP server";
|
description = "colin-FTP server";
|
||||||
};
|
};
|
||||||
"990" = {
|
"990" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
visibleTo.doof = true;
|
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
|
visibleTo.wan = true;
|
||||||
description = "colin-FTPS server";
|
description = "colin-FTPS server";
|
||||||
};
|
};
|
||||||
} // (sane-lib.mapToAttrs
|
} // (sane-lib.mapToAttrs
|
||||||
@@ -40,8 +41,8 @@ in
|
|||||||
name = builtins.toString port;
|
name = builtins.toString port;
|
||||||
value = {
|
value = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
visibleTo.doof = true;
|
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
|
visibleTo.wan = true;
|
||||||
description = "colin-FTP server data port range";
|
description = "colin-FTP server data port range";
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
@@ -100,13 +101,6 @@ in
|
|||||||
debug = true;
|
debug = true;
|
||||||
tls_mode = 2; # 2 = "implicit FTPS": client negotiates TLS before any FTP command.
|
tls_mode = 2; # 2 = "implicit FTPS": client negotiates TLS before any FTP command.
|
||||||
}
|
}
|
||||||
{
|
|
||||||
# binding this means any doof client can connect (TLS only)
|
|
||||||
address = config.sane.netns.doof.hostVethIpv4;
|
|
||||||
port = 990;
|
|
||||||
debug = true;
|
|
||||||
tls_mode = 2; # 2 = "implicit FTPS": client negotiates TLS before any FTP command.
|
|
||||||
}
|
|
||||||
];
|
];
|
||||||
|
|
||||||
# active mode is susceptible to "bounce attacks", without much benefit over passive mode
|
# active mode is susceptible to "bounce attacks", without much benefit over passive mode
|
||||||
@@ -123,7 +117,7 @@ in
|
|||||||
banner = ''
|
banner = ''
|
||||||
Welcome, friends, to Colin's FTP server! Also available via NFS on the same host, but LAN-only.
|
Welcome, friends, to Colin's FTP server! Also available via NFS on the same host, but LAN-only.
|
||||||
|
|
||||||
Read-only access (LAN clients see everything; WAN clients can only see /pub):
|
Read-only access (LAN-restricted):
|
||||||
Username: "anonymous"
|
Username: "anonymous"
|
||||||
Password: "anonymous"
|
Password: "anonymous"
|
||||||
|
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env nix-shell
|
#!/usr/bin/env nix-shell
|
||||||
#!nix-shell -i python3 -p python3 -p python3.pkgs.passlib
|
#!nix-shell -i python3 -p "python3.withPackages (ps: [ ps.passlib ])"
|
||||||
# vim: set filetype=python :
|
# vim: set filetype=python :
|
||||||
#
|
#
|
||||||
# available environment variables:
|
# available environment variables:
|
||||||
@@ -45,8 +45,6 @@ from hmac import compare_digest
|
|||||||
|
|
||||||
authFail = dict(username="")
|
authFail = dict(username="")
|
||||||
|
|
||||||
PERM_DENY = []
|
|
||||||
PERM_LIST = [ "list" ]
|
|
||||||
PERM_RO = [ "list", "download" ]
|
PERM_RO = [ "list", "download" ]
|
||||||
PERM_RW = [
|
PERM_RW = [
|
||||||
# read-only:
|
# read-only:
|
||||||
@@ -129,14 +127,12 @@ def getAuthResponse(ip: str, username: str, password: str) -> dict:
|
|||||||
return mkAuthOk(username, permissions = {
|
return mkAuthOk(username, permissions = {
|
||||||
"/": PERM_RW,
|
"/": PERM_RW,
|
||||||
"/playground": PERM_RW,
|
"/playground": PERM_RW,
|
||||||
"/pub": PERM_RO,
|
|
||||||
})
|
})
|
||||||
if isWireguard(ip):
|
if isWireguard(ip):
|
||||||
# allow any user from wireguard
|
# allow any user from wireguard
|
||||||
return mkAuthOk(username, permissions = {
|
return mkAuthOk(username, permissions = {
|
||||||
"/": PERM_RW,
|
"/": PERM_RW,
|
||||||
"/playground": PERM_RW,
|
"/playground": PERM_RW,
|
||||||
"/pub": PERM_RO,
|
|
||||||
})
|
})
|
||||||
if isLan(ip):
|
if isLan(ip):
|
||||||
if username == "anonymous":
|
if username == "anonymous":
|
||||||
@@ -144,19 +140,7 @@ def getAuthResponse(ip: str, username: str, password: str) -> dict:
|
|||||||
return mkAuthOk("anonymous", permissions = {
|
return mkAuthOk("anonymous", permissions = {
|
||||||
"/": PERM_RO,
|
"/": PERM_RO,
|
||||||
"/playground": PERM_RW,
|
"/playground": PERM_RW,
|
||||||
"/pub": PERM_RO,
|
|
||||||
})
|
})
|
||||||
if username == "anonymous":
|
|
||||||
# anonymous users from the www can have even more limited access.
|
|
||||||
# mostly because i need an easy way to test WAN connectivity :-)
|
|
||||||
return mkAuthOk("anonymous", permissions = {
|
|
||||||
# "/": PERM_DENY,
|
|
||||||
"/": PERM_LIST, #< REQUIRED, even for lftp to list a subdir
|
|
||||||
"/media": PERM_DENY,
|
|
||||||
"/playground": PERM_DENY,
|
|
||||||
"/pub": PERM_RO,
|
|
||||||
# "/README.md": PERM_RO, #< does not work
|
|
||||||
})
|
|
||||||
|
|
||||||
return authFail
|
return authFail
|
||||||
|
|
||||||
|
@@ -10,7 +10,6 @@
|
|||||||
# ```
|
# ```
|
||||||
|
|
||||||
{ config, lib, pkgs, sane-lib, ... }:
|
{ config, lib, pkgs, sane-lib, ... }:
|
||||||
lib.mkIf false #< 2024/07/04: i haven't actively used this for months
|
|
||||||
{
|
{
|
||||||
sops.secrets."freshrss_passwd" = {
|
sops.secrets."freshrss_passwd" = {
|
||||||
owner = config.users.users.freshrss.name;
|
owner = config.users.users.freshrss.name;
|
||||||
|
@@ -38,34 +38,28 @@
|
|||||||
ROOT_URL = "https://git.uninsane.org/";
|
ROOT_URL = "https://git.uninsane.org/";
|
||||||
};
|
};
|
||||||
service = {
|
service = {
|
||||||
# timeout for email approval. 5760 = 4 days. 10080 = 7 days
|
# timeout for email approval. 5760 = 4 days
|
||||||
ACTIVE_CODE_LIVE_MINUTES = 10080;
|
ACTIVE_CODE_LIVE_MINUTES = 5760;
|
||||||
# REGISTER_EMAIL_CONFIRM = false;
|
# REGISTER_EMAIL_CONFIRM = false;
|
||||||
# REGISTER_MANUAL_CONFIRM = true;
|
# REGISTER_MANUAL_CONFIRM = true;
|
||||||
REGISTER_EMAIL_CONFIRM = true;
|
REGISTER_EMAIL_CONFIRM = true;
|
||||||
# not sure what this notifies *on*...
|
# not sure what this notified 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";
|
||||||
};
|
};
|
||||||
session = {
|
session.COOKIE_SECURE = true;
|
||||||
COOKIE_SECURE = true;
|
|
||||||
# keep me logged in for 30 days
|
|
||||||
SESSION_LIFE_TIME = 60 * 60 * 24 * 30;
|
|
||||||
};
|
|
||||||
repository = {
|
repository = {
|
||||||
DEFAULT_BRANCH = "master";
|
DEFAULT_BRANCH = "master";
|
||||||
ENABLE_PUSH_CREATE_USER = true;
|
|
||||||
ENABLE_PUSH_CREATE_ORG = true;
|
|
||||||
};
|
};
|
||||||
other = {
|
other = {
|
||||||
SHOW_FOOTER_TEMPLATE_LOAD_TIME = false;
|
SHOW_FOOTER_TEMPLATE_LOAD_TIME = false;
|
||||||
};
|
};
|
||||||
ui = {
|
ui = {
|
||||||
# options: "gitea-auto" (adapt to system theme), "gitea-dark", "gitea-light"
|
# options: "auto", "gitea", "arc-green"
|
||||||
# DEFAULT_THEME = "gitea-auto";
|
DEFAULT_THEME = "arc-green";
|
||||||
# cache frontend assets if true
|
# cache frontend assets if true
|
||||||
# USE_SERVICE_WORKER = true;
|
# USE_SERVICE_WORKER = true;
|
||||||
};
|
};
|
||||||
@@ -74,10 +68,9 @@
|
|||||||
# alternative is to use nixos-level config:
|
# alternative is to use nixos-level config:
|
||||||
# services.gitea.mailerPasswordFile = ...
|
# services.gitea.mailerPasswordFile = ...
|
||||||
ENABLED = true;
|
ENABLED = true;
|
||||||
|
MAILER_TYPE = "sendmail";
|
||||||
FROM = "notify.git@uninsane.org";
|
FROM = "notify.git@uninsane.org";
|
||||||
PROTOCOL = "sendmail";
|
|
||||||
SENDMAIL_PATH = "${pkgs.postfix}/bin/sendmail";
|
SENDMAIL_PATH = "${pkgs.postfix}/bin/sendmail";
|
||||||
SENDMAIL_ARGS = "--"; # most "sendmail" programs take options, "--" will prevent an email address being interpreted as an option.
|
|
||||||
};
|
};
|
||||||
time = {
|
time = {
|
||||||
# options: ANSIC, UnixDate, RubyDate, RFC822, RFC822Z, RFC850, RFC1123, RFC1123Z, RFC3339, RFC3339Nano, Kitchen, Stamp, StampMilli, StampMicro, StampNano
|
# options: ANSIC, UnixDate, RubyDate, RFC822, RFC822Z, RFC850, RFC1123, RFC1123Z, RFC3339, RFC3339Nano, Kitchen, Stamp, StampMilli, StampMicro, StampNano
|
||||||
@@ -134,7 +127,7 @@
|
|||||||
sane.ports.ports."22" = {
|
sane.ports.ports."22" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
visibleTo.doof = true;
|
visibleTo.wan = true;
|
||||||
description = "colin-git@git.uninsane.org";
|
description = "colin-git@git.uninsane.org";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
{ lib, pkgs, ... }:
|
||||||
|
|
||||||
|
lib.mkIf false #< TODO: re-enable once confident of sandboxing
|
||||||
{
|
{
|
||||||
sane.persist.sys.byStore.plaintext = [
|
sane.persist.sys.byStore.plaintext = [
|
||||||
# TODO: mode? we only need this to save Indexer creds ==> migrate to config?
|
# TODO: mode? we only need this to save Indexer creds ==> migrate to config?
|
||||||
@@ -12,7 +13,7 @@
|
|||||||
systemd.services.jackett.serviceConfig = {
|
systemd.services.jackett.serviceConfig = {
|
||||||
# run this behind the OVPN static VPN
|
# run this behind the OVPN static VPN
|
||||||
NetworkNamespacePath = "/run/netns/ovpns";
|
NetworkNamespacePath = "/run/netns/ovpns";
|
||||||
ExecStartPre = [ "${lib.getExe pkgs.sane-scripts.ip-check} --no-upnp --expect ${config.sane.netns.ovpns.netnsPubIpv4}" ]; # abort if public IP is not as expected
|
ExecStartPre = [ "${lib.getExe pkgs.sane-scripts.ip-check} --no-upnp --expect 185.157.162.178" ]; # abort if public IP is not as expected
|
||||||
|
|
||||||
# patch jackett to listen on the public interfaces
|
# patch jackett to listen on the public interfaces
|
||||||
# ExecStart = lib.mkForce "${pkgs.jackett}/bin/Jackett --NoUpdates --DataFolder /var/lib/jackett/.config/Jackett --ListenPublic";
|
# ExecStart = lib.mkForce "${pkgs.jackett}/bin/Jackett --NoUpdates --DataFolder /var/lib/jackett/.config/Jackett --ListenPublic";
|
||||||
@@ -24,7 +25,8 @@
|
|||||||
enableACME = true;
|
enableACME = true;
|
||||||
# inherit kTLS;
|
# inherit kTLS;
|
||||||
locations."/" = {
|
locations."/" = {
|
||||||
proxyPass = "http://${config.sane.netns.ovpns.netnsVethIpv4}:9117";
|
# proxyPass = "http://ovpns.uninsane.org:9117";
|
||||||
|
proxyPass = "http://10.0.1.6:9117";
|
||||||
recommendedProxySettings = true;
|
recommendedProxySettings = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@@ -46,7 +46,6 @@ in {
|
|||||||
};
|
};
|
||||||
systemd.services.lemmy.environment = {
|
systemd.services.lemmy.environment = {
|
||||||
RUST_BACKTRACE = "full";
|
RUST_BACKTRACE = "full";
|
||||||
RUST_LOG = "warn";
|
|
||||||
# RUST_LOG = "debug";
|
# RUST_LOG = "debug";
|
||||||
# RUST_LOG = "trace";
|
# RUST_LOG = "trace";
|
||||||
# upstream defaults LEMMY_DATABASE_URL = "postgres:///lemmy?host=/run/postgresql";
|
# upstream defaults LEMMY_DATABASE_URL = "postgres:///lemmy?host=/run/postgresql";
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# docs: <https://nixos.wiki/wiki/Matrix>
|
# docs: <https://nixos.wiki/wiki/Matrix>
|
||||||
# docs: <https://nixos.org/manual/nixos/stable/index.html#module-services-matrix-synapse>
|
# docs: <https://nixos.org/manual/nixos/stable/index.html#module-services-matrix-synapse>
|
||||||
# example config: <https://github.com/element-hq/synapse/blob/develop/docs/sample_config.yaml>
|
# example config: <https://github.com/matrix-org/synapse/blob/develop/docs/sample_config.yaml>
|
||||||
#
|
#
|
||||||
# ENABLING PUSH NOTIFICATIONS (with UnifiedPush/ntfy):
|
# ENABLING PUSH NOTIFICATIONS (with UnifiedPush/ntfy):
|
||||||
# - Matrix "pushers" API spec: <https://spec.matrix.org/latest/client-server-api/#post_matrixclientv3pushersset>
|
# - Matrix "pushers" API spec: <https://spec.matrix.org/latest/client-server-api/#post_matrixclientv3pushersset>
|
||||||
@@ -24,8 +24,10 @@
|
|||||||
{ user = "matrix-synapse"; group = "matrix-synapse"; path = "/var/lib/matrix-synapse"; method = "bind"; }
|
{ user = "matrix-synapse"; group = "matrix-synapse"; path = "/var/lib/matrix-synapse"; method = "bind"; }
|
||||||
];
|
];
|
||||||
services.matrix-synapse.enable = true;
|
services.matrix-synapse.enable = true;
|
||||||
services.matrix-synapse.log.root.level = "WARNING"; # accepts "DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL" (?)
|
|
||||||
services.matrix-synapse.settings = {
|
services.matrix-synapse.settings = {
|
||||||
|
# this changes the default log level from INFO to WARN.
|
||||||
|
# maybe there's an easier way?
|
||||||
|
log_config = ./synapse-log_level.yaml;
|
||||||
server_name = "uninsane.org";
|
server_name = "uninsane.org";
|
||||||
|
|
||||||
# services.matrix-synapse.enable_registration_captcha = true;
|
# services.matrix-synapse.enable_registration_captcha = true;
|
||||||
|
@@ -1,13 +1,15 @@
|
|||||||
# config docs:
|
# config docs:
|
||||||
# - <https://github.com/matrix-org/matrix-appservice-irc/blob/develop/config.sample.yaml>
|
# - <https://github.com/matrix-org/matrix-appservice-irc/blob/develop/config.sample.yaml>
|
||||||
|
# probably want to remove that.
|
||||||
{ config, lib, ... }:
|
{ config, lib, ... }:
|
||||||
|
|
||||||
let
|
let
|
||||||
ircServer = { name, additionalAddresses ? [], ssl ? true, sasl ? true, port ? if ssl then 6697 else 6667 }: let
|
ircServer = { name, additionalAddresses ? [], sasl ? true, port ? 6697 }: let
|
||||||
lowerName = lib.toLower name;
|
lowerName = lib.toLower name;
|
||||||
in {
|
in {
|
||||||
# XXX sasl: appservice doesn't support NickServ identification (only SASL, or PASS if sasl = false)
|
# XXX sasl: appservice doesn't support NickServ identification (only SASL, or PASS if sasl = false)
|
||||||
inherit additionalAddresses name port sasl ssl;
|
inherit name additionalAddresses sasl port;
|
||||||
|
ssl = true;
|
||||||
botConfig = {
|
botConfig = {
|
||||||
# bot has no presence in IRC channel; only real Matrix users
|
# bot has no presence in IRC channel; only real Matrix users
|
||||||
enabled = false;
|
enabled = false;
|
||||||
@@ -127,7 +129,6 @@ in
|
|||||||
};
|
};
|
||||||
|
|
||||||
ircService = {
|
ircService = {
|
||||||
logging.level = "warn"; # "error", "warn", "info", "debug"
|
|
||||||
servers = {
|
servers = {
|
||||||
"irc.esper.net" = ircServer {
|
"irc.esper.net" = ircServer {
|
||||||
name = "esper";
|
name = "esper";
|
||||||
@@ -155,10 +156,6 @@ in
|
|||||||
# - #sxmo-offtopic
|
# - #sxmo-offtopic
|
||||||
};
|
};
|
||||||
"irc.rizon.net" = ircServer { name = "Rizon"; };
|
"irc.rizon.net" = ircServer { name = "Rizon"; };
|
||||||
"wigle.net" = ircServer {
|
|
||||||
name = "WiGLE";
|
|
||||||
ssl = false;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
27
hosts/by-name/servo/services/matrix/synapse-log_level.yaml
Normal file
27
hosts/by-name/servo/services/matrix/synapse-log_level.yaml
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
version: 1
|
||||||
|
|
||||||
|
# In systemd's journal, loglevel is implicitly stored, so let's omit it
|
||||||
|
# from the message text.
|
||||||
|
formatters:
|
||||||
|
journal_fmt:
|
||||||
|
format: '%(name)s: [%(request)s] %(message)s'
|
||||||
|
|
||||||
|
filters:
|
||||||
|
context:
|
||||||
|
(): synapse.util.logcontext.LoggingContextFilter
|
||||||
|
request: ""
|
||||||
|
|
||||||
|
handlers:
|
||||||
|
journal:
|
||||||
|
class: systemd.journal.JournalHandler
|
||||||
|
formatter: journal_fmt
|
||||||
|
filters: [context]
|
||||||
|
SYSLOG_IDENTIFIER: synapse
|
||||||
|
|
||||||
|
# default log level: INFO
|
||||||
|
root:
|
||||||
|
level: WARN
|
||||||
|
handlers: [journal]
|
||||||
|
|
||||||
|
disable_existing_loggers: False
|
||||||
|
|
@@ -17,14 +17,14 @@ in
|
|||||||
sane.ports.ports."80" = {
|
sane.ports.ports."80" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
visibleTo.ovpns = true; # so that letsencrypt can procure a cert for the mx record
|
visibleTo.wan = true;
|
||||||
visibleTo.doof = true;
|
visibleTo.ovpn = true; # so that letsencrypt can procure a cert for the mx record
|
||||||
description = "colin-http-uninsane.org";
|
description = "colin-http-uninsane.org";
|
||||||
};
|
};
|
||||||
sane.ports.ports."443" = {
|
sane.ports.ports."443" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
visibleTo.doof = true;
|
visibleTo.wan = true;
|
||||||
description = "colin-https-uninsane.org";
|
description = "colin-https-uninsane.org";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -86,7 +86,7 @@ in
|
|||||||
sane.ports.ports."${builtins.toString altPort}" = {
|
sane.ports.ports."${builtins.toString altPort}" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
visibleTo.doof = true;
|
visibleTo.wan = true;
|
||||||
description = "colin-ntfy.uninsane.org";
|
description = "colin-ntfy.uninsane.org";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env nix-shell
|
#!/usr/bin/env nix-shell
|
||||||
#!nix-shell -i python3 -p ntfy-sh -p python3
|
#!nix-shell -i python3 -p "python3.withPackages (ps: [ ])" -p ntfy-sh
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import logging
|
import logging
|
||||||
|
@@ -47,7 +47,7 @@ in
|
|||||||
};
|
};
|
||||||
sane.ntfy-waiter.package = mkOption {
|
sane.ntfy-waiter.package = mkOption {
|
||||||
type = types.package;
|
type = types.package;
|
||||||
default = pkgs.static-nix-shell.mkPython3 {
|
default = pkgs.static-nix-shell.mkPython3Bin {
|
||||||
pname = "ntfy-waiter";
|
pname = "ntfy-waiter";
|
||||||
srcRoot = ./.;
|
srcRoot = ./.;
|
||||||
pkgs = [ "ntfy-sh" ];
|
pkgs = [ "ntfy-sh" ];
|
||||||
@@ -62,8 +62,8 @@ in
|
|||||||
sane.ports.ports = lib.mkMerge (lib.forEach portRange (port: {
|
sane.ports.ports = lib.mkMerge (lib.forEach portRange (port: {
|
||||||
"${builtins.toString port}" = {
|
"${builtins.toString port}" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
visibleTo.doof = true;
|
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
|
visibleTo.wan = true;
|
||||||
description = "colin-notification-waiter-${builtins.toString (port - portLow + 1)}-of-${builtins.toString numPorts}";
|
description = "colin-notification-waiter-${builtins.toString (port - portLow + 1)}-of-${builtins.toString numPorts}";
|
||||||
};
|
};
|
||||||
}));
|
}));
|
||||||
|
@@ -61,42 +61,42 @@ in
|
|||||||
];
|
];
|
||||||
sane.ports.ports."5000" = {
|
sane.ports.ports."5000" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
visibleTo.doof = true;
|
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
|
visibleTo.wan = true;
|
||||||
description = "colin-xmpp-prosody-fileshare-proxy65";
|
description = "colin-xmpp-prosody-fileshare-proxy65";
|
||||||
};
|
};
|
||||||
sane.ports.ports."5222" = {
|
sane.ports.ports."5222" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
visibleTo.doof = true;
|
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
|
visibleTo.wan = true;
|
||||||
description = "colin-xmpp-client-to-server";
|
description = "colin-xmpp-client-to-server";
|
||||||
};
|
};
|
||||||
sane.ports.ports."5223" = {
|
sane.ports.ports."5223" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
visibleTo.doof = true;
|
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
|
visibleTo.wan = true;
|
||||||
description = "colin-xmpps-client-to-server"; # XMPP over TLS
|
description = "colin-xmpps-client-to-server"; # XMPP over TLS
|
||||||
};
|
};
|
||||||
sane.ports.ports."5269" = {
|
sane.ports.ports."5269" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
visibleTo.doof = true;
|
visibleTo.wan = true;
|
||||||
description = "colin-xmpp-server-to-server";
|
description = "colin-xmpp-server-to-server";
|
||||||
};
|
};
|
||||||
sane.ports.ports."5270" = {
|
sane.ports.ports."5270" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
visibleTo.doof = true;
|
visibleTo.wan = true;
|
||||||
description = "colin-xmpps-server-to-server"; # XMPP over TLS
|
description = "colin-xmpps-server-to-server"; # XMPP over TLS
|
||||||
};
|
};
|
||||||
sane.ports.ports."5280" = {
|
sane.ports.ports."5280" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
visibleTo.doof = true;
|
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
|
visibleTo.wan = true;
|
||||||
description = "colin-xmpp-bosh";
|
description = "colin-xmpp-bosh";
|
||||||
};
|
};
|
||||||
sane.ports.ports."5281" = {
|
sane.ports.ports."5281" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
visibleTo.doof = true;
|
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
|
visibleTo.wan = true;
|
||||||
description = "colin-xmpp-prosody-https"; # necessary?
|
description = "colin-xmpp-prosody-https"; # necessary?
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -22,7 +22,8 @@
|
|||||||
|
|
||||||
sane.ports.ports."50300" = {
|
sane.ports.ports."50300" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
# visibleTo.ovpns = true; #< not needed: it runs in the ovpns namespace
|
# not visible to WAN: i run this in a separate netns
|
||||||
|
visibleTo.ovpn = true;
|
||||||
description = "colin-soulseek";
|
description = "colin-soulseek";
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -32,7 +33,7 @@
|
|||||||
forceSSL = true;
|
forceSSL = true;
|
||||||
enableACME = true;
|
enableACME = true;
|
||||||
locations."/" = {
|
locations."/" = {
|
||||||
proxyPass = "http://${config.sane.netns.ovpns.netnsVethIpv4}:5030";
|
proxyPass = "http://10.0.1.6:5030";
|
||||||
proxyWebsockets = true;
|
proxyWebsockets = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -71,7 +72,7 @@
|
|||||||
systemd.services.slskd.serviceConfig = {
|
systemd.services.slskd.serviceConfig = {
|
||||||
# run this behind the OVPN static VPN
|
# run this behind the OVPN static VPN
|
||||||
NetworkNamespacePath = "/run/netns/ovpns";
|
NetworkNamespacePath = "/run/netns/ovpns";
|
||||||
ExecStartPre = [ "${lib.getExe pkgs.sane-scripts.ip-check} --no-upnp --expect ${config.sane.netns.ovpns.netnsPubIpv4}" ]; # abort if public IP is not as expected
|
ExecStartPre = [ "${lib.getExe pkgs.sane-scripts.ip-check} --no-upnp --expect 185.157.162.178" ]; # abort if public IP is not as expected
|
||||||
|
|
||||||
Restart = lib.mkForce "always"; # exits "success" when it fails to connect to soulseek server
|
Restart = lib.mkForce "always"; # exits "success" when it fails to connect to soulseek server
|
||||||
RestartSec = "60s";
|
RestartSec = "60s";
|
||||||
|
@@ -22,19 +22,67 @@ let
|
|||||||
--replace-fail 'set(TR_USER_AGENT_PREFIX "''${TR_SEMVER}")' 'set(TR_USER_AGENT_PREFIX "3.00")'
|
--replace-fail 'set(TR_USER_AGENT_PREFIX "''${TR_SEMVER}")' 'set(TR_USER_AGENT_PREFIX "3.00")'
|
||||||
'';
|
'';
|
||||||
});
|
});
|
||||||
download-dir = "/var/media/torrents"; #< keep in sync with consts embedded in `torrent-done`
|
download-dir = "/var/media/torrents";
|
||||||
torrent-done = pkgs.static-nix-shell.mkBash {
|
torrent-done = pkgs.writeShellApplication {
|
||||||
pname = "torrent-done";
|
name = "torrent-done";
|
||||||
srcRoot = ./.;
|
runtimeInputs = with pkgs; [
|
||||||
pkgs = [
|
acl
|
||||||
"acl"
|
coreutils
|
||||||
"coreutils"
|
findutils
|
||||||
"findutils"
|
rsync
|
||||||
"rsync"
|
util-linux
|
||||||
"util-linux"
|
|
||||||
];
|
];
|
||||||
|
text = ''
|
||||||
|
destructive() {
|
||||||
|
if [ -n "''${TR_DRY_RUN-}" ]; then
|
||||||
|
echo "$*"
|
||||||
|
else
|
||||||
|
"$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
if [[ "$TR_TORRENT_DIR" =~ ^.*freeleech.*$ ]]; then
|
||||||
|
# freeleech torrents have no place in my permanent library
|
||||||
|
echo "freeleech: nothing to do"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
if ! [[ "$TR_TORRENT_DIR" =~ ^${download-dir}/.*$ ]]; then
|
||||||
|
echo "unexpected torrent dir, aborting: $TR_TORRENT_DIR"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
REL_DIR="''${TR_TORRENT_DIR#${download-dir}/}"
|
||||||
|
MEDIA_DIR="/var/media/$REL_DIR"
|
||||||
|
|
||||||
|
destructive mkdir -p "$(dirname "$MEDIA_DIR")"
|
||||||
|
destructive rsync -arv "$TR_TORRENT_DIR/" "$MEDIA_DIR/"
|
||||||
|
# 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 chmod g+rw,a+rx {} \;
|
||||||
|
|
||||||
|
# if there's a single directory inside the media dir, then inline that
|
||||||
|
subdirs=("$MEDIA_DIR"/*)
|
||||||
|
if [ ''${#subdirs} -eq 1 ]; then
|
||||||
|
dirname="''${subdirs[0]}"
|
||||||
|
if [ -d "$dirname" ]; then
|
||||||
|
mv "$dirname"/* "$MEDIA_DIR/" && rmdir "$dirname"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# remove noisy files:
|
||||||
|
find "$MEDIA_DIR/" -type f \(\
|
||||||
|
-iname 'www.YTS.*.jpg' \
|
||||||
|
-o -iname 'WWW.YIFY*.COM.jpg' \
|
||||||
|
-o -iname 'YIFY*.com.txt' \
|
||||||
|
-o -iname 'YTS*.com.txt' \
|
||||||
|
\) -exec rm {} \;
|
||||||
|
|
||||||
|
# dedupe the whole media library.
|
||||||
|
# yeah, a bit excessive: move this to a cron job if that's problematic.
|
||||||
|
destructive hardlink /var/media --reflink=always --ignore-time --verbose
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
|
lib.mkIf false #< TODO: re-enable once confident of sandboxing
|
||||||
{
|
{
|
||||||
sane.persist.sys.byStore.plaintext = [
|
sane.persist.sys.byStore.plaintext = [
|
||||||
# TODO: mode? we need this specifically for the stats tracking in .config/
|
# TODO: mode? we need this specifically for the stats tracking in .config/
|
||||||
@@ -58,8 +106,8 @@ in
|
|||||||
# DOCUMENTATION/options list: <https://github.com/transmission/transmission/blob/main/docs/Editing-Configuration-Files.md#options>
|
# DOCUMENTATION/options list: <https://github.com/transmission/transmission/blob/main/docs/Editing-Configuration-Files.md#options>
|
||||||
|
|
||||||
# message-level = 3; #< enable for debug logging. 0-3, default is 2.
|
# message-level = 3; #< enable for debug logging. 0-3, default is 2.
|
||||||
# ovpns.netnsVethIpv4 => allow rpc only from the root servo ns. it'll tunnel things to the net, if need be.
|
# 10.0.1.6 => allow rpc only from the root servo ns. it'll tunnel things to the net, if need be.
|
||||||
rpc-bind-address = config.sane.netns.ovpns.netnsVethIpv4;
|
rpc-bind-address = "10.0.1.6";
|
||||||
#rpc-host-whitelist = "bt.uninsane.org";
|
#rpc-host-whitelist = "bt.uninsane.org";
|
||||||
#rpc-whitelist = "*.*.*.*";
|
#rpc-whitelist = "*.*.*.*";
|
||||||
rpc-authentication-required = true;
|
rpc-authentication-required = true;
|
||||||
@@ -70,7 +118,7 @@ in
|
|||||||
rpc-whitelist-enabled = false;
|
rpc-whitelist-enabled = false;
|
||||||
|
|
||||||
# force behind ovpns in case the NetworkNamespace fails somehow
|
# force behind ovpns in case the NetworkNamespace fails somehow
|
||||||
bind-address-ipv4 = config.sane.netns.ovpns.netnsPubIpv4;
|
bind-address-ipv4 = "185.157.162.178";
|
||||||
port-forwarding-enabled = false;
|
port-forwarding-enabled = false;
|
||||||
|
|
||||||
# hopefully, make the downloads world-readable
|
# hopefully, make the downloads world-readable
|
||||||
@@ -112,7 +160,7 @@ in
|
|||||||
systemd.services.transmission.serviceConfig = {
|
systemd.services.transmission.serviceConfig = {
|
||||||
# run this behind the OVPN static VPN
|
# run this behind the OVPN static VPN
|
||||||
NetworkNamespacePath = "/run/netns/ovpns";
|
NetworkNamespacePath = "/run/netns/ovpns";
|
||||||
ExecStartPre = [ "${lib.getExe pkgs.sane-scripts.ip-check} --no-upnp --expect ${config.sane.netns.ovpns.netnsPubIpv4}" ]; # abort if public IP is not as expected
|
ExecStartPre = [ "${lib.getExe pkgs.sane-scripts.ip-check} --no-upnp --expect 185.157.162.178" ]; # abort if public IP is not as expected
|
||||||
|
|
||||||
Restart = "on-failure";
|
Restart = "on-failure";
|
||||||
RestartSec = "30s";
|
RestartSec = "30s";
|
||||||
@@ -142,14 +190,14 @@ in
|
|||||||
# inherit kTLS;
|
# inherit kTLS;
|
||||||
locations."/" = {
|
locations."/" = {
|
||||||
# proxyPass = "http://ovpns.uninsane.org:9091";
|
# proxyPass = "http://ovpns.uninsane.org:9091";
|
||||||
proxyPass = "http://${config.sane.netns.ovpns.netnsVethIpv4}:9091";
|
proxyPass = "http://10.0.1.6:9091";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
sane.dns.zones."uninsane.org".inet.CNAME."bt" = "native";
|
sane.dns.zones."uninsane.org".inet.CNAME."bt" = "native";
|
||||||
sane.ports.ports."51413" = {
|
sane.ports.ports."51413" = {
|
||||||
protocol = [ "tcp" "udp" ];
|
protocol = [ "tcp" "udp" ];
|
||||||
# visibleTo.ovpns = true; #< not needed: it runs in the ovpns namespace
|
visibleTo.ovpn = true;
|
||||||
description = "colin-bittorrent";
|
description = "colin-bittorrent";
|
||||||
};
|
};
|
||||||
}
|
}
|
@@ -1,76 +0,0 @@
|
|||||||
#!/usr/bin/env nix-shell
|
|
||||||
#!nix-shell -i bash -p acl -p bash -p coreutils -p findutils -p rsync -p util-linux
|
|
||||||
|
|
||||||
# transmission invokes this with no args, and the following env vars:
|
|
||||||
# - TR_TORRENT_DIR: full path to the folder i told transmission to download it to.
|
|
||||||
# e.g. /var/media/torrents/Videos/Film/Jason.Bourne-2016
|
|
||||||
# optionally:
|
|
||||||
# - TR_DRY_RUN=1
|
|
||||||
# - TR_DEBUG=1
|
|
||||||
# - TR_NO_HARDLINK=1
|
|
||||||
|
|
||||||
DOWNLOAD_DIR=/var/media/torrents
|
|
||||||
|
|
||||||
destructive() {
|
|
||||||
if [ -n "${TR_DRY_RUN-}" ]; then
|
|
||||||
echo "[dry-run] $*"
|
|
||||||
else
|
|
||||||
debug "$@"
|
|
||||||
"$@"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
debug() {
|
|
||||||
if [ -n "${TR_DEBUG-}" ]; then
|
|
||||||
echo "$@"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
echo "TR_TORRENT_DIR=$TR_TORRENT_DIR torrent-done $*"
|
|
||||||
|
|
||||||
if [[ "$TR_TORRENT_DIR" =~ ^.*freeleech.*$ ]]; then
|
|
||||||
# freeleech torrents have no place in my permanent library
|
|
||||||
echo "freeleech: nothing to do"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
if ! [[ "$TR_TORRENT_DIR" =~ ^$DOWNLOAD_DIR/.*$ ]]; then
|
|
||||||
echo "unexpected torrent dir, aborting: $TR_TORRENT_DIR"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
REL_DIR="${TR_TORRENT_DIR#$DOWNLOAD_DIR/}"
|
|
||||||
MEDIA_DIR="/var/media/$REL_DIR"
|
|
||||||
|
|
||||||
destructive mkdir -p "$(dirname "$MEDIA_DIR")"
|
|
||||||
destructive rsync -arv "$TR_TORRENT_DIR/" "$MEDIA_DIR/"
|
|
||||||
# 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 chmod g+rw,a+rx {} \;
|
|
||||||
|
|
||||||
# if there's a single directory inside the media dir, then inline that
|
|
||||||
subdirs=("$MEDIA_DIR"/*)
|
|
||||||
debug "top-level items in torrent dir:" "${subdirs[@]}"
|
|
||||||
if [ ${#subdirs[@]} -eq 1 ]; then
|
|
||||||
dirname="${subdirs[0]}"
|
|
||||||
debug "exactly one top-level item, checking if directory: $dirname"
|
|
||||||
if [ -d "$dirname" ]; then
|
|
||||||
destructive mv "$dirname"/* "$MEDIA_DIR/" && destructive rmdir "$dirname"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# remove noisy files:
|
|
||||||
destructive find "$MEDIA_DIR/" -type f \(\
|
|
||||||
-iname '.*downloaded.?from.*' \
|
|
||||||
-o -iname 'source.txt' \
|
|
||||||
-o -iname 'upcoming.?releases.*' \
|
|
||||||
-o -iname 'www.YTS.*.jpg' \
|
|
||||||
-o -iname 'WWW.YIFY*.COM.jpg' \
|
|
||||||
-o -iname 'YIFY*.com.txt' \
|
|
||||||
-o -iname 'YTS*.com.txt' \
|
|
||||||
\) -exec rm {} \;
|
|
||||||
|
|
||||||
if ! [ -n "${TR_NO_HARDLINK}" ]; then
|
|
||||||
# dedupe the whole media library.
|
|
||||||
# yeah, a bit excessive: move this to a cron job if that's problematic
|
|
||||||
# or make it run with only 1/N probability, etc.
|
|
||||||
destructive hardlink /var/media --reflink=always --ignore-time --verbose
|
|
||||||
fi
|
|
@@ -4,14 +4,14 @@
|
|||||||
let
|
let
|
||||||
dyn-dns = config.sane.services.dyn-dns;
|
dyn-dns = config.sane.services.dyn-dns;
|
||||||
nativeAddrs = lib.mapAttrs (_name: builtins.head) config.sane.dns.zones."uninsane.org".inet.A;
|
nativeAddrs = lib.mapAttrs (_name: builtins.head) config.sane.dns.zones."uninsane.org".inet.A;
|
||||||
|
bindOvpn = "10.0.1.5";
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
sane.ports.ports."53" = {
|
sane.ports.ports."53" = {
|
||||||
protocol = [ "udp" "tcp" ];
|
protocol = [ "udp" "tcp" ];
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
# visibleTo.wan = true;
|
visibleTo.wan = true;
|
||||||
visibleTo.ovpns = true;
|
visibleTo.ovpn = true;
|
||||||
visibleTo.doof = true;
|
|
||||||
description = "colin-dns-hosting";
|
description = "colin-dns-hosting";
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -39,7 +39,6 @@ in
|
|||||||
CNAME."native" = "%CNAMENATIVE%";
|
CNAME."native" = "%CNAMENATIVE%";
|
||||||
A."@" = "%ANATIVE%";
|
A."@" = "%ANATIVE%";
|
||||||
A."servo.wan" = "%AWAN%";
|
A."servo.wan" = "%AWAN%";
|
||||||
A."servo.doof" = "%ADOOF%";
|
|
||||||
A."servo.lan" = config.sane.hosts.by-name."servo".lan-ip;
|
A."servo.lan" = config.sane.hosts.by-name."servo".lan-ip;
|
||||||
A."servo.hn" = config.sane.hosts.by-name."servo".wg-home.ip;
|
A."servo.hn" = config.sane.hosts.by-name."servo".wg-home.ip;
|
||||||
|
|
||||||
@@ -47,9 +46,9 @@ in
|
|||||||
# it's best that we keep this identical, or a superset of, what org. lists as our NS.
|
# it's best that we keep this identical, or a superset of, what org. lists as our NS.
|
||||||
# so, org. can specify ns2/ns3 as being to the VPN, with no mention of ns1. we provide ns1 here.
|
# so, org. can specify ns2/ns3 as being to the VPN, with no mention of ns1. we provide ns1 here.
|
||||||
A."ns1" = "%ANATIVE%";
|
A."ns1" = "%ANATIVE%";
|
||||||
A."ns2" = "%ADOOF%";
|
A."ns2" = "185.157.162.178";
|
||||||
A."ns3" = "%AOVPNS%";
|
A."ns3" = "185.157.162.178";
|
||||||
A."ovpns" = "%AOVPNS%";
|
A."ovpns" = "185.157.162.178";
|
||||||
NS."@" = [
|
NS."@" = [
|
||||||
"ns1.uninsane.org."
|
"ns1.uninsane.org."
|
||||||
"ns2.uninsane.org."
|
"ns2.uninsane.org."
|
||||||
@@ -60,91 +59,101 @@ in
|
|||||||
services.trust-dns.settings.zones = [ "uninsane.org" ];
|
services.trust-dns.settings.zones = [ "uninsane.org" ];
|
||||||
|
|
||||||
|
|
||||||
networking.nat.enable = true; #< TODO: try removing this?
|
networking.nat.enable = true;
|
||||||
# networking.nat.extraCommands = ''
|
networking.nat.extraCommands = ''
|
||||||
# # redirect incoming DNS requests from LAN addresses
|
# redirect incoming DNS requests from LAN addresses
|
||||||
# # to the LAN-specialized DNS service
|
# to the LAN-specialized DNS service
|
||||||
# # N.B.: use the `nixos-*` chains instead of e.g. PREROUTING
|
# N.B.: use the `nixos-*` chains instead of e.g. PREROUTING
|
||||||
# # because they get cleanly reset across activations or `systemctl restart firewall`
|
# because they get cleanly reset across activations or `systemctl restart firewall`
|
||||||
# # instead of accumulating cruft
|
# instead of accumulating cruft
|
||||||
# iptables -t nat -A nixos-nat-pre -p udp --dport 53 \
|
iptables -t nat -A nixos-nat-pre -p udp --dport 53 \
|
||||||
# -m iprange --src-range 10.78.76.0-10.78.79.255 \
|
-m iprange --src-range 10.78.76.0-10.78.79.255 \
|
||||||
# -j DNAT --to-destination :1053
|
-j DNAT --to-destination :1053
|
||||||
# iptables -t nat -A nixos-nat-pre -p tcp --dport 53 \
|
iptables -t nat -A nixos-nat-pre -p tcp --dport 53 \
|
||||||
# -m iprange --src-range 10.78.76.0-10.78.79.255 \
|
-m iprange --src-range 10.78.76.0-10.78.79.255 \
|
||||||
# -j DNAT --to-destination :1053
|
-j DNAT --to-destination :1053
|
||||||
# '';
|
'';
|
||||||
# sane.ports.ports."1053" = {
|
sane.ports.ports."1053" = {
|
||||||
# # because the NAT above redirects in nixos-nat-pre, LAN requests behave as though they arrived on the external interface at the redirected port.
|
# because the NAT above redirects in nixos-nat-pre, LAN requests behave as though they arrived on the external interface at the redirected port.
|
||||||
# # TODO: try nixos-nat-post instead?
|
# TODO: try nixos-nat-post instead?
|
||||||
# # TODO: or, don't NAT from port 53 -> port 1053, but rather nat from LAN addr to a loopback addr.
|
# TODO: or, don't NAT from port 53 -> port 1053, but rather nat from LAN addr to a loopback addr.
|
||||||
# # - this is complicated in that loopback is a different interface than eth0, so rewriting the destination address would cause the packets to just be dropped by the interface
|
# - this is complicated in that loopback is a different interface than eth0, so rewriting the destination address would cause the packets to just be dropped by the interface
|
||||||
# protocol = [ "udp" "tcp" ];
|
protocol = [ "udp" "tcp" ];
|
||||||
# visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
# description = "colin-redirected-dns-for-lan-namespace";
|
description = "colin-redirected-dns-for-lan-namespace";
|
||||||
# };
|
};
|
||||||
|
|
||||||
|
|
||||||
sane.services.trust-dns.enable = true;
|
sane.services.trust-dns.enable = true;
|
||||||
sane.services.trust-dns.instances = let
|
sane.services.trust-dns.instances = let
|
||||||
mkSubstitutions = flavor: {
|
mkSubstitutions = flavor: {
|
||||||
"%ADOOF%" = config.sane.netns.doof.netnsPubIpv4;
|
|
||||||
"%ANATIVE%" = nativeAddrs."servo.${flavor}";
|
|
||||||
"%AOVPNS%" = config.sane.netns.ovpns.netnsPubIpv4;
|
|
||||||
"%AWAN%" = "$(cat '${dyn-dns.ipPath}')";
|
"%AWAN%" = "$(cat '${dyn-dns.ipPath}')";
|
||||||
"%CNAMENATIVE%" = "servo.${flavor}";
|
"%CNAMENATIVE%" = "servo.${flavor}";
|
||||||
|
"%ANATIVE%" = nativeAddrs."servo.${flavor}";
|
||||||
|
"%AOVPNS%" = "185.157.162.178";
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
doof = {
|
wan = {
|
||||||
substitutions = mkSubstitutions "doof";
|
substitutions = mkSubstitutions "wan";
|
||||||
listenAddrsIpv4 = [
|
listenAddrsIpv4 = [
|
||||||
config.sane.netns.doof.hostVethIpv4
|
nativeAddrs."servo.lan"
|
||||||
config.sane.netns.ovpns.hostVethIpv4
|
bindOvpn
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
hn = {
|
|
||||||
substitutions = mkSubstitutions "hn";
|
|
||||||
listenAddrsIpv4 = [ nativeAddrs."servo.hn" ];
|
|
||||||
enableRecursiveResolver = true; #< allow wireguard clients to use this as their DNS resolver
|
|
||||||
# extraConfig = {
|
|
||||||
# zones = [
|
|
||||||
# {
|
|
||||||
# # forward the root zone to the local DNS resolver
|
|
||||||
# # to allow wireguard clients to use this as their DNS resolver
|
|
||||||
# zone = ".";
|
|
||||||
# zone_type = "Forward";
|
|
||||||
# stores = {
|
|
||||||
# type = "forward";
|
|
||||||
# name_servers = [
|
|
||||||
# {
|
|
||||||
# socket_addr = "127.0.0.53:53";
|
|
||||||
# protocol = "udp";
|
|
||||||
# trust_nx_responses = true;
|
|
||||||
# }
|
|
||||||
# ];
|
|
||||||
# };
|
|
||||||
# }
|
|
||||||
# ];
|
|
||||||
# };
|
|
||||||
};
|
|
||||||
lan = {
|
lan = {
|
||||||
substitutions = mkSubstitutions "lan";
|
substitutions = mkSubstitutions "lan";
|
||||||
listenAddrsIpv4 = [ nativeAddrs."servo.lan" ];
|
listenAddrsIpv4 = [ nativeAddrs."servo.lan" ];
|
||||||
# port = 1053;
|
port = 1053;
|
||||||
};
|
};
|
||||||
# wan = {
|
hn = {
|
||||||
# substitutions = mkSubstitutions "wan";
|
substitutions = mkSubstitutions "hn";
|
||||||
# listenAddrsIpv4 = [
|
listenAddrsIpv4 = [ nativeAddrs."servo.hn" ];
|
||||||
# nativeAddrs."servo.lan"
|
port = 1053;
|
||||||
# ];
|
};
|
||||||
|
# hn-resolver = {
|
||||||
|
# # don't need %AWAN% here because we forward to the hn instance.
|
||||||
|
# listenAddrsIpv4 = [ nativeAddrs."servo.hn" ];
|
||||||
|
# extraConfig = {
|
||||||
|
# zones = [
|
||||||
|
# {
|
||||||
|
# zone = "uninsane.org";
|
||||||
|
# zone_type = "Forward";
|
||||||
|
# stores = {
|
||||||
|
# type = "forward";
|
||||||
|
# name_servers = [
|
||||||
|
# {
|
||||||
|
# socket_addr = "${nativeAddrs."servo.hn"}:1053";
|
||||||
|
# protocol = "udp";
|
||||||
|
# trust_nx_responses = true;
|
||||||
|
# }
|
||||||
|
# ];
|
||||||
|
# };
|
||||||
|
# }
|
||||||
|
# {
|
||||||
|
# # forward the root zone to the local DNS resolver
|
||||||
|
# zone = ".";
|
||||||
|
# zone_type = "Forward";
|
||||||
|
# stores = {
|
||||||
|
# type = "forward";
|
||||||
|
# name_servers = [
|
||||||
|
# {
|
||||||
|
# socket_addr = "127.0.0.53:53";
|
||||||
|
# protocol = "udp";
|
||||||
|
# trust_nx_responses = true;
|
||||||
|
# }
|
||||||
|
# ];
|
||||||
|
# };
|
||||||
|
# }
|
||||||
|
# ];
|
||||||
|
# };
|
||||||
# };
|
# };
|
||||||
};
|
};
|
||||||
|
|
||||||
sane.services.dyn-dns.restartOnChange = [
|
sane.services.dyn-dns.restartOnChange = [
|
||||||
"trust-dns-doof.service"
|
"trust-dns-wan.service"
|
||||||
"trust-dns-hn.service"
|
|
||||||
"trust-dns-lan.service"
|
"trust-dns-lan.service"
|
||||||
# "trust-dns-wan.service"
|
"trust-dns-hn.service"
|
||||||
|
# "trust-dns-hn-resolver.service" # doesn't need restart because it doesn't know about WAN IP
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@@ -1,50 +0,0 @@
|
|||||||
{ lib, pkgs, ... }:
|
|
||||||
{
|
|
||||||
boot.initrd.supportedFilesystems = [ "ext4" "btrfs" "ext2" "ext3" "vfat" ];
|
|
||||||
# useful emergency utils
|
|
||||||
boot.initrd.extraUtilsCommands = ''
|
|
||||||
copy_bin_and_libs ${pkgs.btrfs-progs}/bin/btrfstune
|
|
||||||
copy_bin_and_libs ${pkgs.util-linux}/bin/{cfdisk,lsblk,lscpu}
|
|
||||||
copy_bin_and_libs ${pkgs.gptfdisk}/bin/{cgdisk,gdisk}
|
|
||||||
copy_bin_and_libs ${pkgs.smartmontools}/bin/smartctl
|
|
||||||
copy_bin_and_libs ${pkgs.e2fsprogs}/bin/resize2fs
|
|
||||||
'' + lib.optionalString pkgs.stdenv.hostPlatform.isx86_64 ''
|
|
||||||
copy_bin_and_libs ${pkgs.nvme-cli}/bin/nvme # doesn't cross compile
|
|
||||||
'';
|
|
||||||
boot.kernelParams = [
|
|
||||||
"boot.shell_on_fail"
|
|
||||||
#v experimental full pre-emption for hopefully better call/audio latency on moby.
|
|
||||||
# also toggleable at runtime via /sys/kernel/debug/sched/preempt
|
|
||||||
# defaults to preempt=voluntary
|
|
||||||
# "preempt=full"
|
|
||||||
];
|
|
||||||
# other kernelParams:
|
|
||||||
# "boot.trace"
|
|
||||||
# "systemd.log_level=debug"
|
|
||||||
# "systemd.log_target=console"
|
|
||||||
|
|
||||||
# moby has to run recent kernels (defined elsewhere).
|
|
||||||
# meanwhile, kernel variation plays some minor role in things like sandboxing (landlock) and capabilities.
|
|
||||||
# simpler to keep near the latest kernel on all devices,
|
|
||||||
# and also makes certain that any weird system-level bugs i see aren't likely to be stale kernel bugs.
|
|
||||||
# servo needs zfs though, which doesn't support every kernel.
|
|
||||||
boot.kernelPackages = lib.mkDefault pkgs.zfs.latestCompatibleLinuxPackages;
|
|
||||||
|
|
||||||
# hack in the `boot.shell_on_fail` arg since that doesn't always seem to work.
|
|
||||||
boot.initrd.preFailCommands = "allowShell=1";
|
|
||||||
|
|
||||||
# default: 4 (warn). 7 is debug
|
|
||||||
boot.consoleLogLevel = 7;
|
|
||||||
|
|
||||||
boot.loader.grub.enable = lib.mkDefault false;
|
|
||||||
boot.loader.generic-extlinux-compatible.enable = lib.mkDefault true;
|
|
||||||
|
|
||||||
hardware.enableAllFirmware = true; # firmware with licenses that don't allow for redistribution. fuck lawyers, fuck IP, give me the goddamn firmware.
|
|
||||||
# hardware.enableRedistributableFirmware = true; # proprietary but free-to-distribute firmware (extraneous to `enableAllFirmware` option)
|
|
||||||
|
|
||||||
# default is 252274, which is too low particularly for servo.
|
|
||||||
# manifests as spurious "No space left on device" when trying to install watches,
|
|
||||||
# e.g. in dyn-dns by `systemctl start dyn-dns-watcher.path`.
|
|
||||||
# see: <https://askubuntu.com/questions/828779/failed-to-add-run-systemd-ask-password-to-directory-watch-no-space-left-on-dev>
|
|
||||||
boot.kernel.sysctl."fs.inotify.max_user_watches" = 1048576;
|
|
||||||
}
|
|
@@ -1,30 +1,24 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
./boot.nix
|
|
||||||
./feeds.nix
|
./feeds.nix
|
||||||
./fs.nix
|
./fs.nix
|
||||||
|
./hardware
|
||||||
./home
|
./home
|
||||||
./hosts.nix
|
./hosts.nix
|
||||||
./ids.nix
|
./ids.nix
|
||||||
./machine-id.nix
|
./machine-id.nix
|
||||||
./net
|
./net
|
||||||
./nix.nix
|
./nix
|
||||||
./persist.nix
|
./persist.nix
|
||||||
./polyunfill.nix
|
./polyunfill.nix
|
||||||
./programs
|
./programs
|
||||||
./quirks.nix
|
|
||||||
./secrets.nix
|
./secrets.nix
|
||||||
./ssh.nix
|
./ssh.nix
|
||||||
./systemd.nix
|
./systemd.nix
|
||||||
./users
|
./users
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
# docs: https://nixos.org/manual/nixos/stable/options.html#opt-system.stateVersion
|
|
||||||
# this affects where nixos modules look for stateful data which might have been migrated across releases.
|
|
||||||
system.stateVersion = "21.11";
|
|
||||||
|
|
||||||
sane.nixcache.enable-trusted-keys = true;
|
sane.nixcache.enable-trusted-keys = true;
|
||||||
sane.nixcache.enable = lib.mkDefault true;
|
sane.nixcache.enable = lib.mkDefault true;
|
||||||
sane.persist.enable = lib.mkDefault true;
|
sane.persist.enable = lib.mkDefault true;
|
||||||
@@ -32,6 +26,9 @@
|
|||||||
sane.programs.sysadminUtils.enableFor.system = lib.mkDefault true;
|
sane.programs.sysadminUtils.enableFor.system = lib.mkDefault true;
|
||||||
sane.programs.consoleUtils.enableFor.user.colin = lib.mkDefault true;
|
sane.programs.consoleUtils.enableFor.user.colin = lib.mkDefault true;
|
||||||
|
|
||||||
|
nixpkgs.config.allowUnfree = true; # NIXPKGS_ALLOW_UNFREE=1
|
||||||
|
nixpkgs.config.allowBroken = true; # NIXPKGS_ALLOW_BROKEN=1
|
||||||
|
|
||||||
# time.timeZone = "America/Los_Angeles";
|
# time.timeZone = "America/Los_Angeles";
|
||||||
time.timeZone = "Etc/UTC"; # DST is too confusing for me => use a stable timezone
|
time.timeZone = "Etc/UTC"; # DST is too confusing for me => use a stable timezone
|
||||||
|
|
||||||
|
@@ -1,9 +1,14 @@
|
|||||||
# where to find good stuff?
|
# where to find good stuff?
|
||||||
# - universal search/directory: <https://podcastindex.org>
|
# - universal search/directory: <https://podcastindex.org>
|
||||||
# - list of lists: <https://en.wikipedia.org/wiki/Category:Lists_of_podcasts>
|
|
||||||
# - podcasts w/ a community: <https://lemmyverse.net/communities?query=podcast>
|
# - podcasts w/ a community: <https://lemmyverse.net/communities?query=podcast>
|
||||||
# - podcast rec thread: <https://lemmy.ml/post/1565858>
|
# - podcast rec thread: <https://lemmy.ml/post/1565858>
|
||||||
#
|
#
|
||||||
|
# candidates:
|
||||||
|
# - The Nonlinear Library (podcast): <https://forum.effectivealtruism.org/posts/JTZTBienqWEAjGDRv/listen-to-more-ea-content-with-the-nonlinear-library>
|
||||||
|
# - has ~10 posts per day, text-to-speech; i would need better tagging before adding this
|
||||||
|
# - <https://www.metaculus.com/questions/11102/introducing-the-metaculus-journal-podcast/>
|
||||||
|
# - dead since 2022/10 - 2023/03
|
||||||
|
|
||||||
{ lib, sane-data, ... }:
|
{ lib, sane-data, ... }:
|
||||||
let
|
let
|
||||||
hourly = { freq = "hourly"; };
|
hourly = { freq = "hourly"; };
|
||||||
@@ -75,7 +80,6 @@ let
|
|||||||
(fromDb "feeds.simplecast.com/wgl4xEgL" // rat) # Econ Talk
|
(fromDb "feeds.simplecast.com/wgl4xEgL" // rat) # Econ Talk
|
||||||
(fromDb "feeds.simplecast.com/xKJ93w_w" // uncat) # Atlas Obscura
|
(fromDb "feeds.simplecast.com/xKJ93w_w" // uncat) # Atlas Obscura
|
||||||
(fromDb "feeds.transistor.fm/acquired" // tech)
|
(fromDb "feeds.transistor.fm/acquired" // tech)
|
||||||
(fromDb "feeds.twit.tv/floss.xml" // tech)
|
|
||||||
(fromDb "fulltimenix.com" // tech)
|
(fromDb "fulltimenix.com" // tech)
|
||||||
(fromDb "futureofcoding.org/episodes" // tech)
|
(fromDb "futureofcoding.org/episodes" // tech)
|
||||||
(fromDb "hackerpublicradio.org" // tech)
|
(fromDb "hackerpublicradio.org" // tech)
|
||||||
@@ -99,7 +103,6 @@ let
|
|||||||
(fromDb "seattlenice.buzzsprout.com" // pol)
|
(fromDb "seattlenice.buzzsprout.com" // pol)
|
||||||
(fromDb "srslywrong.com" // pol)
|
(fromDb "srslywrong.com" // pol)
|
||||||
(fromDb "sharkbytes.transistor.fm" // tech) # Wireshark Podcast o_0
|
(fromDb "sharkbytes.transistor.fm" // tech) # Wireshark Podcast o_0
|
||||||
(fromDb "sharptech.fm/feed/podcast" // tech)
|
|
||||||
(fromDb "sscpodcast.libsyn.com" // rat) # Astral Codex Ten
|
(fromDb "sscpodcast.libsyn.com" // rat) # Astral Codex Ten
|
||||||
(fromDb "talesfromthebridge.buzzsprout.com" // tech) # Sci-Fi? has Peter Watts; author of No Moods, Ads or Cutesy Fucking Icons (rifters.com)
|
(fromDb "talesfromthebridge.buzzsprout.com" // tech) # Sci-Fi? has Peter Watts; author of No Moods, Ads or Cutesy Fucking Icons (rifters.com)
|
||||||
(fromDb "theamphour.com" // tech)
|
(fromDb "theamphour.com" // tech)
|
||||||
@@ -132,7 +135,6 @@ let
|
|||||||
(fromDb "artemis.sh" // tech)
|
(fromDb "artemis.sh" // tech)
|
||||||
(fromDb "ascii.textfiles.com" // tech) # Jason Scott
|
(fromDb "ascii.textfiles.com" // tech) # Jason Scott
|
||||||
(fromDb "austinvernon.site" // tech)
|
(fromDb "austinvernon.site" // tech)
|
||||||
(fromDb "buttondown.email" // tech)
|
|
||||||
(fromDb "ben-evans.com/benedictevans" // pol)
|
(fromDb "ben-evans.com/benedictevans" // pol)
|
||||||
(fromDb "bitbashing.io" // tech)
|
(fromDb "bitbashing.io" // tech)
|
||||||
(fromDb "bitsaboutmoney.com" // uncat)
|
(fromDb "bitsaboutmoney.com" // uncat)
|
||||||
@@ -193,8 +195,6 @@ let
|
|||||||
(fromDb "weekinethereumnews.com" // tech)
|
(fromDb "weekinethereumnews.com" // tech)
|
||||||
(fromDb "willow.phantoma.online") # wizard@xyzzy.link
|
(fromDb "willow.phantoma.online") # wizard@xyzzy.link
|
||||||
(fromDb "xn--gckvb8fzb.com" // tech)
|
(fromDb "xn--gckvb8fzb.com" // tech)
|
||||||
(fromDb "xorvoid.com" // tech)
|
|
||||||
(fromDb "www.thebignewsletter.com" // pol)
|
|
||||||
(mkSubstack "astralcodexten" // rat // daily) # Scott Alexander
|
(mkSubstack "astralcodexten" // rat // daily) # Scott Alexander
|
||||||
(mkSubstack "eliqian" // rat // weekly)
|
(mkSubstack "eliqian" // rat // weekly)
|
||||||
(mkSubstack "oversharing" // pol // daily)
|
(mkSubstack "oversharing" // pol // daily)
|
||||||
@@ -238,7 +238,7 @@ let
|
|||||||
(fromDb "youtube.com/@TomScottGo")
|
(fromDb "youtube.com/@TomScottGo")
|
||||||
(fromDb "youtube.com/@Vihart")
|
(fromDb "youtube.com/@Vihart")
|
||||||
(fromDb "youtube.com/@Vox")
|
(fromDb "youtube.com/@Vox")
|
||||||
# (fromDb "youtube.com/@Vsauce") # they're all like 1-minute long videos now? what happened @Vsauce?
|
(fromDb "youtube.com/@Vsauce")
|
||||||
|
|
||||||
# (fromDb "youtube.com/@rossmanngroup" // pol // tech) # Louis Rossmann
|
# (fromDb "youtube.com/@rossmanngroup" // pol // tech) # Louis Rossmann
|
||||||
];
|
];
|
||||||
|
@@ -26,6 +26,10 @@ let
|
|||||||
# lazyMount: defer mounting until first access from userspace.
|
# lazyMount: defer mounting until first access from userspace.
|
||||||
# see: `man systemd.automount`, `man automount`, `man autofs`
|
# see: `man systemd.automount`, `man automount`, `man autofs`
|
||||||
lazyMount = noauto ++ automount;
|
lazyMount = noauto ++ automount;
|
||||||
|
wg = [
|
||||||
|
"x-systemd.requires=wireguard-wg-home.service"
|
||||||
|
"x-systemd.after=wireguard-wg-home.service"
|
||||||
|
];
|
||||||
|
|
||||||
fuse = [
|
fuse = [
|
||||||
"allow_other" # allow users other than the one who mounts it to access it. needed, if systemd is the one mounting this fs (as root)
|
"allow_other" # allow users other than the one who mounts it to access it. needed, if systemd is the one mounting this fs (as root)
|
||||||
@@ -132,9 +136,9 @@ let
|
|||||||
device = "ftp://servo-hn:/${subdir}";
|
device = "ftp://servo-hn:/${subdir}";
|
||||||
noCheck = true;
|
noCheck = true;
|
||||||
fsType = "fuse.curlftpfs";
|
fsType = "fuse.curlftpfs";
|
||||||
options = fsOpts.ftp ++ fsOpts.noauto;
|
options = fsOpts.ftp ++ fsOpts.noauto ++ fsOpts.wg;
|
||||||
# fsType = "nfs";
|
# fsType = "nfs";
|
||||||
# options = fsOpts.nfs ++ fsOpts.lazyMount;
|
# options = fsOpts.nfs ++ fsOpts.lazyMount ++ fsOpts.wg;
|
||||||
};
|
};
|
||||||
systemd.services."automount-servo-${utils.escapeSystemdPath subdir}" = let
|
systemd.services."automount-servo-${utils.escapeSystemdPath subdir}" = let
|
||||||
fs = config.fileSystems."/mnt/servo/${subdir}";
|
fs = config.fileSystems."/mnt/servo/${subdir}";
|
||||||
@@ -212,7 +216,6 @@ 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")
|
|
||||||
(remoteHome "desko")
|
(remoteHome "desko")
|
||||||
(remoteHome "lappy")
|
(remoteHome "lappy")
|
||||||
(remoteHome "moby")
|
(remoteHome "moby")
|
||||||
|
99
hosts/common/hardware/default.nix
Normal file
99
hosts/common/hardware/default.nix
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./x86_64.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
boot.initrd.supportedFilesystems = [ "ext4" "btrfs" "ext2" "ext3" "vfat" ];
|
||||||
|
# useful emergency utils
|
||||||
|
boot.initrd.extraUtilsCommands = ''
|
||||||
|
copy_bin_and_libs ${pkgs.btrfs-progs}/bin/btrfstune
|
||||||
|
copy_bin_and_libs ${pkgs.util-linux}/bin/{cfdisk,lsblk,lscpu}
|
||||||
|
copy_bin_and_libs ${pkgs.gptfdisk}/bin/{cgdisk,gdisk}
|
||||||
|
copy_bin_and_libs ${pkgs.smartmontools}/bin/smartctl
|
||||||
|
copy_bin_and_libs ${pkgs.e2fsprogs}/bin/resize2fs
|
||||||
|
'' + lib.optionalString pkgs.stdenv.hostPlatform.isx86_64 ''
|
||||||
|
copy_bin_and_libs ${pkgs.nvme-cli}/bin/nvme # doesn't cross compile
|
||||||
|
'';
|
||||||
|
boot.kernelParams = [
|
||||||
|
"boot.shell_on_fail"
|
||||||
|
#v experimental full pre-emption for hopefully better call/audio latency on moby.
|
||||||
|
# also toggleable at runtime via /sys/kernel/debug/sched/preempt
|
||||||
|
# defaults to preempt=voluntary
|
||||||
|
# "preempt=full"
|
||||||
|
];
|
||||||
|
# other kernelParams:
|
||||||
|
# "boot.trace"
|
||||||
|
# "systemd.log_level=debug"
|
||||||
|
# "systemd.log_target=console"
|
||||||
|
|
||||||
|
# moby has to run recent kernels (defined elsewhere).
|
||||||
|
# meanwhile, kernel variation plays some minor role in things like sandboxing (landlock) and capabilities.
|
||||||
|
# simpler to keep near the latest kernel on all devices,
|
||||||
|
# and also makes certain that any weird system-level bugs i see aren't likely to be stale kernel bugs.
|
||||||
|
# servo needs zfs though, which doesn't support every kernel.
|
||||||
|
boot.kernelPackages = lib.mkDefault pkgs.zfs.latestCompatibleLinuxPackages;
|
||||||
|
|
||||||
|
# TODO: remove after linux 6.9. see: <https://github.com/axboe/liburing/issues/1113>
|
||||||
|
# - <https://github.com/neovim/neovim/issues/28149>
|
||||||
|
# - <https://git.kernel.dk/cgit/linux/commit/?h=io_uring-6.9&id=e5444baa42e545bb929ba56c497e7f3c73634099>
|
||||||
|
# when removing, try starting and suspending (ctrl+z) two instances of neovim simultaneously.
|
||||||
|
# if the system doesn't freeze, then this is safe to remove.
|
||||||
|
# added 2024-04-04
|
||||||
|
sane.user.fs.".profile".symlink.text = lib.mkBefore ''
|
||||||
|
export UV_USE_IO_URING=0
|
||||||
|
'';
|
||||||
|
|
||||||
|
# hack in the `boot.shell_on_fail` arg since that doesn't always seem to work.
|
||||||
|
boot.initrd.preFailCommands = "allowShell=1";
|
||||||
|
|
||||||
|
# default: 4 (warn). 7 is debug
|
||||||
|
boot.consoleLogLevel = 7;
|
||||||
|
|
||||||
|
boot.loader.grub.enable = lib.mkDefault false;
|
||||||
|
boot.loader.generic-extlinux-compatible.enable = lib.mkDefault true;
|
||||||
|
|
||||||
|
# non-free firmware
|
||||||
|
hardware.enableRedistributableFirmware = true;
|
||||||
|
|
||||||
|
# default is 252274, which is too low particularly for servo.
|
||||||
|
# manifests as spurious "No space left on device" when trying to install watches,
|
||||||
|
# e.g. in dyn-dns by `systemctl start dyn-dns-watcher.path`.
|
||||||
|
# see: <https://askubuntu.com/questions/828779/failed-to-add-run-systemd-ask-password-to-directory-watch-no-space-left-on-dev>
|
||||||
|
boot.kernel.sysctl."fs.inotify.max_user_watches" = 1048576;
|
||||||
|
|
||||||
|
# powertop will default to putting USB devices -- including HID -- to sleep after TWO SECONDS
|
||||||
|
powerManagement.powertop.enable = false;
|
||||||
|
# linux CPU governor: <https://www.kernel.org/doc/Documentation/cpu-freq/governors.txt>
|
||||||
|
# - options:
|
||||||
|
# - "powersave" => force CPU to always run at lowest supported frequency
|
||||||
|
# - "performance" => force CPU to always run at highest frequency
|
||||||
|
# - "ondemand" => adjust frequency based on load
|
||||||
|
# - "conservative" (ondemand but slower to adjust)
|
||||||
|
# - "schedutil"
|
||||||
|
# - "userspace"
|
||||||
|
# - not all options are available for all platforms
|
||||||
|
# - intel (intel_pstate) appears to manage scaling w/o intervention/control from the OS.
|
||||||
|
# - AMD (acpi-cpufreq) appears to manage scaling via the OS *or* HW. but the ondemand defaults never put it to max hardware frequency.
|
||||||
|
# - qualcomm (cpufreq-dt) appears to manage scaling *only* via the OS. ondemand governor exercises the full range.
|
||||||
|
# - query details with `sudo cpupower frequency-info`
|
||||||
|
powerManagement.cpuFreqGovernor = "ondemand";
|
||||||
|
|
||||||
|
# see: `man logind.conf`
|
||||||
|
# don’t shutdown when power button is short-pressed (commonly done an accident, or by cats).
|
||||||
|
# but do on long-press: useful to gracefully power-off server.
|
||||||
|
services.logind.powerKey = "lock";
|
||||||
|
services.logind.powerKeyLongPress = "poweroff";
|
||||||
|
services.logind.lidSwitch = "lock";
|
||||||
|
|
||||||
|
# services.snapper.configs = {
|
||||||
|
# root = {
|
||||||
|
# subvolume = "/";
|
||||||
|
# extraConfig = {
|
||||||
|
# ALLOW_USERS = "colin";
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
# services.snapper.snapshotInterval = "daily";
|
||||||
|
}
|
@@ -1,14 +1,7 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
{ lib, pkgs, ... }:
|
||||||
let
|
|
||||||
cfg = config.sane.hal.x86_64;
|
|
||||||
in
|
|
||||||
{
|
{
|
||||||
options = {
|
config = lib.mkIf (pkgs.system == "x86_64-linux") {
|
||||||
sane.hal.x86_64.enable = (lib.mkEnableOption "x86_64-specific hardware support") // {
|
|
||||||
default = pkgs.system == "x86_64-linux";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
config = lib.mkIf cfg.enable {
|
|
||||||
boot.initrd.availableKernelModules = [
|
boot.initrd.availableKernelModules = [
|
||||||
"xhci_pci" "ahci" "sd_mod" "sdhci_pci" # nixos-generate-config defaults
|
"xhci_pci" "ahci" "sd_mod" "sdhci_pci" # nixos-generate-config defaults
|
||||||
"usb_storage" # rpi needed this to boot from usb storage, i think.
|
"usb_storage" # rpi needed this to boot from usb storage, i think.
|
@@ -2,14 +2,6 @@
|
|||||||
|
|
||||||
{
|
{
|
||||||
# TODO: this should be populated per-host
|
# TODO: this should be populated per-host
|
||||||
sane.hosts.by-name."crappy" = {
|
|
||||||
ssh.user_pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMIvSQAGKqmymXIL4La9B00LPxBIqWAr5AsJxk3UQeY5";
|
|
||||||
ssh.host_pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMN0cpRAloCBOE5/2wuzgik35iNDv5KLceWMCVaa7DIQ";
|
|
||||||
# wg-home.pubkey = "TODO";
|
|
||||||
# wg-home.ip = "10.0.10.55";
|
|
||||||
lan-ip = "10.78.79.55";
|
|
||||||
};
|
|
||||||
|
|
||||||
sane.hosts.by-name."desko" = {
|
sane.hosts.by-name."desko" = {
|
||||||
ssh.user_pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPU5GlsSfbaarMvDA20bxpSZGWviEzXGD8gtrIowc1pX";
|
ssh.user_pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPU5GlsSfbaarMvDA20bxpSZGWviEzXGD8gtrIowc1pX";
|
||||||
ssh.host_pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFw9NoRaYrM6LbDd3aFBc4yyBlxGQn8HjeHd/dZ3CfHk";
|
ssh.host_pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFw9NoRaYrM6LbDd3aFBc4yyBlxGQn8HjeHd/dZ3CfHk";
|
||||||
|
@@ -62,7 +62,6 @@
|
|||||||
sane.ids.clightning.gid = 2419;
|
sane.ids.clightning.gid = 2419;
|
||||||
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.colin.uid = 1000;
|
sane.ids.colin.uid = 1000;
|
||||||
sane.ids.guest.uid = 1100;
|
sane.ids.guest.uid = 1100;
|
||||||
|
@@ -20,7 +20,7 @@
|
|||||||
# - each namespace may use a different /etc/resolv.conf to specify different DNS servers
|
# - each namespace may use a different /etc/resolv.conf to specify different DNS servers
|
||||||
# - nscd breaks namespacing: the host nscd is unaware of the guest's /etc/resolv.conf, and so directs the guest's DNS requests to the host's servers.
|
# - nscd breaks namespacing: the host nscd is unaware of the guest's /etc/resolv.conf, and so directs the guest's DNS requests to the host's servers.
|
||||||
# - this is fixed by either removing `/var/run/nscd/socket` from the namespace, or disabling nscd altogether.
|
# - this is fixed by either removing `/var/run/nscd/socket` from the namespace, or disabling nscd altogether.
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, ... }:
|
||||||
lib.mkMerge [
|
lib.mkMerge [
|
||||||
{
|
{
|
||||||
sane.services.trust-dns.enable = lib.mkDefault config.sane.services.trust-dns.asSystemResolver;
|
sane.services.trust-dns.enable = lib.mkDefault config.sane.services.trust-dns.asSystemResolver;
|
||||||
@@ -59,35 +59,15 @@ lib.mkMerge [
|
|||||||
# in the netns and we query upstream DNS more often than needed. hm.
|
# in the netns and we query upstream DNS more often than needed. hm.
|
||||||
# services.nscd.enableNsncd = true;
|
# services.nscd.enableNsncd = true;
|
||||||
|
|
||||||
# disabling nscd LOSES US SOME FUNCTIONALITY. in particular, only the glibc-builtin modules are accessible via /etc/resolv.conf (er, did i mean /etc/nsswitch.conf?).
|
# disabling nscd LOSES US SOME FUNCTIONALITY. in particular, only the glibc-builtin modules are accessible via /etc/resolv.conf.
|
||||||
# - dns: glibc-bultin
|
# - dns: glibc-bultin
|
||||||
# - files: glibc-builtin
|
# - files: glibc-builtin
|
||||||
# - myhostname: systemd
|
# - myhostname: systemd
|
||||||
# - mymachines: systemd
|
# - mymachines: systemd
|
||||||
# - resolve: systemd
|
# - resolve: systemd
|
||||||
# in practice, i see no difference with nscd disabled.
|
# in practice, i see no difference with nscd disabled.
|
||||||
# - the exception is when the system dns resolver doesn't do everything.
|
|
||||||
# for example, systemd-resolved does mDNS. hickory-dns does not. a hickory-dns system won't be mDNS-capable.
|
|
||||||
# disabling nscd VASTLY simplifies netns and process isolation. see explainer at top of file.
|
# disabling nscd VASTLY simplifies netns and process isolation. see explainer at top of file.
|
||||||
services.nscd.enable = false;
|
services.nscd.enable = false;
|
||||||
# system.nssModules = lib.mkForce [];
|
system.nssModules = lib.mkForce [];
|
||||||
sane.silencedAssertions = [''.*Loading NSS modules from system.nssModules.*requires services.nscd.enable being set to true.*''];
|
|
||||||
# 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.
|
|
||||||
# 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
|
|
||||||
# (except avahi doesn't act as a local resolver over DNS protocol -- only dbus).
|
|
||||||
environment.systemPackages = [(pkgs.symlinkJoin {
|
|
||||||
name = "nss-modules";
|
|
||||||
paths = config.system.nssModules.list;
|
|
||||||
postBuild = ''
|
|
||||||
mkdir nss
|
|
||||||
mv $out/lib/libnss_* nss
|
|
||||||
rm -rf $out
|
|
||||||
mkdir -p $out/lib
|
|
||||||
mv nss $out/lib
|
|
||||||
'';
|
|
||||||
})];
|
|
||||||
environment.variables.LD_LIBRARY_PATH = [ "/run/current-system/sw/lib/nss" ];
|
|
||||||
systemd.globalEnvironment.LD_LIBRARY_PATH = "/run/current-system/sw/lib/nss"; #< specifically for `geoclue.service`
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@@ -14,7 +14,7 @@
|
|||||||
# after = [ "polkit.service" ];
|
# after = [ "polkit.service" ];
|
||||||
# requires = [ "polkit.service" ];
|
# requires = [ "polkit.service" ];
|
||||||
wantedBy = [ "network.target" ]; #< default is `multi-user.target`, somehow it doesn't auto-start with that...
|
wantedBy = [ "network.target" ]; #< default is `multi-user.target`, somehow it doesn't auto-start with that...
|
||||||
path = [ "/run/current-system/sw" ]; #< so it can find `sanebox`
|
# path = [ "/run/current-system/sw" ]; #< so it can find `sanebox`
|
||||||
|
|
||||||
# serviceConfig.Type = "dbus";
|
# serviceConfig.Type = "dbus";
|
||||||
# serviceConfig.BusName = "org.freedesktop.ModemManager1";
|
# serviceConfig.BusName = "org.freedesktop.ModemManager1";
|
||||||
@@ -32,33 +32,15 @@
|
|||||||
# serviceConfig.Restart = "on-abort";
|
# serviceConfig.Restart = "on-abort";
|
||||||
# serviceConfig.StandardError = "null";
|
# serviceConfig.StandardError = "null";
|
||||||
# serviceConfig.CapabilityBoundingSet = "CAP_SYS_ADMIN CAP_NET_ADMIN";
|
# serviceConfig.CapabilityBoundingSet = "CAP_SYS_ADMIN CAP_NET_ADMIN";
|
||||||
# serviceConfig.ProtectSystem = true; # makes empty: /boot, /usr
|
# serviceConfig.ProtectSystem = true;
|
||||||
# serviceConfig.ProtectHome = true; # makes empty: /home, /root, /run/user
|
# serviceConfig.ProtectHome = true;
|
||||||
# serviceConfig.PrivateTmp = true;
|
# serviceConfig.PrivateTmp = true;
|
||||||
# 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
|
# TODO: sandbox more aggressively
|
||||||
serviceConfig.LockPersonality = true;
|
# - CAP_NET_ADMIN *only*?
|
||||||
# serviceConfig.PrivateUsers = true; #< untried, not likely to work since it needs capabilities
|
# it needs these paths:
|
||||||
serviceConfig.PrivateTmp = true;
|
|
||||||
serviceConfig.ProtectClock = true; # syscall filter to prevent changing the RTC
|
|
||||||
serviceConfig.ProtectControlGroups = true;
|
|
||||||
serviceConfig.ProtectHome = true; # makes empty: /home, /root, /run/user
|
|
||||||
serviceConfig.ProtectHostname = true; # prevents changing hostname
|
|
||||||
serviceConfig.ProtectKernelLogs = true; # disable /proc/kmsg, /dev/kmsg
|
|
||||||
serviceConfig.ProtectKernelModules = true; # syscall filter to prevent module calls
|
|
||||||
serviceConfig.ProtectKernelTunables = true;
|
|
||||||
serviceConfig.ProtectSystem = "strict"; # makes read-only all but /dev, /proc, /sys
|
|
||||||
serviceConfig.RestrictAddressFamilies = [
|
|
||||||
"AF_NETLINK"
|
|
||||||
"AF_QIPCRTR"
|
|
||||||
"AF_UNIX"
|
|
||||||
];
|
|
||||||
serviceConfig.RestrictSUIDSGID = true;
|
|
||||||
serviceConfig.SystemCallArchitectures = "native"; # prevents e.g. aarch64 syscalls in the event that the kernel is multi-architecture.
|
|
||||||
|
|
||||||
# from earlier `landlock` sandboxing, i know it needs these directories:
|
|
||||||
# - # "/"
|
# - # "/"
|
||||||
# - "/dev" #v modem-power + net are not enough
|
# - "/dev" #v modem-power + net are not enough
|
||||||
# - # "/dev/modem-power"
|
# - # "/dev/modem-power"
|
||||||
|
@@ -61,46 +61,35 @@ in {
|
|||||||
serviceConfig.AmbientCapabilities = [
|
serviceConfig.AmbientCapabilities = [
|
||||||
# "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"
|
||||||
"CAP_NET_BIND_SERVICE" #< this *does* seem to be necessary, though i don't understand why. DHCP?
|
"CAP_NET_BIND_SERVICE" #< this *does* seem to be necessary, though i don't understand why. DHCP?
|
||||||
# "CAP_SYS_MODULE"
|
# "CAP_SYS_MODULE"
|
||||||
# "CAP_AUDIT_WRITE" #< allow writing to the audit log (optional)
|
"CAP_AUDIT_WRITE" #< allow writing to the audit log
|
||||||
# "CAP_KILL"
|
# "CAP_KILL"
|
||||||
];
|
];
|
||||||
serviceConfig.LockPersonality = true;
|
serviceConfig.LockPersonality = true;
|
||||||
serviceConfig.NoNewPrivileges = 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.PrivateUsers = true; # TODO: might break hooks?
|
||||||
# serviceConfig.PrivateUsers = true; #< BREAKS NetworkManager (presumably, it causes a new user namespace, breaking CAP_NET_ADMIN & others). "platform-linux: do-change-link[3]: failure 1 (Operation not permitted)"
|
|
||||||
serviceConfig.ProtectClock = true; # syscall filter to prevent changing the RTC
|
serviceConfig.ProtectClock = true; # syscall filter to prevent changing the RTC
|
||||||
serviceConfig.ProtectControlGroups = true;
|
serviceConfig.ProtectControlGroups = true;
|
||||||
serviceConfig.ProtectHome = true; # makes empty: /home, /root, /run/user
|
serviceConfig.ProtectHome = true; # makes empty: /home, /root, /run/user
|
||||||
serviceConfig.ProtectHostname = true; # probably not upstreamable: prevents changing hostname
|
serviceConfig.ProtectHostname = true; # probably not upstreamable: prevents changing hostname
|
||||||
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
|
||||||
serviceConfig.ProtectKernelTunables = true; # but NM might need to write /proc/sys/net/...
|
# ProtectKernelTunables = true; # but NM might need to write /proc/sys/net/...
|
||||||
serviceConfig.ProtectSystem = "strict"; # makes read-only: all but /dev, /proc, /sys.
|
serviceConfig.ProtectSystem = "full"; # makes read-only: /boot, /etc/, /usr. TODO: "strict" would make all but /dev, /proc, /sys inaccessible.
|
||||||
serviceConfig.RestrictAddressFamilies = [
|
# serviceConfig.RestrictAddressFamilies = TODO
|
||||||
"AF_INET"
|
|
||||||
"AF_INET6"
|
|
||||||
"AF_NETLINK" # breaks near DHCP without this
|
|
||||||
"AF_PACKET" # for DHCP
|
|
||||||
"AF_UNIX"
|
|
||||||
# AF_ALG ?
|
|
||||||
# AF_BLUETOOTH ?
|
|
||||||
# AF_BRIDGE ?
|
|
||||||
];
|
|
||||||
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.
|
||||||
# from earlier `landlock` sandboxing, i know it needs these directories:
|
# TODO: 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 trust-dns-nmhook
|
||||||
# - "/run/udev"
|
# - "/run/udev"
|
||||||
# - # "/run/wg-home.priv"
|
# - # "/run/wg-home.priv"
|
||||||
# - "/sys/class"
|
# - "/sys/class" #< TODO: specify this more precisely
|
||||||
# - "/sys/devices"
|
# - "/sys/devices"
|
||||||
# - "/var/lib/NetworkManager"
|
# - "/var/lib/NetworkManager"
|
||||||
# - "/var/lib/trust-dns" #< for trust-dns-nmhook
|
# - "/var/lib/trust-dns" #< for trust-dns-nmhook
|
||||||
@@ -122,29 +111,9 @@ in {
|
|||||||
# ];
|
# ];
|
||||||
# serviceConfig.Restart = "always";
|
# serviceConfig.Restart = "always";
|
||||||
# serviceConfig.RestartSec = "1s";
|
# serviceConfig.RestartSec = "1s";
|
||||||
|
serviceConfig.User = "networkmanager";
|
||||||
# serviceConfig.DynamicUser = true; #< not possible, else we lose group perms (so can't write to `trust-dns`'s files in the nm hook)
|
|
||||||
serviceConfig.User = "networkmanager"; # TODO: should arguably use `DynamicUser`
|
|
||||||
serviceConfig.Group = "networkmanager";
|
serviceConfig.Group = "networkmanager";
|
||||||
serviceConfig.LockPersonality = true;
|
# TODO: it needs access only to the above mentioned directories
|
||||||
serviceConfig.NoNewPrivileges = true;
|
|
||||||
serviceConfig.PrivateDevices = true; # remount /dev with just the basics, syscall filter to block @raw-io
|
|
||||||
serviceConfig.PrivateIPC = true;
|
|
||||||
serviceConfig.PrivateTmp = true;
|
|
||||||
serviceConfig.PrivateUsers = true;
|
|
||||||
serviceConfig.ProtectClock = true; # syscall filter to prevent changing the RTC
|
|
||||||
serviceConfig.ProtectControlGroups = true;
|
|
||||||
serviceConfig.ProtectHome = true; # makes empty: /home, /root, /run/user
|
|
||||||
serviceConfig.ProtectHostname = true; # probably not upstreamable: prevents changing hostname
|
|
||||||
serviceConfig.ProtectKernelLogs = true; # disable /proc/kmsg, /dev/kmsg
|
|
||||||
serviceConfig.ProtectKernelModules = true; # syscall filter to prevent module calls
|
|
||||||
serviceConfig.ProtectKernelTunables = true;
|
|
||||||
serviceConfig.ProtectSystem = "full"; # makes read-only: /boot, /etc/, /usr. `strict` isn't possible due to trust-dns hook
|
|
||||||
serviceConfig.RestrictAddressFamilies = [
|
|
||||||
"AF_UNIX" # required, probably for dbus or systemd connectivity
|
|
||||||
];
|
|
||||||
serviceConfig.RestrictSUIDSGID = true;
|
|
||||||
serviceConfig.SystemCallArchitectures = "native"; # prevents e.g. aarch64 syscalls in the event that the kernel is multi-architecture.
|
|
||||||
};
|
};
|
||||||
|
|
||||||
# harden wpa_supplicant (used by NetworkManager)
|
# harden wpa_supplicant (used by NetworkManager)
|
||||||
@@ -155,31 +124,7 @@ in {
|
|||||||
"CAP_NET_ADMIN"
|
"CAP_NET_ADMIN"
|
||||||
"CAP_NET_RAW"
|
"CAP_NET_RAW"
|
||||||
];
|
];
|
||||||
serviceConfig.LockPersonality = true;
|
# TODO: it needs only these paths:
|
||||||
serviceConfig.NoNewPrivileges = true;
|
|
||||||
# serviceConfig.PrivateDevices = true; # untried, not likely to work. remount /dev with just the basics, syscall filter to block @raw-io
|
|
||||||
serviceConfig.PrivateIPC = true;
|
|
||||||
serviceConfig.PrivateTmp = true;
|
|
||||||
# serviceConfig.PrivateUsers = true; #< untried, not likely to work
|
|
||||||
serviceConfig.ProtectClock = true; # syscall filter to prevent changing the RTC
|
|
||||||
serviceConfig.ProtectControlGroups = true;
|
|
||||||
serviceConfig.ProtectHome = true; # makes empty: /home, /root, /run/user
|
|
||||||
serviceConfig.ProtectHostname = true; # prevents changing hostname
|
|
||||||
serviceConfig.ProtectKernelLogs = true; # disable /proc/kmsg, /dev/kmsg
|
|
||||||
serviceConfig.ProtectKernelModules = true; # syscall filter to prevent module calls
|
|
||||||
serviceConfig.ProtectKernelTunables = true; #< N.B.: i think this makes certain /proc writes fail
|
|
||||||
serviceConfig.ProtectSystem = "strict"; # makes read-only: all but /dev, /proc, /sys.
|
|
||||||
serviceConfig.RestrictAddressFamilies = [
|
|
||||||
"AF_INET" #< required
|
|
||||||
"AF_INET6"
|
|
||||||
"AF_NETLINK" #< required
|
|
||||||
"AF_PACKET" #< required
|
|
||||||
"AF_UNIX" #< required (wpa_supplicant wants to use dbus)
|
|
||||||
];
|
|
||||||
serviceConfig.RestrictSUIDSGID = true;
|
|
||||||
serviceConfig.SystemCallArchitectures = "native"; # prevents e.g. aarch64 syscalls in the event that the kernel is multi-architecture.
|
|
||||||
|
|
||||||
# from earlier `landlock` sandboxing, i know it needs only these paths:
|
|
||||||
# - "/dev/net"
|
# - "/dev/net"
|
||||||
# - "/dev/rfkill"
|
# - "/dev/rfkill"
|
||||||
# - "/proc/sys/net"
|
# - "/proc/sys/net"
|
||||||
|
@@ -59,18 +59,14 @@
|
|||||||
# note the import starts at repo root: this allows `./overlay/default.nix` to access the stuff at the root
|
# note the import starts at repo root: this allows `./overlay/default.nix` to access the stuff at the root
|
||||||
# "nixpkgs-overlays=${../../..}/hosts/common/nix-path/overlay"
|
# "nixpkgs-overlays=${../../..}/hosts/common/nix-path/overlay"
|
||||||
# as long as my system itself doesn't rely on NIXPKGS at runtime, we can point the overlays to git
|
# as long as my system itself doesn't rely on NIXPKGS at runtime, we can point the overlays to git
|
||||||
# to avoid `switch`ing so much during development.
|
# to avoid switching so much during development
|
||||||
# TODO: it would be nice to remove this someday!
|
"nixpkgs-overlays=/home/colin/dev/nixos/hosts/common/nix/overlay"
|
||||||
# it's an impurity that touches way more than i need and tends to cause hard-to-debug eval issues
|
|
||||||
# when it goes wrong. should i port my `nix-shell` scripts to something more tailored to my uses
|
|
||||||
# and then delete `nixpkgs-overlays`?
|
|
||||||
"nixpkgs-overlays=/home/colin/dev/nixos/integrations/nixpkgs/nixpkgs-overlays.nix"
|
|
||||||
];
|
];
|
||||||
|
|
||||||
# ensure new deployments have a source of this repo with which they can bootstrap.
|
# ensure new deployments have a source of this repo with which they can bootstrap.
|
||||||
# this however changes on every commit and can be slow to copy for e.g. `moby`.
|
# this however changes on every commit and can be slow to copy for e.g. `moby`.
|
||||||
environment.etc."nixos" = lib.mkIf (config.sane.maxBuildCost >= 3) {
|
environment.etc."nixos" = lib.mkIf (config.sane.maxBuildCost >= 3) {
|
||||||
source = pkgs.sane-nix-files;
|
source = ../../..;
|
||||||
};
|
};
|
||||||
environment.etc."nix/registry.json" = lib.mkIf (config.sane.maxBuildCost < 3) {
|
environment.etc."nix/registry.json" = lib.mkIf (config.sane.maxBuildCost < 3) {
|
||||||
enable = false;
|
enable = false;
|
4
hosts/common/nix/overlay/default.nix
Normal file
4
hosts/common/nix/overlay/default.nix
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# XXX: NIX_PATH=...:nixpkgs-overlays=... will import every overlay in the directory
|
||||||
|
# so we prefer to give it a directory with just this *one* overlay, otherwise it imports conflicting overlays
|
||||||
|
# and gets stuck in a loop until it OOMs
|
||||||
|
import ../../../../overlays/all.nix
|
@@ -50,14 +50,12 @@ in
|
|||||||
"fd"
|
"fd"
|
||||||
"file"
|
"file"
|
||||||
"forkstat" # monitor every spawned/forked process
|
"forkstat" # monitor every spawned/forked process
|
||||||
"free"
|
|
||||||
# "fwupd"
|
# "fwupd"
|
||||||
"gawk"
|
"gawk"
|
||||||
"gdb" # to debug segfaults
|
"gdb" # to debug segfaults
|
||||||
"git"
|
"git"
|
||||||
"gptfdisk" # gdisk
|
"gptfdisk" # gdisk
|
||||||
"hdparm"
|
"hdparm"
|
||||||
"hping"
|
|
||||||
"htop"
|
"htop"
|
||||||
"iftop"
|
"iftop"
|
||||||
"inetutils" # for telnet
|
"inetutils" # for telnet
|
||||||
@@ -86,7 +84,6 @@ in
|
|||||||
"parted"
|
"parted"
|
||||||
"pciutils"
|
"pciutils"
|
||||||
"powertop"
|
"powertop"
|
||||||
"ps"
|
|
||||||
"pstree"
|
"pstree"
|
||||||
"ripgrep"
|
"ripgrep"
|
||||||
"s6-rc" # service manager
|
"s6-rc" # service manager
|
||||||
@@ -100,7 +97,6 @@ in
|
|||||||
"usbutils" # lsusb
|
"usbutils" # lsusb
|
||||||
"util-linux" # lsblk, lscpu, etc
|
"util-linux" # lsblk, lscpu, etc
|
||||||
"valgrind"
|
"valgrind"
|
||||||
"watch"
|
|
||||||
"wget"
|
"wget"
|
||||||
"wirelesstools" # iwlist
|
"wirelesstools" # iwlist
|
||||||
# "xq" # jq for XML
|
# "xq" # jq for XML
|
||||||
@@ -152,7 +148,7 @@ in
|
|||||||
# "ponymix"
|
# "ponymix"
|
||||||
"pulsemixer"
|
"pulsemixer"
|
||||||
"python3-repl"
|
"python3-repl"
|
||||||
# "python3.pkgs.eyeD3" # music tagging
|
# "python3Packages.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"
|
||||||
"sane-scripts.bittorrent"
|
"sane-scripts.bittorrent"
|
||||||
@@ -176,12 +172,8 @@ in
|
|||||||
# "gh" # MS GitHub cli
|
# "gh" # MS GitHub cli
|
||||||
"nix-index"
|
"nix-index"
|
||||||
"nixpkgs-review"
|
"nixpkgs-review"
|
||||||
"qmk-udev-rules"
|
|
||||||
"sane-scripts.dev"
|
"sane-scripts.dev"
|
||||||
"sequoia"
|
"sequoia"
|
||||||
# "via"
|
|
||||||
"wally-cli"
|
|
||||||
# "zsa-udev-rules"
|
|
||||||
];
|
];
|
||||||
|
|
||||||
consoleMediaUtils = declPackageSet [
|
consoleMediaUtils = declPackageSet [
|
||||||
@@ -248,7 +240,6 @@ in
|
|||||||
# "powermanga" # STYLISH space invaders derivative (keyboard-only)
|
# "powermanga" # STYLISH space invaders derivative (keyboard-only)
|
||||||
"shattered-pixel-dungeon" # doesn't cross compile
|
"shattered-pixel-dungeon" # doesn't cross compile
|
||||||
"space-cadet-pinball" # LMB/RMB controls (bindable though. volume buttons?)
|
"space-cadet-pinball" # LMB/RMB controls (bindable though. volume buttons?)
|
||||||
"steam"
|
|
||||||
"superTux" # keyboard-only controls
|
"superTux" # keyboard-only controls
|
||||||
"superTuxKart" # poor FPS on pinephone
|
"superTuxKart" # poor FPS on pinephone
|
||||||
"tumiki-fighters" # keyboard-only
|
"tumiki-fighters" # keyboard-only
|
||||||
@@ -281,28 +272,27 @@ in
|
|||||||
# "gnome.cheese"
|
# "gnome.cheese"
|
||||||
# "gnome-feeds" # RSS reader (with claimed mobile support)
|
# "gnome-feeds" # RSS reader (with claimed mobile support)
|
||||||
# "gnome.file-roller"
|
# "gnome.file-roller"
|
||||||
"geary" # adaptive e-mail client; uses webkitgtk 4.1
|
"gnome.geary" # adaptive e-mail client; uses webkitgtk 4.1
|
||||||
"gnome-calculator"
|
"gnome.gnome-calculator"
|
||||||
"gnome-calendar"
|
"gnome.gnome-calendar"
|
||||||
"gnome.gnome-clocks"
|
"gnome.gnome-clocks"
|
||||||
"gnome.gnome-maps"
|
"gnome.gnome-maps"
|
||||||
# "gnome-podcasts"
|
# "gnome-podcasts"
|
||||||
# "gnome.gnome-system-monitor"
|
# "gnome.gnome-system-monitor"
|
||||||
# "gnome.gnome-terminal" # works on phosh
|
# "gnome.gnome-terminal" # works on phosh
|
||||||
"gnome.gnome-weather"
|
"gnome.gnome-weather"
|
||||||
# "seahorse" # keyring/secret manager
|
# "gnome.seahorse" # keyring/secret manager
|
||||||
"gnome-frog" # OCR/QR decoder
|
"gnome-frog" # OCR/QR decoder
|
||||||
"gpodder"
|
"gpodder"
|
||||||
# "gst-device-monitor" # for debugging audio/video
|
"gst-device-monitor" # for debugging audio/video
|
||||||
# "gthumb"
|
# "gthumb"
|
||||||
# "lemoa" # lemmy app
|
# "lemoa" # lemmy app
|
||||||
# "libcamera" # for `cam` binary (useful for debugging cameras)
|
"libcamera" # for `cam` binary (useful for debugging cameras)
|
||||||
"libnotify" # for notify-send; debugging
|
"libnotify" # for notify-send; debugging
|
||||||
# "lollypop"
|
# "lollypop"
|
||||||
"loupe" # image viewer
|
"loupe" # image viewer
|
||||||
"mate.engrampa" # archive manager
|
"mate.engrampa" # archive manager
|
||||||
"mepo" # maps viewer
|
"mepo" # maps viewer
|
||||||
# "mesa-demos" # for eglinfo, glxinfo & other testing tools
|
|
||||||
"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
|
||||||
@@ -312,7 +302,7 @@ in
|
|||||||
# "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
|
||||||
@@ -327,7 +317,7 @@ in
|
|||||||
handheldGuiApps = declPackageSet [
|
handheldGuiApps = declPackageSet [
|
||||||
# "celluloid" # mpv frontend
|
# "celluloid" # mpv frontend
|
||||||
# "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
|
||||||
# "iotas" # note taking app
|
# "iotas" # note taking app
|
||||||
"komikku"
|
"komikku"
|
||||||
@@ -353,7 +343,7 @@ in
|
|||||||
# "chromium" # chromium takes hours to build. brave is chromium-based, distributed in binary form, so prefer it.
|
# "chromium" # chromium takes hours to build. brave is chromium-based, distributed in binary form, so prefer it.
|
||||||
# "cups"
|
# "cups"
|
||||||
"discord" # x86-only
|
"discord" # x86-only
|
||||||
# "electrum"
|
"electrum"
|
||||||
"element-desktop"
|
"element-desktop"
|
||||||
"firefox"
|
"firefox"
|
||||||
"font-manager"
|
"font-manager"
|
||||||
@@ -361,14 +351,13 @@ in
|
|||||||
"gimp" # broken on phosh
|
"gimp" # broken on phosh
|
||||||
# "gnome.dconf-editor"
|
# "gnome.dconf-editor"
|
||||||
# "gnome.file-roller"
|
# "gnome.file-roller"
|
||||||
"gnome-disk-utility"
|
"gnome.gnome-disk-utility"
|
||||||
"nautilus" # file browser
|
"gnome.nautilus" # file browser
|
||||||
# "gnome.totem" # video player, supposedly supports UPnP
|
# "gnome.totem" # video player, supposedly supports UPnP
|
||||||
# "handbrake" #< TODO: fix build
|
"handbrake"
|
||||||
"inkscape"
|
"inkscape"
|
||||||
# "jellyfin-media-player"
|
# "jellyfin-media-player"
|
||||||
"kdenlive"
|
"kdenlive"
|
||||||
# "keymapp"
|
|
||||||
# "kid3" # audio tagging
|
# "kid3" # audio tagging
|
||||||
"krita"
|
"krita"
|
||||||
"libreoffice" # TODO: replace with an office suite that uses saner packaging?
|
"libreoffice" # TODO: replace with an office suite that uses saner packaging?
|
||||||
@@ -384,6 +373,7 @@ in
|
|||||||
# "slic3r"
|
# "slic3r"
|
||||||
"soundconverter"
|
"soundconverter"
|
||||||
"spotify" # x86-only
|
"spotify" # x86-only
|
||||||
|
"steam"
|
||||||
"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
|
||||||
@@ -400,12 +390,6 @@ in
|
|||||||
|
|
||||||
backblaze-b2 = {};
|
backblaze-b2 = {};
|
||||||
|
|
||||||
bitcoind.sandbox.method = "bwrap";
|
|
||||||
bitcoind.sandbox.extraHomePaths = [
|
|
||||||
".config/bitcoin/bitcoin.conf"
|
|
||||||
];
|
|
||||||
bitcoind.sandbox.net = "all"; # actually needs only localhost
|
|
||||||
|
|
||||||
blanket.buildCost = 1;
|
blanket.buildCost = 1;
|
||||||
blanket.sandbox.method = "bwrap";
|
blanket.sandbox.method = "bwrap";
|
||||||
blanket.sandbox.whitelistAudio = true;
|
blanket.sandbox.whitelistAudio = true;
|
||||||
@@ -434,16 +418,6 @@ in
|
|||||||
|
|
||||||
clang = {};
|
clang = {};
|
||||||
|
|
||||||
clightning.sandbox.method = "bwrap";
|
|
||||||
clightning.sandbox.extraHomePaths = [
|
|
||||||
".lightning/bitcoin/lightning-rpc"
|
|
||||||
];
|
|
||||||
|
|
||||||
clightning-sane.sandbox.method = "bwrap";
|
|
||||||
clightning-sane.sandbox.extraPaths = [
|
|
||||||
"/var/lib/clightning/bitcoin/lightning-rpc"
|
|
||||||
];
|
|
||||||
|
|
||||||
# cryptsetup: typical use is `cryptsetup open /dev/loopxyz mappedName`, and creates `/dev/mapper/mappedName`
|
# cryptsetup: typical use is `cryptsetup open /dev/loopxyz mappedName`, and creates `/dev/mapper/mappedName`
|
||||||
cryptsetup.sandbox.method = "landlock";
|
cryptsetup.sandbox.method = "landlock";
|
||||||
cryptsetup.sandbox.extraPaths = [
|
cryptsetup.sandbox.extraPaths = [
|
||||||
@@ -596,6 +570,10 @@ in
|
|||||||
gawk.sandbox.wrapperType = "inplace"; # /share/gawk libraries refer to /libexec
|
gawk.sandbox.wrapperType = "inplace"; # /share/gawk libraries refer to /libexec
|
||||||
gawk.sandbox.autodetectCliPaths = "existingFile";
|
gawk.sandbox.autodetectCliPaths = "existingFile";
|
||||||
|
|
||||||
|
gdb.sandbox.enable = false; # gdb doesn't sandbox well. i don't know how you could.
|
||||||
|
# gdb.sandbox.method = "landlock"; # permission denied when trying to attach, even as root
|
||||||
|
gdb.sandbox.autodetectCliPaths = true;
|
||||||
|
|
||||||
geoclue2-with-demo-agent = {};
|
geoclue2-with-demo-agent = {};
|
||||||
|
|
||||||
# MS GitHub stores auth token in .config
|
# MS GitHub stores auth token in .config
|
||||||
@@ -622,37 +600,32 @@ in
|
|||||||
"/tmp" # "Cannot open display:" if it can't mount /tmp 👀
|
"/tmp" # "Cannot open display:" if it can't mount /tmp 👀
|
||||||
];
|
];
|
||||||
|
|
||||||
gnome-calculator.buildCost = 1;
|
"gnome.gnome-calculator".buildCost = 1;
|
||||||
gnome-calculator.sandbox.method = "bwrap";
|
"gnome.gnome-calculator".sandbox.method = "bwrap";
|
||||||
gnome-calculator.sandbox.whitelistWayland = true;
|
"gnome.gnome-calculator".sandbox.whitelistWayland = true;
|
||||||
|
|
||||||
gnome-calendar.buildCost = 1;
|
"gnome.gnome-calendar".buildCost = 1;
|
||||||
# gnome-calendar surely has data to persist, but i use it strictly to do date math, not track events.
|
# gnome-calendar surely has data to persist, but i use it strictly to do date math, not track events.
|
||||||
gnome-calendar.sandbox.method = "bwrap";
|
"gnome.gnome-calendar".sandbox.method = "bwrap";
|
||||||
gnome-calendar.sandbox.whitelistWayland = true;
|
"gnome.gnome-calendar".sandbox.whitelistWayland = true;
|
||||||
|
|
||||||
# gnome-disks
|
# gnome-disks
|
||||||
gnome-disk-utility.buildCost = 1;
|
"gnome.gnome-disk-utility".buildCost = 1;
|
||||||
gnome-disk-utility.sandbox.method = "bwrap";
|
"gnome.gnome-disk-utility".sandbox.method = "bwrap";
|
||||||
gnome-disk-utility.sandbox.whitelistDbus = [ "system" ];
|
"gnome.gnome-disk-utility".sandbox.whitelistDbus = [ "system" ];
|
||||||
gnome-disk-utility.sandbox.whitelistWayland = true;
|
"gnome.gnome-disk-utility".sandbox.whitelistWayland = true;
|
||||||
gnome-disk-utility.sandbox.extraHomePaths = [
|
"gnome.gnome-disk-utility".sandbox.extraHomePaths = [
|
||||||
"tmp"
|
"tmp"
|
||||||
"use/iso"
|
"use/iso"
|
||||||
# TODO: probably need /dev and such
|
# TODO: probably need /dev and such
|
||||||
];
|
];
|
||||||
|
|
||||||
hping.sandbox.method = "landlock";
|
|
||||||
hping.sandbox.net = "all";
|
|
||||||
hping.sandbox.capabilities = [ "net_raw" ];
|
|
||||||
hping.sandbox.autodetectCliPaths = "existingFile"; # for sending packet data from file
|
|
||||||
|
|
||||||
# seahorse: dump gnome-keyring secrets.
|
# seahorse: dump gnome-keyring secrets.
|
||||||
seahorse.buildCost = 1;
|
"gnome.seahorse".buildCost = 1;
|
||||||
# N.B. it can lso manage ~/.ssh keys, but i explicitly don't add those to the sandbox for now.
|
# N.B.: it can also manage ~/.ssh keys, but i explicitly don't add those to the sandbox for now.
|
||||||
seahorse.sandbox.method = "bwrap";
|
"gnome.seahorse".sandbox.method = "bwrap";
|
||||||
seahorse.sandbox.whitelistDbus = [ "user" ];
|
"gnome.seahorse".sandbox.whitelistDbus = [ "user" ];
|
||||||
seahorse.sandbox.whitelistWayland = true;
|
"gnome.seahorse".sandbox.whitelistWayland = true;
|
||||||
|
|
||||||
gnome-2048.buildCost = 1;
|
gnome-2048.buildCost = 1;
|
||||||
gnome-2048.sandbox.method = "bwrap";
|
gnome-2048.sandbox.method = "bwrap";
|
||||||
@@ -842,11 +815,6 @@ in
|
|||||||
mercurial.sandbox.net = "clearnet";
|
mercurial.sandbox.net = "clearnet";
|
||||||
mercurial.sandbox.whitelistPwd = true;
|
mercurial.sandbox.whitelistPwd = true;
|
||||||
|
|
||||||
mesa-demos.sandbox.method = "bwrap";
|
|
||||||
mesa-demos.sandbox.whitelistDri = true;
|
|
||||||
mesa-demos.sandbox.whitelistWayland = true;
|
|
||||||
mesa-demos.sandbox.whitelistX = true;
|
|
||||||
|
|
||||||
# actual monero blockchain (not wallet/etc; safe to delete, just slow to regenerate)
|
# actual monero blockchain (not wallet/etc; safe to delete, just slow to regenerate)
|
||||||
monero-gui.buildCost = 1;
|
monero-gui.buildCost = 1;
|
||||||
# XXX: is it really safe to persist this? it doesn't have info that could de-anonymize if captured?
|
# XXX: is it really safe to persist this? it doesn't have info that could de-anonymize if captured?
|
||||||
@@ -975,9 +943,7 @@ in
|
|||||||
|
|
||||||
python3-repl.packageUnwrapped = pkgs.python3.withPackages (ps: with ps; [
|
python3-repl.packageUnwrapped = pkgs.python3.withPackages (ps: with ps; [
|
||||||
psutil
|
psutil
|
||||||
pykakasi
|
|
||||||
requests
|
requests
|
||||||
unidecode
|
|
||||||
]);
|
]);
|
||||||
python3-repl.sandbox.method = "bwrap";
|
python3-repl.sandbox.method = "bwrap";
|
||||||
python3-repl.sandbox.net = "clearnet";
|
python3-repl.sandbox.net = "clearnet";
|
||||||
@@ -1051,9 +1017,7 @@ in
|
|||||||
"Music"
|
"Music"
|
||||||
"tmp"
|
"tmp"
|
||||||
"use"
|
"use"
|
||||||
".config/dconf"
|
|
||||||
];
|
];
|
||||||
soundconverter.sandbox.whitelistDbus = [ "user" ]; # for dconf
|
|
||||||
soundconverter.sandbox.extraPaths = [
|
soundconverter.sandbox.extraPaths = [
|
||||||
"/mnt/servo/media/Music"
|
"/mnt/servo/media/Music"
|
||||||
"/mnt/servo/media/games"
|
"/mnt/servo/media/games"
|
||||||
@@ -1133,6 +1097,9 @@ in
|
|||||||
valgrind.buildCost = 1;
|
valgrind.buildCost = 1;
|
||||||
valgrind.sandbox.enable = false; #< it's a launcher: can't sandbox
|
valgrind.sandbox.enable = false; #< it's a launcher: can't sandbox
|
||||||
|
|
||||||
|
visidata.sandbox.method = "bwrap"; # TODO:sandbox: untested
|
||||||
|
visidata.sandbox.autodetectCliPaths = true;
|
||||||
|
|
||||||
# `vulkaninfo`, `vkcube`
|
# `vulkaninfo`, `vkcube`
|
||||||
vulkan-tools.sandbox.method = "landlock";
|
vulkan-tools.sandbox.method = "landlock";
|
||||||
|
|
||||||
@@ -1150,8 +1117,6 @@ in
|
|||||||
"tmp"
|
"tmp"
|
||||||
];
|
];
|
||||||
|
|
||||||
watch.sandbox.enable = false; #< it executes the command it's given
|
|
||||||
|
|
||||||
wdisplays.sandbox.method = "bwrap";
|
wdisplays.sandbox.method = "bwrap";
|
||||||
wdisplays.sandbox.whitelistWayland = true;
|
wdisplays.sandbox.whitelistWayland = true;
|
||||||
|
|
||||||
@@ -1190,6 +1155,8 @@ in
|
|||||||
yt-dlp.sandbox.method = "bwrap"; # TODO:sandbox: untested
|
yt-dlp.sandbox.method = "bwrap"; # TODO:sandbox: untested
|
||||||
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
|
||||||
|
|
||||||
|
zfs = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
sane.persist.sys.byStore.plaintext = lib.mkIf config.sane.programs.guiApps.enabled [
|
sane.persist.sys.byStore.plaintext = lib.mkIf config.sane.programs.guiApps.enabled [
|
||||||
@@ -1206,12 +1173,13 @@ in
|
|||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
hardware.graphics = lib.mkIf config.sane.programs.guiApps.enabled ({
|
hardware.opengl = lib.mkIf config.sane.programs.guiApps.enabled ({
|
||||||
enable = true;
|
enable = true;
|
||||||
|
driSupport = lib.mkDefault true;
|
||||||
} // (lib.optionalAttrs pkgs.stdenv.isx86_64 {
|
} // (lib.optionalAttrs pkgs.stdenv.isx86_64 {
|
||||||
# for 32 bit applications
|
# for 32 bit applications
|
||||||
# upstream nixpkgs forbids setting enable32Bit unless specifically x86_64 (so aarch64 isn't allowed)
|
# upstream nixpkgs forbids setting driSupport32Bit unless specifically x86_64 (so aarch64 isn't allowed)
|
||||||
enable32Bit = lib.mkDefault true;
|
driSupport32Bit = lib.mkDefault true;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
system.activationScripts.notifyActive = lib.mkIf config.sane.programs.guiApps.enabled {
|
system.activationScripts.notifyActive = lib.mkIf config.sane.programs.guiApps.enabled {
|
||||||
|
@@ -1,42 +0,0 @@
|
|||||||
# Avahi zeroconf (mDNS) implementation.
|
|
||||||
# runs as systemd `avahi-daemon.service`
|
|
||||||
#
|
|
||||||
# - <https://avahi.org/>
|
|
||||||
# - code: <https://github.com/avahi/avahi>
|
|
||||||
# - IRC: #avahi on irc.libera.chat
|
|
||||||
#
|
|
||||||
# - `avahi-browse --help` for usage
|
|
||||||
# - `man avahi-daemon.conf`
|
|
||||||
# - `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
|
|
||||||
#
|
|
||||||
{ config, lib, ... }:
|
|
||||||
{
|
|
||||||
sane.programs.avahi = {
|
|
||||||
sandbox.method = "bwrap";
|
|
||||||
sandbox.whitelistDbus = [ "system" ];
|
|
||||||
sandbox.net = "all"; #< otherwise it will show 'null' in place of each interface name.
|
|
||||||
sandbox.extraPaths = [
|
|
||||||
"/" #< else the daemon exits immediately. TODO: decrease this scope.
|
|
||||||
];
|
|
||||||
};
|
|
||||||
services.avahi = lib.mkIf config.sane.programs.avahi.enabled {
|
|
||||||
enable = true;
|
|
||||||
package = config.sane.programs.avahi.package;
|
|
||||||
publish.enable = true;
|
|
||||||
publish.userServices = true;
|
|
||||||
nssmdns4 = true;
|
|
||||||
nssmdns6 = true;
|
|
||||||
# reflector = true;
|
|
||||||
allowInterfaces = [
|
|
||||||
# particularly, the default config disallows loopback, which is kinda fucking retarded, right?
|
|
||||||
"ens1" #< servo
|
|
||||||
"enp5s0" #< desko
|
|
||||||
"lo"
|
|
||||||
"wg-home"
|
|
||||||
"wlan0" #< moby
|
|
||||||
"wlp3s0" #< lappy
|
|
||||||
"wlp4s0" #< desko
|
|
||||||
];
|
|
||||||
};
|
|
||||||
}
|
|
@@ -95,7 +95,7 @@ in
|
|||||||
|
|
||||||
packageUnwrapped = pkgs.bemenu.overrideAttrs (upstream: {
|
packageUnwrapped = pkgs.bemenu.overrideAttrs (upstream: {
|
||||||
nativeBuildInputs = (upstream.nativeBuildInputs or []) ++ [
|
nativeBuildInputs = (upstream.nativeBuildInputs or []) ++ [
|
||||||
pkgs.makeBinaryWrapper
|
pkgs.makeWrapper
|
||||||
];
|
];
|
||||||
# can alternatively be specified as CLI flags
|
# can alternatively be specified as CLI flags
|
||||||
postInstall = (upstream.postInstall or "") + ''
|
postInstall = (upstream.postInstall or "") + ''
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env nix-shell
|
#!/usr/bin/env nix-shell
|
||||||
#!nix-shell -i python3 -p blast-ugjka -p python3
|
#!nix-shell -i python3 -p "python3.withPackages (ps: [ ])" -p blast-ugjka
|
||||||
# vim: set filetype=python :
|
# vim: set filetype=python :
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
@@ -31,7 +31,7 @@ in
|
|||||||
|
|
||||||
sane.programs.blast-to-default = {
|
sane.programs.blast-to-default = {
|
||||||
# helper to deal with blast's interactive CLI
|
# helper to deal with blast's interactive CLI
|
||||||
packageUnwrapped = pkgs.static-nix-shell.mkPython3 {
|
packageUnwrapped = pkgs.static-nix-shell.mkPython3Bin {
|
||||||
pname = "blast-to-default";
|
pname = "blast-to-default";
|
||||||
pkgs = [ "blast-ugjka" ];
|
pkgs = [ "blast-ugjka" ];
|
||||||
srcRoot = ./.;
|
srcRoot = ./.;
|
||||||
|
@@ -111,7 +111,7 @@ in
|
|||||||
'';
|
'';
|
||||||
});
|
});
|
||||||
|
|
||||||
fs.".config/bonsai/bonsai_tree.json".symlink.target = pkgs.writers.writeJSON "bonsai_tree.json" cfg.config.transitions;
|
fs.".config/bonsai/bonsai_tree.json".symlink.text = builtins.toJSON cfg.config.transitions;
|
||||||
|
|
||||||
sandbox.method = "bwrap";
|
sandbox.method = "bwrap";
|
||||||
sandbox.extraRuntimePaths = [
|
sandbox.extraRuntimePaths = [
|
||||||
|
@@ -1,12 +1,6 @@
|
|||||||
{ pkgs, ... }:
|
{ ... }:
|
||||||
{
|
{
|
||||||
sane.programs.brave = {
|
sane.programs.brave = {
|
||||||
# convert eval error to build failure
|
|
||||||
packageUnwrapped = if (builtins.tryEval pkgs.brave).success then
|
|
||||||
pkgs.brave
|
|
||||||
else
|
|
||||||
pkgs.runCommandLocal "brave-not-supported" {} "false"
|
|
||||||
;
|
|
||||||
sandbox.method = "bwrap";
|
sandbox.method = "bwrap";
|
||||||
sandbox.wrapperType = "inplace"; # /opt/share/brave.com vendor-style packaging
|
sandbox.wrapperType = "inplace"; # /opt/share/brave.com vendor-style packaging
|
||||||
sandbox.net = "all";
|
sandbox.net = "all";
|
||||||
|
@@ -13,7 +13,7 @@
|
|||||||
sane.programs.callaudiod = {
|
sane.programs.callaudiod = {
|
||||||
packageUnwrapped = pkgs.rmDbusServices pkgs.callaudiod;
|
packageUnwrapped = pkgs.rmDbusServices pkgs.callaudiod;
|
||||||
|
|
||||||
sandbox.method = "bwrap";
|
# probably more needed once i enable proper sandboxing, but for now this ensures the service isn't started too early!
|
||||||
sandbox.whitelistAudio = true;
|
sandbox.whitelistAudio = true;
|
||||||
sandbox.whitelistDbus = [ "user" ];
|
sandbox.whitelistDbus = [ "user" ];
|
||||||
|
|
||||||
|
@@ -24,7 +24,7 @@ in
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
packageUnwrapped = pkgs.rmDbusServicesInPlace (pkgs.calls.overrideAttrs (upstream: {
|
packageUnwrapped = pkgs.calls.overrideAttrs (upstream: {
|
||||||
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,10 +33,10 @@ in
|
|||||||
hash = "sha256-NoVQV2TlkCcsBt0uwSyK82hBKySUW4pADrJVfLFvWgU=";
|
hash = "sha256-NoVQV2TlkCcsBt0uwSyK82hBKySUW4pADrJVfLFvWgU=";
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
}));
|
});
|
||||||
|
|
||||||
sandbox.method = "bwrap";
|
sandbox.method = "bwrap";
|
||||||
sandbox.net = "vpn.wg-home"; #< XXX(2024/07/05): my cell carrier seems to block RTP, so tunnel it.
|
sandbox.net = "clearnet";
|
||||||
sandbox.whitelistAudio = true;
|
sandbox.whitelistAudio = true;
|
||||||
sandbox.whitelistDbus = [ "user" ]; # necessary for secrets, at the minimum
|
sandbox.whitelistDbus = [ "user" ]; # necessary for secrets, at the minimum
|
||||||
sandbox.whitelistWayland = true;
|
sandbox.whitelistWayland = true;
|
||||||
|
@@ -66,7 +66,6 @@ end
|
|||||||
if vars.percent ~= nil then
|
if vars.percent ~= nil then
|
||||||
bat_args = bat_args .. " --percent-suffix '" .. vars.percent .. "'"
|
bat_args = bat_args .. " --percent-suffix '" .. vars.percent .. "'"
|
||||||
end
|
end
|
||||||
bat_args = bat_args .. " {bat}"
|
|
||||||
|
|
||||||
-- N.B.: `[[ <text> ]]` is Lua's multiline string literal
|
-- N.B.: `[[ <text> ]]` is Lua's multiline string literal
|
||||||
conky.text = [[
|
conky.text = [[
|
||||||
@@ -74,8 +73,8 @@ ${color1}${shadecolor 707070}${font sans-serif:size=50:style=Bold}${alignc}${exe
|
|||||||
${color2}${shadecolor a4d7d0}${font sans-serif:size=20}${alignc}${exec date +"%a %d %b"}${font}
|
${color2}${shadecolor a4d7d0}${font sans-serif:size=20}${alignc}${exec date +"%a %d %b"}${font}
|
||||||
|
|
||||||
|
|
||||||
${color1}${shadecolor}${font sans-serif:size=22:style=Bold}${alignc}${execp sane-sysload ]] .. bat_args .. [[ }${font}
|
${color1}${shadecolor}${font sans-serif:size=22:style=Bold}${alignc}${execp @bat@ ]] .. bat_args .. [[ }${font}
|
||||||
${color1}${shadecolor}${font sans-serif:size=20:style=Bold}${alignc}${texeci 600 timeout 20 sane-weather }${font}
|
${color1}${shadecolor}${font sans-serif:size=20:style=Bold}${alignc}${texeci 600 @weather@ }${font}
|
||||||
|
|
||||||
|
|
||||||
${color2}${shadecolor a4d7d0}${font sans-serif:size=16}${alignc}⇅ ${downspeedf wlan0}]] .. vars.kBps .. [[${font}
|
${color2}${shadecolor a4d7d0}${font sans-serif:size=16}${alignc}⇅ ${downspeedf wlan0}]] .. vars.kBps .. [[${font}
|
||||||
|
@@ -1,22 +1,38 @@
|
|||||||
{ pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
{
|
{
|
||||||
|
sane.programs.sane-battery-estimate = {
|
||||||
|
packageUnwrapped = pkgs.static-nix-shell.mkBash {
|
||||||
|
pname = "sane-battery-estimate";
|
||||||
|
srcRoot = ./.;
|
||||||
|
};
|
||||||
|
sandbox.method = "bwrap";
|
||||||
|
sandbox.extraPaths = [
|
||||||
|
"/sys/class/power_supply"
|
||||||
|
"/sys/devices"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
sane.programs.conky = {
|
sane.programs.conky = {
|
||||||
sandbox.method = "bwrap";
|
sandbox.method = "bwrap";
|
||||||
sandbox.net = "clearnet"; #< for the scripts it calls (weather)
|
sandbox.net = "clearnet"; #< for the scripts it calls (weather)
|
||||||
sandbox.extraPaths = [
|
sandbox.extraPaths = [
|
||||||
"/sys/class/power_supply"
|
"/sys/class/power_supply"
|
||||||
"/sys/devices" # needed by sane-sysload
|
"/sys/devices" # needed by battery_estimate
|
||||||
# "/sys/devices/cpu"
|
# "/sys/devices/cpu"
|
||||||
# "/sys/devices/system"
|
# "/sys/devices/system"
|
||||||
];
|
];
|
||||||
sandbox.whitelistWayland = true;
|
sandbox.whitelistWayland = true;
|
||||||
|
|
||||||
suggestedPrograms = [
|
suggestedPrograms = [
|
||||||
"sane-sysload"
|
"sane-battery-estimate"
|
||||||
"sane-weather"
|
"sane-weather"
|
||||||
];
|
];
|
||||||
|
|
||||||
fs.".config/conky/conky.conf".symlink.target = ./conky.conf;
|
fs.".config/conky/conky.conf".symlink.target = pkgs.substituteAll {
|
||||||
|
src = ./conky.conf;
|
||||||
|
bat = "sane-battery-estimate";
|
||||||
|
weather = "timeout 20 sane-weather";
|
||||||
|
};
|
||||||
|
|
||||||
services.conky = {
|
services.conky = {
|
||||||
description = "conky dynamic desktop background";
|
description = "conky dynamic desktop background";
|
||||||
|
183
hosts/common/programs/conky/sane-battery-estimate
Executable file
183
hosts/common/programs/conky/sane-battery-estimate
Executable file
@@ -0,0 +1,183 @@
|
|||||||
|
#!/usr/bin/env nix-shell
|
||||||
|
#!nix-shell -i bash
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
echo "usage: battery_estimate [options...]"
|
||||||
|
echo
|
||||||
|
echo "pretty-prints a battery estimate (icon to indicate state, and a duration estimate)"
|
||||||
|
echo
|
||||||
|
echo "options:"
|
||||||
|
echo " --debug: output additional information, to stderr"
|
||||||
|
echo " --minute-suffix <string>: use the provided string as a minutes suffix"
|
||||||
|
echo " --hour-suffix <string>: use the provided string as an hours suffix"
|
||||||
|
echo " --icon-suffix <string>: use the provided string as an icon suffix"
|
||||||
|
echo " --percent-suffix <string>: use the provided string when displaying percents"
|
||||||
|
}
|
||||||
|
|
||||||
|
# these icons may only render in nerdfonts
|
||||||
|
icon_bat_chg=("" "" "" "")
|
||||||
|
icon_bat_dis=("" "" "" "")
|
||||||
|
suffix_icon=" " # thin space
|
||||||
|
suffix_percent="%"
|
||||||
|
# suffix_icon=" "
|
||||||
|
|
||||||
|
# render time like: 2ʰ08ᵐ
|
||||||
|
# unicode sub/super-scripts: <https://en.wikipedia.org/wiki/Unicode_subscripts_and_superscripts>
|
||||||
|
# symbol_hr="ʰ"
|
||||||
|
# symbol_min="ᵐ"
|
||||||
|
|
||||||
|
# render time like: 2ₕ08ₘ
|
||||||
|
# symbol_hr="ₕ"
|
||||||
|
# symbol_min="ₘ"
|
||||||
|
|
||||||
|
# render time like: 2h08m
|
||||||
|
# symbol_hr="h"
|
||||||
|
# symbol_min="m"
|
||||||
|
|
||||||
|
# render time like: 2:08
|
||||||
|
# symbol_hr=":"
|
||||||
|
# symbol_min=
|
||||||
|
|
||||||
|
# render time like: 2꞉08⧗
|
||||||
|
symbol_hr="꞉"
|
||||||
|
symbol_min="⧗"
|
||||||
|
# variants:
|
||||||
|
# symbol_hr=":"
|
||||||
|
# symbol_min="⧖"
|
||||||
|
# symbol_min="⌛"
|
||||||
|
|
||||||
|
# render time like: 2'08"
|
||||||
|
# symbol_hr="'"
|
||||||
|
# symbol_min='"'
|
||||||
|
|
||||||
|
log() {
|
||||||
|
if [ "$BATTERY_ESTIMATE_DEBUG" = "1" ]; then
|
||||||
|
printf "$@" >&2
|
||||||
|
echo >&2
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
render_icon() {
|
||||||
|
# args:
|
||||||
|
# 1: "chg" or "dis"
|
||||||
|
# 2: current battery percentage
|
||||||
|
level=$(($2 / 25))
|
||||||
|
level=$(($level > 3 ? 3 : $level))
|
||||||
|
level=$(($level < 0 ? 0 : $level))
|
||||||
|
log "icon: %s %d" "$1" "$level"
|
||||||
|
if [ "$1" = "dis" ]; then
|
||||||
|
printf "%s" "${icon_bat_dis[$level]}"
|
||||||
|
elif [ "$1" = "chg" ]; then
|
||||||
|
printf "%s" "${icon_bat_chg[$level]}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
try_path() {
|
||||||
|
# assigns output variables:
|
||||||
|
# - perc, perc_from_full (0-100)
|
||||||
|
# - full, rate (pos means charging)
|
||||||
|
if [ -f "$1/capacity" ]; then
|
||||||
|
log "perc, perc_from_full from %s" "$1/capacity"
|
||||||
|
perc=$(cat "$1/capacity")
|
||||||
|
perc_from_full=$((100 - $perc))
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "$1/charge_full_design" ] && [ -f "$1/current_now" ]; then
|
||||||
|
log "full, rate from %s and %s" "$1/charge_full_design" "$1/current_now"
|
||||||
|
# current is positive when charging
|
||||||
|
full=$(cat "$1/charge_full_design")
|
||||||
|
rate=$(cat "$1/current_now")
|
||||||
|
elif [ -f "$1/energy_full" ] && [ -f "$1/power_now" ]; then
|
||||||
|
log "full, rate from %s and %s" "$1/energy_full" "$1/power_now"
|
||||||
|
# power_now is positive when discharging
|
||||||
|
full=$(cat "$1/energy_full")
|
||||||
|
rate=-$(cat "$1/power_now")
|
||||||
|
elif [ -f "$1/energy_full" ] && [ -f "$1/energy_now" ]; then
|
||||||
|
log "full, rate from %s and %s" "$1/energy_full" "$1/energy_now"
|
||||||
|
log " this is a compatibility path for legacy Thinkpad batteries which do not populate the 'power_now' field, and incorrectly populate 'energy_now' with power info"
|
||||||
|
# energy_now is positive when discharging
|
||||||
|
full=$(cat "$1/energy_full")
|
||||||
|
rate=-$(cat "$1/energy_now")
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
try_all_paths() {
|
||||||
|
try_path "/sys/class/power_supply/axp20x-battery" # Pinephone
|
||||||
|
try_path "/sys/class/power_supply/BAT0" # Thinkpad
|
||||||
|
log "perc: %d, perc_from_full: %d" "$perc" "$perc_from_full"
|
||||||
|
log "full: %f, rate: %f" "$full" "$rate"
|
||||||
|
log " rate > 0 means charging, else discharging"
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt_minutes() {
|
||||||
|
# args:
|
||||||
|
# 1: icon to render
|
||||||
|
# 2: string to show if charge/discharge time is indefinite
|
||||||
|
# 3: minutes to stable state (i.e. to full charge or full discharge)
|
||||||
|
# - we work in minutes instead of hours for precision: bash math is integer-only
|
||||||
|
log "charge/discharge time: %f min" "$3"
|
||||||
|
# args: <battery symbol> <text if ludicrous estimate> <estimated minutes to full/empty>
|
||||||
|
if [ -n "$3" ] && [ "$3" -lt 1440 ]; then
|
||||||
|
hr=$(($3 / 60))
|
||||||
|
hr_in_min=$(($hr * 60))
|
||||||
|
min=$(($3 - $hr_in_min))
|
||||||
|
printf "%s%s%d%s%02d%s" "$1" "$suffix_icon" "$hr" "$symbol_hr" "$min" "$symbol_min"
|
||||||
|
else
|
||||||
|
log "charge/discharge duration > 1d"
|
||||||
|
printf "%s%s%s" "$1" "$suffix_icon" "$2" # more than 1d
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
pretty_output() {
|
||||||
|
if [ -n "$perc" ]; then
|
||||||
|
duration=""
|
||||||
|
if [ "$rate" -gt 0 ]; then
|
||||||
|
log "charging"
|
||||||
|
icon="$(render_icon chg $perc)"
|
||||||
|
duration="$(($full * 60 * $perc_from_full / (100 * $rate)))"
|
||||||
|
else
|
||||||
|
log "discharging"
|
||||||
|
icon="$(render_icon dis $perc)"
|
||||||
|
if [ "$rate" -lt 0 ]; then
|
||||||
|
duration="$(($full * 60 * $perc / (-100 * $rate)))"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fmt_minutes "$icon" "$perc$suffix_percent" "$duration"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
while [ "$#" -gt 0 ]; do
|
||||||
|
case "$1" in
|
||||||
|
"--debug")
|
||||||
|
shift
|
||||||
|
BATTERY_ESTIMATE_DEBUG=1
|
||||||
|
;;
|
||||||
|
"--icon-suffix")
|
||||||
|
shift
|
||||||
|
suffix_icon="$1"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
"--hour-suffix")
|
||||||
|
shift
|
||||||
|
symbol_hr="$1"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
"--minute-suffix")
|
||||||
|
shift
|
||||||
|
symbol_min="$1"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
"--percent-suffix")
|
||||||
|
shift
|
||||||
|
suffix_percent="$1"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
try_all_paths
|
||||||
|
pretty_output
|
@@ -10,7 +10,6 @@
|
|||||||
./assorted.nix
|
./assorted.nix
|
||||||
./audacity.nix
|
./audacity.nix
|
||||||
./ausyscall.nix
|
./ausyscall.nix
|
||||||
./avahi.nix
|
|
||||||
./bemenu.nix
|
./bemenu.nix
|
||||||
./blast-ugjka
|
./blast-ugjka
|
||||||
./bonsai.nix
|
./bonsai.nix
|
||||||
@@ -46,16 +45,12 @@
|
|||||||
./flare-signal.nix
|
./flare-signal.nix
|
||||||
./fontconfig.nix
|
./fontconfig.nix
|
||||||
./fractal.nix
|
./fractal.nix
|
||||||
./free.nix
|
|
||||||
./frozen-bubble.nix
|
./frozen-bubble.nix
|
||||||
./fwupd.nix
|
./fwupd.nix
|
||||||
./g4music.nix
|
./g4music.nix
|
||||||
./gajim.nix
|
./gajim.nix
|
||||||
./gdb.nix
|
|
||||||
./gdbus.nix
|
./gdbus.nix
|
||||||
./geary.nix
|
./geary.nix
|
||||||
./geoclue-demo-agent.nix
|
|
||||||
./geoclue2.nix
|
|
||||||
./git.nix
|
./git.nix
|
||||||
./gnome-clocks.nix
|
./gnome-clocks.nix
|
||||||
./gnome-feeds.nix
|
./gnome-feeds.nix
|
||||||
@@ -64,8 +59,6 @@
|
|||||||
./gnome-weather.nix
|
./gnome-weather.nix
|
||||||
./go2tv.nix
|
./go2tv.nix
|
||||||
./gpodder.nix
|
./gpodder.nix
|
||||||
./gpsd.nix
|
|
||||||
./gps-share.nix
|
|
||||||
./grimshot.nix
|
./grimshot.nix
|
||||||
./gst-device-monitor.nix
|
./gst-device-monitor.nix
|
||||||
./gthumb.nix
|
./gthumb.nix
|
||||||
@@ -73,11 +66,9 @@
|
|||||||
./handbrake.nix
|
./handbrake.nix
|
||||||
./helix.nix
|
./helix.nix
|
||||||
./htop
|
./htop
|
||||||
./iio-sensor-proxy.nix
|
|
||||||
./imagemagick.nix
|
./imagemagick.nix
|
||||||
./jellyfin-media-player.nix
|
./jellyfin-media-player.nix
|
||||||
./kdenlive.nix
|
./kdenlive.nix
|
||||||
./keymapp.nix
|
|
||||||
./komikku.nix
|
./komikku.nix
|
||||||
./koreader
|
./koreader
|
||||||
./less.nix
|
./less.nix
|
||||||
@@ -95,7 +86,6 @@
|
|||||||
./msmtp.nix
|
./msmtp.nix
|
||||||
./nautilus.nix
|
./nautilus.nix
|
||||||
./neovim.nix
|
./neovim.nix
|
||||||
./networkmanager_dmenu
|
|
||||||
./newsflash.nix
|
./newsflash.nix
|
||||||
./nheko.nix
|
./nheko.nix
|
||||||
./nicotine-plus.nix
|
./nicotine-plus.nix
|
||||||
@@ -103,21 +93,14 @@
|
|||||||
./nmcli.nix
|
./nmcli.nix
|
||||||
./notejot.nix
|
./notejot.nix
|
||||||
./ntfy-sh.nix
|
./ntfy-sh.nix
|
||||||
./nwg-panel
|
|
||||||
./objdump.nix
|
./objdump.nix
|
||||||
./obsidian.nix
|
./obsidian.nix
|
||||||
./offlineimap.nix
|
./offlineimap.nix
|
||||||
./ols.nix
|
|
||||||
./open-in-mpv.nix
|
./open-in-mpv.nix
|
||||||
./pactl.nix
|
|
||||||
./pidof.nix
|
|
||||||
./pipewire.nix
|
./pipewire.nix
|
||||||
./pkill.nix
|
|
||||||
./planify.nix
|
./planify.nix
|
||||||
./portfolio-filemanager.nix
|
./portfolio-filemanager.nix
|
||||||
./playerctl.nix
|
./playerctl.nix
|
||||||
./ps.nix
|
|
||||||
./qmk-udev-rules.nix
|
|
||||||
./rhythmbox.nix
|
./rhythmbox.nix
|
||||||
./ripgrep.nix
|
./ripgrep.nix
|
||||||
./rofi
|
./rofi
|
||||||
@@ -127,10 +110,8 @@
|
|||||||
./sane-open.nix
|
./sane-open.nix
|
||||||
./sane-screenshot.nix
|
./sane-screenshot.nix
|
||||||
./sane-scripts.nix
|
./sane-scripts.nix
|
||||||
./sane-sysload.nix
|
|
||||||
./sane-theme.nix
|
./sane-theme.nix
|
||||||
./sanebox.nix
|
./sanebox.nix
|
||||||
./satellite.nix
|
|
||||||
./schlock.nix
|
./schlock.nix
|
||||||
./seatd.nix
|
./seatd.nix
|
||||||
./sfeed.nix
|
./sfeed.nix
|
||||||
@@ -149,19 +130,14 @@
|
|||||||
./swayidle.nix
|
./swayidle.nix
|
||||||
./swaylock.nix
|
./swaylock.nix
|
||||||
./swaynotificationcenter
|
./swaynotificationcenter
|
||||||
./switchboard.nix
|
./sysvol.nix
|
||||||
./syshud.nix
|
|
||||||
./tangram.nix
|
./tangram.nix
|
||||||
./tor-browser.nix
|
./tor-browser.nix
|
||||||
./tuba.nix
|
./tuba.nix
|
||||||
./unl0kr
|
./unl0kr
|
||||||
./via.nix
|
|
||||||
./visidata.nix
|
|
||||||
./vlc.nix
|
./vlc.nix
|
||||||
./wally-cli.nix
|
|
||||||
./waybar
|
./waybar
|
||||||
./waylock.nix
|
./waylock.nix
|
||||||
./where-am-i.nix
|
|
||||||
./wike.nix
|
./wike.nix
|
||||||
./wine.nix
|
./wine.nix
|
||||||
./wireplumber.nix
|
./wireplumber.nix
|
||||||
@@ -177,8 +153,6 @@
|
|||||||
./zeal.nix
|
./zeal.nix
|
||||||
./zecwallet-lite.nix
|
./zecwallet-lite.nix
|
||||||
./zulip.nix
|
./zulip.nix
|
||||||
./zsa-udev-rules.nix
|
|
||||||
./zfs-tools.nix
|
|
||||||
./zsh
|
./zsh
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@@ -50,13 +50,32 @@ in
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
packageUnwrapped = pkgs.dino.override {
|
packageUnwrapped = (pkgs.dino.override {
|
||||||
# XXX(2024/04/24): build without echo cancelation (i.e. force WITH_VOICE_PROCESSOR to be undefined).
|
# XXX(2024/04/24): build without echo cancelation (i.e. force WITH_VOICE_PROCESSOR to be undefined).
|
||||||
# this means that if the other end of the call is on speaker phone, i'm liable to hear my own voice
|
# this means that if the other end of the call is on speaker phone, i'm liable to hear my own voice
|
||||||
# leave their speaker, enter their mic, and then return to me.
|
# leave their speaker, enter their mic, and then return to me.
|
||||||
# the benefit is a >50% reduction in CPU use. insignificant on any modern PC; make-or-break on a low-power Pinephone.
|
# the benefit is a >50% reduction in CPU use. insignificant on any modern PC; make-or-break on a low-power Pinephone.
|
||||||
webrtc-audio-processing = null;
|
webrtc-audio-processing = null;
|
||||||
};
|
}).overrideAttrs (upstream: {
|
||||||
|
# i'm updating experimentally to see if it improves call performance.
|
||||||
|
# i don't *think* this is actually necessary; i don't notice any difference.
|
||||||
|
version = "0.4.3-unstable-2024-04-28";
|
||||||
|
src = lib.warnIf (lib.versionOlder "0.4.3" upstream.version) "dino update: safe to remove sane patches" pkgs.fetchFromGitHub {
|
||||||
|
owner = "dino";
|
||||||
|
repo = "dino";
|
||||||
|
rev = "657502955567dd538e56f300e075c7db52e25d74";
|
||||||
|
hash = "sha256-SApJy9FgxxLOB5A/zGtpdFZtSqSiS03vggRrCte1tFE=";
|
||||||
|
};
|
||||||
|
# avoid double-application of upstreamed patches
|
||||||
|
# https://github.com/NixOS/nixpkgs/pull/309265
|
||||||
|
patches = [];
|
||||||
|
checkPhase = ''
|
||||||
|
runHook preCheck
|
||||||
|
./xmpp-vala-test
|
||||||
|
# ./signal-protocol-vala-test # doesn't exist anymore
|
||||||
|
runHook postCheck
|
||||||
|
'';
|
||||||
|
});
|
||||||
|
|
||||||
sandbox.method = "bwrap";
|
sandbox.method = "bwrap";
|
||||||
sandbox.net = "clearnet";
|
sandbox.net = "clearnet";
|
||||||
|
@@ -6,17 +6,6 @@ in
|
|||||||
sane.programs.eg25-control = {
|
sane.programs.eg25-control = {
|
||||||
suggestedPrograms = [ "mmcli" ];
|
suggestedPrograms = [ "mmcli" ];
|
||||||
|
|
||||||
sandbox.method = "bwrap";
|
|
||||||
sandbox.extraPaths = [
|
|
||||||
"/sys/class/modem-power"
|
|
||||||
"/sys/devices"
|
|
||||||
# "/var/lib/eg25-control"
|
|
||||||
];
|
|
||||||
sandbox.net = "all"; #< for downloading the almanac
|
|
||||||
sandbox.whitelistDbus = [
|
|
||||||
"system" #< used by `mmcli`
|
|
||||||
];
|
|
||||||
|
|
||||||
services.eg25-control-powered = {
|
services.eg25-control-powered = {
|
||||||
description = "eg25-control-powered: power to the Qualcomm eg25 modem used by PinePhone";
|
description = "eg25-control-powered: power to the Qualcomm eg25 modem used by PinePhone";
|
||||||
startCommand = "eg25-control --power-on --verbose";
|
startCommand = "eg25-control --power-on --verbose";
|
||||||
|
@@ -55,7 +55,7 @@ in
|
|||||||
# - theme-demo
|
# - theme-demo
|
||||||
# - timeout-completed
|
# - timeout-completed
|
||||||
# - window-close
|
# - window-close
|
||||||
fs.".config/feedbackd/themes/proxied.json".symlink.target = pkgs.writers.writeJSON "proxied.json" {
|
fs.".config/feedbackd/themes/proxied.json".symlink.text = builtins.toJSON {
|
||||||
name = "proxied";
|
name = "proxied";
|
||||||
parent-theme = "default";
|
parent-theme = "default";
|
||||||
profiles = [
|
profiles = [
|
||||||
|
@@ -1,9 +0,0 @@
|
|||||||
{ pkgs, ... }:
|
|
||||||
{
|
|
||||||
sane.programs.free = {
|
|
||||||
packageUnwrapped = pkgs.linkIntoOwnPackage pkgs.procps "bin/free";
|
|
||||||
sandbox.method = "bwrap";
|
|
||||||
sandbox.isolatePids = false;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
@@ -1,13 +0,0 @@
|
|||||||
{ pkgs, ... }:
|
|
||||||
{
|
|
||||||
sane.programs.gdb = {
|
|
||||||
sandbox.enable = false; # gdb doesn't sandbox well. i don't know how you could.
|
|
||||||
# sandbox.method = "landlock"; # permission denied when trying to attach, even as root
|
|
||||||
sandbox.autodetectCliPaths = true;
|
|
||||||
fs.".config/gdb/gdbinit".symlink.text = ''
|
|
||||||
# enable commands like `py-bt`, `py-list`, etc.
|
|
||||||
# for usage, see: <https://wiki.python.org/moin/DebuggingWithGdb>
|
|
||||||
source ${pkgs.python3}/share/gdb/libpython.py
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
}
|
|
@@ -5,10 +5,10 @@
|
|||||||
# <https://gitlab.gnome.org/GNOME/geary/-/issues/1212>
|
# <https://gitlab.gnome.org/GNOME/geary/-/issues/1212>
|
||||||
{ config, lib, ... }:
|
{ config, lib, ... }:
|
||||||
let
|
let
|
||||||
cfg = config.sane.programs."geary";
|
cfg = config.sane.programs."gnome.geary";
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
sane.programs."geary" = {
|
sane.programs."gnome.geary" = {
|
||||||
configOption = with lib; mkOption {
|
configOption = with lib; mkOption {
|
||||||
default = {};
|
default = {};
|
||||||
type = types.submodule {
|
type = types.submodule {
|
||||||
|
@@ -1,23 +0,0 @@
|
|||||||
{ config, pkgs, ... }:
|
|
||||||
{
|
|
||||||
sane.programs.geoclue-demo-agent = {
|
|
||||||
packageUnwrapped = pkgs.linkFarm "geoclue-demo-agent" [{
|
|
||||||
# bring the demo agent into a `bin/` directory so it can be invokable via PATH
|
|
||||||
name = "bin/geoclue-demo-agent";
|
|
||||||
path = "${config.sane.programs.geoclue2.packageUnwrapped}/libexec/geoclue-2.0/demos/agent";
|
|
||||||
}];
|
|
||||||
|
|
||||||
sandbox.method = "bwrap";
|
|
||||||
sandbox.whitelistDbus = [
|
|
||||||
"system"
|
|
||||||
];
|
|
||||||
|
|
||||||
services.geoclue-agent = {
|
|
||||||
description = "geoclue 'demo' agent";
|
|
||||||
# XXX: i don't actually understand how this works: upstream dbus rules would appear to restrict
|
|
||||||
# the dbus owner to just root/geoclue, but we're neither and this still works (and breaks if i remove the agent service!)
|
|
||||||
command = "geoclue-demo-agent";
|
|
||||||
partOf = [ "graphical-session" ];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
@@ -1,76 +0,0 @@
|
|||||||
# geoclue location services daemon.
|
|
||||||
#
|
|
||||||
# SUPPORT:
|
|
||||||
# - irc: #gnome-maps on irc.gimp.org
|
|
||||||
# - Matrix: #gnome-maps:gnome.org (unclear if bridged to IRC)
|
|
||||||
# - forums: <https://discourse.gnome.org/c/platform>
|
|
||||||
# - git: <https://gitlab.freedesktop.org/geoclue/geoclue/>
|
|
||||||
# - D-Bus API docs: <https://www.freedesktop.org/software/geoclue/docs/>
|
|
||||||
#
|
|
||||||
# HOW TO TEST:
|
|
||||||
# - just invoke `where-am-i`: it should output the current latitude/longitude.
|
|
||||||
## more manual testing:
|
|
||||||
# - build `geoclue2-with-demo-agent`
|
|
||||||
# - run the service: `systemctl start geoclue` or "${geoclue2-with-demo-agent}/libexec/geoclue"
|
|
||||||
# - run "${geoclue2-with-demo-agent}/libexec/geoclue-2.0/demos/agent"
|
|
||||||
# - keep this running in the background
|
|
||||||
# - run "${geoclue2-with-demo-agent}/libexec/geoclue-2.0/demos/where-am-i"
|
|
||||||
#
|
|
||||||
# DATA FLOW:
|
|
||||||
# - geoclue2 does http calls into local `ols`, which either hits the local disk or queries https://wigle.net.
|
|
||||||
# - geoclue users like gnome-maps somehow depend on an "agent",
|
|
||||||
# a user service which launches the geoclue system service on-demand (via dbus activation).
|
|
||||||
#
|
|
||||||
{ config, lib, pkgs, ... }:
|
|
||||||
let
|
|
||||||
cfg = config.sane.programs.geoclue2;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
sane.programs.geoclue2 = {
|
|
||||||
# packageUnwrapped = pkgs.rmDbusServices pkgs.geoclue2;
|
|
||||||
# packageUnwrapped = pkgs.geoclue2.override { withDemoAgent = true; };
|
|
||||||
packageUnwrapped = pkgs.geoclue2-with-demo-agent;
|
|
||||||
suggestedPrograms = [
|
|
||||||
"avahi" #< to discover LAN gps devices
|
|
||||||
"geoclue-demo-agent"
|
|
||||||
# "gps-share"
|
|
||||||
"iio-sensor-proxy"
|
|
||||||
"ols" #< WiFi SSID -> lat/long lookups
|
|
||||||
"satellite" #< graphical view into GPS fix data
|
|
||||||
"where-am-i" #< handy debugging/testing tool
|
|
||||||
];
|
|
||||||
|
|
||||||
# XXX(2024/07/05): no way to plumb my sandboxed geoclue into `services.geoclue2`.
|
|
||||||
# then, the package doesn't get used directly anywhere. but other programs reference `packageUnwrapped`,
|
|
||||||
# so keep that part still.
|
|
||||||
sandbox.enable = false;
|
|
||||||
package = lib.mkForce null;
|
|
||||||
|
|
||||||
# experimental sandboxing (2024/07/05)
|
|
||||||
# sandbox.method = "bwrap";
|
|
||||||
# sandbox.whitelistDbus = [
|
|
||||||
# "system"
|
|
||||||
# ];
|
|
||||||
# sandbox.net = "all";
|
|
||||||
};
|
|
||||||
|
|
||||||
# sane.programs.geoclue2.enableFor.system = lib.mkIf (builtins.any (en: en) (builtins.attrValues cfg.enableFor.user)) true;
|
|
||||||
|
|
||||||
services.geoclue2 = lib.mkIf cfg.enabled {
|
|
||||||
enable = true;
|
|
||||||
geoProviderUrl = "http://127.0.0.1:8088/v1/geolocate"; #< ols
|
|
||||||
# XXX(2024/06/25): when Geoclue uses ModemManager's GPS API, it wants to enable GPS
|
|
||||||
# tracking at the start, and disable it at the end. that causes tracking to be lost, regularly.
|
|
||||||
# this is not optional behavior: if Geoclue fails to control modem manager (because of a polkit policy, say),
|
|
||||||
# then it won't even try to read the data from modem manager.
|
|
||||||
# SOLUTION: tell Geoclue to get GPS from gps-share ("enableNmea", i.e. `network-nmea.enable`)
|
|
||||||
# and NOT from modem manager.
|
|
||||||
enableModemGPS = false;
|
|
||||||
enableNmea = true;
|
|
||||||
};
|
|
||||||
systemd.user.services = lib.mkIf cfg.enabled {
|
|
||||||
# nixos services.geoclue2 runs the agent as a user service by default, but i don't use systemd so that doesn't work.
|
|
||||||
# i manage the agent myself, in sane.programs.geoclue-demo-agent.
|
|
||||||
geoclue-agent.enable = false;
|
|
||||||
};
|
|
||||||
}
|
|
@@ -40,7 +40,6 @@ in
|
|||||||
alias.amend = "commit --amend --no-edit";
|
alias.amend = "commit --amend --no-edit";
|
||||||
alias.br = "branch";
|
alias.br = "branch";
|
||||||
alias.co = "checkout";
|
alias.co = "checkout";
|
||||||
alias.com = "commit";
|
|
||||||
alias.cp = "cherry-pick";
|
alias.cp = "cherry-pick";
|
||||||
alias.d = "difftool";
|
alias.d = "difftool";
|
||||||
alias.dif = "diff"; # common typo
|
alias.dif = "diff"; # common typo
|
||||||
|
@@ -1,12 +1,12 @@
|
|||||||
# gnome feeds RSS viewer
|
# gnome feeds RSS viewer
|
||||||
{ config, lib, pkgs, sane-lib, ... }:
|
{ config, lib, sane-lib, ... }:
|
||||||
|
|
||||||
let
|
let
|
||||||
feeds = sane-lib.feeds;
|
feeds = sane-lib.feeds;
|
||||||
all-feeds = config.sane.feeds;
|
all-feeds = config.sane.feeds;
|
||||||
wanted-feeds = feeds.filterByFormat ["text" "image"] all-feeds;
|
wanted-feeds = feeds.filterByFormat ["text" "image"] all-feeds;
|
||||||
in {
|
in {
|
||||||
sane.programs.gnome-feeds.fs.".config/org.gabmus.gfeeds.json".symlink.target = pkgs.writers.writeJSON "org.gabmus.gfeeds.json" {
|
sane.programs.gnome-feeds.fs.".config/org.gabmus.gfeeds.json".symlink.text = builtins.toJSON {
|
||||||
# feed format is a map from URL to a dict,
|
# feed format is a map from URL to a dict,
|
||||||
# with dict["tags"] a list of string tags.
|
# with dict["tags"] a list of string tags.
|
||||||
feeds = sane-lib.mapToAttrs (feed: {
|
feeds = sane-lib.mapToAttrs (feed: {
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
{ lib, pkgs, ... }:
|
{ lib, pkgs, ... }:
|
||||||
{
|
{
|
||||||
sane.programs.gnome-keyring = {
|
sane.programs.gnome-keyring = {
|
||||||
packageUnwrapped = pkgs.rmDbusServices pkgs.gnome-keyring;
|
packageUnwrapped = pkgs.rmDbusServices pkgs.gnome.gnome-keyring;
|
||||||
sandbox.method = "bwrap";
|
sandbox.method = "bwrap";
|
||||||
sandbox.whitelistDbus = [ "user" ];
|
sandbox.whitelistDbus = [ "user" ];
|
||||||
sandbox.extraRuntimePaths = [
|
sandbox.extraRuntimePaths = [
|
||||||
|
@@ -1,30 +1,7 @@
|
|||||||
# SUPPORT:
|
|
||||||
# - irc: #gnome-maps on irc.gimp.org
|
|
||||||
# - Matrix: #gnome-maps:gnome.org (unclear if bridged to IRC)
|
|
||||||
#
|
|
||||||
# INTEGRATIONS:
|
|
||||||
# - uses https://graphhopper.com for routing
|
|
||||||
# - <https://github.com/graphhopper/graphhopper> (not packaged for Nix)
|
|
||||||
# - uses https://tile.openstreetmap.org for tiles
|
|
||||||
# - uses https://overpass-api.de for ... ?
|
|
||||||
# TIPS:
|
|
||||||
# - use "Northwest" instead of "NW", and "Street" instead of "St", etc.
|
|
||||||
# otherwise, it might not find your destination!
|
|
||||||
{ pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
{
|
{
|
||||||
sane.programs."gnome.gnome-maps" = {
|
sane.programs."gnome.gnome-maps" = {
|
||||||
packageUnwrapped = pkgs.rmDbusServicesInPlace (pkgs.gnome.gnome-maps.overrideAttrs (base: {
|
packageUnwrapped = pkgs.rmDbusServices pkgs.gnome.gnome-maps;
|
||||||
# default .desktop file is trying to do some dbus launch (?) which fails even *if* i install `gapplication` (glib.bin)
|
|
||||||
postPatch = (base.postPatch or "") + ''
|
|
||||||
substituteInPlace data/org.gnome.Maps.desktop.in.in \
|
|
||||||
--replace-fail 'Exec=gapplication launch @app-id@ %U' 'Exec=gnome-maps %U'
|
|
||||||
'';
|
|
||||||
}));
|
|
||||||
suggestedPrograms = [
|
|
||||||
"geoclue2"
|
|
||||||
];
|
|
||||||
|
|
||||||
sandbox.wrapperType = "inplace"; #< /share directory contains Gir info which references libgnome-maps.so by path
|
|
||||||
sandbox.method = "bwrap";
|
sandbox.method = "bwrap";
|
||||||
sandbox.whitelistDri = true; # for perf
|
sandbox.whitelistDri = true; # for perf
|
||||||
sandbox.whitelistDbus = [
|
sandbox.whitelistDbus = [
|
||||||
|
@@ -1,56 +0,0 @@
|
|||||||
# gps-share: <https://github.com/zeenix/gps-share>
|
|
||||||
# takes a local GPS device (e.g. /dev/ttyUSB1) and makes it available over TCP/Avahi (multicast DNS).
|
|
||||||
#
|
|
||||||
# common usecases:
|
|
||||||
# 1. make positioning available to any device on a network, even if that device has no local GPS
|
|
||||||
# - e.g. my desktop can use my phone's GPS device, if on the same network.
|
|
||||||
# 2. allow multiple clients to share a GPS device.
|
|
||||||
# GPS devices are serial devices, and so only one process can consume the data at a time.
|
|
||||||
# gps-share can camp the serial device, and then allow *multiple* subscribers
|
|
||||||
# 3. provide a *read-only* API to clients like Geoclue.
|
|
||||||
# that is, expose the GPS device *output* to a client, but don't let the client write to the device (e.g. enable/disable the GPS).
|
|
||||||
# this is the primary function i derive from gps-share
|
|
||||||
#
|
|
||||||
# HOW TO TEST:
|
|
||||||
# - `nc localhost 10110`
|
|
||||||
# should stream GPS NMEA output to the console
|
|
||||||
# - `avahi-browse --resolve _nmea-0183._tcp`: should show hosts on the local network which provide GPS info
|
|
||||||
{ config, lib, pkgs, ... }:
|
|
||||||
let
|
|
||||||
cfg = config.sane.programs.gps-share;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
sane.programs.gps-share = {
|
|
||||||
suggestedPrograms = [
|
|
||||||
"jq"
|
|
||||||
# and systemd, for udevadm
|
|
||||||
];
|
|
||||||
services.gps-share = {
|
|
||||||
description = "gps-share: make local GPS serial readings available over Avahi";
|
|
||||||
# usage:
|
|
||||||
# gps-share --no-announce # to disable Avahi
|
|
||||||
# gps-share --no-tcp # only makes sense if using --socket-path
|
|
||||||
# gps-share --network-interface lo # defaults to all interfaces, but firewalling means actually more restrictive
|
|
||||||
# gps-share --socket-path $XDG_RUNTIME_DIR/gps-share/gps-share.sock # share over a unix socket
|
|
||||||
command = pkgs.writeShellScript "gps-share" ''
|
|
||||||
dev=$(udevadm info --property-match=ID_MM_PORT_TYPE_GPS=1 --json=pretty --export-db | jq -r .DEVNAME)
|
|
||||||
if [ -z "$dev" ]; then
|
|
||||||
echo "no GPS device found"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "using $dev for GPS NMEA"
|
|
||||||
gps-share "$dev"
|
|
||||||
'';
|
|
||||||
# TODO: this should be `partOf = [ "gps" ]`:
|
|
||||||
# it fails to launch if the NMEA device doesn't yet exist, and so restart loop when modem is not booted
|
|
||||||
dependencyOf = [ "geoclue-agent" ];
|
|
||||||
};
|
|
||||||
|
|
||||||
sandbox.method = "bwrap";
|
|
||||||
sandbox.net = "all";
|
|
||||||
sandbox.autodetectCliPaths = "existingFile";
|
|
||||||
};
|
|
||||||
|
|
||||||
# TODO: restrict this to just LAN devices!!
|
|
||||||
networking.firewall.allowedTCPPorts = lib.mkIf cfg.enabled [ 10110 ];
|
|
||||||
}
|
|
@@ -1,33 +0,0 @@
|
|||||||
# test gpsd with `gpspipe -w -n 10 2> /dev/null | grep -m 1 TPV | jq '.lat, .lon' | tr '\n' ' '`
|
|
||||||
# ^ should return <lat> <long>
|
|
||||||
#
|
|
||||||
# TODO(2024/06/19): nixpkgs' gpsd service isn't sandboxed at ALL. i should sandbox that, or remove this integration.
|
|
||||||
#
|
|
||||||
# pinephone GPS happens in EG25 modem
|
|
||||||
# serial control interface to modem is /dev/ttyUSB2
|
|
||||||
# after enabling GPS, readout is /dev/ttyUSB1
|
|
||||||
#
|
|
||||||
# minimal process to enable modem and GPS:
|
|
||||||
# - `echo 1 > /sys/class/modem-power/modem-power/device/powered`
|
|
||||||
# - `screen /dev/ttyUSB2 115200`
|
|
||||||
# - `AT+QGPSCFG="nmeasrc",1`
|
|
||||||
# - `AT+QGPS=1`
|
|
||||||
# this process is automated by my `eg25-control` program and services (`eg25-control-powered`, `eg25-control-gps`)
|
|
||||||
# - see the `modules/` directory further up this repository.
|
|
||||||
#
|
|
||||||
# now, something like `gpsd` can directly read from /dev/ttyUSB1,
|
|
||||||
# or geoclue can query the GPS directly through modem-manager
|
|
||||||
#
|
|
||||||
# initial GPS fix can take 15+ minutes.
|
|
||||||
# meanwhile, services like eg25-manager or eg25-control-freshen-agps can speed this up by uploading assisted GPS data to the modem.
|
|
||||||
{ config, lib, ... }:
|
|
||||||
let
|
|
||||||
cfg = config.sane.programs.gpsd;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
sane.programs.gpsd = {};
|
|
||||||
services.gpsd = lib.mkIf cfg.enabled {
|
|
||||||
enable = true;
|
|
||||||
devices = [ "/dev/ttyUSB1" ];
|
|
||||||
};
|
|
||||||
}
|
|
@@ -20,14 +20,5 @@
|
|||||||
pkgs.pipewire #< required for Video/Source (video4linux)
|
pkgs.pipewire #< required for Video/Source (video4linux)
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
|
|
||||||
sandbox.method = "bwrap";
|
|
||||||
sandbox.whitelistAudio = true;
|
|
||||||
sandbox.extraPaths = [
|
|
||||||
"/dev" # tried, but failed to narrow this down (moby)
|
|
||||||
"/run/udev/data"
|
|
||||||
"/sys/class/video4linux"
|
|
||||||
"/sys/devices"
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -1,55 +0,0 @@
|
|||||||
# chat (Matrix): #iio-sensor-proxy:dylanvanassche.be
|
|
||||||
# src: <https://gitlab.freedesktop.org/hadess/iio-sensor-proxy>
|
|
||||||
# IIO = "Industrial I/O": <https://www.kernel.org/doc/html/v4.12/driver-api/iio/index.html>
|
|
||||||
# iio-sensor-proxy reads IIO data reported by the kernel at /sys/bus/iio/* and makes it available to dbus applications.
|
|
||||||
# this includes:
|
|
||||||
# - ambient light sensor
|
|
||||||
# - compass/magnetometer (LIMITED)
|
|
||||||
# - accelerometer (rotation)
|
|
||||||
#
|
|
||||||
# use:
|
|
||||||
# - show available sensors: `gdbus introspect --system --dest net.hadess.SensorProxy --object-path /net/hadess/SensorProxy`
|
|
||||||
# - read sensors: `sudo -u geoclue monitor-sensor --compass`
|
|
||||||
# - default dbus policy only allows geoclue to use the compass
|
|
||||||
# - `sudo monitor-sensor` for light/rotation
|
|
||||||
#
|
|
||||||
# HARDWARE SUPPORT: PINEPHONE (2024/07/01)
|
|
||||||
# - accelerometer and light sensor seem to work
|
|
||||||
# - magnetometer (af8133j, different but similar to lis3mdl) IS NOT SUPPORTED
|
|
||||||
# - <https://gitlab.freedesktop.org/hadess/iio-sensor-proxy/-/issues/310>
|
|
||||||
# - exists in sysfs and can be viewed with
|
|
||||||
# `cat /sys/devices/platform/soc/1c2b000.i2c/i2c-1/1-001c/iio:device2/in_magn_x_raw`
|
|
||||||
# - nothing in iio-sensor-proxy reads anything related to "magn".
|
|
||||||
# - WIP PR to support magnetometers: <https://gitlab.freedesktop.org/hadess/iio-sensor-proxy/-/merge_requests/316>
|
|
||||||
# - after rebase, it *functions*, but does not scale the readings correctly
|
|
||||||
# heading changes only over the range of 50 - 70 deg.
|
|
||||||
{ config, lib, pkgs, ... }:
|
|
||||||
let
|
|
||||||
cfg = config.sane.programs.iio-sensor-proxy;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
sane.programs.iio-sensor-proxy = {
|
|
||||||
packageUnwrapped = pkgs.iio-sensor-proxy.overrideAttrs (upstream: {
|
|
||||||
patches = (upstream.patches or []) ++ [
|
|
||||||
(pkgs.fetchpatch {
|
|
||||||
name = "WIP:compass: Add support for polling uncalibrated devices";
|
|
||||||
# url = "https://gitlab.freedesktop.org/hadess/iio-sensor-proxy/-/merge_requests/316.diff";
|
|
||||||
url = "https://git.uninsane.org/colin/iio-sensor-proxy/commit/fd21f1f4bf1eadd603b1f24f628b979691d9cf3b.diff";
|
|
||||||
hash = "sha256-+GoEPby6q+uSkQlZWFWr5ghx3BKBMGk7uv/DDhGnxDk=";
|
|
||||||
})
|
|
||||||
];
|
|
||||||
});
|
|
||||||
enableFor.system = lib.mkIf (builtins.any (en: en) (builtins.attrValues cfg.enableFor.user)) true; #< for dbus/polkit policies
|
|
||||||
|
|
||||||
sandbox.method = "bwrap";
|
|
||||||
sandbox.whitelistDbus = [ "system" ];
|
|
||||||
sandbox.extraPaths = [
|
|
||||||
"/run/udev/data"
|
|
||||||
"/sys/bus"
|
|
||||||
"/sys/devices"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
services.udev.packages = lib.mkIf cfg.enabled [ cfg.package ];
|
|
||||||
# services.dbus.packages = lib.mkIf cfg.enabled [ cfg.package ]; #< for bus ownership policy
|
|
||||||
systemd.packages = lib.mkIf cfg.enabled [ cfg.package ]; #< for iio-sensor-proxy.service
|
|
||||||
}
|
|
@@ -1,8 +0,0 @@
|
|||||||
# ZSA keyboard (Ergodox, Moonlander, ...) firmware flasher and keymap viewer.
|
|
||||||
# video: <https://www.zsa.io/flash>
|
|
||||||
# displays on launch:
|
|
||||||
# - "Error connecting to the keyboard, make sure the layout flashed on your keyboard was recently compiled with Oryx and that the [Live training] option is toggled on in the advanced settings."
|
|
||||||
{ ... }:
|
|
||||||
{
|
|
||||||
sane.programs.keymapp = {};
|
|
||||||
}
|
|
@@ -17,7 +17,7 @@
|
|||||||
# - these are stored in `~/.config/koreader/data/dict`
|
# - these are stored in `~/.config/koreader/data/dict`
|
||||||
# - configure defaults:
|
# - configure defaults:
|
||||||
# - edit keys in ~/.config/koreader/settings.reader.lua
|
# - edit keys in ~/.config/koreader/settings.reader.lua
|
||||||
# - default font size: `["copt_font_size"] = 30,`
|
# - default font size: `["copt_font_size"] = 28,`
|
||||||
# - home dir: `["home_dir"] = "/home/colin/Books",`
|
# - home dir: `["home_dir"] = "/home/colin/Books",`
|
||||||
{ config, lib, pkgs, sane-lib, ... }:
|
{ config, lib, pkgs, sane-lib, ... }:
|
||||||
|
|
||||||
|
@@ -1,18 +1,14 @@
|
|||||||
# docs: <https://git.sr.ht/~mil/mepo>
|
# docs: <https://git.sr.ht/~mil/mepo>
|
||||||
# irc #mepo:irc.oftc.net
|
# irc #mepo:irc.oftc.net
|
||||||
#
|
|
||||||
{ config, lib, ... }:
|
{ config, lib, ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
sane.programs.mepo = {
|
sane.programs.mepo = {
|
||||||
sandbox.method = "bwrap";
|
sandbox.method = "bwrap";
|
||||||
sandbox.net = "all"; # for tiles *and* for localhost comm to gpsd
|
sandbox.net = "all"; # for tiles *and* for localhost comm to gpsd
|
||||||
sandbox.whitelistDri = true;
|
sandbox.whitelistDri = true;
|
||||||
sandbox.whitelistWayland = true;
|
sandbox.whitelistWayland = true;
|
||||||
sandbox.whitelistDbus = [
|
sandbox.whitelistDbus = [ "user" ]; # for geoclue
|
||||||
"system" # system is required for non-portal location services
|
|
||||||
"user" #< not sure if "user" is necessary?
|
|
||||||
];
|
|
||||||
sandbox.usePortal = false; # TODO: set up portal-based location services
|
|
||||||
|
|
||||||
persist.byStore.plaintext = [ ".cache/mepo/tiles" ];
|
persist.byStore.plaintext = [ ".cache/mepo/tiles" ];
|
||||||
# ~/.cache/mepo/savestate has precise coordinates and pins: keep those private
|
# ~/.cache/mepo/savestate has precise coordinates and pins: keep those private
|
||||||
@@ -20,11 +16,11 @@
|
|||||||
{ type = "file"; path = ".cache/mepo/savestate"; }
|
{ type = "file"; path = ".cache/mepo/savestate"; }
|
||||||
];
|
];
|
||||||
|
|
||||||
# enable geoclue2 and gpsd for location data.
|
# give mepo access to gpsd for location data, if that's enabled.
|
||||||
suggestedPrograms = [
|
# same with geoclue2.
|
||||||
"geoclue2"
|
suggestedPrograms = lib.optional config.services.gpsd.enable "gpsd"
|
||||||
# "gpsd" #< not required, and mepo only uses it if geoclue is unavailable
|
++ lib.optional config.services.geoclue2.enable "geoclue2-with-demo-agent"
|
||||||
];
|
;
|
||||||
};
|
};
|
||||||
|
|
||||||
# programs.mepo = lib.mkIf config.sane.programs.mepo.enabled {
|
# programs.mepo = lib.mkIf config.sane.programs.mepo.enabled {
|
||||||
|
@@ -5,7 +5,7 @@
|
|||||||
# alternative to mimeo is jaro: <https://github.com/isamert/jaro>
|
# alternative to mimeo is jaro: <https://github.com/isamert/jaro>
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
let
|
let
|
||||||
mimeo-open-desktop = pkgs.static-nix-shell.mkPython3 {
|
mimeo-open-desktop = pkgs.static-nix-shell.mkPython3Bin {
|
||||||
pname = "mimeo-open-desktop";
|
pname = "mimeo-open-desktop";
|
||||||
srcRoot = ./.;
|
srcRoot = ./.;
|
||||||
pkgs = [ "mimeo" ];
|
pkgs = [ "mimeo" ];
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env nix-shell
|
#!/usr/bin/env nix-shell
|
||||||
#!nix-shell -i python3 -p mimeo -p python3
|
#!nix-shell -i python3 -p "python3.withPackages (ps: [ ])" -p mimeo
|
||||||
|
|
||||||
# TODO: migrate nixpkgs mimeo to be `buildPythonPackage` to make it importable here.
|
# TODO: migrate nixpkgs mimeo to be `buildPythonPackage` to make it importable here.
|
||||||
# see <doc/languages-frameworks/python.section.md>
|
# see <doc/languages-frameworks/python.section.md>
|
||||||
|
@@ -1,19 +1,3 @@
|
|||||||
# GPS:
|
|
||||||
# - enable: `mmcli --modem any --location-enable-gps-unmanaged`
|
|
||||||
# - or `mmcli -m any --location-enable-gps-nmea`
|
|
||||||
# - or use `s6-rc start eg25-control-gps`
|
|
||||||
# - verify GPS is enabled: `mmcli --modem any --location-status`
|
|
||||||
# - query GPS coordinates: `mmcli -m any --location-get`
|
|
||||||
# - monitor constellation info: `mmcli -m any --location-monitor`
|
|
||||||
# - i.e. which satellites are in view
|
|
||||||
# - or just `cat /dev/ttyUSB1`
|
|
||||||
#
|
|
||||||
# interactions, warnings:
|
|
||||||
# - Geoclue (`where-am-i`) toggles mmcli GPS on/off every 60s, often resetting it to the "off" state
|
|
||||||
# - see: <https://gitlab.freedesktop.org/geoclue/geoclue/-/issues/180>
|
|
||||||
# - the effect is that GPS data is effectively useless inside apps like gnome-maps
|
|
||||||
# i think the trick is to get "--location-enable-gps-unmanaged" gps working again
|
|
||||||
# or use gnss-share/gpsd (this may be what "unmanaged" means).
|
|
||||||
{ pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
{
|
{
|
||||||
sane.programs.mmcli = {
|
sane.programs.mmcli = {
|
||||||
@@ -22,11 +6,7 @@
|
|||||||
mainProgram = "mmcli";
|
mainProgram = "mmcli";
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
# TODO: sandbox
|
||||||
sandbox.method = "bwrap";
|
|
||||||
sandbox.whitelistDbus = [
|
|
||||||
"system"
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -135,54 +135,65 @@ let
|
|||||||
'cycle_key = "c"' 'cycle_key = "v"'
|
'cycle_key = "c"' 'cycle_key = "v"'
|
||||||
'';
|
'';
|
||||||
});
|
});
|
||||||
|
mpv-unwrapped = pkgs.mpv-unwrapped.overrideAttrs (upstream: {
|
||||||
|
version = "0.37.0-unstable-2024-03-31";
|
||||||
|
src = lib.warnIf (lib.versionOlder "0.37.0" upstream.version) "mpv outdated; remove patch?" pkgs.fetchFromGitHub {
|
||||||
|
owner = "mpv-player";
|
||||||
|
repo = "mpv";
|
||||||
|
rev = "4ce4bf1795e6dfd6f1ddf07fb348ce5d191ab1dc";
|
||||||
|
hash = "sha256-nOGuHq7SWDAygROV7qHtezDv1AsMpseImI8TVd3F+Oc=";
|
||||||
|
};
|
||||||
|
patches = [];
|
||||||
|
});
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
sane.programs.mpv = {
|
sane.programs.mpv = {
|
||||||
packageUnwrapped = pkgs.mpv-unwrapped.wrapper {
|
packageUnwrapped = pkgs.wrapMpv
|
||||||
mpv = pkgs.mpv-unwrapped.override rec {
|
(mpv-unwrapped.override rec {
|
||||||
# N.B.: populating `self` to `luajit` is necessary for the resulting `lua.withPackages` function to preserve my override.
|
# N.B.: populating `self` to `luajit` is necessary for the resulting `lua.withPackages` function to preserve my override.
|
||||||
# i use enable52Compat in order to get `table.unpack`.
|
# i use enable52Compat in order to get `table.unpack`.
|
||||||
# i think using `luajit` here instead of `lua` is optional, just i get better perf with it :)
|
# i think using `luajit` here instead of `lua` is optional, just i get better perf with it :)
|
||||||
lua = pkgs.luajit.override { enable52Compat = true; self = lua; };
|
lua = pkgs.luajit.override { enable52Compat = true; self = lua; };
|
||||||
|
})
|
||||||
|
{
|
||||||
|
scripts = [
|
||||||
|
pkgs.mpvScripts.mpris
|
||||||
|
pkgs.mpvScripts.mpv-playlistmanager
|
||||||
|
pkgs.mpvScripts.mpv-webm
|
||||||
|
uosc
|
||||||
|
visualizer
|
||||||
|
# pkgs.mpv-uosc-latest
|
||||||
|
];
|
||||||
|
# extraMakeWrapperArgs = lib.optionals (cfg.config.vo != null) [
|
||||||
|
# # 2023/08/29: fixes an error where mpv on moby launches with the message
|
||||||
|
# # "DRM_IOCTL_MODE_CREATE_DUMB failed: Cannot allocate memory"
|
||||||
|
# # audio still works, and controls, screenshotting, etc -- just not the actual rendering
|
||||||
|
# #
|
||||||
|
# # this is likely a regression for mpv 0.36.0.
|
||||||
|
# # the actual error message *appears* to come from the mesa library, but it's tough to trace.
|
||||||
|
# #
|
||||||
|
# # 2024/03/02: no longer necessary, with mesa 23.3.1: <https://github.com/NixOS/nixpkgs/pull/265740>
|
||||||
|
# #
|
||||||
|
# # backend compatibility (2023/10/22):
|
||||||
|
# # run with `--vo=help` to see a list of all output options.
|
||||||
|
# # non-exhaustive (W=works, F=fails, A=audio-only, U=audio+ui only (no video))
|
||||||
|
# # ? null Null video output
|
||||||
|
# # A (default)
|
||||||
|
# # A dmabuf-wayland Wayland dmabuf video output
|
||||||
|
# # A libmpv render API for libmpv (mpv plays the audio, but doesn't even render a window)
|
||||||
|
# # A vdpau VDPAU with X11
|
||||||
|
# # F drm Direct Rendering Manager (software scaling)
|
||||||
|
# # F gpu-next Video output based on libplacebo
|
||||||
|
# # F vaapi VA API with X11
|
||||||
|
# # F x11 X11 (software scaling)
|
||||||
|
# # F xv X11/Xv
|
||||||
|
# # U gpu Shader-based GPU Renderer
|
||||||
|
# # W caca libcaca (terminal rendering)
|
||||||
|
# # W sdl SDL 2.0 Renderer
|
||||||
|
# # W wlshm Wayland SHM video output (software scaling)
|
||||||
|
# "--add-flags" "--vo=${cfg.config.vo}"
|
||||||
|
# ];
|
||||||
};
|
};
|
||||||
scripts = [
|
|
||||||
pkgs.mpvScripts.mpris
|
|
||||||
pkgs.mpvScripts.mpv-playlistmanager
|
|
||||||
pkgs.mpvScripts.mpv-webm
|
|
||||||
uosc
|
|
||||||
visualizer
|
|
||||||
# pkgs.mpv-uosc-latest
|
|
||||||
];
|
|
||||||
# extraMakeWrapperArgs = lib.optionals (cfg.config.vo != null) [
|
|
||||||
# # 2023/08/29: fixes an error where mpv on moby launches with the message
|
|
||||||
# # "DRM_IOCTL_MODE_CREATE_DUMB failed: Cannot allocate memory"
|
|
||||||
# # audio still works, and controls, screenshotting, etc -- just not the actual rendering
|
|
||||||
# #
|
|
||||||
# # this is likely a regression for mpv 0.36.0.
|
|
||||||
# # the actual error message *appears* to come from the mesa library, but it's tough to trace.
|
|
||||||
# #
|
|
||||||
# # 2024/03/02: no longer necessary, with mesa 23.3.1: <https://github.com/NixOS/nixpkgs/pull/265740>
|
|
||||||
# #
|
|
||||||
# # backend compatibility (2023/10/22):
|
|
||||||
# # run with `--vo=help` to see a list of all output options.
|
|
||||||
# # non-exhaustive (W=works, F=fails, A=audio-only, U=audio+ui only (no video))
|
|
||||||
# # ? null Null video output
|
|
||||||
# # A (default)
|
|
||||||
# # A dmabuf-wayland Wayland dmabuf video output
|
|
||||||
# # A libmpv render API for libmpv (mpv plays the audio, but doesn't even render a window)
|
|
||||||
# # A vdpau VDPAU with X11
|
|
||||||
# # F drm Direct Rendering Manager (software scaling)
|
|
||||||
# # F gpu-next Video output based on libplacebo
|
|
||||||
# # F vaapi VA API with X11
|
|
||||||
# # F x11 X11 (software scaling)
|
|
||||||
# # F xv X11/Xv
|
|
||||||
# # U gpu Shader-based GPU Renderer
|
|
||||||
# # W caca libcaca (terminal rendering)
|
|
||||||
# # W sdl SDL 2.0 Renderer
|
|
||||||
# # W wlshm Wayland SHM video output (software scaling)
|
|
||||||
# "--add-flags" "--vo=${cfg.config.vo}"
|
|
||||||
# ];
|
|
||||||
};
|
|
||||||
|
|
||||||
suggestedPrograms = [
|
suggestedPrograms = [
|
||||||
"blast-to-default"
|
"blast-to-default"
|
||||||
@@ -241,10 +252,9 @@ 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";
|
mime.urlAssociations."^https?://(www.)?youtube.com/watch\?.*v=" = "mpv.desktop";
|
||||||
mime.urlAssociations."^https?://(m\.)?(www\.)?youtube.com/shorts/.+" = "mpv.desktop";
|
mime.urlAssociations."^https?://(www.)?youtube.com/v/" = "mpv.desktop";
|
||||||
mime.urlAssociations."^https?://(m\.)?(www\.)?youtube.com/v/" = "mpv.desktop";
|
mime.urlAssociations."^https?://(www.)?youtu.be/.+" = "mpv.desktop";
|
||||||
mime.urlAssociations."^https?://(m\.)?(www\.)?youtube.com/watch\?.*v=" = "mpv.desktop";
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
{ pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
{
|
{
|
||||||
sane.programs."nautilus" = {
|
sane.programs."gnome.nautilus" = {
|
||||||
# some of its dbus services don't even refer to real paths
|
# some of its dbus services don't even refer to real paths
|
||||||
packageUnwrapped = pkgs.rmDbusServicesInPlace (pkgs.nautilus.overrideAttrs (orig: {
|
packageUnwrapped = pkgs.rmDbusServicesInPlace (pkgs.gnome.nautilus.overrideAttrs (orig: {
|
||||||
# enable the "Audio and Video Properties" pane. see: <https://nixos.wiki/wiki/Nautilus>
|
# enable the "Audio and Video Properties" pane. see: <https://nixos.wiki/wiki/Nautilus>
|
||||||
buildInputs = orig.buildInputs ++ (with pkgs.gst_all_1; [
|
buildInputs = orig.buildInputs ++ (with pkgs.gst_all_1; [
|
||||||
gst-plugins-good
|
gst-plugins-good
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user