Compare commits

..

2 Commits

51 changed files with 504 additions and 526 deletions

61
flake.lock generated
View File

@@ -15,14 +15,35 @@
"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": 1674880620, "lastModified": 1674779092,
"narHash": "sha256-JMALuC7xcoH/T66sKTVLuItHfOJBCWsNKpE49Qrvs80=", "narHash": "sha256-mFBD0Dvjf8tuxWtJhsCQ+8VYqI4fQeWjd/vfWsZiRRo=",
"owner": "nixos", "owner": "nixos",
"repo": "mobile-nixos", "repo": "mobile-nixos",
"rev": "7478a9ffad737486951186b66f6c5535dc5802e2", "rev": "80ece5a61738fbf3b96fdda402ab2dfc74ee5cee",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -39,16 +60,32 @@
}, },
"locked": { "locked": {
"lastModified": 1, "lastModified": 1,
"narHash": "sha256-arp7Uy7ct5ryTcmSY032eN7hr33i7D2XvjTRLliCFDc=", "narHash": "sha256-5pNu9Ph1LIBj5q9RWLV3r7daANjmd4u5y+MVq8vlfS4=",
"path": "/nix/store/jblp2g67p3wid2qarcyd8bzrbs9wg5lb-source/nixpatches", "path": "/nix/store/bjzsgw8zn4av0dv4sqyj7vxhi43na16y-source/nixpatches",
"type": "path" "type": "path"
}, },
"original": { "original": {
"path": "/nix/store/jblp2g67p3wid2qarcyd8bzrbs9wg5lb-source/nixpatches", "path": "/nix/store/bjzsgw8zn4av0dv4sqyj7vxhi43na16y-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=",
@@ -82,8 +119,10 @@
}, },
"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"
@@ -94,7 +133,7 @@
"nixpkgs": [ "nixpkgs": [
"nixpkgs" "nixpkgs"
], ],
"nixpkgs-stable": "nixpkgs-stable" "nixpkgs-stable": "nixpkgs-stable_2"
}, },
"locked": { "locked": {
"lastModified": 1674546403, "lastModified": 1674546403,
@@ -118,11 +157,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1675131883, "lastModified": 1666870107,
"narHash": "sha256-yBgJDG72YqIr1bltasqHD1E/kHc9uRFgDjxDmy6kI8M=", "narHash": "sha256-b9eXZxSwhzdJI5uQgfrMhu4SY2POrPkinUg7F5gQVYo=",
"ref": "refs/heads/master", "ref": "refs/heads/master",
"rev": "b099c24091cc192abf3997b94342d4b31cc5757b", "rev": "80c6ec95bd430e29d231cf745f19279bb76fb382",
"revCount": 170, "revCount": 164,
"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,6 +32,11 @@
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";
@@ -46,12 +51,13 @@
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}";
@@ -117,12 +123,9 @@
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 = stable = next: prev: {
if inputs ? "nixpkgs-stable" then ( stable = nixpkgs-stable.legacyPackages."${prev.stdenv.hostPlatform.system}";
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
@@ -135,6 +138,7 @@
sane = import ./modules; sane = import ./modules;
passthru = { ... }: { passthru = { ... }: {
imports = [ imports = [
home-manager.nixosModule
sops-nix.nixosModules.sops sops-nix.nixosModules.sops
]; ];
}; };

View File

@@ -54,7 +54,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.user.persist.plaintext = [ sane.persist.home.plaintext = [
".steam" ".steam"
".local/share/Steam" ".local/share/Steam"
]; ];

View File

@@ -10,7 +10,7 @@
# sane.packages.enableDevPkgs = true; # 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,7 +37,7 @@
# addons.sideberry.enable = false; # addons.sideberry.enable = false;
}; };
sane.user.persist.plaintext = [ sane.persist.home.plaintext = [
".config/pulse" # persist pulseaudio volume ".config/pulse" # persist pulseaudio volume
]; ];

View File

@@ -1,6 +1,3 @@
# DOCS:
# - dovecot config: <https://doc.dovecot.org/configuration_manual/>
{ config, lib, ... }: { config, lib, ... }:
let let
@@ -146,25 +143,6 @@ 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,17 +10,26 @@
./ids.nix ./ids.nix
./machine-id.nix ./machine-id.nix
./net.nix ./net.nix
./persist.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.packages.enableConsolePkgs = true;
sane.packages.enableSystemPkgs = true; sane.packages.enableSystemPkgs = 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";
@@ -66,20 +75,8 @@
# NIXOS_OZONE_WL = "1"; # NIXOS_OZONE_WL = "1";
# LIBGL_ALWAYS_SOFTWARE = "1"; # LIBGL_ALWAYS_SOFTWARE = "1";
}; };
# enable zsh completions
# dconf docs: <https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/desktop_migration_and_administration_guide/profiles> environment.pathsToLink = [ "/share/zsh" ];
# 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,11 +1,12 @@
# Terminal UI mail client # Terminal UI mail client
{ config, sane-lib, ... }: { config, lib, 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.user.fs.".config/aerc/accounts.conf" = sane-lib.fs.wantedSymlinkTo config.sops.secrets.aerc_accounts.path; sane.fs."/home/colin/.config/aerc/accounts.conf" = sane-lib.fs.wantedSymlinkTo config.sops.secrets.aerc_accounts.path;
} }

