Compare commits

..

1 Commits

Author SHA1 Message Date
8f9cef6ff3 WIP: sxmo: ship deps via package instead of at the DE level 2023-06-23 02:12:23 +00:00
289 changed files with 4742 additions and 21251 deletions

View File

@@ -16,8 +16,6 @@ directly here; even the sources for those packages is often kept here too.
[uninsane-org]: https://uninsane.org [uninsane-org]: https://uninsane.org
## Layout ## Layout
- `doc/`
- instructions for tasks i find myself doing semi-occasionally in this repo.
- `hosts/` - `hosts/`
- the bulk of config which isn'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,
@@ -39,7 +37,9 @@ directly here; even the sources for those packages is often kept here too.
- 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 are referenced by other things in this repo.
- these aren't generally user-facing, but they're factored out so that they can
be invoked directly when i need to debug.
- `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.
@@ -106,6 +106,3 @@ this repo exists in a few known locations:
if you want to contact me for questions, or collaborate to split something useful into a shared repo, etc, if you want to contact me for questions, or collaborate to split something useful into a shared repo, etc,
you can reach me via any method listed [here](https://uninsane.org/about). you can reach me via any method listed [here](https://uninsane.org/about).
patches, for this repo or any other i host, will be warmly welcomed in any manner you see fit:
`git send-email`, DM'ing the patch over Matrix/Lemmy/ActivityPub/etc, even a literal PR where you
link me to your own clone.

72
TODO.md
View File

@@ -1,13 +1,8 @@
## BUGS ## BUGS
- mpv UI is sometimes blank for audio/podcasts?
- i think it's when the audio file has no thumbnail?
- why i need to manually restart `wireguard-wg-ovpns` on servo periodically - why i need to manually restart `wireguard-wg-ovpns` on servo periodically
- else DNS fails - else DNS fails
- fix epiphany URL bar input on moby
- sxmo: wvkbd: missing font for icons on the 3rd page
## REFACTORING: ## REFACTORING:
### sops/secrets ### sops/secrets
- attach secrets to the thing they're used by (sane.programs) - attach secrets to the thing they're used by (sane.programs)
- rework secrets to leverage `sane.fs` - rework secrets to leverage `sane.fs`
@@ -18,18 +13,17 @@
- will make it easier to test new services? - will make it easier to test new services?
### upstreaming ### upstreaming
- split out a sxmo module usable by NUR consumers - split out a trust-dns module
- see: <https://github.com/NixOS/nixpkgs/pull/205866#issuecomment-1575753054>
- bump nodejs version in lemmy-ui - bump nodejs version in lemmy-ui
- add updateScripts to all my packages in nixpkgs - add updateScripts to all my packages in nixpkgs
- fix lightdm-mobile-greeter for newer libhandy - fix lightdm-mobile-greeter for newer libhandy
- port zecwallet-lite to a from-source build - port zecwallet-lite to a from-source build
- fix or abandon Whalebird
- FIX failed CI on bonsai PR: <https://github.com/NixOS/nixpkgs/pull/233892>
- REVIEW/integrate jellyfin dataDir config: <https://github.com/NixOS/nixpkgs/pull/233617> - REVIEW/integrate jellyfin dataDir config: <https://github.com/NixOS/nixpkgs/pull/233617>
- remove `libsForQt5.callPackage` broadly: <https://github.com/NixOS/nixpkgs/issues/180841> - remove `libsForQt5.callPackage` broadly: <https://github.com/NixOS/nixpkgs/issues/180841>
#### upstreaming to non-nixpkgs repos
- gtk: build schemas even on cross compilation: <https://github.com/NixOS/nixpkgs/pull/247844>
- sxmo: add new app entries
## IMPROVEMENTS: ## IMPROVEMENTS:
### security/resilience ### security/resilience
@@ -39,65 +33,45 @@
- have `sane.programs` be wrapped such that they run in a cgroup? - have `sane.programs` be wrapped such that they run in a cgroup?
- at least, only give them access to the portion of the fs they *need*. - at least, only give them access to the portion of the fs they *need*.
- Android takes approach of giving each app its own user: could hack that in here. - Android takes approach of giving each app its own user: could hack that in here.
- **systemd-run** takes a command and runs it in a temporary scope (cgroup)
- presumably uses the same options as systemd services
- see e.g. <https://github.com/NixOS/nixpkgs/issues/113903#issuecomment-857296349>
- flatpak does this, somehow
- apparmor? SElinux? (desktop) "portals"?
- see Spectrum OS; Alyssa Ross; etc
- bubblewrap-based sandboxing: <https://github.com/nixpak/nixpak>
- canaries for important services - canaries for important services
- e.g. daily email checks; daily backup checks - e.g. daily email checks; daily backup checks
- integrate `nix check` into Gitea actions?
### user experience ### user experience
- moby: sxmo: fix youtube scripts (package youtube-cli) - firefox/librewolf: don't show browserpass/sponsorblock/metamask "first run" on every boot
- moby: tune GPS
- run only geoclue, and not gpsd, to save power?
- 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?
- manually do smoothing, as some layer between mepo and geoclue/gpsd?
- neovim: set up language server (lsp; rnix-lsp; nvim-lspconfig)
- Helix: make copy-to-system clipboard be the default
- firefox/librewolf: persist history
- just not cookies or tabs
- moby: improve gPodder launch time - moby: improve gPodder launch time
- moby: theme GTK apps (i.e. non-adwaita styles) - moby: replace jellyfin-desktop with jellyfin-vue?
- especially, make the menubar collapsible - allows (maybe) to cache media for offline use
- try Gradience tool specifically for theming adwaita? <https://linuxphoneapps.org/apps/com.github.gradienceteam.gradience/> - "newer" jellyfin client
- not packaged for nix
- moby/sxmo: display numerical vol percentage in topbar
- moby/sxmo: include librewolf, jellyfin in `apps` menu
- find a nice desktop ActivityPub client
- package Nix/NixOS docs for Zeal - package Nix/NixOS docs for Zeal
- install [doc-browser](https://github.com/qwfy/doc-browser) - install [doc-browser](https://github.com/qwfy/doc-browser)
- this supports both dash (zeal) *and* the datasets from <https://devdocs.io> (which includes nix!) - this supports both dash (zeal) *and* the datasets from <https://devdocs.io> (which includes nix!)
- install [devhelp](https://wiki.gnome.org/Apps/Devhelp) (gnome) - install [devhelp](https://wiki.gnome.org/Apps/Devhelp) (gnome)
- auto-mount servo
- have xdg-open parse `<repo:...> URIs (or adjust them so that it _can_ parse) - have xdg-open parse `<repo:...> URIs (or adjust them so that it _can_ parse)
- `sane.programs`: auto-populate defaults with everything from `pkgs`
- zsh: disable "command not found" corrections
- sane-bt-search: show details like 5.1 vs stereo, h264 vs h265 - sane-bt-search: show details like 5.1 vs stereo, h264 vs h265
- uninsane.org: make URLs relative to allow local use (and as offline homepage)
- 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
- could change junk filter from "no DKIM success" to explicit "DKIM failed"
- sxmo: don't put all deps on PATH
- maybe: use resholve to hard-code them
- this is the most "correct", but least patchable
- maybe: express each invocation as a function in sxmo_common.sh
- this will require some patching to handle `exec <foo>` style
- maybe: save original PATH and reset it before invoking user files
### perf ### perf
- add `pkgs.impure-cached.<foo>` package set to build things with ccache enabled
- every package here can be auto-generated, and marked with some env var so that it doesn't pollute the pure package set
- would be super handy for package prototyping!
- why does nixos-rebuild switch take 5 minutes when net is flakey? - why does nixos-rebuild switch take 5 minutes when net is flakey?
- trying to auto-mount servo? - trying to auto-mount servo?
- something to do with systemd services restarting/stalling - something to do with systemd services restarting/stalling
- maybe wireguard & its refresh operation, specifically? - maybe wireguard & its refresh operation, specifically?
- get moby to build without binfmt emulation (i.e. make all emulation explicit) - fix OOM for large builds like webkitgtk
- then i can distribute builds across servo + desko, and also allow servo to pull packages from desko w/o worrying about purity - these use significant /tmp space.
- either place /tmp on encrypted-cleared-at-boot storage
- which probably causes each CPU load for the encryption
- **or set up encrypted swap**
- encrypted swap could remove the need for my encrypted-cleared-at-boot stuff
## NEW FEATURES: ## NEW FEATURES:
- add a FTP-accessible file share to servo
- just /var/www?
- migrate MAME cabinet to nix - migrate MAME cabinet to nix
- boot it from PXE from servo? - boot it from PXE from servo?
- deploy to new server, and use it as a remote builder
- enable IPv6 - enable IPv6
- package lemonade lemmy app: <https://linuxphoneapps.org/apps/ml.mdwalters.lemonade/>

View File

@@ -1,13 +0,0 @@
to ship `pkgs.foo` on some host, either:
- add it as an entry in `suggestedPrograms` to the appropriate category in `hosts/common/programs/assorted.nix`, or
- `sane.programs.foo.enableFor.user.colin = true` in `hosts/by-name/myhost/default.nix`
if the program needs customization (persistence, configs, secrets):
- add a file for it at `hosts/common/programs/<foo>.nix`
- set the options, `sane.programs.foo.{fs,persist}`
if it's unclear what fs paths a program uses:
- run one of these commands, launch the program, run it again, and `diff`:
- `du -x --apparent-size ~`
- `find ~ -xdev`
- or, inspect the whole tmpfs root with `ncdu -x /`

62
flake.lock generated
View File

@@ -1,15 +1,12 @@
{ {
"nodes": { "nodes": {
"flake-utils": { "flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": { "locked": {
"lastModified": 1687709756, "lastModified": 1678901627,
"narHash": "sha256-Y5wKlQSkgEK2weWdOu4J3riRd+kV/VCgHsqLNTTWQ/0=", "narHash": "sha256-U02riOqrKKzwjsxc/400XnElV+UtPUQWpANPlyazjH0=",
"owner": "numtide", "owner": "numtide",
"repo": "flake-utils", "repo": "flake-utils",
"rev": "dbabf0ca0c0c4bce6ea5eaf65af5cb694d2082c7", "rev": "93a2b84fc4b70d9e089d029deacc3583435c2ed6",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -21,11 +18,11 @@
"mobile-nixos": { "mobile-nixos": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1690059310, "lastModified": 1683422260,
"narHash": "sha256-4zcoDp8wwZVfGSzXltC5x+eH4kDWC/eJpyQNgr7shAA=", "narHash": "sha256-79zaClbubRkBNlJ04OSADILuLQHH48N5fu296hEWYlw=",
"owner": "nixos", "owner": "nixos",
"repo": "mobile-nixos", "repo": "mobile-nixos",
"rev": "56fc9f9619f305f0865354975a98d22410eed127", "rev": "ba4638836e94a8f16d1d1f9e8c0530b86078029c",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -39,11 +36,11 @@
"nixpkgs": "nixpkgs" "nixpkgs": "nixpkgs"
}, },
"locked": { "locked": {
"lastModified": 1687251388, "lastModified": 1684319086,
"narHash": "sha256-E9cVlgeCvzPbA/G3mCDCzz8TdRwXyGYzIjmwcvIfghg=", "narHash": "sha256-5wwlkWqP1cQUPXp/PJsi09FkgAule5yBghngRZZbUQg=",
"owner": "edolstra", "owner": "edolstra",
"repo": "nix-serve", "repo": "nix-serve",
"rev": "d6df5bd8584f37e22cff627db2fc4058a4aab5ee", "rev": "e6e3d09438e803daa5374ad8edf1271289348456",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -69,11 +66,11 @@
}, },
"nixpkgs-stable": { "nixpkgs-stable": {
"locked": { "locked": {
"lastModified": 1693097136, "lastModified": 1687031877,
"narHash": "sha256-fBZSMdBaoZ0INFbyZ5s0DOF7zDNcLsLxgkwdDh3l9Pc=", "narHash": "sha256-yMFcVeI+kZ6KD2QBrFPNsvBrLq2Gt//D0baHByMrjFY=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "9117c4e9dc117a6cd0319cca40f2349ed333669d", "rev": "e2e2059d19668dab1744301b8b0e821e3aae9c99",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -85,11 +82,11 @@
}, },
"nixpkgs-unpatched": { "nixpkgs-unpatched": {
"locked": { "locked": {
"lastModified": 1693377291, "lastModified": 1686960236,
"narHash": "sha256-vYGY9bnqEeIncNarDZYhm6KdLKgXMS+HA2mTRaWEc80=", "narHash": "sha256-AYCC9rXNLpUWzD9hm+askOfpliLEC9kwAo7ITJc4HIw=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "e7f38be3775bab9659575f192ece011c033655f0", "rev": "04af42f3b31dba0ef742d254456dc4c14eedac86",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -116,11 +113,11 @@
"nixpkgs-stable": "nixpkgs-stable" "nixpkgs-stable": "nixpkgs-stable"
}, },
"locked": { "locked": {
"lastModified": 1693404499, "lastModified": 1687058111,
"narHash": "sha256-cx/7yvM/AP+o/3wPJmA9W9F+WHemJk5t+Xcr+Qwkqhg=", "narHash": "sha256-xDSn/APfAdJinHV4reTfplX5XnLsJSGdVwHpmdgP9Mo=",
"owner": "Mic92", "owner": "Mic92",
"repo": "sops-nix", "repo": "sops-nix",
"rev": "d9c5dc41c4b1f74c77f0dbffd0f3a4ebde447b7a", "rev": "1634d2da53f079e7f5924efa7a96511cd9596f81",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -129,21 +126,6 @@
"type": "github" "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"
}
},
"uninsane-dot-org": { "uninsane-dot-org": {
"inputs": { "inputs": {
"flake-utils": "flake-utils", "flake-utils": "flake-utils",
@@ -152,11 +134,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1691106178, "lastModified": 1686876043,
"narHash": "sha256-3mZ9gTvMpbZA9ea9ovoQpn2wKuQY0QZ7MDdEjArYdAQ=", "narHash": "sha256-71SNPU2aeeJx29JSeW4JCJb8HXAuZRvL7sbh+c3wgkk=",
"ref": "refs/heads/master", "ref": "refs/heads/master",
"rev": "f4d91aa201b6e49af690f250d4786bd1d8b4dcfd", "rev": "0e0aa12aca143639f158b3a5c0c00349fcc2166c",
"revCount": 205, "revCount": 199,
"type": "git", "type": "git",
"url": "https://git.uninsane.org/colin/uninsane" "url": "https://git.uninsane.org/colin/uninsane"
}, },

111
flake.nix
View File

@@ -23,6 +23,9 @@
# preferably, i would rewrite the human-readable https URLs to nix-specific github: URLs with a helper, # 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. # but `inputs` is required to be a strict attrset: not an expression.
inputs = { inputs = {
# <https://github.com/nixos/nixpkgs/tree/nixos-22.11>
# nixpkgs-stable.url = "github:nixos/nixpkgs?ref=nixos-22.11";
# branch workflow: # branch workflow:
# - daily: # - daily:
# - nixos-unstable cut from master after enough packages have been built in caches. # - nixos-unstable cut from master after enough packages have been built in caches.
@@ -94,17 +97,7 @@
evalHost = { name, local, target }: nixpkgs.lib.nixosSystem { evalHost = { name, local, target }: nixpkgs.lib.nixosSystem {
system = target; system = target;
modules = [ modules = [
{ (import ./hosts/instantiate.nix { localSystem = local; hostName = name; })
nixpkgs = (if (local != null) then {
buildPlatform = local;
} else {}) // {
# TODO: does the earlier `system` arg to nixosSystem make its way here?
hostPlatform.system = target;
};
# nixpkgs.buildPlatform = local; # set by instantiate.nix instead
# nixpkgs.config.replaceStdenv = { pkgs }: pkgs.ccacheStdenv;
}
(import ./hosts/instantiate.nix { hostName = name; })
self.nixosModules.default self.nixosModules.default
self.nixosModules.passthru self.nixosModules.passthru
{ {
@@ -113,6 +106,12 @@
self.overlays.sane-all self.overlays.sane-all
]; ];
} }
({ lib, ... }: {
# TODO: does the earlier `system` arg to nixosSystem make its way here?
nixpkgs.hostPlatform.system = target;
# nixpkgs.buildPlatform = local; # set by instantiate.nix instead
# nixpkgs.config.replaceStdenv = { pkgs }: pkgs.ccacheStdenv;
})
]; ];
}; };
in { in {
@@ -178,10 +177,15 @@
disable-flakey-tests = final: prev: import ./overlays/disable-flakey-tests.nix final prev; disable-flakey-tests = final: prev: import ./overlays/disable-flakey-tests.nix final prev;
pkgs = final: prev: import ./overlays/pkgs.nix final prev; pkgs = final: prev: import ./overlays/pkgs.nix final prev;
pins = final: prev: import ./overlays/pins.nix final prev; pins = final: prev: import ./overlays/pins.nix final prev;
preferences = final: prev: import ./overlays/preferences.nix final prev;
optimizations = final: prev: import ./overlays/optimizations.nix final prev; optimizations = final: prev: import ./overlays/optimizations.nix final prev;
passthru = final: prev: passthru = final: prev:
let let
stable =
if inputs ? "nixpkgs-stable" then (
final': prev': {
stable = inputs.nixpkgs-stable.legacyPackages."${prev'.stdenv.hostPlatform.system}";
}
) else (final': prev': {});
mobile = (import "${mobile-nixos}/overlay/overlay.nix"); mobile = (import "${mobile-nixos}/overlay/overlay.nix");
uninsane = uninsane-dot-org.overlay; uninsane = uninsane-dot-org.overlay;
# nix-serve' = nix-serve.overlay; # nix-serve' = nix-serve.overlay;
@@ -192,7 +196,8 @@
inherit (nix-serve.packages."${next.system}") nix-serve; inherit (nix-serve.packages."${next.system}") nix-serve;
}; };
in in
(mobile final prev) (stable final prev)
// (mobile final prev)
// (uninsane final prev) // (uninsane final prev)
// (nix-serve' final prev) // (nix-serve' final prev)
; ;
@@ -244,94 +249,32 @@
apps."x86_64-linux" = apps."x86_64-linux" =
let let
pkgs = self.legacyPackages."x86_64-linux"; pkgs = self.legacyPackages."x86_64-linux";
deployScript = host: addr: action: pkgs.writeShellScript "deploy-${host}" '' deployScript = action: pkgs.writeShellScript "deploy-moby" ''
nix build '.#nixosConfigurations.${host}.config.system.build.toplevel' --out-link ./result-${host} $@ nixos-rebuild --flake '.#moby' build $@
sudo nix sign-paths -r -k /run/secrets/nix_serve_privkey $(readlink ./result-${host}) sudo nix sign-paths -r -k /run/secrets/nix_serve_privkey $(readlink ./result)
nixos-rebuild --flake '.#moby' ${action} --target-host colin@moby-hn --use-remote-sudo $@
# XXX: this triggers another config eval & (potentially) build.
# if the config changed between these invocations, the above signatures might not apply to the deployed config.
# let the user handle that edge case by re-running this whole command
nixos-rebuild --flake '.#${host}' ${action} --target-host colin@${addr} --use-remote-sudo $@
''; '';
in { in {
help = {
type = "app";
program = let
helpMsg = builtins.toFile "nixos-config-help-message" ''
commands:
- `nix run '.#help'`
- show this message
- `nix run '.#update-feeds'`
- updates metadata for all feeds
- `nix run '.#init-feed' <url>`
- `nix run '.#deploy-{lappy,moby,moby-test,servo}' [nixos-rebuild args ...]`
- `nix run '.#check-nur'`
'';
in builtins.toString (pkgs.writeShellScript "nixos-config-help" ''
cat ${helpMsg}
'');
};
update-feeds = { update-feeds = {
type = "app"; type = "app";
program = "${pkgs.feeds.updateScript}"; program = "${pkgs.feeds.updateScript}";
}; };
init-feed = { init-feed = {
# use like `nix run '.#init-feed' uninsane.org`
type = "app"; type = "app";
program = "${pkgs.feeds.initFeedScript}"; program = "${pkgs.feeds.initFeedScript}";
}; };
deploy-lappy = {
type = "app";
program = ''${deployScript "lappy" "lappy" "switch"}'';
};
deploy-moby-test = { deploy-moby-test = {
# `nix run '.#deploy-moby-test'`
type = "app"; type = "app";
program = ''${deployScript "moby" "moby-hn" "test"}''; program = ''${deployScript "test"}'';
}; };
deploy-moby = { deploy-moby = {
# `nix run '.#deploy-moby-switch'`
type = "app"; type = "app";
program = ''${deployScript "moby" "moby-hn" "switch"}''; program = ''${deployScript "switch"}'';
};
deploy-servo = {
type = "app";
program = ''${deployScript "servo" "servo" "switch"}'';
};
sync-moby = {
# copy music from the current device to moby
# TODO: should i actually sync from /mnt/servo-media/Music instead of the local drive?
type = "app";
program = builtins.toString (pkgs.writeShellScript "sync-to-moby" ''
sudo mount /mnt/moby-home
${pkgs.sane-scripts.sync-music}/bin/sane-sync-music ~/Music /mnt/moby-home/Music
'');
};
sync-lappy = {
# copy music from servo to lappy
# can run this from any device that has ssh access to lappy
type = "app";
program = builtins.toString (pkgs.writeShellScript "sync-to-lappy" ''
sudo mount /mnt/lappy-home
${pkgs.sane-scripts.sync-music}/bin/sane-sync-music /mnt/servo-media/Music /mnt/lappy-home/Music
'');
};
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=$(nix-instantiate --find-file nixpkgs) \
-I ../../
'');
}; };
}; };

View File

@@ -4,11 +4,6 @@
./fs.nix ./fs.nix
]; ];
# sane.guest.enable = true;
# services.distccd.enable = true;
# sane.programs.distcc.enableFor.user.guest = true;
sops.secrets.colin-passwd.neededForUsers = true; sops.secrets.colin-passwd.neededForUsers = true;
sane.roles.build-machine.enable = true; sane.roles.build-machine.enable = true;
@@ -22,11 +17,9 @@
sane.gui.sway.enable = true; sane.gui.sway.enable = true;
sane.programs.iphoneUtils.enableFor.user.colin = true; sane.programs.iphoneUtils.enableFor.user.colin = true;
sane.programs.steam.enableFor.user.colin = true;
sane.programs.guiApps.suggestedPrograms = [ "desktopGuiApps" ]; sane.programs.guiApps.suggestedPrograms = [ "desktopGuiApps" ];
sane.programs.consoleUtils.suggestedPrograms = [ "consoleMediaUtils" "desktopConsoleUtils" ]; sane.programs.consoleUtils.suggestedPrograms = [ "consoleMediaUtils" ];
# sane.programs.devPkgs.enableFor.user.colin = true;
boot.loader.efi.canTouchEfiVariables = false; boot.loader.efi.canTouchEfiVariables = false;
sane.image.extraBootFiles = [ pkgs.bootpart-uefi-x86_64 ]; sane.image.extraBootFiles = [ pkgs.bootpart-uefi-x86_64 ];
@@ -36,7 +29,6 @@
# don't enable wifi by default: it messes with connectivity. # don't enable wifi by default: it messes with connectivity.
systemd.services.iwd.enable = false; systemd.services.iwd.enable = false;
systemd.services.wpa_supplicant.enable = false;
# default config: https://man.archlinux.org/man/snapper-configs.5 # default config: https://man.archlinux.org/man/snapper-configs.5
# defaults to something like: # defaults to something like:
@@ -50,6 +42,17 @@
ALLOW_USERS = [ "colin" ]; ALLOW_USERS = [ "colin" ];
}; };
programs.steam = {
enable = true;
# not sure if needed: stole this whole snippet from the wiki
remotePlay.openFirewall = true; # Open ports in the firewall for Steam Remote Play
dedicatedServer.openFirewall = true; # Open ports in the firewall for Source Dedicated Server
};
sane.user.persist.plaintext = [
".steam"
".local/share/Steam"
];
# docs: https://nixos.org/manual/nixos/stable/options.html#opt-system.stateVersion # docs: https://nixos.org/manual/nixos/stable/options.html#opt-system.stateVersion
system.stateVersion = "21.05"; system.stateVersion = "21.05";
} }

View File

@@ -2,10 +2,17 @@
{ {
sane.persist.root-on-tmpfs = true; sane.persist.root-on-tmpfs = true;
# increase /tmp space (defaults to 50% of RAM) for building large nix things. # we need a /tmp for building large nix things.
# a cross-compiled kernel, particularly, will easily use 30+GB of tmp # a cross-compiled kernel, particularly, will easily use 30+GB of tmp
fileSystems."/tmp".options = [ "size=64G" ]; fileSystems."/tmp" = {
device = "none";
fsType = "tmpfs";
options = [
"mode=777"
"size=64G"
"defaults"
];
};
fileSystems."/nix" = { fileSystems."/nix" = {
# device = "/dev/disk/by-uuid/985a0a32-da52-4043-9df7-615adec2e4ff"; # device = "/dev/disk/by-uuid/985a0a32-da52-4043-9df7-615adec2e4ff";
device = "/dev/disk/by-uuid/0ab0770b-7734-4167-88d9-6e4e20bb2a56"; device = "/dev/disk/by-uuid/0ab0770b-7734-4167-88d9-6e4e20bb2a56";

View File

@@ -19,7 +19,7 @@
"desktopGuiApps" "desktopGuiApps"
"stepmania" "stepmania"
]; ];
sane.programs.consoleUtils.suggestedPrograms = [ "consoleMediaUtils" "desktopConsoleUtils" ]; sane.programs.consoleUtils.suggestedPrograms = [ "consoleMediaUtils" ];
sops.secrets.colin-passwd.neededForUsers = true; sops.secrets.colin-passwd.neededForUsers = true;
@@ -34,6 +34,9 @@
ALLOW_USERS = [ "colin" ]; ALLOW_USERS = [ "colin" ];
}; };
# TODO: only here for debugging
# services.ipfs.enable = true;
# docs: https://nixos.org/manual/nixos/stable/options.html#opt-system.stateVersion # docs: https://nixos.org/manual/nixos/stable/options.html#opt-system.stateVersion
system.stateVersion = "21.05"; system.stateVersion = "21.05";
} }

View File

@@ -2,6 +2,15 @@
{ {
sane.persist.root-on-tmpfs = true; sane.persist.root-on-tmpfs = true;
# we need a /tmp of default size (half RAM) for building large nix things
fileSystems."/tmp" = {
device = "none";
fsType = "tmpfs";
options = [
"mode=777"
"defaults"
];
};
fileSystems."/nix" = { fileSystems."/nix" = {
device = "/dev/disk/by-uuid/75230e56-2c69-4e41-b03e-68475f119980"; device = "/dev/disk/by-uuid/75230e56-2c69-4e41-b03e-68475f119980";

View File

@@ -1,6 +1,6 @@
# doesn't actually *enable* anything, # doesn't actually *enable* anything,
# but sets up any modules such that if they *were* enabled, they'll act as expected. # but sets up any modules such that if they *were* enabled, they'll act as expected.
{ pkgs, ... }: { ... }:
{ {
sane.gui.sxmo = { sane.gui.sxmo = {
greeter = "sway"; greeter = "sway";
@@ -28,11 +28,5 @@
# see <repo:mil/sxmo-utils:scripts/deviceprofiles> # see <repo:mil/sxmo-utils:scripts/deviceprofiles>
# SXMO_DEVICE_NAME = "pine64,pinephone-1.2"; # SXMO_DEVICE_NAME = "pine64,pinephone-1.2";
}; };
package = pkgs.sxmo-utils-latest.overrideAttrs (base: {
postPatch = (base.postPatch or "") + ''
# after volume-button navigation mode, restore full keyboard functionality
cp ${./xkb_mobile_normal_buttons} ./configs/xkb/xkb_mobile_normal_buttons
'';
});
}; };
} }

View File

@@ -1,26 +1,13 @@
# Pinephone
# other setups to reference:
# - <https://hamblingreen.gitlab.io/2022/03/02/my-pinephone-setup.html>
# - sxmo Arch user. lots of app recommendations
#
# wikis, resources, ...:
# - Linux Phone Apps: <https://linuxphoneapps.org/>
# - massive mobile-friendly app database
# - Mobian wiki: <https://wiki.mobian-project.org/doku.php?id=start>
# - recommended apps, chatrooms
{ config, pkgs, lib, ... }: { config, pkgs, lib, ... }:
{ {
imports = [ imports = [
./bootloader.nix ./firmware.nix
./fs.nix ./fs.nix
./gps.nix
./kernel.nix ./kernel.nix
./polyfill.nix ./polyfill.nix
]; ];
sane.roles.client = true; sane.roles.client = true;
sane.zsh.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;
@@ -31,32 +18,36 @@
sops.secrets.colin-passwd.neededForUsers = true; sops.secrets.colin-passwd.neededForUsers = true;
sane.programs.web-browser.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;
# addons.sideberry.enable = false;
};
sane.user.persist.plaintext = [ sane.user.persist.plaintext = [
# TODO: make this just generally conditional upon pulse being enabled? # TODO: make this just generally conditional upon pulse being enabled?
".config/pulse" # persist pulseaudio volume ".config/pulse" # persist pulseaudio volume
]; ];
sane.gui.sxmo.enable = true; sane.gui.sxmo.enable = true;
sane.programs.guiApps.suggestedPrograms = [ "handheldGuiApps" ];
# sane.programs.consoleUtils.enableFor.user.colin = false; # sane.programs.consoleUtils.enableFor.user.colin = false;
# sane.programs.guiApps.enableFor.user.colin = false; # sane.programs.guiApps.enableFor.user.colin = false;
sane.programs.sequoia.enableFor.user.colin = false; sane.programs.sequoia.enableFor.user.colin = false;
sane.programs.tuiApps.enableFor.user.colin = false; # visidata, others, don't compile well sane.programs.tuiApps.enableFor.user.colin = false; # visidata, others, don't compile well
# disabled for faster deploys # disabled for faster deploys (gthumb depends on webkitgtk, particularly)
sane.programs.soundconverter.enableFor.user.colin = false; sane.programs.soundconverter.enableFor.user.colin = false;
sane.programs.eg25-control.enableFor.user.colin = true; sane.programs.gthumb.enableFor.user.colin = false;
sane.programs.jellyfin-media-player.enableFor.user.colin = false;
# 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.firefox.enableFor.user.colin = false; # use epiphany instead
# sane.programs.mpv.enableFor.user.colin = true; # sane.programs.mpv.enableFor.user.colin = true;
boot.loader.efi.canTouchEfiVariables = false; 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
# TODO: compress moby kernels!
boot.loader.generic-extlinux-compatible.configurationLimit = 8; boot.loader.generic-extlinux-compatible.configurationLimit = 8;
# mobile.bootloader.enable = false; # mobile.bootloader.enable = false;
# mobile.boot.stage-1.enable = false; # mobile.boot.stage-1.enable = false;
@@ -113,28 +104,8 @@
services.pipewire.environment.ALSA_CONFIG_UCM2 = ucm-env; services.pipewire.environment.ALSA_CONFIG_UCM2 = ucm-env;
services.pipewire-pulse.environment.ALSA_CONFIG_UCM2 = ucm-env; services.pipewire-pulse.environment.ALSA_CONFIG_UCM2 = ucm-env;
services.wireplumber.environment.ALSA_CONFIG_UCM2 = ucm-env; services.wireplumber.environment.ALSA_CONFIG_UCM2 = ucm-env;
# TODO: move elsewhere...
services.ModemManager.serviceConfig = {
# N.B.: the extra "" in ExecStart serves to force upstream ExecStart to be ignored
ExecStart = [ "" "${pkgs.modemmanager}/bin/ModemManager --debug" ];
# --debug sets DEBUG level logging: so reset
ExecStartPost = [ "${pkgs.modemmanager}/bin/mmcli --set-logging=INFO" ];
};
}; };
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"
'';
hardware.opengl.driSupport = true; hardware.opengl.driSupport = true;
} }

View File

@@ -1,42 +0,0 @@
# 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`
#
# now, something like `gpsd` can directly read from /dev/ttyUSB1.
#
# initial GPS fix can take 15+ minutes.
# meanwhile, services like eg25-manager can speed this up by uploading assisted GPS data to the modem.
#
# geoclue somehow fits in here as a geospatial provider that leverages GPS and also other sources like radio towers
{ 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/demos/where-am-i"
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
sane.services.eg25-control.enable = true;
}

