Compare commits

...

54 Commits

Author SHA1 Message Date
e08281c380 fix: typo in config option name 2023-02-03 09:09:37 +00:00
afb006f6ec programs: port last users & remove the old packages.nix 2023-02-03 05:26:57 +00:00
a76cf03232 remove unused "enableDevPkgs" option 2023-02-03 05:18:38 +00:00
9c24f24306 programs: port GUI apps to new config system 2023-02-03 05:08:52 +00:00
736999eea6 programs: port console packages to new config system 2023-02-03 04:24:17 +00:00
979ed38506 programs: make system be some type of meta-program/package 2023-02-03 04:03:22 +00:00
46285852d0 modules: add a sane.programs interface which i can use going forward in place of sane.packages 2023-02-03 03:38:23 +00:00
0e756d5064 packages: add sox sound converter 2023-02-02 10:23:01 +00:00
a52ead5aec nit: document what "foliate" application is 2023-02-02 00:21:07 +00:00
c0377ff1a0 dovecot: define Drafts and Trash folders 2023-01-31 08:22:20 +00:00
062ef20d05 dovecot: auto-create the "Sent" message box 2023-01-31 06:57:35 +00:00
a0861edc5f packages: enable kitty on servo to fix login error 2023-01-31 06:43:02 +00:00
eae075acb5 flake: remove unused nixpkgs-stable argument. we can re-add it when needed 2023-01-31 04:09:49 +00:00
ef2ba01141 pins: remove dead nheko code 2023-01-31 04:05:18 +00:00
2756e15bab flake update: nixpkgs-stable 2023-01-29 -> 2023-01-30
```
• Updated input 'nixpkgs-stable':
    'github:nixos/nixpkgs/22c4a7a4796a91c297a7e59078a84ec29515f86e' (2023-01-29)
  → 'github:nixos/nixpkgs/f413457e0dd7a42adefdbcea4391dd9751509025' (2023-01-30)
• Updated input 'uninsane-dot-org':
    'git+https://git.uninsane.org/colin/uninsane?ref=refs%2fheads%2fmaster&rev=80c6ec95bd430e29d231cf745f19279bb76fb382' (2022-10-27)
  → 'git+https://git.uninsane.org/colin/uninsane?ref=refs%2fheads%2fmaster&rev=b099c24091cc192abf3997b94342d4b31cc5757b' (2023-01-31)
```
2023-01-31 03:56:39 +00:00
940aac3a22 refactor: move persist settings into persist.nix 2023-01-31 03:44:48 +00:00
5f24e029af persist stores: make private/crypt support backing stores that aren't /nix/persist 2023-01-31 03:38:41 +00:00
98b542332b persist: crypt store: make paths overridable 2023-01-31 03:36:15 +00:00
70b62e9f76 persist stores: define the path for private at the host level 2023-01-31 03:29:53 +00:00
7c81df00df move nixcache.nix from modules -> hosts/modules 2023-01-30 11:25:46 +00:00
f288f34d1e nixpkgs-stable: 2023-01-28 -> 2023-01-29
```
• Updated input 'nixpkgs-stable':
    'github:nixos/nixpkgs/ce20e9ebe1903ea2ba1ab006ec63093020c761cb' (2023-01-28)
  → 'github:nixos/nixpkgs/22c4a7a4796a91c297a7e59078a84ec29515f86e' (2023-01-29)
```
2023-01-30 11:13:37 +00:00
854977c3aa move duplicity out of modules -> hosts 2023-01-30 11:11:42 +00:00
3653776399 cleanup: modules/users.nix: allow explicitly setting home, if needed 2023-01-30 11:06:47 +00:00
e4bff9b5ef refactor: persist: remove dead code 2023-01-30 10:51:41 +00:00
ec22c128e0 remove reference to /home/colin from modules/persist 2023-01-30 10:48:32 +00:00
77cc560052 use sane.user.persist instead of sane.persist.home 2023-01-30 10:35:03 +00:00
c1f3fc502d sane.users.<user>.persist: forward to sane.persist.home 2023-01-30 10:34:36 +00:00
4d3248d315 lib: mkTypedMerge: fix to work with recursive attrsets 2023-01-30 10:33:59 +00:00
45a1c07210 refactor: make use of sane.user.fs 2023-01-30 09:27:19 +00:00
a1a711190f refactor: make use of sane.user 2023-01-30 09:13:43 +00:00
ee9a2b320d add a sane.user option which is shorthand for the default user 2023-01-30 08:53:40 +00:00
870afec07e add which is shorthand to define a fs entry inside that user's home 2023-01-30 08:32:55 +00:00
5f8154e6ce phosh: add favorite apps to homescreen 2023-01-30 03:38:46 +00:00
0bc3b78a52 docs: document how to find dconf keys/values 2023-01-30 03:02:22 +00:00
5288be1822 phosh: statically configure a few dconf settings (experimental) 2023-01-30 03:00:55 +00:00
5b1113929a refactor: link /share/zsh in the zsh config instead of hosts/common/default.nix 2023-01-30 02:32:19 +00:00
216c812f7b remove config.sane.home-manager.enable as it was always set anyway 2023-01-30 02:10:12 +00:00
39effa15ad flake: remove unused home-manager input 2023-01-30 01:56:22 +00:00
f66de76b76 disable home-manager 2023-01-30 01:54:57 +00:00
427ee669c5 refactor: home.packages: move out of home-manager 2023-01-30 01:53:59 +00:00
8e81b5827c remove dead sane.home-manager.windowManager option 2023-01-30 01:51:36 +00:00
cb3e7623ae refactor: modules/gui/default.nix: fold into hosts/modules/gui/default.nix 2023-01-30 01:49:51 +00:00
a9cf619a14 plasma: move modules/gui/plasma.nix -> hosts/modules/gui/plasma.nix 2023-01-30 01:44:32 +00:00
02100ed1a2 plasma-mobile: move modules/gui/plasma-mobile.nix -> hosts/modules/gui/plasma-mobile.nix 2023-01-30 01:43:33 +00:00
ae22865099 gnome: move modules/gui/gnome.nix -> hosts/modules/gui/gnome.nix 2023-01-30 01:42:12 +00:00
6c85c6ecd8 handbrake: disable on aarch64-linux 2023-01-30 01:40:12 +00:00
161bbc1159 phosh: move out of modules/gui/phosh.nix -> hosts/modules/gui/phosh.nix 2023-01-30 01:39:20 +00:00
b94d0672cc flake update: nixpkgs-stable 2023-01-26 -> 2023-01-28; mobile-nixos
```
• Updated input 'mobile-nixos':
    'github:nixos/mobile-nixos/80ece5a61738fbf3b96fdda402ab2dfc74ee5cee' (2023-01-27)
  → 'github:nixos/mobile-nixos/7478a9ffad737486951186b66f6c5535dc5802e2' (2023-01-28)
• Updated input 'nixpkgs':
    'path:/nix/store/6jkp58bwsyshh7gz3shjlrn8a5zi3lk2-source/nixpatches?lastModified=1&narHash=sha256-arp7Uy7ct5ryTcmSY032eN7hr33i7D2XvjTRLliCFDc=' (1970-01-01)
  → 'path:/nix/store/xm7cg47bcix1s2cfmngvz0hjf0qqsgm1-source/nixpatches?lastModified=1&narHash=sha256-arp7Uy7ct5ryTcmSY032eN7hr33i7D2XvjTRLliCFDc=' (1970-01-01)
• Updated input 'nixpkgs-stable':
    'github:nixos/nixpkgs/def9e420d27c951026d57dc96ce0218c3131f412' (2023-01-26)
  → 'github:nixos/nixpkgs/ce20e9ebe1903ea2ba1ab006ec63093020c761cb' (2023-01-28)
```
2023-01-29 19:37:50 +00:00
768bc35940 sway: enable logging at both levels (base sway and layered sway) 2023-01-29 09:48:41 +00:00
9aca00c186 sway: re-enable the greeter 2023-01-29 08:13:09 +00:00
443100daa4 sway: move out of home-manager 2023-01-29 08:11:52 +00:00
ac25909a10 Merge branch 'wip/sway2' 2023-01-29 08:07:20 +00:00
ed70e045cb waybar: fix by specifying bars as list instead of attrs (wtf home-manager?) 2023-01-29 08:07:03 +00:00
e9172fe731 zsh: add an empty .zshrc to shutup prezto 2023-01-28 12:28:47 +00:00
54 changed files with 859 additions and 694 deletions

61
flake.lock generated
View File