View File

@@ -145,7 +145,7 @@ in
}; };
}; };
config = { config = lib.mkIf config.sane.home-manager.enable {
# uBlock filter list configuration. # uBlock filter list configuration.
# specifically, enable the GDPR cookie prompt blocker. # specifically, enable the GDPR cookie prompt blocker.
@@ -155,7 +155,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.user.fs."${cfg.browser.dotDir}/managed-storage/uBlock0@raymondhill.net.json" = sane-lib.fs.wantedText '' sane.fs."/home/colin/${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,7 +165,7 @@ in
} }
} }
''; '';
sane.user.fs."${cfg.browser.dotDir}/${cfg.browser.libName}.overrides.cfg" = sane-lib.fs.wantedText '' sane.fs."/home/colin/${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>
@@ -174,17 +174,17 @@ in
sane.packages.extraGuiPkgs = [ package ]; 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.user.persist.byPath."${cfg.browser.cacheDir}" = lib.mkIf (cfg.persistCache != null) { sane.persist.home.byPath."${cfg.browser.cacheDir}" = lib.mkIf (cfg.persistCache != null) {
store = cfg.persistCache; store = cfg.persistCache;
}; };
sane.user.persist.byPath."${cfg.browser.dotDir}/default" = lib.mkIf (cfg.persistData != null) { sane.persist.home.byPath."${cfg.browser.dotDir}/default" = lib.mkIf (cfg.persistData != null) {
store = cfg.persistData; store = cfg.persistData;
}; };
sane.user.fs."${cfg.browser.dotDir}/default" = sane-lib.fs.wantedDir; sane.fs."/home/colin/${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.user.fs."${cfg.browser.dotDir}/profiles.ini" = sane-lib.fs.wantedText '' sane.fs."/home/colin/${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.user.fs.".config/org.gabmus.gfeeds.json" = sane-lib.fs.wantedText ( sane.fs."/home/colin/.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,10 +1,11 @@
{ lib, pkgs, sane-lib, ... }: { config, lib, pkgs, sane-lib, ... }:
let let
mkCfg = lib.generators.toINI { }; mkCfg = lib.generators.toINI { };
in in
lib.mkIf config.sane.home-manager.enable
{ {
sane.user.fs.".config/git/config" = sane-lib.fs.wantedText (mkCfg { sane.fs."/home/colin/.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.user.fs.".config/gpodderFeeds.opml" = sane-lib.fs.wantedText ( sane.fs."/home/colin/.config/gpodderFeeds.opml" = sane-lib.fs.wantedText (
feeds.feedsToOpml wanted-feeds feeds.feedsToOpml wanted-feeds
); );
} }

View File

@@ -1,11 +1,11 @@
{ config, sane-lib, ... }: { config, lib, sane-lib, ... }:
lib.mkIf config.sane.home-manager.enable
{ {
sane.user.persist.private = [ ".local/share/keyrings" ]; sane.persist.home.private = [ ".local/share/keyrings" ];
sane.user.fs."private/.local/share/keyrings/default" = { sane.fs."/home/colin/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,7 +1,8 @@
{ pkgs, sane-lib, ... }: { config, lib, pkgs, sane-lib, ... }:
lib.mkIf config.sane.home-manager.enable
{ {
sane.user.fs.".config/kitty/kitty.conf" = sane-lib.fs.wantedText '' sane.fs."/home/colin/.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,8 +1,9 @@
{ sane-lib, ... }: { config, lib, sane-lib, ... }:
lib.mkIf config.sane.home-manager.enable
{ {
# libreoffice: disable first-run stuff # libreoffice: disable first-run stuff
sane.user.fs.".config/libreoffice/4/user/registrymodifications.xcu" = sane-lib.fs.wantedText '' sane.fs."/home/colin/.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, sane-lib, ...}: { config, lib, sane-lib, ...}:
let let
www = config.sane.web-browser.browser.desktop; www = config.sane.web-browser.browser.desktop;
@@ -9,6 +9,7 @@ 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,8 +1,9 @@
{ sane-lib, ... }: { config, lib, sane-lib, ... }:
lib.mkIf config.sane.home-manager.enable
{ {
# format is <key>=%<length>%<value> # format is <key>=%<length>%<value>
sane.user.fs.".config/mpv/mpv.conf" = sane-lib.fs.wantedText '' sane.fs."/home/colin/.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 @@
{ lib, pkgs, ... }: { config, lib, pkgs, ... }:
let let
inherit (builtins) map; inherit (builtins) map;
@@ -70,9 +70,10 @@ 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.user.persist.private = [ ".cache/vim-swap" ]; sane.persist.home.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.user.fs.".config/newsflashFeeds.opml" = sane-lib.fs.wantedText ( sane.fs."/home/colin/.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.user.persist.plaintext = [ ".local/state/splatmoji" ]; sane.persist.home.plaintext = [ ".local/state/splatmoji" ];
sane.user.fs.".config/splatmoji/splatmoji.config" = sane-lib.fs.wantedText '' sane.fs."/home/colin/.config/splatmoji/splatmoji.config" = sane-lib.fs.wantedText ''
history_file=~/.local/state/splatmoji/history history_file=/home/colin/.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, sane-lib, ... }: { config, lib, pkgs, sane-lib, ... }:
with lib; with lib;
let let
@@ -9,12 +9,11 @@ let
"\n" "\n"
(map (k: k.asHostKey) host-keys) (map (k: k.asHostKey) host-keys)
; ;
in in lib.mkIf config.sane.home-manager.enable {
{
# ssh key is stored in private storage # ssh key is stored in private storage
sane.user.persist.private = [ ".ssh/id_ed25519" ]; sane.persist.home.private = [ ".ssh/id_ed25519" ];
sane.user.fs.".ssh/id_ed25519.pub" = sane-lib.fs.wantedText user-pubkey; sane.fs."/home/colin/.ssh/id_ed25519.pub" = sane-lib.fs.wantedText user-pubkey;
sane.user.fs.".ssh/known_hosts" = sane-lib.fs.wantedText known-hosts-text; sane.fs."/home/colin/.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,5 +1,6 @@
{ config, sane-lib, ... }: { config, lib, 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" = {
@@ -7,5 +8,5 @@
sopsFile = ../../../secrets/universal/sublime_music_config.json.bin; sopsFile = ../../../secrets/universal/sublime_music_config.json.bin;
format = "binary"; format = "binary";
}; };
sane.user.fs.".config/sublime-music/config.json" = sane-lib.fs.wantedSymlinkTo config.sops.secrets.sublime_music_config.path; sane.fs."/home/colin/.config/sublime-music/config.json" = sane-lib.fs.wantedSymlinkTo config.sops.secrets.sublime_music_config.path;
} }

View File

@@ -8,8 +8,9 @@ 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.user.fs.".config/vlc/vlcrc" = sane-lib.fs.wantedText '' sane.fs."/home/colin/.config/vlc/vlcrc" = sane-lib.fs.wantedText ''
[podcast] [podcast]
podcast-urls=${podcast-urls} podcast-urls=${podcast-urls}
[core] [core]

View File

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

View File

@@ -1,4 +1,4 @@
{ pkgs, sane-lib, ... }: { config, lib, pkgs, sane-lib, ... }:
let let
# powerlevel10k prompt config # powerlevel10k prompt config
@@ -25,8 +25,9 @@ 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.user.persist.plaintext = [ sane.persist.home.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?
@@ -36,10 +37,7 @@ in
]; ];
# 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.user.fs.".config/zsh/.zshrc" = sane-lib.fs.wantedText "# "; sane.fs."/home/colin/.config/zsh/.zshrc" = sane-lib.fs.wantedText "# ";
# enable zsh completions
environment.pathsToLink = [ "/share/zsh" ];
programs.zsh = { programs.zsh = {
enable = true; enable = true;
@@ -107,7 +105,7 @@ in
# 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.user.fs.".config/zsh/.zpreztorc" = sane-lib.fs.wantedText '' sane.fs."/home/colin/.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):

View File

@@ -1,16 +0,0 @@
{ ... }:
{
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.
];
}

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.guest; cfg = config.sane.users;
fs = sane-lib.fs; fs = sane-lib.fs;
in in
{ {
options = { options = {
sane.guest.enable = mkOption { sane.users.guest.enable = mkOption {
default = false; default = false;
type = types.bool; type = types.bool;
}; };
@@ -49,8 +49,6 @@ in
shell = pkgs.zsh; shell = pkgs.zsh;
packages = builtins.map (p: p.pkg) config.sane.packages.enabledUserPkgs;
# mount encrypted stuff at login # mount encrypted stuff at login
# some other nix pam users: # some other nix pam users:
# - <https://github.com/g00pix/nixconf/blob/32c04f6fa843fed97639dd3f09e157668d3eea1f/profiles/sshfs.nix> # - <https://github.com/g00pix/nixconf/blob/32c04f6fa843fed97639dd3f09e157668d3eea1f/profiles/sshfs.nix>
@@ -68,7 +66,6 @@ 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 = {
@@ -77,7 +74,7 @@ in
mode = config.users.users.colin.homeMode; mode = config.users.users.colin.homeMode;
}; };
sane.user.persist.plaintext = [ sane.persist.home.plaintext = [
"archive" "archive"
"dev" "dev"
# TODO: records should be private # TODO: records should be private
@@ -96,20 +93,20 @@ in
]; ];
# convenience # convenience
sane.user.fs."knowledge" = fs.wantedSymlinkTo "private/knowledge"; sane.fs."/home/colin/knowledge" = fs.wantedSymlinkTo "/home/colin/private/knowledge";
sane.user.fs."nixos" = fs.wantedSymlinkTo "dev/nixos"; sane.fs."/home/colin/nixos" = fs.wantedSymlinkTo "/home/colin/dev/nixos";
sane.user.fs."Videos/servo" = fs.wantedSymlinkTo "/mnt/servo-media/Videos"; sane.fs."/home/colin/Videos/servo" = fs.wantedSymlinkTo "/mnt/servo-media/Videos";
sane.user.fs."Videos/servo-incomplete" = fs.wantedSymlinkTo "/mnt/servo-media/incomplete"; sane.fs."/home/colin/Videos/servo-incomplete" = fs.wantedSymlinkTo "/mnt/servo-media/incomplete";
sane.user.fs."Music/servo" = fs.wantedSymlinkTo "/mnt/servo-media/Music"; sane.fs."/home/colin/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.user.fs.".password-store" = fs.wantedSymlinkTo "knowledge/secrets/accounts"; sane.fs."/home/colin/.password-store" = fs.wantedSymlinkTo "/home/colin/knowledge/secrets/accounts";
sane.persist.sys.plaintext = mkIf cfg.enable [ sane.persist.sys.plaintext = mkIf cfg.guest.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.enable { users.users.guest = mkIf cfg.guest.enable {
isNormalUser = true; isNormalUser = true;
home = "/home/guest"; home = "/home/guest";
subUidRanges = [ subUidRanges = [

View File

@@ -3,13 +3,10 @@
{ {
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,6 +0,0 @@
{ ... }:
{
imports = [
./duplicity.nix
];
}

View File

@@ -4,14 +4,16 @@
imports = [ imports = [
./feeds.nix ./feeds.nix
./fs ./fs
./gui
./home-manager
./ids.nix ./ids.nix
./packages.nix ./packages.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,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,19 +14,15 @@ 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 = mkIf cfg.enable { config = lib.mkIf cfg.enable {
sane.packages.enableGuiPkgs = mkDefault true; sane.packages.enableGuiPkgs = lib.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;
}; };
# user extras: # home-mananger.users.colin 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,24 +59,6 @@ in
NIXOS_OZONE_WL = "1"; NIXOS_OZONE_WL = "1";
}; };
programs.dconf.packages = [
(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']
'';
})
];
sane.packages.extraUserPkgs = with pkgs; [ sane.packages.extraUserPkgs = with pkgs; [
phosh-mobile-settings phosh-mobile-settings

View File

@@ -70,40 +70,7 @@ let
}; };
} }
]; ];
# 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;
# 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 = {
@@ -123,19 +90,42 @@ in
config = mkIf cfg.enable { config = mkIf cfg.enable {
sane.gui.enable = true; sane.gui.enable = true;
# swap in these lines to use SDDM instead of `services.greetd`. programs.sway = {
# we configure sway with home-manager, but this enable gets us e.g. opengl and fonts
enable = true;
};
# instead of using `services.greetd`, can instead use SDDM by swapping in these lines.
# services.xserver.displayManager.sddm.enable = true; # services.xserver.displayManager.sddm.enable = true;
# services.xserver.enable = true; # services.xserver.enable = true;
services.greetd = { services.greetd = let
swayConfig-greeter = pkgs.writeText "greetd-sway-config" ''
# `-l` activates layer-shell mode.
exec "${pkgs.greetd.gtkgreet}/bin/gtkgreet -l -c sway"
'';
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 = "${pkgs.sway}/bin/sway";
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 = if cfg.useGreeter then greeter-session else greeterless-session; default_session = default_session."0${builtins.toString cfg.useGreeter}";
}; };
}; };
# 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;
@@ -167,18 +157,14 @@ in
# a system service can't depend on a user service, so just launch it at graphical-session # a system service can't depend on a user service, so just launch it at graphical-session
systemd.user.services."pipewire".wantedBy = [ "graphical-session.target" ]; systemd.user.services."pipewire".wantedBy = [ "graphical-session.target" ];
programs.sway = { sane.home-manager.windowManager.sway = {
enable = true; enable = true;
wrapperFeatures.gtk = true; wrapperFeatures.gtk = true;
}; config = let
sane.user.fs.".config/sway/config" =
let
fuzzel = "${pkgs.fuzzel}/bin/fuzzel"; fuzzel = "${pkgs.fuzzel}/bin/fuzzel";
sed = "${pkgs.gnused}/bin/sed"; sed = "${pkgs.gnused}/bin/sed";
wtype = "${pkgs.wtype}/bin/wtype"; wtype = "${pkgs.wtype}/bin/wtype";
kitty = "${pkgs.kitty}/bin/kitty"; kitty = "${pkgs.kitty}/bin/kitty";
launcher-cmd = fuzzel;
terminal-cmd = kitty;
lock-cmd = "${pkgs.swaylock}/bin/swaylock --indicator-idle-visible --indicator-radius 100 --indicator-thickness 30"; lock-cmd = "${pkgs.swaylock}/bin/swaylock --indicator-idle-visible --indicator-radius 100 --indicator-thickness 30";
vol-up-cmd = "${pkgs.pulsemixer}/bin/pulsemixer --change-volume +5"; vol-up-cmd = "${pkgs.pulsemixer}/bin/pulsemixer --change-volume +5";
vol-down-cmd = "${pkgs.pulsemixer}/bin/pulsemixer --change-volume -5"; vol-down-cmd = "${pkgs.pulsemixer}/bin/pulsemixer --change-volume -5";
@@ -195,161 +181,184 @@ in
snip-cmd = "${wtype} $(${list-snips} | ${fuzzel} -d -i -w 60 | ${strip-comments})"; snip-cmd = "${wtype} $(${list-snips} | ${fuzzel} -d -i -w 60 | ${strip-comments})";
# TODO: next splatmoji release should allow `-s none` to disable skin tones # TODO: next splatmoji release should allow `-s none` to disable skin tones
emoji-cmd = "${pkgs.splatmoji}/bin/splatmoji -s medium-light type"; emoji-cmd = "${pkgs.splatmoji}/bin/splatmoji -s medium-light type";
in sane-lib.fs.wantedText '' in rec {
### default font terminal = kitty;
font pango:monospace 8 window = {
border = 3; # pixel boundary between windows
hideEdgeBorders = "smart"; # don't show border if only window on workspace
};
output = {
### DESKTOP
"Samsung Electric Company S22C300 0x00007F35" = { pos = "0,0"; res = "1920x1080"; };
"Goldstar Company Ltd LG ULTRAWIDE 0x00004E94" = { pos = "1920,0"; res = "3440x1440"; };
### pixel boundary between windows ### LAPTOP
default_border pixel 3 # shen TV
default_floating_border pixel 2 "Pioneer Electronic Corporation VSX-524 0x00000101" = { pos = "0,0"; res = "1920x1080"; };
hide_edge_borders smart # internal display
"Unknown 0x0637 0x00000000" = { pos = "1920,0"; res = "1920x1080"; };
};
### defaults # defaults; required for keybindings decl.
focus_wrapping no modifier = "Mod1";
focus_follows_mouse yes # list of launchers: https://www.reddit.com/r/swaywm/comments/v39hxa/your_favorite_launcher/
focus_on_window_activation smart # menu = "${pkgs.dmenu}/bin/dmenu_path";
mouse_warping output menu = fuzzel;
workspace_layout default # menu = "${pkgs.albert}/bin/albert";
workspace_auto_back_and_forth no left = "h";
down = "j";
up = "k";
right = "l";
# XKB key names: https://wiki.linuxquestions.org/wiki/List_of_Keysyms_Recognised_by_Xmodmap
keybindings = {
"${modifier}+Return" = "exec ${terminal}";
"${modifier}+Shift+q" = "kill";
"${modifier}+d" = "exec ${menu}";
"${modifier}+s" = "exec ${snip-cmd}";
"${modifier}+l" = "exec ${lock-cmd}";
"${modifier}+slash" = "exec ${emoji-cmd}";
### default colors (#border #background #text #indicator #childBorder) # "${modifier}+${left}" = "focus left";
client.focused #4c7899 #285577 #ffffff #2e9ef4 #285577 # "${modifier}+${down}" = "focus down";
client.focused_inactive #333333 #5f676a #ffffff #484e50 #5f676a # "${modifier}+${up}" = "focus up";
client.unfocused #333333 #222222 #888888 #292d2e #222222 # "${modifier}+${right}" = "focus right";
client.urgent #2f343a #900000 #ffffff #900000 #900000
client.placeholder #000000 #0c0c0c #ffffff #000000 #0c0c0c
client.background #ffffff
### key bindings "${modifier}+Left" = "focus left";
floating_modifier Mod1 "${modifier}+Down" = "focus down";
## media keys "${modifier}+Up" = "focus up";
bindsym XF86AudioRaiseVolume exec ${vol-up-cmd} "${modifier}+Right" = "focus right";
bindsym XF86AudioLowerVolume exec ${vol-down-cmd}
bindsym Mod1+Page_Up exec ${vol-up-cmd}
bindsym Mod1+Page_Down exec ${vol-down-cmd}
bindsym XF86AudioMute exec ${mute-cmd}
bindsym XF86MonBrightnessUp exec ${brightness-up-cmd}
bindsym XF86MonBrightnessDown exec ${brightness-down-cmd}
## special functions
bindsym Mod1+Print exec ${screenshot-cmd}
bindsym Mod1+l exec ${lock-cmd}
bindsym Mod1+s exec ${snip-cmd}
bindsym Mod1+slash exec ${emoji-cmd}
bindsym Mod1+d exec ${launcher-cmd}
bindsym Mod1+Return exec ${terminal-cmd}
bindsym Mod1+Shift+q kill
bindsym Mod1+Shift+e exec swaynag -t warning -m 'You pressed the exit shortcut. Do you really want to exit sway? This will end your Wayland session.' -b 'Yes, exit sway' 'swaymsg exit'
bindsym Mod1+Shift+c reload
## layout
bindsym Mod1+b splith
bindsym Mod1+v splitv
bindsym Mod1+f fullscreen toggle
bindsym Mod1+a focus parent
bindsym Mod1+w layout tabbed
bindsym Mod1+e layout toggle split
bindsym Mod1+Shift+space floating toggle
bindsym Mod1+space focus mode_toggle
bindsym Mod1+r mode resize
## movement
bindsym Mod1+Up focus up
bindsym Mod1+Down focus down
bindsym Mod1+Left focus left
bindsym Mod1+Right focus right
bindsym Mod1+Shift+Up move up
bindsym Mod1+Shift+Down move down
bindsym Mod1+Shift+Left move left
bindsym Mod1+Shift+Right move right
## workspaces
bindsym Mod1+1 workspace number 1
bindsym Mod1+2 workspace number 2
bindsym Mod1+3 workspace number 3
bindsym Mod1+4 workspace number 4
bindsym Mod1+5 workspace number 5
bindsym Mod1+6 workspace number 6
bindsym Mod1+7 workspace number 7
bindsym Mod1+8 workspace number 8
bindsym Mod1+9 workspace number 9
bindsym Mod1+Shift+1 move container to workspace number 1
bindsym Mod1+Shift+2 move container to workspace number 2
bindsym Mod1+Shift+3 move container to workspace number 3
bindsym Mod1+Shift+4 move container to workspace number 4
bindsym Mod1+Shift+5 move container to workspace number 5
bindsym Mod1+Shift+6 move container to workspace number 6
bindsym Mod1+Shift+7 move container to workspace number 7
bindsym Mod1+Shift+8 move container to workspace number 8
bindsym Mod1+Shift+9 move container to workspace number 9
## "scratchpad" = ??
bindsym Mod1+Shift+minus move scratchpad
bindsym Mod1+minus scratchpad show
### defaults # "${modifier}+Shift+${left}" = "move left";
mode "resize" { # "${modifier}+Shift+${down}" = "move down";
bindsym Down resize grow height 10 px # "${modifier}+Shift+${up}" = "move up";
bindsym Escape mode default # "${modifier}+Shift+${right}" = "move right";
bindsym Left resize shrink width 10 px
bindsym Return mode default
bindsym Right resize grow width 10 px
bindsym Up resize shrink height 10 px
bindsym h resize shrink width 10 px
bindsym j resize grow height 10 px
bindsym k resize shrink height 10 px
bindsym l resize grow width 10 px
}
### lightly modified bars "${modifier}+Shift+Left" = "move left";
bar { "${modifier}+Shift+Down" = "move down";
# TODO: fonts was: "${modifier}+Shift+Up" = "move up";
# config.fonts.fontconfig.defaultFonts; (monospace ++ emoji) "${modifier}+Shift+Right" = "move right";
font pango:Hack, Font Awesome 6 Free, Twitter Color Emoji 24.000000
mode dock
hidden_state hide
position top
status_command ${pkgs.i3status}/bin/i3status
swaybar_command ${pkgs.waybar}/bin/waybar
workspace_buttons yes
strip_workspace_numbers no
tray_output primary
colors {
background #000000
statusline #ffffff
separator #666666
# #border #background #text
focused_workspace #4c7899 #285577 #ffffff
active_workspace #333333 #5f676a #ffffff
inactive_workspace #333333 #222222 #888888
urgent_workspace #2f343a #900000 #ffffff
binding_mode #2f343a #900000 #ffffff
}
}
### displays "${modifier}+b" = "splith";
## DESKTOP "${modifier}+v" = "splitv";
output "Samsung Electric Company S22C300 0x00007F35" { "${modifier}+f" = "fullscreen toggle";
pos 0,0 "${modifier}+a" = "focus parent";
res 1920x1080
}
output "Goldstar Company Ltd LG ULTRAWIDE 0x00004E94" {
pos 1920,0
res 3440x1440
}
## LAPTOP # "${modifier}+s" = "layout stacking";
# sh/en TV "${modifier}+w" = "layout tabbed";
output "Pioneer Electronic Corporation VSX-524 0x00000101" { "${modifier}+e" = "layout toggle split";
pos 0,0
res 1920x1080
}
# internal display
output "Unknown 0x0637 0x00000000" {
pos 1920,0
res 1920x1080
}
'';
sane.user.fs.".config/waybar/config" = sane-lib.fs.wantedSymlinkTo waybar-config-text; "${modifier}+Shift+space" = "floating toggle";
"${modifier}+space" = "focus mode_toggle";
"${modifier}+1" = "workspace number 1";
"${modifier}+2" = "workspace number 2";
"${modifier}+3" = "workspace number 3";
"${modifier}+4" = "workspace number 4";
"${modifier}+5" = "workspace number 5";
"${modifier}+6" = "workspace number 6";
"${modifier}+7" = "workspace number 7";
"${modifier}+8" = "workspace number 8";
"${modifier}+9" = "workspace number 9";
"${modifier}+Shift+1" =
"move container to workspace number 1";
"${modifier}+Shift+2" =
"move container to workspace number 2";
"${modifier}+Shift+3" =
"move container to workspace number 3";
"${modifier}+Shift+4" =
"move container to workspace number 4";
"${modifier}+Shift+5" =
"move container to workspace number 5";
"${modifier}+Shift+6" =
"move container to workspace number 6";
"${modifier}+Shift+7" =
"move container to workspace number 7";
"${modifier}+Shift+8" =
"move container to workspace number 8";
"${modifier}+Shift+9" =
"move container to workspace number 9";
"${modifier}+Shift+minus" = "move scratchpad";
"${modifier}+minus" = "scratchpad show";
"${modifier}+Shift+c" = "reload";
"${modifier}+Shift+e" =
"exec swaynag -t warning -m 'You pressed the exit shortcut. Do you really want to exit sway? This will end your Wayland session.' -b 'Yes, exit sway' 'swaymsg exit'";
"${modifier}+r" = "mode resize";
# media keys
XF86MonBrightnessDown = "exec ${brightness-down-cmd}";
XF86MonBrightnessUp = "exec ${brightness-up-cmd}";
# TODO: hook into a visual prompt to display volume?
XF86AudioRaiseVolume = "exec ${vol-up-cmd}";
XF86AudioLowerVolume = "exec ${vol-down-cmd}";
XF86AudioMute = "exec ${mute-cmd}";
"${modifier}+Page_Up" = "exec ${vol-up-cmd}";
"${modifier}+Page_Down" = "exec ${vol-down-cmd}";
"${modifier}+Print" = "exec ${screenshot-cmd}";
};
# mostly defaults:
bars = [{
mode = "dock";
hiddenState = "hide";
position = "top";
command = "${pkgs.waybar}/bin/waybar";
workspaceButtons = true;
workspaceNumbers = true;
statusCommand = "${pkgs.i3status}/bin/i3status";
fonts = {
# names = [ "monospace" "Noto Color Emoji" ];
# size = 8.0;
# names = [ "Font Awesome 6 Free" "DejaVu Sans" "Hack" ];
# names = with config.fonts.fontconfig.defaultFonts; (emoji ++ monospace ++ serif ++ sansSerif);
names = with config.fonts.fontconfig.defaultFonts; (monospace ++ emoji);
size = 24.0;
};
trayOutput = "primary";
colors = {
background = "#000000";
statusline = "#ffffff";
separator = "#666666";
focusedWorkspace = {
border = "#4c7899";
background = "#285577";
text = "#ffffff";
};
activeWorkspace = {
border = "#333333";
background = "#5f676a";
text = "#ffffff";
};
inactiveWorkspace = {
border = "#333333";
background = "#222222";
text = "#888888";
};
urgentWorkspace = {
border = "#2f343a";
background = "#900000";
text = "#ffffff";
};
bindingMode = {
border = "#2f343a";
background = "#900000";
text = "#ffffff";
};
};
}];
};
};
sane.fs."/home/colin/.config/waybar/config" = sane-lib.fs.wantedText waybar-config-text;
# style docs: https://github.com/Alexays/Waybar/wiki/Styling # style docs: https://github.com/Alexays/Waybar/wiki/Styling
sane.user.fs.".config/waybar/style.css" = sane-lib.fs.wantedText '' sane.fs."/home/colin/.config/waybar/style.css" = sane-lib.fs.wantedText ''
* { * {
font-family: monospace; font-family: monospace;
} }

View File

@@ -0,0 +1,52 @@
# 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,13 +20,9 @@ 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: joinAttrsets :: [AttrSet] -> AttrSet # Type: flattenAttrsList :: [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.joinAttrsetsRecursive merged; sane-lib.joinAttrsets 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

@@ -25,7 +25,6 @@ let
ifuse ifuse
imagemagick imagemagick
ipfs ipfs
kitty # TODO: move to GUI, but `ssh servo` from kitty sets `TERM=xterm-kitty` in the remove and breaks things
libimobiledevice libimobiledevice
libsecret # for managing user keyrings libsecret # for managing user keyrings
lm_sensors # for sensors-detect lm_sensors # for sensors-detect
@@ -108,10 +107,12 @@ let
{ pkg = gpodder-configured; dir = [ "gPodder" ]; } { pkg = gpodder-configured; dir = [ "gPodder" ]; }
gthumb gthumb
handbrake
inkscape inkscape
kdenlive kdenlive
kid3 # audio tagging kid3 # audio tagging
kitty
krita krita
libreoffice-fresh # XXX colin: maybe don't want this on mobile libreoffice-fresh # XXX colin: maybe don't want this on mobile
lollypop lollypop
@@ -129,7 +130,7 @@ let
".local/share/nheko" # per-account state database ".local/share/nheko" # per-account state database
]; } ]; }
# settings (electron app) # settings (electron app). TODO: can i manage these settings with home-manager?
{ pkg = obsidian; dir = [ ".config/obsidian" ]; } { pkg = obsidian; dir = [ ".config/obsidian" ]; }
pavucontrol pavucontrol
@@ -173,9 +174,6 @@ let
# gnome.zenity # for kaiteki (it will use qarma, kdialog, or zenity) # gnome.zenity # for kaiteki (it will use qarma, kdialog, or zenity)
# gpt2tc # XXX: unreliable mirror # gpt2tc # XXX: unreliable mirror
# TODO(unpin): handbrake is broken on aarch64-linux 2023/01/29
handbrake
logseq logseq
losslesscut-bin losslesscut-bin
makemkv makemkv
@@ -186,7 +184,7 @@ let
# creds, media # creds, media
{ pkg = signal-desktop; private = [ ".config/Signal" ]; } { pkg = signal-desktop; private = [ ".config/Signal" ]; }
# creds, widevine .so download. TODO: could easily manage these statically. # creds. TODO: can i manage this with home-manager?
{ pkg = spotify; dir = [ ".config/spotify" ]; } { pkg = spotify; dir = [ ".config/spotify" ]; }
# hardenedMalloc solves a crash at startup # hardenedMalloc solves a crash at startup
@@ -322,8 +320,8 @@ in
config = { config = {
environment.systemPackages = mkIf cfg.enableSystemPkgs systemPkgs; environment.systemPackages = mkIf cfg.enableSystemPkgs systemPkgs;
sane.user.persist.plaintext = concatLists (map (p: p.dir) cfg.enabledUserPkgs); sane.persist.home.plaintext = concatLists (map (p: p.dir) cfg.enabledUserPkgs);
sane.user.persist.private = concatLists (map (p: p.private) 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? # 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/*"; environment.etc."ssl/certs".source = mkIf cfg.enableSystemPkgs "${pkgs.cacert.unbundled}/etc/ssl/certs/*";
}; };

View File

@@ -0,0 +1,18 @@
{ 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,11 +179,23 @@ 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 = {};
@@ -194,6 +206,7 @@ in
}; };
imports = [ imports = [
./computed.nix
./root-on-tmpfs.nix ./root-on-tmpfs.nix
./stores ./stores
]; ];
@@ -234,7 +247,7 @@ in
); );
} }
]; ];
configs = lib.mapAttrsToList cfgFor cfg.sys.byPath; configs = lib.mapAttrsToList cfgFor cfg.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,10 +1,14 @@
{ config, lib, pkgs, sane-lib, utils, ... }: { config, lib, pkgs, utils, ... }:
let let
persist-base = config.sane.persist.stores."plaintext".origin; store = rec {
device = config.sane.persist.stores."cryptClearOnBoot".origin; device = "/mnt/persist/crypt/clearedonboot";
key = "${device}.key"; underlying = {
underlying = sane-lib.path.concat [ persist-base "crypt/clearedonboot" ]; path = "/nix/persist/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
{ {
@@ -13,35 +17,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 = lib.mkDefault "/mnt/persist/crypt/clearedonboot"; origin = store.device;
}; };
fileSystems."${device}" = { fileSystems."${store.device}" = {
device = underlying; device = store.underlying.path;
fsType = "fuse.gocryptfs"; fsType = "fuse.gocryptfs";
options = [ options = [
"nodev" "nodev"
"nosuid" "nosuid"
"allow_other" "allow_other"
"passfile=${key}" "passfile=${store.underlying.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."${device}".mount = { sane.fs."${store.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."${underlying}/gocryptfs.conf"; cryptfile = config.sane.fs."${store.underlying.path}/gocryptfs.conf";
keyfile = config.sane.fs."${key}"; keyfile = config.sane.fs."${store.underlying.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."${underlying}/gocryptfs.conf".generated = { sane.fs."${store.underlying.path}/gocryptfs.conf".generated = {
script.script = '' script.script = ''
backing="$1" backing="$1"
passfile="$2" passfile="$2"
@@ -50,17 +54,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 = [ underlying key ]; script.scriptArgs = [ store.underlying.path store.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."${key}".unit ]; depends = [ config.sane.fs."${store.underlying.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."${key}".generated = { sane.fs."${store.underlying.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 = [ key ]; script.scriptArgs = [ store.underlying.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" = lib.mkDefault { sane.persist.stores."plaintext" = {
origin = "/nix/persist"; origin = "/nix/persist";
}; };
# TODO: needed? # TODO: needed?

View File

@@ -1,23 +1,21 @@
{ config, lib, pkgs, sane-lib, utils, ... }: { config, lib, pkgs, 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 store which persists across boots. encrypted to the user's password and auto-unlocked at login
typical use case is for the user to encrypt this store using their login password so that it
can be auto-unlocked at login.
''; '';
origin = lib.mkDefault "/mnt/private"; origin = "/home/colin/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."${private-dir}".unit; private-unit = config.sane.fs."/home/colin/private".unit;
in { in {
# auto create only after the store is mounted # auto create only after ~/private 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 = [ ];
@@ -25,13 +23,13 @@ lib.mkIf config.sane.persist.enable
defaultMethod = "symlink"; defaultMethod = "symlink";
}; };
fileSystems."${private-dir}" = { fileSystems."/home/colin/private" = {
device = private-backing-dir; device = "/nix/persist/home/colin/private";
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 other users. "allow_other" # root ends up being the user that mounts this, so need to make it visible to `colin`.
"nodev" "nodev"
"nosuid" "nosuid"
"quiet" "quiet"
@@ -41,9 +39,9 @@ lib.mkIf config.sane.persist.enable
}; };
# let sane.fs know about the mount # let sane.fs know about the mount
sane.fs."${private-dir}".mount = {}; sane.fs."/home/colin/private".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."${private-backing-dir}".dir = {}; sane.fs."/nix/persist/home/colin/private".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

View File

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

View File

@@ -1,110 +0,0 @@
{ 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,5 +8,27 @@
# 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
; ;
}) })