View File

@@ -1,56 +1,71 @@
{ pkgs, ... }: { lib, pkgs, ... }:
let let
dmesg = "${pkgs.util-linux}/bin/dmesg"; # use the last commit on the 5.18 branch (5.18.14)
grep = "${pkgs.gnugrep}/bin/grep"; # manjaro's changes between kernel patch versions tend to be minimal if any.
modprobe = "${pkgs.kmod}/bin/modprobe"; manjaroBase = "https://gitlab.manjaro.org/manjaro-arm/packages/core/linux/-/raw/25bd828cd47b1c6e09fcbcf394a649b89d2876dd";
ensureHWReady = '' manjaroPatch = name: sha256: {
# common boot failure: inherit name;
# blank screen (no backlight even), with the following log: patch = pkgs.fetchpatch {
# ```syslog inherit name;
# sun8i-dw-hdmi 1ee0000.hdmi: Couldn't get the HDMI PHY url = "${manjaroBase}/${name}?inline=false";
# ... inherit sha256;
# 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') # the idea for patching off Manjaro's kernel comes from jakewaksbaum:
then # - https://git.sr.ht/~jakewaksbaum/pi/tree/af20aae5653545d6e67a459b59ee3e1ca8a680b0/item/kernel/default.nix
echo "reprobing sun8i_drm_hdmi" # - he later abandoned this, i think because he's using the Pinephone Pro which received mainline support.
# if a command here fails it errors the whole service, so prefer to log instead manjaroPatches = [
${modprobe} -r sun8i_drm_hdmi || echo "failed to unload sun8i_drm_hdmi" (manjaroPatch
${modprobe} sun8i_drm_hdmi || echo "failed to load sub8i_drm_hdmi" "1001-arm64-dts-allwinner-add-hdmi-sound-to-pine-devices.patch"
fi "sha256-DApd791A+AxB28Ven/MVAyuyVphdo8KQDx8O7oxVPnc="
''; )
# these patches below are critical to enable wifi (RTL8723CS)
# - the alternative is a wholly forked kernel by megi/megous:
# - https://xnux.eu/howtos/build-pinephone-kernel.html#toc-how-to-build-megi-s-pinehpone-kernel
# - i don't know if these patches are based on megi's or original
(manjaroPatch
"2001-Bluetooth-Add-new-quirk-for-broken-local-ext-features.patch"
"sha256-CExhJuUWivegxPdnzKINEsKrMFx/m/1kOZFmlZ2SEOc="
)
(manjaroPatch
"2002-Bluetooth-btrtl-add-support-for-the-RTL8723CS.patch"
"sha256-dDdvOphTcP/Aog93HyH+L9m55laTgtjndPSE4/rnzUA="
)
(manjaroPatch
"2004-arm64-dts-allwinner-enable-bluetooth-pinetab-pinepho.patch"
"sha256-o43P3WzXyHK1PF+Kdter4asuyGAEKO6wf5ixcco2kCQ="
)
# XXX: this one has a Makefile, which hardcodes /sbin/depmod:
# - drivers/staging/rtl8723cs/Makefile
# - not sure if this is problematic?
(manjaroPatch
"2005-staging-add-rtl8723cs-driver.patch"
"sha256-6ywm3dQQ5JYl60CLKarxlSUukwi4QzqctCj3tVgzFbo="
)
];
in in
{ {
# use Megi's kernel:
# even with the Manjaro patches, stock 5.18 has a few issues on Pinephone:
# - no battery charging
# - phone rotation sensor is off by 90 degrees
# - ambient light sensor causes screen brightness to be shakey
# - phosh greeter may not appear after wake from sleep
boot.kernelPackages = pkgs.linuxPackagesFor pkgs.linux-megous; boot.kernelPackages = pkgs.linuxPackagesFor pkgs.linux-megous;
# boot.kernelPackages = pkgs.linuxPackagesFor pkgs.linux-manjaro;
# boot.kernelPackages = pkgs.linuxPackagesFor pkgs.linux_latest;
# alternatively, apply patches directly to stock nixos kernel: # alternatively, use nixos' kernel and add the stuff we want:
# # cross-compilation optimization:
# boot.kernelPackages =
# let p = (import nixpkgs { localSystem = "x86_64-linux"; });
# in p.pkgsCross.aarch64-multiplatform.linuxPackages_5_18;
# # non-cross:
# # boot.kernelPackages = pkgs.linuxPackages_5_18;
# boot.kernelPatches = manjaroPatches ++ [ # boot.kernelPatches = manjaroPatches ++ [
# (patchDefconfig kernelConfig) # (patchDefconfig kernelConfig)
# ]; # ];
# configure nixos to build a compressed kernel image, since it doesn't usually do that for aarch64 target.
# without this i run out of /boot space in < 10 generations
nixpkgs.hostPlatform.linux-kernel = { nixpkgs.hostPlatform.linux-kernel = {
# defaults: # defaults:
name = "aarch64-multiplatform"; name = "aarch64-multiplatform";
@@ -65,7 +80,4 @@ in
target = "Image.gz"; # <-- compress the kernel image target = "Image.gz"; # <-- compress the kernel image
# target = "zImage"; # <-- confuses other parts of nixos :-( # target = "zImage"; # <-- confuses other parts of nixos :-(
}; };
services.xserver.displayManager.job.preStart = ensureHWReady;
systemd.services.greetd.preStart = ensureHWReady;
} }

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 118 KiB

View File

@@ -1,179 +1,17 @@
# this file configures preferences per program, without actually enabling any programs. { sane-lib, ... }:
# 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, ... }:
let
# TODO: generate this from the .svg
# bg = ./nixos-bg-02.png;
bg = pkgs.runCommand "nixos-bg.png" { nativeBuildInputs = [ pkgs.inkscape ]; } ''
inkscape ${./nixos-bg-02.svg} -o $out
'';
in
{ {
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.gui.sxmo = { sane.gui.sxmo = {
nogesture = true;
settings = { settings = {
### hardware: touch screen # touch screen
SXMO_LISGD_INPUT_DEVICE = "/dev/input/by-path/platform-1c2ac00.i2c-event"; SXMO_LISGD_INPUT_DEVICE = "/dev/input/by-path/platform-1c2ac00.i2c-event";
# vol and power are detected correctly by upstream # vol and power are detected correctly by upstream
# preferences
### preferences # N.B. some deviceprofiles explicitly set SXMO_SWAY_SCALE, overwriting what we put here.
# notable bemenu options: SXMO_SWAY_SCALE = "1.5";
# - see `bemenu --help` for all SXMO_ROTATION_GRAVITY = "12800";
# -P, --prefix text to show before highlighted item.
# --scrollbar display scrollbar. (none (default), always, autohide)
# -H, --line-height defines the height to make each menu line (0 = default height). (wx)
# -M, --margin defines the empty space on either side of the menu. (wx)
# -W, --width-factor defines the relative width factor of the menu (from 0 to 1). (wx)
# -B, --border defines the width of the border in pixels around the menu. (wx)
# -R --border-radius defines the radius of the border around the menu (0 = no curved borders).
# --ch defines the height of the cursor (0 = scales with line height). (wx)
# --cw defines the width of the cursor. (wx)
# --hp defines the horizontal padding for the entries in single line mode. (wx)
# --fn defines the font to be used ('name [size]'). (wx)
# --tb defines the title background color. (wx)
# --tf defines the title foreground color. (wx)
# --fb defines the filter background color. (wx)
# --ff defines the filter foreground color. (wx)
# --nb defines the normal background color. (wx)
# --nf defines the normal foreground color. (wx)
# --hb defines the highlighted background color. (wx)
# --hf defines the highlighted foreground color. (wx)
# --fbb defines the feedback background color. (wx)
# --fbf defines the feedback foreground color. (wx)
# --sb defines the selected background color. (wx)
# --sf defines the selected foreground color. (wx)
# --ab defines the alternating background color. (wx)
# --af defines the alternating foreground color. (wx)
# --scb defines the scrollbar background color. (wx)
# --scf defines the scrollbar foreground color. (wx)
# --bdr defines the border color. (wx)
#
# colors are specified as `#RRGGBB`
# defaults:
# --ab "#222222"
# --af "#bbbbbb"
# --bdr "#005577"
# --border 3
# --cb "#222222"
# --center
# --cf "#bbbbbb"
# --fb "#222222"
# --fbb "#eeeeee"
# --fbf "#222222"
# --ff "#bbbbbb"
# --fixed-height
# --fn 'Sxmo 14'
# --hb "#005577"
# --hf "#eeeeee"
# --line-height 20
# --list 16
# --margin 40
# --nb "#222222"
# --nf "#bbbbbb"
# --no-overlap
# --no-spacing
# --sb "#323232"
# --scb "#005577"
# --scf "#eeeeee"
# --scrollbar autohide
# --tb "#005577"
# --tf "#eeeeee"
# --wrap
BEMENU_OPTS = let
bg = "#1d1721"; # slight purple
fg0 = "#d8d8d8"; # inactive text (light grey)
fg1 = "#ffffff"; # active text (white)
accent0 = "#1f5e54"; # darker but saturated teal
accent1 = "#418379"; # teal (matches nixos-bg)
accent2 = "#5b938a"; # brighter but muted teal
in lib.concatStringsSep " " [
"--wrap --scrollbar autohide --fixed-height"
"--center --margin 45"
"--no-spacing"
# XXX: font size doesn't seem to take effect (would prefer larger)
"--fn 'Sxmo 14' --line-height 22 --border 3"
"--bdr '${accent0}'" # border
"--scf '${accent2}' --scb '${accent0}'" # scrollbar
"--tb '${accent0}' --tf '${fg0}'" # title
"--fb '${accent0}' --ff '${fg1}'" # filter (i.e. text that's been entered)
"--hb '${accent1}' --hf '${fg1}'" # selected item
"--nb '${bg}' --nf '${fg0}'" # normal lines (even)
"--ab '${bg}' --af '${fg0}'" # alternated lines (odd)
"--cf '${accent0}' --cb '${accent0}'" # cursor (not very useful)
];
DEFAULT_COUNTRY = "US"; DEFAULT_COUNTRY = "US";
BROWSWER = "librewolf";
# BEMENU lines (wayland DMENU):
# - camera is 9th entry
# - flashlight is 10th entry
# - config is 14th entry. inside that:
# - autorotate is 11th entry
# - system menu is 19th entry
# - close is 20th entry
# - power is 15th entry
# - close is 16th entry
SXMO_BEMENU_LANDSCAPE_LINES = "11"; # default 8
SXMO_BEMENU_PORTRAIT_LINES = "16"; # default 16
SXMO_BG_IMG = "${bg}";
SXMO_LOCK_IDLE_TIME = "15"; # how long between screenoff -> lock -> back to screenoff (default: 8)
# gravity: how far to tilt the device before the screen rotates
# for a given setting, normal <-> invert requires more movement then left <-> right
# i.e. the settingd doesn't feel completely symmetric
# SXMO_ROTATION_GRAVITY default is 16374
# SXMO_ROTATION_GRAVITY = "12800"; # uncomfortably high
# SXMO_ROTATION_GRAVITY = "12500"; # kinda uncomfortable when walking
SXMO_ROTATION_GRAVITY = "12000";
SXMO_SCREENSHOT_DIR = "/home/colin/Pictures"; # default: "$HOME"
# test new scales by running `swaymsg -- output DSI-1 scale x.y`
# SXMO_SWAY_SCALE = "1.5"; # hard to press gPodder icons
SXMO_SWAY_SCALE = "1.8";
# SXMO_SWAY_SCALE = "2";
SXMO_WORKSPACE_WRAPPING = "5"; # how many workspaces. default: 4
# wvkbd layers:
# - full
# - landscape
# - special (e.g. coding symbols like ~)
# - emoji
# - nav
# - simple (like landscape, but no parens/tab/etc; even fewer chars)
# - simplegrid (simple, but grid layout)
# - dialer (digits)
# - cyrillic
# - arabic
# - persian
# - greek
# - georgian
WVKBD_LANDSCAPE_LAYERS = "landscape,special,emoji";
WVKBD_LAYERS = "full,special,emoji";
}; };
package = pkgs.sxmo-utils-latest.overrideAttrs (base: {
postPatch = (base.postPatch or "") + ''
cat <<EOF >> ./configs/default_hooks/sxmo_hook_start.sh
# rotate UI based on physical display angle by default
sxmo_daemons.sh start autorotate sxmo_autorotate.sh
EOF
'';
});
}; };
} }

View File

@@ -18,16 +18,10 @@
sane.roles.build-machine.enable = true; sane.roles.build-machine.enable = true;
sane.roles.build-machine.emulation = false; sane.roles.build-machine.emulation = false;
sane.zsh.showDeadlines = false; # ~/knowledge doesn't always exist sane.zsh.showDeadlines = false; # ~/knowledge doesn't always exist
sane.programs.consoleUtils.suggestedPrograms = [
"desktopConsoleUtils"
"sane-scripts.stop-all-servo"
];
sane.services.dyn-dns.enable = true; sane.services.dyn-dns.enable = true;
sane.services.wg-home.enable = true; sane.services.wg-home.enable = true;
sane.services.wg-home.enableWan = true; sane.services.wg-home.enableWan = true;
sane.services.wg-home.ip = config.sane.hosts.by-name."servo".wg-home.ip; sane.services.wg-home.ip = config.sane.hosts.by-name."servo".wg-home.ip;
sane.nixcache.substituters.servo = false;
sane.nixcache.substituters.desko = false;
# sane.services.duplicity.enable = true; # TODO: re-enable after HW upgrade # sane.services.duplicity.enable = true; # TODO: re-enable after HW upgrade
# automatically log in at the virtual consoles. # automatically log in at the virtual consoles.

