Compare commits
112 Commits
wip-doofne
...
save-geocl
Author | SHA1 | Date | |
---|---|---|---|
bcd467e60e | |||
304c8f8e3e | |||
5a09a2665b | |||
209545fc41 | |||
1e12566207 | |||
9a53cbc833 | |||
439bb5263f | |||
845dba3ca5 | |||
5e7fe850ec | |||
832338488d | |||
86ee95f607 | |||
5f5e55c98b | |||
7d59782005 | |||
62b541012b | |||
514197a17f | |||
143bdf672b | |||
a6c48eda71 | |||
a603c3e6bc | |||
1f48f41927 | |||
c0d9f05575 | |||
7f46b034f9 | |||
ba66378bc0 | |||
dcc8168aa0 | |||
f7d3c26d12 | |||
3d871e8d7c | |||
78f4cd9be2 | |||
f83bac3c2b | |||
58de5d661f | |||
599832d59c | |||
625cb0992b | |||
a02f221628 | |||
ad8bcfc09e | |||
815ce6287f | |||
0d1d56870f | |||
2445b882c2 | |||
12465e111e | |||
65a0914828 | |||
dab60e79c1 | |||
fe57f186cd | |||
78d66a8b09 | |||
b2955c9c9d | |||
b0e184b0f0 | |||
3cd97b522c | |||
c91681c77c | |||
d0d623da15 | |||
0db86d8c86 | |||
b74dfe7578 | |||
d1843b6b3d | |||
b482a1dfd6 | |||
5ba74a4055 | |||
b3b77e3e62 | |||
63bc58a56f | |||
efcf8639dc | |||
90b86dc7fc | |||
8bf8d31c5f | |||
2e44abc55d | |||
9e92069ba3 | |||
2a592a4a15 | |||
8ca357ea7f | |||
4f4c05a922 | |||
7c4be0f4e9 | |||
afea7fe5e7 | |||
294f0061bd | |||
4efe159933 | |||
b7f99c022b | |||
b3c5e53156 | |||
91c2b04ab4 | |||
27efb10a27 | |||
e4e32f46fe | |||
64b169069a | |||
c2c15e1ac3 | |||
0b3156c4c7 | |||
1c8551c842 | |||
2755d98b99 | |||
543108a5dd | |||
b32d02dc3f | |||
0bd92ef77e | |||
a7df4cc125 | |||
09a615ee62 | |||
8523b406ad | |||
6021da072c | |||
a49abbd123 | |||
f9091c0b0c | |||
bbf8fd5b20 | |||
be84747ffc | |||
478b443430 | |||
ded5f6560d | |||
c1b3629dcf | |||
5879499924 | |||
5a63f294c0 | |||
891a29feeb | |||
0863505877 | |||
0c922bd63a | |||
e04ec4c706 | |||
b0f9733ac8 | |||
e2babfc076 | |||
ef29b569e5 | |||
6f0a455d0b | |||
7d6a420c52 | |||
259143b87e | |||
fce426c318 | |||
9b794777b5 | |||
3ada668366 | |||
39a39e763d | |||
50353280d3 | |||
72b8211029 | |||
dbf719b59b | |||
57d7d3821f | |||
e86e9fc079 | |||
d708b78ebe | |||
075418eda1 | |||
9fc5b83b61 |
11
TODO.md
11
TODO.md
@@ -15,7 +15,7 @@
|
||||
- decrease s6 restart time?
|
||||
- `ssh` access doesn't grant same linux capabilities as login
|
||||
- ringer (i.e. dino incoming call) doesn't prevent moby from sleeping
|
||||
- sysvol (volume overlay): when casting with `blast`, sysvol doesn't react to volume changes
|
||||
- syshud (volume overlay): when casting with `blast`, syshud doesn't react to volume changes
|
||||
- moby: kaslr is effectively disabled
|
||||
- `dmesg | grep "KASLR disabled due to lack of seed"`
|
||||
- fix by adding `kaslrseed` to uboot script before `booti`
|
||||
@@ -26,6 +26,11 @@
|
||||
- `dmesg | grep 'hid_bpf: error while preloading HID BPF dispatcher: -22'`
|
||||
- `s6` is not re-entrant
|
||||
- so if the desktop crashes, the login process from `unl0kr` fails to re-launch the GUI
|
||||
- swaync brightness slider does not work
|
||||
- it reads brightness from /sys/class/backlight/....
|
||||
- but to *set* the brightness it assumes systemd logind is running
|
||||
<repo:ErikReider/SwayNotificationCenter:src/controlCenter/widgets/backlight/backlightUtil.vala>
|
||||
no reason i can't just write to that file, or exec brightnessctl (if i learn vala)
|
||||
|
||||
## REFACTORING:
|
||||
- add import checks to my Python nix-shell scripts
|
||||
@@ -126,11 +131,9 @@
|
||||
- add option to change audio output
|
||||
- fix colors (red alert) to match overall theme
|
||||
- moby: tune GPS
|
||||
- run only geoclue, and not gpsd, to save power?
|
||||
- tune QGPS setting in eg25-control, for less jitter?
|
||||
- direct mepo to prefer gpsd, with fallback to geoclue, for better accuracy?
|
||||
- configure geoclue to do some smoothing?
|
||||
- manually do smoothing, as some layer between mepo and geoclue/gpsd?
|
||||
- manually do smoothing, as some layer between mepo and geoclue?
|
||||
- moby: port `freshen-agps` timer service to s6 (maybe i want some `s6-cron` or something)
|
||||
- moby: show battery state on ssh login
|
||||
- moby: improve gPodder launch time
|
||||
|
70
default.nix
70
default.nix
@@ -1,67 +1,5 @@
|
||||
# limited, non-flake interface to this repo.
|
||||
# this file exposes the same view into `pkgs` which the flake would see when evaluated.
|
||||
#
|
||||
# the primary purpose of this file is so i can run `updateScript`s which expect
|
||||
# the root to be `default.nix`
|
||||
{ }:
|
||||
{ ... }@args:
|
||||
let
|
||||
mkPkgs = args: (import ./pkgs/additional/nixpkgs args).extend
|
||||
(import ./overlays/all.nix);
|
||||
inherit (mkPkgs {}) lib;
|
||||
|
||||
evalHost = { name, system, branch ? "master", variant ? null }:
|
||||
let
|
||||
pkgs = mkPkgs { inherit system; variant = branch; };
|
||||
in pkgs.nixos (
|
||||
[
|
||||
(lib.optionalAttrs (variant == "light") {
|
||||
sane.maxBuildCost = 2;
|
||||
})
|
||||
(lib.optionalAttrs (variant == "min") {
|
||||
sane.maxBuildCost = 0;
|
||||
})
|
||||
(import ./hosts/instantiate.nix { hostName = name; })
|
||||
(import ./modules)
|
||||
pkgs.sops-nix.nixosModules.sops
|
||||
]
|
||||
);
|
||||
mkFlavoredHost = args: let
|
||||
host = evalHost args;
|
||||
# expose the toplevel nixos system as the toplevel attribute itself,
|
||||
# with nested aliases for other common build targets
|
||||
in host.config.system.build.toplevel.overrideAttrs (base: {
|
||||
passthru = (base.passthru or {}) // {
|
||||
config = host.config;
|
||||
fs = host.config.sane.fs;
|
||||
img = host.config.system.build.img;
|
||||
pkgs = host.config.system.build.pkgs;
|
||||
programs = lib.mapAttrs (_: p: p.package) host.config.sane.programs;
|
||||
toplevel = host.config.system.build.toplevel; #< self
|
||||
};
|
||||
});
|
||||
mkHost = args: {
|
||||
# TODO: swap order: $host-{next,staging}-{min,light}:
|
||||
# then lexicographically-adjacent targets would also have the minimal difference in closure,
|
||||
# and the order in which each target should be built is more evident
|
||||
"${args.name}" = mkFlavoredHost args;
|
||||
"${args.name}-next" = mkFlavoredHost args // { branch = "staging-next"; };
|
||||
"${args.name}-staging" = mkFlavoredHost args // { branch = "staging"; };
|
||||
"${args.name}-light" = mkFlavoredHost args // { variant = "light"; };
|
||||
"${args.name}-light-next" = mkFlavoredHost args // { variant = "light"; branch = "staging-next"; };
|
||||
"${args.name}-light-staging" = mkFlavoredHost args // { variant = "light"; branch = "staging"; };
|
||||
"${args.name}-min" = mkFlavoredHost args // { variant = "min"; };
|
||||
"${args.name}-min-next" = mkFlavoredHost args // { variant = "min"; branch = "staging-next"; };
|
||||
"${args.name}-min-staging" = mkFlavoredHost args // { variant = "min"; branch = "staging-staging"; };
|
||||
};
|
||||
|
||||
hosts = lib.foldl' (acc: host: acc // (mkHost host)) {} [
|
||||
{ name = "crappy"; system = "armv7l-linux"; }
|
||||
{ name = "desko"; system = "x86_64-linux"; }
|
||||
{ name = "lappy"; system = "x86_64-linux"; }
|
||||
{ name = "moby"; system = "aarch64-linux"; }
|
||||
{ name = "rescue"; system = "x86_64-linux"; }
|
||||
{ name = "servo"; system = "x86_64-linux"; }
|
||||
];
|
||||
in {
|
||||
inherit hosts;
|
||||
} // (mkPkgs {})
|
||||
sane-nix-files = import ./pkgs/additional/sane-nix-files { };
|
||||
in
|
||||
import "${sane-nix-files}/impure.nix" args
|
||||
|
@@ -25,6 +25,7 @@
|
||||
sane.programs.dino.config.autostart = false;
|
||||
sane.programs.dissent.config.autostart = false;
|
||||
sane.programs.fractal.config.autostart = false;
|
||||
sane.programs.sway.config.mod = "Mod1"; #< alt key instead of Super
|
||||
|
||||
# sane.programs.guiApps.enableFor.user.colin = false;
|
||||
|
||||
|
@@ -10,7 +10,6 @@
|
||||
{
|
||||
imports = [
|
||||
./fs.nix
|
||||
./gps.nix
|
||||
];
|
||||
|
||||
sane.hal.pine64.enable = true;
|
||||
@@ -29,6 +28,7 @@
|
||||
sops.secrets.colin-passwd.neededForUsers = true;
|
||||
|
||||
sane.programs.sway.enableFor.user.colin = true;
|
||||
sane.programs.sway.config.mod = "Mod1"; #< alt key instead of Super
|
||||
sane.programs.blueberry.enableFor.user.colin = false; # bluetooth manager: doesn't cross compile!
|
||||
sane.programs.fcitx5.enableFor.user.colin = false; # does not cross compile
|
||||
sane.programs.mercurial.enableFor.user.colin = false; # does not cross compile
|
||||
|
@@ -1,68 +0,0 @@
|
||||
# pinephone GPS happens in EG25 modem
|
||||
# serial control interface to modem is /dev/ttyUSB2
|
||||
# after enabling GPS, readout is /dev/ttyUSB1
|
||||
#
|
||||
# minimal process to enable modem and GPS:
|
||||
# - `echo 1 > /sys/class/modem-power/modem-power/device/powered`
|
||||
# - `screen /dev/ttyUSB2 115200`
|
||||
# - `AT+QGPSCFG="nmeasrc",1`
|
||||
# - `AT+QGPS=1`
|
||||
# this process is automated by my `eg25-control` program and services (`eg25-control-powered`, `eg25-control-gps`)
|
||||
# - see the `modules/` directory further up this repository.
|
||||
#
|
||||
# now, something like `gpsd` can directly read from /dev/ttyUSB1,
|
||||
# or geoclue can query the GPS directly through modem-manager
|
||||
#
|
||||
# initial GPS fix can take 15+ minutes.
|
||||
# meanwhile, services like eg25-manager or eg25-control-freshen-agps can speed this up by uploading assisted GPS data to the modem.
|
||||
#
|
||||
# support/help:
|
||||
# - geoclue, gnome-maps
|
||||
# - irc: #gnome-maps on irc.gimp.org
|
||||
# - Matrix: #gnome-maps:gnome.org (unclear if bridged to IRC)
|
||||
#
|
||||
# programs to pair this with:
|
||||
# - `satellite-gtk`: <https://codeberg.org/tpikonen/satellite>
|
||||
# - shows/tracks which satellites the GPS is connected to; useful to understand fix characteristics
|
||||
# - `gnome-maps`: uses geoclue, has route planning
|
||||
# - `mepo`: uses gpsd, minimalist, flaky, and buttons are kinda hard to activate on mobile
|
||||
# - puremaps?
|
||||
# - osmin?
|
||||
#
|
||||
# known/outstanding bugs:
|
||||
# - `systemctl start eg25-control-gps` can the hang the whole system (2023/10/06)
|
||||
# - i think it's actually `eg25-control-powered` which does this (started by the gps)
|
||||
# - best guess is modem draws so much power at launch that other parts of the system see undervoltage
|
||||
# - workaround is to hard power-cycle the system. the modem may not bring up after reboot: leave unpowered for 60s and boot again.
|
||||
#
|
||||
# future work:
|
||||
# - integrate with [wigle](https://www.wigle.net/) for offline equivalent to Mozilla Location Services
|
||||
|
||||
{ config, lib, ... }:
|
||||
{
|
||||
# test gpsd with `gpspipe -w -n 10 2> /dev/null | grep -m 1 TPV | jq '.lat, .lon' | tr '\n' ' '`
|
||||
# ^ should return <lat> <long>
|
||||
services.gpsd.enable = true;
|
||||
services.gpsd.devices = [ "/dev/ttyUSB1" ];
|
||||
|
||||
# test geoclue2 by building `geoclue2-with-demo-agent`
|
||||
# and running "${geoclue2-with-demo-agent}/libexec/geoclue-2.0/demos/where-am-i"
|
||||
# note that geoclue is dbus-activated, and auto-stops after 60s with no caller
|
||||
services.geoclue2.enable = true;
|
||||
services.geoclue2.appConfig.where-am-i = {
|
||||
# this is the default "agent", shipped by geoclue package: allow it to use location
|
||||
isAllowed = true;
|
||||
isSystem = false;
|
||||
# XXX: setting users != [] might be causing `where-am-i` to time out
|
||||
users = [
|
||||
# restrict to only one set of users. empty array (default) means "allow any user to access geolocation".
|
||||
(builtins.toString config.users.users.colin.uid)
|
||||
];
|
||||
};
|
||||
systemd.services.geoclue.after = lib.mkForce []; #< defaults to network-online, but not all my sources require network
|
||||
users.users.geoclue.extraGroups = [
|
||||
"dialout" # TODO: figure out if dialout is required. that's for /dev/ttyUSB1, but geoclue probably doesn't read that?
|
||||
];
|
||||
|
||||
sane.programs.where-am-i.enableFor.user.colin = true;
|
||||
}
|
@@ -36,7 +36,8 @@
|
||||
# - rb = received bytes
|
||||
# - sp = sent packets
|
||||
# - sb = sent bytes
|
||||
{ lib, ... }:
|
||||
|
||||
{ config, lib, ... }:
|
||||
let
|
||||
# TURN port range (inclusive).
|
||||
# default coturn behavior is to use the upper quarter of all ports. i.e. 49152 - 65535.
|
||||
@@ -130,11 +131,11 @@ in
|
||||
"verbose"
|
||||
# "Verbose" #< even MORE verbosity than "verbose" (it's TOO MUCH verbosity really)
|
||||
"no-multicast-peers" # disables sending to IPv4 broadcast addresses (e.g. 224.0.0.0/3)
|
||||
# "listening-ip=10.0.1.5" "external-ip=185.157.162.178" #< 2024/04/25: works, if running in root namespace
|
||||
"listening-ip=185.157.162.178" "external-ip=185.157.162.178"
|
||||
# "listening-ip=${config.sane.netns.ovpns.hostVethIpv4}" "external-ip=${config.sane.netns.ovpns.netnsPubIpv4}" #< 2024/04/25: works, if running in root namespace
|
||||
"listening-ip=${config.sane.netns.ovpns.netnsPubIpv4}" "external-ip=${config.sane.netns.ovpns.netnsPubIpv4}"
|
||||
|
||||
# old attempts:
|
||||
# "external-ip=185.157.162.178/10.0.1.5"
|
||||
# "external-ip=${config.sane.netns.ovpns.netnsPubIpv4}/${config.sane.netns.ovpns.hostVethIpv4}"
|
||||
# "listening-ip=10.78.79.51" # can be specified multiple times; omit for *
|
||||
# "external-ip=97.113.128.229/10.78.79.51"
|
||||
# "external-ip=97.113.128.229"
|
||||
|
@@ -51,54 +51,54 @@ lib.mkIf false
|
||||
{
|
||||
"3478" = {
|
||||
protocol = [ "tcp" "udp" ];
|
||||
visibleTo.doof = true;
|
||||
visibleTo.lan = true;
|
||||
visibleTo.wan = true;
|
||||
description = "colin-xmpp-stun-turn";
|
||||
};
|
||||
"5222" = {
|
||||
protocol = [ "tcp" ];
|
||||
visibleTo.doof = true;
|
||||
visibleTo.lan = true;
|
||||
visibleTo.wan = true;
|
||||
description = "colin-xmpp-client-to-server";
|
||||
};
|
||||
"5223" = {
|
||||
protocol = [ "tcp" ];
|
||||
visibleTo.doof = true;
|
||||
visibleTo.lan = true;
|
||||
visibleTo.wan = true;
|
||||
description = "colin-xmpps-client-to-server"; # XMPP over TLS
|
||||
};
|
||||
"5269" = {
|
||||
protocol = [ "tcp" ];
|
||||
visibleTo.wan = true;
|
||||
visibleTo.doof = true;
|
||||
description = "colin-xmpp-server-to-server";
|
||||
};
|
||||
"5270" = {
|
||||
protocol = [ "tcp" ];
|
||||
visibleTo.wan = true;
|
||||
visibleTo.doof = true;
|
||||
description = "colin-xmpps-server-to-server"; # XMPP over TLS
|
||||
};
|
||||
"5280" = {
|
||||
protocol = [ "tcp" ];
|
||||
visibleTo.doof = true;
|
||||
visibleTo.lan = true;
|
||||
visibleTo.wan = true;
|
||||
description = "colin-xmpp-bosh";
|
||||
};
|
||||
"5281" = {
|
||||
protocol = [ "tcp" ];
|
||||
visibleTo.doof = true;
|
||||
visibleTo.lan = true;
|
||||
visibleTo.wan = true;
|
||||
description = "colin-xmpp-bosh-https";
|
||||
};
|
||||
"5349" = {
|
||||
protocol = [ "tcp" ];
|
||||
visibleTo.doof = true;
|
||||
visibleTo.lan = true;
|
||||
visibleTo.wan = true;
|
||||
description = "colin-xmpp-stun-turn-over-tls";
|
||||
};
|
||||
"5443" = {
|
||||
protocol = [ "tcp" ];
|
||||
visibleTo.doof = true;
|
||||
visibleTo.lan = true;
|
||||
visibleTo.wan = true;
|
||||
description = "colin-xmpp-web-services"; # file uploads, websockets, admin
|
||||
};
|
||||
}
|
||||
@@ -109,8 +109,8 @@ lib.mkIf false
|
||||
numPorts = turnPortHigh - turnPortLow + 1;
|
||||
in {
|
||||
protocol = [ "tcp" "udp" ];
|
||||
visibleTo.doof = true;
|
||||
visibleTo.lan = true;
|
||||
visibleTo.wan = true;
|
||||
description = "colin-xmpp-turn-${builtins.toString count}-of-${builtins.toString numPorts}";
|
||||
};
|
||||
})
|
||||
|
@@ -8,14 +8,14 @@
|
||||
{
|
||||
sane.ports.ports."143" = {
|
||||
protocol = [ "tcp" ];
|
||||
visibleTo.doof = true;
|
||||
visibleTo.lan = true;
|
||||
visibleTo.wan = true;
|
||||
description = "colin-imap-imap.uninsane.org";
|
||||
};
|
||||
sane.ports.ports."993" = {
|
||||
protocol = [ "tcp" ];
|
||||
visibleTo.doof = true;
|
||||
visibleTo.lan = true;
|
||||
visibleTo.wan = true;
|
||||
description = "colin-imaps-imap.uninsane.org";
|
||||
};
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
# postfix config options: <https://www.postfix.org/postconf.5.html>
|
||||
|
||||
{ lib, pkgs, ... }:
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
submissionOptions = {
|
||||
@@ -56,8 +56,7 @@ in
|
||||
|
||||
sane.dns.zones."uninsane.org".inet = {
|
||||
MX."@" = "10 mx.uninsane.org.";
|
||||
# XXX: RFC's specify that the MX record CANNOT BE A CNAME
|
||||
A."mx" = "185.157.162.178";
|
||||
A."mx" = "%AOVPNS%"; #< XXX: RFC's specify that the MX record CANNOT BE A CNAME. TODO: use "%AOVPNS%?
|
||||
|
||||
# Sender Policy Framework:
|
||||
# +mx => mail passes if it originated from the MX
|
||||
|
@@ -12,6 +12,10 @@
|
||||
device = "/var/media";
|
||||
options = [ "rbind" ];
|
||||
};
|
||||
fileSystems."/var/export/pub" = {
|
||||
device = "/var/www/sites/uninsane.org/share";
|
||||
options = [ "rbind" ];
|
||||
};
|
||||
# fileSystems."/var/export/playground" = {
|
||||
# device = config.fileSystems."/mnt/persist/ext".device;
|
||||
# fsType = "btrfs";
|
||||
@@ -37,7 +41,8 @@
|
||||
wantedBy = [ "nfs.service" "sftpgo.service" ];
|
||||
file.text = ''
|
||||
- media/ read-only: Videos, Music, Books, etc
|
||||
- playground/ read-write: use it to share files with other users of this server
|
||||
- playground/ read-write: use it to share files with other users of this server, inaccessible from the www
|
||||
- pub/ read-only: content made to be shared with the www
|
||||
'';
|
||||
};
|
||||
|
||||
|
@@ -27,13 +27,12 @@ in
|
||||
"21" = {
|
||||
protocol = [ "tcp" ];
|
||||
visibleTo.lan = true;
|
||||
# visibleTo.wan = true;
|
||||
description = "colin-FTP server";
|
||||
};
|
||||
"990" = {
|
||||
protocol = [ "tcp" ];
|
||||
visibleTo.doof = true;
|
||||
visibleTo.lan = true;
|
||||
visibleTo.wan = true;
|
||||
description = "colin-FTPS server";
|
||||
};
|
||||
} // (sane-lib.mapToAttrs
|
||||
@@ -41,8 +40,8 @@ in
|
||||
name = builtins.toString port;
|
||||
value = {
|
||||
protocol = [ "tcp" ];
|
||||
visibleTo.doof = true;
|
||||
visibleTo.lan = true;
|
||||
visibleTo.wan = true;
|
||||
description = "colin-FTP server data port range";
|
||||
};
|
||||
})
|
||||
@@ -101,6 +100,13 @@ in
|
||||
debug = true;
|
||||
tls_mode = 2; # 2 = "implicit FTPS": client negotiates TLS before any FTP command.
|
||||
}
|
||||
{
|
||||
# binding this means any doof client can connect (TLS only)
|
||||
address = config.sane.netns.doof.hostVethIpv4;
|
||||
port = 990;
|
||||
debug = true;
|
||||
tls_mode = 2; # 2 = "implicit FTPS": client negotiates TLS before any FTP command.
|
||||
}
|
||||
];
|
||||
|
||||
# active mode is susceptible to "bounce attacks", without much benefit over passive mode
|
||||
@@ -117,7 +123,7 @@ in
|
||||
banner = ''
|
||||
Welcome, friends, to Colin's FTP server! Also available via NFS on the same host, but LAN-only.
|
||||
|
||||
Read-only access (LAN-restricted):
|
||||
Read-only access (LAN clients see everything; WAN clients can only see /pub):
|
||||
Username: "anonymous"
|
||||
Password: "anonymous"
|
||||
|
||||
|
@@ -45,6 +45,8 @@ from hmac import compare_digest
|
||||
|
||||
authFail = dict(username="")
|
||||
|
||||
PERM_DENY = []
|
||||
PERM_LIST = [ "list" ]
|
||||
PERM_RO = [ "list", "download" ]
|
||||
PERM_RW = [
|
||||
# read-only:
|
||||
@@ -127,12 +129,14 @@ def getAuthResponse(ip: str, username: str, password: str) -> dict:
|
||||
return mkAuthOk(username, permissions = {
|
||||
"/": PERM_RW,
|
||||
"/playground": PERM_RW,
|
||||
"/pub": PERM_RO,
|
||||
})
|
||||
if isWireguard(ip):
|
||||
# allow any user from wireguard
|
||||
return mkAuthOk(username, permissions = {
|
||||
"/": PERM_RW,
|
||||
"/playground": PERM_RW,
|
||||
"/pub": PERM_RO,
|
||||
})
|
||||
if isLan(ip):
|
||||
if username == "anonymous":
|
||||
@@ -140,7 +144,19 @@ def getAuthResponse(ip: str, username: str, password: str) -> dict:
|
||||
return mkAuthOk("anonymous", permissions = {
|
||||
"/": PERM_RO,
|
||||
"/playground": PERM_RW,
|
||||
"/pub": PERM_RO,
|
||||
})
|
||||
if username == "anonymous":
|
||||
# anonymous users from the www can have even more limited access.
|
||||
# mostly because i need an easy way to test WAN connectivity :-)
|
||||
return mkAuthOk("anonymous", permissions = {
|
||||
# "/": PERM_DENY,
|
||||
"/": PERM_LIST, #< REQUIRED, even for lftp to list a subdir
|
||||
"/media": PERM_DENY,
|
||||
"/playground": PERM_DENY,
|
||||
"/pub": PERM_RO,
|
||||
# "/README.md": PERM_RO, #< does not work
|
||||
})
|
||||
|
||||
return authFail
|
||||
|
||||
|
@@ -133,7 +133,7 @@
|
||||
sane.ports.ports."22" = {
|
||||
protocol = [ "tcp" ];
|
||||
visibleTo.lan = true;
|
||||
visibleTo.wan = true;
|
||||
visibleTo.doof = true;
|
||||
description = "colin-git@git.uninsane.org";
|
||||
};
|
||||
}
|
||||
|
@@ -1,6 +1,5 @@
|
||||
{ lib, pkgs, ... }:
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
lib.mkIf false #< TODO: re-enable once confident of sandboxing
|
||||
{
|
||||
sane.persist.sys.byStore.plaintext = [
|
||||
# TODO: mode? we only need this to save Indexer creds ==> migrate to config?
|
||||
@@ -13,7 +12,7 @@ lib.mkIf false #< TODO: re-enable once confident of sandboxing
|
||||
systemd.services.jackett.serviceConfig = {
|
||||
# run this behind the OVPN static VPN
|
||||
NetworkNamespacePath = "/run/netns/ovpns";
|
||||
ExecStartPre = [ "${lib.getExe pkgs.sane-scripts.ip-check} --no-upnp --expect 185.157.162.178" ]; # abort if public IP is not as expected
|
||||
ExecStartPre = [ "${lib.getExe pkgs.sane-scripts.ip-check} --no-upnp --expect ${config.sane.netns.ovpns.netnsPubIpv4}" ]; # abort if public IP is not as expected
|
||||
|
||||
# patch jackett to listen on the public interfaces
|
||||
# ExecStart = lib.mkForce "${pkgs.jackett}/bin/Jackett --NoUpdates --DataFolder /var/lib/jackett/.config/Jackett --ListenPublic";
|
||||
@@ -25,8 +24,7 @@ lib.mkIf false #< TODO: re-enable once confident of sandboxing
|
||||
enableACME = true;
|
||||
# inherit kTLS;
|
||||
locations."/" = {
|
||||
# proxyPass = "http://ovpns.uninsane.org:9117";
|
||||
proxyPass = "http://10.0.1.6:9117";
|
||||
proxyPass = "http://${config.sane.netns.ovpns.netnsVethIpv4}:9117";
|
||||
recommendedProxySettings = true;
|
||||
};
|
||||
};
|
||||
|
@@ -4,12 +4,11 @@
|
||||
{ config, lib, ... }:
|
||||
|
||||
let
|
||||
ircServer = { name, additionalAddresses ? [], sasl ? true, port ? 6697 }: let
|
||||
ircServer = { name, additionalAddresses ? [], ssl ? true, sasl ? true, port ? if ssl then 6697 else 6667 }: let
|
||||
lowerName = lib.toLower name;
|
||||
in {
|
||||
# XXX sasl: appservice doesn't support NickServ identification (only SASL, or PASS if sasl = false)
|
||||
inherit name additionalAddresses sasl port;
|
||||
ssl = true;
|
||||
inherit additionalAddresses name port sasl ssl;
|
||||
botConfig = {
|
||||
# bot has no presence in IRC channel; only real Matrix users
|
||||
enabled = false;
|
||||
@@ -156,6 +155,10 @@ in
|
||||
# - #sxmo-offtopic
|
||||
};
|
||||
"irc.rizon.net" = ircServer { name = "Rizon"; };
|
||||
"wigle.net" = ircServer {
|
||||
name = "WiGLE";
|
||||
ssl = false;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@@ -17,7 +17,6 @@ in
|
||||
sane.ports.ports."80" = {
|
||||
protocol = [ "tcp" ];
|
||||
visibleTo.lan = true;
|
||||
visibleTo.wan = true;
|
||||
visibleTo.ovpns = true; # so that letsencrypt can procure a cert for the mx record
|
||||
visibleTo.doof = true;
|
||||
description = "colin-http-uninsane.org";
|
||||
@@ -25,7 +24,6 @@ in
|
||||
sane.ports.ports."443" = {
|
||||
protocol = [ "tcp" ];
|
||||
visibleTo.lan = true;
|
||||
visibleTo.wan = true;
|
||||
visibleTo.doof = true;
|
||||
description = "colin-https-uninsane.org";
|
||||
};
|
||||
|
@@ -86,7 +86,7 @@ in
|
||||
sane.ports.ports."${builtins.toString altPort}" = {
|
||||
protocol = [ "tcp" ];
|
||||
visibleTo.lan = true;
|
||||
visibleTo.wan = true;
|
||||
visibleTo.doof = true;
|
||||
description = "colin-ntfy.uninsane.org";
|
||||
};
|
||||
}
|
||||
|
@@ -62,8 +62,8 @@ in
|
||||
sane.ports.ports = lib.mkMerge (lib.forEach portRange (port: {
|
||||
"${builtins.toString port}" = {
|
||||
protocol = [ "tcp" ];
|
||||
visibleTo.doof = true;
|
||||
visibleTo.lan = true;
|
||||
visibleTo.wan = true;
|
||||
description = "colin-notification-waiter-${builtins.toString (port - portLow + 1)}-of-${builtins.toString numPorts}";
|
||||
};
|
||||
}));
|
||||
|
@@ -61,42 +61,42 @@ in
|
||||
];
|
||||
sane.ports.ports."5000" = {
|
||||
protocol = [ "tcp" ];
|
||||
visibleTo.doof = true;
|
||||
visibleTo.lan = true;
|
||||
visibleTo.wan = true;
|
||||
description = "colin-xmpp-prosody-fileshare-proxy65";
|
||||
};
|
||||
sane.ports.ports."5222" = {
|
||||
protocol = [ "tcp" ];
|
||||
visibleTo.doof = true;
|
||||
visibleTo.lan = true;
|
||||
visibleTo.wan = true;
|
||||
description = "colin-xmpp-client-to-server";
|
||||
};
|
||||
sane.ports.ports."5223" = {
|
||||
protocol = [ "tcp" ];
|
||||
visibleTo.doof = true;
|
||||
visibleTo.lan = true;
|
||||
visibleTo.wan = true;
|
||||
description = "colin-xmpps-client-to-server"; # XMPP over TLS
|
||||
};
|
||||
sane.ports.ports."5269" = {
|
||||
protocol = [ "tcp" ];
|
||||
visibleTo.wan = true;
|
||||
visibleTo.doof = true;
|
||||
description = "colin-xmpp-server-to-server";
|
||||
};
|
||||
sane.ports.ports."5270" = {
|
||||
protocol = [ "tcp" ];
|
||||
visibleTo.wan = true;
|
||||
visibleTo.doof = true;
|
||||
description = "colin-xmpps-server-to-server"; # XMPP over TLS
|
||||
};
|
||||
sane.ports.ports."5280" = {
|
||||
protocol = [ "tcp" ];
|
||||
visibleTo.doof = true;
|
||||
visibleTo.lan = true;
|
||||
visibleTo.wan = true;
|
||||
description = "colin-xmpp-bosh";
|
||||
};
|
||||
sane.ports.ports."5281" = {
|
||||
protocol = [ "tcp" ];
|
||||
visibleTo.doof = true;
|
||||
visibleTo.lan = true;
|
||||
visibleTo.wan = true;
|
||||
description = "colin-xmpp-prosody-https"; # necessary?
|
||||
};
|
||||
|
||||
|
@@ -32,7 +32,7 @@
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
locations."/" = {
|
||||
proxyPass = "http://10.0.1.6:5030";
|
||||
proxyPass = "http://${config.sane.netns.ovpns.netnsVethIpv4}:5030";
|
||||
proxyWebsockets = true;
|
||||
};
|
||||
};
|
||||
@@ -71,7 +71,7 @@
|
||||
systemd.services.slskd.serviceConfig = {
|
||||
# run this behind the OVPN static VPN
|
||||
NetworkNamespacePath = "/run/netns/ovpns";
|
||||
ExecStartPre = [ "${lib.getExe pkgs.sane-scripts.ip-check} --no-upnp --expect 185.157.162.178" ]; # abort if public IP is not as expected
|
||||
ExecStartPre = [ "${lib.getExe pkgs.sane-scripts.ip-check} --no-upnp --expect ${config.sane.netns.ovpns.netnsPubIpv4}" ]; # abort if public IP is not as expected
|
||||
|
||||
Restart = lib.mkForce "always"; # exits "success" when it fails to connect to soulseek server
|
||||
RestartSec = "60s";
|
||||
|
@@ -82,7 +82,6 @@ let
|
||||
'';
|
||||
};
|
||||
in
|
||||
lib.mkIf false #< TODO: re-enable once confident of sandboxing
|
||||
{
|
||||
sane.persist.sys.byStore.plaintext = [
|
||||
# TODO: mode? we need this specifically for the stats tracking in .config/
|
||||
@@ -106,8 +105,8 @@ lib.mkIf false #< TODO: re-enable once confident of sandboxing
|
||||
# DOCUMENTATION/options list: <https://github.com/transmission/transmission/blob/main/docs/Editing-Configuration-Files.md#options>
|
||||
|
||||
# message-level = 3; #< enable for debug logging. 0-3, default is 2.
|
||||
# 10.0.1.6 => allow rpc only from the root servo ns. it'll tunnel things to the net, if need be.
|
||||
rpc-bind-address = "10.0.1.6";
|
||||
# ovpns.netnsVethIpv4 => allow rpc only from the root servo ns. it'll tunnel things to the net, if need be.
|
||||
rpc-bind-address = config.sane.netns.ovpns.netnsVethIpv4;
|
||||
#rpc-host-whitelist = "bt.uninsane.org";
|
||||
#rpc-whitelist = "*.*.*.*";
|
||||
rpc-authentication-required = true;
|
||||
@@ -118,7 +117,7 @@ lib.mkIf false #< TODO: re-enable once confident of sandboxing
|
||||
rpc-whitelist-enabled = false;
|
||||
|
||||
# force behind ovpns in case the NetworkNamespace fails somehow
|
||||
bind-address-ipv4 = "185.157.162.178";
|
||||
bind-address-ipv4 = config.sane.netns.ovpns.netnsPubIpv4;
|
||||
port-forwarding-enabled = false;
|
||||
|
||||
# hopefully, make the downloads world-readable
|
||||
@@ -160,7 +159,7 @@ lib.mkIf false #< TODO: re-enable once confident of sandboxing
|
||||
systemd.services.transmission.serviceConfig = {
|
||||
# run this behind the OVPN static VPN
|
||||
NetworkNamespacePath = "/run/netns/ovpns";
|
||||
ExecStartPre = [ "${lib.getExe pkgs.sane-scripts.ip-check} --no-upnp --expect 185.157.162.178" ]; # abort if public IP is not as expected
|
||||
ExecStartPre = [ "${lib.getExe pkgs.sane-scripts.ip-check} --no-upnp --expect ${config.sane.netns.ovpns.netnsPubIpv4}" ]; # abort if public IP is not as expected
|
||||
|
||||
Restart = "on-failure";
|
||||
RestartSec = "30s";
|
||||
@@ -190,7 +189,7 @@ lib.mkIf false #< TODO: re-enable once confident of sandboxing
|
||||
# inherit kTLS;
|
||||
locations."/" = {
|
||||
# proxyPass = "http://ovpns.uninsane.org:9091";
|
||||
proxyPass = "http://10.0.1.6:9091";
|
||||
proxyPass = "http://${config.sane.netns.ovpns.netnsVethIpv4}:9091";
|
||||
};
|
||||
};
|
||||
|
||||
|
@@ -4,14 +4,12 @@
|
||||
let
|
||||
dyn-dns = config.sane.services.dyn-dns;
|
||||
nativeAddrs = lib.mapAttrs (_name: builtins.head) config.sane.dns.zones."uninsane.org".inet.A;
|
||||
bindOvpn = "10.0.1.5";
|
||||
bindDoof = "10.0.2.5";
|
||||
in
|
||||
{
|
||||
sane.ports.ports."53" = {
|
||||
protocol = [ "udp" "tcp" ];
|
||||
visibleTo.lan = true;
|
||||
visibleTo.wan = true;
|
||||
# visibleTo.wan = true;
|
||||
visibleTo.ovpns = true;
|
||||
visibleTo.doof = true;
|
||||
description = "colin-dns-hosting";
|
||||
@@ -41,6 +39,7 @@ in
|
||||
CNAME."native" = "%CNAMENATIVE%";
|
||||
A."@" = "%ANATIVE%";
|
||||
A."servo.wan" = "%AWAN%";
|
||||
A."servo.doof" = "%ADOOF%";
|
||||
A."servo.lan" = config.sane.hosts.by-name."servo".lan-ip;
|
||||
A."servo.hn" = config.sane.hosts.by-name."servo".wg-home.ip;
|
||||
|
||||
@@ -48,9 +47,9 @@ in
|
||||
# it's best that we keep this identical, or a superset of, what org. lists as our NS.
|
||||
# so, org. can specify ns2/ns3 as being to the VPN, with no mention of ns1. we provide ns1 here.
|
||||
A."ns1" = "%ANATIVE%";
|
||||
A."ns2" = "185.157.162.178";
|
||||
A."ns3" = "185.157.162.178";
|
||||
A."ovpns" = "185.157.162.178";
|
||||
A."ns2" = "%ADOOF%";
|
||||
A."ns3" = "%AOVPNS%";
|
||||
A."ovpns" = "%AOVPNS%";
|
||||
NS."@" = [
|
||||
"ns1.uninsane.org."
|
||||
"ns2.uninsane.org."
|
||||
@@ -61,59 +60,64 @@ in
|
||||
services.trust-dns.settings.zones = [ "uninsane.org" ];
|
||||
|
||||
|
||||
networking.nat.enable = true;
|
||||
networking.nat.extraCommands = ''
|
||||
# redirect incoming DNS requests from LAN addresses
|
||||
# to the LAN-specialized DNS service
|
||||
# N.B.: use the `nixos-*` chains instead of e.g. PREROUTING
|
||||
# because they get cleanly reset across activations or `systemctl restart firewall`
|
||||
# instead of accumulating cruft
|
||||
iptables -t nat -A nixos-nat-pre -p udp --dport 53 \
|
||||
-m iprange --src-range 10.78.76.0-10.78.79.255 \
|
||||
-j DNAT --to-destination :1053
|
||||
iptables -t nat -A nixos-nat-pre -p tcp --dport 53 \
|
||||
-m iprange --src-range 10.78.76.0-10.78.79.255 \
|
||||
-j DNAT --to-destination :1053
|
||||
'';
|
||||
sane.ports.ports."1053" = {
|
||||
# because the NAT above redirects in nixos-nat-pre, LAN requests behave as though they arrived on the external interface at the redirected port.
|
||||
# TODO: try nixos-nat-post instead?
|
||||
# TODO: or, don't NAT from port 53 -> port 1053, but rather nat from LAN addr to a loopback addr.
|
||||
# - this is complicated in that loopback is a different interface than eth0, so rewriting the destination address would cause the packets to just be dropped by the interface
|
||||
protocol = [ "udp" "tcp" ];
|
||||
visibleTo.lan = true;
|
||||
description = "colin-redirected-dns-for-lan-namespace";
|
||||
};
|
||||
networking.nat.enable = true; #< TODO: try removing this?
|
||||
# networking.nat.extraCommands = ''
|
||||
# # redirect incoming DNS requests from LAN addresses
|
||||
# # to the LAN-specialized DNS service
|
||||
# # N.B.: use the `nixos-*` chains instead of e.g. PREROUTING
|
||||
# # because they get cleanly reset across activations or `systemctl restart firewall`
|
||||
# # instead of accumulating cruft
|
||||
# iptables -t nat -A nixos-nat-pre -p udp --dport 53 \
|
||||
# -m iprange --src-range 10.78.76.0-10.78.79.255 \
|
||||
# -j DNAT --to-destination :1053
|
||||
# iptables -t nat -A nixos-nat-pre -p tcp --dport 53 \
|
||||
# -m iprange --src-range 10.78.76.0-10.78.79.255 \
|
||||
# -j DNAT --to-destination :1053
|
||||
# '';
|
||||
# sane.ports.ports."1053" = {
|
||||
# # because the NAT above redirects in nixos-nat-pre, LAN requests behave as though they arrived on the external interface at the redirected port.
|
||||
# # TODO: try nixos-nat-post instead?
|
||||
# # TODO: or, don't NAT from port 53 -> port 1053, but rather nat from LAN addr to a loopback addr.
|
||||
# # - this is complicated in that loopback is a different interface than eth0, so rewriting the destination address would cause the packets to just be dropped by the interface
|
||||
# protocol = [ "udp" "tcp" ];
|
||||
# visibleTo.lan = true;
|
||||
# description = "colin-redirected-dns-for-lan-namespace";
|
||||
# };
|
||||
|
||||
|
||||
sane.services.trust-dns.enable = true;
|
||||
sane.services.trust-dns.instances = let
|
||||
mkSubstitutions = flavor: {
|
||||
"%ADOOF%" = config.sane.netns.doof.netnsPubIpv4;
|
||||
"%ANATIVE%" = nativeAddrs."servo.${flavor}";
|
||||
"%AOVPNS%" = config.sane.netns.ovpns.netnsPubIpv4;
|
||||
"%AWAN%" = "$(cat '${dyn-dns.ipPath}')";
|
||||
"%CNAMENATIVE%" = "servo.${flavor}";
|
||||
"%ANATIVE%" = nativeAddrs."servo.${flavor}";
|
||||
"%AOVPNS%" = "185.157.162.178";
|
||||
};
|
||||
in
|
||||
{
|
||||
wan = {
|
||||
substitutions = mkSubstitutions "wan";
|
||||
doof = {
|
||||
substitutions = mkSubstitutions "doof";
|
||||
listenAddrsIpv4 = [
|
||||
nativeAddrs."servo.lan"
|
||||
bindOvpn
|
||||
bindDoof
|
||||
config.sane.netns.doof.hostVethIpv4
|
||||
config.sane.netns.ovpns.hostVethIpv4
|
||||
];
|
||||
};
|
||||
lan = {
|
||||
substitutions = mkSubstitutions "lan";
|
||||
listenAddrsIpv4 = [ nativeAddrs."servo.lan" ];
|
||||
port = 1053;
|
||||
};
|
||||
hn = {
|
||||
substitutions = mkSubstitutions "hn";
|
||||
listenAddrsIpv4 = [ nativeAddrs."servo.hn" ];
|
||||
port = 1053;
|
||||
};
|
||||
lan = {
|
||||
substitutions = mkSubstitutions "lan";
|
||||
listenAddrsIpv4 = [ nativeAddrs."servo.lan" ];
|
||||
# port = 1053;
|
||||
};
|
||||
# wan = {
|
||||
# substitutions = mkSubstitutions "wan";
|
||||
# listenAddrsIpv4 = [
|
||||
# nativeAddrs."servo.lan"
|
||||
# ];
|
||||
# };
|
||||
# hn-resolver = {
|
||||
# # don't need %AWAN% here because we forward to the hn instance.
|
||||
# listenAddrsIpv4 = [ nativeAddrs."servo.hn" ];
|
||||
@@ -154,9 +158,10 @@ in
|
||||
};
|
||||
|
||||
sane.services.dyn-dns.restartOnChange = [
|
||||
"trust-dns-wan.service"
|
||||
"trust-dns-lan.service"
|
||||
"trust-dns-doof.service"
|
||||
"trust-dns-hn.service"
|
||||
"trust-dns-lan.service"
|
||||
# "trust-dns-wan.service"
|
||||
# "trust-dns-hn-resolver.service" # doesn't need restart because it doesn't know about WAN IP
|
||||
];
|
||||
}
|
||||
|
@@ -574,10 +574,6 @@ in
|
||||
gawk.sandbox.wrapperType = "inplace"; # /share/gawk libraries refer to /libexec
|
||||
gawk.sandbox.autodetectCliPaths = "existingFile";
|
||||
|
||||
gdb.sandbox.enable = false; # gdb doesn't sandbox well. i don't know how you could.
|
||||
# gdb.sandbox.method = "landlock"; # permission denied when trying to attach, even as root
|
||||
gdb.sandbox.autodetectCliPaths = true;
|
||||
|
||||
geoclue2-with-demo-agent = {};
|
||||
|
||||
# MS GitHub stores auth token in .config
|
||||
@@ -1181,13 +1177,12 @@ in
|
||||
];
|
||||
};
|
||||
|
||||
hardware.opengl = lib.mkIf config.sane.programs.guiApps.enabled ({
|
||||
hardware.graphics = lib.mkIf config.sane.programs.guiApps.enabled ({
|
||||
enable = true;
|
||||
driSupport = lib.mkDefault true;
|
||||
} // (lib.optionalAttrs pkgs.stdenv.isx86_64 {
|
||||
# for 32 bit applications
|
||||
# upstream nixpkgs forbids setting driSupport32Bit unless specifically x86_64 (so aarch64 isn't allowed)
|
||||
driSupport32Bit = lib.mkDefault true;
|
||||
# upstream nixpkgs forbids setting enable32Bit unless specifically x86_64 (so aarch64 isn't allowed)
|
||||
enable32Bit = lib.mkDefault true;
|
||||
}));
|
||||
|
||||
system.activationScripts.notifyActive = lib.mkIf config.sane.programs.guiApps.enabled {
|
||||
|
@@ -111,7 +111,7 @@ in
|
||||
'';
|
||||
});
|
||||
|
||||
fs.".config/bonsai/bonsai_tree.json".symlink.text = builtins.toJSON cfg.config.transitions;
|
||||
fs.".config/bonsai/bonsai_tree.json".symlink.target = pkgs.writers.writeJSON "bonsai_tree.json" cfg.config.transitions;
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.extraRuntimePaths = [
|
||||
|
@@ -66,6 +66,7 @@ end
|
||||
if vars.percent ~= nil then
|
||||
bat_args = bat_args .. " --percent-suffix '" .. vars.percent .. "'"
|
||||
end
|
||||
bat_args = bat_args .. " {bat}"
|
||||
|
||||
-- N.B.: `[[ <text> ]]` is Lua's multiline string literal
|
||||
conky.text = [[
|
||||
@@ -73,8 +74,8 @@ ${color1}${shadecolor 707070}${font sans-serif:size=50:style=Bold}${alignc}${exe
|
||||
${color2}${shadecolor a4d7d0}${font sans-serif:size=20}${alignc}${exec date +"%a %d %b"}${font}
|
||||
|
||||
|
||||
${color1}${shadecolor}${font sans-serif:size=22:style=Bold}${alignc}${execp @bat@ ]] .. bat_args .. [[ }${font}
|
||||
${color1}${shadecolor}${font sans-serif:size=20:style=Bold}${alignc}${texeci 600 @weather@ }${font}
|
||||
${color1}${shadecolor}${font sans-serif:size=22:style=Bold}${alignc}${execp sane-sysload ]] .. bat_args .. [[ }${font}
|
||||
${color1}${shadecolor}${font sans-serif:size=20:style=Bold}${alignc}${texeci 600 timeout 20 sane-weather }${font}
|
||||
|
||||
|
||||
${color2}${shadecolor a4d7d0}${font sans-serif:size=16}${alignc}⇅ ${downspeedf wlan0}]] .. vars.kBps .. [[${font}
|
||||
|
@@ -5,22 +5,18 @@
|
||||
sandbox.net = "clearnet"; #< for the scripts it calls (weather)
|
||||
sandbox.extraPaths = [
|
||||
"/sys/class/power_supply"
|
||||
"/sys/devices" # needed by sane-sysinfo
|
||||
"/sys/devices" # needed by sane-sysload
|
||||
# "/sys/devices/cpu"
|
||||
# "/sys/devices/system"
|
||||
];
|
||||
sandbox.whitelistWayland = true;
|
||||
|
||||
suggestedPrograms = [
|
||||
"sane-sysinfo"
|
||||
"sane-sysload"
|
||||
"sane-weather"
|
||||
];
|
||||
|
||||
fs.".config/conky/conky.conf".symlink.target = pkgs.substituteAll {
|
||||
src = ./conky.conf;
|
||||
bat = "sane-sysinfo";
|
||||
weather = "timeout 20 sane-weather";
|
||||
};
|
||||
fs.".config/conky/conky.conf".symlink.target = ./conky.conf;
|
||||
|
||||
services.conky = {
|
||||
description = "conky dynamic desktop background";
|
||||
|
@@ -50,8 +50,11 @@
|
||||
./fwupd.nix
|
||||
./g4music.nix
|
||||
./gajim.nix
|
||||
./gdb.nix
|
||||
./gdbus.nix
|
||||
./geary.nix
|
||||
./geoclue-demo-agent.nix
|
||||
./geoclue2.nix
|
||||
./git.nix
|
||||
./gnome-clocks.nix
|
||||
./gnome-feeds.nix
|
||||
@@ -60,6 +63,7 @@
|
||||
./gnome-weather.nix
|
||||
./go2tv.nix
|
||||
./gpodder.nix
|
||||
./gpsd.nix
|
||||
./grimshot.nix
|
||||
./gst-device-monitor.nix
|
||||
./gthumb.nix
|
||||
@@ -87,6 +91,7 @@
|
||||
./msmtp.nix
|
||||
./nautilus.nix
|
||||
./neovim.nix
|
||||
./networkmanager_dmenu
|
||||
./newsflash.nix
|
||||
./nheko.nix
|
||||
./nicotine-plus.nix
|
||||
@@ -98,8 +103,10 @@
|
||||
./objdump.nix
|
||||
./obsidian.nix
|
||||
./offlineimap.nix
|
||||
./ols.nix
|
||||
./open-in-mpv.nix
|
||||
./pactl.nix
|
||||
./pidof.nix
|
||||
./pipewire.nix
|
||||
./planify.nix
|
||||
./portfolio-filemanager.nix
|
||||
@@ -114,9 +121,10 @@
|
||||
./sane-open.nix
|
||||
./sane-screenshot.nix
|
||||
./sane-scripts.nix
|
||||
./sane-sysinfo.nix
|
||||
./sane-sysload.nix
|
||||
./sane-theme.nix
|
||||
./sanebox.nix
|
||||
./satellite.nix
|
||||
./schlock.nix
|
||||
./seatd.nix
|
||||
./sfeed.nix
|
||||
@@ -136,7 +144,7 @@
|
||||
./swaylock.nix
|
||||
./swaynotificationcenter
|
||||
./switchboard.nix
|
||||
./sysvol.nix
|
||||
./syshud.nix
|
||||
./tangram.nix
|
||||
./tor-browser.nix
|
||||
./tuba.nix
|
||||
@@ -144,6 +152,7 @@
|
||||
./vlc.nix
|
||||
./waybar
|
||||
./waylock.nix
|
||||
./where-am-i.nix
|
||||
./wike.nix
|
||||
./wine.nix
|
||||
./wireplumber.nix
|
||||
|
@@ -55,7 +55,7 @@ in
|
||||
# - theme-demo
|
||||
# - timeout-completed
|
||||
# - window-close
|
||||
fs.".config/feedbackd/themes/proxied.json".symlink.text = builtins.toJSON {
|
||||
fs.".config/feedbackd/themes/proxied.json".symlink.target = pkgs.writers.writeJSON "proxied.json" {
|
||||
name = "proxied";
|
||||
parent-theme = "default";
|
||||
profiles = [
|
||||
|
13
hosts/common/programs/gdb.nix
Normal file
13
hosts/common/programs/gdb.nix
Normal file
@@ -0,0 +1,13 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
sane.programs.gdb = {
|
||||
sandbox.enable = false; # gdb doesn't sandbox well. i don't know how you could.
|
||||
# sandbox.method = "landlock"; # permission denied when trying to attach, even as root
|
||||
sandbox.autodetectCliPaths = true;
|
||||
fs.".config/gdb/gdbinit".symlink.text = ''
|
||||
# enable commands like `py-bt`, `py-list`, etc.
|
||||
# for usage, see: <https://wiki.python.org/moin/DebuggingWithGdb>
|
||||
source ${pkgs.python3}/share/gdb/libpython.py
|
||||
'';
|
||||
};
|
||||
}
|
16
hosts/common/programs/geoclue-demo-agent.nix
Normal file
16
hosts/common/programs/geoclue-demo-agent.nix
Normal file
@@ -0,0 +1,16 @@
|
||||
{ config, pkgs, ... }:
|
||||
{
|
||||
sane.programs.geoclue-demo-agent = {
|
||||
packageUnwrapped = pkgs.linkFarm "geoclue-demo-agent" [{
|
||||
# bring the demo agent into a `bin/` directory so it can be invokable via PATH
|
||||
name = "bin/geoclue-demo-agent";
|
||||
path = "${config.sane.programs.geoclue2.packageUnwrapped}/libexec/geoclue-2.0/demos/agent";
|
||||
}];
|
||||
|
||||
services.geoclue-agent = {
|
||||
description = "geoclue 'demo' agent";
|
||||
command = "geoclue-demo-agent";
|
||||
partOf = [ "graphical-session" ];
|
||||
};
|
||||
};
|
||||
}
|
62
hosts/common/programs/geoclue2.nix
Normal file
62
hosts/common/programs/geoclue2.nix
Normal file
@@ -0,0 +1,62 @@
|
||||
# geoclue location services daemon.
|
||||
#
|
||||
# SUPPORT:
|
||||
# - irc: #gnome-maps on irc.gimp.org
|
||||
# - Matrix: #gnome-maps:gnome.org (unclear if bridged to IRC)
|
||||
# - forums: <https://discourse.gnome.org/c/platform>
|
||||
# - git: <https://gitlab.freedesktop.org/geoclue/geoclue/>
|
||||
# - D-Bus API docs: <https://www.freedesktop.org/software/geoclue/docs/>
|
||||
#
|
||||
# HOW TO TEST:
|
||||
# - just invoke `where-am-i`: it should output the current latitude/longitude.
|
||||
## more manual testing:
|
||||
# - build `geoclue2-with-demo-agent`
|
||||
# - run the service: `systemctl start geoclue` or "${geoclue2-with-demo-agent}/libexec/geoclue"
|
||||
# - run "${geoclue2-with-demo-agent}/libexec/geoclue-2.0/demos/agent"
|
||||
# - keep this running in the background
|
||||
# - run "${geoclue2-with-demo-agent}/libexec/geoclue-2.0/demos/where-am-i"
|
||||
#
|
||||
# DATA FLOW:
|
||||
# - geoclue2 does http calls into local `ols`, which either hits the local disk or queries https://wigle.net.
|
||||
# - geoclue users like gnome-maps somehow depend on an "agent",
|
||||
# a user service which launches the geoclue system service on-demand (via dbus activation).
|
||||
#
|
||||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
cfg = config.sane.programs.geoclue2;
|
||||
in
|
||||
{
|
||||
sane.programs.geoclue2 = {
|
||||
# packageUnwrapped = pkgs.rmDbusServices pkgs.geoclue2;
|
||||
# packageUnwrapped = pkgs.geoclue2.override { withDemoAgent = true; };
|
||||
packageUnwrapped = pkgs.geoclue2-with-demo-agent;
|
||||
suggestedPrograms = [
|
||||
"geoclue-demo-agent"
|
||||
"ols" #< WiFi SSID -> lat/long lookups
|
||||
"satellite" #< graphical view into GPS fix data
|
||||
"where-am-i" #< handy debugging/testing tool
|
||||
];
|
||||
};
|
||||
|
||||
# sane.programs.geoclue2.enableFor.system = lib.mkIf (builtins.any (en: en) (builtins.attrValues cfg.enableFor.user)) true;
|
||||
|
||||
# prevent geoclue from modifying the GPS settings: i manage that myself, and trying to co-manage it with geoclue causes issues.
|
||||
security.polkit.extraConfig = lib.optionalString cfg.enabled ''
|
||||
polkit.addRule(function(action, subject) {
|
||||
if (subject.user == "geoclue" && action.id == "org.freedesktop.ModemManager1.Device.Control") {
|
||||
return polkit.Result.NO;
|
||||
}
|
||||
});
|
||||
'';
|
||||
|
||||
|
||||
services.geoclue2 = lib.mkIf cfg.enabled {
|
||||
enable = true;
|
||||
geoProviderUrl = "http://127.0.0.1:8088/v1/geolocate"; #< ols
|
||||
};
|
||||
systemd.user.services = lib.mkIf cfg.enabled {
|
||||
# nixos services.geoclue2 runs the agent as a user service by default, but i don't use systemd so that doesn't work.
|
||||
# i manage the agent myself, in sane.programs.geoclue-demo-agent.
|
||||
geoclue-agent.enable = false;
|
||||
};
|
||||
}
|
@@ -40,6 +40,7 @@ in
|
||||
alias.amend = "commit --amend --no-edit";
|
||||
alias.br = "branch";
|
||||
alias.co = "checkout";
|
||||
alias.com = "commit";
|
||||
alias.cp = "cherry-pick";
|
||||
alias.d = "difftool";
|
||||
alias.dif = "diff"; # common typo
|
||||
|
@@ -1,12 +1,12 @@
|
||||
# gnome feeds RSS viewer
|
||||
{ config, lib, sane-lib, ... }:
|
||||
{ config, lib, pkgs, sane-lib, ... }:
|
||||
|
||||
let
|
||||
feeds = sane-lib.feeds;
|
||||
all-feeds = config.sane.feeds;
|
||||
wanted-feeds = feeds.filterByFormat ["text" "image"] all-feeds;
|
||||
in {
|
||||
sane.programs.gnome-feeds.fs.".config/org.gabmus.gfeeds.json".symlink.text = builtins.toJSON {
|
||||
sane.programs.gnome-feeds.fs.".config/org.gabmus.gfeeds.json".symlink.target = pkgs.writers.writeJSON "org.gabmus.gfeeds.json" {
|
||||
# feed format is a map from URL to a dict,
|
||||
# with dict["tags"] a list of string tags.
|
||||
feeds = sane-lib.mapToAttrs (feed: {
|
||||
|
@@ -1,7 +1,14 @@
|
||||
# SUPPORT:
|
||||
# - irc: #gnome-maps on irc.gimp.org
|
||||
# - Matrix: #gnome-maps:gnome.org (unclear if bridged to IRC)
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
sane.programs."gnome.gnome-maps" = {
|
||||
packageUnwrapped = pkgs.rmDbusServices pkgs.gnome.gnome-maps;
|
||||
suggestedPrograms = [
|
||||
"geoclue2"
|
||||
];
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.whitelistDri = true; # for perf
|
||||
sandbox.whitelistDbus = [
|
||||
|
33
hosts/common/programs/gpsd.nix
Normal file
33
hosts/common/programs/gpsd.nix
Normal file
@@ -0,0 +1,33 @@
|
||||
# test gpsd with `gpspipe -w -n 10 2> /dev/null | grep -m 1 TPV | jq '.lat, .lon' | tr '\n' ' '`
|
||||
# ^ should return <lat> <long>
|
||||
#
|
||||
# TODO(2024/06/19): nixpkgs' gpsd service isn't sandboxed at ALL. i should sandbox that, or remove this integration.
|
||||
#
|
||||
# pinephone GPS happens in EG25 modem
|
||||
# serial control interface to modem is /dev/ttyUSB2
|
||||
# after enabling GPS, readout is /dev/ttyUSB1
|
||||
#
|
||||
# minimal process to enable modem and GPS:
|
||||
# - `echo 1 > /sys/class/modem-power/modem-power/device/powered`
|
||||
# - `screen /dev/ttyUSB2 115200`
|
||||
# - `AT+QGPSCFG="nmeasrc",1`
|
||||
# - `AT+QGPS=1`
|
||||
# this process is automated by my `eg25-control` program and services (`eg25-control-powered`, `eg25-control-gps`)
|
||||
# - see the `modules/` directory further up this repository.
|
||||
#
|
||||
# now, something like `gpsd` can directly read from /dev/ttyUSB1,
|
||||
# or geoclue can query the GPS directly through modem-manager
|
||||
#
|
||||
# initial GPS fix can take 15+ minutes.
|
||||
# meanwhile, services like eg25-manager or eg25-control-freshen-agps can speed this up by uploading assisted GPS data to the modem.
|
||||
{ config, lib, ... }:
|
||||
let
|
||||
cfg = config.sane.programs.gpsd;
|
||||
in
|
||||
{
|
||||
sane.programs.gpsd = {};
|
||||
services.gpsd = lib.mkIf cfg.enabled {
|
||||
enable = true;
|
||||
devices = [ "/dev/ttyUSB1" ];
|
||||
};
|
||||
}
|
@@ -1,7 +1,7 @@
|
||||
# docs: <https://git.sr.ht/~mil/mepo>
|
||||
# irc #mepo:irc.oftc.net
|
||||
#
|
||||
{ config, lib, ... }:
|
||||
|
||||
{
|
||||
sane.programs.mepo = {
|
||||
sandbox.method = "bwrap";
|
||||
@@ -16,11 +16,11 @@
|
||||
{ type = "file"; path = ".cache/mepo/savestate"; }
|
||||
];
|
||||
|
||||
# give mepo access to gpsd for location data, if that's enabled.
|
||||
# same with geoclue2.
|
||||
suggestedPrograms = lib.optional config.services.gpsd.enable "gpsd"
|
||||
++ lib.optional config.services.geoclue2.enable "geoclue2-with-demo-agent"
|
||||
;
|
||||
# enable geoclue2 and gpsd for location data.
|
||||
suggestedPrograms = [
|
||||
"geoclue2"
|
||||
# "gpsd" #< not required, and mepo only uses it if geoclue is unavailable
|
||||
];
|
||||
};
|
||||
|
||||
# programs.mepo = lib.mkIf config.sane.programs.mepo.enabled {
|
||||
|
@@ -1,3 +1,19 @@
|
||||
# GPS:
|
||||
# - enable: `mmcli --modem any --location-enable-gps-unmanaged`
|
||||
# - or `mmcli -m any --location-enable-gps-nmea`
|
||||
# - or use `s6-rc start eg25-control-gps`
|
||||
# - verify GPS is enabled: `mmcli --modem any --location-status`
|
||||
# - query GPS coordinates: `mmcli -m any --location-get`
|
||||
# - monitor constellation info: `mmcli -m any --location-monitor`
|
||||
# - i.e. which satellites are in view
|
||||
# - or just `cat /dev/ttyUSB1`
|
||||
#
|
||||
# interactions, warnings:
|
||||
# - Geoclue (`where-am-i`) toggles mmcli GPS on/off every 60s, often resetting it to the "off" state
|
||||
# - see: <https://gitlab.freedesktop.org/geoclue/geoclue/-/issues/180>
|
||||
# - the effect is that GPS data is effectively useless inside apps like gnome-maps
|
||||
# i think the trick is to get "--location-enable-gps-unmanaged" gps working again
|
||||
# or use gnss-share/gpsd (this may be what "unmanaged" means).
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
sane.programs.mmcli = {
|
||||
|
44
hosts/common/programs/networkmanager_dmenu/config.ini
Normal file
44
hosts/common/programs/networkmanager_dmenu/config.ini
Normal file
@@ -0,0 +1,44 @@
|
||||
[dmenu]
|
||||
dmenu_command = rofi -dmenu
|
||||
# # Note that dmenu_command can contain arguments as well like:
|
||||
# # `dmenu_command = rofi -dmenu -i -theme nmdm`
|
||||
# # `dmenu_command = rofi -dmenu -width 30 -i`
|
||||
# # `dmenu_command = dmenu -i -l 25 -b -nb #909090 -nf #303030`
|
||||
# # `dmenu_command = fuzzel --dmenu`
|
||||
rofi_highlight = True
|
||||
compact = True
|
||||
# pinentry = <Pinentry command> # (Default: None) e.g. `pinentry-gtk`
|
||||
# wifi_chars = <string of 4 unicode characters representing 1-4 bars strength>
|
||||
wifi_chars = ▂▄▆█
|
||||
# wifi_icons = <characters representing signal strength as an icon>
|
||||
wifi_icons =
|
||||
# format = <Python style format string for the access point entries>
|
||||
# # TODO: replace `{sec}` with a locked/unlocked icon
|
||||
format = {icon} {name} [{signal}%%] [{sec}]
|
||||
# # Available variables are:
|
||||
# # * {name} - Access point name
|
||||
# # * {sec} - Security type
|
||||
# # * {signal} - Signal strength on a scale of 0-100
|
||||
# # * {bars} - Bar-based display of signal strength (see wifi_chars)
|
||||
# # * {icon} - Icon-based display of signal strength (see wifi_icons)
|
||||
# # * {max_len_name} and {max_len_sec} are the maximum lengths of {name} / {sec}
|
||||
# # respectively and may be useful for formatting.
|
||||
# list_saved = <True or False> # (Default: False) list saved connections
|
||||
|
||||
[dmenu_passphrase]
|
||||
# # Uses the -password flag for Rofi, -x for bemenu. For dmenu, sets -nb and
|
||||
# # -nf to the same color or uses -P if the dmenu password patch is applied
|
||||
# # https://tools.suckless.org/dmenu/patches/password/
|
||||
# obscure = True
|
||||
# obscure_color = #222222
|
||||
|
||||
[pinentry]
|
||||
# description = <Pinentry description> (Default: Get network password)
|
||||
# prompt = <Pinentry prompt> (Default: Password:)
|
||||
|
||||
[editor]
|
||||
# terminal = <name of terminal program>
|
||||
# gui_if_available = <True or False> (Default: True)
|
||||
|
||||
[nmdm]
|
||||
# rescan_delay = <seconds> # (seconds to wait after a wifi rescan before redisplaying the results)
|
21
hosts/common/programs/networkmanager_dmenu/default.nix
Normal file
21
hosts/common/programs/networkmanager_dmenu/default.nix
Normal file
@@ -0,0 +1,21 @@
|
||||
# source: <https://github.com/firecat53/networkmanager-dmenu>
|
||||
{ ... }:
|
||||
{
|
||||
sane.programs.networkmanager_dmenu = {
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.isolatePids = false; #< so it can know that NetworkManager really is running... (?)
|
||||
sandbox.whitelistDbus = [
|
||||
"system"
|
||||
];
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.extraHomePaths = [
|
||||
".cache/rofi"
|
||||
".config/rofi"
|
||||
];
|
||||
suggestedPrograms = [
|
||||
"pidof"
|
||||
];
|
||||
|
||||
fs.".config/networkmanager-dmenu/config.ini".symlink.target = ./config.ini;
|
||||
};
|
||||
}
|
@@ -2,6 +2,9 @@
|
||||
{
|
||||
sane.programs.nmcli = {
|
||||
packageUnwrapped = pkgs.networkmanager-split.nmcli;
|
||||
# TODO: sandbox
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.whitelistDbus = [
|
||||
"system"
|
||||
];
|
||||
};
|
||||
}
|
||||
|
7
hosts/common/programs/nwg-panel/common-settings.json
Normal file
7
hosts/common/programs/nwg-panel/common-settings.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"restart-on-display": true,
|
||||
"restart-delay": 500,
|
||||
"run-through-compositor": false,
|
||||
"processes-background-only": true,
|
||||
"processes-own-only": true
|
||||
}
|
@@ -4,11 +4,14 @@
|
||||
# - add network/bluetooth indicator
|
||||
# - <https://github.com/nwg-piotr/nwg-panel/issues/269>
|
||||
# - add CPU/meminfo executor
|
||||
# - use sane-sysinfo
|
||||
# - use sane-sysload
|
||||
{
|
||||
components,
|
||||
controlsSettingsComponents,
|
||||
height,
|
||||
locker,
|
||||
modulesRight,
|
||||
playerctlChars,
|
||||
mediaPrevNext,
|
||||
windowIcon,
|
||||
windowTitle,
|
||||
workspaceHideEmpty,
|
||||
@@ -49,9 +52,7 @@
|
||||
modules-center = [
|
||||
"clock"
|
||||
];
|
||||
modules-right = [
|
||||
"playerctl"
|
||||
];
|
||||
modules-right = modulesRight;
|
||||
|
||||
clock = {
|
||||
angle = 0.0;
|
||||
@@ -79,7 +80,7 @@
|
||||
battery-low-interval = 4; #< notify every N minutes when battery continues to remain low
|
||||
battery-low-level = 15; #< notify if battery is lower than this percent
|
||||
# commands.battery = ""; #< optional action to perform when battery icon is clicked in the drop-down menu
|
||||
components = components;
|
||||
components = controlsSettingsComponents;
|
||||
click-closes = false;
|
||||
custom-items = [];
|
||||
css-name = "controls-window";
|
||||
@@ -90,21 +91,20 @@
|
||||
menu.icon = "system-shutdown-symbolic";
|
||||
menu.items = [
|
||||
{
|
||||
# TODO: plumb through the configured locker instead of assuming `swaylock`
|
||||
name = "Lock";
|
||||
cmd = "swaylock -f -c 000000";
|
||||
}
|
||||
{
|
||||
name = "Logout";
|
||||
cmd = "swaymsg exit";
|
||||
cmd = "s6-rc start ${locker}";
|
||||
}
|
||||
# {
|
||||
# name = "Logout";
|
||||
# cmd = "swaymsg exit";
|
||||
# }
|
||||
{
|
||||
name = "Reboot";
|
||||
cmd = "systemctl reboot";
|
||||
cmd = "reboot";
|
||||
}
|
||||
{
|
||||
name = "Shutdown";
|
||||
cmd = "systemctl -i poweroff";
|
||||
cmd = "shutdown now";
|
||||
}
|
||||
];
|
||||
menu.name = "Exit";
|
||||
@@ -127,6 +127,23 @@
|
||||
interval = 2;
|
||||
label-css-name = "playerctl-label";
|
||||
scroll = false;
|
||||
show-cover = false; #< don't show the little music-note icon
|
||||
show-previous = mediaPrevNext;
|
||||
show-next = mediaPrevNext;
|
||||
show-name = mediaPrevNext;
|
||||
};
|
||||
swaync = {
|
||||
css-name = "swaync-label";
|
||||
# interval = 1;
|
||||
# icon-placement = "left";
|
||||
# icon-size = 18;
|
||||
# tooltip-text = "";
|
||||
# on-left-click = "swaync-client -t";
|
||||
# on-right-click = "";
|
||||
# on-middle-click = "";
|
||||
# on-scroll-up = "";
|
||||
# on-scroll-down = "";
|
||||
# always-show-icon = true;
|
||||
};
|
||||
sway-workspaces = {
|
||||
angle = 0.0;
|
||||
@@ -143,6 +160,20 @@
|
||||
show-name = windowTitle;
|
||||
};
|
||||
|
||||
executor-sysload = {
|
||||
script = "sane-sysload {mem} {cpu}";
|
||||
interval = 10;
|
||||
css-name = "";
|
||||
on-right-click = "";
|
||||
icon-size = 16;
|
||||
show-icon = false;
|
||||
tooltip-text = "";
|
||||
on-left-click = "";
|
||||
on-middle-click = "";
|
||||
on-scroll-up = "";
|
||||
on-scroll-down = "";
|
||||
};
|
||||
|
||||
# unused modules:
|
||||
brightness-slider = {};
|
||||
dwl-tags = {};
|
||||
|
@@ -23,7 +23,8 @@ in
|
||||
# what looks good:
|
||||
# - 15px on moby
|
||||
# - 24px on lappy
|
||||
default = lib.min 24 (cfg.config.fontSize - 1);
|
||||
# there's about 10px padding total around this (above + below)
|
||||
default = lib.min 24 (cfg.config.height - 11);
|
||||
};
|
||||
fontSize = mkOption {
|
||||
type = types.int;
|
||||
@@ -36,10 +37,18 @@ in
|
||||
height of the top bar in px.
|
||||
'';
|
||||
};
|
||||
locker = mkOption {
|
||||
type = types.str;
|
||||
default = config.sane.programs.swayidle.config.actions.lock.service;
|
||||
description = ''
|
||||
s6 service to start which can lock the screen
|
||||
'';
|
||||
};
|
||||
battery = mkEnableOption' true "display battery status";
|
||||
brightness = mkEnableOption' true "display backlight level and slider";
|
||||
mediaTitle = mkEnableOption' true "display title of current song/media";
|
||||
mediaPrevNext = mkEnableOption' true "display prev/next button in media";
|
||||
sysload = mkEnableOption' true "display system load info (cpu/memory)";
|
||||
windowIcon = mkEnableOption' true "display icon of active window";
|
||||
windowTitle = mkEnableOption' true "display title of active window";
|
||||
workspaceNumbers = mkOption {
|
||||
@@ -66,8 +75,16 @@ in
|
||||
# XXX(2024/06/13): wlr-randr does not cross compile
|
||||
wlr-randr = null; #< only used if not on sway/hyprland; or if using dwl
|
||||
}).overrideAttrs (base: {
|
||||
patches = (base.patches or []) ++ lib.optionals (!cfg.config.mediaPrevNext) [
|
||||
./playerctl-no-prev-next.diff
|
||||
# patches = (base.patches or []) ++ lib.optionals (!cfg.config.mediaPrevNext) [
|
||||
# ./playerctl-no-prev-next.diff
|
||||
# ];
|
||||
patches = (base.patches or []) ++ [
|
||||
(pkgs.fetchpatch {
|
||||
# upstreaming: <https://github.com/nwg-piotr/nwg-panel/pull/309>
|
||||
url = "https://git.uninsane.org/colin/nwg-panel/commit/a714e4100c409feb02c454874d030d192bfb0ae5.patch";
|
||||
name = "playerctl: add settings to control which elements are displayed";
|
||||
hash = "sha256-OofS46wAI3EDE3JbYs/Nn+Vkw9TP1mwSFvk+vBERg2s=";
|
||||
})
|
||||
];
|
||||
|
||||
# - disable the drop-down chevron by the controls.
|
||||
@@ -75,17 +92,22 @@ in
|
||||
# - disable brightness indicator for same reason.
|
||||
# - *leave* the volume indicator: one *could* remove it, however on desko that would leave the controls pane empty
|
||||
# making the dropdown inaccessible
|
||||
# also, remove padding from the items. i can manage that in css and the python padding prevents that.
|
||||
postPatch = (base.postPatch or "") + ''
|
||||
substituteInPlace nwg_panel/modules/controls.py --replace-fail \
|
||||
'self.box.pack_start(box, False, False, 6)' \
|
||||
'self.box.pack_start(box, False, False, 0)'
|
||||
|
||||
substituteInPlace nwg_panel/modules/controls.py --replace-fail \
|
||||
'box.pack_start(self.pan_image, False, False, 4)' \
|
||||
'# box.pack_start(self.pan_image, False, False, 4)'
|
||||
'# box.pack_start(self.pan_image, False, False, 0)'
|
||||
substituteInPlace nwg_panel/modules/controls.py --replace-fail \
|
||||
'box.pack_start(self.bri_image, False, False, 4)' \
|
||||
'# box.pack_start(self.bri_image, False, False, 4)'
|
||||
'# box.pack_start(self.bri_image, False, False, 0)'
|
||||
|
||||
# substituteInPlace nwg_panel/modules/controls.py --replace-fail \
|
||||
# 'box.pack_start(self.vol_image, False, False, 4)' \
|
||||
# '# box.pack_start(self.vol_image, False, False, 4)'
|
||||
substituteInPlace nwg_panel/modules/controls.py --replace-fail \
|
||||
'box.pack_start(self.vol_image, False, False, 4)' \
|
||||
'box.pack_start(self.vol_image, False, False, 0)'
|
||||
'';
|
||||
|
||||
# XXX(2024/06/13) the bluetooth stuff doesn't cross compile, so disable it
|
||||
@@ -102,11 +124,12 @@ in
|
||||
src = ./style.css;
|
||||
inherit (cfg.config) fontSize clockFontSize;
|
||||
};
|
||||
fs.".config/nwg-panel/common-settings.json".symlink.target = ./common-settings.json;
|
||||
fs.".config/nwg-panel/config".symlink.target = pkgs.writers.writeJSON "config" (import ./config.nix {
|
||||
inherit (cfg.config) height windowIcon windowTitle workspaceHideEmpty workspaceNumbers;
|
||||
inherit (cfg.config) locker height mediaPrevNext windowIcon windowTitle workspaceHideEmpty workspaceNumbers;
|
||||
# component order matters, mostly for the drop-down.
|
||||
# default for most tools (e.g. swaync) is brightness control above volume.
|
||||
components =
|
||||
controlsSettingsComponents =
|
||||
lib.optionals cfg.config.brightness [
|
||||
"brightness"
|
||||
] ++ [
|
||||
@@ -116,6 +139,11 @@ in
|
||||
"battery"
|
||||
]
|
||||
;
|
||||
modulesRight = [
|
||||
"playerctl"
|
||||
] ++ lib.optionals cfg.config.sysload [
|
||||
"executor-sysload"
|
||||
];
|
||||
playerctlChars = if cfg.config.mediaTitle then 60 else 0;
|
||||
});
|
||||
|
||||
|
@@ -1,11 +1,19 @@
|
||||
commit 7aa759990b38b09abf9010dfe58e4cbdc1493282 (HEAD -> dev-sane)
|
||||
Author: Colin <colin@uninsane.org>
|
||||
Date: 2024-06-15 21:41:46 +0000
|
||||
|
||||
playerctl: remove backward/forward/music-note icons
|
||||
|
||||
these aren't worth the space cost on narrow devices (moby)
|
||||
|
||||
diff --git a/nwg_panel/modules/playerctl.py b/nwg_panel/modules/playerctl.py
|
||||
index 9b53b4b..c4d96ae 100644
|
||||
index ff48d4c..43ae221 100644
|
||||
--- a/nwg_panel/modules/playerctl.py
|
||||
+++ b/nwg_panel/modules/playerctl.py
|
||||
@@ -180,15 +180,6 @@ class Playerctl(Gtk.EventBox):
|
||||
@@ -211,15 +211,6 @@ class Playerctl(Gtk.EventBox):
|
||||
if self.settings["angle"] != 0.0:
|
||||
button_box.set_orientation(Gtk.Orientation.VERTICAL)
|
||||
|
||||
|
||||
- img = Gtk.Image()
|
||||
- update_image(img, "media-skip-backward-symbolic", self.settings["icon-size"], icons_path=self.icons_path)
|
||||
- btn = Gtk.Button()
|
||||
@@ -18,10 +26,10 @@ index 9b53b4b..c4d96ae 100644
|
||||
self.play_pause_btn = Gtk.Button()
|
||||
if self.settings["button-css-name"]:
|
||||
self.play_pause_btn.set_property("name", self.settings["button-css-name"])
|
||||
@@ -198,15 +189,6 @@ class Playerctl(Gtk.EventBox):
|
||||
@@ -229,15 +220,6 @@ class Playerctl(Gtk.EventBox):
|
||||
self.play_pause_btn.connect("clicked", self.launch, self.PlayerOps.PLAY_PAUSE)
|
||||
button_box.pack_start(self.play_pause_btn, False, False, 1)
|
||||
|
||||
|
||||
- img = Gtk.Image()
|
||||
- update_image(img, "media-skip-forward-symbolic", self.settings["icon-size"], icons_path=self.icons_path)
|
||||
- btn = Gtk.Button()
|
||||
@@ -31,6 +39,21 @@ index 9b53b4b..c4d96ae 100644
|
||||
- btn.connect("clicked", self.launch, self.PlayerOps.NEXT)
|
||||
- button_box.pack_start(btn, False, False, 1)
|
||||
-
|
||||
self.label = AutoScrollLabel(self.settings["scroll"],
|
||||
self.settings["chars"],
|
||||
self.settings["interval"])
|
||||
self.num_players_lbl = Gtk.Label.new("")
|
||||
if self.settings["label-css-name"]:
|
||||
self.num_players_lbl.set_property("name", self.settings["label-css-name"])
|
||||
@@ -257,13 +239,9 @@ class Playerctl(Gtk.EventBox):
|
||||
self.box.pack_start(button_box, False, False, 2)
|
||||
if self.settings["show-cover"]:
|
||||
self.box.pack_start(self.cover_img, False, False, 0)
|
||||
- self.box.pack_start(self.num_players_lbl, False, False, 0)
|
||||
- self.box.pack_start(self.label, False, False, 5)
|
||||
else:
|
||||
if self.settings["show-cover"]:
|
||||
self.box.pack_start(self.cover_img, False, False, 2)
|
||||
- self.box.pack_start(self.num_players_lbl, False, False, 0)
|
||||
- self.box.pack_start(self.label, False, False, 2)
|
||||
self.box.pack_start(button_box, False, False, 10)
|
||||
|
||||
def launch(self, button, op):
|
||||
|
||||
|
@@ -20,35 +20,61 @@
|
||||
font-size: @fontSize@px;
|
||||
}
|
||||
|
||||
button {
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
#task-box {
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
#task-box-focused {
|
||||
background-color: @accent-g2;
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
|
||||
#playerctl-button {
|
||||
background-color: rgba(0, 0, 0, 0.08);
|
||||
background-image: none;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
margin: -1;
|
||||
/* remove the 1px gap between buttons, since that causes color stripes if the background is a different color */
|
||||
margin-left: -1;
|
||||
margin-right: -1;
|
||||
outline: none;
|
||||
/* prevent the buttons from pushing the whole bar down */
|
||||
padding-top: 0px;
|
||||
padding-bottom: 0px;
|
||||
margin-top: 0px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
#panel-top {
|
||||
background: @accent-g1;
|
||||
color: @fg1;
|
||||
}
|
||||
/* fix up the top bar sections so that the clock can be centered, even without forcing it to take 1/3rd of the bar */
|
||||
/* pair with `homogenous = false` in config. on overflow, the clock may be rendered on top of the left portion of the bar */
|
||||
/* and the right portion of the bar will render on top of all */
|
||||
#panel-top > box > box > box > #left-box {
|
||||
margin-left: 0px;
|
||||
margin-right: -16384px;
|
||||
}
|
||||
#panel-top > box > box > box > #center-box {
|
||||
margin-left: 0px;
|
||||
margin-right: 0px;
|
||||
}
|
||||
#panel-top > box > box > box > box {
|
||||
/* this is the *parent* of #right-box, which is uniquely under an unnamed "helper box" */
|
||||
/* i have to address this parent, because otherwise only the controls are visible and the executors (including playerctl) */
|
||||
/* are packed in a fill mode that pushes them off the visible section of the bar */
|
||||
margin-left: -16384px;
|
||||
}
|
||||
|
||||
#right-box > widget > * {
|
||||
/* TODO: tune this for moby */
|
||||
padding-right: 3px;
|
||||
padding-left: 2px;
|
||||
}
|
||||
|
||||
#swaync-label {
|
||||
/* move the notification count closer to the bell icon */
|
||||
margin-left: -3px;
|
||||
/* TODO: this should be main font size -1 */
|
||||
font-size: 14px;
|
||||
color: @accent-r2;
|
||||
}
|
||||
|
||||
/* increase the size of each workspace icon */
|
||||
#sway-workspaces-item > label {
|
||||
|
45
hosts/common/programs/ols.nix
Normal file
45
hosts/common/programs/ols.nix
Normal file
@@ -0,0 +1,45 @@
|
||||
# OLS: Offline Location Service: <https://codeberg.org/tpikonen/ols>
|
||||
# fields {wifi SSID,cell tower} -> lat/long queries from geoclue
|
||||
# satisfies queries via https://wigle.net, by learning about map tiles
|
||||
# and caching those on-disk so that repeat queries may be serviced offline.
|
||||
#
|
||||
# it listens on localhost:8088, and one can validate its operation with a query like (substitute macAddresses for something real):
|
||||
# - WiFi: curl -d '{"wifiAccessPoints":[{"macAddress":"01:23:45:67:89:ab","signalStrength":-78},{"macAddress":"cd:ef:01:23:45:56","signalStrength":-76}]}' http://127.0.0.1:8088/v1/geolocate
|
||||
# - Cell: curl -d '{"cellTowers":[{ "radioType": "lte", "mobileCountryCode": 310, "mobileNetworkCode": 260, "locationAreaCode": NNNNN, "cellId": MMMMMMMM }]}' http://127.0.0.1:8088/v1/geolocate
|
||||
#
|
||||
## wigle docs:
|
||||
# - IRC: #wigle on WiGLE.net:6667
|
||||
# - API: <https://api.wigle.net/swagger>
|
||||
# API return codes:
|
||||
# - 429: "too many queries today."
|
||||
#
|
||||
# rate limiting:
|
||||
# - as a new user you'll be limited to something ridiculous like 5 queries per day.
|
||||
# supposedly this improves "based on history and participation".
|
||||
# - source: <https://api.wigle.net/swagger#/Network%20search%20and%20information%20tools/search_2>
|
||||
# - "API for some functions is limited on a daily basis for all users for the time being, but if you'd like increased access, please email us (include your username and usecase) at WiGLE-admin@wigle.net."
|
||||
# - source: <https://wigle.net/account>
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
sane.programs.ols = {
|
||||
packageUnwrapped = pkgs.python3Packages.ols;
|
||||
|
||||
fs.".config/ols/cell.db".symlink.target = pkgs.runCommandLocal "cell.db" {
|
||||
nativeBuildInputs = [ pkgs.python3Packages.ols ];
|
||||
} ''
|
||||
cellid-ols-import -o "$out" "${pkgs.opencellid}"
|
||||
'';
|
||||
|
||||
persist.byStore.private = [
|
||||
".local/share/ols"
|
||||
];
|
||||
|
||||
secrets.".config/ols/ols.toml" = ../../../secrets/common/ols.toml.bin;
|
||||
|
||||
services.ols = {
|
||||
description = "ols: Offline Location Service";
|
||||
command = "ols 2>&1"; # XXX: it logs to stderr, and my s6 infrastructure apparently doesn't handle that
|
||||
partOf = [ "graphical-session" ];
|
||||
};
|
||||
};
|
||||
}
|
8
hosts/common/programs/pidof.nix
Normal file
8
hosts/common/programs/pidof.nix
Normal file
@@ -0,0 +1,8 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
sane.programs.pidof = {
|
||||
packageUnwrapped = pkgs.linkIntoOwnPackage pkgs.procps "bin/pidof";
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.isolatePids = false;
|
||||
};
|
||||
}
|
@@ -116,6 +116,7 @@ in
|
||||
|
||||
fs.".config/rofi/config.rasi".symlink.target = ./config.rasi;
|
||||
fs."Apps".symlink.target = ".local/share/applications/rofi-applications.desktop";
|
||||
fs."WiFi".symlink.target = ".local/share/applications/networkmanager_dmenu.desktop";
|
||||
persist.byStore.cryptClearOnBoot = [
|
||||
# this gets us a few things:
|
||||
# - file browser remembers its last directory
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{ ... }:
|
||||
{
|
||||
sane.programs.sane-sysinfo = {
|
||||
sane.programs.sane-sysload = {
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.extraPaths = [
|
||||
"/sys/class/power_supply"
|
@@ -44,19 +44,19 @@ in
|
||||
# XXX: /run/current-system symlink can't be cached without forcing regular mass rebuilds:
|
||||
# mount it as if it were a directory instead.
|
||||
"/run/current-system" = "";
|
||||
} // lib.optionalAttrs config.hardware.opengl.enable {
|
||||
} // lib.optionalAttrs config.hardware.graphics.enable {
|
||||
"/run/opengl-driver" = let
|
||||
gl = config.hardware.opengl;
|
||||
# from: <repo:nixos/nixpkgs:nixos/modules/hardware/opengl.nix>
|
||||
gl = config.hardware.graphics;
|
||||
# from: <repo:nixos/nixpkgs:nixos/modules/hardware/graphics.nix>
|
||||
package = pkgs.buildEnv {
|
||||
name = "opengl-drivers";
|
||||
paths = [ gl.package ] ++ gl.extraPackages;
|
||||
};
|
||||
in "${package}";
|
||||
} // lib.optionalAttrs (config.hardware.opengl.enable && config.hardware.opengl.driSupport32Bit) {
|
||||
} // lib.optionalAttrs (config.hardware.graphics.enable && config.hardware.graphics.enable32Bit) {
|
||||
"/run/opengl-driver-32" = let
|
||||
gl = config.hardware.opengl;
|
||||
# from: <repo:nixos/nixpkgs:nixos/modules/hardware/opengl.nix>
|
||||
gl = config.hardware.graphics;
|
||||
# from: <repo:nixos/nixpkgs:nixos/modules/hardware/graphics.nix>
|
||||
package = pkgs.buildEnv {
|
||||
name = "opengl-drivers-32bit";
|
||||
paths = [ gl.package32 ] ++ gl.extraPackages32;
|
||||
|
53
hosts/common/programs/satellite.nix
Normal file
53
hosts/common/programs/satellite.nix
Normal file
@@ -0,0 +1,53 @@
|
||||
# satellite-gtk: <https://codeberg.org/tpikonen/satellite>
|
||||
# - presents GPS tracking *details* in a graphical way
|
||||
# - shows which satellites are in view, their SNR, and the subset currently being used for triangulation
|
||||
# - shows fix coordinates (time, lat, long, altitude, speed)
|
||||
#
|
||||
### how to read the bargraph (example):
|
||||
#
|
||||
# 14 | XXXXXXXXXXXXX 26
|
||||
# 76 | =========== 23
|
||||
# 15 | XXXXXXXX 16
|
||||
# =
|
||||
# +----------------|
|
||||
# 0 30
|
||||
#
|
||||
# ^ this view means:
|
||||
# - GPS is receiving from sats 14, 76, 15 (by PRN) -- this comes from GSGSV NMEA data (Satellites in-View)
|
||||
# - sat 14 and 15 (shaded solid) are "active" -- this comes from GSGSA NMEA data ("Satellites Active")
|
||||
# - i believe "active" means "this sat was used in the most recent solution"
|
||||
#
|
||||
### text fields
|
||||
# - Modes (GP,GL,GA) ...
|
||||
# one letter each, indicating the mode for GPS, GLONASS, Galileo sats:
|
||||
# - N = no fix
|
||||
# - A = autonomous
|
||||
# - D = differential mode
|
||||
# - E = estimated (dead reckoning)
|
||||
# - etc
|
||||
# - Active / in use sats
|
||||
# - A/U, where A = number of satellites used in the previous fix,
|
||||
# U = number of satellites mentioned in latest GNS + GGA messages
|
||||
# - Receiving sats
|
||||
# shows the count of sats with non-zero SNR, from GSV messages
|
||||
# - Visible sats
|
||||
# shows the count of sats from GSV messages
|
||||
# - Age of update / fix
|
||||
# - Sys. Time
|
||||
# - Latitude
|
||||
# - Longitude
|
||||
# - Altitude
|
||||
# - Geoidal separation
|
||||
# - Speed
|
||||
# - True Course
|
||||
# - PDOP/HDOP/VDOP
|
||||
# - shows how sensitive the reported location is to measurement error (low values are better)
|
||||
# - HDOP = horizontal sensitivity, VDOP = vertical sensitivity, PDOP = positional (d) sensitivity
|
||||
# - 1-2 => excellent fix
|
||||
# - >10 => low confidence fix; recommended to discard the fix
|
||||
# - <https://en.wikipedia.org/wiki/Dilution_of_precision_(navigation)>
|
||||
#
|
||||
{ ... }:
|
||||
{
|
||||
sane.programs.satellite = {};
|
||||
}
|
@@ -148,6 +148,7 @@ in
|
||||
"fontconfig"
|
||||
# "gnome.gnome-bluetooth" # XXX(2023/05/14): broken
|
||||
# "gnome.gnome-control-center" # XXX(2023/06/28): depends on webkitgtk4_1
|
||||
"networkmanager_dmenu"
|
||||
"nwg-panel"
|
||||
"pipewire"
|
||||
"playerctl" # for waybar & particularly to have playerctld running
|
||||
@@ -163,7 +164,7 @@ in
|
||||
"swayidle" # enable if you need it
|
||||
"swaynotificationcenter" # notification daemon
|
||||
"switchboard" # network/bluetooth/sound control panel
|
||||
"sysvol" # volume notifier
|
||||
"syshud" # volume notifier
|
||||
"unl0kr" # greeter
|
||||
# "waybar"
|
||||
"wdisplays" # like xrandr
|
||||
@@ -198,6 +199,7 @@ in
|
||||
sandbox.whitelistAudio = true; # it runs playerctl directly
|
||||
sandbox.whitelistDbus = [ "system" "user" ]; # to e.g. launch apps
|
||||
sandbox.whitelistDri = true;
|
||||
sandbox.whitelistS6 = true; #< for Super+L to start the screen locker service
|
||||
sandbox.whitelistX = true; # sway invokes xwayland itself
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.extraRuntimePaths = [
|
||||
@@ -227,7 +229,7 @@ in
|
||||
'';
|
||||
|
||||
fs.".config/sway/config".symlink.target = pkgs.substituteAll {
|
||||
src = ./sway-config;
|
||||
src = ./config;
|
||||
inherit (cfg.config)
|
||||
extra_lines
|
||||
font
|
||||
|
@@ -32,6 +32,7 @@ in
|
||||
};
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.whitelistS6 = true;
|
||||
sandbox.isolatePids = false; #< XXX: not sure why, but swaync segfaults under load without this!
|
||||
};
|
||||
|
||||
sane.programs.swaync-fbcli = {
|
||||
@@ -61,6 +62,8 @@ in
|
||||
name of entry in /sys/class/backlight which indicates the primary backlight.
|
||||
'';
|
||||
};
|
||||
enableBacklight = mkEnableOption "include a backlight slider in the swaync dropdown (requires an active session with systemd-logind)";
|
||||
enableMpris = (mkEnableOption "show the currently playing media in the swaync dropdown, and navigation buttons") // { default = true; };
|
||||
};
|
||||
};
|
||||
default = {};
|
||||
@@ -116,27 +119,14 @@ in
|
||||
env.GNOTIFICATION_BACKEND = "freedesktop";
|
||||
|
||||
fs.".config/swaync/style.css".symlink.target = ./style.css;
|
||||
fs.".config/swaync/config.json".symlink.text = builtins.toJSON {
|
||||
fs.".config/swaync/config.json".symlink.target = pkgs.writers.writeJSON "config.json" {
|
||||
"$schema" = "/etc/xdg/swaync/configSchema.json";
|
||||
positionX = "right";
|
||||
positionY = "top";
|
||||
layer = "overlay";
|
||||
control-center-height = 600;
|
||||
control-center-layer = "top";
|
||||
layer-shell = true;
|
||||
cssPriority = "user"; # "application"|"user". "user" in order to override the system gtk theme.
|
||||
control-center-margin-top = 0;
|
||||
control-center-margin-bottom = 0;
|
||||
control-center-margin-right = 0;
|
||||
control-center-margin-left = 0;
|
||||
notification-2fa-action = true;
|
||||
notification-inline-replies = false;
|
||||
notification-icon-size = 64;
|
||||
notification-body-image-height = 100;
|
||||
notification-body-image-width = 200;
|
||||
timeout = 30;
|
||||
timeout-low = 5;
|
||||
timeout-critical = 0;
|
||||
fit-to-screen = true; #< have notification center take full vertical screen space
|
||||
control-center-margin-right = 0;
|
||||
control-center-margin-top = 0;
|
||||
# control-center-width:
|
||||
# pinephone native display is 720 x 1440
|
||||
# - for compositor scale=2.0 => 360
|
||||
@@ -144,14 +134,28 @@ in
|
||||
# - for compositor scale=1.6 => 450
|
||||
# if it's set to something wider than the screen, then it overflows and items aren't visible.
|
||||
control-center-width = 360;
|
||||
control-center-height = 600;
|
||||
notification-window-width = 360;
|
||||
keyboard-shortcuts = true;
|
||||
image-visibility = "when-available";
|
||||
transition-time = 100;
|
||||
hide-on-clear = true; #< hide control center when clicking "clear all"
|
||||
cssPriority = "user"; # "application"|"user". "user" in order to override the system gtk theme.
|
||||
fit-to-screen = true; #< have notification center take full vertical screen space
|
||||
hide-on-action = true;
|
||||
hide-on-clear = true; #< hide control center when clicking "clear all"
|
||||
image-visibility = "when-available";
|
||||
keyboard-shortcuts = true;
|
||||
layer = "overlay";
|
||||
layer-shell = true;
|
||||
notification-2fa-action = true;
|
||||
notification-body-image-height = 100;
|
||||
notification-body-image-width = 200;
|
||||
notification-icon-size = 64;
|
||||
notification-inline-replies = false;
|
||||
notification-window-width = 360;
|
||||
positionX = "right";
|
||||
positionY = "top";
|
||||
script-fail-notify = true;
|
||||
timeout = 30;
|
||||
timeout-critical = 0;
|
||||
timeout-low = 5;
|
||||
transition-time = 100;
|
||||
|
||||
inherit scripts;
|
||||
widgets = [
|
||||
# what to show in the notification center (and in which order).
|
||||
@@ -164,9 +168,13 @@ in
|
||||
"dnd"
|
||||
"inhibitors"
|
||||
"buttons-grid"
|
||||
] ++ lib.optionals cfg.config.enableBacklight [
|
||||
"backlight"
|
||||
] ++ [
|
||||
"volume"
|
||||
] ++ lib.optionals cfg.config.enableMpris [
|
||||
"mpris"
|
||||
] ++ [
|
||||
"notifications"
|
||||
];
|
||||
widget-config = {
|
||||
@@ -228,7 +236,10 @@ in
|
||||
depends = [ "sound" ]; #< TODO: else it will NEVER see the pulse socket in its sandbox
|
||||
partOf = [ "graphical-session" ];
|
||||
|
||||
command = "env G_MESSAGES_DEBUG=all swaync";
|
||||
# N.B.: G_MESSAGES_DEBUG=all breaks DND mode:
|
||||
# messages are still hidden, but are not silent!
|
||||
# command = "env G_MESSAGES_DEBUG=all SWAYNC_DEBUG=1 swaync";
|
||||
command = "swaync";
|
||||
readiness.waitDbus = "org.freedesktop.Notifications";
|
||||
};
|
||||
};
|
||||
|
@@ -24,7 +24,7 @@
|
||||
# - SWAYNC_SUMMARY
|
||||
|
||||
# rules to use for testing. trigger with:
|
||||
# - `notify-send --app-id=foo subject body` (etc)
|
||||
# - `notify-send --app-name=foo subject body` (etc)
|
||||
# should also be possible to trigger via any messaging app
|
||||
fbcli-test-im = {
|
||||
body = "test:message";
|
||||
|
@@ -17,7 +17,12 @@ log() {
|
||||
checkActive() {
|
||||
# simulate a dry-run start. if no actions would be performed, then the service is up.
|
||||
# alternative is s6-svstat, but that doesn't support oneshots
|
||||
test -z "$(s6-rc -n 0 -b start "$service")" && echo true || echo false
|
||||
local s6Output=$(s6-rc -n 0 -b start "$service")
|
||||
if [ -z "$s6Output" ]; then
|
||||
echo true
|
||||
else
|
||||
echo false
|
||||
fi
|
||||
}
|
||||
startService() {
|
||||
log "startService: $service"
|
||||
|
@@ -1,3 +1,6 @@
|
||||
# BUGS
|
||||
# - switchboard-plug-sound errors because
|
||||
# GLib-GIO-ERROR **: Settings schema 'org.gnome.settings-daemon.plugins.media-keys' is not installed
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
sane.programs.switchboard = {
|
||||
@@ -24,5 +27,9 @@
|
||||
];
|
||||
xorg = pkgs.buildPackages.xorg; #< cross compilation fix (TODO: upstream)
|
||||
};
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.whitelistDbus = [ "system" ]; #< to speak with NetworkManager
|
||||
sandbox.whitelistAudio = true; #< even with this, the sound plugin doesn't seem to work...
|
||||
};
|
||||
}
|
||||
|
@@ -1,11 +1,15 @@
|
||||
{ ... }:
|
||||
{
|
||||
sane.programs.sysvol = {
|
||||
sane.programs.syshud = {
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.whitelistAudio = true;
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.extraPaths = [
|
||||
"/sys/class/backlight" #< crashes if unable to access this directory
|
||||
# "/sys/devices" #< only if you want it to actually show when the backlight changes
|
||||
];
|
||||
|
||||
fs.".config/sys64/volume.css".symlink.text = ''
|
||||
fs.".config/sys64/hud.css".symlink.text = ''
|
||||
window {
|
||||
background: transparent;
|
||||
}
|
||||
@@ -53,8 +57,8 @@
|
||||
}
|
||||
'';
|
||||
|
||||
services."sysvol" = {
|
||||
description = "sysvol: volume monitor/notifier";
|
||||
services."syshud" = {
|
||||
description = "syshud: volume monitor/notifier";
|
||||
depends = [ "sound" ]; #< specifically wireplumber-pulse
|
||||
partOf = [ "graphical-session" ];
|
||||
|
||||
@@ -67,7 +71,7 @@
|
||||
# -{H,W} N to set the height/width of the notifier, in px.
|
||||
# -i N to set the size of the volume icon
|
||||
# -P to hide percentage text
|
||||
command = "sysvol -p top -t 1 -T 0 -m 22 -H 39 -W 256 -i 32 -P";
|
||||
command = "syshud -p top -t 1 -T 0 -m 22 -H 39 -W 256 -i 32 -P";
|
||||
};
|
||||
};
|
||||
}
|
11
hosts/common/programs/where-am-i.nix
Normal file
11
hosts/common/programs/where-am-i.nix
Normal file
@@ -0,0 +1,11 @@
|
||||
{ config, pkgs, ... }:
|
||||
{
|
||||
sane.programs.where-am-i = {
|
||||
# packageUnwrapped = pkgs.linkIntoOwnPackage config.sane.programs.geoclue2.packageUnwrapped "libexec/geoclue-2.0/demos/where-am-i";
|
||||
packageUnwrapped = pkgs.linkFarm "where-am-i" [{
|
||||
# bring the `where-am-i` tool into a `bin/` directory so it can be invokable via PATH
|
||||
name = "bin/where-am-i";
|
||||
path = "${config.sane.programs.geoclue2.packageUnwrapped}/libexec/geoclue-2.0/demos/where-am-i";
|
||||
}];
|
||||
};
|
||||
}
|
@@ -1,13 +1,17 @@
|
||||
{ config, lib, sane-lib, ... }:
|
||||
|
||||
let
|
||||
keysForHost = hostName: let
|
||||
hostCfg = config.sane.hosts.by-name."${hostName}";
|
||||
in {
|
||||
"root@${hostName}" = hostCfg.ssh.host_pubkey;
|
||||
"colin@${hostName}" = lib.mkIf (hostCfg.ssh.user_pubkey != null && hostCfg.ssh.authorized) hostCfg.ssh.user_pubkey;
|
||||
};
|
||||
hostKeys = builtins.map keysForHost (builtins.attrNames config.sane.hosts.by-name);
|
||||
hostKeys = lib.mapAttrsToList
|
||||
(hostName: hostCfg:
|
||||
# generate `root@servo`, `colin@servo`, `root@servo-hn`, `colin@servo-hn`, ... as a single attrset:
|
||||
lib.foldl' (acc: alias: acc // {
|
||||
"root@${alias}" = hostCfg.ssh.host_pubkey;
|
||||
"colin@${alias}" = lib.mkIf (hostCfg.ssh.user_pubkey != null && hostCfg.ssh.authorized) hostCfg.ssh.user_pubkey;
|
||||
})
|
||||
{}
|
||||
hostCfg.names
|
||||
)
|
||||
config.sane.hosts.by-name;
|
||||
in
|
||||
{
|
||||
sane.ssh.pubkeys = lib.mkMerge (hostKeys ++ [
|
||||
|
@@ -1,10 +1,10 @@
|
||||
# trampoline from flake.nix into the specific host definition, while doing a tiny bit of common setup
|
||||
|
||||
# args from flake-level `import`
|
||||
{ hostName }:
|
||||
{ hostName, variant }:
|
||||
|
||||
# module args
|
||||
{ ... }:
|
||||
{ lib, ... }:
|
||||
|
||||
{
|
||||
imports = [
|
||||
@@ -14,4 +14,14 @@
|
||||
];
|
||||
|
||||
networking.hostName = hostName;
|
||||
system.name = if variant == null then
|
||||
hostName
|
||||
else
|
||||
"${hostName}-${variant}"
|
||||
;
|
||||
|
||||
sane = lib.mkMerge [
|
||||
(lib.mkIf (variant == "min") { maxBuildCost = 0; })
|
||||
(lib.mkIf (variant == "light") { maxBuildCost = 2; })
|
||||
];
|
||||
}
|
||||
|
@@ -45,6 +45,9 @@
|
||||
actions.screenoff.delay = 300;
|
||||
actions.screenoff.enable = true;
|
||||
};
|
||||
sane.programs.swaynotificationcenter.config = {
|
||||
enableMpris = false; #< consumes too much screen real-estate
|
||||
};
|
||||
|
||||
sane.programs.waybar.config = {
|
||||
fontSize = 14;
|
||||
@@ -63,6 +66,7 @@
|
||||
windowTitle = false;
|
||||
mediaPrevNext = false;
|
||||
mediaTitle = false;
|
||||
sysload = false;
|
||||
workspaceNumbers = [ "1" "2" "3" "4" "5" ];
|
||||
workspaceHideEmpty = false;
|
||||
};
|
||||
|
@@ -80,6 +80,7 @@ in
|
||||
protocol = [ "udp" ];
|
||||
visibleTo.lan = true;
|
||||
visibleTo.wan = cfg.visibleToWan;
|
||||
visibleTo.doof = cfg.visibleToWan;
|
||||
description = "colin-wireguard";
|
||||
};
|
||||
|
||||
|
62
impure.nix
Normal file
62
impure.nix
Normal file
@@ -0,0 +1,62 @@
|
||||
# this entry-point exposes all packages, hosts, etc, but with no purity guarnatees.
|
||||
# the intended way to use this is to first copy every .nix file and dependency in this repo to the nix store, then enter this file.
|
||||
# entering this file *before* copying anything into the nix store can cause interesting
|
||||
# race conditions or eval failures.
|
||||
#
|
||||
# see default.nix for a wrapper around this with better purity guarantees.
|
||||
{ }:
|
||||
let
|
||||
mkPkgs = args: (import ./pkgs/additional/nixpkgs args).extend
|
||||
(import ./overlays/all.nix);
|
||||
inherit (mkPkgs {}) lib;
|
||||
|
||||
evalHost = { name, system, branch ? "master", variant ? null }:
|
||||
let
|
||||
pkgs = mkPkgs { inherit system; variant = branch; };
|
||||
in pkgs.nixos (
|
||||
[
|
||||
(import ./hosts/instantiate.nix { hostName = name; inherit variant; })
|
||||
(import ./modules)
|
||||
pkgs.sops-nix.nixosModules.sops
|
||||
]
|
||||
);
|
||||
mkFlavoredHost = args: let
|
||||
host = evalHost args;
|
||||
# expose the toplevel nixos system as the toplevel attribute itself,
|
||||
# with nested aliases for other common build targets
|
||||
in host.config.system.build.toplevel.overrideAttrs (base: {
|
||||
passthru = (base.passthru or {}) // {
|
||||
config = host.config;
|
||||
fs = host.config.sane.fs;
|
||||
img = host.config.system.build.img;
|
||||
pkgs = host.config.system.build.pkgs;
|
||||
programs = lib.mapAttrs (_: p: p.package) host.config.sane.programs;
|
||||
toplevel = host.config.system.build.toplevel; #< self
|
||||
};
|
||||
});
|
||||
mkHost = args: {
|
||||
# TODO: swap order: $host-{next,staging}-{min,light}:
|
||||
# then lexicographically-adjacent targets would also have the minimal difference in closure,
|
||||
# and the order in which each target should be built is more evident
|
||||
"${args.name}" = mkFlavoredHost args;
|
||||
"${args.name}-next" = mkFlavoredHost (args // { branch = "staging-next"; });
|
||||
"${args.name}-staging" = mkFlavoredHost (args // { branch = "staging"; });
|
||||
"${args.name}-light" = mkFlavoredHost (args // { variant = "light"; });
|
||||
"${args.name}-light-next" = mkFlavoredHost (args // { variant = "light"; branch = "staging-next"; });
|
||||
"${args.name}-light-staging" = mkFlavoredHost (args // { variant = "light"; branch = "staging"; });
|
||||
"${args.name}-min" = mkFlavoredHost (args // { variant = "min"; });
|
||||
"${args.name}-min-next" = mkFlavoredHost (args // { variant = "min"; branch = "staging-next"; });
|
||||
"${args.name}-min-staging" = mkFlavoredHost (args // { variant = "min"; branch = "staging-staging"; });
|
||||
};
|
||||
|
||||
hosts = lib.foldl' (acc: host: acc // (mkHost host)) {} [
|
||||
{ name = "crappy"; system = "armv7l-linux"; }
|
||||
{ name = "desko"; system = "x86_64-linux"; }
|
||||
{ name = "lappy"; system = "x86_64-linux"; }
|
||||
{ name = "moby"; system = "aarch64-linux"; }
|
||||
{ name = "rescue"; system = "x86_64-linux"; }
|
||||
{ name = "servo"; system = "x86_64-linux"; }
|
||||
];
|
||||
in {
|
||||
inherit hosts;
|
||||
} // (mkPkgs {})
|
5
integrations/nix-update/default.nix
Normal file
5
integrations/nix-update/default.nix
Normal file
@@ -0,0 +1,5 @@
|
||||
# this is the entry point for `nix-update`, used when i update the packages in this repo.
|
||||
# nix-update needs to work on the actual out-of-store source,
|
||||
# which means it can't call through the hermetic `default.nix` at the top of this repo,
|
||||
# but rather needs the in-place `impure.nix` entry point.
|
||||
import ../../impure.nix
|
@@ -26,9 +26,10 @@ let
|
||||
};
|
||||
};
|
||||
mkNetNsConfig = name: opts: with opts; {
|
||||
networking.localCommands = let
|
||||
iptables = "${pkgs.iptables}/bin/iptables";
|
||||
in-ns = "ip netns exec ${name}";
|
||||
systemd.services."netns-${name}" = let
|
||||
ip = lib.getExe' pkgs.iproute2 "ip";
|
||||
iptables = lib.getExe pkgs.iptables;
|
||||
in-ns = "${ip} netns exec ${name}";
|
||||
bridgePort = port: proto: ''
|
||||
${in-ns} ${iptables} -A PREROUTING -t nat -p ${proto} --dport ${port} -m iprange --dst-range ${netnsPubIpv4} \
|
||||
-j DNAT --to-destination ${hostVethIpv4}
|
||||
@@ -41,55 +42,61 @@ let
|
||||
config.sane.ports.ports
|
||||
)
|
||||
;
|
||||
in ''
|
||||
ip netns add ${name} || (test -e /run/netns/${name} && echo "${name} already exists")
|
||||
# DOCS:
|
||||
# - some of this approach is described here: <https://josephmuia.ca/2018-05-16-net-namespaces-veth-nat/>
|
||||
# - iptables primer: <https://danielmiessler.com/study/iptables/>
|
||||
# create veth pair
|
||||
ip link add ${name}-veth-a type veth peer name ${name}-veth-b || echo "${name}-veth-{a,b} aleady exists"
|
||||
ip addr add ${hostVethIpv4}/24 dev ${name}-veth-a || echo "${name}-veth-a aleady has IP address"
|
||||
ip link set ${name}-veth-a up
|
||||
in {
|
||||
description = "create a network namespace which will selectively bridge traffic with the init namespace";
|
||||
# specifically, we need to set these up before wireguard-wg-*,
|
||||
wantedBy = [ "network-pre.target" ];
|
||||
before = [ "network-pre.target" ];
|
||||
serviceConfig.Type = "oneshot";
|
||||
serviceConfig.RemainAfterExit = true;
|
||||
script = ''
|
||||
${ip} netns add ${name} || (test -e /run/netns/${name} && echo "${name} already exists")
|
||||
# DOCS:
|
||||
# - some of this approach is described here: <https://josephmuia.ca/2018-05-16-net-namespaces-veth-nat/>
|
||||
# - iptables primer: <https://danielmiessler.com/study/iptables/>
|
||||
# create veth pair
|
||||
${ip} link add ${name}-veth-a type veth peer name ${name}-veth-b || echo "${name}-veth-{a,b} aleady exists"
|
||||
${ip} addr add ${hostVethIpv4}/24 dev ${name}-veth-a || echo "${name}-veth-a aleady has IP address"
|
||||
${ip} link set ${name}-veth-a up
|
||||
|
||||
# move veth-b into the namespace
|
||||
ip link set ${name}-veth-b netns ${name} || echo "${name}-veth-b was already moved into its netns"
|
||||
${in-ns} ip addr add ${netnsVethIpv4}/24 dev ${name}-veth-b || echo "${name}-veth-b aleady has IP address"
|
||||
${in-ns} ip link set ${name}-veth-b up
|
||||
# move veth-b into the namespace
|
||||
${ip} link set ${name}-veth-b netns ${name} || echo "${name}-veth-b was already moved into its netns"
|
||||
${in-ns} ${ip} addr add ${netnsVethIpv4}/24 dev ${name}-veth-b || echo "${name}-veth-b aleady has IP address"
|
||||
${in-ns} ${ip} link set ${name}-veth-b up
|
||||
|
||||
# make it so traffic originating from the host side of the veth
|
||||
# is sent over the veth no matter its destination.
|
||||
ip rule add from ${hostVethIpv4} lookup ${name} pref 50 || echo "${name} already has ip rules (pref 50)"
|
||||
# make it so traffic originating from the host side of the veth
|
||||
# is sent over the veth no matter its destination.
|
||||
${ip} rule add from ${hostVethIpv4} lookup ${name} pref 50 || echo "${name} already has ip rules (pref 50)"
|
||||
|
||||
# for traffic originating at the host veth to the WAN, use the veth as our gateway
|
||||
# not sure if the metric 1002 matters.
|
||||
ip route add default via ${netnsVethIpv4} dev ${name}-veth-a proto kernel src ${hostVethIpv4} metric 1002 table ${name} || \
|
||||
echo "${name} already has default route"
|
||||
# give the default route lower priority
|
||||
ip rule add from all lookup local pref 100 || echo "${name}: already has ip rules (pref 100)"
|
||||
ip rule del from all lookup local pref 0 || echo "${name}: already removed ip rule of default lookup (pref 0)"
|
||||
# for traffic originating at the host veth to the WAN, use the veth as our gateway
|
||||
# not sure if the metric 1002 matters.
|
||||
${ip} route add default via ${netnsVethIpv4} dev ${name}-veth-a proto kernel src ${hostVethIpv4} metric 1002 table ${name} || \
|
||||
echo "${name} already has default route"
|
||||
# give the default route lower priority
|
||||
${ip} rule add from all lookup local pref 100 || echo "${name}: already has ip rules (pref 100)"
|
||||
${ip} rule del from all lookup local pref 0 || echo "${name}: already removed ip rule of default lookup (pref 0)"
|
||||
|
||||
# in order to access DNS in this netns, we need to route it to the VPN's nameservers
|
||||
# - alternatively, we could fix DNS servers like 1.1.1.1.
|
||||
${in-ns} ${iptables} -A OUTPUT -t nat -p udp --dport 53 -m iprange --dst-range 127.0.0.53 \
|
||||
-j DNAT --to-destination ${dns}:53
|
||||
'' + (lib.concatStringsSep "\n" bridgeStatements);
|
||||
# in order to access DNS in this netns, we need to route it to the VPN's nameservers
|
||||
# - alternatively, we could fix DNS servers like 1.1.1.1.
|
||||
${in-ns} ${iptables} -A OUTPUT -t nat -p udp --dport 53 -m iprange --dst-range 127.0.0.53 \
|
||||
-j DNAT --to-destination ${dns}:53
|
||||
'' + (lib.concatStringsSep "\n" bridgeStatements);
|
||||
preStop = ''
|
||||
${in-ns} ${ip} link del ${name}-veth-b || echo "couldn't delete ${name}-veth-b"
|
||||
${ip} link del ${name}-veth-a || echo "couldn't delete ${name}-veth-a"
|
||||
${ip} netns delete ${name} || echo "couldn't delete ${name}"
|
||||
# restore rules/routes
|
||||
${ip} rule del from ${hostVethIpv4} lookup ${name} pref 50 || echo "couldn't delete init -> ${name} rule"
|
||||
${ip} route del default via ${netnsVethIpv4} dev ${name}-veth-a proto kernel src ${hostVethIpv4} metric 1002 table ${name} || echo "couldn't delete init > ${name} route"
|
||||
# FIXME: if there are other net namespaces active, changing the prefs here may break those!
|
||||
${ip} rule add from all lookup local pref 0
|
||||
${ip} rule del from all lookup local pref 100
|
||||
'';
|
||||
};
|
||||
|
||||
# postShutdown = ''
|
||||
# ${in-ns} ip link del ${name}-veth-b || echo "couldn't delete ${name}-veth-b"
|
||||
# ip link del ${name}-veth-a || echo "couldn't delete ${name}-veth-a"
|
||||
# ip netns delete ${name} || echo "couldn't delete ${name}"
|
||||
# # restore rules/routes
|
||||
# ip rule del from ${veth-host-ip} lookup ${name} pref 50 || echo "couldn't delete init -> ${name} rule"
|
||||
# ip route del default via ${veth-local-ip} dev ${name}-veth-a proto kernel src ${veth-host-ip} metric 1002 table ${name} || echo "couldn't delete init > #{name} route"
|
||||
# ip rule add from all lookup local pref 0
|
||||
# ip rule del from all lookup local pref 100
|
||||
# '';
|
||||
|
||||
# specifically, we need to set these up before wireguard-wg-*,
|
||||
# whose unit files are BEFORE "network.target", and therefore
|
||||
# ordered ambiguously w.r.t. network-local-commands (a dep of "network.target").
|
||||
systemd.services.network-local-commands.wantedBy = [ "network-pre.target" ];
|
||||
systemd.services.network-local-commands.before = [ "network-pre.target" ];
|
||||
# for some reason network-pre doesn't actually get run before network.target by default??
|
||||
systemd.targets.network-pre.wantedBy = [ "network.target" ];
|
||||
systemd.targets.network-pre.before = [ "network.target" ];
|
||||
|
||||
# create a new routing table that we can use to proxy traffic out of the root namespace
|
||||
# through the wireguard namespaces, and to the WAN via VPN.
|
||||
@@ -114,7 +121,8 @@ in
|
||||
networking.localCommands = f.networking.localCommands;
|
||||
networking.iproute2.rttablesExtraConfig = f.networking.iproute2.rttablesExtraConfig;
|
||||
networking.iproute2.enable = f.networking.iproute2.enable;
|
||||
systemd.services.network-local-commands = f.systemd.services.network-local-commands;
|
||||
systemd.services = f.systemd.services;
|
||||
systemd.targets.network-pre = f.systemd.targets.network-pre;
|
||||
};
|
||||
in take (sane-lib.mkTypedMerge take configs);
|
||||
}
|
||||
|
@@ -96,7 +96,13 @@ let
|
||||
} // extraConfig
|
||||
);
|
||||
configPath = "/var/lib/trust-dns/${flavor}-config.toml";
|
||||
sedArgs = lib.mapAttrsToList (key: value: ''-e "s/${key}/${value}/g"'') substitutions;
|
||||
sedArgs = builtins.map (key: ''-e "s/${key}/${substitutions."${key}"}/g"'') (
|
||||
# HACK: %ANATIVE% often expands to one of the other subtitutions (e.g. %AWAN%)
|
||||
# so we must expand it *first*.
|
||||
lib.sortOn
|
||||
(k: if k == "%ANATIVE%" then 0 else 1)
|
||||
(builtins.attrNames substitutions)
|
||||
);
|
||||
subs = lib.concatStringsSep " " sedArgs;
|
||||
in {
|
||||
description = "trust-dns Domain Name Server (serving ${flavor})";
|
||||
|
@@ -127,14 +127,12 @@ let
|
||||
FirewallMark = fwmark;
|
||||
};
|
||||
wireguardPeers = [{
|
||||
wireguardPeerConfig = {
|
||||
AllowedIPs = [
|
||||
"0.0.0.0/0"
|
||||
"::/0"
|
||||
];
|
||||
Endpoint = endpoint;
|
||||
PublicKey = publicKey;
|
||||
};
|
||||
AllowedIPs = [
|
||||
"0.0.0.0/0"
|
||||
"::/0"
|
||||
];
|
||||
Endpoint = endpoint;
|
||||
PublicKey = publicKey;
|
||||
}];
|
||||
};
|
||||
|
||||
@@ -149,10 +147,10 @@ let
|
||||
# Domains = ~.: system DNS queries are sent to this link's DNS server
|
||||
# networkConfig.Domains = "~.";
|
||||
routes = [{
|
||||
routeConfig.Table = id;
|
||||
routeConfig.Scope = "link";
|
||||
routeConfig.Destination = "0.0.0.0/0";
|
||||
routeConfig.Source = addrV4;
|
||||
Table = id;
|
||||
Scope = "link";
|
||||
Destination = "0.0.0.0/0";
|
||||
Source = addrV4;
|
||||
}];
|
||||
# RequiredForOnline => should `systemd-networkd-wait-online` fail if this network can't come up?
|
||||
linkConfig.RequiredForOnline = false;
|
||||
|
@@ -2,17 +2,18 @@
|
||||
, fetchFromGitHub
|
||||
, lib
|
||||
, makeWrapper
|
||||
, nix-update-script
|
||||
, pulseaudio
|
||||
}:
|
||||
buildGoModule rec {
|
||||
pname = "blast-ugjka";
|
||||
version = "0.6.2";
|
||||
version = "0.7.0";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "ugjka";
|
||||
repo = "blast";
|
||||
rev = "v${version}";
|
||||
hash = "sha256-Y9Jj+UrrsyRfihHAdC354jb1385xqLIufB0DoikrXYM=";
|
||||
hash = "sha256-yMwMG0y2ehq2dBMlv9hF+i0TgmMjW3ojBVGiqEUSrhU=";
|
||||
};
|
||||
|
||||
vendorHash = "sha256-yPwLilMiDR1aSeuk8AEmuYPsHPRWqiByGLwgkdI5t+s=";
|
||||
@@ -26,10 +27,12 @@ buildGoModule rec {
|
||||
--suffix PATH : ${lib.makeBinPath [ pulseaudio ]}
|
||||
'';
|
||||
|
||||
passthru.updateScript = nix-update-script { };
|
||||
|
||||
meta = with lib; {
|
||||
description = "blast your linux audio to DLNA receivers";
|
||||
# license = licenses.mit; # MIT + NoAI
|
||||
inherit (src.meta) homepage;
|
||||
homepage = "https://github.com/ugjka/blast";
|
||||
maintainers = with maintainers; [ colinsane ];
|
||||
platforms = platforms.unix;
|
||||
};
|
||||
|
@@ -8,6 +8,15 @@
|
||||
#
|
||||
# this script downloads assisted GPS (AGPS) data via the system's default gateway (i.e. WiFi)
|
||||
# and shares that with the modem. this quickens the process of acquiring a GPS fix.
|
||||
# AGPS data includes an almanac and "ephemeris" [Wikipedia-GPS_signals#Navigation_message]
|
||||
# - Almanac: valid for 2 weeks; status & low-res orbital info for *all* satellites.
|
||||
# - used to know which GPS signals to *search* for.
|
||||
# - every sat broadcasts the global almanac over 12.5min cycles.
|
||||
# - Ephemeris: valid for 4 hours; precise orbital info for each satellite.
|
||||
# - takes 30s to learn this info w/o AGPS data.
|
||||
# - every sat broadcasts *its own* ephemeris over 30s cycles.
|
||||
#
|
||||
# [Wikipedia-GPS_signals#Navigation_message]: https://en.wikipedia.org/wiki/GPS_signals#Navigation_message
|
||||
#
|
||||
# the script may also configure other parts of the modem as `eg25-manager` does.
|
||||
# these options are less tested: see `--help` for more.
|
||||
|
@@ -145,8 +145,8 @@ in (lib.makeScope newScope (self: with self; {
|
||||
extid = "webextension@metamask.io";
|
||||
pname = "ether-metamask";
|
||||
url = "https://github.com/MetaMask/metamask-extension/releases/download/v${version}/metamask-firefox-${version}.zip";
|
||||
version = "11.16.9";
|
||||
hash = "sha256-IYRCR0jX2agMHj/Pnnc+q6X92yrhdIJF+uRtw7C2T2k=";
|
||||
version = "11.16.13";
|
||||
hash = "sha256-aiWFfGGbjFfKEJSe2wnCfxSABs6ELQ2h0x90IAF3wec=";
|
||||
};
|
||||
fx_cast = fetchVersionedAddon rec {
|
||||
extid = "fx_cast@matt.tf";
|
||||
@@ -173,8 +173,8 @@ in (lib.makeScope newScope (self: with self; {
|
||||
extid = "@ublacklist";
|
||||
pname = "ublacklist";
|
||||
url = "https://github.com/iorate/ublacklist/releases/download/v${version}/ublacklist-v${version}-firefox.zip";
|
||||
version = "8.7.1";
|
||||
hash = "sha256-FvZ2IFlvoAYMmZFXTkGtCZ+44MmXioA271DXvNY96j8=";
|
||||
version = "8.8.1";
|
||||
hash = "sha256-b9XiA62Hc32enn04DfUJDVW+Wab5zKgUFwO+oFeTT/w=";
|
||||
};
|
||||
ublock-origin = fetchVersionedAddon rec {
|
||||
extid = "uBlock0@raymondhill.net";
|
||||
|
@@ -1,13 +1,14 @@
|
||||
{ buildLinux
|
||||
{ lib
|
||||
, buildLinux
|
||||
, fetchFromGitLab
|
||||
#v nixpkgs calls `.override` on the kernel to configure additional things
|
||||
, features ? {}
|
||||
, kernelPatches ? []
|
||||
, kernelPatches ? null
|
||||
, randstructSeed ? ""
|
||||
, structuredExtraConfig ? {}
|
||||
, ...
|
||||
}:
|
||||
buildLinux {
|
||||
buildLinux ({
|
||||
src = fetchFromGitLab {
|
||||
owner = "exynos5-mainline";
|
||||
repo = "linux";
|
||||
@@ -23,5 +24,9 @@ buildLinux {
|
||||
autoModules = false;
|
||||
# preferBuiltin = false;
|
||||
|
||||
inherit features kernelPatches randstructSeed structuredExtraConfig;
|
||||
}
|
||||
inherit features randstructSeed structuredExtraConfig;
|
||||
} // lib.optionalAttrs (builtins.isList kernelPatches) {
|
||||
# callPackage mucks with `kernelPatches`: only forward this argument if it's a list,
|
||||
# as expected by `buildLinux`
|
||||
inherit kernelPatches;
|
||||
})
|
||||
|
@@ -7,8 +7,8 @@ let
|
||||
src = fetchFromGitHub {
|
||||
owner = "nix-community";
|
||||
repo = "nixpkgs-wayland";
|
||||
rev = "422bb5c5106008418f499ca591c0138f73e213f4";
|
||||
hash = "sha256-32ukRcPI2W5exf4A7/ISqoKp+sL1MxdMjFt3I+8XS5Y=";
|
||||
rev = "d0eb8a2eb4b9e30e10b95ed5d99f3501c1b3367d";
|
||||
hash = "sha256-WA75k8/SJkHd+qaLUJFy4uGM95wDn/18wv+awR0kTbo=";
|
||||
};
|
||||
flake = import "${src}/flake.nix";
|
||||
evaluated = flake.outputs {
|
||||
@@ -25,7 +25,7 @@ let
|
||||
in src.overrideAttrs (base: {
|
||||
# attributes required by update scripts
|
||||
pname = "nixpkgs-wayland";
|
||||
version = "0-unstable-2024-06-14";
|
||||
version = "0-unstable-2024-06-21";
|
||||
src = src;
|
||||
|
||||
# passthru only nixpkgs-wayland's own packages -- not the whole nixpkgs-with-nixpkgs-wayland-as-overlay:
|
||||
|
@@ -27,12 +27,12 @@
|
||||
}:
|
||||
let
|
||||
lock = {
|
||||
master.rev = "bac3e728035fee7d7fd3df57e7bb89298d1b1b2e";
|
||||
master.sha256 = "sha256-tW1Tzz/2SX8HiAXkQm6IbsRbzQuPH9W/ouoTt+bUGdk=";
|
||||
staging.rev = "bac3e728035fee7d7fd3df57e7bb89298d1b1b2e";
|
||||
staging.sha256 = "sha256-tW1Tzz/2SX8HiAXkQm6IbsRbzQuPH9W/ouoTt+bUGdk=";
|
||||
staging-next.rev = "bac3e728035fee7d7fd3df57e7bb89298d1b1b2e";
|
||||
staging-next.sha256 = "sha256-tW1Tzz/2SX8HiAXkQm6IbsRbzQuPH9W/ouoTt+bUGdk=";
|
||||
master.rev = "124ae37067e998cc9286daccf1f222d651c6bef5";
|
||||
master.sha256 = "sha256-7GVAIzW3dgQrUpqrcOlZct8KnT+O9isobOvM/08fYIU=";
|
||||
staging.rev = "124ae37067e998cc9286daccf1f222d651c6bef5";
|
||||
staging.sha256 = "sha256-7GVAIzW3dgQrUpqrcOlZct8KnT+O9isobOvM/08fYIU=";
|
||||
staging-next.rev = "124ae37067e998cc9286daccf1f222d651c6bef5";
|
||||
staging-next.sha256 = "sha256-7GVAIzW3dgQrUpqrcOlZct8KnT+O9isobOvM/08fYIU=";
|
||||
};
|
||||
lock' = lock."${variant}";
|
||||
unpatchedSrc = fetchzip {
|
||||
@@ -81,7 +81,7 @@ in
|
||||
src.overrideAttrs (base: {
|
||||
# attributes needed for update scripts
|
||||
pname = "nixpkgs";
|
||||
version = "24.05-unstable-2024-06-15";
|
||||
version = "24.05-unstable-2024-06-21";
|
||||
passthru = (base.passthru or {}) // nixpkgs // {
|
||||
src = unpatchedSrc // {
|
||||
inherit (lock') rev;
|
||||
|
@@ -30,6 +30,14 @@ in
|
||||
# hash = "sha256-fGuS46f9qSMRHvWZvTmcirKufIqlXHwwhckeK1RNejE=";
|
||||
# })
|
||||
|
||||
(fetchpatch' {
|
||||
# xsimd is required by scipy, which is required by ols
|
||||
title = "xsimd: fix cross compilation";
|
||||
# prUrl = "https://github.com/NixOS/nixpkgs/pull/321253";
|
||||
prUrl = "https://github.com/NixOS/nixpkgs/pull/321288";
|
||||
hash = "sha256-jeRM/dfnljX0i3lHsg8bPfQXO3+Wx9M+hSypJiG9MfE=";
|
||||
})
|
||||
|
||||
(fetchpatch' {
|
||||
title = "unl0kr: 2.0.0 -> 3.2.0";
|
||||
prUrl = "https://github.com/NixOS/nixpkgs/pull/319126";
|
||||
@@ -37,9 +45,9 @@ in
|
||||
})
|
||||
|
||||
(fetchpatch' {
|
||||
title = "sysvol: init at 0-unstable-2024-06-07";
|
||||
title = "syshud: init at 0-unstable-2024-06-20";
|
||||
prUrl = "https://github.com/NixOS/nixpkgs/pull/318440";
|
||||
hash = "sha256-OX1OP2m9LJYjVcryhpt520XJmdK1XS0KKaEBzMjdpNo=";
|
||||
hash = "sha256-jVw5pC+f8Z68S/X9EvMB6nbwvoiR03qI7ALeLtkmN24=";
|
||||
})
|
||||
|
||||
(fetchpatch' {
|
||||
|
32
pkgs/additional/opencellid/default.nix
Normal file
32
pkgs/additional/opencellid/default.nix
Normal file
@@ -0,0 +1,32 @@
|
||||
{ stdenv
|
||||
, lib
|
||||
, fetchurl
|
||||
# database downloads are limited per API key, so please consider supplying your own API key if using this package
|
||||
, apiKey ? "pk.758ba60a9bf5fc060451153c3e2542dc"
|
||||
}:
|
||||
|
||||
stdenv.mkDerivation {
|
||||
pname = "opencellid";
|
||||
version = "0-unstable-2024-06-20";
|
||||
|
||||
src = fetchurl {
|
||||
# this is a live url. updated daily? TODO: add an update script for this.
|
||||
# the API key should allow for at least 2 downloads per day
|
||||
url = "https://opencellid.org/ocid/downloads?token=${apiKey}&type=full&file=cell_towers.csv.gz";
|
||||
hash = "sha256-uY9nHY/LHPJSqMjvIpRgiW++fzucRn1JwPdNXE63bq8=";
|
||||
};
|
||||
|
||||
unpackPhase = ''
|
||||
gunzip "$src" --stdout > cell_towers.csv
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
cp cell_towers.csv $out
|
||||
'';
|
||||
|
||||
meta = with lib; {
|
||||
description = "100M-ish csv database of known celltower positions";
|
||||
homepage = "https://opencellid.org";
|
||||
maintainers = with maintainers; [ colinsane ];
|
||||
};
|
||||
}
|
@@ -1,34 +1,54 @@
|
||||
{
|
||||
findutils,
|
||||
runCommandLocal,
|
||||
rsync,
|
||||
}:
|
||||
runCommandLocal "sane-nix-files" {
|
||||
nativeBuildInputs = [
|
||||
findutils
|
||||
rsync
|
||||
];
|
||||
{ stdenv ? null }:
|
||||
with builtins;
|
||||
let
|
||||
src = filterSource
|
||||
(path: type:
|
||||
let name = baseNameOf path;
|
||||
in !(
|
||||
# mimic .gitignore
|
||||
(name == ".working")
|
||||
|| (name == "result")
|
||||
|| (match "^result-.*" name != null)
|
||||
))
|
||||
../../../.
|
||||
;
|
||||
|
||||
meta = {
|
||||
description = "top-level host configs for Colin's machines";
|
||||
longDescription = ''
|
||||
i like to ensure a copy of my config is present on all my machines,
|
||||
and this does that in a hermetic way.
|
||||
'';
|
||||
fakeDeriv = {
|
||||
# in the bootstrap path, we don't have enough available to actually
|
||||
# link these files into a derivation.
|
||||
# but that's ok, because the caller immediately `import`s it anyway,
|
||||
# so just yield something importable.
|
||||
outPath = src;
|
||||
};
|
||||
realDeriv = stdenv.mkDerivation {
|
||||
name = "sane-nix-files";
|
||||
inherit src;
|
||||
installPhase = ''
|
||||
ln -s "$src" "$out"
|
||||
'';
|
||||
dontFixup = true;
|
||||
};
|
||||
} ''
|
||||
mkdir src
|
||||
pushd src
|
||||
|
||||
rsync -lptr ${../../../.}/ ./
|
||||
chmod u+w .
|
||||
for pat in $(cat .gitignore); do
|
||||
set +e
|
||||
chmod u+w -R "$pat" ; rm -rf "$pat"
|
||||
find $PWD -name "$pat" -exec 'chmod u+w -R {}; rm -rf {}' \;
|
||||
set -e
|
||||
done
|
||||
rsync -lptr ./ $out/
|
||||
# alternative implementation which always returns a real derivation,
|
||||
# but requires a pre-compiled statically-linked `sln` or `cp` implementation.
|
||||
# self = derivation {
|
||||
# name = "sane-nix-files";
|
||||
# system = "x86_64-linux";
|
||||
|
||||
popd
|
||||
''
|
||||
# # builder = "${./sln}";
|
||||
# # args = [
|
||||
# # src
|
||||
# # self.outPath
|
||||
# # ];
|
||||
|
||||
# builder = "/bin/sh";
|
||||
# args = [
|
||||
# "-c"
|
||||
# "${./sln} ${src} $out"
|
||||
# ];
|
||||
# };
|
||||
in
|
||||
if stdenv == null then
|
||||
fakeDeriv
|
||||
else
|
||||
realDeriv
|
||||
|
@@ -35,6 +35,9 @@ configureKeyboardFor_application() {
|
||||
# io.github.lainsce.Notejot.desktop)
|
||||
# setKeyboard showIfRoom
|
||||
# ;;
|
||||
networkmanager_dmenu.desktop)
|
||||
setKeyboard showIfRoom
|
||||
;;
|
||||
org.gnome.Epiphany.desktop)
|
||||
setKeyboard showIfRoom
|
||||
;;
|
||||
|
@@ -12,6 +12,7 @@ usageDescription() {
|
||||
echo "sane-vpn up [REGION]"
|
||||
echo "sane-vpn down [REGION]"
|
||||
echo "sane-vpn do [REGION [COMMAND ...] ]"
|
||||
echo "sane-vpn do -- [COMMAND ...]"
|
||||
echo "sane-vpn dns-fix"
|
||||
echo "sane-vpn help"
|
||||
}
|
||||
@@ -63,7 +64,7 @@ canonicalizeRegion() {
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -z "$region" ] || [ "$region" = "default" ]; then
|
||||
if [ -z "$region" ] || [ "$region" = "default" ] || [ "$region" = "-" ] || [ "$region" = "--" ]; then
|
||||
debug "canonicalizing default region to '$defaultVpn'"
|
||||
region="$defaultVpn"
|
||||
fi
|
||||
|
@@ -1,5 +1,5 @@
|
||||
{ static-nix-shell }:
|
||||
static-nix-shell.mkPython3Bin {
|
||||
pname = "sane-sysinfo";
|
||||
pname = "sane-sysload";
|
||||
srcRoot = ./.;
|
||||
}
|
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -i python3 -p "python3.withPackages (ps: [ ])"
|
||||
"""
|
||||
usage: sane-sysinfo [options...]
|
||||
usage: sane-sysload [options...] formatstr
|
||||
|
||||
pretty-prints a battery estimate (icon to indicate state, and a duration estimate)
|
||||
|
||||
@@ -11,10 +11,24 @@ options:
|
||||
--hour-suffix <string>: use the provided string as an hours suffix
|
||||
--icon-suffix <string>: use the provided string as an icon suffix
|
||||
--percent-suffix <string>: use the provided string when displaying percents
|
||||
|
||||
formatstr is a Python format string.
|
||||
variables available for formatting:
|
||||
- {bat_icon}
|
||||
- {bat_time}
|
||||
- {cpu_icon}
|
||||
- {cpu_pct}
|
||||
- {mem_icon}
|
||||
- {mem_pct}
|
||||
and some presets, encapsulating the above:
|
||||
- {bat}
|
||||
- {cpu}
|
||||
- {mem}
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import logging
|
||||
import time
|
||||
|
||||
from dataclasses import dataclass
|
||||
from enum import Enum
|
||||
@@ -24,6 +38,7 @@ logger = logging.getLogger(__name__)
|
||||
# these icons may only render in nerdfonts
|
||||
ICON_BAT_CHG = ["", "", "", ""]
|
||||
ICON_BAT_DIS = ["", "", "", ""]
|
||||
ICON_CPU=""
|
||||
ICON_MEM="☵"
|
||||
SUFFIX_ICON = " " # thin space
|
||||
SUFFIX_PERCENT = "%"
|
||||
@@ -72,6 +87,9 @@ class Formatter:
|
||||
def render_charge_icon(self, direction: ChargeDirection, percentage: float) -> str:
|
||||
return f"{self._choose_icon(direction, percentage)}{self.suffix_icon}"
|
||||
|
||||
def render_cpu_icon(self) -> str:
|
||||
return f"{ICON_CPU}{self.suffix_icon}"
|
||||
|
||||
def render_mem_icon(self) -> str:
|
||||
return f"{ICON_MEM}{self.suffix_icon}"
|
||||
|
||||
@@ -137,6 +155,83 @@ class MemInfo:
|
||||
logger.debug(f"/proc/meminfo: {entry}={v}")
|
||||
return v
|
||||
|
||||
class ProcStat:
|
||||
"""
|
||||
reads vaues from /proc/stat, mostly CPU-related.
|
||||
"""
|
||||
# /proc/stat format is documented here: <https://www.linuxhowtos.org/System/procstat.htm>
|
||||
# these are AGGREGATES SINCE SYSTEM BOOT
|
||||
# to measure current CPU usage, need to take multiple samples
|
||||
# cpu <user> <system> <nice> <idle> <iowait> <irg> <softirq> 0 0 0
|
||||
# (what are the last three fields?)
|
||||
# where:
|
||||
# measurements are in units of jiffies or USER_HZ
|
||||
# user: normal processes executing in user mode
|
||||
# nice: niced processes executing in user mode
|
||||
# system: processes executing in kernel mode
|
||||
# idle: twiddling thumbs
|
||||
# iowait: waiting for I/O to complete
|
||||
# irq: servicing interrupts
|
||||
# softirq: servicing softirqs
|
||||
def __init__(self, entries=None):
|
||||
if entries is not None:
|
||||
self.entries = entries
|
||||
return
|
||||
|
||||
# else, read from procfs...
|
||||
try:
|
||||
lines = open("/proc/stat").readlines()
|
||||
except Exception as e:
|
||||
logger.info(f"failed to open /proc/stat: {e}")
|
||||
lines = []
|
||||
|
||||
self.entries = {}
|
||||
for l in lines:
|
||||
pieces = l.strip().split(" ")
|
||||
name, values = pieces[0], [p for p in pieces[1:] if p]
|
||||
if name:
|
||||
self.entries[name] = [int(v) for v in values]
|
||||
|
||||
@staticmethod
|
||||
def sample(seconds: float = 1.0):
|
||||
sample1 = ProcStat()
|
||||
time.sleep(seconds)
|
||||
sample2 = ProcStat()
|
||||
return sample2 - sample1
|
||||
|
||||
def __sub__(self, other: 'ProcStat') -> 'ProcStat':
|
||||
entries = {}
|
||||
for k in self.entries:
|
||||
entries[k] = [i - j for i, j in zip(self.entries[k], other.entries[k])]
|
||||
return ProcStat(entries)
|
||||
|
||||
@property
|
||||
def cpu_user(self) -> int:
|
||||
return self.entries["cpu"][0]
|
||||
@property
|
||||
def cpu_system(self) -> int:
|
||||
return self.entries["cpu"][1]
|
||||
@property
|
||||
def cpu_nice(self) -> int:
|
||||
return self.entries["cpu"][2]
|
||||
@property
|
||||
def cpu_idle(self) -> int:
|
||||
return self.entries["cpu"][3]
|
||||
@property
|
||||
def cpu_iowait(self) -> int:
|
||||
return self.entries["cpu"][4]
|
||||
@property
|
||||
def cpu_irq(self) -> int:
|
||||
return self.entries["cpu"][5]
|
||||
@property
|
||||
def cpu_softirq(self) -> int:
|
||||
return self.entries["cpu"][6]
|
||||
|
||||
@property
|
||||
def cpu_total(self) -> int:
|
||||
# TODO: not sure if i'm supposed to include irq stuff here?
|
||||
return self.cpu_user + self.cpu_system + self.cpu_nice + self.cpu_idle + self.cpu_iowait + self.cpu_irq + self.cpu_softirq
|
||||
|
||||
class PowerSupply:
|
||||
"""
|
||||
reads values from /sys/class/power_supply/$dev/ API
|
||||
@@ -263,9 +358,39 @@ def try_all_batteries() -> BatteryInfo | None:
|
||||
@dataclass
|
||||
class AllInfo:
|
||||
_fmt: Formatter
|
||||
_mem: MemInfo | None
|
||||
_bat: BatteryInfo | None
|
||||
__bat: BatteryInfo | None = None
|
||||
__cpu: ProcStat | None = None
|
||||
__mem: MemInfo | None = None
|
||||
|
||||
# lazy-loading
|
||||
@property
|
||||
def _bat(self):
|
||||
if self.__bat is None:
|
||||
self.__bat = try_all_batteries()
|
||||
return self.__bat
|
||||
@property
|
||||
def _cpu(self):
|
||||
if self.__cpu is None:
|
||||
self.__cpu = ProcStat.sample()
|
||||
return self.__cpu
|
||||
@property
|
||||
def _mem(self):
|
||||
if self.__mem is None:
|
||||
self.__mem = MemInfo()
|
||||
return self.__mem
|
||||
|
||||
# user-facing format shorthands
|
||||
@property
|
||||
def bat(self) -> str:
|
||||
return f"{self.bat_icon}{self.bat_time}"
|
||||
@property
|
||||
def cpu(self) -> str:
|
||||
return f"{self.cpu_icon}{self.cpu_pct}"
|
||||
@property
|
||||
def mem(self) -> str:
|
||||
return f"{self.mem_icon}{self.mem_pct}"
|
||||
|
||||
# manual/low-level fields
|
||||
@property
|
||||
def mem_icon(self) -> str:
|
||||
if self._mem is None: return ""
|
||||
@@ -307,6 +432,34 @@ class AllInfo:
|
||||
else:
|
||||
return self._fmt.render_percent(self._bat.percent_charged)
|
||||
|
||||
@property
|
||||
def cpu_icon(self) -> str:
|
||||
if self._cpu is None: return ""
|
||||
return self._fmt.render_cpu_icon()
|
||||
|
||||
@property
|
||||
def cpu_pct(self) -> str:
|
||||
if self._cpu is None:
|
||||
return ""
|
||||
|
||||
idle = self._cpu.cpu_idle + self._cpu.cpu_iowait
|
||||
total = self._cpu.cpu_total
|
||||
|
||||
cpu_use_pct = int((total - idle) / total * 100)
|
||||
return self._fmt.render_percent(cpu_use_pct)
|
||||
|
||||
|
||||
class LazyFormatter:
|
||||
def __init__(self, obj: object, attr: str):
|
||||
self.obj = obj
|
||||
self.attr = attr
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return repr(getattr(self.obj, self.attr))
|
||||
|
||||
def __str__(self) -> str:
|
||||
return str(getattr(self.obj, self.attr))
|
||||
|
||||
def main() -> None:
|
||||
logging.basicConfig()
|
||||
logging.getLogger().setLevel(logging.INFO)
|
||||
@@ -317,8 +470,7 @@ def main() -> None:
|
||||
parser.add_argument("--hour-suffix", default=SUFFIX_HR)
|
||||
parser.add_argument("--minute-suffix", default=SUFFIX_MIN)
|
||||
parser.add_argument("--percent-suffix", default=SUFFIX_PERCENT)
|
||||
parser.add_argument("--template", default="{_.bat_icon}{_.bat_time}")
|
||||
# parser.add_argument("--template", default="{_.mem_icon}{_.mem_pct}")
|
||||
parser.add_argument("formatstr", nargs="+")
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.debug:
|
||||
@@ -330,12 +482,19 @@ def main() -> None:
|
||||
f.suffix_hr = args.hour_suffix
|
||||
f.suffix_min = args.minute_suffix
|
||||
|
||||
info = AllInfo(
|
||||
f,
|
||||
MemInfo(),
|
||||
try_all_batteries(),
|
||||
)
|
||||
print(args.template.format(_=info))
|
||||
info = AllInfo(f)
|
||||
formatstr = " ".join(args.formatstr)
|
||||
print(formatstr.format(
|
||||
bat=LazyFormatter(info, "bat"),
|
||||
bat_icon=LazyFormatter(info, "bat_icon"),
|
||||
bat_time=LazyFormatter(info, "bat_time"),
|
||||
cpu=LazyFormatter(info, "cpu"),
|
||||
cpu_icon=LazyFormatter(info, "cpu_icon"),
|
||||
cpu_pct=LazyFormatter(info, "cpu_pct"),
|
||||
mem=LazyFormatter(info, "mem"),
|
||||
mem_icon=LazyFormatter(info, "mem_icon"),
|
||||
mem_pct=LazyFormatter(info, "mem_pct"),
|
||||
))
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@@ -6,8 +6,8 @@ let
|
||||
src = fetchFromGitHub {
|
||||
owner = "Mic92";
|
||||
repo = "sops-nix";
|
||||
rev = "c279dec105dd53df13a5e57525da97905cc0f0d6";
|
||||
hash = "sha256-psA+1Q5fPaK6yI3vzlLINNtb6EeXj111zQWnZYyJS9c=";
|
||||
rev = "797ce4c1f45a85df6dd3d9abdc53f2691bea9251";
|
||||
hash = "sha256-Pm9I/BMQHbsucdWf6y9G3xBZh3TMlThGo4KBbeoeczg=";
|
||||
};
|
||||
flake = import "${src}/flake.nix";
|
||||
evaluated = flake.outputs {
|
||||
@@ -21,7 +21,7 @@ in src.overrideAttrs (base: {
|
||||
# attributes required by update scripts
|
||||
pname = "sops-nix";
|
||||
# nix-update-script insists on this weird `assets-` version format
|
||||
version = "assets-unstable-2024-06-11";
|
||||
version = "assets-unstable-2024-06-16";
|
||||
src = src;
|
||||
|
||||
passthru = base.passthru
|
||||
|
@@ -107,6 +107,7 @@ let
|
||||
xdotool
|
||||
] ++ lib.optionals preferXdgOpen [ xdg-utils ];
|
||||
in
|
||||
lib.warn "sxmo-utils from nur.colinsane is no longer maintained and will be removed in the future. consider pointing to a different upstream or copying the package into your own config."
|
||||
stdenv.mkDerivation rec {
|
||||
pname = "sxmo-utils";
|
||||
version = "unstable-2024-02-05";
|
||||
|
@@ -8,14 +8,14 @@
|
||||
, wrapGAppsHook4
|
||||
}:
|
||||
stdenv.mkDerivation {
|
||||
pname = "sysvol";
|
||||
version = "0-unstable-2024-06-13";
|
||||
pname = "syshud";
|
||||
version = "0-unstable-2024-06-20";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "System64fumo";
|
||||
repo = "sysvol";
|
||||
rev = "af882d40df7c6e1a0ec415d934f643933f455b5a";
|
||||
hash = "sha256-3gB1u7fEi7EB+FWZKS8ddJ53RC5Chyw3fTBX8Z0Itis=";
|
||||
repo = "syshud";
|
||||
rev = "2b97f3441970efe67c788a8313eb58182aa7965b";
|
||||
hash = "sha256-XPAKjBLaTGEyDgiZT8tYinYzMivOocOEeauzR4leOjI=";
|
||||
};
|
||||
postPatch = ''
|
||||
substituteInPlace Makefile \
|
||||
@@ -40,9 +40,9 @@ stdenv.mkDerivation {
|
||||
};
|
||||
|
||||
meta = {
|
||||
description = "A basic GTK4 volume indicator";
|
||||
homepage = "https://github.com/System64fumo/sysvol";
|
||||
mainProgram = "sysvol";
|
||||
description = "Simple heads up display written in gtkmm 4";
|
||||
homepage = "https://github.com/System64fumo/syshud";
|
||||
mainProgram = "syshud";
|
||||
platforms = lib.platforms.linux;
|
||||
maintainers = with lib.maintainers; [ colinsane ];
|
||||
};
|
@@ -5,12 +5,12 @@
|
||||
}:
|
||||
stdenv.mkDerivation {
|
||||
pname = "uassets";
|
||||
version = "0-unstable-2024-06-15";
|
||||
version = "0-unstable-2024-06-21";
|
||||
src = fetchFromGitHub {
|
||||
owner = "uBlockOrigin";
|
||||
repo = "uAssets";
|
||||
rev = "bbb9bd592fe54dc2cbc952a68dd715bb481ab83d";
|
||||
hash = "sha256-r7ZCfHxCNVETu1X7O8vb4xkxTAmYVWFDTHQOZeQ8C2I=";
|
||||
rev = "05dfb7b5504b20e5432f7092111ad51568b3d9f4";
|
||||
hash = "sha256-FrSMmZxR+XWUUOb8X1kImEM4Lhw8Ikg8k1vtqXOJD+8=";
|
||||
};
|
||||
|
||||
dontBuild = true;
|
||||
|
@@ -1,9 +0,0 @@
|
||||
{ linkFarm
|
||||
, geoclue2
|
||||
}:
|
||||
linkFarm "where-am-i" [{
|
||||
# bring the `where-am-i` tool into a `bin/` directory so it can be invokable via PATH
|
||||
name = "bin/where-am-i";
|
||||
path = "${geoclue2}/libexec/geoclue-2.0/demos/where-am-i";
|
||||
}]
|
||||
|
@@ -71,6 +71,7 @@ let
|
||||
nixpkgs-staging = nixpkgs.override { variant = "staging"; };
|
||||
nixpkgs-next = nixpkgs.override { variant = "staging-next"; };
|
||||
nixpkgs-wayland = callPackage ./additional/nixpkgs-wayland { };
|
||||
opencellid = callPackage ./additional/opencellid { };
|
||||
peerswap = callPackage ./additional/peerswap { };
|
||||
phog = callPackage ./additional/phog { };
|
||||
pipeline = callPackage ./additional/pipeline { };
|
||||
@@ -84,7 +85,7 @@ let
|
||||
sane-open = callPackage ./additional/sane-open { };
|
||||
sane-screenshot = callPackage ./additional/sane-screenshot { };
|
||||
sane-scripts = lib.recurseIntoAttrs (callPackage ./additional/sane-scripts { });
|
||||
sane-sysinfo = callPackage ./additional/sane-sysinfo { };
|
||||
sane-sysload = callPackage ./additional/sane-sysload { };
|
||||
sane-weather = callPackage ./additional/sane-weather { };
|
||||
sanebox = callPackage ./additional/sanebox { };
|
||||
schlock = callPackage ./additional/schlock { };
|
||||
@@ -97,7 +98,7 @@ let
|
||||
sxmo_swaylock = callPackage ./additional/sxmo_swaylock { };
|
||||
sxmo-suspend = callPackage ./additional/sxmo-suspend { };
|
||||
sxmo-utils = callPackage ./additional/sxmo-utils { };
|
||||
sysvol = callPackage ./additional/sysvol { };
|
||||
syshud = callPackage ./additional/syshud { };
|
||||
tow-boot-pinephone = callPackage ./additional/tow-boot-pinephone { };
|
||||
tree-sitter-nix-shell = callPackage ./additional/tree-sitter-nix-shell { };
|
||||
trivial-builders = lib.recurseIntoAttrs (callPackage ./additional/trivial-builders { });
|
||||
@@ -113,7 +114,6 @@ let
|
||||
runCommandLocalOverridable
|
||||
;
|
||||
unftp = callPackage ./additional/unftp { };
|
||||
where-am-i = callPackage ./additional/where-am-i { };
|
||||
zecwallet-light-cli = callPackage ./additional/zecwallet-light-cli { };
|
||||
|
||||
# packages i haven't used for a while, may or may not still work
|
||||
@@ -162,6 +162,20 @@ let
|
||||
|
||||
# modemmanager = callPackage ./patched/modemmanager { inherit (unpatched) modemmanager; };
|
||||
|
||||
playerctl = unpatched.playerctl.overrideAttrs (upstream: {
|
||||
patches = (upstream.patches or []) ++ [
|
||||
(fetchpatch {
|
||||
# playerctl, when used as a library, doesn't expect its user to `unref` it inside a glib signal.
|
||||
# nwg-panel does this though, and then segfaults.
|
||||
# playerctl project looks dead as of 2024/06/19, no hope for upstreaming this.
|
||||
# TODO: consider removing this if nwg-panel code is changed to not trigger this.
|
||||
# - <https://github.com/nwg-piotr/nwg-panel/issues/233>
|
||||
name = "dbus_name_owner_changed_callback: acquire a ref on the manager before using it";
|
||||
url = "https://git.uninsane.org/colin/playerctl/commit/bbcbbe4e03da93523b431ffee5b64e10b17b4f9f.patch";
|
||||
hash = "sha256-l/w+ozga8blAB2wtEd1SPBE6wpHNXWk7NrOL7x10oUI=";
|
||||
})
|
||||
];
|
||||
});
|
||||
|
||||
### PYTHON PACKAGES
|
||||
pythonPackagesExtensions = (unpatched.pythonPackagesExtensions or []) ++ [
|
||||
|
@@ -2,6 +2,8 @@
|
||||
{
|
||||
depthcharge-tools = callPackage ./depthcharge-tools { };
|
||||
feedsearch-crawler = callPackage ./feedsearch-crawler { };
|
||||
fastcluster = callPackage ./fastcluster { };
|
||||
ols = callPackage ./ols { };
|
||||
pa-dlna = callPackage ./pa-dlna { };
|
||||
pyln-bolt7 = callPackage ./pyln-bolt7 { };
|
||||
pyln-client = callPackage ./pyln-client { };
|
||||
|
38
pkgs/python-packages/fastcluster/default.nix
Normal file
38
pkgs/python-packages/fastcluster/default.nix
Normal file
@@ -0,0 +1,38 @@
|
||||
{ lib
|
||||
, buildPythonPackage
|
||||
, fetchFromGitHub
|
||||
, oldest-supported-numpy
|
||||
, numpy
|
||||
, setuptools
|
||||
}: buildPythonPackage rec {
|
||||
pname = "fastcluster";
|
||||
version = "1.2.6";
|
||||
format = "pyproject";
|
||||
# format = "setuptools";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "fastcluster";
|
||||
repo = "fastcluster";
|
||||
rev = "v${version}";
|
||||
hash = "sha256-8FDipkAcOAI5zAC7JaJExe6HO1xHg+eXAL7IUIVrA3k=";
|
||||
};
|
||||
|
||||
nativeBuildInputs = [
|
||||
oldest-supported-numpy
|
||||
setuptools
|
||||
];
|
||||
|
||||
# propagatedBuildInputs = [
|
||||
# numpy
|
||||
# ];
|
||||
|
||||
pythonImportsCheck = [
|
||||
"fastcluster"
|
||||
];
|
||||
|
||||
meta = with lib; {
|
||||
homepage = "https://danifold.net/fastcluster.html";
|
||||
description = "fast hierarchical clustering routines for R and Python";
|
||||
maintainers = with maintainers; [ colinsane ];
|
||||
};
|
||||
}
|
60
pkgs/python-packages/ols/default.nix
Normal file
60
pkgs/python-packages/ols/default.nix
Normal file
@@ -0,0 +1,60 @@
|
||||
{ lib
|
||||
, buildPythonPackage
|
||||
, fetchFromGitea
|
||||
, aiohttp
|
||||
, fastcluster
|
||||
, fastjsonschema
|
||||
, mercantile
|
||||
, numpy
|
||||
, scipy
|
||||
, setuptools
|
||||
# , wheel
|
||||
}: buildPythonPackage {
|
||||
pname = "ols";
|
||||
version = "0.1.0-unstable-2024-06-21";
|
||||
format = "pyproject";
|
||||
# format = "setuptools";
|
||||
|
||||
src = fetchFromGitea {
|
||||
# my dev branch has a few changes:
|
||||
# - fix `cellid-ols-import` to make --mcc, --mnc actually be optional
|
||||
# - synthesize cell locations when no exact match is found
|
||||
domain = "git.uninsane.org";
|
||||
owner = "colin";
|
||||
repo = "ols";
|
||||
rev = "2caacd27a6253f711d0820ae51e6fe178bd80343";
|
||||
hash = "sha256-vzvEraBi71xz1rjQWFRFKkAaVO9ASNQ2dTvT6y+xihI=";
|
||||
};
|
||||
# src = fetchFromGitea {
|
||||
# domain = "codeberg.org";
|
||||
# owner = "tpikonen";
|
||||
# repo = "ols";
|
||||
# rev = "069560accc6558f16d6d9abea63bd7563ea3f0e9";
|
||||
# hash = "sha256-/931fc37QzITOA61D2CeXr/JmvDg0t8fLSt2y+2kSyQ=";
|
||||
# };
|
||||
# src = /home/colin/ref/repos/tpikonen/ols;
|
||||
|
||||
propagatedBuildInputs = [
|
||||
aiohttp
|
||||
fastcluster
|
||||
fastjsonschema
|
||||
mercantile
|
||||
numpy
|
||||
scipy
|
||||
];
|
||||
|
||||
nativeBuildInputs = [
|
||||
setuptools
|
||||
# wheel
|
||||
];
|
||||
|
||||
pythonImportsCheck = [
|
||||
"ols"
|
||||
];
|
||||
|
||||
meta = with lib; {
|
||||
homepage = "https://codeberg.org/tpikonen/ols";
|
||||
description = "HTTP location service with Mozilla Location Service (MLS) compatible API";
|
||||
maintainers = with maintainers; [ colinsane ];
|
||||
};
|
||||
}
|
@@ -1,7 +1,8 @@
|
||||
#!/bin/sh
|
||||
cd ../integrations/nur
|
||||
NIX_FILES_TOP=/home/colin/nixos
|
||||
cd $NIX_FILES_TOP/integrations/nur
|
||||
# TODO: should include `-I nixpkgs=</path/to/an/unpatched/nixpkgs>`
|
||||
NIX_PATH= NIXPKGS_ALLOW_UNSUPPORTED_SYSTEM=1 nix-env -f . -qa \* --meta --xml \
|
||||
NIX_PATH= NIXPKGS_ALLOW_UNSUPPORTED_SYSTEM=1 nix-env -f . -qa linux\* --meta --xml \
|
||||
--allowed-uris https://static.rust-lang.org \
|
||||
--option restrict-eval true \
|
||||
--option allow-import-from-derivation true \
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -i bash -p curl -p dig -p iputils -p lftp -p openssh
|
||||
#!nix-shell -i bash -p curl -p dig -p iputils -p openssh
|
||||
|
||||
echo "this script will check that uninsane.org is baseline operational"
|
||||
echo "it doesn't check all services, just the most critical ones"
|
||||
@@ -8,12 +8,40 @@ echo ""
|
||||
OVPNS_IPV4=185.157.162.178
|
||||
DOOF_IPV4=205.201.63.12
|
||||
|
||||
usage() {
|
||||
echo "usage: check-uninsane [flags ...]"
|
||||
echo "flags:"
|
||||
echo "- --verbose: show commands before running them"
|
||||
exit 1
|
||||
}
|
||||
|
||||
verbose=
|
||||
parseArgs() {
|
||||
while [ "$#" -ne 0 ]; do
|
||||
local arg=$1
|
||||
shift
|
||||
case $arg in
|
||||
(--verbose)
|
||||
verbose=1
|
||||
;;
|
||||
(*)
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
last_error=0
|
||||
check() {
|
||||
local label=$1
|
||||
shift
|
||||
printf "checking %s\n" "$label"
|
||||
"$@" > /dev/null
|
||||
if [ -n "$verbose" ]; then
|
||||
printf "checking %s (%s) \n" "$label" "$*"
|
||||
"$@"
|
||||
else
|
||||
printf "checking %s\n" "$label"
|
||||
"$@" > /dev/null
|
||||
fi
|
||||
local rc=$?
|
||||
if [ $rc -ne 0 ]; then
|
||||
last_error=$rc
|
||||
@@ -23,6 +51,16 @@ check() {
|
||||
return $rc
|
||||
}
|
||||
|
||||
runOnHost() {
|
||||
local host="$1"
|
||||
shift
|
||||
if [ "$host" = "$(hostname)" ]; then
|
||||
"$@"
|
||||
else
|
||||
ssh "$host-hn" "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
check "self-test" false 2> /dev/null
|
||||
if [ $last_error -eq 0 ]; then
|
||||
echo "SELF-TEST FAILED" >&2
|
||||
@@ -31,10 +69,12 @@ if [ $last_error -eq 0 ]; then
|
||||
fi
|
||||
last_error=0
|
||||
|
||||
parseArgs "$@"
|
||||
|
||||
check "uninsane.org. DNS" nslookup uninsane.org.
|
||||
check "uninsane.org. DNS via external resolver" nslookup uninsane.org. 1.1.1.1
|
||||
check "uninsane.org. bootstrap DNS" nslookup uninsane.org. ovpns.uninsane.org
|
||||
check "[1.1.1.1] uninsane.org. DNS" nslookup uninsane.org. 1.1.1.1
|
||||
check "[OVPNS] uninsane.org. DNS" nslookup uninsane.org. "$OVPNS_IPV4"
|
||||
check "[DOOF] uninsane.org. DNS" nslookup uninsane.org. "$DOOF_IPV4"
|
||||
|
||||
check "https://uninsane.org online" curl --silent --fail-with-body https://uninsane.org
|
||||
check "https://matrix.uninsane.org online" curl --silent --fail-with-body https://matrix.uninsane.org
|
||||
@@ -53,13 +93,14 @@ check "uninsane.org DMARC record" nslookup -querytype=TXT _dmarc.uninsane.org.
|
||||
|
||||
check "servo-hn wireguard network" ping -c 1 -W 3 servo-hn
|
||||
|
||||
check "git.uninsane.org" git ls-remote origin --quiet
|
||||
check "git.uninsane.org" git ls-remote https://git.uninsane.org/colin/nix-files.git --quiet
|
||||
|
||||
check "ftp://uninsane.org" lftpget ftp://uninsane.org/README.md && rm README.md
|
||||
check "ftps://ftp.uninsane.org" curl --silent ftps://ftp.uninsane.org/pub/test
|
||||
check "[DOOF] ftps://ftp.uninsane.org" curl "--connect-to" "uninsane.org:80:$DOOF_IPV4:80" --silent ftps://ftp.uninsane.org/pub/test
|
||||
|
||||
echo ""
|
||||
echo "systemctl --failed:"
|
||||
ssh uninsane.org systemctl -q --failed
|
||||
runOnHost servo systemctl -q --failed
|
||||
|
||||
echo ""
|
||||
if [ $last_error -eq 0 ]; then
|
||||
|
@@ -9,8 +9,10 @@ usage() {
|
||||
echo "usage: deploy [options] [host] [host2 ...]"
|
||||
echo "options:"
|
||||
echo "- --action copy|switch|test (default: 'switch')"
|
||||
echo "- --variant light|min|''|all (default: '')"
|
||||
echo "- --dry-run: show what would be done without actually doing it"
|
||||
echo "- --pre: alias for --action copy --variant all all"
|
||||
echo "- --reboot: reboot the target machine after deploying (whether deployment was 'successful' or not)"
|
||||
echo "- --variant light|min|''|all (default: '')"
|
||||
echo ""
|
||||
echo "common idioms:"
|
||||
echo "- deploy all: deploy all hosts, sequentially"
|
||||
@@ -30,6 +32,8 @@ defaultHost="$SELF"
|
||||
variants=()
|
||||
defaultVariant=
|
||||
nixArgs=()
|
||||
doReboot=
|
||||
dryRun=
|
||||
addHost() {
|
||||
if [ "$1" = all ]; then
|
||||
# order matters:
|
||||
@@ -57,9 +61,20 @@ parseArgs() {
|
||||
action=$1
|
||||
shift
|
||||
;;
|
||||
(--dry-run)
|
||||
dryRun=1
|
||||
;;
|
||||
(--help)
|
||||
usage
|
||||
;;
|
||||
(--pre)
|
||||
action=copy
|
||||
defaultVariant=all
|
||||
defaultHost=all
|
||||
;;
|
||||
(--reboot)
|
||||
doReboot=1
|
||||
;;
|
||||
(--variant)
|
||||
addVariant "$1"
|
||||
shift
|
||||
@@ -67,11 +82,6 @@ parseArgs() {
|
||||
(all|crappy|desko|lappy|moby|servo)
|
||||
addHost "$arg"
|
||||
;;
|
||||
(--pre)
|
||||
action=copy
|
||||
defaultVariant=all
|
||||
defaultHost=all
|
||||
;;
|
||||
(*)
|
||||
nixArgs+=("$arg")
|
||||
;;
|
||||
@@ -86,14 +96,24 @@ parseArgs() {
|
||||
fi
|
||||
}
|
||||
|
||||
destructive() {
|
||||
if [ -z "$dryRun" ]; then
|
||||
"$@"
|
||||
else
|
||||
echo "dry-run: $@"
|
||||
fi
|
||||
}
|
||||
|
||||
runOnTarget() {
|
||||
local host="$1"
|
||||
shift
|
||||
# run the command ($@) on the machine we're deploying to.
|
||||
# if that's a remote machine, then do it via ssh, else local shell.
|
||||
if [ -n "$host" ] && [ "$host" != "$SELF" ]; then
|
||||
info "running on remote:" "$@"
|
||||
info "running on remote ($host):" "$@"
|
||||
ssh "$host" "$@"
|
||||
else
|
||||
info "running locally:" "$@"
|
||||
info "running locally ($SELF):" "$@"
|
||||
"$@"
|
||||
fi
|
||||
}
|
||||
@@ -104,7 +124,7 @@ deployOneHost() {
|
||||
local variant="$2"
|
||||
|
||||
info "building $host$variant ..."
|
||||
nix-build -A "hosts.$host$variant.toplevel" --out-link "./build/result-$host$variant" "${nixArgs[@]}" || return 1
|
||||
destructive nix-build -A "hosts.$host$variant.toplevel" --out-link "./build/result-$host$variant" "${nixArgs[@]}" || return 1
|
||||
storePath="$(readlink ./build/result-$host$variant)"
|
||||
info "build $host$variant -> $storePath"
|
||||
|
||||
@@ -120,20 +140,24 @@ deployOneHost() {
|
||||
if [ -n "$host" ] && [ "$host" != "$SELF" ]; then
|
||||
if [ -e /run/secrets/nix_signing_key ]; then
|
||||
info "signing store paths ..."
|
||||
sudo nix store sign -r -k /run/secrets/nix_signing_key "$storePath"
|
||||
destructive sudo nix store sign -r -k /run/secrets/nix_signing_key "$storePath"
|
||||
else
|
||||
info "not signing store paths: /run/secrets/nix_signing_key does not exist"
|
||||
fi
|
||||
# add more `-v` for more verbosity (up to 5).
|
||||
# builders-use-substitutes false: optimizes so that the remote machine doesn't try to get paths from its substituters.
|
||||
# we already have all paths here, and the remote substitution is slow to check and SERIOUSLY flaky on moby in particular.
|
||||
nix copy -vv --option builders-use-substitutes false --to "ssh-ng://$host" "$storePath" || return 1
|
||||
destructive nix copy -vv --option builders-use-substitutes false --to "ssh-ng://$host" "$storePath" || return 1
|
||||
fi
|
||||
|
||||
if [ -n "$action" ] && [ "$action" != "copy" ]; then
|
||||
info "activating profile... "
|
||||
runOnTarget sudo nix-env -p /nix/var/nix/profiles/system --set "$storePath" || return 1
|
||||
runOnTarget sudo "$storePath/bin/switch-to-configuration" "$action" || return 1
|
||||
destructive runOnTarget "$host" sudo nix-env -p /nix/var/nix/profiles/system --set "$storePath" || return 1
|
||||
destructive runOnTarget "$host" sudo "$storePath/bin/switch-to-configuration" "$action" || return 1
|
||||
if [ -n "$doReboot" ]; then
|
||||
info "rebooting $host"
|
||||
destructive runOnTarget "$host" sane-reboot
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -141,8 +165,8 @@ deployOneHost() {
|
||||
parseArgs "$@"
|
||||
|
||||
failedDeploys=()
|
||||
for h in "${hosts[@]}"; do
|
||||
for v in "${variants[@]}"; do
|
||||
for v in "${variants[@]}"; do
|
||||
for h in "${hosts[@]}"; do
|
||||
deployOneHost "$h" "$v" || \
|
||||
failedDeploys+=("$h$v")
|
||||
done
|
||||
|
@@ -1,6 +1,8 @@
|
||||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -i bash -p nix-update
|
||||
|
||||
NIX_FILES_TOP=/home/colin/nixos
|
||||
|
||||
usage() {
|
||||
echo "update: update rev/hash for one or more packages"
|
||||
echo "usage: update [options] [attr-path]"
|
||||
@@ -44,34 +46,51 @@ getPkgs() {
|
||||
attrPrefix=sane
|
||||
fi
|
||||
|
||||
local attrs="$(nix-env -f . --query --available --attr-path --no-name -A $attrPrefix)"
|
||||
# nix-env doesn't seem to build anything when evaluating queries,
|
||||
# but since i use Import From Derivation along paths which i also want to query,
|
||||
# then i need to ensure those derivations are available for import.
|
||||
debug "creating requisite .drv store paths"
|
||||
nix-instantiate -A nixpkgs "$NIX_FILES_TOP"
|
||||
debug "querying attributes which match '$attrPrefix'"
|
||||
local attrs=$(nix-env -f "$NIX_FILES_TOP" --query --available --attr-path --no-name -A "$attrPrefix" --show-trace)
|
||||
debug "got: $attrs"
|
||||
attrsArr+=($attrs)
|
||||
}
|
||||
|
||||
updateOnePkg() {
|
||||
local attrPath="$1"
|
||||
|
||||
if [[ "$attrPath" =~ ^"$ignore" ]]; then
|
||||
if [ -n "$ignore" ] && [[ "$attrPath" =~ ^"$ignore" ]]; then
|
||||
warn "ignoring $attrPath"
|
||||
return
|
||||
fi
|
||||
|
||||
local updateScript="$(nix eval --raw -f . $attrPath.passthru.updateScript --apply 'builtins.concatStringsSep "'" "'"')"
|
||||
local updateScript=$(nix eval --raw -f "$NIX_FILES_TOP" $attrPath.passthru.updateScript --apply 'builtins.concatStringsSep "'" "'"')
|
||||
if [ -z "$updateScript" ]; then
|
||||
warn "don't know how to update '$attrPath'"
|
||||
return
|
||||
fi
|
||||
|
||||
# make sure everything needed to invoke the script actually exists on disk
|
||||
nix-build -A "$attrPath.passthru.updateScript" || true
|
||||
# make sure everything needed to invoke the update script exists in-store
|
||||
local context=$(nix eval --raw -f "$NIX_FILES_TOP" $attrPath.passthru.updateScript --apply 's: builtins.concatStringsSep " " (builtins.foldl'"'"' (acc: next: acc ++ next) [] (builtins.map builtins.attrNames (builtins.map builtins.getContext s)))')
|
||||
for c in $context; do
|
||||
debug "realizing updateScript requisite: $context"
|
||||
nix-store --realize "$c" || true
|
||||
done
|
||||
|
||||
local UPDATE_NIX_NAME="$(nix eval --raw -f . $attrPath.name)"
|
||||
local UPDATE_NIX_PNAME="$(nix eval --raw -f . $attrPath.pname)"
|
||||
local UPDATE_NIX_OLD_VERSION="$(nix eval --raw -f . $attrPath.version)"
|
||||
local UPDATE_NIX_NAME=$(nix eval --raw -f "$NIX_FILES_TOP" $attrPath.name)
|
||||
local UPDATE_NIX_PNAME=$(nix eval --raw -f "$NIX_FILES_TOP" $attrPath.pname)
|
||||
local UPDATE_NIX_OLD_VERSION=$(nix eval --raw -f "$NIX_FILES_TOP" $attrPath.version)
|
||||
info "updating: '$attrPath'"
|
||||
debug "$updateScript"
|
||||
# we lose spaces inside the exec args... could `nix eval` without `--raw` to fix that.
|
||||
UPDATE_NIX_NAME="$UPDATE_NIX_NAME" UPDATE_NIX_PNAME="$UPDATE_NIX_PNAME" UPDATE_NIX_OLD_VERSION="$UPDATE_NIX_OLD_VERSION" UPDATE_NIX_ATTR_PATH="$attrPath" eval $updateScript
|
||||
(
|
||||
# update script assumes $PWD is an entry point to a writable copy of my nix config,
|
||||
# so provide that:
|
||||
pushd "$NIX_FILES_TOP/integrations/nix-update"
|
||||
# we lose spaces inside the exec args... could `nix eval` without `--raw` to fix that.
|
||||
UPDATE_NIX_NAME="$UPDATE_NIX_NAME" UPDATE_NIX_PNAME="$UPDATE_NIX_PNAME" UPDATE_NIX_OLD_VERSION="$UPDATE_NIX_OLD_VERSION" UPDATE_NIX_ATTR_PATH="$attrPath" eval $updateScript
|
||||
popd
|
||||
)
|
||||
}
|
||||
|
||||
dryRun=
|
||||
|
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"data": "ENC[AES256_GCM,data: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,iv:9WvW3DScrLPI3bEb7neJgWI/MDTvBfajWDtDj3rGxJs=,tag:VTDd0X5Oep/dSlZbjIO6tw==,type:str]",
|
||||
"data": "ENC[AES256_GCM,data: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,iv:jlCa29fKe/HWq3z17ymOrgYt50g3EjzOYYln6ywLWLg=,tag:MFtkrsTjtYCqZ+AYloffGQ==,type:str]",
|
||||
"sops": {
|
||||
"kms": null,
|
||||
"gcp_kms": null,
|
||||
@@ -43,8 +43,8 @@
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAwcXlNMlFUaWhXbmlPc0Ir\nT2hRd3BMQUZ1TkVkWGlrdjJ5ZnhPdWhPbTFBCmdzazV5bzV0aTNNaTFpaDlBOWU5\naUdBTFlEeWM5T1Q3UGhrZWdGZkVPUzQKLS0tIEloSFVJd2JCNmY0VkpqTGppRE1p\nQ2Mvekx0RWN5dlhxWmwwaDVnUUVDdFEKJgyAed3yBaIBwfxypG7RKV+u80SiQV89\ntU4YMw0j7GvnkVhPenB8q0w3yrslCh35GDvKkaMpfp8jVFIpcrRXtA==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||
}
|
||||
],
|
||||
"lastmodified": "2023-10-28T10:34:31Z",
|
||||
"mac": "ENC[AES256_GCM,data:GS492dizmvoW6uCO4Wz+YzwFbtM6LfUdEgx7DzSbHG3hM/q3k5LW8E4HzxkBkDUylL5GS3FUWCADcoKe+JWqX3TUqQDqqrYScAVcE5e9TM2mZ12U6xz1SU8Tc5DkqQuUgrv/pvaJBI1UlEEdFkSOSIBzHZ5C7xW0WsNFauC9HFI=,iv:rnDBUWzieefIpES4WjWWEiAY3LtKkfazAgHaSoJ9VEw=,tag:n4b6kctXHHKiQfQAeQeFTw==,type:str]",
|
||||
"lastmodified": "2024-06-23T17:59:53Z",
|
||||
"mac": "ENC[AES256_GCM,data:ZKGwqisn27YnSjroCxrCxIoR5vkYgnfzVoLNbxfnti+RFUX67eBfcj0jOc8KqfAWyNOCMlWlfOZ1AonIOqsBqhPrX1LEyOdhrCp+M7zfhnIheOJFfqVyUzN0O7N0PIj696tM8HgYg2OX+YLCvZvFf9DSrK92RsRCkWSfH34OKd8=,iv:AByoesqgTOoet2BR01d6G1CBx0o/PDGj2kbxNU5St20=,tag:Um2vz1mdD5gu4CifY4QuTA==,type:str]",
|
||||
"pgp": null,
|
||||
"unencrypted_suffix": "_unencrypted",
|
||||
"version": "3.8.1"
|
||||
|
52
secrets/common/ols.toml.bin
Normal file
52
secrets/common/ols.toml.bin
Normal file
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"data": "ENC[AES256_GCM,data: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,iv:jbrfq9CYDgVQUK3od8eFjm6+KOTcypeTF3itq72XBBE=,tag:1jbIG1GaI0pSxIsErUXoBg==,type:str]",
|
||||
"sops": {
|
||||
"kms": null,
|
||||
"gcp_kms": null,
|
||||
"azure_kv": null,
|
||||
"hc_vault": null,
|
||||
"age": [
|
||||
{
|
||||
"recipient": "age1tnl4jfgacwkargzeqnhzernw29xx8mkv73xh6ufdyde6q7859slsnzf24x",
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBwQU9melI3VDB1aEtOYW5E\nbDRDL1BWMExsbjlxckFYZWtWMTlPZ29yR25BCjV5a0VyNHdQbXpMVGljZENxM2hl\nRlBRYTZoWnE4VVNQb05MTm1pcGsrVk0KLS0tIFFhOTE2S1luLzMxWnlmbGlzbEh5\nS1dFZU1JRG8vdDFjL3g5eEJ3ckZKNEkK1S1FMhvKCNbWlmDdOIgnn3+uAcK9bs9G\nvlfoV6xzAdAJDlckPLDipfS0x6HKUkN9PdA2K+SYJJ9673xegZ/xeQ==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||
},
|
||||
{
|
||||
"recipient": "age1j2pqnl8j0krdzk6npe93s4nnqrzwx978qrc0u570gzlamqpnje9sc8le2g",
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBHWkZva1JreGpGWTBzcVBz\nSXlxakpjVk5ycndQRnUzYm9ZMXRXcFZTK3c0CmRBUFowNDlTMEgwVkpkOEQvNms4\nY2NRZ3g2SnJhdEJjbDlKZzlmVjFFL1EKLS0tIEFlL3VoUGJUaGY2SzFPT09QSXNS\ndElTQ2ZnNzJIRG51NmNjWldZYVFLV0EKOMJvXC9HjtNDuJELLfbByES0yVpliAnq\n7sWQRkY3K/J/F6cW5++LepZWMmMY7YmnKzIphreBeZncYUYx4JuzUQ==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||
},
|
||||
{
|
||||
"recipient": "age1z8fauff34cdecr6sjkre260luzxcca05kpcwvhx988d306tpcejsp63znu",
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBTMmVSU1ByanlMYUR4TlFN\nYml4SjU4b1ZRR3VDazFlN3p2ZndacFZXUmo0CkhhTWtzVyszaUR4dG9nWmhoSHFn\nSWNtaGN2SzhtVWNkSkdUUEdqWmNyWTQKLS0tIHJnblV3Z082dVNLRUtNN216eTJL\nRXlKRVd0UGE3SE1rdUQ1NVlCSUFjL1UKf6Y6lvki5rFjqrPCLCL8SulHh3yg0Cns\nDdMsZgqLql1O3Cua4CHjSi+08hsz0RT9qqzcNr798Bqj5JnvFSTUPw==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||
},
|
||||
{
|
||||
"recipient": "age1zsrsvd7j6l62fjxpfd2qnhqlk8wk4p8r0dtxpe4sdgnh2474095qdu7xj9",
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBpZGs5MHZqOFVoSzQxdEFC\nem1yVzZCditGekRMYzFCcWsvVk0vYlBubEJVCmV2ZHZqR3BMTW9Pa1RGWXVFdkV4\nbnNlKy9PUSswTVlETmxjMDAxakp2cmsKLS0tIFJDZlZzYmwwaFlua2FGeTdTUGtZ\nUXNoVFpwT21uR0NpcTFzZEgzby9YR0UKmZFKfm6ypb9SZBW0vTtw6SDL6TgZnsp3\ns41G4S4PS/8XyAHKrLlgGiJK/Fv3bMULG54D2TKQSbuYRhKXT9nWoA==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||
},
|
||||
{
|
||||
"recipient": "age1hl50ufuxnqy0jnk8fqeu4tclh4vte2xn2d59pxff0gun20vsmv5sp78chj",
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB2Y3Frc2RleThrK1NmRTcx\nUkxvV29GNXllU0tXOWQ2YVkwSTloUjFCaUZFCk5iaVpJLy8vVUh5cGJBODVNWXNG\nRmtZYTZKK044S0VpSGdhSVBZZlZGY0kKLS0tIDg5c0IyTjNlU2FRYy9ueVYxbXIz\nZjZ0MGoweEtwQ2lUWDlqcEZvdThzYjQKMi0m7wyRoCoIbS/HBl6xaVEeK4TvYzkW\ny/rDK0IZuBAr9I1/avdDGM8LWo2EBSmqEqW6jooMmdrkkjwJE6lwVA==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||
},
|
||||
{
|
||||
"recipient": "age1vnw7lnfpdpjn62l3u5nyv5xt2c965k96p98kc43mcnyzpetrts9q54mc9v",
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBMc0grUDVodGp5YWtpb1RS\nVUpweUUzcGxIbVpPYTJma3RaSDUwM2MvUlRJCmdacFE3OEQ1am53Q2hzYjRRaFRI\nSXlrbzVacDVlMnp1YlgrckExSG1yWTQKLS0tIE55R1QxOUJyN0N5Vmh1cG1iN2xC\nclNrWUF6TFRsTlBIUE9mNFZmQXNrMnMKVTrGgIrxA0pAjGOZyHJpwl6TBPBqXbGz\nUPgPFUUfLpUA+soyAQGE+/4bD4WFWwnro8B9zj0ahZYj1GvC8ddbig==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||
},
|
||||
{
|
||||
"recipient": "age1w7mectcjku6x3sd8plm8wkn2qfrhv9n6zhzlf329e2r2uycgke8qkf9dyn",
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBtT3NIUE1ZeXN1ZnkxaXJ4\nUzJNRFZWMHg0WWNJeFJ0NUlITGMwYVlLajEwCkd4WGJXbjdwcnJPeDdrZEFyaDds\nZjR2eEtkc1ZpdzVFeG9LajBIcVVNTVEKLS0tIEwzd1ppa3EvSHNYdUhjcHVnZ3Fh\ncWJwUkZVM1QwTHp6a1N2MzVQcUFSeGMK0PFJNAkpQEKQiNarb9dDr7MwtvGZeke6\n7vBhMsJ1lmCMu0TshNNbOmQpre2J6ZnGDnvOrpy8IQukym2py9KvXQ==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||
},
|
||||
{
|
||||
"recipient": "age1tzlyex2z6t88tg9h82943e39shxhmqeyr7ywhlwpdjmyqsndv3qq27x0rf",
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBzSkFLMnF0ZGdQV056VTdw\neUhyYnhGbzJORTh2ZlhXM0RzaWNjL3VybGlNCmNBVGlxSHIwWkxhZEg0ZXI3RFN0\nSk1XU0dTbFJ5NENGUnh0K3NRUCtzY1kKLS0tIGh2TnhuSERKb3B2c0oramhPelhm\nT1BBODhUaDVJbjg2Nlh3dnNPOUtvWmMKDyrOAsUZXp/hhXWczlf+VZRcz4mzaYZF\n3bW7w/nkojmMfKwKWvEYsunNPJSV+In1CTkvv8e8E1aIq5jithYe6Q==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||
},
|
||||
{
|
||||
"recipient": "age18vq5ktwgeaysucvw9t67drqmg5zd5c5k3le34yqxckkfj7wqdqgsd4ejmt",
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBGVmZEU2ozMjBNTmVMU1NG\ndFIzSndXcmZQVWphU1BWSURCVGhGQVhPUDE4CmZMS1dFU1BxL3FYQ25ETDJJWjhu\nTWwrd2VzemxoWGhJTzFXUzh4d0o2c2sKLS0tIEt1cmg1WHFQWjV6UlRvWEJhQVFh\nQjV0MU5zYm1US1Y0dUR1RldZeUxkcmcKgbhTfvnP+krgib2xcZ85szzH/EvgxAwH\nqKlmN5J8DmllxR+O97hwCdDMu3vC5Vx+lp7Rxs85xFHu2quw37liGw==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||
}
|
||||
],
|
||||
"lastmodified": "2024-06-21T13:47:00Z",
|
||||
"mac": "ENC[AES256_GCM,data:vY0UHEkQKgWaevRo+9FxBjdSSFkAPMFt6ABSsZfArVqjBRLAo5O53aIV40KTDahd5UP25UgjPE8TVqXpWo/CVXct3M6SOnbSAlO9NGHkygyM5xk8PqzA6TXfPw7XzInvwMiAIuRNqJRAyKktHYmuiFMlEnhPhuCB6GLUdqpZEmQ=,iv:sK+QmTpl9y0UrruTqTb8oNcKrZrn9fgmldMxxyqr+vg=,tag:aeJeVIjwrcXAVOqMHNgIfQ==,type:str]",
|
||||
"pgp": null,
|
||||
"unencrypted_suffix": "_unencrypted",
|
||||
"version": "3.8.1"
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user