@@ -15,35 +15,14 @@
"type": "github" "type": "github"
} }
}, },
"home-manager": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1667907331,
"narHash": "sha256-bHkAwkYlBjkupPUFcQjimNS8gxWSWjOTevEuwdnp5m0=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "6639e3a837fc5deb6f99554072789724997bc8e5",
"type": "github"
},
"original": {
"owner": "nix-community",
"ref": "release-22.05",
"repo": "home-manager",
"type": "github"
}
},
"mobile-nixos": { "mobile-nixos": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1674779092, "lastModified": 1674880620,
"narHash": "sha256-mFBD0Dvjf8tuxWtJhsCQ+8VYqI4fQeWjd/vfWsZiRRo=", "narHash": "sha256-JMALuC7xcoH/T66sKTVLuItHfOJBCWsNKpE49Qrvs80=",
"owner": "nixos", "owner": "nixos",
"repo": "mobile-nixos", "repo": "mobile-nixos",
"rev": "80ece5a61738fbf3b96fdda402ab2dfc74ee5cee", "rev": "7478a9ffad737486951186b66f6c5535dc5802e2",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -60,32 +39,16 @@
}, },
"locked": { "locked": {
"lastModified": 1, "lastModified": 1,
"narHash": "sha256-5pNu9Ph1LIBj5q9RWLV3r7daANjmd4u5y+MVq8vlfS4=", "narHash": "sha256-arp7Uy7ct5ryTcmSY032eN7hr33i7D2XvjTRLliCFDc=",
"path": "/nix/store/bjzsgw8zn4av0dv4sqyj7vxhi43na16y-source/nixpatches", "path": "/nix/store/jblp2g67p3wid2qarcyd8bzrbs9wg5lb-source/nixpatches",
"type": "path" "type": "path"
}, },
"original": { "original": {
"path": "/nix/store/bjzsgw8zn4av0dv4sqyj7vxhi43na16y-source/nixpatches", "path": "/nix/store/jblp2g67p3wid2qarcyd8bzrbs9wg5lb-source/nixpatches",
"type": "path" "type": "path"
} }
}, },
"nixpkgs-stable": { "nixpkgs-stable": {
"locked": {
"lastModified": 1674692158,
"narHash": "sha256-oqGpwVg4D+eMSgF7Th5Ve1ysCiH3H3g85vGJ3nvJsZQ=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "def9e420d27c951026d57dc96ce0218c3131f412",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-22.11",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-stable_2": {
"locked": { "locked": {
"lastModified": 1674352297, "lastModified": 1674352297,
"narHash": "sha256-OkAnJPrauEcUCrst4/3DKoQfUn2gXKuU6CFvhtMrLgg=", "narHash": "sha256-OkAnJPrauEcUCrst4/3DKoQfUn2gXKuU6CFvhtMrLgg=",
@@ -119,10 +82,8 @@
}, },
"root": { "root": {
"inputs": { "inputs": {
"home-manager": "home-manager",
"mobile-nixos": "mobile-nixos", "mobile-nixos": "mobile-nixos",
"nixpkgs": "nixpkgs", "nixpkgs": "nixpkgs",
"nixpkgs-stable": "nixpkgs-stable",
"nixpkgs-unpatched": "nixpkgs-unpatched", "nixpkgs-unpatched": "nixpkgs-unpatched",
"sops-nix": "sops-nix", "sops-nix": "sops-nix",
"uninsane-dot-org": "uninsane-dot-org" "uninsane-dot-org": "uninsane-dot-org"
@@ -133,7 +94,7 @@
"nixpkgs": [ "nixpkgs": [
"nixpkgs" "nixpkgs"
], ],
"nixpkgs-stable": "nixpkgs-stable_2" "nixpkgs-stable": "nixpkgs-stable"
}, },
"locked": { "locked": {
"lastModified": 1674546403, "lastModified": 1674546403,
@@ -157,11 +118,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1666870107, "lastModified": 1675131883,
"narHash": "sha256-b9eXZxSwhzdJI5uQgfrMhu4SY2POrPkinUg7F5gQVYo=", "narHash": "sha256-yBgJDG72YqIr1bltasqHD1E/kHc9uRFgDjxDmy6kI8M=",
"ref": "refs/heads/master", "ref": "refs/heads/master",
"rev": "80c6ec95bd430e29d231cf745f19279bb76fb382", "rev": "b099c24091cc192abf3997b94342d4b31cc5757b",
"revCount": 164, "revCount": 170,
"type": "git", "type": "git",
"url": "https://git.uninsane.org/colin/uninsane" "url": "https://git.uninsane.org/colin/uninsane"
}, },

View File

@@ -19,7 +19,7 @@
# 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> # <https://github.com/nixos/nixpkgs/tree/nixos-22.11>
nixpkgs-stable.url = "github:nixos/nixpkgs?ref=nixos-22.11"; # nixpkgs-stable.url = "github:nixos/nixpkgs?ref=nixos-22.11";
# <https://github.com/nixos/nixpkgs/tree/nixos-unstable> # <https://github.com/nixos/nixpkgs/tree/nixos-unstable>
nixpkgs-unpatched.url = "github:nixos/nixpkgs?ref=nixos-unstable"; nixpkgs-unpatched.url = "github:nixos/nixpkgs?ref=nixos-unstable";
@@ -32,11 +32,6 @@
url = "github:nixos/mobile-nixos"; url = "github:nixos/mobile-nixos";
flake = false; flake = false;
}; };
home-manager = {
# <https://github.com/nix-community/home-manager/tree/release-22.05>
url = "github:nix-community/home-manager?ref=release-22.05";
inputs.nixpkgs.follows = "nixpkgs";
};
sops-nix = { sops-nix = {
# <https://github.com/Mic92/sops-nix> # <https://github.com/Mic92/sops-nix>
url = "github:Mic92/sops-nix"; url = "github:Mic92/sops-nix";
@@ -51,13 +46,12 @@
outputs = { outputs = {
self, self,
nixpkgs, nixpkgs,
nixpkgs-stable,
nixpkgs-unpatched, nixpkgs-unpatched,
mobile-nixos, mobile-nixos,
home-manager,
sops-nix, sops-nix,
uninsane-dot-org uninsane-dot-org,
}: ...
}@inputs:
let let
nixpkgsCompiledBy = local: nixpkgs.legacyPackages."${local}"; nixpkgsCompiledBy = local: nixpkgs.legacyPackages."${local}";
@@ -123,9 +117,12 @@
pins = import ./overlays/pins.nix; # TODO: move to `nixpatches/` input pins = import ./overlays/pins.nix; # TODO: move to `nixpatches/` input
passthru = passthru =
let let
stable = next: prev: { stable =
stable = nixpkgs-stable.legacyPackages."${prev.stdenv.hostPlatform.system}"; if inputs ? "nixpkgs-stable" then (
}; next: prev: {
stable = inputs.nixpkgs-stable.legacyPackages."${prev.stdenv.hostPlatform.system}";
}
) else (next: 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;
in in
@@ -138,7 +135,6 @@
sane = import ./modules; sane = import ./modules;
passthru = { ... }: { passthru = { ... }: {
imports = [ imports = [
home-manager.nixosModule
sops-nix.nixosModules.sops sops-nix.nixosModules.sops
]; ];
}; };

View File

@@ -4,8 +4,6 @@
./fs.nix ./fs.nix
]; ];
# sane.packages.enableDevPkgs = true;
sane.roles.client = true; sane.roles.client = true;
sane.services.wg-home.enable = true; sane.services.wg-home.enable = true;
sane.services.wg-home.ip = config.sane.hosts.by-name."desko".wg-home.ip; sane.services.wg-home.ip = config.sane.hosts.by-name."desko".wg-home.ip;
@@ -54,7 +52,7 @@
remotePlay.openFirewall = true; # Open ports in the firewall for Steam Remote Play remotePlay.openFirewall = true; # Open ports in the firewall for Steam Remote Play
dedicatedServer.openFirewall = true; # Open ports in the firewall for Source Dedicated Server dedicatedServer.openFirewall = true; # Open ports in the firewall for Source Dedicated Server
}; };
sane.persist.home.plaintext = [ sane.user.persist.plaintext = [
".steam" ".steam"
".local/share/Steam" ".local/share/Steam"
]; ];

View File

@@ -8,9 +8,7 @@
sane.services.wg-home.enable = true; sane.services.wg-home.enable = true;
sane.services.wg-home.ip = config.sane.hosts.by-name."lappy".wg-home.ip; sane.services.wg-home.ip = config.sane.hosts.by-name."lappy".wg-home.ip;
# sane.packages.enableDevPkgs = true; # sane.guest.enable = true;
# sane.users.guest.enable = true;
sane.gui.sway.enable = true; sane.gui.sway.enable = true;
sane.persist.enable = true; sane.persist.enable = true;
sane.nixcache.enable = true; sane.nixcache.enable = true;

View File

@@ -37,14 +37,16 @@
# addons.sideberry.enable = false; # addons.sideberry.enable = false;
}; };
sane.persist.home.plaintext = [ sane.user.persist.plaintext = [
".config/pulse" # persist pulseaudio volume ".config/pulse" # persist pulseaudio volume
]; ];
# sane.packages.enableGuiPkgs = false; # XXX faster builds/imaging for debugging sane.programs."pkgs.plasma5Packages.konsole" = {
sane.packages.extraUserPkgs = [ # more reliable terminal
pkgs.plasma5Packages.konsole # terminal # TODO: move to gui/phosh
]; package = pkgs.plasma5Packages.konsole;
enableFor.user.colin = true;
};
sane.nixcache.enable = true; sane.nixcache.enable = true;
sane.persist.enable = true; sane.persist.enable = true;

View File

@@ -8,12 +8,13 @@
./services ./services
]; ];
sane.packages.extraUserPkgs = with pkgs; [ sane.programs = {
# for administering services # for administering services
freshrss freshrss.enableFor.user.colin = true;
matrix-synapse matrix-synapse.enableFor.user.colin = true;
signaldctl signaldctl.enableFor.user.colin = true;
]; };
sane.persist.enable = true; sane.persist.enable = true;
sane.services.dyn-dns.enable = true; sane.services.dyn-dns.enable = true;
sane.services.wg-home.enable = true; sane.services.wg-home.enable = true;

View File

@@ -1,3 +1,6 @@
# DOCS:
# - dovecot config: <https://doc.dovecot.org/configuration_manual/>
{ config, lib, ... }: { config, lib, ... }:
let let
@@ -143,6 +146,25 @@ in
# inspired by https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/ # inspired by https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/
services.dovecot2.enable = true; services.dovecot2.enable = true;
services.dovecot2.mailboxes = {
# special-purpose mailboxes: "All" "Archive" "Drafts" "Flagged" "Junk" "Sent" "Trash"
# RFC6154 describes these special mailboxes: https://www.ietf.org/rfc/rfc6154.html
# how these boxes are treated is 100% up to the client and server to decide.
# client behavior:
# iOS
# - Drafts: ?
# - Sent: works
# - Trash: works
# aerc
# - Drafts: works
# - Sent: works
# - Trash: no; deleted messages are actually deleted
# use `:move trash` instead
# Sent mailbox: all sent messages are copied to it. unclear if this happens server-side or client-side.
Drafts = { specialUse = "Drafts"; auto = "create"; };
Sent = { specialUse = "Sent"; auto = "create"; };
Trash = { specialUse = "Trash"; auto = "create"; };
};
services.dovecot2.sslServerCert = "/var/lib/acme/imap.uninsane.org/fullchain.pem"; services.dovecot2.sslServerCert = "/var/lib/acme/imap.uninsane.org/fullchain.pem";
services.dovecot2.sslServerKey = "/var/lib/acme/imap.uninsane.org/key.pem"; services.dovecot2.sslServerKey = "/var/lib/acme/imap.uninsane.org/key.pem";
services.dovecot2.enablePAM = false; services.dovecot2.enablePAM = false;

View File

@@ -10,25 +10,17 @@
./ids.nix ./ids.nix
./machine-id.nix ./machine-id.nix
./net.nix ./net.nix
./persist.nix
./programs.nix
./secrets.nix ./secrets.nix
./ssh.nix ./ssh.nix
./users.nix ./users.nix
./vpn.nix ./vpn.nix
]; ];
sane.home-manager.enable = true;
sane.nixcache.enable-trusted-keys = true; sane.nixcache.enable-trusted-keys = true;
sane.packages.enableConsolePkgs = true; sane.programs.sysadminUtils.enableFor.system = true;
sane.packages.enableSystemPkgs = true; sane.programs.consoleUtils.enableFor.user.colin = true;
sane.persist.sys.plaintext = [
"/var/log"
"/var/backup" # for e.g. postgres dumps
# TODO: move elsewhere
"/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.
];
# some services which use private directories error if the parent (/var/lib/private) isn't 700. # 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"; sane.fs."/var/lib/private".dir.acl.mode = "0700";
@@ -75,8 +67,20 @@
# NIXOS_OZONE_WL = "1"; # NIXOS_OZONE_WL = "1";
# LIBGL_ALWAYS_SOFTWARE = "1"; # LIBGL_ALWAYS_SOFTWARE = "1";
}; };
# enable zsh completions
environment.pathsToLink = [ "/share/zsh" ]; # dconf docs: <https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/desktop_migration_and_administration_guide/profiles>
# find keys/values with `dconf dump /`
programs.dconf.enable = true;
programs.dconf.packages = [
(pkgs.writeTextFile {
name = "dconf-user-profile";
destination = "/etc/dconf/profile/user";
text = ''
user-db:user
system-db:site
'';
})
];
# 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,12 +1,11 @@
# Terminal UI mail client # Terminal UI mail client
{ config, lib, sane-lib, ... }: { config, sane-lib, ... }:
lib.mkIf config.sane.home-manager.enable
{ {
sops.secrets."aerc_accounts" = { sops.secrets."aerc_accounts" = {
owner = config.users.users.colin.name; owner = config.users.users.colin.name;
sopsFile = ../../../secrets/universal/aerc_accounts.conf; sopsFile = ../../../secrets/universal/aerc_accounts.conf;
format = "binary"; format = "binary";
}; };
sane.fs."/home/colin/.config/aerc/accounts.conf" = sane-lib.fs.wantedSymlinkTo config.sops.secrets.aerc_accounts.path; sane.user.fs.".config/aerc/accounts.conf" = sane-lib.fs.wantedSymlinkTo config.sops.secrets.aerc_accounts.path;
} }

View File