View File

@@ -2,9 +2,15 @@
{ {
sane.persist.root-on-tmpfs = true; sane.persist.root-on-tmpfs = true;
# increase /tmp space (defaults to 50% of RAM) for building large nix things. # we need a /tmp for building large nix things
# even the stock `nixpkgs.linux` consumes > 16 GB of tmp fileSystems."/tmp" = {
fileSystems."/tmp".options = [ "size=32G" ]; device = "none";
fsType = "tmpfs";
options = [
"mode=777"
"defaults"
];
};
fileSystems."/nix" = { fileSystems."/nix" = {
device = "/dev/disk/by-uuid/cc81cca0-3cc7-4d82-a00c-6243af3e7776"; device = "/dev/disk/by-uuid/cc81cca0-3cc7-4d82-a00c-6243af3e7776";
@@ -38,7 +44,7 @@
sane.persist.sys.plaintext = [ sane.persist.sys.plaintext = [
# TODO: this is overly broad; only need media and share directories to be persisted # TODO: this is overly broad; only need media and share directories to be persisted
{ user = "colin"; group = "users"; path = "/var/lib/uninsane"; } { user = "colin"; group = "users"; directory = "/var/lib/uninsane"; }
]; ];
# make sure large media is stored to the HDD # make sure large media is stored to the HDD
sane.persist.sys.ext = [ sane.persist.sys.ext = [
@@ -46,22 +52,21 @@
user = "colin"; user = "colin";
group = "users"; group = "users";
mode = "0777"; mode = "0777";
path = "/var/lib/uninsane/media/Videos"; directory = "/var/lib/uninsane/media/Videos";
} }
{ {
user = "colin"; user = "colin";
group = "users"; group = "users";
mode = "0777"; mode = "0777";
path = "/var/lib/uninsane/media/freeleech"; directory = "/var/lib/uninsane/media/freeleech";
}
{
user = "colin";
group = "users";
mode = "0777";
path = "/var/lib/uninsane/media/datasets";
} }
]; ];
# in-memory compressed RAM (seems to be dynamically sized)
# zramSwap = {
# enable = true;
# };
# btrfs doesn't easily support swapfiles # btrfs doesn't easily support swapfiles
# swapDevices = [ # swapDevices = [
# { device = "/nix/persist/swapfile"; size = 4096; } # { device = "/nix/persist/swapfile"; size = 4096; }

View File

@@ -13,7 +13,7 @@ in
lib.mkIf false lib.mkIf false
{ {
sane.persist.sys.plaintext = [ sane.persist.sys.plaintext = [
{ inherit user group; mode = "0700"; path = svc-dir; } { inherit user group; mode = "0700"; directory = svc-dir; }
]; ];
services.calibre-web.enable = true; services.calibre-web.enable = true;

View File

@@ -7,7 +7,7 @@
./email ./email
./ejabberd.nix ./ejabberd.nix
./freshrss.nix ./freshrss.nix
./export ./ftp
./gitea.nix ./gitea.nix
./goaccess.nix ./goaccess.nix
./ipfs.nix ./ipfs.nix
@@ -18,6 +18,7 @@
./lemmy.nix ./lemmy.nix
./matrix ./matrix
./navidrome.nix ./navidrome.nix
./nfs.nix
./nixserve.nix ./nixserve.nix
./nginx.nix ./nginx.nix
./pict-rs.nix ./pict-rs.nix

View File

@@ -17,86 +17,73 @@
{ config, lib, pkgs, ... }: { config, lib, pkgs, ... }:
# XXX: avatar support works in MUCs but not DMs # XXX: avatar support works in MUCs but not DMs
let # lib.mkIf false
# TODO: this range could be larger, but right now that's costly because each element is its own UPnP forward
# TURN port range (inclusive)
turnPortLow = 49152;
turnPortHigh = 49167;
turnPortRange = lib.range turnPortLow turnPortHigh;
in
{ {
sane.persist.sys.plaintext = [ sane.persist.sys.plaintext = [
{ user = "ejabberd"; group = "ejabberd"; path = "/var/lib/ejabberd"; } { user = "ejabberd"; group = "ejabberd"; directory = "/var/lib/ejabberd"; }
]; ];
sane.ports.ports = lib.mkMerge ([ sane.ports.ports."3478" = {
{
"3478" = {
protocol = [ "tcp" "udp" ]; protocol = [ "tcp" "udp" ];
visibleTo.lan = true; visibleTo.lan = true;
visibleTo.wan = true; visibleTo.wan = true;
description = "colin-xmpp-stun-turn"; description = "colin-xmpp-stun-turn";
}; };
"5222" = { sane.ports.ports."5222" = {
protocol = [ "tcp" ]; protocol = [ "tcp" ];
visibleTo.lan = true; visibleTo.lan = true;
visibleTo.wan = true; visibleTo.wan = true;
description = "colin-xmpp-client-to-server"; description = "colin-xmpp-client-to-server";
}; };
"5223" = { sane.ports.ports."5223" = {
protocol = [ "tcp" ]; protocol = [ "tcp" ];
visibleTo.lan = true; visibleTo.lan = true;
visibleTo.wan = true; visibleTo.wan = true;
description = "colin-xmpps-client-to-server"; # XMPP over TLS description = "colin-xmpps-client-to-server"; # XMPP over TLS
}; };
"5269" = { sane.ports.ports."5269" = {
protocol = [ "tcp" ]; protocol = [ "tcp" ];
visibleTo.wan = true; visibleTo.wan = true;
description = "colin-xmpp-server-to-server"; description = "colin-xmpp-server-to-server";
}; };
"5270" = { sane.ports.ports."5270" = {
protocol = [ "tcp" ]; protocol = [ "tcp" ];
visibleTo.wan = true; visibleTo.wan = true;
description = "colin-xmpps-server-to-server"; # XMPP over TLS description = "colin-xmpps-server-to-server"; # XMPP over TLS
}; };
"5280" = { sane.ports.ports."5280" = {
protocol = [ "tcp" ]; protocol = [ "tcp" ];
visibleTo.lan = true; visibleTo.lan = true;
visibleTo.wan = true; visibleTo.wan = true;
description = "colin-xmpp-bosh"; description = "colin-xmpp-bosh";
}; };
"5281" = { sane.ports.ports."5281" = {
protocol = [ "tcp" ]; protocol = [ "tcp" ];
visibleTo.lan = true; visibleTo.lan = true;
visibleTo.wan = true; visibleTo.wan = true;
description = "colin-xmpp-bosh-https"; description = "colin-xmpp-bosh-https";
}; };
"5349" = { sane.ports.ports."5349" = {
protocol = [ "tcp" ]; protocol = [ "tcp" ];
visibleTo.lan = true; visibleTo.lan = true;
visibleTo.wan = true; visibleTo.wan = true;
description = "colin-xmpp-stun-turn-over-tls"; description = "colin-xmpp-stun-turn-over-tls";
}; };
"5443" = { sane.ports.ports."5443" = {
protocol = [ "tcp" ]; protocol = [ "tcp" ];
visibleTo.lan = true; visibleTo.lan = true;
visibleTo.wan = true; visibleTo.wan = true;
description = "colin-xmpp-web-services"; # file uploads, websockets, admin description = "colin-xmpp-web-services"; # file uploads, websockets, admin
}; };
}
] ++ (builtins.map # TODO: forward these TURN ports!
(port: { networking.firewall.allowedTCPPortRanges = [{
"${builtins.toString port}" = let from = 49152; # TURN
count = port - turnPortLow + 1; to = 49408;
numPorts = turnPortHigh - turnPortLow + 1; }];
in { networking.firewall.allowedUDPPortRanges = [{
protocol = [ "tcp" "udp" ]; from = 49152; # TURN
visibleTo.lan = true; to = 49408;
visibleTo.wan = true; }];
description = "colin-xmpp-turn-${builtins.toString count}-of-${builtins.toString numPorts}";
};
})
turnPortRange
));
# provide access to certs # provide access to certs
# TODO: this should just be `acme`. then we also add nginx to the `acme` group. # TODO: this should just be `acme`. then we also add nginx to the `acme` group.
@@ -285,8 +272,8 @@ in
module: ejabberd_stun module: ejabberd_stun
transport: tcp transport: tcp
use_turn: true use_turn: true
turn_min_port: ${builtins.toString turnPortLow} turn_min_port: 49152
turn_max_port: ${builtins.toString turnPortHigh} turn_max_port: 65535
turn_ipv4_address: %ANATIVE% turn_ipv4_address: %ANATIVE%
- -
# STUN+TURN UDP # STUN+TURN UDP
@@ -294,8 +281,8 @@ in
module: ejabberd_stun module: ejabberd_stun
transport: udp transport: udp
use_turn: true use_turn: true
turn_min_port: ${builtins.toString turnPortLow} turn_min_port: 49152
turn_max_port: ${builtins.toString turnPortHigh} turn_max_port: 65535
turn_ipv4_address: %ANATIVE% turn_ipv4_address: %ANATIVE%
- -
# STUN+TURN TLS over TCP # STUN+TURN TLS over TCP
@@ -305,8 +292,8 @@ in
tls: true tls: true
certfile: /var/lib/acme/uninsane.org/full.pem certfile: /var/lib/acme/uninsane.org/full.pem
use_turn: true use_turn: true
turn_min_port: ${builtins.toString turnPortLow} turn_min_port: 49152
turn_max_port: ${builtins.toString turnPortHigh} turn_max_port: 65535
turn_ipv4_address: %ANATIVE% turn_ipv4_address: %ANATIVE%
# TODO: enable mod_fail2ban # TODO: enable mod_fail2ban

View File

@@ -20,9 +20,9 @@ in
{ {
sane.persist.sys.plaintext = [ sane.persist.sys.plaintext = [
# TODO: mode? could be more granular # TODO: mode? could be more granular
{ user = "opendkim"; group = "opendkim"; path = "/var/lib/opendkim"; } { user = "opendkim"; group = "opendkim"; directory = "/var/lib/opendkim"; }
{ user = "root"; group = "root"; path = "/var/lib/postfix"; } { user = "root"; group = "root"; directory = "/var/lib/postfix"; }
{ user = "root"; group = "root"; path = "/var/spool/mail"; } { user = "root"; group = "root"; directory = "/var/spool/mail"; }
# *probably* don't need these dirs: # *probably* don't need these dirs:
# "/var/lib/dhparams" # https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/security/dhparams.nix # "/var/lib/dhparams" # https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/security/dhparams.nix
# "/var/lib/dovecot" # "/var/lib/dovecot"

View File

@@ -1,42 +0,0 @@
{ config, ... }:
{
imports = [
./nfs.nix
./sftpgo.nix
];
fileSystems."/var/export/media" = {
# everything in here could be considered publicly readable (based on the viewer's legal jurisdiction)
device = "/var/lib/uninsane/media";
options = [ "rbind" ];
};
fileSystems."/var/export/playground" = {
device = config.fileSystems."/mnt/persist/ext".device;
fsType = "btrfs";
options = [
"subvol=export-playground"
"compress=zstd"
"defaults"
];
};
sane.fs."/var/export/README.md" = {
wantedBy = [ "nfs.service" "sftpgo.service" ];
file.text = ''
- media/ read-only: Videos, Music, Books, etc
- playground/ read-write: use it to share files with other users of this server
'';
};
# sane.fs."/var/lib/sftpgo/export/playground/README.md" = {
# wantedBy = [ "nfs.service" "sftpgo.service" ];
# file.text = ''
# this directory is intentionally read+write by anyone.
# there are no rules, except a server-level quota:
# - share files
# - write poetry
# - be a friendly troll
# '';
# };
}

View File

@@ -1,193 +0,0 @@
# docs:
# - <https://github.com/drakkan/sftpgo>
# - config options: <https://github.com/drakkan/sftpgo/blob/main/docs/full-configuration.md>
# - config defaults: <https://github.com/drakkan/sftpgo/blob/main/sftpgo.json>
# - nixos options: <repo:nixos/nixpkgs:nixos/modules/services/web-apps/sftpgo.nix>
# - nixos example: <repo:nixos/nixpkgs:nixos/tests/sftpgo.nix>
#
# sftpgo is a FTP server that also supports WebDAV, SFTP, and web clients.
#
# TODO: change umask so sftpgo-created files default to 644.
# - it does indeed appear that the 600 is not something sftpgo is explicitly doing.
#
# TODO: enforce a "quota" by placing /playground on a btrfs subvolume
# - sane.persist API could expose a `subvolume` option to make this feel natural
{ config, lib, pkgs, sane-lib, ... }:
let
# user permissions:
# - see <repo:drakkan/sftpgo:internal/dataprovider/user.go>
# - "*" = grant all permissions
# - read-only perms:
# - "list" = list files and directories
# - "download"
# - rw perms:
# - "upload"
# - "overwrite" = allow uploads to replace existing files
# - "delete" = delete files and directories
# - "delete_files"
# - "delete_dirs"
# - "rename" = rename files and directories
# - "rename_files"
# - "rename_dirs"
# - "create_dirs"
# - "create_symlinks"
# - "chmod"
# - "chown"
# - "chtimes" = change atime/mtime (access and modification times)
#
# home_dir:
# - it seems (empirically) that a user can't cd above their home directory.
# though i don't have a reference for that in the docs.
authResponseSuccess = {
status = 1;
username = "anonymous";
expiration_date = 0;
home_dir = "/var/export";
# uid/gid 0 means to inherit sftpgo uid.
# - i.e. users can't read files which Linux user `sftpgo` can't read
# - uploaded files belong to Linux user `sftpgo`
# other uid/gid values aren't possible for localfs backend, unless i let sftpgo use `sudo`.
uid = 0;
gid = 0;
# uid = 65534;
# gid = 65534;
max_sessions = 0;
# quota_*: 0 means to not use SFTP's quota system
quota_size = 0;
quota_files = 0;
permissions = {
"/" = [ "list" "download" ];
"/playground" = [
# read-only:
"list"
"download"
# write:
"upload"
"overwrite"
"delete"
"rename"
"create_dirs"
"create_symlinks"
# intentionally omitted:
# "chmod"
# "chown"
# "chtimes"
];
};
upload_bandwidth = 0;
download_bandwidth = 0;
filters = {
allowed_ip = [];
denied_ip = [];
};
public_keys = [];
# other fields:
# ? groups
# ? virtual_folders
};
authResponseFail = {
username = "";
};
authSuccessJson = pkgs.writeText "sftp-auth-success.json" (builtins.toJSON authResponseSuccess);
authFailJson = pkgs.writeText "sftp-auth-fail.json" (builtins.toJSON authResponseFail);
unwrappedAuthProgram = pkgs.static-nix-shell.mkBash {
pname = "sftpgo_external_auth_hook";
src = ./.;
pkgs = [ "coreutils" ];
};
authProgram = pkgs.writeShellScript "sftpgo-auth-hook" ''
${unwrappedAuthProgram}/bin/sftpgo_external_auth_hook ${authFailJson} ${authSuccessJson}
'';
in
{
# 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
# - file data, directory listings, etc need to be transferred on an ephemeral "data port".
# - 50000-50100 is a common port range for this.
sane.ports.ports = {
"21" = {
protocol = [ "tcp" ];
visibleTo.lan = true;
description = "colin-FTP server";
};
} // (sane-lib.mapToAttrs
(port: {
name = builtins.toString port;
value = {
protocol = [ "tcp" ];
visibleTo.lan = true;
description = "colin-FTP server data port range";
};
})
(lib.range 50000 50100)
);
services.sftpgo = {
enable = true;
settings = {
ftpd = {
bindings = [
{
# binding this means any wireguard client can connect
address = "10.0.10.5";
port = 21;
debug = true;
}
{
# binding this means any LAN client can connect
address = "10.78.79.51";
port = 21;
debug = true;
}
];
# active mode is susceptible to "bounce attacks", without much benefit over passive mode
disable_active_mode = true;
hash_support = true;
passive_port_range = {
start = 50000;
end = 50100;
};
banner = ''
Welcome, friends, to Colin's read-only FTP server! Also available via NFS on the same host.
Username: "anonymous"
Password: "anonymous"
CONFIGURE YOUR CLIENT FOR "PASSIVE" mode, e.g. `ftp --passive uninsane.org`
Please let me know if anything's broken or not as it should be. Otherwise, browse and DL freely :)
'';
};
data_provider = {
driver = "memory";
external_auth_hook = "${authProgram}";
# track_quota:
# - 0: disable quota tracking
# - 1: quota is updated on every upload/delete, even if user has no quota restriction
# - 2: quota is updated on every upload/delete, but only if user/folder has a quota restriction (default, i think)
# track_quota = 2;
};
};
};
# fileSystems."/var/lib/sftpgo/export/media" = {
# # everything in here could be considered publicly readable (based on the viewer's legal jurisdiction)
# device = "/var/lib/uninsane/media";
# options = [ "rbind" ];
# };
# sane.persist.sys.plaintext = [
# { user = "sftpgo"; group = "sftpgo"; path = "/var/lib/sftpgo/export/playground"; }
# ];
# sane.fs."/var/lib/sftpgo/export/playground/README.md" = {
# wantedBy = [ "sftpgo.service" ];
# file.text = ''
# this directory is intentionally read+write by anyone.
# there are no rules, except a server-level quota:
# - share files
# - write poetry
# - be a friendly troll
# '';
# };
}

View File

@@ -1,23 +0,0 @@
#!/usr/bin/env nix-shell
#!nix-shell -i bash -p coreutils
# vim: set filetype=bash :
#
# available environment variables:
# - SFTPGO_AUTHD_USERNAME
# - SFTPGO_AUTHD_USER
# - SFTPGO_AUTHD_IP
# - SFTPGO_AUTHD_PROTOCOL = { "DAV", "FTP", "HTTP", "SSH" }
# - SFTPGO_AUTHD_PASSWORD
# - SFTPGO_AUTHD_PUBLIC_KEY
# - SFTPGO_AUTHD_KEYBOARD_INTERACTIVE
# - SFTPGO_AUTHD_TLS_CERT
#
#
# call with <script_name> /path/to/fail/response.json /path/to/success/response.json
if [ "$SFTPGO_AUTHD_USERNAME" = "anonymous" ]; then
cat "$2"
else
cat "$1"
fi

View File

@@ -16,7 +16,7 @@
mode = "0400"; mode = "0400";
}; };
sane.persist.sys.plaintext = [ sane.persist.sys.plaintext = [
{ user = "freshrss"; group = "freshrss"; path = "/var/lib/freshrss"; } { user = "freshrss"; group = "freshrss"; directory = "/var/lib/freshrss"; }
]; ];
services.freshrss.enable = true; services.freshrss.enable = true;

View File

@@ -0,0 +1,70 @@
# docs:
# - <https://github.com/drakkan/sftpgo>
# - config options: <https://github.com/drakkan/sftpgo/blob/main/docs/full-configuration.md>
# - config defaults: <https://github.com/drakkan/sftpgo/blob/main/sftpgo.json>
# - nixos options: <repo:nixos/nixpkgs:nixos/modules/services/web-apps/sftpgo.nix>
#
# sftpgo is a FTP server that also supports WebDAV, SFTP, and web clients.
{ lib, pkgs, sane-lib, ... }:
let
authProgram = pkgs.static-nix-shell.mkBash {
pname = "sftpgo_external_auth_hook";
src = ./.;
};
in
{
# 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
# - file data, directory listings, etc need to be transferred on an ephemeral "data port".
# - 50000-50100 is a common port range for this.
sane.ports.ports = {
"21" = {
protocol = [ "tcp" ];
visibleTo.lan = true;
description = "colin-FTP server";
};
} // (sane-lib.mapToAttrs
(port: {
name = builtins.toString port;
value = {
protocol = [ "tcp" ];
visibleTo.lan = true;
description = "colin-FTP server data port range";
};
})
(lib.range 50000 50100)
);
services.sftpgo = {
enable = true;
settings = {
ftpd = {
bindings = [{
address = "10.0.10.5";
port = 21;
debug = true;
}];
# active mode is susceptible to "bounce attacks", without much benefit over passive mode
disable_active_mode = true;
hash_support = true;
passive_port_range = {
start = 50000;
end = 50100;
};
banner = ''
Welcome, friends, to Colin's read-only FTP server! Also available via NFS on the same host.
Please let me know if anything's broken or not as it should be. Otherwise, browse and DL freely :)
'';
};
data_provider = {
driver = "memory";
external_auth_hook = "${authProgram}/bin/sftpgo_external_auth_hook";
};
};
};
}

View File

@@ -0,0 +1,55 @@
#!/usr/bin/env nix-shell
#!nix-shell -i bash
# vim: set filetype=bash :
#
# available environment variables:
# - SFTPGO_AUTHD_USERNAME
# - SFTPGO_AUTHD_USER
# - SFTPGO_AUTHD_IP
# - SFTPGO_AUTHD_PROTOCOL = { "DAV", "FTP", "HTTP", "SSH" }
# - SFTPGO_AUTHD_PASSWORD
# - SFTPGO_AUTHD_PUBLIC_KEY
# - SFTPGO_AUTHD_KEYBOARD_INTERACTIVE
# - SFTPGO_AUTHD_TLS_CERT
#
# user permissions:
# - see <repo:drakkan/sftpgo:internal/dataprovider/user.go>
# - "*" = grant all permissions
# - read-only perms:
# - "list" = list files and directories
# - "download"
# - rw perms:
# - "upload"
# - "overwrite" = allow uploads to replace existing files
# - "delete" = delete files and directories
# - "delete_files"
# - "delete_dirs"
# - "rename" = rename files and directories
# - "rename_files"
# - "rename_dirs"
# - "create_dirs"
# - "create_symlinks"
# - "chmod"
# - "chown"
# - "chtimes" = change atime/mtime (access and modification times)
#
# home_dir:
# - it seems (empirically) that a user can't cd above their home directory.
# though i don't have a reference for that in the docs.
# TODO: don't reuse /var/nfs/export here. formalize this some other way.
if [ "$SFTPGO_AUTHD_USERNAME" = "anonymous" ]; then
echo '{'
echo ' "status":1,'
echo ' "username":"anonymous","expiration_date":0,'
echo ' "home_dir":"/var/nfs/export","uid":65534,"gid":65534,"max_sessions":0,"quota_size":0,"quota_files":100000,'
echo ' "permissions":{'
echo ' "/":["list", "download"]'
echo ' },'
echo ' "upload_bandwidth":0,"download_bandwidth":0,'
echo ' "filters":{"allowed_ip":[],"denied_ip":[]},"public_keys":[]'
echo '}'
else
echo '{"username":""}'
fi

View File

@@ -4,7 +4,7 @@
{ {
sane.persist.sys.plaintext = [ sane.persist.sys.plaintext = [
# TODO: mode? could be more granular # TODO: mode? could be more granular
{ user = "git"; group = "gitea"; path = "/var/lib/gitea"; } { user = "git"; group = "gitea"; directory = "/var/lib/gitea"; }
]; ];
services.gitea.enable = true; services.gitea.enable = true;
services.gitea.user = "git"; # default is 'gitea' services.gitea.user = "git"; # default is 'gitea'

View File

@@ -12,7 +12,7 @@ lib.mkIf false # i don't actively use ipfs anymore
{ {
sane.persist.sys.plaintext = [ sane.persist.sys.plaintext = [
# TODO: mode? could be more granular # TODO: mode? could be more granular
{ user = "261"; group = "261"; path = "/var/lib/ipfs"; } { user = "261"; group = "261"; directory = "/var/lib/ipfs"; }
]; ];
networking.firewall.allowedTCPPorts = [ 4001 ]; networking.firewall.allowedTCPPorts = [ 4001 ];

View File

@@ -3,7 +3,7 @@
{ {
sane.persist.sys.plaintext = [ sane.persist.sys.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?
{ user = "root"; group = "root"; path = "/var/lib/jackett"; } { user = "root"; group = "root"; directory = "/var/lib/jackett"; }
]; ];
services.jackett.enable = true; services.jackett.enable = true;

View File

@@ -41,7 +41,7 @@
}; };
sane.persist.sys.plaintext = [ sane.persist.sys.plaintext = [
{ user = "jellyfin"; group = "jellyfin"; mode = "0700"; path = "/var/lib/jellyfin"; } { user = "jellyfin"; group = "jellyfin"; mode = "0700"; directory = "/var/lib/jellyfin"; }
]; ];
sane.fs."/var/lib/jellyfin/config/logging.json" = { sane.fs."/var/lib/jellyfin/config/logging.json" = {
# "Emby.Dlna" logging: <https://jellyfin.org/docs/general/networking/dlna> # "Emby.Dlna" logging: <https://jellyfin.org/docs/general/networking/dlna>

View File

@@ -5,7 +5,7 @@ let
in in
{ {
sane.persist.sys.plaintext = [ sane.persist.sys.plaintext = [
{ inherit user group; mode = "0700"; path = stateDir; } { inherit user group; mode = "0700"; directory = stateDir; }
]; ];
services.komga.enable = true; services.komga.enable = true;

View File

@@ -3,23 +3,13 @@
# - <repo:LemmyNet/lemmy:docker/nginx.conf> # - <repo:LemmyNet/lemmy:docker/nginx.conf>
# - <repo:LemmyNet/lemmy-ansible:templates/nginx.conf> # - <repo:LemmyNet/lemmy-ansible:templates/nginx.conf>
{ config, lib, pkgs, ... }: { config, lib, ... }:
let let
inherit (builtins) toString; inherit (builtins) toString;
inherit (lib) mkForce; inherit (lib) mkForce;
uiPort = 1234; # default ui port is 1234 uiPort = 1234; # default ui port is 1234
backendPort = 8536; # default backend port is 8536 backendPort = 8536; # default backend port is 8536
#^ i guess the "backend" port is used for federation? # - i guess the "backend" port is used for federation?
pict-rs = pkgs.pict-rs.overrideAttrs (upstream: {
# as of v 0.4.2, all non-GIF video is forcibly transcoded.
# that breaks lemmy, because of the request latency.
# and it eats up hella CPU.
# pict-rs is iffy around video altogether: mp4 seems the best supported.
postPatch = (upstream.postPatch or "") + ''
substituteInPlace src/validate.rs \
--replace 'if transcode_options.needs_reencode() {' 'if false {'
'';
});
in { in {
services.lemmy = { services.lemmy = {
enable = true; enable = true;
@@ -66,20 +56,4 @@ in {
}; };
sane.dns.zones."uninsane.org".inet.CNAME."lemmy" = "native"; sane.dns.zones."uninsane.org".inet.CNAME."lemmy" = "native";
#v DO NOT REMOVE: defaults to 0.3, instead of latest, so always need to explicitly set this.
services.pict-rs.package = pict-rs;
# pict-rs configuration is applied in this order:
# - via toml
# - via env vars (overrides everything above)
# - via CLI flags (overrides everything above)
# some of the CLI flags have defaults, making it the only actual way to configure certain things even when docs claim otherwise.
# CLI args: <https://git.asonix.dog/asonix/pict-rs#user-content-running>
systemd.services.pict-rs.serviceConfig.ExecStart = lib.mkForce (lib.concatStringsSep " " [
"${lib.getBin pict-rs}/bin/pict-rs run"
"--media-max-frame-count" (builtins.toString (30*60*60))
"--media-process-timeout 120"
"--media-enable-full-video true" # allow audio
]);
} }

View File

@@ -11,7 +11,7 @@
]; ];
sane.persist.sys.plaintext = [ sane.persist.sys.plaintext = [
{ user = "matrix-synapse"; group = "matrix-synapse"; path = "/var/lib/matrix-synapse"; } { user = "matrix-synapse"; group = "matrix-synapse"; directory = "/var/lib/matrix-synapse"; }
]; ];
services.matrix-synapse.enable = true; services.matrix-synapse.enable = true;
# this changes the default log level from INFO to WARN. # this changes the default log level from INFO to WARN.

View File

@@ -6,7 +6,7 @@
lib.mkIf false lib.mkIf false
{ {
sane.persist.sys.plaintext = [ sane.persist.sys.plaintext = [
{ user = "matrix-synapse"; group = "matrix-synapse"; path = "/var/lib/mx-puppet-discord"; } { user = "matrix-synapse"; group = "matrix-synapse"; directory = "/var/lib/mx-puppet-discord"; }
]; ];
services.matrix-synapse.settings.app_service_config_files = [ services.matrix-synapse.settings.app_service_config_files = [

View File

@@ -1,14 +1,16 @@
# 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>
# TODO: /quit message for bridged users reveals to IRC users that i'm using a bridge;
# probably want to remove that. # probably want to remove that.
{ config, lib, ... }: { config, lib, ... }:
let let
ircServer = { name, additionalAddresses ? [], sasl ? true, port ? 6697 }: let ircServer = { name, additionalAddresses ? [], sasl ? true }: 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 name additionalAddresses sasl port; inherit name additionalAddresses sasl;
port = 6697;
ssl = true; 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
@@ -103,7 +105,7 @@ in
sane.persist.sys.plaintext = [ sane.persist.sys.plaintext = [
# TODO: mode? # TODO: mode?
{ user = "matrix-appservice-irc"; group = "matrix-appservice-irc"; path = "/var/lib/matrix-appservice-irc"; } { user = "matrix-appservice-irc"; group = "matrix-appservice-irc"; directory = "/var/lib/matrix-appservice-irc"; }
]; ];
# XXX: matrix-appservice-irc PreStart tries to chgrp the registration.yml to matrix-synapse, # XXX: matrix-appservice-irc PreStart tries to chgrp the registration.yml to matrix-synapse,
@@ -149,7 +151,6 @@ in
}; };
"irc.oftc.net" = ircServer { "irc.oftc.net" = ircServer {
name = "oftc"; name = "oftc";
sasl = false;
# notable channels: # notable channels:
# - #sxmo # - #sxmo
# - #sxmo-offtopic # - #sxmo-offtopic

View File

@@ -3,8 +3,8 @@
{ config, pkgs, ... }: { config, pkgs, ... }:
{ {
sane.persist.sys.plaintext = [ sane.persist.sys.plaintext = [
{ user = "mautrix-signal"; group = "mautrix-signal"; path = "/var/lib/mautrix-signal"; } { user = "mautrix-signal"; group = "mautrix-signal"; directory = "/var/lib/mautrix-signal"; }
{ user = "signald"; group = "signald"; path = "/var/lib/signald"; } { user = "signald"; group = "signald"; directory = "/var/lib/signald"; }
]; ];
# allow synapse to read the registration file # allow synapse to read the registration file

View File

@@ -2,7 +2,7 @@
{ {
sane.persist.sys.plaintext = [ sane.persist.sys.plaintext = [
{ user = "navidrome"; group = "navidrome"; path = "/var/lib/navidrome"; } { user = "navidrome"; group = "navidrome"; directory = "/var/lib/navidrome"; }
]; ];
services.navidrome.enable = true; services.navidrome.enable = true;
services.navidrome.settings = { services.navidrome.settings = {

View File

@@ -56,6 +56,12 @@
# #
# 10.0.0.0/8 to export (readonly) both to LAN (unencrypted) and wg vpn (encrypted) # 10.0.0.0/8 to export (readonly) both to LAN (unencrypted) and wg vpn (encrypted)
services.nfs.server.exports = '' services.nfs.server.exports = ''
/var/export 10.78.79.0/22(ro,crossmnt,fsid=0,subtree_check) 10.0.10.0/24(rw,no_root_squash,crossmnt,fsid=0,subtree_check) /var/nfs/export 10.78.79.0/22(ro,crossmnt,fsid=0,subtree_check) 10.0.10.0/24(rw,no_root_squash,crossmnt,fsid=0,subtree_check)
''; '';
fileSystems."/var/nfs/export/media" = {
# everything in here could be considered publicly readable (based on the viewer's legal jurisdiction)
device = "/var/lib/uninsane/media";
options = [ "rbind" ];
};
} }

View File

@@ -101,8 +101,7 @@ in
}; };
# allow ActivityPub clients to discover how to reach @user@uninsane.org # allow ActivityPub clients to discover how to reach @user@uninsane.org
# see: https://git.pleroma.social/pleroma/pleroma/-/merge_requests/3361/ # TODO: waiting on https://git.pleroma.social/pleroma/pleroma/-/merge_requests/3361/
# not sure this makes sense while i run multiple AP services (pleroma, lemmy)
# locations."/.well-known/nodeinfo" = { # locations."/.well-known/nodeinfo" = {
# proxyPass = "http://127.0.0.1:4000"; # proxyPass = "http://127.0.0.1:4000";
# extraConfig = pleromaExtraConfig; # extraConfig = pleromaExtraConfig;
@@ -135,8 +134,8 @@ in
sane.persist.sys.plaintext = [ sane.persist.sys.plaintext = [
# TODO: mode? # TODO: mode?
{ user = "acme"; group = "acme"; path = "/var/lib/acme"; } { user = "acme"; group = "acme"; directory = "/var/lib/acme"; }
{ user = "colin"; group = "users"; path = "/var/www/sites"; } { user = "colin"; group = "users"; directory = "/var/www/sites"; }
]; ];
# let's encrypt default chain looks like: # let's encrypt default chain looks like:

View File

@@ -6,7 +6,7 @@ let
in in
{ {
sane.persist.sys.plaintext = lib.mkIf cfg.enable [ sane.persist.sys.plaintext = lib.mkIf cfg.enable [
{ user = "pict-rs"; group = "pict-rs"; path = cfg.dataDir; } { user = "pict-rs"; group = "pict-rs"; directory = cfg.dataDir; }
]; ];
systemd.services.pict-rs.serviceConfig = { systemd.services.pict-rs.serviceConfig = {

View File

@@ -1,21 +1,14 @@
# docs: # docs:
# - <https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/services/networking/pleroma.nix> # - https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/services/networking/pleroma.nix
# - <https://docs.pleroma.social/backend/configuration/cheatsheet/> # - https://docs.pleroma.social/backend/configuration/cheatsheet/
# example config:
# - <https://git.pleroma.social/pleroma/pleroma/-/blob/develop/config/config.exs>
# #
# to run it in a oci-container: <https://github.com/barrucadu/nixfiles/blob/master/services/pleroma.nix> # to run it in a oci-container: https://github.com/barrucadu/nixfiles/blob/master/services/pleroma.nix
#
# admin frontend: <https://fed.uninsane.org/pleroma/admin>
{ config, pkgs, ... }: { config, pkgs, ... }:
let
logLevel = "warn";
# logLevel = "debug";
in
{ {
sane.persist.sys.plaintext = [ sane.persist.sys.plaintext = [
{ user = "pleroma"; group = "pleroma"; path = "/var/lib/pleroma"; } # TODO: mode? could be more granular
{ user = "pleroma"; group = "pleroma"; directory = "/var/lib/pleroma"; }
]; ];
services.pleroma.enable = true; services.pleroma.enable = true;
services.pleroma.secretConfigFile = config.sops.secrets.pleroma_secrets.path; services.pleroma.secretConfigFile = config.sops.secrets.pleroma_secrets.path;
@@ -63,7 +56,6 @@ in
database: "pleroma", database: "pleroma",
hostname: "localhost", hostname: "localhost",
pool_size: 10, pool_size: 10,
prepare: :named,
parameters: [ parameters: [
plan_cache_mode: "force_custom_plan" plan_cache_mode: "force_custom_plan"
] ]
@@ -104,22 +96,10 @@ in
backends: [{ExSyslogger, :ex_syslogger}] backends: [{ExSyslogger, :ex_syslogger}]
config :logger, :ex_syslogger, config :logger, :ex_syslogger,
level: :${logLevel} level: :warn
# level: :debug
# policies => list of message rewriting facilities to be enabled
# transparence => whether to publish these rules in node_info (and /about)
config :pleroma, :mrf,
policies: [Pleroma.Web.ActivityPub.MRF.SimplePolicy],
transparency: true
# reject => { host, reason }
config :pleroma, :mrf_simple,
reject: [ {"threads.net", "megacorp"}, {"*.threads.net", "megacorp"} ]
# reject: [ [host: "threads.net", reason: "megacorp"], [host: "*.threads.net", reason: "megacorp"] ]
# XXX colin: not sure if this actually _does_ anything # XXX colin: not sure if this actually _does_ anything
# better to steal emoji from other instances?
# - <https://docs.pleroma.social/backend/configuration/cheatsheet/#mrf_steal_emoji>
config :pleroma, :emoji, config :pleroma, :emoji,
shortcode_globs: ["/emoji/**/*.png"], shortcode_globs: ["/emoji/**/*.png"],
groups: [ groups: [
@@ -168,7 +148,6 @@ in
# inherit kTLS; # inherit kTLS;
locations."/" = { locations."/" = {
proxyPass = "http://127.0.0.1:4000"; proxyPass = "http://127.0.0.1:4000";
recommendedProxySettings = true;
# documented: https://git.pleroma.social/pleroma/pleroma/-/blob/develop/installation/pleroma.nginx # documented: https://git.pleroma.social/pleroma/pleroma/-/blob/develop/installation/pleroma.nginx
extraConfig = '' extraConfig = ''
# XXX colin: this block is in the nixos examples: i don't understand all of it # XXX colin: this block is in the nixos examples: i don't understand all of it
@@ -187,18 +166,17 @@ in
add_header Referrer-Policy same-origin; add_header Referrer-Policy same-origin;
add_header X-Download-Options noopen; add_header X-Download-Options noopen;
# proxy_http_version 1.1; proxy_http_version 1.1;
# proxy_set_header Upgrade $http_upgrade; proxy_set_header Upgrade $http_upgrade;
# proxy_set_header Connection "upgrade"; proxy_set_header Connection "upgrade";
# # proxy_set_header Host $http_host; # proxy_set_header Host $http_host;
# proxy_set_header Host $host; proxy_set_header Host $host;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# colin: added this due to Pleroma complaining in its logs # colin: added this due to Pleroma complaining in its logs
# proxy_set_header X-Real-IP $remote_addr; # proxy_set_header X-Real-IP $remote_addr;
# proxy_set_header X-Forwarded-Proto $scheme; # proxy_set_header X-Forwarded-Proto $scheme;
# NB: this defines the maximum upload size
client_max_body_size 16m; client_max_body_size 16m;
''; '';
}; };

View File

@@ -1,39 +1,12 @@
{ pkgs, ... }: { ... }:
let
GiB = n: MiB 1024*n;
MiB = n: KiB 1024*n;
KiB = n: 1024*n;
in
{ {
sane.persist.sys.plaintext = [ sane.persist.sys.plaintext = [
# TODO: mode? # TODO: mode?
{ user = "postgres"; group = "postgres"; path = "/var/lib/postgresql"; } { user = "postgres"; group = "postgres"; directory = "/var/lib/postgresql"; }
]; ];
services.postgresql.enable = true; services.postgresql.enable = true;
# services.postgresql.dataDir = "/opt/postgresql/13";
# HOW TO UPDATE:
# postgres version updates are manual and require intervention.
# - `sane-stop-all-servo`
# - `systemctl start postgresql`
# - as `sudo su postgres`:
# - `cd /var/log/postgresql`
# - `pg_dumpall > state.sql`
# - `echo placeholder > <new_version>` # to prevent state from being created earlier than we want
# - then, atomically:
# - update the `services.postgresql.package` here
# - `dataDir` is atomically updated to match package; don't touch
# - `nixos-rebuild --flake . switch ; sane-stop-all-servo`
# - `sudo rm -rf /var/lib/postgresql/<new_version>`
# - `systemctl start postgresql`
# - as `sudo su postgres`:
# - `cd /var/lib/postgreql`
# - `psql -f state.sql`
# - restart dependent services (maybe test one at a time)
services.postgresql.package = pkgs.postgresql_15;
# XXX colin: for a proper deploy, we'd want to include something for Pleroma here too. # XXX colin: for a proper deploy, we'd want to include something for Pleroma here too.
# services.postgresql.initialScript = pkgs.writeText "synapse-init.sql" '' # services.postgresql.initialScript = pkgs.writeText "synapse-init.sql" ''
# CREATE ROLE "matrix-synapse" WITH LOGIN PASSWORD '<password goes here>'; # CREATE ROLE "matrix-synapse" WITH LOGIN PASSWORD '<password goes here>';
@@ -44,33 +17,10 @@ in
# LC_CTYPE = "C"; # LC_CTYPE = "C";
# ''; # '';
# perf tuning # TODO: perf tuning
# - for recommended values see: <https://pgtune.leopard.in.ua/> # - for recommended values see: <https://pgtune.leopard.in.ua/>
# - for official docs (sparse), see: <https://www.postgresql.org/docs/11/config-setting.html#CONFIG-SETTING-CONFIGURATION-FILE> # - for official docs (sparse), see: <https://www.postgresql.org/docs/11/config-setting.html#CONFIG-SETTING-CONFIGURATION-FILE>
services.postgresql.settings = { # services.postgresql.settings = { ... }
# DB Version: 15
# OS Type: linux
# DB Type: web
# Total Memory (RAM): 32 GB
# CPUs num: 12
# Data Storage: ssd
max_connections = 200;
shared_buffers = "8GB";
effective_cache_size = "24GB";
maintenance_work_mem = "2GB";
checkpoint_completion_target = 0.9;
wal_buffers = "16MB";
default_statistics_target = 100;
random_page_cost = 1.1;
effective_io_concurrency = 200;
work_mem = "10485kB";
min_wal_size = "1GB";
max_wal_size = "4GB";
max_worker_processes = 12;
max_parallel_workers_per_gather = 4;
max_parallel_workers = 12;
max_parallel_maintenance_workers = 4;
};
# daily backups to /var/backup # daily backups to /var/backup
services.postgresqlBackup.enable = true; services.postgresqlBackup.enable = true;

View File

@@ -10,7 +10,7 @@
lib.mkIf false lib.mkIf false
{ {
sane.persist.sys.plaintext = [ sane.persist.sys.plaintext = [
{ user = "prosody"; group = "prosody"; path = "/var/lib/prosody"; } { user = "prosody"; group = "prosody"; directory = "/var/lib/prosody"; }
]; ];
sane.ports.ports."5222" = { sane.ports.ports."5222" = {
protocol = [ "tcp" ]; protocol = [ "tcp" ];

View File

@@ -3,7 +3,7 @@
{ {
sane.persist.sys.plaintext = [ sane.persist.sys.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/
{ user = "transmission"; group = "transmission"; path = "/var/lib/transmission"; } { user = "transmission"; group = "transmission"; directory = "/var/lib/transmission"; }
]; ];
services.transmission.enable = true; services.transmission.enable = true;
services.transmission.settings = { services.transmission.settings = {

View File

@@ -1,25 +1,15 @@
{ config, lib, pkgs, ... }: { config, lib, pkgs, ... }:
{ {
services.trust-dns.enable = true; sane.services.trust-dns.enable = true;
services.trust-dns.settings.listen_addrs_ipv4 = [ sane.services.trust-dns.listenAddrsIPv4 = [
# specify each address explicitly, instead of using "*". # specify each address explicitly, instead of using "*".
# this ensures responses are sent from the address at which the request was received. # this ensures responses are sent from the address at which the request was received.
config.sane.hosts.by-name."servo".lan-ip config.sane.hosts.by-name."servo".lan-ip
"10.0.1.5" "10.0.1.5"
]; ];
# don't bind to IPv6 until i explicitly test that stack sane.services.trust-dns.quiet = true;
services.trust-dns.settings.listen_addrs_ipv6 = [];
services.trust-dns.quiet = true;
# services.trust-dns.debug = true;
sane.ports.ports."53" = {
protocol = [ "udp" "tcp" ];
visibleTo.lan = true;
visibleTo.wan = true;
description = "colin-dns-hosting";
};
sane.dns.zones."uninsane.org".TTL = 900; sane.dns.zones."uninsane.org".TTL = 900;
@@ -61,15 +51,18 @@
]; ];
}; };
services.trust-dns.settings.zones = [ "uninsane.org" ]; # we need trust-dns to load our zone by relative path instead of /nix/store path
# because we generate it at runtime.
sane.services.trust-dns.zones."uninsane.org".file = lib.mkForce "uninsane.org.zone";
sane.services.trust-dns.zonedir = null;
services.trust-dns.package = sane.services.trust-dns.package =
let let
sed = "${pkgs.gnused}/bin/sed"; sed = "${pkgs.gnused}/bin/sed";
zone-dir = "/var/lib/trust-dns"; zone-dir = "/var/lib/trust-dns";
zone-wan = "${zone-dir}/wan/uninsane.org.zone"; zone-wan = "${zone-dir}/wan/uninsane.org.zone";
zone-lan = "${zone-dir}/lan/uninsane.org.zone"; zone-lan = "${zone-dir}/lan/uninsane.org.zone";
zone-template = pkgs.writeText "uninsane.org.zone.in" config.sane.dns.zones."uninsane.org".rendered; zone-template = pkgs.writeText "uninsane.org.zone.in" config.sane.services.trust-dns.zones."uninsane.org".text;
in pkgs.writeShellScriptBin "named" '' in pkgs.writeShellScriptBin "named" ''
# compute wan/lan values # compute wan/lan values
mkdir -p ${zone-dir}/{ovpn,wan,lan} mkdir -p ${zone-dir}/{ovpn,wan,lan}
@@ -100,17 +93,6 @@
exit 1 exit 1
''; '';
systemd.services.trust-dns.serviceConfig = {
DynamicUser = lib.mkForce false;
User = "trust-dns";
Group = "trust-dns";
};
users.groups.trust-dns = {};
users.users.trust-dns = {
group = "trust-dns";
isSystemUser = true;
};
sane.services.dyn-dns.restartOnChange = [ "trust-dns.service" ]; sane.services.dyn-dns.restartOnChange = [ "trust-dns.service" ];
networking.nat.enable = true; networking.nat.enable = true;

View File

@@ -13,7 +13,7 @@
./programs ./programs
./secrets.nix ./secrets.nix
./ssh.nix ./ssh.nix
./users ./users.nix
./vpn.nix ./vpn.nix
]; ];
@@ -23,6 +23,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;
# some services which use private directories error if the parent (/var/lib/private) isn't 700.
sane.fs."/var/lib/private".dir.acl.mode = "0700";
nixpkgs.config.allowUnfree = true; nixpkgs.config.allowUnfree = true;
nixpkgs.config.allowBroken = true; # NIXPKGS_ALLOW_BROKEN nixpkgs.config.allowBroken = true; # NIXPKGS_ALLOW_BROKEN
@@ -40,39 +43,48 @@
# does the builder use some content-addressed db to efficiently dedupe? # does the builder use some content-addressed db to efficiently dedupe?
nix.settings.auto-optimise-store = true; nix.settings.auto-optimise-store = true;
systemd.services.nix-daemon.serviceConfig = { fonts = {
# the nix-daemon manages nix builders enableDefaultFonts = true;
# kill nix-daemon subprocesses when systemd-oomd detects an out-of-memory condition fonts = with pkgs; [ font-awesome noto-fonts-emoji hack-font ];
# see: fontconfig.enable = true;
# - nixos PR that enabled systemd-oomd: <https://github.com/NixOS/nixpkgs/pull/169613> fontconfig.defaultFonts = {
# - systemd's docs on these properties: <https://www.freedesktop.org/software/systemd/man/systemd.resource-control.html#ManagedOOMSwap=auto%7Ckill> emoji = [ "Font Awesome 6 Free" "Noto Color Emoji" ];
# monospace = [ "Hack" ];
# systemd's docs warn that without swap, systemd-oomd might not be able to react quick enough to save the system. serif = [ "DejaVu Serif" ];
# see `man oomd.conf` for further tunables that may help. sansSerif = [ "DejaVu Sans" ];
# };
# alternatively, apply this more broadly with `systemd.oomd.enableSystemSlice = true` or `enableRootSlice`
# TODO: also apply this to the guest user's slice (user-1100.slice)
# TODO: also apply this to distccd
ManagedOOMMemoryPressure = "kill";
ManagedOOMSwap = "kill";
}; };
# XXX: twitter-color-emoji doesn't cross-compile; but not-fonts-emoji does
system.activationScripts.nixClosureDiff = { # fonts = {
supportsDryActivation = true; # enableDefaultFonts = true;
text = '' # fonts = with pkgs; [ font-awesome twitter-color-emoji hack-font ];
# show which packages changed versions or are new/removed in this upgrade # fontconfig.enable = true;
# source: <https://github.com/luishfonseca/dotfiles/blob/32c10e775d9ec7cc55e44592a060c1c9aadf113e/modules/upgrade-diff.nix> # fontconfig.defaultFonts = {
${pkgs.nvd}/bin/nvd --nix-bin-dir=${pkgs.nix}/bin diff /run/current-system "$systemConfig" # emoji = [ "Font Awesome 6 Free" "Twitter Color Emoji" ];
''; # monospace = [ "Hack" ];
}; # serif = [ "DejaVu Serif" ];
# sansSerif = [ "DejaVu Sans" ];
# };
# };
# disable non-required packages like nano, perl, rsync, strace # disable non-required packages like nano, perl, rsync, strace
environment.defaultPackages = []; environment.defaultPackages = [];
# programs.vim.defaultEditor = true;
environment.variables = {
EDITOR = "vim";
# git claims it should use EDITOR, but it doesn't!
GIT_EDITOR = "vim";
# TODO: these should be moved to `home.sessionVariables` (home-manager)
# Electron apps should use native wayland backend:
# https://nixos.wiki/wiki/Slack#Wayland
# Discord under sway crashes with this.
# NIXOS_OZONE_WL = "1";
# LIBGL_ALWAYS_SOFTWARE = "1";
};
# dconf docs: <https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/desktop_migration_and_administration_guide/profiles> # dconf docs: <https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/desktop_migration_and_administration_guide/profiles>
# this lets programs temporarily write user-level dconf settings (aka gsettings).
# they're written to ~/.config/dconf/user, unless `DCONF_PROFILE` is set to something other than the default of /etc/dconf/profile/user
# find keys/values with `dconf dump /` # find keys/values with `dconf dump /`
programs.dconf.enable = true; programs.dconf.enable = true;
programs.dconf.packages = [ programs.dconf.packages = [
@@ -85,7 +97,6 @@
''; '';
}) })
]; ];
# sane.programs.glib.enableFor.user.colin = true; # for `gsettings`
# link debug symbols into /run/current-system/sw/lib/debug # link debug symbols into /run/current-system/sw/lib/debug
# hopefully picked up by gdb automatically? # hopefully picked up by gdb automatically?

View File

@@ -1,7 +1,3 @@
# where to find good stuff?
# - podcasts w/ a community: <https://lemmyverse.net/communities?query=podcast>
# - podcast rec thread: <https://lemmy.ml/post/1565858>
#
# candidates: # candidates:
# - The Nonlinear Library (podcast): <https://forum.effectivealtruism.org/posts/JTZTBienqWEAjGDRv/listen-to-more-ea-content-with-the-nonlinear-library> # - 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 # - has ~10 posts per day, text-to-speech; i would need better tagging before adding this
@@ -68,12 +64,7 @@ let
(fromDb "craphound.com" // pol) (fromDb "craphound.com" // pol)
## Maggie Killjoy -- referenced by Cory Doctorow ## Maggie Killjoy -- referenced by Cory Doctorow
(fromDb "omny.fm/shows/cool-people-who-did-cool-stuff" // pol) (fromDb "omny.fm/shows/cool-people-who-did-cool-stuff" // pol)
## also Maggie Killjoy
(fromDb "feeds.megaphone.fm/behindthebastards" // pol)
## Jennifer Briney
(fromDb "congressionaldish.libsyn.com" // pol) (fromDb "congressionaldish.libsyn.com" // pol)
(fromDb "werenotwrong.fireside.fm" // pol)
(fromDb "usefulidiots.substack.com" // pol)
# (mkPod "https://podcasts.la.utexas.edu/this-is-democracy/feed/podcast/" // pol // weekly) # (mkPod "https://podcasts.la.utexas.edu/this-is-democracy/feed/podcast/" // pol // weekly)
## Civboot -- https://anchor.fm/civboot ## Civboot -- https://anchor.fm/civboot
(fromDb "anchor.fm/s/34c7232c/podcast/rss" // tech) (fromDb "anchor.fm/s/34c7232c/podcast/rss" // tech)
@@ -113,8 +104,6 @@ let
(fromDb "feeds.megaphone.fm/recodedecode" // tech) (fromDb "feeds.megaphone.fm/recodedecode" // tech)
## Matrix (chat) Live ## Matrix (chat) Live
(fromDb "feed.podbean.com/matrixlive/feed.xml" // tech) (fromDb "feed.podbean.com/matrixlive/feed.xml" // tech)
(fromDb "cast.postmarketos.org" // tech)
(fromDb "podcast.thelinuxexp.com" // tech)
## Michael Malice - Your Welcome -- also available here: <https://origin.podcastone.com/podcast?categoryID2=2232> ## Michael Malice - Your Welcome -- also available here: <https://origin.podcastone.com/podcast?categoryID2=2232>
(fromDb "rss.art19.com/your-welcome" // pol) (fromDb "rss.art19.com/your-welcome" // pol)
(fromDb "seattlenice.buzzsprout.com" // pol) (fromDb "seattlenice.buzzsprout.com" // pol)
@@ -125,22 +114,12 @@ let
## The Witch Trials of J.K. Rowling ## The Witch Trials of J.K. Rowling
## - <https://www.thefp.com/witchtrials> ## - <https://www.thefp.com/witchtrials>
(mkPod "https://feeds.megaphone.fm/RUNMED9919162779" // pol // infrequent) (mkPod "https://feeds.megaphone.fm/RUNMED9919162779" // pol // infrequent)
## Atlas Obscura
(fromDb "feeds.simplecast.com/xKJ93w_w" // uncat)
## Ezra Klein Show
(fromDb "feeds.simplecast.com/82FI35Px" // pol)
## Wireshark Podcast o_0
(fromDb "sharkbytes.transistor.fm" // tech)
## 3/4 German; 1/4 eps are English
(fromDb "omegataupodcast.net" // tech)
## Lateral with Tom Scott
(mkPod "https://audioboom.com/channels/5097784.rss" // tech)
]; ];
texts = [ texts = [
# AGGREGATORS (> 1 post/day) # AGGREGATORS (> 1 post/day)
(fromDb "lwn.net" // tech) (fromDb "lwn.net" // tech)
# (fromDb "lesswrong.com" // rat) (fromDb "lesswrong.com" // rat)
# (fromDb "econlib.org" // pol) # (fromDb "econlib.org" // pol)
# AGGREGATORS (< 1 post/day) # AGGREGATORS (< 1 post/day)
@@ -182,11 +161,10 @@ let
(fromDb "ianthehenry.com" // tech) (fromDb "ianthehenry.com" // tech)
(fromDb "bitbashing.io" // tech) (fromDb "bitbashing.io" // tech)
(fromDb "idiomdrottning.org" // uncat) (fromDb "idiomdrottning.org" // uncat)
(mkText "http://boginjr.com/feed" // tech // infrequent)
(mkText "https://anish.lakhwara.com/home.html" // tech // weekly) (mkText "https://anish.lakhwara.com/home.html" // tech // weekly)
(fromDb "jefftk.com" // tech) (fromDb "jefftk.com" // tech)
(fromDb "pomeroyb.com" // tech) (fromDb "pomeroyb.com" // tech)
# (mkText "https://til.simonwillison.net/tils/feed.atom" // tech // weekly) (mkText "https://til.simonwillison.net/tils/feed.atom" // tech // weekly)
# TECH PROJECTS # TECH PROJECTS
(fromDb "blog.rust-lang.org" // tech) (fromDb "blog.rust-lang.org" // tech)
@@ -236,7 +214,6 @@ let
(fromDb "preposterousuniverse.com" // rat) (fromDb "preposterousuniverse.com" // rat)
(mkSubstack "eliqian" // rat // weekly) (mkSubstack "eliqian" // rat // weekly)
(mkText "https://acoup.blog/feed" // rat // weekly) (mkText "https://acoup.blog/feed" // rat // weekly)
(fromDb "mindingourway.com" // rat)
## mostly dating topics. not advice, or humor, but looking through a social lens ## mostly dating topics. not advice, or humor, but looking through a social lens
(fromDb "putanumonit.com" // rat) (fromDb "putanumonit.com" // rat)

View File

@@ -1,14 +1,12 @@
# docs # docs
# - x-systemd options: <https://www.freedesktop.org/software/systemd/man/systemd.mount.html> # - x-systemd options: <https://www.freedesktop.org/software/systemd/man/systemd.mount.html>
{ lib, pkgs, sane-lib, ... }: { pkgs, sane-lib, ... }:
let let fsOpts = rec {
fsOpts = rec {
common = [ common = [
"_netdev" "_netdev"
"noatime" "noatime"
"user" # allow any user with access to the device to mount the fs
"x-systemd.requires=network-online.target" "x-systemd.requires=network-online.target"
"x-systemd.after=network-online.target" "x-systemd.after=network-online.target"
"x-systemd.mount-timeout=10s" # how long to wait for mount **and** how long to wait for unmount "x-systemd.mount-timeout=10s" # how long to wait for mount **and** how long to wait for unmount
@@ -21,6 +19,7 @@ let
]; ];
ssh = common ++ [ ssh = common ++ [
"user"
"identityfile=/home/colin/.ssh/id_ed25519" "identityfile=/home/colin/.ssh/id_ed25519"
"allow_other" "allow_other"
"default_permissions" "default_permissions"
@@ -56,49 +55,8 @@ let
"nofail" # don't fail remote-fs.target when this mount fails (not an option for sshfs else would be common) "nofail" # don't fail remote-fs.target when this mount fails (not an option for sshfs else would be common)
]; ];
}; };
remoteHome = host: {
fileSystems."/mnt/${host}-home" = {
device = "colin@${host}:/home/colin";
fsType = "fuse.sshfs";
options = fsOpts.sshColin ++ fsOpts.noauto;
noCheck = true;
};
sane.fs."/mnt/${host}-home" = sane-lib.fs.wantedDir;
};
in in
lib.mkMerge [
{ {
# some services which use private directories error if the parent (/var/lib/private) isn't 700.
sane.fs."/var/lib/private".dir.acl.mode = "0700";
# in-memory compressed RAM
# defaults to compressing at most 50% size of RAM
# claimed compression ratio is about 2:1
# - but on moby w/ zstd default i see 4-7:1 (ratio lowers as it fills)
# note that idle overhead is about 0.05% of capacity (e.g. 2B per 4kB page)
# docs: <https://www.kernel.org/doc/Documentation/blockdev/zram.txt>
#
# to query effectiveness:
# `cat /sys/block/zram0/mm_stat`. whitespace separated fields:
# - *orig_data_size* (bytes)
# - *compr_data_size* (bytes)
# - mem_used_total (bytes)
# - mem_limit (bytes)
# - mem_used_max (bytes)
# - *same_pages* (pages which are e.g. all zeros (consumes no additional mem))
# - *pages_compacted* (pages which have been freed thanks to compression)
# - huge_pages (incompressible)
#
# see also:
# - `man zramctl`
zramSwap.enable = true;
# how much ram can be swapped into the zram device.
# this shouldn't be higher than the observed compression ratio.
# the default is 50% (why?)
# 100% should be "guaranteed" safe so long as the data is even *slightly* compressible.
# but it decreases working memory under the heaviest of loads by however much space the compressed memory occupies (e.g. 50% if 2:1; 25% if 4:1)
zramSwap.memoryPercent = 100;
# fileSystems."/mnt/servo-nfs" = { # fileSystems."/mnt/servo-nfs" = {
# device = "servo-hn:/"; # device = "servo-hn:/";
# noCheck = true; # noCheck = true;
@@ -119,6 +77,49 @@ lib.mkMerge [
# }; # };
sane.fs."/mnt/servo-media" = sane-lib.fs.wantedSymlinkTo "/mnt/servo-nfs/media"; sane.fs."/mnt/servo-media" = sane-lib.fs.wantedSymlinkTo "/mnt/servo-nfs/media";
fileSystems."/mnt/servo-media-wan" = {
device = "colin@uninsane.org:/var/lib/uninsane/media";
fsType = "fuse.sshfs";
options = fsOpts.sshColin ++ fsOpts.noauto;
noCheck = true;
};
sane.fs."/mnt/servo-media-wan" = sane-lib.fs.wantedDir;
fileSystems."/mnt/servo-media-lan" = {
device = "colin@servo:/var/lib/uninsane/media";
fsType = "fuse.sshfs";
options = fsOpts.sshColin ++ fsOpts.noauto;
noCheck = true;
};
sane.fs."/mnt/servo-media-lan" = sane-lib.fs.wantedDir;
fileSystems."/mnt/servo-root-wan" = {
device = "colin@uninsane.org:/";
fsType = "fuse.sshfs";
options = fsOpts.sshRoot ++ fsOpts.noauto;
noCheck = true;
};
sane.fs."/mnt/servo-root-wan" = sane-lib.fs.wantedDir;
fileSystems."/mnt/servo-root-lan" = {
device = "colin@servo:/";
fsType = "fuse.sshfs";
options = fsOpts.sshRoot ++ fsOpts.noauto;
noCheck = true;
};
sane.fs."/mnt/servo-root-lan" = sane-lib.fs.wantedDir;
fileSystems."/mnt/desko-home" = {
device = "colin@desko:/home/colin";
fsType = "fuse.sshfs";
options = fsOpts.sshColin ++ fsOpts.noauto;
noCheck = true;
};
sane.fs."/mnt/desko-home" = sane-lib.fs.wantedDir;
fileSystems."/mnt/desko-root" = {
device = "colin@desko:/";
fsType = "fuse.sshfs";
options = fsOpts.sshRoot ++ fsOpts.noauto;
noCheck = true;
};
sane.fs."/mnt/desko-root" = sane-lib.fs.wantedDir;
environment.pathsToLink = [ environment.pathsToLink = [
# needed to achieve superuser access for user-mounted filesystems (see optionsRoot above) # needed to achieve superuser access for user-mounted filesystems (see optionsRoot above)
# we can only link whole directories here, even though we're only interested in pkgs.openssh # we can only link whole directories here, even though we're only interested in pkgs.openssh
@@ -130,8 +131,3 @@ lib.mkMerge [
]; ];
} }
(remoteHome "desko")
(remoteHome "lappy")
(remoteHome "moby")
]

View File

@@ -23,6 +23,7 @@
# non-free firmware # non-free firmware
hardware.enableRedistributableFirmware = true; hardware.enableRedistributableFirmware = true;
services.fwupd.enable = true;
# powertop will default to putting USB devices -- including HID -- to sleep after TWO SECONDS # powertop will default to putting USB devices -- including HID -- to sleep after TWO SECONDS
powerManagement.powertop.enable = false; powerManagement.powertop.enable = false;

View File

@@ -1,7 +1,7 @@
{ ... }: { ... }:
{ {
imports = [ imports = [
./keyring ./keyring.nix
./mime.nix ./mime.nix
./ssh.nix ./ssh.nix
./xdg-dirs.nix ./xdg-dirs.nix

View File

@@ -0,0 +1,11 @@
{ config, sane-lib, ... }:
{
sane.user.persist.private = [ ".local/share/keyrings" ];
sane.user.fs."private/.local/share/keyrings/default" = {
generated.script.script = builtins.readFile ../../../scripts/init-keyring;
# TODO: is this `wantedBy` needed? can we inherit it?
wantedBy = [ config.sane.fs."/home/colin/private".unit ];
};
}

View File

@@ -1,17 +0,0 @@
{ config, pkgs, sane-lib, ... }:
let
init-keyring = pkgs.static-nix-shell.mkBash {
pname = "init-keyring";
src = ./.;
};
in
{
sane.user.persist.private = [ ".local/share/keyrings" ];
sane.user.fs."private/.local/share/keyrings/default" = {
generated.command = [ "${init-keyring}/bin/init-keyring" ];
wantedBy = [ config.sane.fs."/home/colin/private".unit ];
wantedBeforeBy = [ ]; # don't created this as part of `multi-user.target`
};
}

View File

@@ -1,28 +1,43 @@
{ config, lib, ...}: { config, sane-lib, ...}:
let let
# ProgramConfig -> { "<mime-type>" = { priority, desktop }; } www = config.sane.programs.web-browser.config.browser.desktop;
weightedMimes = prog: builtins.mapAttrs (_key: desktop: { priority = prog.mime.priority; desktop = desktop; }) prog.mime.associations; pdf = "org.gnome.Evince.desktop";
# [ { "<mime-type>" = { priority, desktop } ]; } ] -> { "<mime-type>" = [ { priority, desktop } ... ]; } md = "obsidian.desktop";
mergeMimes = mimes: lib.foldAttrs (item: acc: [item] ++ acc) [] mimes; thumb = "org.gnome.gThumb.desktop";
# [ { priority, desktop } ... ] -> Self video = "vlc.desktop";
sortOneMimeType = associations: builtins.sort (l: r: assert l.priority != r.priority; l.priority < r.priority) associations; # audio = "mpv.desktop";
sortMimes = mimes: builtins.mapAttrs (_k: sortOneMimeType) mimes; audio = "vlc.desktop";
removePriorities = mimes: builtins.mapAttrs (_k: associations: builtins.map (a: a.desktop) associations) mimes;
# [ ProgramConfig ]
enabledPrograms = builtins.filter (p: p.enabled) (builtins.attrValues config.sane.programs);
# [ { "<mime-type>" = { prority, desktop } ]
enabledWeightedMimes = builtins.map weightedMimes enabledPrograms;
in in
{ {
# the xdg mime type for a file can be found with: # the xdg mime type for a file can be found with:
# - `xdg-mime query filetype path/to/thing.ext` # - `xdg-mime query filetype path/to/thing.ext`
# the default handler for a mime type can be found with:
# - `xdg-mime query default <mimetype>` (e.g. x-scheme-handler/http)
#
# we can have single associations or a list of associations. # we can have single associations or a list of associations.
# there's also options to *remove* [non-default] associations from specific apps # there's also options to *remove* [non-default] associations from specific apps
xdg.mime.enable = true; xdg.mime.enable = true;
xdg.mime.defaultApplications = removePriorities (sortMimes (mergeMimes enabledWeightedMimes)); xdg.mime.defaultApplications = {
# AUDIO
"audio/flac" = audio;
"audio/mpeg" = audio;
"audio/x-vorbis+ogg" = audio;
# IMAGES
"image/heif" = thumb; # apple codec
"image/png" = thumb;
"image/jpeg" = thumb;
# VIDEO
"video/mp4" = video;
"video/quicktime" = video;
"video/webm" = video;
"video/x-matroska" = video;
# HTML
"text/html" = www;
"x-scheme-handler/http" = www;
"x-scheme-handler/https" = www;
"x-scheme-handler/about" = www;
"x-scheme-handler/unknown" = www;
# RICH-TEXT DOCUMENTS
"application/pdf" = pdf;
"text/markdown" = md;
};
} }

View File

@@ -1,29 +1,26 @@
# TODO: this should be moved to users/colin.nix { config, lib, sane-lib, ... }:
{ config, lib, ... }:
with lib;
let let
host = config.networking.hostName; host = config.networking.hostName;
user-pubkey-full = config.sane.ssh.pubkeys."colin@${host}" or {}; user-pubkey-full = config.sane.ssh.pubkeys."colin@${host}" or {};
user-pubkey = user-pubkey-full.asUserKey or null; user-pubkey = user-pubkey-full.asUserKey or null;
host-keys = lib.filter (k: k.user == "root") (lib.attrValues config.sane.ssh.pubkeys); host-keys = filter (k: k.user == "root") (attrValues config.sane.ssh.pubkeys);
known-hosts-text = lib.concatStringsSep known-hosts-text = concatStringsSep
"\n" "\n"
(builtins.map (k: k.asHostKey) host-keys) (map (k: k.asHostKey) host-keys)
; ;
in in
{ {
# ssh key is stored in private storage # ssh key is stored in private storage
sane.user.persist.private = [ sane.user.persist.private = [ ".ssh/id_ed25519" ];
{ type = "file"; path = ".ssh/id_ed25519"; } sane.user.fs.".ssh/id_ed25519.pub" =
]; mkIf (user-pubkey != null) (sane-lib.fs.wantedText user-pubkey);
sane.user.fs.".ssh/id_ed25519.pub" = lib.mkIf (user-pubkey != null) { sane.user.fs.".ssh/known_hosts" = sane-lib.fs.wantedText known-hosts-text;
symlink.text = user-pubkey;
};
sane.user.fs.".ssh/known_hosts".symlink.text = known-hosts-text;
users.users.colin.openssh.authorizedKeys.keys = users.users.colin.openssh.authorizedKeys.keys =
let let
user-keys = lib.filter (k: k.user == "colin") (lib.attrValues config.sane.ssh.pubkeys); user-keys = filter (k: k.user == "colin") (attrValues config.sane.ssh.pubkeys);
in in
builtins.map (k: k.asUserKey) user-keys; map (k: k.asUserKey) user-keys;
} }

View File

@@ -1,9 +1,9 @@
{ ... }: { lib, sane-lib, ...}:
{ {
# XDG defines things like ~/Desktop, ~/Downloads, etc. # XDG defines things like ~/Desktop, ~/Downloads, etc.
# these clutter the home, so i mostly don't use them. # these clutter the home, so i mostly don't use them.
sane.user.fs.".config/user-dirs.dirs".symlink.text = '' sane.user.fs.".config/user-dirs.dirs" = sane-lib.fs.wantedText ''
XDG_DESKTOP_DIR="$HOME/.xdg/Desktop" XDG_DESKTOP_DIR="$HOME/.xdg/Desktop"
XDG_DOCUMENTS_DIR="$HOME/dev" XDG_DOCUMENTS_DIR="$HOME/dev"
XDG_DOWNLOAD_DIR="$HOME/tmp" XDG_DOWNLOAD_DIR="$HOME/tmp"
@@ -16,5 +16,5 @@
# prevent `xdg-user-dirs-update` from overriding/updating our config # prevent `xdg-user-dirs-update` from overriding/updating our config
# see <https://manpages.ubuntu.com/manpages/bionic/man5/user-dirs.conf.5.html> # see <https://manpages.ubuntu.com/manpages/bionic/man5/user-dirs.conf.5.html>
sane.user.fs.".config/user-dirs.conf".symlink.text = "enabled=False"; sane.user.fs.".config/user-dirs.conf" = sane-lib.fs.wantedText "enabled=False";
} }

View File

@@ -42,8 +42,6 @@
sane.ids.pict-rs.gid = 2409; sane.ids.pict-rs.gid = 2409;
sane.ids.sftpgo.uid = 2410; sane.ids.sftpgo.uid = 2410;
sane.ids.sftpgo.gid = 2410; sane.ids.sftpgo.gid = 2410;
sane.ids.trust-dns.uid = 2411;
sane.ids.trust-dns.gid = 2411;
sane.ids.colin.uid = 1000; sane.ids.colin.uid = 1000;
sane.ids.guest.uid = 1100; sane.ids.guest.uid = 1100;

View File

@@ -11,37 +11,17 @@
# - `man iwd.config` for global config # - `man iwd.config` for global config
# - `man iwd.network` for per-SSID config # - `man iwd.network` for per-SSID config
# use `iwctl` to control # use `iwctl` to control
# networking.networkmanager.wifi.backend = "iwd"; networking.networkmanager.wifi.backend = "iwd";
# networking.wireless.iwd.enable = true; networking.wireless.iwd.enable = true;
# networking.wireless.iwd.settings = { networking.wireless.iwd.settings = {
# # auto-connect to a stronger network if signal drops below this value # auto-connect to a stronger network if signal drops below this value
# # bedroom -> bedroom connection is -35 to -40 dBm # bedroom -> bedroom connection is -35 to -40 dBm
# # bedroom -> living room connection is -60 dBm # bedroom -> living room connection is -60 dBm
# General.RoamThreshold = "-52"; # default -70 General.RoamThreshold = "-52"; # default -70
# General.RoamThreshold5G = "-52"; # default -76 General.RoamThreshold5G = "-52"; # default -76
# }; };
# plugins mostly add support for establishing different VPN connections.
# the default plugin set includes mostly proprietary VPNs:
# - fortisslvpn (Fortinet)
# - iodine (DNS tunnels)
# - l2tp
# - openconnect (Cisco Anyconnect / Juniper / ocserv)
# - openvpn
# - vpnc (Cisco VPN)
# - sstp
#
# i don't use these, and notably they drag in huge dependency sets and don't cross compile well.
# e.g. openconnect drags in webkitgtk (for SSO)!
networking.networkmanager.plugins = lib.mkForce [];
networking.firewall.allowedUDPPorts = [ networking.firewall.allowedUDPPorts = [
1900 # to received UPnP advertisements. required by sane-ip-check-upnp 1900 # to received UPnP advertisements. required by sane-ip-check-upnp
]; ];
# keyfile.path = where networkmanager should look for connection credentials
networking.networkmanager.extraConfig = ''
[keyfile]
path=/var/lib/NetworkManager/system-connections
'';
} }

View File

@@ -6,11 +6,13 @@
sane.persist.stores.private.prefix = "/home/colin"; sane.persist.stores.private.prefix = "/home/colin";
sane.persist.sys.plaintext = [ sane.persist.sys.plaintext = [
# TODO: these should be private.. somehow
"/var/log" "/var/log"
"/var/backup" # for e.g. postgres dumps "/var/backup" # for e.g. postgres dumps
]; # TODO: move elsewhere
sane.persist.sys.cryptClearOnBoot = [ "/var/lib/alsa" # preserve output levels, default devices
"/var/lib/colord" # preserve color calibrations (?)
"/var/lib/machines" # maybe not needed, but would be painful to add a VM and forget.
"/var/lib/systemd/backlight" # backlight brightness
"/var/lib/systemd/coredump" "/var/lib/systemd/coredump"
]; ];
} }

View File

@@ -2,8 +2,5 @@
{ ... }: { ... }:
{ {
sane.programs.aerc = { sane.programs.aerc.secrets.".config/aerc/accounts.conf" = ../../../secrets/common/aerc_accounts.conf.bin;
secrets.".config/aerc/accounts.conf" = ../../../secrets/common/aerc_accounts.conf.bin;
mime.associations."x-scheme-handler/mailto" = "aerc.desktop";
};
} }

View File

@@ -1,24 +0,0 @@
# alacritty terminal emulator
# - config options: <https://github.com/alacritty/alacritty/blob/master/extra/man/alacritty.5.scd>
# - `man 5 alacritty`
# - defaults: <https://github.com/alacritty/alacritty/releases> -> alacritty.yml
# - irc: #alacritty on libera.chat
{ lib, ... }:
{
sane.programs.alacritty = {
env.TERMINAL = lib.mkDefault "alacritty";
# note: alacritty will switch to .toml config in 13.0 release
# - run `alacritty migrate` to convert the yaml to toml
fs.".config/alacritty/alacritty.yml".symlink.text = ''
font:
size: 14
key_bindings:
- { key: N, mods: Control, action: CreateNewWindow }
- { key: PageUp, mods: Control, action: ScrollPageUp }
- { key: PageDown, mods: Control, action: ScrollPageDown }
- { key: PageUp, mods: Control|Shift, action: ScrollPageUp }
- { key: PageDown, mods: Control|Shift, action: ScrollPageDown }
'';
};
}

View File

@@ -1,216 +1,340 @@
{ pkgs, ... }: { lib, pkgs, ... }:
let let
declPackageSet = pkgs: { inherit (builtins) attrNames;
package = null;
suggestedPrograms = pkgs;
};
in
{
sane.programs = {
# PACKAGE SETS
"sane-scripts.backup" = declPackageSet [
"sane-scripts.backup-ls"
"sane-scripts.backup-restore"
];
"sane-scripts.bittorrent" = declPackageSet [
"sane-scripts.bt-add"
"sane-scripts.bt-rm"
"sane-scripts.bt-search"
"sane-scripts.bt-show"
];
"sane-scripts.dev" = declPackageSet [
"sane-scripts.dev-cargo-loop"
"sane-scripts.git-init"
];
"sane-scripts.cli" = declPackageSet [
"sane-scripts.deadlines"
"sane-scripts.find-dotfiles"
"sane-scripts.ip-check"
"sane-scripts.ip-reconnect"
"sane-scripts.private-change-passwd"
"sane-scripts.private-do"
"sane-scripts.private-init"
"sane-scripts.private-lock"
"sane-scripts.private-unlock"
"sane-scripts.rcp"
"sane-scripts.reboot"
"sane-scripts.reclaim-boot-space"
"sane-scripts.reclaim-disk-space"
"sane-scripts.secrets-dump"
"sane-scripts.secrets-unlock"
"sane-scripts.secrets-update-keys"
"sane-scripts.shutdown"
"sane-scripts.ssl-dump"
"sane-scripts.sudo-redirect"
"sane-scripts.sync-from-servo"
"sane-scripts.vpn-down"
"sane-scripts.vpn-up"
"sane-scripts.which"
"sane-scripts.wipe-browser"
];
"sane-scripts.sys-utils" = declPackageSet [
"sane-scripts.ip-port-forward"
"sane-scripts.sync-music"
];
flattenedPkgs = pkgs // (with pkgs; {
# XXX can't `inherit` a nested attr, so we move them to the toplevel
"cacert.unbundled" = pkgs.cacert.unbundled;
"gnome.cheese" = gnome.cheese;
"gnome.dconf-editor" = gnome.dconf-editor;
"gnome.file-roller" = gnome.file-roller;
"gnome.gnome-disk-utility" = gnome.gnome-disk-utility;
"gnome.gnome-maps" = gnome.gnome-maps;
"gnome.nautilus" = gnome.nautilus;
"gnome.gnome-system-monitor" = gnome.gnome-system-monitor;
"gnome.gnome-terminal" = gnome.gnome-terminal;
"gnome.gnome-weather" = gnome.gnome-weather;
"gnome.totem" = gnome.totem;
"libsForQt5.plasmatube" = libsForQt5.plasmatube;
});
sysadminUtils = declPackageSet [ sysadminPkgs = {
"btrfs-progs" inherit (flattenedPkgs)
btrfs-progs
"cacert.unbundled" # some services require unbundled /etc/ssl/certs "cacert.unbundled" # some services require unbundled /etc/ssl/certs
"cryptsetup" cryptsetup
"dig" dig
"efibootmgr" efibootmgr
"fatresize" fatresize
"fd" fd
"file" file
# "fwupd" gawk
"gawk" git
"git" gptfdisk
"gptfdisk" hdparm
"hdparm" htop
"htop" iftop
"iftop" inetutils # for telnet
"inetutils" # for telnet iotop
"iotop" iptables
"iptables" jq
"jq" killall
"killall" lsof
"lsof" miniupnpc
"miniupnpc" nano
"nano" netcat
# "ncdu" # ncurses disk usage. doesn't cross compile (zig) nethogs
"neovim" nmap
"netcat" openssl
"nethogs" parted
"nmap" pciutils
"openssl" powertop
"parted" pstree
"pciutils" ripgrep
"powertop" screen
"pstree" smartmontools
"ripgrep" socat
"screen" strace
"smartmontools" subversion
"socat" tcpdump
"strace" tree
"subversion" usbutils
"tcpdump" wget
"tree" wirelesstools # iwlist
"usbutils" ;
"wget" };
"wirelesstools" # iwlist sysadminExtraPkgs = {
]; # application-specific packages
sysadminExtraUtils = declPackageSet [ inherit (pkgs)
"backblaze-b2" backblaze-b2
"duplicity" duplicity
"sane-scripts.backup" sqlite # to debug sqlite3 databases
"sqlite" # to debug sqlite3 databases ;
]; };
iphonePkgs = {
inherit (pkgs)
ifuse
ipfs
libimobiledevice
;
};
tuiPkgs = {
inherit (pkgs)
aerc # email client
offlineimap # email mailox sync
sfeed # RSS fetcher
visidata # TUI spreadsheet viewer/editor
w3m
;
};
consoleMediaPkgs = {
inherit (pkgs)
ffmpeg
imagemagick
sox
yt-dlp
;
};
# TODO: split these into smaller groups. # TODO: split these into smaller groups.
# - moby doesn't want a lot of these. # - moby doesn't want a lot of these.
# - categories like # - categories like
# - dev? # - dev?
# - debugging? # - debugging?
consoleUtils = declPackageSet [ consolePkgs = {
"alsaUtils" # for aplay, speaker-test inherit (pkgs)
# "cdrtools" alsaUtils # for aplay, speaker-test
"clinfo" cdrtools
"dmidecode" clinfo
"dtrx" # `unar` alternative, "Do The Right eXtraction" dmidecode
"efivar" efivar
# "flashrom" flashrom
"git" # needed as a user package, for config. fwupd
# "gnupg" gh # MS GitHub cli
# "gocryptfs" git # needed as a user package, for config.
# "gopass" gnupg
# "gopass-jsonapi" gocryptfs
"helix" # text editor gopass # TODO: shouldn't be needed here
# "kitty" # XXX needs to be in consolueUtils because `ssh servo` from kitty sets `TERM=xterm-kitty` in the remote and breaks things gopass-jsonapi
"libsecret" # for managing user keyrings. TODO: what needs this? lift into the consumer kitty # TODO: move to GUI, but `ssh servo` from kitty sets `TERM=xterm-kitty` in the remove and breaks things
"lm_sensors" # for sensors-detect. TODO: what needs this? lift into the consumer libsecret # for managing user keyrings
"lshw" lm_sensors # for sensors-detect
# "memtester" lshw
"neovim" # needed as a user package, for swap persistence # memtester
# "nettools" neovim
# "networkmanager" # nettools
# "nixos-generators" # networkmanager
"nmon" nixpkgs-review
# "node2nix" # nixos-generators
# "oathToolkit" # for oathtool nmon
# "ponymix" # node2nix
"pulsemixer" # oathToolkit # for oathtool
"python3" # ponymix
# "python3Packages.eyeD3" # music tagging pulsemixer
"ripgrep" # needed as a user package so that its user-level config file can be installed python3
"rsync" ripgrep # needed as a user package so that its user-level config file can be installed
"sane-scripts.bittorrent" rsync
"sane-scripts.cli" # python3Packages.eyeD3 # music tagging
"snapper" sane-scripts
"sops" sequoia
"speedtest-cli" snapper
# "ssh-to-age" sops
"sudo" speedtest-cli
# "tageditor" # music tagging # ssh-to-age
# "unar" sudo
"wireguard-tools" # tageditor # music tagging
"xdg-terminal-exec" unar
"xdg-utils" # for xdg-open wireguard-tools
# "yarn" xdg-utils # for xdg-open
"zsh" # yarn
]; zsh
;
};
desktopConsoleUtils = declPackageSet [ guiPkgs = {
"gh" # MS GitHub cli inherit (flattenedPkgs)
"nix-index" # celluloid # mpv frontend
"nixpkgs-review" cozy # audiobook player
"sane-scripts.dev" # emote
"sequoia" evince # works on phosh
];
consoleMediaUtils = declPackageSet [ # { pkg = fluffychat-moby; persist.plaintext = [ ".local/share/chat.fluffy.fluffychat" ]; } # TODO: ship normal fluffychat on non-moby?
"ffmpeg"
"imagemagick"
"sox"
"yt-dlp"
];
tuiApps = declPackageSet [ # foliate # e-book reader
"aerc" # email client
"msmtp" # sendmail
"offlineimap" # email mailbox sync
"sfeed" # RSS fetcher
"visidata" # TUI spreadsheet viewer/editor
"w3m" # web browser
];
iphoneUtils = declPackageSet [ # XXX by default fractal stores its state in ~/.local/share/<UUID>.
"ifuse" # after logging in, manually change ~/.local/share/keyrings/... to point it to some predictable subdir.
"ipfs" # then reboot (so that libsecret daemon re-loads the keyring...?)
"libimobiledevice" # { pkg = fractal-latest; persist.private = [ ".local/share/fractal" ]; }
"sane-scripts.sync-from-iphone" # { pkg = fractal-next; persist.private = [ ".local/share/fractal" ]; }
];
devPkgs = declPackageSet [ # "gnome.cheese"
"clang" # gnome-feeds # RSS reader (with claimed mobile support)
"nodejs" "gnome.file-roller"
"tree-sitter" # "gnome.gnome-maps" # works on phosh
]; "gnome.nautilus"
# gnome-podcasts
# "gnome.gnome-system-monitor"
# "gnome.gnome-terminal" # works on phosh
# "gnome.gnome-weather"
gpodder
gthumb
jellyfin-media-player
komikku
koreader
# lollypop
# mpv
# networkmanagerapplet
# newsflash
nheko
pavucontrol
# picard # music tagging
# "libsForQt5.plasmatube" # Youtube player
soundconverter
# sublime-music
# tdesktop # broken on phosh
# tokodon
vlc
# pleroma client (Electron). input is broken on phosh. TODO(2023/02/02): fix electron19 input (insecure)
# whalebird
xterm # broken on phosh
;
};
desktopGuiPkgs = {
inherit (flattenedPkgs)
audacity
brave # for the integrated wallet -- as a backup
chromium
dino
electrum
element-desktop
font-manager
gajim # XMPP client
gimp # broken on phosh
"gnome.dconf-editor"
"gnome.gnome-disk-utility"
# "gnome.totem" # video player, supposedly supports UPnP
handbrake
hase
inkscape
kdenlive
kid3 # audio tagging
krita
libreoffice-fresh
mumble
obsidian
slic3r
steam
wireshark # could maybe ship the cli as sysadmin pkg
;
};
x86GuiPkgs = {
inherit (pkgs)
discord
# kaiteki # Pleroma client
# gnome.zenity # for kaiteki (it will use qarma, kdialog, or zenity)
# gpt2tc # XXX: unreliable mirror
# INDIVIDUAL PACKAGE DEFINITIONS # logseq # Personal Knowledge Management
losslesscut-bin
makemkv
monero-gui
signal-desktop
spotify
tor-browser-bundle-bin
zecwallet-lite
;
};
# packages not part of any package set; not enabled by default
otherPkgs = {
inherit (pkgs)
lemmy-server
mx-sanebot
stepmania
;
};
# define -- but don't enable -- the packages in some attrset.
declarePkgs = pkgsAsAttrs: lib.mapAttrs (_n: p: {
# no need to actually define the package here: it's defaulted
# package = mkDefault p;
}) pkgsAsAttrs;
in
{
sane.programs = lib.mkMerge [
(declarePkgs consoleMediaPkgs)
(declarePkgs consolePkgs)
(declarePkgs desktopGuiPkgs)
(declarePkgs guiPkgs)
(declarePkgs iphonePkgs)
(declarePkgs sysadminPkgs)
(declarePkgs sysadminExtraPkgs)
(declarePkgs tuiPkgs)
(declarePkgs x86GuiPkgs)
(declarePkgs otherPkgs)
{
# link the various package sets into their own meta packages
consoleMediaUtils = {
package = null;
suggestedPrograms = attrNames consoleMediaPkgs;
};
consoleUtils = {
package = null;
suggestedPrograms = attrNames consolePkgs;
};
desktopGuiApps = {
package = null;
suggestedPrograms = attrNames desktopGuiPkgs;
};
guiApps = {
package = null;
suggestedPrograms = (attrNames guiPkgs)
++ [ "web-browser" ]
++ [ "tuiApps" ]
++ lib.optional (pkgs.system == "x86_64-linux") "x86GuiApps";
};
iphoneUtils = {
package = null;
suggestedPrograms = attrNames iphonePkgs;
};
sysadminUtils = {
package = null;
suggestedPrograms = attrNames sysadminPkgs;
};
sysadminExtraUtils = {
package = null;
suggestedPrograms = attrNames sysadminExtraPkgs;
};
tuiApps = {
package = null;
suggestedPrograms = attrNames tuiPkgs;
};
x86GuiApps = {
package = null;
suggestedPrograms = attrNames x86GuiPkgs;
};
}
{
# nontrivial package definitions
dino.persist.private = [ ".local/share/dino" ];
# creds, but also 200 MB of node modules, etc # creds, but also 200 MB of node modules, etc
discord.persist.private = [ ".config/discord" ]; discord.persist.private = [ ".config/discord" ];
# creds/session keys, etc
element-desktop.persist.private = [ ".config/Element" ];
# `emote` will show a first-run dialog based on what's in this directory. # `emote` will show a first-run dialog based on what's in this directory.
# mostly, it just keeps a LRU of previously-used emotes to optimize display order. # mostly, it just keeps a LRU of previously-used emotes to optimize display order.
# TODO: package [smile](https://github.com/mijorus/smile) for probably a better mobile experience. # TODO: package [smile](https://github.com/mijorus/smile) for probably a better mobile experience.
emote.persist.plaintext = [ ".local/share/Emote" ]; emote.persist.plaintext = [ ".local/share/Emote" ];
fluffychat-moby.persist.plaintext = [ ".local/share/chat.fluffy.fluffychat" ];
# MS GitHub stores auth token in .config # MS GitHub stores auth token in .config
# TODO: we can populate gh's stuff statically; it even lets us use the same oauth across machines # TODO: we can populate gh's stuff statically; it even lets us use the same oauth across machines
gh.persist.private = [ ".config/gh" ]; gh.persist.private = [ ".config/gh" ];
@@ -221,6 +345,13 @@ in
mumble.persist.private = [ ".local/share/Mumble" ]; mumble.persist.private = [ ".local/share/Mumble" ];
# not strictly necessary, but allows caching articles; offline use, etc.
nheko.persist.private = [
".config/nheko" # config file (including client token)
".cache/nheko" # media cache
".local/share/nheko" # per-account state database
];
# settings (electron app) # settings (electron app)
obsidian.persist.plaintext = [ ".config/obsidian" ]; obsidian.persist.plaintext = [ ".config/obsidian" ];
@@ -237,8 +368,8 @@ in
tokodon.persist.private = [ ".cache/KDE/tokodon" ]; tokodon.persist.private = [ ".cache/KDE/tokodon" ];
# hardenedMalloc solves an "unable to connect to Tor" error when pressing the "connect" button # hardenedMalloc solves a crash at startup
# - still required as of 2023/07/14 # TODO 2023/02/02: is this safe to remove yet?
tor-browser-bundle-bin.package = pkgs.tor-browser-bundle-bin.override { tor-browser-bundle-bin.package = pkgs.tor-browser-bundle-bin.override {
useHardenedMalloc = false; useHardenedMalloc = false;
}; };
@@ -249,5 +380,6 @@ in
# zcash coins. safe to delete, just slow to regenerate (10-60 minutes) # zcash coins. safe to delete, just slow to regenerate (10-60 minutes)
zecwallet-lite.persist.private = [ ".zcash" ]; zecwallet-lite.persist.private = [ ".zcash" ];
}; }
];
} }

View File

@@ -1,36 +0,0 @@
# cantata is a mpd frontend.
# before launching it, run `mopidy` in some tab
# TODO: auto-launch mopidy when cantata launches?
{ ... }:
{
sane.programs.cantata = {
persist.plaintext = [
".cache/cantata" # album art
".local/share/cantata/library" # library index (?)
];
fs.".config/cantata/cantata.conf".symlink.text = ''
[General]
fetchCovers=true
storeCoversInMpdDir=false
version=2.5.0
[Connection]
allowLocalStreaming=true
applyReplayGain=true
autoUpdate=false
dir=~/Music
host=localhost
partition=
passwd=
port=6600
replayGain=off
streamUrl=
[LibraryPage]
artist\gridZoom=100
artist\searchActive=false
artist\viewMode=detailedtree
'';
suggestedPrograms = [ "mopidy" ];
};
}

View File

@@ -1,46 +0,0 @@
{ pkgs, ... }:
let
chattyNoOauth = pkgs.chatty.override {
# the OAuth feature (presumably used for web-based logins) pulls a full webkitgtk.
# especially when using the gtk3 version of evolution-data-server, it's an ancient webkitgtk_4_1.
# disable OAuth for a faster build & smaller closure
evolution-data-server = pkgs.evolution-data-server.override {
enableOAuth2 = false;
gnome-online-accounts = pkgs.gnome-online-accounts.override {
# disables the upstream "goabackend" feature -- presumably "Gnome Online Accounts Backend"
# frees us from webkit_4_1, in turn.
enableBackend = false;
gvfs = pkgs.gvfs.override {
# saves 20 minutes of build time, for unused feature
samba = null;
};
};
};
};
chatty-latest = pkgs.chatty-latest.override {
evolution-data-server-gtk4 = pkgs.evolution-data-server-gtk4.override {
gnome-online-accounts = pkgs.gnome-online-accounts.override {
# disables the upstream "goabackend" feature -- presumably "Gnome Online Accounts Backend"
# frees us from webkit_4_1, in turn.
enableBackend = false;
gvfs = pkgs.gvfs.override {
# saves 20 minutes of build time, for unused feature
samba = null;
};
};
};
};
in
{
sane.programs.chatty = {
# package = chattyNoOauth;
package = chatty-latest;
suggestedPrograms = [ "gnome-keyring" ];
persist.private = [
".local/share/chatty" # matrix avatars and files
# not just XMPP; without this Chatty will regenerate its device-id every boot.
# .purple/ contains XMPP *and* Matrix auth, logs, avatar cache, and a bit more
".purple"
];
};
}

View File

@@ -3,56 +3,29 @@
{ {
imports = [ imports = [
./aerc.nix ./aerc.nix
./alacritty.nix
./assorted.nix ./assorted.nix
./cantata.nix
./chatty.nix
./cozy.nix ./cozy.nix
./dino.nix
./element-desktop.nix
./epiphany.nix
./evince.nix
./firefox.nix
./fontconfig.nix
./fractal.nix
./fwupd.nix
./g4music.nix
./git.nix ./git.nix
./gnome-feeds.nix ./gnome-feeds.nix
./gnome-keyring.nix
./gnome-weather.nix
./gpodder.nix ./gpodder.nix
./gthumb.nix
./helix.nix
./imagemagick.nix ./imagemagick.nix
./jellyfin-media-player.nix ./jellyfin-media-player.nix
./kitty ./kitty
./komikku.nix ./komikku.nix
./koreader ./koreader
./libreoffice.nix ./libreoffice.nix
./lemoa.nix
./megapixels.nix
./mepo.nix
./mopidy.nix
./mpv.nix ./mpv.nix
./msmtp.nix
./neovim.nix ./neovim.nix
./newsflash.nix ./newsflash.nix
./nheko.nix
./nix-index.nix
./obsidian.nix
./offlineimap.nix ./offlineimap.nix
./rhythmbox.nix
./ripgrep.nix ./ripgrep.nix
./sfeed.nix ./sfeed.nix
./splatmoji.nix ./splatmoji.nix
./steam.nix ./steam.nix
./sublime-music.nix ./sublime-music.nix
./tangram.nix
./tuba.nix
./vlc.nix ./vlc.nix
./web-browser.nix
./wireshark.nix ./wireshark.nix
./xarchiver.nix
./zeal.nix ./zeal.nix
./zsh ./zsh
]; ];

View File

@@ -1,15 +0,0 @@
# usage:
# - start a DM with a rando via
# - '+' -> 'start conversation'
# - add a user to your roster via
# - '+' -> 'start conversation' -> '+' (opens the "add contact" dialog)
# - this triggers a popup on the remote side asking them for confirmation
# - after the remote's confirmation there will be a local popup for you to allow them to add you to their roster
# - to make a call:
# - ensure the other party is in your roster
# - open a DM with the party
# - click the phone icon at top (only visible if other party is in your roster)
{ ... }:
{
sane.programs.dino.persist.private = [ ".local/share/dino" ];
}

View File

@@ -1,9 +0,0 @@
{ ... }:
{
sane.programs.element-desktop = {
# creds/session keys, etc
persist.private = [ ".config/Element" ];
suggestedPrograms = [ "gnome-keyring" ];
};
}

View File

@@ -1,45 +0,0 @@
# epiphany web browser
# - GTK4/webkitgtk
#
# usability notes:
# - touch-based scroll works well (for moby)
# - URL bar constantly resets cursor to the start of the line as i type
# - maybe due to the URLbar suggestions getting in the way
{ pkgs, ... }:
{
sane.programs.epiphany = {
# XXX(2023/07/08): running on moby without this hack fails, with:
# - `bwrap: Can't make symlink at /var/run: File exists`
# this could be due to:
# - epiphany is somewhere following a symlink into /var/run instead of /run
# - (nothing in `env` or in this repo touches /var/run)
# - no xdg-desktop-portal is installed (unlikely)
#
# a few other users have hit this, in different contexts:
# - <https://gitlab.gnome.org/GNOME/gnome-builder/-/issues/1164>
# - <https://github.com/flatpak/flatpak/issues/3477>
# - <https://github.com/NixOS/nixpkgs/issues/197085>
package = pkgs.epiphany.overrideAttrs (upstream: {
preFixup = ''
gappsWrapperArgs+=(
--set WEBKIT_DISABLE_SANDBOX_THIS_IS_DANGEROUS "1"
);
'' + (upstream.preFixup or "");
});
persist.private = [
".cache/epiphany"
".local/share/epiphany"
# also .config/epiphany, but appears empty
];
mime.priority = 200; # default priority is 100: install epiphany only as a fallback
mime.associations = let
desktop = "org.gnome.Epiphany.desktop";
in {
"text/html" = desktop;
"x-scheme-handler/http" = desktop;
"x-scheme-handler/https" = desktop;
"x-scheme-handler/about" = desktop;
"x-scheme-handler/unknown" = desktop;
};
};
}

View File

@@ -1,4 +0,0 @@
{ ... }:
{
sane.programs.evince.mime.associations."application/pdf" = "org.gnome.Evince.desktop";
}

View File

@@ -1,15 +0,0 @@
{ config, lib, pkgs, ... }:
{
fonts = lib.mkIf config.sane.programs.fontconfig.enabled {
fontconfig.enable = true;
fontconfig.defaultFonts = {
emoji = [ "Font Awesome 6 Free" "Noto Color Emoji" ];
monospace = [ "Hack" ];
serif = [ "DejaVu Serif" ];
sansSerif = [ "DejaVu Sans" ];
};
#vvv enables dejavu_fonts, freefont_ttf, gyre-fonts, liberation_ttf, unifont, noto-fonts-emoji
enableDefaultPackages = true;
packages = with pkgs; [ font-awesome noto-fonts-emoji hack-font ];
};
}

View File

@@ -1,12 +0,0 @@
{ pkgs, ... }:
{
sane.programs.fractal = {
# package = pkgs.fractal-latest;
package = pkgs.fractal-next;
# XXX by default fractal stores its state in ~/.local/share/stable/<UUID>.
persist.private = [ ".local/share/stable" ];
suggestedPrograms = [ "gnome-keyring" ];
};
}

View File

@@ -1,7 +0,0 @@
{ config, lib, ... }:
{
services.fwupd = lib.mkIf config.sane.programs.fwupd.enabled {
# enables the dbus service, which i think the frontend speaks to.
enable = true;
};
}

View File

@@ -1,16 +0,0 @@
# N.B.: requires first-run setup on moby:
# - UI will render transparent
# - click the hamburger (top-right: immediately left from close button)
# > Preferences
# > Background-blur mode: change from "Always" to "Never"
#
# the background blur is probably some dconf setting somewhere.
{ ... }:
{
sane.programs.g4music = {
persist.plaintext = [
# index?
".cache/com.github.neithern.g4music"
];
};
}

View File

@@ -1,8 +1,6 @@
{ lib, pkgs, ... }: { lib, pkgs, ... }:
let let
# TODO: use formats.gitIni or lib.generators.toGitINI
# - see: <repo:nixos/nixpkgs:pkgs/pkgs-lib/formats.nix>
mkCfg = lib.generators.toINI { }; mkCfg = lib.generators.toINI { };
in in
{ {
@@ -13,15 +11,7 @@ in
user.name = "Colin"; user.name = "Colin";
user.email = "colin@uninsane.org"; user.email = "colin@uninsane.org";
alias.br = "branch";
alias.co = "checkout"; alias.co = "checkout";
alias.cp = "cherry-pick";
alias.d = "difftool";
alias.dif = "diff"; # common typo
alias.difsum = "diff --compact-summary"; #< show only the list of files which changed, not contents
alias.rb = "rebase";
alias.st = "status";
alias.stat = "status";
# difftastic docs: # difftastic docs:
# - <https://difftastic.wilfred.me.uk/git.html> # - <https://difftastic.wilfred.me.uk/git.html>
@@ -32,10 +22,5 @@ in
# render dates as YYYY-MM-DD HH:MM:SS +TZ # render dates as YYYY-MM-DD HH:MM:SS +TZ
log.date = "iso"; log.date = "iso";
sendemail.annotate = "yes";
sendemail.confirm = "always";
stash.showPatch = true;
}; };
} }

View File

@@ -1,10 +0,0 @@
{ config, lib, pkgs, ... }:
{
sane.programs.gnome-keyring = {
package = pkgs.gnome.gnome-keyring;
};
# adds gnome-keyring as a xdg-data-portal (xdg.portal)
services.gnome.gnome-keyring = lib.mkIf config.sane.programs.gnome-keyring.enabled {
enable = true;
};
}

View File

@@ -1,10 +0,0 @@
# preferences are saved via dconf; see `dconf dump /`
# cache dir is just for weather data (or maybe a http cache)
{ ... }:
{
sane.programs.gnome-weather = {
persist.plaintext = [
".cache/libgweather"
];
};
}

View File

@@ -1,15 +0,0 @@
{ pkgs, ... }:
{
sane.programs.gthumb = {
# compile without webservices to avoid the expensive webkitgtk dependency
package = pkgs.gthumb.override { withWebservices = false; };
mime.associations = {
"image/gif" = "org.gnome.gThumb.desktop";
"image/heif" = "org.gnome.gThumb.desktop"; # apple codec
"image/png" = "org.gnome.gThumb.desktop";
"image/jpeg" = "org.gnome.gThumb.desktop";
"image/svg+xml" = "org.gnome.gThumb.desktop";
"image/webp" = "org.gnome.gThumb.desktop";
};
};
}

View File

@@ -1,22 +0,0 @@
# Helix text editor
# debug log: `~/.cache/helix/helix.log`
# binary name is `hx`
{ ... }:
{
sane.programs.helix = {
# grammars need to be persisted when developing them
# - `hx --grammar fetch` and `hx --grammar build`
# but otherwise, they ship as part of HELIX_RUNTIME, in the nix store
# persist.plaintext = [ ".config/helix/runtime/grammars" ];
fs.".config/helix/config.toml".symlink.text = ''
# docs: <https://docs.helix-editor.com/configuration.html>
[editor.soft-wrap]
enable = true
[editor.whitespace.render]
space = "all"
tab = "all"
newline = "none"
'';
};
}

View File

@@ -6,4 +6,5 @@
}; };
suggestedPrograms = [ "ghostscript" ]; suggestedPrograms = [ "ghostscript" ];
}; };
sane.programs.ghostscript = {};
} }

View File

@@ -3,9 +3,7 @@
{ {
sane.programs.jellyfin-media-player = { sane.programs.jellyfin-media-player = {
# package = pkgs.jellyfin-media-player; # package = pkgs.jellyfin-media-player;
# qt6 version is slightly buggy, but also most qtwebengine apps (e.g. zeal) are on qt5 package = pkgs.jellyfin-media-player-qt6;
# so using qt6 would force yet *another* qtwebengine compile.
# package = pkgs.jellyfin-media-player-qt6;
# jellyfin stores things in a bunch of directories: this one persists auth info. # jellyfin stores things in a bunch of directories: this one persists auth info.
# it *might* be possible to populate this externally (it's Qt stuff), but likely to # it *might* be possible to populate this externally (it's Qt stuff), but likely to

View File

@@ -1,8 +1,7 @@
{ lib, ... }: { ... }:
{ {
sane.programs.kitty = { sane.programs.kitty.fs.".config/kitty/kitty.conf".symlink.text = ''
fs.".config/kitty/kitty.conf".symlink.text = ''
# docs: https://sw.kovidgoyal.net/kitty/conf/ # docs: https://sw.kovidgoyal.net/kitty/conf/
# disable terminal bell (when e.g. you backspace too many times) # disable terminal bell (when e.g. you backspace too many times)
enable_audio_bell no enable_audio_bell no
@@ -10,8 +9,6 @@
map ctrl+n new_os_window_with_cwd map ctrl+n new_os_window_with_cwd
include ${./PaperColor_dark.conf} include ${./PaperColor_dark.conf}
''; '';
env.TERMINAL = lib.mkDefault "kitty";
};
# include ${pkgs.kitty-themes}/themes/PaperColor_dark.conf # include ${pkgs.kitty-themes}/themes/PaperColor_dark.conf

View File

@@ -1,4 +1,4 @@
{ config, lib, pkgs, sane-lib, ... }: { config, lib, sane-lib, ... }:
let let
feeds = sane-lib.feeds; feeds = sane-lib.feeds;
@@ -10,12 +10,11 @@ let
# limit = 0 => download and keep *all* articles # limit = 0 => download and keep *all* articles
# download_full_article = true => populate feed by downloading the webpage -- not just what's encoded in the RSS <article> tags # download_full_article = true => populate feed by downloading the webpage -- not just what's encoded in the RSS <article> tags
# - use this for articles where the RSS only encodes content previews # - use this for articles where the RSS only encodes content previews
# - in practice, most articles don't work with download_full_article = false
# enable_filter = true => only render content that matches the filter_element css selector. # enable_filter = true => only render content that matches the filter_element css selector.
let fields = [ let fields = [
(lib.escapeShellArg feed.url) (lib.escapeShellArg feed.url)
"limit = 5" "limit = 5"
"download_full_article = true" "download_full_article = false"
"include_images = true" "include_images = true"
"enable_filter = false" "enable_filter = false"
"filter_element = \"\"" "filter_element = \"\""
@@ -23,7 +22,6 @@ let
) wantedFeeds; ) wantedFeeds;
in { in {
sane.programs.koreader = { sane.programs.koreader = {
package = pkgs.koreader-from-src;
# koreader applies these lua "patches" at boot: # koreader applies these lua "patches" at boot:
# - <https://github.com/koreader/koreader/wiki/User-patches> # - <https://github.com/koreader/koreader/wiki/User-patches>
# - TODO: upstream this patch to koreader # - TODO: upstream this patch to koreader

View File

@@ -1,7 +0,0 @@
{ ... }:
{
sane.programs.lemoa = {
# creds
persist.private = [ ".local/share/io.github.lemmygtk.lemoa" ];
};
}

View File

@@ -1,13 +1,8 @@
{ pkgs, ... }: { ... }:
{ {
sane.programs.libreoffice = { # libreoffice: disable first-run stuff
# package = pkgs.libreoffice-bin; sane.programs.libreoffice-fresh.fs.".config/libreoffice/4/user/registrymodifications.xcu".symlink.text = ''
# package = pkgs.libreoffice-still;
package = pkgs.libreoffice-fresh;
# disable first-run stuff
fs.".config/libreoffice/4/user/registrymodifications.xcu".symlink.text = ''
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<oor:items xmlns:oor="http://openoffice.org/2001/registry" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <oor:items xmlns:oor="http://openoffice.org/2001/registry" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<item oor:path="/org.openoffice.Office.Common/Misc"><prop oor:name="FirstRun" oor:op="fuse"><value>false</value></prop></item> <item oor:path="/org.openoffice.Office.Common/Misc"><prop oor:name="FirstRun" oor:op="fuse"><value>false</value></prop></item>
@@ -16,5 +11,4 @@
''; '';
# <item oor:path="/org.openoffice.Setup/Product"><prop oor:name="LastTimeDonateShown" oor:op="fuse"><value>1667693880</value></prop></item> # <item oor:path="/org.openoffice.Setup/Product"><prop oor:name="LastTimeDonateShown" oor:op="fuse"><value>1667693880</value></prop></item>
# <item oor:path="/org.openoffice.Setup/Product"><prop oor:name="LastTimeGetInvolvedShown" oor:op="fuse"><value>1667693880</value></prop></item> # <item oor:path="/org.openoffice.Setup/Product"><prop oor:name="LastTimeGetInvolvedShown" oor:op="fuse"><value>1667693880</value></prop></item>
};
} }

View File

@@ -1,11 +0,0 @@
{ pkgs, ... }:
{
sane.programs.megapixels.package = pkgs.megapixels.override {
# megapixels uses zbar to read barcodes.
# zbar by default ships zbarcam-gtk and zbarcam-qt, neither of which megapixels needs.
# but the latter takes a dep on qt, which bloats the closure and the build, so disable this feature.
zbar = pkgs.zbar.override {
enableVideo = false;
};
};
}

View File

@@ -1,26 +0,0 @@
# docs: <https://git.sr.ht/~mil/mepo>
# irc #mepo:irc.oftc.net
{ config, lib, ... }:
{
sane.programs.mepo = {
persist.plaintext = [ ".cache/mepo/tiles" ];
# ~/.cache/mepo/savestate has precise coordinates and pins: keep those private
persist.private = [
{ type = "file"; path = ".cache/mepo/savestate"; }
];
# give mepo access to gpsd for location data, if that's enabled.
# same with geoclue2.
suggestedPrograms = lib.optional config.services.gpsd.enable "gpsd"
++ lib.optional config.services.geoclue2.enable "geoclue2-with-demo-agent"
;
};
# programs.mepo = lib.mkIf config.sane.programs.mepo.enabled {
# # enable location services (via geoclue)
# enable = true;
# # more precise, via gpsd ("may require additional config")
# # programs.mepo.gpsd.enable = true
# };
}

View File

@@ -1,56 +0,0 @@
# chat: <https://mopidy.zulipchat.com/>
# config docs: <https://docs.mopidy.com/en/latest/config/>
# web client: <http://localhost:6680>
# mpd: hosted on `localhost:6600`, no password`
#
# dump config:
# - `mopidy config`
# update local file index with
# - `mopidy local scan`
#
# if running as service, those commands are `mopidy --config ... <command>`
# and config path is found by `systemctl cat mopidy`
{ config, lib, pkgs, ... }:
let
# TODO: upstream this as `mopidy.withExtensions`
# this is borrowed from the nixos mopidy service
mopidyWithExtensions = extensions: with pkgs; buildEnv {
name = "mopidy-with-extensions-${mopidy.version}";
paths = lib.closePropagation extensions;
pathsToLink = [ "/${mopidyPackages.python.sitePackages}" ];
nativeBuildInputs = [ makeWrapper ];
postBuild = ''
makeWrapper ${mopidy}/bin/mopidy $out/bin/mopidy \
--prefix PYTHONPATH : $out/${mopidyPackages.python.sitePackages}
'';
};
in
{
sane.programs.mopidy = {
package = mopidyWithExtensions (with pkgs; [
mopidy-iris # web client: <https://github.com/jaedb/Iris>
mopidy-jellyfin
mopidy-local
mopidy-mpd
mopidy-mpris
mopidy-spotify
# TODO: mopidy-podcast, mopidy-youtube
# alternate web clients:
# mopidy-moped: <https://github.com/martijnboland/moped>
# mopidy-muse: <https://github.com/cristianpb/muse>
]);
persist.plaintext = [
".local/share/mopidy/local" # thumbs, library db
];
persist.private = [
".local/share/mopidy/http" # cookie
];
secrets.".config/mopidy/mopidy.conf" = ../../../secrets/common/mopidy.conf.bin;
# other folders:
# - .cache/mopidy
# - .config/mopidy
};
}

View File

@@ -1,109 +1,13 @@
# mpv docs: { ... }:
# - <https://mpv.io/manual/master>
# - <https://github.com/mpv-player/mpv/wiki>
# curated mpv mods/scripts/users:
# - <https://github.com/stax76/awesome-mpv>
{ pkgs, ... }:
{ {
sane.programs.mpv = { sane.programs.mpv = {
package = pkgs.wrapMpv pkgs.mpv-unwrapped {
youtubeSupport = false; #< XXX(2023/08/03): doesn't cross compile until next staging -> master merge
scripts = with pkgs.mpvScripts; [
mpris
# uosc
pkgs.mpv-uosc-latest
];
extraMakeWrapperArgs = [
# 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.
# run with `--vo=help` to see a list of all output options.
# non-exhaustive (F=fails, W=works)
# ? libmpv render API for libmpv
# ? gpu Shader-based GPU Renderer
# ? gpu-next Video output based on libplacebo
# ? vdpau VDPAU with X11
# ? wlshm Wayland SHM video output (software scaling)
# ? xv X11/Xv
# W sdl SDL 2.0 Renderer
# F dmabuf-wayland Wayland dmabuf video output
# ? vaapi VA API with X11
# ? x11 X11 (software scaling)
# ? null Null video output
# ? caca libcaca
# F drm Direct Rendering Manager (software scaling)
"--add-flags" "--vo=sdl"
];
};
persist.plaintext = [ ".config/mpv/watch_later" ]; persist.plaintext = [ ".config/mpv/watch_later" ];
fs.".config/mpv/input.conf".symlink.text = '' # format is <key>=%<length>%<value>
# let volume keys be interpreted by the system.
# this is important for sxmo.
VOLUME_UP ignore
VOLUME_DOWN ignore
'';
fs.".config/mpv/mpv.conf".symlink.text = '' fs.".config/mpv/mpv.conf".symlink.text = ''
save-position-on-quit=yes save-position-on-quit=%3%yes
keep-open=yes keep-open=%3%yes
# force GUI, even for tracks w/o album art
# see: <https://www.reddit.com/r/mpv/comments/rvrrpt/oscosdgui_and_arch_linux/>
player-operation-mode=pseudo-gui
# use uosc instead (for On Screen Controls)
osc=no
# uosc provides its own seeking/volume indicators, so you also don't need this
osd-bar=no
# uosc will draw its own window controls if you disable window border
border=no
''; '';
fs.".config/mpv/script-opts/osc.conf".symlink.text = ''
# make the on-screen controls *always* visible
# unfortunately, this applies to full-screen as well
# - docs: <https://mpv.io/manual/master/#on-screen-controller-visibility>
# if uosc is installed, this file is unused
visibility=always
'';
fs.".config/mpv/script-opts/uosc.conf".symlink.text = let
play_pause_btn = "cycle:play_arrow:pause:no=pause/yes=play_arrow";
rev_btn = "command:replay_10:seek -10";
fwd_btn = "command:forward_30:seek 30";
in ''
# docs:
# - <https://github.com/tomasklaen/uosc>
# - <https://superuser.com/questions/1775550/add-new-buttons-to-mpv-uosc-ui>
timeline_style=bar
timeline_persistency=paused,audio
controls_persistency=paused,audio
volume_persistency=audio
volume_opacity=0.75
# speed_persistency=paused,audio
# vvv want a close button?
top_bar=always
top_bar_persistency=paused
controls=menu,<video>subtitles,<has_many_audio>audio,<has_many_video>video,<has_many_edition>editions,<stream>stream-quality,space,${rev_btn},${play_pause_btn},${fwd_btn},space,speed:1.0,gap,<video>fullscreen
text_border=6.0
font_bold=yes
background_text=ff8080
foreground=ff8080
ui_scale=1.0
'';
mime.priority = 200; # default = 100; 200 means to yield to other apps
mime.associations."audio/flac" = "mpv.desktop";
mime.associations."audio/mpeg" = "mpv.desktop";
mime.associations."audio/x-vorbis+ogg" = "mpv.desktop";
mime.associations."video/mp4" = "mpv.desktop";
mime.associations."video/quicktime" = "mpv.desktop";
mime.associations."video/webm" = "mpv.desktop";
mime.associations."video/x-matroska" = "mpv.desktop";
}; };
} }

View File

@@ -1,25 +0,0 @@
# docs: <https://nixos.wiki/wiki/Msmtp>
# validate with e.g.
# - `echo -e "Content-Type: text/plain\r\nSubject: Test\r\n\r\nHello World" | sendmail test@uninsane.org`
{ config, lib, ... }:
{
sane.programs.msmtp = {
secrets.".config/msmtp/password.txt" = ../../../secrets/common/msmtp_password.txt.bin;
};
programs.msmtp = lib.mkIf config.sane.programs.msmtp.enabled {
enable = true;
accounts = {
default = {
auth = true;
tls = true;
tls_starttls = false; # needed else sendmail hangs
from = "Colin <colin@uninsane.org>";
host = "mx.uninsane.org";
user = "colin";
passwordeval = "cat ~/.config/msmtp/password.txt";
};
};
};
}

View File

@@ -5,21 +5,35 @@ let
inherit (lib) concatMapStrings mkIf optionalString; inherit (lib) concatMapStrings mkIf optionalString;
# this structure roughly mirrors home-manager's `programs.neovim.plugins` option # this structure roughly mirrors home-manager's `programs.neovim.plugins` option
plugins = with pkgs.vimPlugins; [ plugins = with pkgs.vimPlugins; [
{ # docs: surround-nvim: https://github.com/ur4ltz/surround.nvim/
# docs: vim-surround: https://github.com/tpope/vim-surround
{ plugin = vim-surround; }
# docs: fzf-vim (fuzzy finder): https://github.com/junegunn/fzf.vim # docs: fzf-vim (fuzzy finder): https://github.com/junegunn/fzf.vim
plugin = fzf-vim; { plugin = fzf-vim; }
} ({
{ # docs: tex-conceal-vim: https://github.com/KeitaNakamura/tex-conceal.vim/
plugin = tex-conceal-vim;
type = "viml";
config = ''
" present prettier fractions
let g:tex_conceal_frac=1
'';
})
({
plugin = vim-SyntaxRange;
type = "viml";
config = ''
" enable markdown-style codeblock highlighting for tex code
autocmd BufEnter * call SyntaxRange#Include('```tex', '```', 'tex', 'NonText')
" autocmd Syntax tex set conceallevel=2
'';
})
({
# treesitter syntax highlighting: https://nixos.wiki/wiki/Tree_sitters # treesitter syntax highlighting: https://nixos.wiki/wiki/Tree_sitters
# docs: https://github.com/nvim-treesitter/nvim-treesitter # docs: https://github.com/nvim-treesitter/nvim-treesitter
# config taken from: https://github.com/i077/system/blob/master/modules/home/neovim/default.nix # config taken from: https://github.com/i077/system/blob/master/modules/home/neovim/default.nix
# this is required for tree-sitter to even highlight # this is required for tree-sitter to even highlight
plugin = nvim-treesitter.withPlugins (_: nvim-treesitter.allGrammars ++ [ plugin = nvim-treesitter.withAllGrammars;
# XXX: this is apparently not enough to enable syntax highlighting!
# nvim-treesitter ships its own queries which may be distinct from e.g. helix.
# the queries aren't included when i ship the grammar in this manner
pkgs.tree-sitter-nix-shell
]);
type = "lua"; type = "lua";
config = '' config = ''
require'nvim-treesitter.configs'.setup { require'nvim-treesitter.configs'.setup {
@@ -50,48 +64,15 @@ let
vim.o.foldmethod = 'expr' vim.o.foldmethod = 'expr'
vim.o.foldexpr = 'nvim_treesitter#foldexpr()' vim.o.foldexpr = 'nvim_treesitter#foldexpr()'
''; '';
} })
{
# docs: tex-conceal-vim: https://github.com/KeitaNakamura/tex-conceal.vim/
plugin = tex-conceal-vim;
type = "viml";
config = ''
" present prettier fractions
let g:tex_conceal_frac=1
'';
}
{
# source: <https://github.com/LnL7/vim-nix>
# fixes auto-indent (incl tab size) when editing .nix files
plugin = vim-nix;
}
{
# docs: surround-nvim: https://github.com/ur4ltz/surround.nvim/
# docs: vim-surround: https://github.com/tpope/vim-surround
plugin = vim-surround;
}
{
plugin = vim-SyntaxRange;
type = "viml";
config = ''
" enable markdown-style codeblock highlighting for tex code
autocmd BufEnter * call SyntaxRange#Include('```tex', '```', 'tex', 'NonText')
" autocmd Syntax tex set conceallevel=2
'';
}
]; ];
plugin-packages = map (p: p.plugin) plugins; plugin-packages = map (p: p.plugin) plugins;
plugin-config-viml = concatMapStrings (p: optionalString (p.type or "" == "viml") p.config) plugins; plugin-config-tex = concatMapStrings (p: optionalString (p.type or "" == "viml") p.config) plugins;
plugin-config-lua = concatMapStrings (p: optionalString (p.type or "" == "lua") p.config) plugins; plugin-config-lua = concatMapStrings (p: optionalString (p.type or "" == "lua") p.config) plugins;
in in
{ {
# private because there could be sensitive things in the swap # private because there could be sensitive things in the swap
sane.programs.neovim = { sane.programs.neovim.persist.private = [ ".cache/vim-swap" ];
persist.private = [ ".cache/vim-swap" ];
env.EDITOR = "vim";
# git claims it should use EDITOR, but it doesn't!
env.GIT_EDITOR = "vim";
};
programs.neovim = mkIf config.sane.programs.neovim.enabled { programs.neovim = mkIf config.sane.programs.neovim.enabled {
# neovim: https://github.com/neovim/neovim # neovim: https://github.com/neovim/neovim
@@ -99,7 +80,7 @@ in
viAlias = true; viAlias = true;
vimAlias = true; vimAlias = true;
configure = { configure = {
packages.plugins = { packages.myVimPackage = {
start = plugin-packages; start = plugin-packages;
}; };
customRC = '' customRC = ''
@@ -135,8 +116,8 @@ in
set list set list
set listchars=tab:\·,trail:·,extends:,precedes:,nbsp: set listchars=tab:\·,trail:·,extends:,precedes:,nbsp:
""""" PLUGIN CONFIG (vim) """"" PLUGIN CONFIG (tex)
${plugin-config-viml} ${plugin-config-tex}
""""" PLUGIN CONFIG (lua) """"" PLUGIN CONFIG (lua)
lua <<EOF lua <<EOF

View File

@@ -1,9 +0,0 @@
{ ... }:
{
# not strictly necessary, but allows caching articles; offline use, etc.
sane.programs.nheko.persist.private = [
".config/nheko" # config file (including client token)
".cache/nheko" # media cache
".local/share/nheko" # per-account state database
];
}

View File

@@ -1,7 +0,0 @@
{ config, lib, ... }:
{
# provides `nix-locate`, backed by the manually run `nix-index`
sane.programs.nix-index = {
persist.plaintext = [ ".cache/nix-index" ];
};
}

View File

@@ -1,4 +0,0 @@
{ ... }:
{
sane.programs.obsidian.mime.associations."text/markdown" = "obsidian.desktop";
}

View File

@@ -1,11 +0,0 @@
{ ... }:
{
sane.programs.rhythmbox = {
persist.plaintext = [
# playlists; index
".local/share/rhythmbox"
# album art
".cache/rhythmbox"
];
};
}

View File

@@ -10,11 +10,13 @@
# XXX doesn't seem to understand ~ as shorthand for `$HOME` # XXX doesn't seem to understand ~ as shorthand for `$HOME`
history_file=/home/colin/.local/state/splatmoji/history history_file=/home/colin/.local/state/splatmoji/history
history_length=5 history_length=5
paste_command=${pkgs.wtype}/bin/wtype -M Ctrl -k v # TODO: wayland equiv
paste_command=xdotool key ctrl+v
# rofi_command=${pkgs.wofi}/bin/wofi --dmenu --insensitive --cache-file /dev/null # rofi_command=${pkgs.wofi}/bin/wofi --dmenu --insensitive --cache-file /dev/null
rofi_command=${pkgs.fuzzel}/bin/fuzzel -d -i -w 60 rofi_command=${pkgs.fuzzel}/bin/fuzzel -d -i -w 60
xdotool_command=${pkgs.wtype}/bin/wtype xdotool_command=${pkgs.wtype}/bin/wtype
xsel_command=${pkgs.findutils}/bin/xargs ${pkgs.wl-clipboard}/bin/wl-copy # TODO: wayland equiv
xsel_command=xsel -b -i
''; '';
}; };
} }

View File

@@ -1,42 +0,0 @@
# Tangram is a GTK/webkit browser
# it views each tab as a distinct application, persisted, and where the 'home' button action is specific to each tab.
# it supports ephemeral tabs, but UX is heavily geared to GCing those as early as possible.
{ pkgs, ... }:
let
dconfProfile = pkgs.writeTextFile {
name = "dconf-tangram-profile";
destination = "/etc/dconf/profile/tangram";
text = ''
user-db:tangram
system-db:site
'';
};
in
{
sane.programs.tangram = {
# XXX(2023/07/08): running on moby without disabling the webkit sandbox fails, with:
# - `bwrap: Can't make symlink at /var/run: File exists`
# see epiphany.nix for more info
package = pkgs.tangram.overrideAttrs (upstream: {
preFixup = ''
gappsWrapperArgs+=(
--set WEBKIT_DISABLE_SANDBOX_THIS_IS_DANGEROUS "1"
--set DCONF_PROFILE "${dconfProfile}/etc/dconf/profile/tangram"
);
'' + (upstream.preFixup or "");
});
persist.private = [
".cache/Tangram"
".local/share/Tangram"
# dconf achieves atomic writes via `mv`, so a symlink doesn't work
# moreover, i have to persist the *whole* directory:
# - `user-db:tangram/user` causes a schema failure
# - bind-mounting `~/private/.config/dconf/tangram` causes dconf to try a cross-fs `mv`, which fails
# - dconf provides no way to specify an alternate ~/.config/dconf dir, except by overriding XDG_CONFIG_HOME
# { type = "file"; path = ".config/dconf/tangram"; method = "bind"; }
".config/dconf"
];
};
}

View File

@@ -1,4 +0,0 @@
{ ... }:
{
sane.programs.tuba.suggestedPrograms = [ "gnome-keyring" ];
}

View File

@@ -10,13 +10,8 @@ let
in in
{ {
sane.programs.vlc = { sane.programs.vlc = {
persist.private = [
# vlc remembers play position in ~/.config/vlc/vlc-qt-interface.conf # vlc remembers play position in ~/.config/vlc/vlc-qt-interface.conf
# filenames are stored in plaintext (unlike mpv, which i think hashes them) persist.plaintext = [ ".config/vlc" ];
".config/vlc"
# vlc caches artwork. i'm not sure where it gets the artwork (internet? embedded metadata?)
".cache/vlc"
];
fs.".config/vlc/vlcrc".symlink.text = '' fs.".config/vlc/vlcrc".symlink.text = ''
[podcast] [podcast]
podcast-urls=${podcast-urls} podcast-urls=${podcast-urls}
@@ -25,13 +20,5 @@ in
[qt] [qt]
qt-privacy-ask=0 qt-privacy-ask=0
''; '';
mime.associations."audio/flac" = "vlc.desktop";
mime.associations."audio/mpeg" = "vlc.desktop";
mime.associations."audio/x-vorbis+ogg" = "vlc.desktop";
mime.associations."video/mp4" = "vlc.desktop";
mime.associations."video/quicktime" = "vlc.desktop";
mime.associations."video/webm" = "vlc.desktop";
mime.associations."video/x-matroska" = "vlc.desktop";
}; };
} }

View File

@@ -9,20 +9,21 @@
{ config, lib, pkgs, ...}: { config, lib, pkgs, ...}:
with lib; with lib;
let let
cfg = config.sane.programs.firefox.config; cfg = config.sane.programs.web-browser.config;
mobile-prefs = lib.optionals false pkgs.librewolf-pmos-mobile.extraPrefsFiles;
# allow easy switching between firefox and librewolf with `defaultSettings`, below # allow easy switching between firefox and librewolf with `defaultSettings`, below
librewolfSettings = { librewolfSettings = {
browser = pkgs.librewolf-unwrapped; browser = pkgs.librewolf-unwrapped;
extraPrefsFiles = pkgs.librewolf-unwrapped.extraPrefsFiles ++ mobile-prefs; # browser = pkgs.librewolf-unwrapped.overrideAttrs (drv: {
# # this allows side-loading unsigned addons
# MOZ_REQUIRE_SIGNING = false;
# });
libName = "librewolf"; libName = "librewolf";
dotDir = ".librewolf"; dotDir = ".librewolf";
cacheDir = ".cache/librewolf"; cacheDir = ".cache/librewolf"; # TODO: is it?
desktop = "librewolf.desktop"; desktop = "librewolf.desktop";
}; };
firefoxSettings = { firefoxSettings = {
browser = pkgs.firefox-esr-unwrapped; browser = pkgs.firefox-esr-unwrapped;
extraPrefsFiles = mobile-prefs;
libName = "firefox"; libName = "firefox";
dotDir = ".mozilla/firefox"; dotDir = ".mozilla/firefox";
cacheDir = ".cache/mozilla"; cacheDir = ".cache/mozilla";
@@ -46,7 +47,8 @@ let
package = pkgs.wrapFirefox cfg.browser.browser { package = pkgs.wrapFirefox cfg.browser.browser {
# inherit the default librewolf.cfg # inherit the default librewolf.cfg
# it can be further customized via ~/.librewolf/librewolf.overrides.cfg # it can be further customized via ~/.librewolf/librewolf.overrides.cfg
inherit (cfg.browser) extraPrefsFiles libName; inherit (pkgs.librewolf-unwrapped) extraPrefsFiles;
inherit (cfg.browser) libName;
extraNativeMessagingHosts = optional cfg.addons.browserpass-extension.enable pkgs.browserpass; extraNativeMessagingHosts = optional cfg.addons.browserpass-extension.enable pkgs.browserpass;
# extraNativeMessagingHosts = [ pkgs.gopass-native-messaging-host ]; # extraNativeMessagingHosts = [ pkgs.gopass-native-messaging-host ];
@@ -70,10 +72,7 @@ let
}; };
UserMessaging = { UserMessaging = {
ExtensionRecommendations = false; ExtensionRecommendations = false;
FeatureRecommendations = false;
SkipOnboarding = true; SkipOnboarding = true;
UrlbarInterventions = false;
WhatsNew = false;
}; };
# these were taken from Librewolf # these were taken from Librewolf
@@ -145,62 +144,54 @@ in
{ {
config = mkMerge [ config = mkMerge [
({ ({
sane.programs.firefox.configOption = mkOption { sane.programs.web-browser.configOption = mkOption {
type = types.submodule configOpts; type = types.submodule configOpts;
default = {}; default = {};
}; };
sane.programs.firefox.config.addons = { sane.programs.web-browser.config.addons = {
# get names from:
# - ~/ref/nix-community/nur-combined/repos/rycee/pkgs/firefox-addons/generated-firefox-addons.nix
# `wget ...xpi`; `unar ...xpi`; `cat */manifest.json | jq '.browser_specific_settings.gecko.id'`
browserpass-extension = { browserpass-extension = {
package = pkgs.firefox-extensions.browserpass-extension; # package = addon "browserpass-ce" "browserpass@maximbaz.com" "sha256-sXgUBbRvMnRpeIW1MTkmTcoqtW/8RDXAkxAq1evFkpc=";
enable = lib.mkDefault true; package = localAddon pkgs.browserpass-extension;
};
bypass-paywalls-clean = {
package = pkgs.firefox-extensions.bypass-paywalls-clean;
enable = lib.mkDefault true; enable = lib.mkDefault true;
}; };
# TODO: build bypass-paywalls from source? it's mysteriously disappeared from the Mozilla store.
# bypass-paywalls-clean.package = addon "bypass-paywalls-clean" "{d133e097-46d9-4ecc-9903-fa6a722a6e0e}" "sha256-oUwdqdAwV3DezaTtOMx7A/s4lzIws+t2f08mwk+324k=";
# bypass-paywalls-clean.enable = lib.mkDefault true;
ether-metamask = { ether-metamask = {
package = pkgs.firefox-extensions.ether-metamask; package = addon "ether-metamask" "webextension@metamask.io" "sha256-G+MwJDOcsaxYSUXjahHJmkWnjLeQ0Wven8DU/lGeMzA=";
enable = lib.mkDefault false; # until i can disable the first-run notification enable = lib.mkDefault true;
}; };
i2p-in-private-browsing = { i2p-in-private-browsing = {
package = pkgs.firefox-extensions.i2p-in-private-browsing; package = addon "i2p-in-private-browsing" "i2ppb@eyedeekay.github.io" "sha256-dJcJ3jxeAeAkRvhODeIVrCflvX+S4E0wT/PyYzQBQWs=";
enable = lib.mkDefault config.services.i2p.enable; enable = lib.mkDefault config.services.i2p.enable;
}; };
sidebery = { sidebery = {
package = pkgs.firefox-extensions.sidebery; package = addon "sidebery" "{3c078156-979c-498b-8990-85f7987dd929}" "sha256-YONfK/rIjlsrTgRHIt3km07Q7KnpIW89Z9r92ZSCc6w=";
enable = lib.mkDefault true; enable = lib.mkDefault true;
}; };
sponsorblock = { sponsorblock = {
package = pkgs.firefox-extensions.sponsorblock; package = addon "sponsorblock" "sponsorBlocker@ajay.app" "sha256-hRsvLaAsVm3dALsTrJqHTNgRFAQcU7XSaGhr5G6+mFs=";
enable = lib.mkDefault true; enable = lib.mkDefault true;
}; };
ublacklist = { ublacklist = {
package = pkgs.firefox-extensions.ublacklist; package = addon "ublacklist" "@ublacklist" "sha256-RqY5iHzbL2qizth7aguyOKWPyINXmrwOlf/OsfqAS48=";
enable = lib.mkDefault true; enable = lib.mkDefault true;
}; };
ublock-origin = { ublock-origin = {
package = pkgs.firefox-extensions.ublock-origin; package = addon "ublock-origin" "uBlock0@raymondhill.net" "sha256-eHlQrU/b9X/6sTbHBpGAd+0VsLT7IrVCnd0AQ948lyA=";
enable = lib.mkDefault true; enable = lib.mkDefault true;
}; };
}; };
}) })
({ ({
sane.programs.firefox = { sane.programs.web-browser = {
inherit package; inherit package;
mime.associations = let
inherit (cfg.browser) desktop;
in {
"text/html" = desktop;
"x-scheme-handler/http" = desktop;
"x-scheme-handler/https" = desktop;
"x-scheme-handler/about" = desktop;
"x-scheme-handler/unknown" = desktop;
};
# env.BROWSER = "${package}/bin/${cfg.browser.libName}";
env.BROWSER = cfg.browser.libName; # used by misc tools like xdg-email, as fallback
# uBlock filter list configuration. # uBlock filter list configuration.
# specifically, enable the GDPR cookie prompt blocker. # specifically, enable the GDPR cookie prompt blocker.
# data.toOverwrite.filterLists is additive (i.e. it supplements the default filters) # data.toOverwrite.filterLists is additive (i.e. it supplements the default filters)
@@ -219,7 +210,6 @@ in
} }
} }
''; '';
# TODO: this is better suited in `extraPrefs` during `wrapFirefox` call
fs."${cfg.browser.dotDir}/${cfg.browser.libName}.overrides.cfg".symlink.text = '' fs."${cfg.browser.dotDir}/${cfg.browser.libName}.overrides.cfg".symlink.text = ''
// if we can't query the revocation status of a SSL cert because the issuer is offline, // if we can't query the revocation status of a SSL cert because the issuer is offline,
// treat it as unrevoked. // treat it as unrevoked.
@@ -241,22 +231,16 @@ in
''; '';
}; };
}) })
(mkIf config.sane.programs.firefox.enabled { (mkIf config.sane.programs.web-browser.enabled {
# TODO: move the persistence into the sane.programs API (above) # TODO: move the persistence into the sane.programs API (above)
# flush the cache to disk to avoid it taking up too much tmp. # flush the cache to disk to avoid it taking up too much tmp
sane.user.persist.byPath."${cfg.browser.cacheDir}".store = sane.user.persist.byPath."${cfg.browser.cacheDir}" = lib.mkIf (cfg.persistCache != null) {
if (cfg.persistData != null) then store = cfg.persistCache;
cfg.persistData };
else
"cryptClearOnBoot"
;
sane.user.persist.byPath."${cfg.browser.dotDir}/default".store = sane.user.persist.byPath."${cfg.browser.dotDir}/default" = lib.mkIf (cfg.persistData != null) {
if (cfg.persistData != null) then store = cfg.persistData;
cfg.persistData };
else
"cryptClearOnBoot"
;
}) })
]; ];
} }

Some files were not shown because too many files have changed in this diff Show More