@@ -145,7 +145,12 @@ in
}; };
}; };
config = lib.mkIf config.sane.home-manager.enable { config = {
sane.programs.web-browser = {
inherit package;
# TODO: define the persistence & fs config here
};
sane.programs.guiApps.suggestedPrograms = [ "web-browser" ];
# uBlock filter list configuration. # uBlock filter list configuration.
# specifically, enable the GDPR cookie prompt blocker. # specifically, enable the GDPR cookie prompt blocker.
@@ -155,7 +160,7 @@ in
# the specific attribute path is found via scraping ublock code here: # the specific attribute path is found via scraping ublock code here:
# - <https://github.com/gorhill/uBlock/blob/master/src/js/storage.js> # - <https://github.com/gorhill/uBlock/blob/master/src/js/storage.js>
# - <https://github.com/gorhill/uBlock/blob/master/assets/assets.json> # - <https://github.com/gorhill/uBlock/blob/master/assets/assets.json>
sane.fs."/home/colin/${cfg.browser.dotDir}/managed-storage/uBlock0@raymondhill.net.json" = sane-lib.fs.wantedText '' sane.user.fs."${cfg.browser.dotDir}/managed-storage/uBlock0@raymondhill.net.json" = sane-lib.fs.wantedText ''
{ {
"name": "uBlock0@raymondhill.net", "name": "uBlock0@raymondhill.net",
"description": "ignored", "description": "ignored",
@@ -165,26 +170,24 @@ in
} }
} }
''; '';
sane.fs."/home/colin/${cfg.browser.dotDir}/${cfg.browser.libName}.overrides.cfg" = sane-lib.fs.wantedText '' sane.user.fs."${cfg.browser.dotDir}/${cfg.browser.libName}.overrides.cfg" = sane-lib.fs.wantedText ''
// 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.
// see: <https://librewolf.net/docs/faq/#im-getting-sec_error_ocsp_server_error-what-can-i-do> // see: <https://librewolf.net/docs/faq/#im-getting-sec_error_ocsp_server_error-what-can-i-do>
defaultPref("security.OCSP.require", false); defaultPref("security.OCSP.require", false);
''; '';
sane.packages.extraGuiPkgs = [ package ];
# 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.persist.home.byPath."${cfg.browser.cacheDir}" = lib.mkIf (cfg.persistCache != null) { sane.user.persist.byPath."${cfg.browser.cacheDir}" = lib.mkIf (cfg.persistCache != null) {
store = cfg.persistCache; store = cfg.persistCache;
}; };
sane.persist.home.byPath."${cfg.browser.dotDir}/default" = lib.mkIf (cfg.persistData != null) { sane.user.persist.byPath."${cfg.browser.dotDir}/default" = lib.mkIf (cfg.persistData != null) {
store = cfg.persistData; store = cfg.persistData;
}; };
sane.fs."/home/colin/${cfg.browser.dotDir}/default" = sane-lib.fs.wantedDir; sane.user.fs."${cfg.browser.dotDir}/default" = sane-lib.fs.wantedDir;
# instruct Firefox to put the profile in a predictable directory (so we can do things like persist just it). # instruct Firefox to put the profile in a predictable directory (so we can do things like persist just it).
# XXX: the directory *must* exist, even if empty; Firefox will not create the directory itself. # XXX: the directory *must* exist, even if empty; Firefox will not create the directory itself.
sane.fs."/home/colin/${cfg.browser.dotDir}/profiles.ini" = sane-lib.fs.wantedText '' sane.user.fs."${cfg.browser.dotDir}/profiles.ini" = sane-lib.fs.wantedText ''
[Profile0] [Profile0]
Name=default Name=default
IsRelative=1 IsRelative=1

View File

@@ -6,7 +6,7 @@ let
all-feeds = config.sane.feeds; all-feeds = config.sane.feeds;
wanted-feeds = feeds.filterByFormat ["text" "image"] all-feeds; wanted-feeds = feeds.filterByFormat ["text" "image"] all-feeds;
in { in {
sane.fs."/home/colin/.config/org.gabmus.gfeeds.json" = sane-lib.fs.wantedText ( sane.user.fs.".config/org.gabmus.gfeeds.json" = sane-lib.fs.wantedText (
builtins.toJSON { builtins.toJSON {
# feed format is a map from URL to a dict, # feed format is a map from URL to a dict,
# with dict["tags"] a list of string tags. # with dict["tags"] a list of string tags.

View File

@@ -1,11 +1,10 @@
{ config, lib, pkgs, sane-lib, ... }: { lib, pkgs, sane-lib, ... }:
let let
mkCfg = lib.generators.toINI { }; mkCfg = lib.generators.toINI { };
in in
lib.mkIf config.sane.home-manager.enable
{ {
sane.fs."/home/colin/.config/git/config" = sane-lib.fs.wantedText (mkCfg { sane.user.fs.".config/git/config" = sane-lib.fs.wantedText (mkCfg {
user.name = "Colin"; user.name = "Colin";
user.email = "colin@uninsane.org"; user.email = "colin@uninsane.org";
alias.co = "checkout"; alias.co = "checkout";

View File

@@ -6,7 +6,7 @@ let
all-feeds = config.sane.feeds; all-feeds = config.sane.feeds;
wanted-feeds = feeds.filterByFormat ["podcast"] all-feeds; wanted-feeds = feeds.filterByFormat ["podcast"] all-feeds;
in { in {
sane.fs."/home/colin/.config/gpodderFeeds.opml" = sane-lib.fs.wantedText ( sane.user.fs.".config/gpodderFeeds.opml" = sane-lib.fs.wantedText (
feeds.feedsToOpml wanted-feeds feeds.feedsToOpml wanted-feeds
); );
} }

View File

@@ -1,11 +1,11 @@
{ config, lib, sane-lib, ... }: { config, sane-lib, ... }:
lib.mkIf config.sane.home-manager.enable
{ {
sane.persist.home.private = [ ".local/share/keyrings" ]; sane.user.persist.private = [ ".local/share/keyrings" ];
sane.fs."/home/colin/private/.local/share/keyrings/default" = { sane.user.fs."private/.local/share/keyrings/default" = {
generated.script.script = builtins.readFile ../../../scripts/init-keyring; 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 ]; wantedBy = [ config.sane.fs."/home/colin/private".unit ];
}; };
} }

View File

@@ -1,8 +1,7 @@
{ config, lib, pkgs, sane-lib, ... }: { pkgs, sane-lib, ... }:
lib.mkIf config.sane.home-manager.enable
{ {
sane.fs."/home/colin/.config/kitty/kitty.conf" = sane-lib.fs.wantedText '' sane.user.fs.".config/kitty/kitty.conf" = sane-lib.fs.wantedText ''
# 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

View File

@@ -1,9 +1,8 @@
{ config, lib, sane-lib, ... }: { sane-lib, ... }:
lib.mkIf config.sane.home-manager.enable
{ {
# libreoffice: disable first-run stuff # libreoffice: disable first-run stuff
sane.fs."/home/colin/.config/libreoffice/4/user/registrymodifications.xcu" = sane-lib.fs.wantedText '' sane.user.fs.".config/libreoffice/4/user/registrymodifications.xcu" = sane-lib.fs.wantedText ''
<?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>

View File

@@ -1,4 +1,4 @@
{ config, lib, sane-lib, ...}: { config, sane-lib, ...}:
let let
www = config.sane.web-browser.browser.desktop; www = config.sane.web-browser.browser.desktop;
@@ -9,7 +9,6 @@ let
# audio = "mpv.desktop"; # audio = "mpv.desktop";
audio = "vlc.desktop"; audio = "vlc.desktop";
in in
lib.mkIf config.sane.home-manager.enable
{ {
# the xdg mime type for a file can be found with: # the xdg mime type for a file can be found with:

View File

@@ -1,9 +1,8 @@
{ config, lib, sane-lib, ... }: { sane-lib, ... }:
lib.mkIf config.sane.home-manager.enable
{ {
# format is <key>=%<length>%<value> # format is <key>=%<length>%<value>
sane.fs."/home/colin/.config/mpv/mpv.conf" = sane-lib.fs.wantedText '' sane.user.fs.".config/mpv/mpv.conf" = sane-lib.fs.wantedText ''
save-position-on-quit=%3%yes save-position-on-quit=%3%yes
keep-open=%3%yes keep-open=%3%yes
''; '';

View File

@@ -1,4 +1,4 @@
{ config, lib, pkgs, ... }: { lib, pkgs, ... }:
let let
inherit (builtins) map; inherit (builtins) map;
@@ -70,10 +70,9 @@ let
plugin-config-tex = 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
lib.mkIf config.sane.home-manager.enable
{ {
# private because there could be sensitive things in the swap # private because there could be sensitive things in the swap
sane.persist.home.private = [ ".cache/vim-swap" ]; sane.user.persist.private = [ ".cache/vim-swap" ];
programs.neovim = { programs.neovim = {
# neovim: https://github.com/neovim/neovim # neovim: https://github.com/neovim/neovim

View File

@@ -6,7 +6,7 @@ let
all-feeds = config.sane.feeds; all-feeds = config.sane.feeds;
wanted-feeds = feeds.filterByFormat ["text" "image"] all-feeds; wanted-feeds = feeds.filterByFormat ["text" "image"] all-feeds;
in { in {
sane.fs."/home/colin/.config/newsflashFeeds.opml" = sane-lib.fs.wantedText ( sane.user.fs.".config/newsflashFeeds.opml" = sane-lib.fs.wantedText (
feeds.feedsToOpml wanted-feeds feeds.feedsToOpml wanted-feeds
); );
} }

View File

@@ -4,9 +4,9 @@
{ pkgs, sane-lib, ... }: { pkgs, sane-lib, ... }:
{ {
sane.persist.home.plaintext = [ ".local/state/splatmoji" ]; sane.user.persist.plaintext = [ ".local/state/splatmoji" ];
sane.fs."/home/colin/.config/splatmoji/splatmoji.config" = sane-lib.fs.wantedText '' sane.user.fs.".config/splatmoji/splatmoji.config" = sane-lib.fs.wantedText ''
history_file=/home/colin/.local/state/splatmoji/history history_file=~/.local/state/splatmoji/history
history_length=5 history_length=5
# TODO: wayland equiv # TODO: wayland equiv
paste_command=xdotool key ctrl+v paste_command=xdotool key ctrl+v

View File

@@ -1,4 +1,4 @@
{ config, lib, pkgs, sane-lib, ... }: { config, lib, sane-lib, ... }:
with lib; with lib;
let let
@@ -9,11 +9,12 @@ let
"\n" "\n"
(map (k: k.asHostKey) host-keys) (map (k: k.asHostKey) host-keys)
; ;
in lib.mkIf config.sane.home-manager.enable { in
{
# ssh key is stored in private storage # ssh key is stored in private storage
sane.persist.home.private = [ ".ssh/id_ed25519" ]; sane.user.persist.private = [ ".ssh/id_ed25519" ];
sane.fs."/home/colin/.ssh/id_ed25519.pub" = sane-lib.fs.wantedText user-pubkey; sane.user.fs.".ssh/id_ed25519.pub" = sane-lib.fs.wantedText user-pubkey;
sane.fs."/home/colin/.ssh/known_hosts" = sane-lib.fs.wantedText known-hosts-text; sane.user.fs.".ssh/known_hosts" = sane-lib.fs.wantedText known-hosts-text;
users.users.colin.openssh.authorizedKeys.keys = users.users.colin.openssh.authorizedKeys.keys =
let let

View File

@@ -1,6 +1,5 @@
{ config, lib, sane-lib, ... }: { config, sane-lib, ... }:
lib.mkIf config.sane.home-manager.enable
{ {
# TODO: this should only be shipped on gui platforms # TODO: this should only be shipped on gui platforms
sops.secrets."sublime_music_config" = { sops.secrets."sublime_music_config" = {
@@ -8,5 +7,5 @@ lib.mkIf config.sane.home-manager.enable
sopsFile = ../../../secrets/universal/sublime_music_config.json.bin; sopsFile = ../../../secrets/universal/sublime_music_config.json.bin;
format = "binary"; format = "binary";
}; };
sane.fs."/home/colin/.config/sublime-music/config.json" = sane-lib.fs.wantedSymlinkTo config.sops.secrets.sublime_music_config.path; sane.user.fs.".config/sublime-music/config.json" = sane-lib.fs.wantedSymlinkTo config.sops.secrets.sublime_music_config.path;
} }

View File

@@ -8,9 +8,8 @@ let
builtins.map (feed: feed.url) wanted-feeds builtins.map (feed: feed.url) wanted-feeds
); );
in in
lib.mkIf config.sane.home-manager.enable
{ {
sane.fs."/home/colin/.config/vlc/vlcrc" = sane-lib.fs.wantedText '' sane.user.fs.".config/vlc/vlcrc" = sane-lib.fs.wantedText ''
[podcast] [podcast]
podcast-urls=${podcast-urls} podcast-urls=${podcast-urls}
[core] [core]

View File

@@ -1,10 +1,9 @@
{ config, lib, sane-lib, ...}: { lib, sane-lib, ...}:
lib.mkIf config.sane.home-manager.enable
{ {
# 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.fs."/home/colin/.config/user-dirs.dirs" = sane-lib.fs.wantedText '' 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"
@@ -17,5 +16,5 @@ lib.mkIf config.sane.home-manager.enable
# 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.fs."/home/colin/.config/user-dirs.conf" = sane-lib.fs.wantedText "enabled=False"; sane.user.fs.".config/user-dirs.conf" = sane-lib.fs.wantedText "enabled=False";
} }

View File

@@ -1,4 +1,4 @@
{ config, lib, pkgs, sane-lib, ... }: { pkgs, sane-lib, ... }:
let let
# powerlevel10k prompt config # powerlevel10k prompt config
@@ -25,9 +25,8 @@ let
source ${pkgs.zsh-prezto}/share/zsh-prezto/init.zsh source ${pkgs.zsh-prezto}/share/zsh-prezto/init.zsh
''; '';
in in
lib.mkIf config.sane.home-manager.enable
{ {
sane.persist.home.plaintext = [ sane.user.persist.plaintext = [
# we don't need to full zsh dir -- just the history file -- # we don't need to full zsh dir -- just the history file --
# but zsh will sometimes backup the history file and we get fewer errors if we do proper mounts instead of symlinks. # but zsh will sometimes backup the history file and we get fewer errors if we do proper mounts instead of symlinks.
# TODO: should be private? # TODO: should be private?
@@ -37,7 +36,10 @@ lib.mkIf config.sane.home-manager.enable
]; ];
# zsh/prezto complains if zshrc doesn't exist; but it does allow an "empty" file. # zsh/prezto complains if zshrc doesn't exist; but it does allow an "empty" file.
sane.fs."/home/colin/.config/zsh/.zshrc" = sane-lib.fs.wantedText "# "; sane.user.fs.".config/zsh/.zshrc" = sane-lib.fs.wantedText "# ";
# enable zsh completions
environment.pathsToLink = [ "/share/zsh" ];
programs.zsh = { programs.zsh = {
enable = true; enable = true;
@@ -105,7 +107,7 @@ lib.mkIf config.sane.home-manager.enable
# prezto = oh-my-zsh fork; controls prompt, auto-completion, etc. # prezto = oh-my-zsh fork; controls prompt, auto-completion, etc.
# see: https://github.com/sorin-ionescu/prezto # see: https://github.com/sorin-ionescu/prezto
# i believe this file is auto-sourced by the prezto init.zsh script. # i believe this file is auto-sourced by the prezto init.zsh script.
sane.fs."/home/colin/.config/zsh/.zpreztorc" = sane-lib.fs.wantedText '' sane.user.fs.".config/zsh/.zpreztorc" = sane-lib.fs.wantedText ''
zstyle ':prezto:*:*' color 'yes' zstyle ':prezto:*:*' color 'yes'
# modules (they ship with prezto): # modules (they ship with prezto):

16
hosts/common/persist.nix Normal file
View File

@@ -0,0 +1,16 @@
{ ... }:
{
sane.persist.stores.private.origin = "/home/colin/private";
# store /home/colin/a/b in /home/private/a/b instead of /home/private/home/colin/a/b
sane.persist.stores.private.prefix = "/home/colin";
sane.persist.sys.plaintext = [
"/var/log"
"/var/backup" # for e.g. postgres dumps
# TODO: move elsewhere
"/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.
];
}

329
hosts/common/programs.nix Normal file
View File

@@ -0,0 +1,329 @@
{ lib, pkgs, ... }:
let
inherit (builtins) attrNames concatLists;
inherit (lib) mapAttrs mapAttrsToList mkDefault mkMerge optional;
sysadminPkgs = {
inherit (pkgs // {
# XXX can't `inherit` a nested attr, so we move them to the toplevel
"cacert.unbundled" = pkgs.cacert.unbundled;
})
btrfs-progs
"cacert.unbundled" # some services require unbundled /etc/ssl/certs
cryptsetup
dig
efibootmgr
fatresize
fd
file
gawk
git
gptfdisk
hdparm
htop
iftop
inetutils # for telnet
iotop
iptables
jq
killall
lsof
nano
netcat
nethogs
nmap
openssl
parted
pciutils
powertop
pstree
ripgrep
screen
smartmontools
socat
strace
tcpdump
tree
usbutils
wget
;
};
consolePkgs = {
inherit (pkgs)
backblaze-b2
cdrtools
dmidecode
duplicity
efivar
flashrom
fwupd
ghostscript # TODO: imagemagick wrapper should add gs to PATH
gnupg
gocryptfs
gopass
gopass-jsonapi
ifuse
imagemagick
ipfs
kitty # TODO: move to GUI, but `ssh servo` from kitty sets `TERM=xterm-kitty` in the remove and breaks things
libimobiledevice
libsecret # for managing user keyrings
lm_sensors # for sensors-detect
lshw
ffmpeg
memtester
networkmanager
nixpkgs-review
# nixos-generators
# nettools
nmon
oathToolkit # for oathtool
# ponymix
pulsemixer
python3
rsync
# python3Packages.eyeD3 # music tagging
sane-scripts
sequoia
snapper
sops
sox
speedtest-cli
sqlite # to debug sqlite3 databases
ssh-to-age
sudo
# tageditor # music tagging
unar
visidata
w3m
wireguard-tools
# youtube-dl
yt-dlp
;
};
guiPkgs = {
inherit (pkgs // (with pkgs; {
# XXX can't `inherit` a nested attr, so we move them to the toplevel
# TODO: could use some "flatten attrs" helper instead
"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;
"libsForQt5.plasmatube" = libsForQt5.plasmatube;
}))
aerc # email client
audacity
celluloid # mpv frontend
chromium
clinfo
dino
electrum
element-desktop
emote
evince # works on phosh
# { pkg = fluffychat-moby; dir = [ ".local/share/chat.fluffy.fluffychat" ]; } # TODO: ship normal fluffychat on non-moby?
foliate # e-book reader
font-manager
# XXX by default fractal stores its state in ~/.local/share/<UUID>.
# after logging in, manually change ~/.local/share/keyrings/... to point it to some predictable subdir.
# then reboot (so that libsecret daemon re-loads the keyring...?)
# { pkg = fractal-latest; private = [ ".local/share/fractal" ]; }
# { pkg = fractal-next; private = [ ".local/share/fractal" ]; }
gajim # XMPP client
gimp # broken on phosh
"gnome.cheese"
"gnome.dconf-editor"
gnome-feeds # RSS reader (with claimed mobile support)
"gnome.file-roller"
"gnome.gnome-disk-utility"
"gnome.gnome-maps" # works on phosh
"gnome.nautilus"
# gnome-podcasts
"gnome.gnome-system-monitor"
"gnome.gnome-terminal" # works on phosh
"gnome.gnome-weather"
gpodder-configured
gthumb
inkscape
kdenlive
kid3 # audio tagging
krita
libreoffice-fresh # XXX colin: maybe don't want this on mobile
lollypop
mpv
networkmanagerapplet
newsflash
nheko
obsidian
pavucontrol
# picard # music tagging
playerctl
"libsForQt5.plasmatube" # Youtube player
soundconverter
# sublime music persists any downloaded albums here.
# it doesn't obey a conventional ~/Music/{Artist}/{Album}/{Track} notation, so no symlinking
# config (e.g. server connection details) is persisted in ~/.config/sublime-music/config.json
# possible to pass config as a CLI arg (sublime-music -c config.json)
# { pkg = sublime-music; dir = [ ".local/share/sublime-music" ]; }
sublime-music-mobile
tdesktop # broken on phosh
tokodon
vlc
# pleroma client (Electron). input is broken on phosh.
whalebird
xdg-utils # for xdg-open
xterm # broken on phosh
;
};
x86GuiPkgs = {
inherit (pkgs)
discord
# kaiteki # Pleroma client
# gnome.zenity # for kaiteki (it will use qarma, kdialog, or zenity)
# gpt2tc # XXX: unreliable mirror
# TODO(unpin): handbrake is broken on aarch64-linux 2023/01/29
handbrake
logseq
losslesscut-bin
makemkv
monero-gui
signal-desktop
spotify
tor-browser-bundle-bin
zecwallet-lite
;
};
# define -- but don't enable -- the packages in some attrset.
# use `mkDefault` for the package here so we can customize some of them further down this file
declarePkgs = pkgsAsAttrs: mapAttrs (_n: p: {
package = mkDefault p;
}) pkgsAsAttrs;
in
{
config = {
sane.programs = mkMerge [
(declarePkgs sysadminPkgs)
(declarePkgs consolePkgs)
(declarePkgs guiPkgs)
(declarePkgs x86GuiPkgs)
{
# link the various package sets into their own meta packages
sysadminUtils = {
package = null;
suggestedPrograms = attrNames sysadminPkgs;
};
consoleUtils = {
package = null;
suggestedPrograms = attrNames consolePkgs;
};
guiApps = {
package = null;
suggestedPrograms = (attrNames guiPkgs)
++ optional (pkgs.system == "x86_64-linux") "x86GuiApps";
};
x86GuiApps = {
package = null;
suggestedPrograms = attrNames x86GuiPkgs;
};
}
{
# nontrivial package definitions
imagemagick.package = pkgs.imagemagick.override {
ghostscriptSupport = true;
};
dino.private = [ ".local/share/dino" ];
# creds, but also 200 MB of node modules, etc
discord = {
package = pkgs.discord.override {
# XXX 2022-07-31: fix to allow links to open in default web-browser:
# https://github.com/NixOS/nixpkgs/issues/78961
nss = pkgs.nss_latest;
};
private = [ ".config/discord" ];
};
# creds/session keys, etc
element-desktop.private = [ ".config/Element" ];
# `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.
# TODO: package [smile](https://github.com/mijorus/smile) for probably a better mobile experience.
emote.dir = [ ".local/share/Emote" ];
# XXX: we preserve the whole thing because if we only preserve gPodder/Downloads
# then startup is SLOW during feed import, and we might end up with zombie eps in the dl dir.
gpodder-configured.dir = [ "gPodder" ];
# actual monero blockchain (not wallet/etc; safe to delete, just slow to regenerate)
# XXX: is it really safe to persist this? it doesn't have info that could de-anonymize if captured?
monero-gui.dir = [ ".bitmonero" ];
mpv.dir = [ ".config/mpv/watch_later" ];
# not strictly necessary, but allows caching articles; offline use, etc.
newsflash.dir = [ ".local/share/news-flash" ];
nheko.private = [
".config/nheko" # config file (including client token)
".cache/nheko" # media cache
".local/share/nheko" # per-account state database
];
# settings (electron app)
obsidian.dir = [ ".config/obsidian" ];
# creds, media
signal-desktop.private = [ ".config/Signal" ];
# creds, widevine .so download. TODO: could easily manage these statically.
spotify.dir = [ ".config/spotify" ];
# sublime music persists any downloaded albums here.
# it doesn't obey a conventional ~/Music/{Artist}/{Album}/{Track} notation, so no symlinking
# config (e.g. server connection details) is persisted in ~/.config/sublime-music/config.json
# possible to pass config as a CLI arg (sublime-music -c config.json)
# { pkg = sublime-music; dir = [ ".local/share/sublime-music" ]; }
sublime-music-mobile.dir = [ ".local/share/sublime-music" ];
tdesktop.private = [ ".local/share/TelegramDesktop" ];
tokodon.private = [ ".cache/KDE/tokodon" ];
# hardenedMalloc solves a crash at startup
# TODO 2023/02/02: is this safe to remove yet?
tor-browser-bundle-bin.package = pkgs.tor-browser-bundle-bin.override {
useHardenedMalloc = false;
};
# vlc remembers play position in ~/.config/vlc/vlc-qt-interface.conf
vlc.dir = [ ".config/vlc" ];
whalebird.private = [ ".config/Whalebird" ];
# zcash coins. safe to delete, just slow to regenerate (10-60 minutes)
zecwallet-lite.private = [ ".zcash" ];
}
];
# XXX: this might not be necessary. try removing this and cacert.unbundled (servo)?
environment.etc."ssl/certs".source = "${pkgs.cacert.unbundled}/etc/ssl/certs/*";
};
}

View File

@@ -3,12 +3,12 @@
# installer docs: https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/profiles/installation-device.nix # installer docs: https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/profiles/installation-device.nix
with lib; with lib;
let let
cfg = config.sane.users; cfg = config.sane.guest;
fs = sane-lib.fs; fs = sane-lib.fs;
in in
{ {
options = { options = {
sane.users.guest.enable = mkOption { sane.guest.enable = mkOption {
default = false; default = false;
type = types.bool; type = types.bool;
}; };
@@ -66,6 +66,7 @@ in
security.pam.mount.enable = true; security.pam.mount.enable = true;
sane.users.colin.default = true;
# ensure ~ perms are known to sane.fs module. # ensure ~ perms are known to sane.fs module.
# TODO: this is generic enough to be lifted up into sane.fs itself. # TODO: this is generic enough to be lifted up into sane.fs itself.
sane.fs."/home/colin".dir.acl = { sane.fs."/home/colin".dir.acl = {
@@ -74,7 +75,7 @@ in
mode = config.users.users.colin.homeMode; mode = config.users.users.colin.homeMode;
}; };
sane.persist.home.plaintext = [ sane.user.persist.plaintext = [
"archive" "archive"
"dev" "dev"
# TODO: records should be private # TODO: records should be private
@@ -93,20 +94,20 @@ in
]; ];
# convenience # convenience
sane.fs."/home/colin/knowledge" = fs.wantedSymlinkTo "/home/colin/private/knowledge"; sane.user.fs."knowledge" = fs.wantedSymlinkTo "private/knowledge";
sane.fs."/home/colin/nixos" = fs.wantedSymlinkTo "/home/colin/dev/nixos"; sane.user.fs."nixos" = fs.wantedSymlinkTo "dev/nixos";
sane.fs."/home/colin/Videos/servo" = fs.wantedSymlinkTo "/mnt/servo-media/Videos"; sane.user.fs."Videos/servo" = fs.wantedSymlinkTo "/mnt/servo-media/Videos";
sane.fs."/home/colin/Videos/servo-incomplete" = fs.wantedSymlinkTo "/mnt/servo-media/incomplete"; sane.user.fs."Videos/servo-incomplete" = fs.wantedSymlinkTo "/mnt/servo-media/incomplete";
sane.fs."/home/colin/Music/servo" = fs.wantedSymlinkTo "/mnt/servo-media/Music"; sane.user.fs."Music/servo" = fs.wantedSymlinkTo "/mnt/servo-media/Music";
# used by password managers, e.g. unix `pass` # used by password managers, e.g. unix `pass`
sane.fs."/home/colin/.password-store" = fs.wantedSymlinkTo "/home/colin/knowledge/secrets/accounts"; sane.user.fs.".password-store" = fs.wantedSymlinkTo "knowledge/secrets/accounts";
sane.persist.sys.plaintext = mkIf cfg.guest.enable [ sane.persist.sys.plaintext = mkIf cfg.enable [
# intentionally allow other users to write to the guest folder # intentionally allow other users to write to the guest folder
{ directory = "/home/guest"; user = "guest"; group = "users"; mode = "0775"; } { directory = "/home/guest"; user = "guest"; group = "users"; mode = "0775"; }
]; ];
users.users.guest = mkIf cfg.guest.enable { users.users.guest = mkIf cfg.enable {
isNormalUser = true; isNormalUser = true;
home = "/home/guest"; home = "/home/guest";
subUidRanges = [ subUidRanges = [

View File

@@ -3,10 +3,13 @@
{ {
imports = [ imports = [
./derived-secrets.nix ./derived-secrets.nix
./gui
./hardware ./hardware
./hostnames.nix ./hostnames.nix
./hosts.nix ./hosts.nix
./nixcache.nix
./roles ./roles
./services
./wg-home.nix ./wg-home.nix
]; ];
} }

View File

@@ -1,7 +1,7 @@
{ lib, config, ... }: { lib, config, ... }:
with lib;
let let
inherit (lib) mkDefault mkIf mkOption types;
cfg = config.sane.gui; cfg = config.sane.gui;
in in
{ {
@@ -14,15 +14,19 @@ in
]; ];
options = { options = {
# doesn't directly create outputs. consumed by e.g. home-manager.nix module
sane.gui.enable = mkOption { sane.gui.enable = mkOption {
default = false; default = false;
type = types.bool; type = types.bool;
description = ''
enables config used by any GUI, like display management or select packages.
the user should prefer to interact with specific GUIs like `sane.gui.sway`
and let those modules auto-set this flag when necessary.
'';
}; };
}; };
config = lib.mkIf cfg.enable { config = mkIf cfg.enable {
sane.packages.enableGuiPkgs = lib.mkDefault true; sane.programs.guiApps.enableFor.user.colin = mkDefault true;
# preserve backlight brightness across power cycles # preserve backlight brightness across power cycles
# see `man systemd-backlight` # see `man systemd-backlight`

View File

@@ -25,7 +25,7 @@ in
networking.networkmanager.enable = true; networking.networkmanager.enable = true;
networking.wireless.enable = lib.mkForce false; networking.wireless.enable = lib.mkForce false;
}; };
# home-mananger.users.colin extras # user extras:
# obtain these by running `dconf dump /` after manually customizing gnome # obtain these by running `dconf dump /` after manually customizing gnome
# TODO: fix "is not of type `GVariant value'" # TODO: fix "is not of type `GVariant value'"
# dconf.settings = lib.mkIf (gui == "gnome") { # dconf.settings = lib.mkIf (gui == "gnome") {

View File

@@ -59,12 +59,31 @@ in
NIXOS_OZONE_WL = "1"; NIXOS_OZONE_WL = "1";
}; };
sane.packages.extraUserPkgs = with pkgs; [ programs.dconf.packages = [
phosh-mobile-settings (pkgs.writeTextFile {
name = "dconf-phosh-settings";
destination = "/etc/dconf/db/site.d/00_phosh_settings";
text = ''
[org/gnome/desktop/interface]
show-battery-percentage=true
[org/gnome/settings-daemon/plugins/power]
sleep-inactive-ac-timeout=5400
sleep-inactive-battery-timeout=5400
[sm/puri/phosh]
favorites=['gpodder.desktop', 'nheko.desktop', 'sublime-music.desktop', 'firefox.desktop', 'org.kde.konsole.desktop']
'';
})
];
# TODO: refactor
sane.programs = {
phosh-mobile-settings.enableFor.user.colin = true;
# TODO: see about removing this if the in-built gnome-settings bluetooth manager can work # TODO: see about removing this if the in-built gnome-settings bluetooth manager can work
gnome.gnome-bluetooth "gnome.gnome-bluetooth".enableFor.user.colin = true;
]; };
} }
(mkIf cfg.useGreeter { (mkIf cfg.useGreeter {
services.xserver.enable = true; services.xserver.enable = true;

View File

@@ -6,8 +6,8 @@ let
cfg = config.sane.gui.sway; cfg = config.sane.gui.sway;
# docs: https://github.com/Alexays/Waybar/wiki/Configuration # docs: https://github.com/Alexays/Waybar/wiki/Configuration
# format specifiers: https://fmt.dev/latest/syntax.html#syntax # format specifiers: https://fmt.dev/latest/syntax.html#syntax
waybar-config = { waybar-config = [
mainBar = { { # TOP BAR
layer = "top"; layer = "top";
height = 40; height = 40;
modules-left = ["sway/workspaces" "sway/mode"]; modules-left = ["sway/workspaces" "sway/mode"];
@@ -68,10 +68,42 @@ let
clock = { clock = {
format-alt = "{:%a, %d. %b %H:%M}"; format-alt = "{:%a, %d. %b %H:%M}";
}; };
}; }
}; ];
# waybar-config-text = lib.generators.toJSON {} waybar-config; # waybar-config-text = lib.generators.toJSON {} waybar-config;
waybar-config-text = (pkgs.formats.json {}).generate "waybar-config.json" waybar-config; waybar-config-text = (pkgs.formats.json {}).generate "waybar-config.json" waybar-config;
# bare sway launcher
sway-launcher = pkgs.writeShellScriptBin "sway-launcher" ''
${pkgs.sway}/bin/sway --debug > /tmp/sway.log 2>&1
'';
# start sway and have it construct the gtkgreeter
sway-as-greeter = pkgs.writeShellScriptBin "sway-as-greeter" ''
${pkgs.sway}/bin/sway --debug --config ${sway-config-into-gtkgreet} > /tmp/sway-as-greeter.log 2>&1
'';
# (config file for the above)
sway-config-into-gtkgreet = pkgs.writeText "greetd-sway-config" ''
exec "${gtkgreet-launcher}"
'';
# gtkgreet which launches a layered sway instance
gtkgreet-launcher = pkgs.writeShellScript "gtkgreet-launcher" ''
# NB: the "command" field here is run in the user's shell.
# so that command must exist on the specific user's path who is logging in. it doesn't need to exist system-wide.
${pkgs.greetd.gtkgreet}/bin/gtkgreet --layer-shell --command sway-launcher
'';
greeter-session = {
# greeter session config
command = "${sway-as-greeter}/bin/sway-as-greeter";
# alternatives:
# - TTY: `command = "${pkgs.greetd.greetd}/bin/agreety --cmd ${pkgs.sway}/bin/sway";`
# - autologin: `command = "${pkgs.sway}/bin/sway"; user = "colin";`
# - Dumb Login (doesn't work)": `command = "${pkgs.greetd.dlm}/bin/dlm";`
};
greeterless-session = {
# no greeter
command = "${sway-launcher}/bin/sway-launcher";
user = "colin";
};
in in
{ {
options = { options = {
@@ -84,47 +116,26 @@ in
launch sway via a greeter (like greetd's gtkgreet). launch sway via a greeter (like greetd's gtkgreet).
sway is usable without a greeter, but skipping the greeter means no PAM session. sway is usable without a greeter, but skipping the greeter means no PAM session.
''; '';
default = false; default = true;
type = types.bool; type = types.bool;
}; };
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
sane.gui.enable = true; sane.gui.enable = true;
# instead of using `services.greetd`, can instead use SDDM by swapping in these lines. # swap in these lines to use SDDM instead of `services.greetd`.
# services.xserver.displayManager.sddm.enable = true; # services.xserver.displayManager.sddm.enable = true;
# services.xserver.enable = true; # services.xserver.enable = true;
services.greetd = let services.greetd = {
swayConfig-greeter = pkgs.writeText "greetd-sway-config" ''
# `-l` activates layer-shell mode.
exec "${pkgs.greetd.gtkgreet}/bin/gtkgreet -l -c sway"
'';
sway-launcher = pkgs.writeShellScript "sway-launcher" ''
${pkgs.sway}/bin/sway --debug > /home/colin/.sway.log 2>&1
'';
default_session = {
"01" = {
# greeter session config
command = "${pkgs.sway}/bin/sway --config ${swayConfig-greeter}";
# alternatives:
# - TTY: `command = "${pkgs.greetd.greetd}/bin/agreety --cmd ${pkgs.sway}/bin/sway";`
# - autologin: `command = "${pkgs.sway}/bin/sway"; user = "colin";`
# - Dumb Login (doesn't work)": `command = "${pkgs.greetd.dlm}/bin/dlm";`
};
"0" = {
# no greeter
command = sway-launcher;
user = "colin";
};
};
in {
# greetd source/docs: # greetd source/docs:
# - <https://git.sr.ht/~kennylevinsen/greetd> # - <https://git.sr.ht/~kennylevinsen/greetd>
enable = true; enable = true;
settings = { settings = {
default_session = default_session."0${builtins.toString cfg.useGreeter}"; default_session = if cfg.useGreeter then greeter-session else greeterless-session;
}; };
}; };
# we need the greeter's command to be on our PATH
users.users.colin.packages = [ sway-launcher ];
# some programs (e.g. fractal) **require** a "Secret Service Provider" # some programs (e.g. fractal) **require** a "Secret Service Provider"
services.gnome.gnome-keyring.enable = true; services.gnome.gnome-keyring.enable = true;
@@ -160,7 +171,7 @@ in
enable = true; enable = true;
wrapperFeatures.gtk = true; wrapperFeatures.gtk = true;
}; };
sane.fs."/home/colin/.config/sway/config" = sane.user.fs.".config/sway/config" =
let let
fuzzel = "${pkgs.fuzzel}/bin/fuzzel"; fuzzel = "${pkgs.fuzzel}/bin/fuzzel";
sed = "${pkgs.gnused}/bin/sed"; sed = "${pkgs.gnused}/bin/sed";
@@ -335,10 +346,10 @@ in
} }
''; '';
sane.fs."/home/colin/.config/waybar/config" = sane-lib.fs.wantedSymlinkTo waybar-config-text; sane.user.fs.".config/waybar/config" = sane-lib.fs.wantedSymlinkTo waybar-config-text;
# style docs: https://github.com/Alexays/Waybar/wiki/Styling # style docs: https://github.com/Alexays/Waybar/wiki/Styling
sane.fs."/home/colin/.config/waybar/style.css" = sane-lib.fs.wantedText '' sane.user.fs.".config/waybar/style.css" = sane-lib.fs.wantedText ''
* { * {
font-family: monospace; font-family: monospace;
} }
@@ -614,18 +625,19 @@ in
# } # }
# ''; # '';
sane.packages.extraUserPkgs = with pkgs; [ # TODO: refactor
swaylock sane.programs = {
swayidle # (unused) swaylock.enableFor.user.colin = true;
wl-clipboard swayidle.enableFor.user.colin = true; # (unused)
mako # notification daemon wl-clipboard.enableFor.user.colin = true;
xdg-utils # for xdg-open mako.enableFor.user.colin = true; # notification daemon
xdg-utils.enableFor.user.colin = true; # for xdg-open
# user stuff # user stuff
# pavucontrol # pavucontrol
sway-contrib.grimshot "sway-contrib.grimshot".enableFor.user.colin = true;
gnome.gnome-bluetooth "gnome.gnome-bluetooth".enableFor.user.colin = true;
gnome.gnome-control-center "gnome.gnome-control-center".enableFor.user.colin = true;
]; };
}; };
} }

View File

@@ -0,0 +1,6 @@
{ ... }:
{
imports = [
./duplicity.nix
];
}

View File

@@ -4,16 +4,14 @@
imports = [ imports = [
./feeds.nix ./feeds.nix
./fs ./fs
./gui
./home-manager
./ids.nix ./ids.nix
./packages.nix ./programs.nix
./image.nix ./image.nix
./nixcache.nix
./persist ./persist
./services ./services
./sops.nix ./sops.nix
./ssh.nix ./ssh.nix
./users.nix
]; ];
_module.args = { _module.args = {

View File

@@ -1,52 +0,0 @@
# docs:
# https://rycee.gitlab.io/home-manager/
# https://rycee.gitlab.io/home-manager/options.html
# man home-configuration.nix
#
{ lib, config, pkgs, ... }:
with lib;
let
cfg = config.sane.home-manager;
# extract `pkg` from `sane.packages.enabledUserPkgs`
pkg-list = pkgspec: builtins.map (e: e.pkg) pkgspec;
in
{
options = {
sane.home-manager.enable = mkOption {
default = false;
type = types.bool;
};
# attributes to copy directly to home-manager's `wayland.windowManager` option
sane.home-manager.windowManager = mkOption {
default = {};
type = types.attrs;
};
};
config = lib.mkIf cfg.enable {
home-manager.useGlobalPkgs = true;
home-manager.useUserPackages = true;
home-manager.users.colin = {
# run `home-manager-help` to access manpages
# or `man home-configuration.nix`
manual.html.enable = false; # TODO: set to true later (build failure)
manual.manpages.enable = false; # TODO: enable after https://github.com/nix-community/home-manager/issues/3344
home.packages = pkg-list config.sane.packages.enabledUserPkgs;
wayland.windowManager = cfg.windowManager;
home.stateVersion = "21.11";
home.username = "colin";
home.homeDirectory = "/home/colin";
programs = {
# XXX: unsure what this does?
home-manager.enable = true;
};
};
};
}

View File

@@ -20,9 +20,13 @@ sane-lib = rec {
isPrefixOfList = p: l: (lib.sublist 0 (lib.length p) l) == p; isPrefixOfList = p: l: (lib.sublist 0 (lib.length p) l) == p;
# merges N attrsets # merges N attrsets
# Type: flattenAttrsList :: [AttrSet] -> AttrSet # Type: joinAttrsets :: [AttrSet] -> AttrSet
joinAttrsets = l: lib.foldl' lib.attrsets.unionOfDisjoint {} l; joinAttrsets = l: lib.foldl' lib.attrsets.unionOfDisjoint {} l;
# merges N attrsets, recursively
# Type: joinAttrsetsRecursive :: [AttrSet] -> AttrSet
joinAttrsetsRecursive = l: lib.foldl' (lib.attrsets.recursiveUpdateUntil (path: lhs: rhs: false)) {} l;
# evaluate a `{ name, value }` pair in the same way that `listToAttrs` does. # evaluate a `{ name, value }` pair in the same way that `listToAttrs` does.
# Type: nameValueToAttrs :: { name :: String, value :: Any } -> Any # Type: nameValueToAttrs :: { name :: String, value :: Any } -> Any
nameValueToAttrs = { name, value }: { nameValueToAttrs = { name, value }: {

View File

@@ -17,7 +17,7 @@ rec {
merged = builtins.map (p: lib.setAttrByPath p (mergeAtPath p discharged)) pathsToMerge; merged = builtins.map (p: lib.setAttrByPath p (mergeAtPath p discharged)) pathsToMerge;
in in
assert builtins.all (assertNoExtraPaths pathsToMerge) discharged; assert builtins.all (assertNoExtraPaths pathsToMerge) discharged;
sane-lib.joinAttrsets merged; sane-lib.joinAttrsetsRecursive merged;
# `take` is as in mkTypedMerge. this function queries which items `take` is interested in. # `take` is as in mkTypedMerge. this function queries which items `take` is interested in.
# for example: # for example:

View File

@@ -1,328 +0,0 @@
{ config, lib, pkgs, ... }:
with lib;
with pkgs;
let
cfg = config.sane.packages;
imagemagick = pkgs.imagemagick.override {
ghostscriptSupport = true;
};
consolePkgs = [
backblaze-b2
cdrtools
dmidecode
duplicity
efivar
flashrom
fwupd
ghostscript # TODO: imagemagick wrapper should add gs to PATH
gnupg
gocryptfs
gopass
gopass-jsonapi
ifuse
imagemagick
ipfs
libimobiledevice
libsecret # for managing user keyrings
lm_sensors # for sensors-detect
lshw
ffmpeg
memtester
networkmanager
nixpkgs-review
# nixos-generators
# nettools
nmon
oathToolkit # for oathtool
# ponymix
pulsemixer
python3
rsync
# python3Packages.eyeD3 # music tagging
sane-scripts
sequoia
snapper
sops
speedtest-cli
sqlite # to debug sqlite3 databases
ssh-to-age
sudo
# tageditor # music tagging
unar
visidata
w3m
wireguard-tools
# youtube-dl
yt-dlp
];
guiPkgs = [
# GUI only
aerc # email client
audacity
celluloid # mpv frontend
chromium
clinfo
{ pkg = dino; private = [ ".local/share/dino" ]; }
electrum
# creds/session keys, etc
{ pkg = element-desktop; private = [ ".config/Element" ]; }
# `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.
# TODO: package [smile](https://github.com/mijorus/smile) for probably a better mobile experience.
{ pkg = emote; dir = [ ".local/share/Emote" ]; }
evince # works on phosh
# { pkg = fluffychat-moby; dir = [ ".local/share/chat.fluffy.fluffychat" ]; } # TODO: ship normal fluffychat on non-moby?
foliate
font-manager
# XXX by default fractal stores its state in ~/.local/share/<UUID>.
# after logging in, manually change ~/.local/share/keyrings/... to point it to some predictable subdir.
# then reboot (so that libsecret daemon re-loads the keyring...?)
# { pkg = fractal-latest; private = [ ".local/share/fractal" ]; }
# { pkg = fractal-next; private = [ ".local/share/fractal" ]; }
gajim # XMPP client
gimp # broken on phosh
gnome.cheese
gnome.dconf-editor
gnome-feeds # RSS reader (with claimed mobile support)
gnome.file-roller
gnome.gnome-disk-utility
gnome.gnome-maps # works on phosh
gnome.nautilus
# gnome-podcasts
gnome.gnome-system-monitor
gnome.gnome-terminal # works on phosh
gnome.gnome-weather
# XXX: we preserve the whole thing because if we only preserve gPodder/Downloads
# then startup is SLOW during feed import, and we might end up with zombie eps in the dl dir.
{ pkg = gpodder-configured; dir = [ "gPodder" ]; }
gthumb
handbrake
inkscape
kdenlive
kid3 # audio tagging
kitty
krita
libreoffice-fresh # XXX colin: maybe don't want this on mobile
lollypop
{ pkg = mpv; dir = [ ".config/mpv/watch_later" ]; }
networkmanagerapplet
# not strictly necessary, but allows caching articles; offline use, etc.
{ pkg = newsflash; dir = [ ".local/share/news-flash" ]; }
{ pkg = nheko; private = [
".config/nheko" # config file (including client token)
".cache/nheko" # media cache
".local/share/nheko" # per-account state database
]; }
# settings (electron app). TODO: can i manage these settings with home-manager?
{ pkg = obsidian; dir = [ ".config/obsidian" ]; }
pavucontrol
# picard # music tagging
playerctl
libsForQt5.plasmatube # Youtube player
soundconverter
# sublime music persists any downloaded albums here.
# it doesn't obey a conventional ~/Music/{Artist}/{Album}/{Track} notation, so no symlinking
# config (e.g. server connection details) is persisted in ~/.config/sublime-music/config.json
# possible to pass config as a CLI arg (sublime-music -c config.json)
# { pkg = sublime-music; dir = [ ".local/share/sublime-music" ]; }
{ pkg = sublime-music-mobile; dir = [ ".local/share/sublime-music" ]; }
{ pkg = tdesktop; private = [ ".local/share/TelegramDesktop" ]; } # broken on phosh
{ pkg = tokodon; private = [ ".cache/KDE/tokodon" ]; }
# vlc remembers play position in ~/.config/vlc/vlc-qt-interface.conf
{ pkg = vlc; dir = [ ".config/vlc" ]; }
# pleroma client (Electron). input is broken on phosh.
{ pkg = whalebird; private = [ ".config/Whalebird" ]; }
xdg-utils # for xdg-open
xterm # broken on phosh
]
++ (if pkgs.system == "x86_64-linux" then
[
# x86_64 only
# creds, but also 200 MB of node modules, etc
(let discord = (pkgs.discord.override {
# XXX 2022-07-31: fix to allow links to open in default web-browser:
# https://github.com/NixOS/nixpkgs/issues/78961
nss = pkgs.nss_latest;
}); in { pkg = discord; private = [ ".config/discord" ]; })
# kaiteki # Pleroma client
# gnome.zenity # for kaiteki (it will use qarma, kdialog, or zenity)
# gpt2tc # XXX: unreliable mirror
logseq
losslesscut-bin
makemkv
# actual monero blockchain (not wallet/etc; safe to delete, just slow to regenerate)
{ pkg = monero-gui; dir = [ ".bitmonero" ]; }
# creds, media
{ pkg = signal-desktop; private = [ ".config/Signal" ]; }
# creds. TODO: can i manage this with home-manager?
{ pkg = spotify; dir = [ ".config/spotify" ]; }
# hardenedMalloc solves a crash at startup
(tor-browser-bundle-bin.override { useHardenedMalloc = false; })
# zcash coins. safe to delete, just slow to regenerate (10-60 minutes)
{ pkg = zecwallet-lite; private = [ ".zcash" ]; }
] else []);
# general-purpose utilities that we want any user to be able to access
# (specifically: root, in case of rescue)
systemPkgs = [
btrfs-progs
cacert.unbundled # some services require unbundled /etc/ssl/certs
cryptsetup
dig
efibootmgr
fatresize
fd
file
gawk
git
gptfdisk
hdparm
htop
iftop
inetutils # for telnet
iotop
iptables
jq
killall
lsof
nano
netcat
nethogs
nmap
openssl
parted
pciutils
powertop
pstree
ripgrep
screen
smartmontools
socat
strace
tcpdump
tree
usbutils
wget
];
# useful devtools:
devPkgs = [
bison
dtc
flex
gcc
gdb
# gcc-arm-embedded
# gcc_multi
gnumake
mercurial
mix2nix
rustup
swig
];
pkgSpec = types.submodule {
options = {
pkg = mkOption {
type = types.package;
};
dir = mkOption {
type = types.listOf types.str;
default = [];
description = "list of home-relative paths to persist for this package";
};
private = mkOption {
type = types.listOf types.str;
default = [];
description = "list of home-relative paths to persist (in encrypted format) for this package";
};
};
};
toPkgSpec = types.coercedTo types.package (p: { pkg = p; }) pkgSpec;
in
{
options = {
# packages to deploy to the user's home
sane.packages.extraUserPkgs = mkOption {
default = [ ];
type = types.listOf toPkgSpec;
};
sane.packages.extraGuiPkgs = mkOption {
default = [ ];
type = types.listOf toPkgSpec;
description = "packages to only ship if gui's enabled";
};
sane.packages.enableConsolePkgs = mkOption {
default = false;
type = types.bool;
};
sane.packages.enableGuiPkgs = mkOption {
default = false;
type = types.bool;
};
sane.packages.enableDevPkgs = mkOption {
description = ''
enable packages that are useful for building other software by hand.
you should prefer to keep this disabled except when prototyping, e.g. packaging new software.
'';
default = false;
type = types.bool;
};
sane.packages.enableSystemPkgs = mkOption {
default = false;
type = types.bool;
description = "enable system-wide packages";
};
sane.packages.enabledUserPkgs = mkOption {
default = cfg.extraUserPkgs
++ (if cfg.enableConsolePkgs then consolePkgs else [])
++ (if cfg.enableGuiPkgs then guiPkgs ++ cfg.extraGuiPkgs else [])
++ (if cfg.enableDevPkgs then devPkgs else [])
;
type = types.listOf toPkgSpec;
description = "generated from other config options";
};
};
config = {
environment.systemPackages = mkIf cfg.enableSystemPkgs systemPkgs;
sane.persist.home.plaintext = concatLists (map (p: p.dir) cfg.enabledUserPkgs);
sane.persist.home.private = concatLists (map (p: p.private) cfg.enabledUserPkgs);
# XXX: this might not be necessary. try removing this and cacert.unbundled?
environment.etc."ssl/certs".source = mkIf cfg.enableSystemPkgs "${pkgs.cacert.unbundled}/etc/ssl/certs/*";
};
}

View File

@@ -1,18 +0,0 @@
{ config, lib, sane-lib, ... }:
let
path = sane-lib.path;
cfg = config.sane.persist;
withPrefix = relativeTo: entries: lib.mapAttrs' (fspath: value: {
name = path.concat [ relativeTo fspath ];
inherit value;
}) entries;
in
{
# merge the `byPath` mappings from both `home` and `sys` into one namespace
sane.persist.byPath = lib.mkMerge [
(withPrefix "/home/colin" cfg.home.byPath)
(withPrefix "/" cfg.sys.byPath)
];
}

View File

@@ -179,23 +179,11 @@ in
type = types.bool; type = types.bool;
description = "define / fs root to be a tmpfs. make sure to mount some other device to /nix"; description = "define / fs root to be a tmpfs. make sure to mount some other device to /nix";
}; };
sane.persist.home = mkOption {
description = "directories to persist to disk, relative to a user's home ~";
default = {};
type = dirsSubModule;
};
sane.persist.sys = mkOption { sane.persist.sys = mkOption {
description = "directories to persist to disk, relative to the fs root /"; description = "directories to persist to disk, relative to the fs root /";
default = {}; default = {};
type = dirsSubModule; type = dirsSubModule;
}; };
sane.persist.byPath = mkOption {
type = types.attrsOf (convertInlineAcl entryAtPath);
description = ''
map of <path> => <path config> for all paths to be persisted.
this is computed from the other options, but users can also set it explicitly (useful for overriding)
'';
};
sane.persist.stores = mkOption { sane.persist.stores = mkOption {
type = types.attrsOf storeType; type = types.attrsOf storeType;
default = {}; default = {};
@@ -206,7 +194,6 @@ in
}; };
imports = [ imports = [
./computed.nix
./root-on-tmpfs.nix ./root-on-tmpfs.nix
./stores ./stores
]; ];
@@ -247,7 +234,7 @@ in
); );
} }
]; ];
configs = lib.mapAttrsToList cfgFor cfg.byPath; configs = lib.mapAttrsToList cfgFor cfg.sys.byPath;
take = f: { sane.fs = f.sane.fs; }; take = f: { sane.fs = f.sane.fs; };
in mkIf cfg.enable ( in mkIf cfg.enable (
take (sane-lib.mkTypedMerge take configs) take (sane-lib.mkTypedMerge take configs)

View File

@@ -1,14 +1,10 @@
{ config, lib, pkgs, utils, ... }: { config, lib, pkgs, sane-lib, utils, ... }:
let let
store = rec { persist-base = config.sane.persist.stores."plaintext".origin;
device = "/mnt/persist/crypt/clearedonboot"; device = config.sane.persist.stores."cryptClearOnBoot".origin;
underlying = { key = "${device}.key";
path = "/nix/persist/crypt/clearedonboot"; underlying = sane-lib.path.concat [ persist-base "crypt/clearedonboot" ];
# TODO: consider moving this to /tmp, but that requires tmp be mounted first?
key = "/mnt/persist/crypt/clearedonboot.key";
};
};
in in
lib.mkIf config.sane.persist.enable lib.mkIf config.sane.persist.enable
{ {
@@ -17,35 +13,35 @@ lib.mkIf config.sane.persist.enable
stored to disk, but encrypted to an in-memory key and cleared on every boot stored to disk, but encrypted to an in-memory key and cleared on every boot
so that it's unreadable after power-off so that it's unreadable after power-off
''; '';
origin = store.device; origin = lib.mkDefault "/mnt/persist/crypt/clearedonboot";
}; };
fileSystems."${store.device}" = { fileSystems."${device}" = {
device = store.underlying.path; device = underlying;
fsType = "fuse.gocryptfs"; fsType = "fuse.gocryptfs";
options = [ options = [
"nodev" "nodev"
"nosuid" "nosuid"
"allow_other" "allow_other"
"passfile=${store.underlying.key}" "passfile=${key}"
"defaults" "defaults"
]; ];
noCheck = true; noCheck = true;
}; };
# let sane.fs know about our fileSystem and automatically add the appropriate dependencies # let sane.fs know about our fileSystem and automatically add the appropriate dependencies
sane.fs."${store.device}".mount = { sane.fs."${device}".mount = {
# technically the dependency on the keyfile is extraneous because that *happens* to # technically the dependency on the keyfile is extraneous because that *happens* to
# be needed to init the store. # be needed to init the store.
depends = let depends = let
cryptfile = config.sane.fs."${store.underlying.path}/gocryptfs.conf"; cryptfile = config.sane.fs."${underlying}/gocryptfs.conf";
keyfile = config.sane.fs."${store.underlying.key}"; keyfile = config.sane.fs."${key}";
in [ keyfile.unit cryptfile.unit ]; in [ keyfile.unit cryptfile.unit ];
}; };
# let sane.fs know how to initialize the gocryptfs store, # let sane.fs know how to initialize the gocryptfs store,
# and that it MUST do so # and that it MUST do so
sane.fs."${store.underlying.path}/gocryptfs.conf".generated = { sane.fs."${underlying}/gocryptfs.conf".generated = {
script.script = '' script.script = ''
backing="$1" backing="$1"
passfile="$2" passfile="$2"
@@ -54,17 +50,17 @@ lib.mkIf config.sane.persist.enable
rm -rf "''${backing:?}"/* rm -rf "''${backing:?}"/*
${pkgs.gocryptfs}/bin/gocryptfs -quiet -passfile "$passfile" -init "$backing" ${pkgs.gocryptfs}/bin/gocryptfs -quiet -passfile "$passfile" -init "$backing"
''; '';
script.scriptArgs = [ store.underlying.path store.underlying.key ]; script.scriptArgs = [ underlying key ];
# we need the key in order to initialize the store # we need the key in order to initialize the store
depends = [ config.sane.fs."${store.underlying.key}".unit ]; depends = [ config.sane.fs."${key}".unit ];
}; };
# let sane.fs know how to generate the key for gocryptfs # let sane.fs know how to generate the key for gocryptfs
sane.fs."${store.underlying.key}".generated = { sane.fs."${key}".generated = {
script.script = '' script.script = ''
dd if=/dev/random bs=128 count=1 | base64 --wrap=0 > "$1" dd if=/dev/random bs=128 count=1 | base64 --wrap=0 > "$1"
''; '';
script.scriptArgs = [ store.underlying.key ]; script.scriptArgs = [ key ];
# no need for anyone else to be able to read the key # no need for anyone else to be able to read the key
acl.mode = "0400"; acl.mode = "0400";
}; };

View File

@@ -3,7 +3,7 @@
let let
cfg = config.sane.persist; cfg = config.sane.persist;
in lib.mkIf cfg.enable { in lib.mkIf cfg.enable {
sane.persist.stores."plaintext" = { sane.persist.stores."plaintext" = lib.mkDefault {
origin = "/nix/persist"; origin = "/nix/persist";
}; };
# TODO: needed? # TODO: needed?

View File

@@ -1,21 +1,23 @@
{ config, lib, pkgs, utils, ... }: { config, lib, pkgs, sane-lib, utils, ... }:
let
persist-base = config.sane.persist.stores."plaintext".origin;
private-dir = config.sane.persist.stores."private".origin;
private-backing-dir = sane-lib.path.concat [ persist-base private-dir ];
in
lib.mkIf config.sane.persist.enable lib.mkIf config.sane.persist.enable
{ {
sane.persist.stores."private" = { sane.persist.stores."private" = {
storeDescription = '' storeDescription = ''
encrypted to the user's password and auto-unlocked at login encrypted store which persists across boots.
typical use case is for the user to encrypt this store using their login password so that it
can be auto-unlocked at login.
''; '';
origin = "/home/colin/private"; origin = lib.mkDefault "/mnt/private";
# files stored under here *must* have the /home/colin prefix.
# internally, this prefix is removed so that e.g.
# /home/colin/foo/bar when stored in `private` is visible at
# /home/colin/private/foo/bar
prefix = "/home/colin";
defaultOrdering = let defaultOrdering = let
private-unit = config.sane.fs."/home/colin/private".unit; private-unit = config.sane.fs."${private-dir}".unit;
in { in {
# auto create only after ~/private is mounted # auto create only after the store is mounted
wantedBy = [ private-unit ]; wantedBy = [ private-unit ];
# we can't create things in private before local-fs.target # we can't create things in private before local-fs.target
wantedBeforeBy = [ ]; wantedBeforeBy = [ ];
@@ -23,13 +25,13 @@ lib.mkIf config.sane.persist.enable
defaultMethod = "symlink"; defaultMethod = "symlink";
}; };
fileSystems."/home/colin/private" = { fileSystems."${private-dir}" = {
device = "/nix/persist/home/colin/private"; device = private-backing-dir;
fsType = "fuse.gocryptfs"; fsType = "fuse.gocryptfs";
options = [ options = [
"noauto" # don't try to mount, until the user logs in! "noauto" # don't try to mount, until the user logs in!
"nofail" "nofail"
"allow_other" # root ends up being the user that mounts this, so need to make it visible to `colin`. "allow_other" # root ends up being the user that mounts this, so need to make it visible to other users.
"nodev" "nodev"
"nosuid" "nosuid"
"quiet" "quiet"
@@ -39,9 +41,9 @@ lib.mkIf config.sane.persist.enable
}; };
# let sane.fs know about the mount # let sane.fs know about the mount
sane.fs."/home/colin/private".mount = {}; sane.fs."${private-dir}".mount = {};
# it also needs to know that the underlying device is an ordinary folder # it also needs to know that the underlying device is an ordinary folder
sane.fs."/nix/persist/home/colin/private".dir = {}; sane.fs."${private-backing-dir}".dir = {};
# TODO: could add this *specifically* to the .mount file for the encrypted fs? # TODO: could add this *specifically* to the .mount file for the encrypted fs?
system.fsPackages = [ pkgs.gocryptfs ]; # fuse needs to find gocryptfs system.fsPackages = [ pkgs.gocryptfs ]; # fuse needs to find gocryptfs

121
modules/programs.nix Normal file
View File

@@ -0,0 +1,121 @@
{ config, lib, pkgs, sane-lib, ... }:
let
inherit (builtins) any elem map;
inherit (lib)
filterAttrs
hasAttrByPath
getAttrFromPath
mapAttrs
mapAttrsToList
mkDefault
mkIf
mkOption
optional
optionalAttrs
splitString
types
;
inherit (sane-lib) joinAttrsets;
cfg = config.sane.programs;
pkgSpec = types.submodule ({ name, ... }: {
options = {
package = mkOption {
type = types.nullOr types.package;
description = ''
package, or `null` if the program is some sort of meta set (in which case it much EXPLICITLY be set null).
'';
default =
let
pkgPath = splitString "." name;
in
# package can be inferred by the attr name, allowing shorthand like
# `sane.programs.nano.enable = true;`
# this indexing will throw if the package doesn't exist and the user forgets to specify
# a valid source explicitly.
getAttrFromPath pkgPath pkgs;
};
enableFor.system = mkOption {
type = types.bool;
default = any (en: en) (
mapAttrsToList
(otherName: otherPkg:
otherName != name && elem name otherPkg.suggestedPrograms && otherPkg.enableSuggested && otherPkg.enableFor.system
)
cfg
);
description = ''
place this program on the system PATH
'';
};
enableFor.user = mkOption {
type = types.attrsOf types.bool;
default = joinAttrsets (mapAttrsToList (otherName: otherPkg:
optionalAttrs
(otherName != name && elem name otherPkg.suggestedPrograms && otherPkg.enableSuggested)
(filterAttrs (user: en: en) otherPkg.enableFor.user)
) cfg);
description = ''
place this program on the PATH for some specified user(s).
'';
};
suggestedPrograms = mkOption {
type = types.listOf types.str;
default = [];
description = ''
list of other programs a user may want to enable alongside this one.
for example, the gnome desktop environment would suggest things like its settings app.
'';
};
enableSuggested = mkOption {
type = types.bool;
default = true;
};
dir = mkOption {
type = types.listOf types.str;
default = [];
description = "list of home-relative paths to persist for this package";
};
private = mkOption {
type = types.listOf types.str;
default = [];
description = "list of home-relative paths to persist (in encrypted format) for this package";
};
};
});
toPkgSpec = types.coercedTo types.package (p: { package = p; }) pkgSpec;
configs = mapAttrsToList (_name: p: {
# conditionally add to system PATH
environment.systemPackages = optional
(p.package != null && p.enableFor.system)
p.package;
# conditionally add to user(s) PATH
users.users = mapAttrs (user: en: {
packages = optional (p.package != null && en) p.package;
}) p.enableFor.user;
# conditionally persist relevant user dirs
sane.users = mapAttrs (user: en: optionalAttrs en {
persist.plaintext = p.dir;
persist.private = p.private;
}) p.enableFor.user;
}) cfg;
in
{
options = {
sane.programs = mkOption {
type = types.attrsOf toPkgSpec;
default = {};
};
};
config =
let
take = f: {
environment.systemPackages = f.environment.systemPackages;
users.users = f.users.users;
sane.users = f.sane.users;
};
in
take (sane-lib.mkTypedMerge take configs);
}

View File

@@ -1,7 +1,6 @@
{ ... }: { ... }:
{ {
imports = [ imports = [
./duplicity.nix
./dyn-dns.nix ./dyn-dns.nix
./kiwix-serve.nix ./kiwix-serve.nix
./mautrix-signal.nix ./mautrix-signal.nix

110
modules/users.nix Normal file
View File

@@ -0,0 +1,110 @@
{ config, lib, options, sane-lib, ... }:
let
inherit (builtins) attrValues;
inherit (lib) count mapAttrs' mapAttrsToList mkIf mkMerge mkOption types;
sane-user-cfg = config.sane.user;
cfg = config.sane.users;
path-lib = sane-lib.path;
userOptions = {
options = {
fs = mkOption {
type = types.attrs;
default = {};
description = ''
entries to pass onto `sane.fs` after prepending the user's home-dir to the path.
e.g. `sane.users.colin.fs."/.config/aerc" = X`
=> `sane.fs."/home/colin/.config/aerc" = X;
'';
};
persist = mkOption {
type = options.sane.persist.sys.type;
default = {};
description = ''
entries to pass onto `sane.persist.sys` after prepending the user's home-dir to the path.
'';
};
};
};
userModule = types.submodule ({ name, config, ... }: {
options = userOptions.options // {
default = mkOption {
type = types.bool;
default = false;
description = ''
only one default user may exist.
this option determines what the `sane.user` shorthand evaluates to.
'';
};
home = mkOption {
type = types.str;
# XXX: we'd prefer to set this to `config.users.users.home`, but that causes infinite recursion...
# TODO: maybe assert that this matches the actual home?
default = "/home/${name}";
};
};
# if we're the default user, inherit whatever settings were routed to the default user
config = mkIf config.default sane-user-cfg;
});
processUser = user: defn:
let
prefixWithHome = mapAttrs' (path: value: {
name = path-lib.concat [ defn.home path ];
inherit value;
});
in
{
sane.fs = prefixWithHome defn.fs;
# `byPath` is the actual output here, computed from the other keys.
sane.persist.sys.byPath = prefixWithHome defn.persist.byPath;
};
in
{
options = {
sane.users = mkOption {
type = types.attrsOf userModule;
default = {};
description = ''
options to apply to the given user.
the user is expected to be created externally.
configs applied at this level are simply transformed and then merged
into the toplevel `sane` options. it's merely a shorthand.
'';
};
sane.user = mkOption {
type = types.nullOr (types.submodule userOptions);
default = null;
description = ''
options to pass down to the default user
'';
};
};
config =
let
configs = mapAttrsToList processUser cfg;
num-default-users = count (u: u.default) (attrValues cfg);
take = f: {
sane.fs = f.sane.fs;
sane.persist.sys.byPath = f.sane.persist.sys.byPath;
};
in mkMerge [
(take (sane-lib.mkTypedMerge take configs))
{
assertions = [
{
assertion = sane-user-cfg == null || num-default-users != 0;
message = "cannot set `sane.user` without first setting `sane.users.<user>.default = true` for some user";
}
{
assertion = num-default-users <= 1;
message = "cannot set more than one default user";
}
];
}
];
}

View File

@@ -8,27 +8,5 @@
# XXX: when invoked outside our flake (e.g. via NIX_PATH) there is no `next.stable`, # XXX: when invoked outside our flake (e.g. via NIX_PATH) there is no `next.stable`,
# so just forward the unstable packages. # so just forward the unstable packages.
inherit (next.stable or prev) inherit (next.stable or prev)
# broken on 2023/01/14 via mtxclient dep, aarch64-only:
# fixed on 2023/01/24?
# error: builder for '/nix/store/gwidl0c9ksxjgx0dgwnjssix4ikq73v5-mtxclient-0.9.0.drv' failed with exit code 2;
# last 10 log lines:
# > make[2]: *** [CMakeFiles/matrix_client.dir/build.make:370: CMakeFiles/matrix_client.dir/lib/structs/events/encrypted.cpp.o] Error 1
# > In file included from /build/source/include/mtxclient/crypto/client.hpp:17,
# > from /build/source/lib/crypto/utils.cpp:17:
# > /build/source/include/mtx/identifiers.hpp:12:10: fatal error: compare: No such file or directory
# > 12 | #include <compare>
# > | ^~~~~~~~~
# > compilation terminated.
# > make[2]: *** [CMakeFiles/matrix_client.dir/build.make:132: CMakeFiles/matrix_client.dir/lib/crypto/utils.cpp.o] Error 1
# > make[1]: *** [CMakeFiles/Makefile2:83: CMakeFiles/matrix_client.dir/all] Error 2
# > make: *** [Makefile:136: all] Error 2
# For full logs, run 'nix log /nix/store/gwidl0c9ksxjgx0dgwnjssix4ikq73v5-mtxclient-0.9.0.drv'.
# error: 1 dependencies of derivation '/nix/store/4i2d1qdh4x6n23h1jbcbhm8q9q2hch9a-nheko-0.11.0.drv' failed to build
# error: 1 dependencies of derivation '/nix/store/k4f7k7cvjp8rb7clhlfq3yxgs6lbfmk7-home-manager-path.drv' failed to build
# error: 1 dependencies of derivation '/nix/store/67d9k554188lh4ddl4ar6j74mpc3r4sv-home-manager-generation.drv' failed to build
# error: 1 dependencies of derivation '/nix/store/5qjxzhsw1jvh2d7jypbcam9409ivb472-user-environment.drv' failed to build
# error: 1 dependencies of derivation '/nix/store/hrb3qpdbisqh0lzlyz1g9g4164khmqwn-etc.drv' failed to build
# error: 1 dependencies of derivation '/nix/store/ny21xyicbgim5wy7ksg2hibd9gn7i01b-nixos-system-moby-23.05pre-git.drv' failed to build
# nheko
; ;
}) })