Compare commits
1564 Commits
wip-doofne
...
2024-09-20
Author | SHA1 | Date | |
---|---|---|---|
29b757638c | |||
821855651d | |||
606be197db | |||
208b634040 | |||
224b298cda | |||
29975ce787 | |||
90d48849cc | |||
9a4635c93b | |||
f7b4e5ba98 | |||
84c4dcb9d1 | |||
3dff60397e | |||
b105e774b3 | |||
e9d3623a97 | |||
a9472a14f2 | |||
a2abe159a4 | |||
0546bf6ea5 | |||
d22bbcf44a | |||
e6803d6068 | |||
3993f26cc6 | |||
f6a93e120a | |||
b3a6656c81 | |||
a4a43d24dc | |||
ec144ae63b | |||
145c65b66b | |||
dfad5d596d | |||
ee083b1b8f | |||
f1d05af377 | |||
c81a6f51e2 | |||
8559de949e | |||
8979ff0eec | |||
2a4043523d | |||
bf53ab1cb1 | |||
381641b2db | |||
1cc809b347 | |||
9e74297acd | |||
51556eeefd | |||
32d565fe77 | |||
0e4b38a163 | |||
03ebb3de28 | |||
b034196ce4 | |||
b0edd56ba2 | |||
717af4e5ff | |||
3c660df817 | |||
dc1999e7b2 | |||
e2698f02c6 | |||
3c863bc004 | |||
fec90421df | |||
1c5b9f1ede | |||
4ea9698959 | |||
c6705be538 | |||
d8b9f58788 | |||
378168776a | |||
f5a86956a9 | |||
965ef91736 | |||
791b96fa8f | |||
92626cd87d | |||
09bbd9fd91 | |||
9b07eebf6d | |||
439ee43a5e | |||
e2a96a391f | |||
6be3a8a245 | |||
7a3c550817 | |||
7b72046bee | |||
5500a7ffcc | |||
e2cd92a356 | |||
b1036896fe | |||
e4ab6e2022 | |||
631bd9998d | |||
28d329855f | |||
4d03d7a845 | |||
2f367c1247 | |||
ee62acab02 | |||
9efa3f8f86 | |||
7b57d62da6 | |||
aa0ca7ed0e | |||
c0347eb68a | |||
e5a1aeedac | |||
9108ecdf59 | |||
1859cfc714 | |||
c8fca594ef | |||
395ff01276 | |||
13b38f523c | |||
1dc18bca5f | |||
e763673e75 | |||
034c3f987e | |||
c15d068f39 | |||
6ad53751a1 | |||
bcc6c773cb | |||
dfe3f39225 | |||
2bb4a3fec2 | |||
a03a0fcefd | |||
b41db547ec | |||
6edc81d437 | |||
6d8008ea5e | |||
2c932ed926 | |||
4560bb9dda | |||
051625fd47 | |||
bb0a90ec1e | |||
acca87c187 | |||
e23429eebe | |||
9fcbd6e7e2 | |||
d943946f9d | |||
c8543e9326 | |||
e9decbbf40 | |||
fe353f3417 | |||
adf554c177 | |||
373356d097 | |||
b5f9ba62d0 | |||
6e0c83b4f3 | |||
4fda2e67a2 | |||
c576885c84 | |||
565684d1e9 | |||
7a75459249 | |||
d0555548b7 | |||
52b71b5ef3 | |||
0ffb67b77e | |||
146a184e43 | |||
9c4f87bbad | |||
54dfb04b81 | |||
a773513189 | |||
4f77b2313b | |||
c7305f3c90 | |||
f3edeca237 | |||
8b3e413cae | |||
1971ef5fd4 | |||
6a1f48420f | |||
441269fb2f | |||
b43ee23459 | |||
b9db78a154 | |||
e2f7cd154d | |||
fa180ff50a | |||
3febbcaef7 | |||
2c68bead1d | |||
129a7aec68 | |||
fbed348e68 | |||
4694dacd2f | |||
7fa689c82d | |||
add5910b4f | |||
590d4d819e | |||
f6493122bb | |||
954fedd41b | |||
858ca4245a | |||
d1044023d3 | |||
53e73659b4 | |||
8a5e1cb6b6 | |||
2a29e22d6d | |||
f5a64bc913 | |||
2407e51b67 | |||
e626044037 | |||
f6abee5670 | |||
8b8bbcd59b | |||
f14dbf13b1 | |||
a0a34cc62e | |||
89b9f693e5 | |||
2c76497d34 | |||
0128826a42 | |||
4de34f662b | |||
07626c55f5 | |||
d53b4df4a8 | |||
f6b6d6488d | |||
c6d93598ed | |||
fad05b929a | |||
e69bacf54e | |||
7d4d4d6c65 | |||
7d6c5cf20c | |||
b483254bb3 | |||
884435fe21 | |||
33aaf8c458 | |||
1c3c7f599f | |||
e7f54cda6b | |||
909beec420 | |||
ae5bad1514 | |||
77683e090c | |||
f7c5b16c1c | |||
ad98e96823 | |||
e167cbbbb4 | |||
eb6c0acf11 | |||
f7a650b0e0 | |||
a37554ada3 | |||
d3fa4e6e7c | |||
90df023be0 | |||
f8141c5270 | |||
1599df26e7 | |||
0b39f18faa | |||
8ae7e255e5 | |||
6f72453f5d | |||
ca09c93bf8 | |||
ba229aaf69 | |||
95994de1ad | |||
f04d0c07af | |||
6dc4aeafc1 | |||
1067bc9215 | |||
bb18f65ed2 | |||
0d6a823382 | |||
13aad0256d | |||
ca4061ab94 | |||
df65454950 | |||
64311094ad | |||
ac53d5512b | |||
9d594f696a | |||
4ade6b1418 | |||
3ef98a5ab3 | |||
130ce0e69f | |||
3fb566a3fd | |||
135af51f37 | |||
98ed5f10ee | |||
71241f83e2 | |||
2b7143fb84 | |||
0605034a53 | |||
140f2b515e | |||
ca5eab656d | |||
028f56f70b | |||
9f4c40fe01 | |||
8eadede76d | |||
823ec0e6f4 | |||
fc865574bf | |||
58b3411c8c | |||
e517c5cecf | |||
c735c0e11e | |||
41d7268094 | |||
e66c389695 | |||
d43a5a4687 | |||
83efe3f552 | |||
5742101191 | |||
7b5508c91d | |||
0b11c0e790 | |||
aeea904e5b | |||
64e302eb20 | |||
91a9d6e0d6 | |||
f593b8ca4a | |||
30060e4bb1 | |||
9b8bdfaf5e | |||
fc72884c2e | |||
8f47636ee0 | |||
f68fbb0e0b | |||
7ce82ca735 | |||
7ce098f2bb | |||
454c109ef8 | |||
4dfc0bf323 | |||
2d1e7777e8 | |||
1d5f71f935 | |||
41a132dd9a | |||
51350d228d | |||
e9a289cc87 | |||
de47a0521d | |||
412e698786 | |||
ed7c5ef89a | |||
9814cb5ad7 | |||
b6d8aa614c | |||
24440b059c | |||
53ec44b3de | |||
e9cd3069fa | |||
7b4fc029b2 | |||
cc6e99361d | |||
ca3dc42586 | |||
8255e419be | |||
9bd5a7e4e4 | |||
baf5aab4b9 | |||
ce7474603f | |||
bf6053985f | |||
c0106c9196 | |||
038e21a447 | |||
6596bad162 | |||
c46c5bb3ca | |||
8079cc47bf | |||
8c802ddc1a | |||
1ed27c166e | |||
82dcd40829 | |||
c6af2c8e02 | |||
8bdb711968 | |||
4b96d10980 | |||
346b887779 | |||
6e30527688 | |||
9340f52df1 | |||
cc90183ca2 | |||
31d475bf88 | |||
329a02f475 | |||
e3dda5b140 | |||
876ec637c2 | |||
d338826855 | |||
b770a77257 | |||
b289f13779 | |||
d8664cd88b | |||
5270c41347 | |||
850c975321 | |||
b1b12c353d | |||
3934d9c5a5 | |||
84a36d9ef8 | |||
05b8352b4d | |||
4123d2d92e | |||
768998f78d | |||
a128f624b2 | |||
f12123416b | |||
392330f9ca | |||
60bdc7c5d3 | |||
aa93ac608b | |||
3ad7271439 | |||
fe087720ed | |||
15ff2589d3 | |||
b74372dd2b | |||
196cf2dc9e | |||
3f6713c12c | |||
d8058f0591 | |||
a1450b4eff | |||
3b009b8435 | |||
c0bf2df718 | |||
24eefbeded | |||
e97302a453 | |||
2b2173be56 | |||
ac5b9061a2 | |||
a54b051bbe | |||
968e9654cf | |||
a557c79f4e | |||
f2dc84a1c8 | |||
8a7a20fe2b | |||
7e674b205f | |||
8d87a15e60 | |||
f39a08e379 | |||
b567aeadd7 | |||
04ac2ada05 | |||
6193f347e7 | |||
39733b4862 | |||
9a7fca267e | |||
364a4f1182 | |||
3e182b2a06 | |||
6ff35b4366 | |||
9f49084ccb | |||
b2f351dba2 | |||
35a41be824 | |||
f384515c51 | |||
c7eb0c7c71 | |||
2debd88019 | |||
783a0ae29f | |||
ad57f1537a | |||
e82de6180c | |||
09cb743865 | |||
0d737216ea | |||
3478224bf9 | |||
94863db03a | |||
3260659fc1 | |||
1ce07e08f6 | |||
2e8904fa52 | |||
0535d97191 | |||
71539036fc | |||
e295da5d67 | |||
986dc8c37a | |||
57637167b1 | |||
9b6ec64ed4 | |||
c7638be79b | |||
f537049387 | |||
2cee6ea954 | |||
36bcda6416 | |||
45907f23b9 | |||
e57e0b9509 | |||
2f00580ddd | |||
c7a786bef3 | |||
646ffa891c | |||
a887d2d780 | |||
291e6fe1e3 | |||
acad3dc60a | |||
de78119e46 | |||
628a701fa0 | |||
851e6e9176 | |||
69bba0f6a9 | |||
3a8f31a490 | |||
4b0518408e | |||
2e38f49773 | |||
4704c9ca9e | |||
6d37c531f2 | |||
1d8f825bc6 | |||
775c1522ee | |||
4856a46388 | |||
2702e2afd5 | |||
2d1ebe7219 | |||
cef2a1e129 | |||
f48b8fb6b9 | |||
a75fb267f1 | |||
981cd4c65c | |||
d25701e280 | |||
562315bf4d | |||
5b9fbb97cb | |||
2965fe29d1 | |||
6692c67e74 | |||
cc7f53a828 | |||
5e38ebef4b | |||
181bc57a8a | |||
8a61ad704a | |||
c93f71e285 | |||
09507a04bd | |||
ccdf633e4f | |||
e62c1fe63f | |||
66f00088f1 | |||
a2366ba9d4 | |||
a2bfb23253 | |||
d474d159ac | |||
60d5dbda77 | |||
ff763b44bc | |||
ba28240a04 | |||
2a755492bd | |||
c682cb5fd7 | |||
68dfd64ee3 | |||
179c6697e6 | |||
9301a84e1c | |||
fc5a1c7d5e | |||
94a261280b | |||
8214b27569 | |||
12c39fec03 | |||
50d443ad46 | |||
a4eb7c0fd6 | |||
a633690ab9 | |||
8badb38b76 | |||
3bc8c34b85 | |||
88263695d3 | |||
7d9b2cb224 | |||
1588ebe696 | |||
8cbe8fc9e2 | |||
0ee564b329 | |||
a9f0f99482 | |||
fd2eabf07e | |||
7b8303f070 | |||
eaf03520e7 | |||
b05ebc6c62 | |||
8c94bc79d5 | |||
d2f86e7b0d | |||
f959a0dd00 | |||
a0240dca36 | |||
471f453321 | |||
3712eaf869 | |||
ecc4e90b4a | |||
c7823ab3f4 | |||
2cc23525ec | |||
07bbf34f59 | |||
941fff725a | |||
d478b945c4 | |||
769fdcee89 | |||
b0aedb6714 | |||
20e71ad800 | |||
0566e237aa | |||
0df02b5ba3 | |||
22a5bcc259 | |||
40d14460ab | |||
ef0f6c2053 | |||
71be891c85 | |||
a163a260fa | |||
fe910ea153 | |||
1e81c033aa | |||
f490a49921 | |||
7b9874b90d | |||
4b52fe260c | |||
8a2951a405 | |||
c81e2fd6fa | |||
1ac244d1de | |||
f70d4b75b2 | |||
34aad6f74c | |||
d20359fc1d | |||
714f727f1a | |||
eff8f2597c | |||
1d7a8c688a | |||
56bac1ac19 | |||
fbe00915bb | |||
bf1d401b48 | |||
424f6ef35a | |||
4637a3eee3 | |||
d2e600dcf8 | |||
a17369cebe | |||
2d5cb84eef | |||
9050d8979e | |||
15d668f1ca | |||
147efe0a9e | |||
d11f3152d0 | |||
8a2a41ecc9 | |||
f1000c9fba | |||
5266a8b8f2 | |||
af99673043 | |||
eb562037b1 | |||
08ed8cd052 | |||
ce7a082447 | |||
53c4054bb7 | |||
070bc867da | |||
9bfc527aa7 | |||
c23cf48001 | |||
dfffa564e2 | |||
8a89e62063 | |||
71d32e442f | |||
68ffdc113e | |||
8b0ca4d393 | |||
743ede00c4 | |||
41d9eccfe8 | |||
04eb5ed012 | |||
0279c030de | |||
f0ea3f8bf6 | |||
f3b9369783 | |||
5ae12272bd | |||
6a1b4fdba1 | |||
0264ed68f4 | |||
384472c1c4 | |||
1719943a6e | |||
0ee51d1812 | |||
5e84056715 | |||
da72fc9d52 | |||
36e2f57b06 | |||
bc2823d622 | |||
8b53f97c1c | |||
712b2c38f0 | |||
3212664f37 | |||
98c62f66dd | |||
1677f77fd6 | |||
c5e21546ff | |||
5eb597b133 | |||
90f7953615 | |||
ab15d2a991 | |||
eba9bb3099 | |||
3deb17125d | |||
49a38001bc | |||
a39d705ff5 | |||
4328a7ddf3 | |||
1b959272a1 | |||
9d83f4cbf7 | |||
48fccebd1e | |||
8f4d4c97bc | |||
0419e50cc3 | |||
80d3ad3d0e | |||
3d3853d596 | |||
cfa60ce41c | |||
942ca82445 | |||
336696bb06 | |||
7d75b3c736 | |||
3ca2c7ec53 | |||
9d605030c3 | |||
e1d678093e | |||
5586a3a87b | |||
38c6ecefa6 | |||
c80aa813d9 | |||
4f6ea0938c | |||
7ed78686c2 | |||
96b90b84d3 | |||
c32be5d170 | |||
7830603ff3 | |||
98f028108e | |||
1649e9e22f | |||
874ba132a8 | |||
1f0fa1cf2b | |||
98e32fbcab | |||
947f2b821d | |||
68478b37fe | |||
097f172e71 | |||
28be40a2c8 | |||
9daa12049f | |||
b9cd911c0d | |||
de2991a515 | |||
dd3dfc1988 | |||
a4dbca48fe | |||
2cfccd948f | |||
d911f92c28 | |||
5a782551f7 | |||
c4f97fc31b | |||
b4f921ab04 | |||
458a87045d | |||
ee4c699850 | |||
341b150254 | |||
737df8c10e | |||
2053ba079c | |||
04c937f04b | |||
475d1615fa | |||
25b3ccaa48 | |||
735079e615 | |||
1a1edc0d19 | |||
9148b49ba2 | |||
67f6026c67 | |||
cfb5a7651b | |||
6f71d2f8db | |||
5f5cda9706 | |||
7ac4a6f060 | |||
1d79f3eacc | |||
e5263915b9 | |||
29cabd2ac4 | |||
475037f9c9 | |||
dab05a0f9c | |||
d2bf8dbdbb | |||
3e5cb29a7d | |||
edeb153eb8 | |||
61e8b99f72 | |||
566a61ca9f | |||
590cd36e53 | |||
9803be75e1 | |||
73583d19d4 | |||
19e2e37105 | |||
f26f13ddf3 | |||
9c69666646 | |||
4f6b1b0a69 | |||
bc1453f675 | |||
353057af23 | |||
7f5b55bc2a | |||
452ee68926 | |||
a2fa3727cc | |||
1676ef77ad | |||
39a7c1a6d9 | |||
d91e1d51c1 | |||
f6d4dcaabb | |||
963a0ee56c | |||
3e9e1168b4 | |||
14929c1102 | |||
35848ece02 | |||
38ee8be785 | |||
b3ea0ff2b3 | |||
e5cdd53537 | |||
fb894bb7a5 | |||
2ffacf0e44 | |||
7dbe64e52f | |||
b9fc61e627 | |||
99de056048 | |||
469b9b9223 | |||
2f6e54f331 | |||
29886d7f10 | |||
861014bca3 | |||
3417a9fd3f | |||
83ef250a34 | |||
59ba9e4853 | |||
3994beaa01 | |||
93159485fa | |||
e1f5a55bca | |||
ea2739f86c | |||
3c9ff16108 | |||
0787a3a50e | |||
446e614e9a | |||
afd0ec09a1 | |||
422e8aeb3f | |||
ae8e9267c4 | |||
60c4b2e4c0 | |||
289e9182fd | |||
ec7b87b985 | |||
9f5d7f2bb2 | |||
64697a2cb8 | |||
1c50ff8fe4 | |||
3010ff89d0 | |||
7a902cabfe | |||
64948a497d | |||
ccddc6f8e1 | |||
7d7abc9619 | |||
f0efa0c255 | |||
9ab6d101f6 | |||
164275fa59 | |||
dbdd356691 | |||
c9157291b9 | |||
e315919b54 | |||
5f35eaccd9 | |||
c86d893a2c | |||
abb19b1fc9 | |||
ab4ebb012a | |||
effec38a99 | |||
c5ed1263dc | |||
e0d33862f0 | |||
7d097474a3 | |||
7a4a7d613b | |||
e457cf96ae | |||
f323c0f90d | |||
5525ea4b59 | |||
daa1783e21 | |||
27d5928155 | |||
2f9dd4cd60 | |||
ba406e912f | |||
45ff21822a | |||
7ef9f0b455 | |||
ec90f5c066 | |||
57e113137f | |||
2c390a8b6d | |||
634f13ba6b | |||
dab7803cbb | |||
64f53020ee | |||
e737d2e24b | |||
9b11b64349 | |||
212f6c0f48 | |||
a9cc0f28e2 | |||
3599f051b1 | |||
d72a1c799e | |||
e78907b88b | |||
04c41f6045 | |||
32a52c3366 | |||
55175e5957 | |||
b4b95be588 | |||
2758b0eae2 | |||
ae0d6cb8e8 | |||
9c9b237e69 | |||
17dcf566f7 | |||
bf94946759 | |||
6e1ccc3e19 | |||
4055c6d3e9 | |||
ba8d9f2882 | |||
82aa0eb1d6 | |||
6341531122 | |||
c71d89e6af | |||
995183a4fd | |||
ddffda1594 | |||
c15cea08f6 | |||
7e73199b68 | |||
705a8a19c9 | |||
c8b28580a9 | |||
1b4266f8a7 | |||
aecbfb45c9 | |||
e16a26fad2 | |||
7d23f9453e | |||
391c4f5aac | |||
48b0960966 | |||
9069a97c26 | |||
ca793af819 | |||
05e2f6f2a0 | |||
08d6f9c761 | |||
05bc5923cf | |||
114b37928a | |||
e846a5046a | |||
5dcb7b5cf6 | |||
f603bad779 | |||
729d2a9809 | |||
a552ed625b | |||
f3df321713 | |||
62ebdf5de4 | |||
f834f551ed | |||
140b61a944 | |||
db7767c679 | |||
fd6959230f | |||
87e9856497 | |||
50b1d82b38 | |||
60a4eb0bde | |||
a96e83f4e1 | |||
0d685f406e | |||
a16e33d7a6 | |||
f38d351869 | |||
e245164da3 | |||
7df8f45e97 | |||
e1ba371838 | |||
467283989f | |||
db39dc209f | |||
7cf860a071 | |||
77a753b0d6 | |||
e2a4f4d63e | |||
31fc072bce | |||
144afd8171 | |||
7d97355d2a | |||
7827f6c584 | |||
e1899495a0 | |||
a56ad56a4f | |||
da551b8b97 | |||
ca412d08bd | |||
e7a1bb6ec0 | |||
74acfeadd5 | |||
e7d5a61014 | |||
6f47708624 | |||
fc826a3503 | |||
ccb2b7b8b6 | |||
78169d50f2 | |||
33a7d3536d | |||
7899c8d033 | |||
82b662a733 | |||
d4290588bf | |||
bd97fb9ec9 | |||
4dbff9c18f | |||
bfe278c17a | |||
295e07d535 | |||
d39459d8b5 | |||
4d5e60756b | |||
119afcf393 | |||
d3d970eb3e | |||
c0d5004926 | |||
d9a876e49a | |||
5a9dd89475 | |||
5e71e5a067 | |||
f0b0d15ad7 | |||
8aebc1fe87 | |||
764c2a3276 | |||
a2f34be9d6 | |||
bda172bc2d | |||
a91a2d8a7f | |||
875d919fa8 | |||
a323f321b5 | |||
f986936bbd | |||
3d773fe375 | |||
055ad222e3 | |||
3aafcb0aa8 | |||
c85f02ca68 | |||
eeafc34ccf | |||
039ffcdcd4 | |||
2a35cb5379 | |||
3db009bc98 | |||
1e840e72b3 | |||
ce1c3ec804 | |||
09dd69a855 | |||
cbe71868ef | |||
7b043d0c87 | |||
fd0188025d | |||
1c57ffa798 | |||
1d205a89bc | |||
5ff643aa2f | |||
bfdf63e641 | |||
c695f7a979 | |||
b3b38451b5 | |||
1ee81db537 | |||
b9947c05ca | |||
2de6491583 | |||
4525df58e0 | |||
9d1ffc7c43 | |||
a69af91b7b | |||
7b5d655c91 | |||
de6ffe6b75 | |||
f8aea34e96 | |||
49efb94a0a | |||
9b1e053ead | |||
235dc86155 | |||
6dad290cd5 | |||
cc6ed6c0ec | |||
cc3aba3cc2 | |||
41f08125bb | |||
27487fe870 | |||
d45ea622d1 | |||
247fd3f807 | |||
816e2a7065 | |||
be842d5c5e | |||
fa6ec981e0 | |||
52b4c1542a | |||
3ff59247da | |||
d9c0855c4e | |||
1a67a05238 | |||
1cdeedd9ec | |||
6830bb7097 | |||
316b0bee3a | |||
638655ff83 | |||
5e57e78411 | |||
3859619ae0 | |||
646c2dd85a | |||
0655b6906c | |||
3019f90f5d | |||
020e5f8c6e | |||
809c3af7fa | |||
93cb1bc546 | |||
53acab834c | |||
3a0610b029 | |||
9cee460d7e | |||
e657507a76 | |||
c706a19836 | |||
566e15286b | |||
d1b4e9c923 | |||
5eca45891b | |||
722fe8f368 | |||
e25dd98f6c | |||
54e9d4a0ae | |||
9f3a13eeb8 | |||
5605ffda4b | |||
9165925469 | |||
f65bf2b433 | |||
0f60a86ed4 | |||
b488b6748d | |||
ef6b7cf175 | |||
0906d76f83 | |||
90c495e74c | |||
74662df720 | |||
2b3278eb7f | |||
9b4e91fbd9 | |||
734627232a | |||
3adbbe5fa7 | |||
b4a244df7a | |||
97268e9b26 | |||
bebf6bdaeb | |||
04fc601c9c | |||
ee062d61d0 | |||
0dba9987c5 | |||
4761690b6d | |||
604782c3a6 | |||
365d33c357 | |||
a39ad8a508 | |||
c49e9a4c2b | |||
36491842cc | |||
81ea2210c9 | |||
f678508b33 | |||
6135be5f72 | |||
c8989ca1a8 | |||
1d665f8ecc | |||
7c284ad8da | |||
1c26674da7 | |||
dae8481176 | |||
42b27f0433 | |||
84be0cae5a | |||
fbfd0afca4 | |||
e586b7b449 | |||
222c37b056 | |||
53b17ec230 | |||
7697704aff | |||
c490b6e6ad | |||
89d678c729 | |||
c64163290c | |||
eaeb8380dc | |||
05a9e8e819 | |||
cf20230d96 | |||
9dbb2a6266 | |||
113b107d73 | |||
96dfe79a8c | |||
6e5bde17aa | |||
3eb66c098b | |||
515aab5370 | |||
f925dd9a20 | |||
cbe6bdf158 | |||
949a52dee1 | |||
2ee1fb17c4 | |||
48cc718700 | |||
6a7dd31755 | |||
2197951e12 | |||
883db3e9ba | |||
312b0a5554 | |||
07de46c616 | |||
efc16a9e80 | |||
161f272f41 | |||
6aa6c0020c | |||
acd46940e4 | |||
00a25f1533 | |||
bc0a1eb1b3 | |||
cd3f483df0 | |||
38a183cf3b | |||
5ed6e84cc7 | |||
7c1a0fc323 | |||
f16066549f | |||
659da66106 | |||
c07eaba873 | |||
bb420bd45d | |||
3902432864 | |||
33efbeda8a | |||
8206fb0519 | |||
2687286489 | |||
d5e52e21f7 | |||
367fc24aa8 | |||
bf45206d1a | |||
397b2ae2ea | |||
f0ebb305ec | |||
e629d2d999 | |||
9b2601e450 | |||
a20c13fffe | |||
20a2d8dc1c | |||
297bf7e090 | |||
ed024d081e | |||
4ddd4191bc | |||
32ef63028b | |||
70bd001171 | |||
b53f376d70 | |||
621c147483 | |||
841076fd9e | |||
80492e902b | |||
f058fe0be6 | |||
8fde3dea77 | |||
ac9238a7f0 | |||
45412e5042 | |||
d76d50f1c4 | |||
f1c76ada43 | |||
9dbd85ba08 | |||
2c707c3acd | |||
0fae963d90 | |||
90df178c35 | |||
dc053149d0 | |||
bce81d0487 | |||
a8eba4df4d | |||
1bb36b74c2 | |||
e21910a1f7 | |||
4b30036973 | |||
ea5919ab6b | |||
43232ff569 | |||
6a9fd04437 | |||
dc2d46b9c0 | |||
666744bda3 | |||
ba09fbeec9 | |||
916ecc30d1 | |||
1536a60a3d | |||
b7418afede | |||
82a0bf3212 | |||
cb79224c7a | |||
b850e25f5b | |||
8f0f7ef333 | |||
0bfaead177 | |||
1b93dbe12c | |||
72d286fbba | |||
033faf6f6b | |||
eb3651ce59 | |||
bf1f843306 | |||
6cc5669772 | |||
cb1fbdcaf0 | |||
c83dc4d601 | |||
36bbac539f | |||
9a1cd9341f | |||
3a6a5ffe01 | |||
971de060d5 | |||
3ea57f1d6a | |||
fa05e59863 | |||
de7ff360dc | |||
7f1f9a082d | |||
6553cdc068 | |||
e44771f67d | |||
cbe17c03e4 | |||
4c4d841038 | |||
060ae113a1 | |||
540124d2f7 | |||
9df947aa74 | |||
66333cbbe7 | |||
3353ed3b66 | |||
447923a231 | |||
3179a6834b | |||
70a470b81e | |||
fff7848cd6 | |||
1fb6cb483b | |||
33e72c8d34 | |||
8629e2600a | |||
2e644dc020 | |||
f4a6bc1991 | |||
19fd45211f | |||
ace03bb0e9 | |||
8819142128 | |||
d905af6cd1 | |||
0f084b19f1 | |||
91263b9dcf | |||
40e4d0f39c | |||
06a17e4425 | |||
cbca403158 | |||
3b8d6c8587 | |||
d59380b4dd | |||
f4df121e3d | |||
3d91fa2475 | |||
96f786de20 | |||
fcbbfc4a65 | |||
b93e9e75e6 | |||
4daf5452e8 | |||
af905a2f58 | |||
8ef5920d84 | |||
b554d32133 | |||
2203d6db59 | |||
07b55bb3ec | |||
874b7aecfa | |||
cf8e9f798d | |||
800945d951 | |||
4c3b0f820b | |||
0756349c86 | |||
490c587737 | |||
15df9edca1 | |||
2d73b85f92 | |||
70d4925483 | |||
dda2ea6fcb | |||
a165e568a8 | |||
a539e52abe | |||
e62df51258 | |||
17e7c7d48b | |||
6f1173e45a | |||
225c8de7a2 | |||
05f8dad425 | |||
8b6971a164 | |||
91359174f6 | |||
b012b93d89 | |||
34e770c5f5 | |||
0460a419c5 | |||
79834aedf3 | |||
2ca8bcda56 | |||
8ced778def | |||
d91ca22587 | |||
a47b9d580a | |||
fc8a54f39b | |||
3ae25fbe31 | |||
36acc87f30 | |||
5b7244d339 | |||
9efa5bb209 | |||
211486f60e | |||
b21002207a | |||
1fc0ae3066 | |||
712cff2867 | |||
a103cd819f | |||
553a2724a4 | |||
bf0583cbda | |||
5a5842d26c | |||
3f8f3f4e54 | |||
4ad6c84d31 | |||
8e215cba69 | |||
1e3b71def3 | |||
90b057af95 | |||
4e35c09a85 | |||
1e0034c66f | |||
ae91b825e6 | |||
3c8b3f2d04 | |||
79fbdc4e15 | |||
284ea45648 | |||
9c33cb44e2 | |||
77a9f47352 | |||
04a5d38f79 | |||
452950d80b | |||
a79d9b1823 | |||
6e3a790a46 | |||
7be997f597 | |||
ef1ee6c1c9 | |||
e196cea667 | |||
105416990a | |||
c0d1f7711a | |||
f123be98b2 | |||
15b0bba329 | |||
734a4c7c31 | |||
3ce2b44b7d | |||
5f0eaa9771 | |||
cd7b36b761 | |||
b72acef8ed | |||
74f2d4d174 | |||
bedc9d4b2c | |||
70b36fd79f | |||
7baed78b65 | |||
7cca126efc | |||
433e8b8736 | |||
c026b8c40d | |||
88df6b30ce | |||
d324a57f06 | |||
55bed1926c | |||
8c9dcdb90f | |||
0ebcbe0ad5 | |||
a9cbb2c092 | |||
c5227c52c4 | |||
0af5e43944 | |||
cd16f8c3b6 | |||
0f7ec33dac | |||
993c3df09e | |||
fccb48cc2d | |||
64ddf15620 | |||
68ef56b572 | |||
99c19ceac0 | |||
f95f9a35fc | |||
5f1ac2afac | |||
2ee53fd5be | |||
9fb2cf4d42 | |||
612fa0cae8 | |||
875e85c646 | |||
94ecca2967 | |||
1fea424052 | |||
4abd782b62 | |||
13b04d50b0 | |||
36b1178fc0 | |||
527e7029b9 | |||
18c07721d9 | |||
6ac700811a | |||
cd62aa2f38 | |||
72a78c5f3e | |||
db292850b0 | |||
8e6272bafd | |||
90e1f4a447 | |||
31c32b9636 | |||
d6aef04a77 | |||
0f08f14dc0 | |||
6d9806613c | |||
c0c2aa00f3 | |||
6d5cd7b604 | |||
98860ccf46 | |||
bc5805b341 | |||
3a4d27c3bf | |||
c88ef43310 | |||
326e71f7b1 | |||
532d3c13f6 | |||
9f26ad40f9 | |||
c8a99317bc | |||
2296e10f15 | |||
ca68434f18 | |||
a1de7a4afd | |||
b692c0b6ce | |||
8ba1e35b9d | |||
765ec610c9 | |||
43c33fef21 | |||
9bcc7cd30b | |||
0b7d8310df | |||
c6f07d4f55 | |||
94a0e77fcc | |||
91d5c20a56 | |||
9b898ce597 | |||
a49411c02d | |||
fcd13d4f6f | |||
ef1be364e7 | |||
8472320629 | |||
19acab1363 | |||
98e1ae53e2 | |||
eb2321aa79 | |||
8febe70665 | |||
ee4ab3b40c | |||
281643afb0 | |||
86f1e36035 | |||
929a8eadbc | |||
e355a4b2eb | |||
132798be23 | |||
c72e66a901 | |||
40d32ec1d5 | |||
1377f5c7bc | |||
bee714311b | |||
b368d4624e | |||
583f7217fc | |||
e8b0979de6 | |||
c4b4ac48fd | |||
8436ba3e02 | |||
8b1f91ca86 | |||
73f6907e9a | |||
d6bfef7657 | |||
0fafd81b79 | |||
2ac9c2cb68 | |||
e8547cc849 | |||
3495f04810 | |||
68a891f6de | |||
b8dbc0c1c0 | |||
6964cf8d46 | |||
c959c0a74a | |||
7b0a4c11ec | |||
a926cbee46 | |||
23d8990596 | |||
76ae404827 | |||
e868e28ed9 | |||
2283a5b167 | |||
8d0b7c5855 | |||
3fb7fe34c4 | |||
10687a80e4 | |||
a8bcfaed53 | |||
ab200f8988 | |||
b443fd46d8 | |||
0473822172 | |||
d0b5f586c4 | |||
f6895393d9 | |||
f78b49f075 | |||
aa3115d2ca | |||
924a6c812c | |||
fd50bf6422 | |||
7c0e7cbb71 | |||
26004da704 | |||
7013b09715 | |||
3969fd484b | |||
eeab1d9fda | |||
deb355d960 | |||
1d4df82bde | |||
f49e87cf99 | |||
e38c2f20e8 | |||
0e5f01f240 | |||
e04dd6cb7d | |||
f4b6bbfbd5 | |||
2e8c58a53d | |||
f6e326869f | |||
c16f2473e5 | |||
d85ffa8539 | |||
987cd93ce3 | |||
e82faa5961 | |||
514cfe7b0b | |||
dd2eb66875 | |||
6ccdbf50cd | |||
e2cca54e08 | |||
721f45f7d4 | |||
774ebd23f9 | |||
bfdacb1941 | |||
beeb5d34b0 | |||
3d3faba263 | |||
a56795ff79 | |||
00d644ef07 | |||
672de68e56 | |||
e47bc4c04d | |||
0b6a8eecce | |||
eaaea26603 | |||
e1c80c9abc | |||
50add19b14 | |||
56032bc040 | |||
6ee33240d7 | |||
4aaeb42cab | |||
2697d068ce | |||
3ae650bcae | |||
ddce650bc5 | |||
96bf9d594f | |||
c2185f44b1 | |||
549fa8e5cd | |||
afc31dfc2f | |||
2011065497 | |||
ca6bb7518a | |||
612274d0b2 | |||
b801ed07d6 | |||
53fd4ee42f | |||
0b610a6683 | |||
3696953ba0 | |||
da8b3fc188 | |||
91db9fef82 | |||
682e9c0c68 | |||
cd9f1cc95e | |||
607845d495 | |||
79c8521f38 | |||
fa284c3dec | |||
3fe5e57c3c | |||
05c212a227 | |||
ea2da626d1 | |||
f8d0c9ce3b | |||
46bf7c5ac9 | |||
d12120d53c | |||
22e3f58ab3 | |||
9f483541a4 | |||
8d8f19752f | |||
49c3bf0f34 | |||
065aba0996 | |||
c7425e792b | |||
74b7e90a34 | |||
9f642980fd | |||
c638218c07 | |||
1ad933ad9c | |||
3dc007448c | |||
3487303216 | |||
b74e797b13 | |||
bb3f148c32 | |||
e235e09cf1 | |||
64610a5806 | |||
15ca5fbfa4 | |||
997b841777 | |||
9ced7bd3b5 | |||
2710f2b2ca | |||
572a340c8a | |||
b844a9ef5d | |||
d41d067405 | |||
f8349a646b | |||
706667f403 | |||
99e0d5f03b | |||
3d82bc8c87 | |||
a3212f6955 | |||
0d3e89a431 | |||
b7c86d5867 | |||
5db8372b24 | |||
da09ab3617 | |||
133744fa4b | |||
bfd272b2c9 | |||
3edc8d87f4 | |||
6824080f6b | |||
0786475c63 | |||
ae082b1654 | |||
a77816e9de | |||
f50b10682f | |||
b062610866 | |||
bce8a0d91f | |||
3c53bca156 | |||
46806e36f0 | |||
4a8a5b309e | |||
8f46bd5497 | |||
2c3239da8b | |||
a08394edf1 | |||
5e5ecfe81e | |||
5048bd8d70 | |||
c7d8d9ee86 | |||
2e49946c65 | |||
a12aa02655 | |||
6d66a5dbf8 | |||
a31f67b793 | |||
5d80e298b5 | |||
56e488b130 | |||
5ebaaf46a2 | |||
bee3ec1fa0 | |||
46eab8f4e2 | |||
828d4fcc9c | |||
ca2ac89cec | |||
1ae1d94d53 | |||
c68f333bc9 | |||
9a09faa9e4 | |||
ae2eaa786c | |||
9c523b3ddd | |||
44c4e88b90 | |||
5ca0ca4f47 | |||
00ea7e17c5 | |||
823f8f2be3 | |||
13bec790cb | |||
e72f9be1bf | |||
0fd8dc2a01 | |||
24ed242bac | |||
f290b16f12 | |||
b4cb3decff | |||
7084bf95fa | |||
acd0926d1f | |||
2dba46da6b | |||
110c440697 | |||
f4047bfbea | |||
c573ac4e7e | |||
cc15be54d4 | |||
8b95a5fa37 | |||
b596f88ccc | |||
e82feb9f71 | |||
4839a40205 | |||
631c47c9bc | |||
b2f36e4ef6 | |||
9a210b4a63 | |||
181ebfc627 | |||
ddb904ae19 | |||
a234e57d89 | |||
a75a8f8425 | |||
9cbe74b20b | |||
6b06062cc9 | |||
b009b2c836 | |||
d46239f2ad | |||
47f474fecd | |||
828ef00b61 | |||
5d14a39d52 | |||
58f89aadf3 | |||
d9a03ee64a | |||
697543a675 | |||
ff235f5806 | |||
39fe0ce43a | |||
98fde86ff6 | |||
5c6a5b01c4 | |||
bb4f963c9c | |||
9eb0b3fc86 | |||
5b7f15b278 | |||
5176d6a3bc | |||
84ba7e3d68 | |||
6d16d83aab | |||
e9c51eddb3 | |||
75473c7123 | |||
10f7714cfd | |||
fe78f8bc45 | |||
6bbe3a8e23 | |||
98c4a5ec87 | |||
bf3a894d38 | |||
c973f2e03b | |||
9f76469b5c | |||
52231f2adc | |||
8c5d9d79d7 | |||
961c38e79b | |||
fc5068f4d4 | |||
e641f5c93a | |||
870e766966 | |||
a75a341b56 | |||
8b7ed2cdd4 | |||
b3a685aa31 | |||
9b8c461ce9 | |||
27de05a751 | |||
f54f1c57bc | |||
98d6439f2a | |||
fbcf2aed41 | |||
fb7701027e | |||
0bc228c07b | |||
943ebba7fb | |||
e41bf78db6 | |||
8588230f80 | |||
8ef1af7e22 | |||
989344f87e | |||
90f8d1e042 | |||
d8ca5f91c3 | |||
167bb4d8de | |||
6b117fa9bf | |||
4b9dcd50fb | |||
84e6d536d6 | |||
4c74e53052 | |||
5def8f30ad | |||
45dd144b24 | |||
66d4b380da | |||
8e7da2c956 | |||
0f11b9a7b7 | |||
d9437bf4aa | |||
5d1c52d0bc | |||
a0dfdb5125 | |||
cbc2ba02a4 | |||
ef0adb5689 | |||
b1bd4399f1 | |||
2b252e3ede | |||
9aaf89408a | |||
283ca45c5d | |||
7955d90f8d | |||
a06481fbef | |||
5db4d73ad6 | |||
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 |
@@ -17,8 +17,6 @@ the only hard dependency for my exported pkgs/modules should be [nixpkgs][nixpkg
|
|||||||
building [hosts/](./hosts/) will require [sops][sops].
|
building [hosts/](./hosts/) will require [sops][sops].
|
||||||
|
|
||||||
you might specifically be interested in these files (elaborated further in #key-points-of-interest):
|
you might specifically be interested in these files (elaborated further in #key-points-of-interest):
|
||||||
- ~~[`sxmo-utils`](./pkgs/additional/sxmo-utils/default.nix)~~
|
|
||||||
- these files will remain until my config settles down, but i no longer use or maintain SXMO.
|
|
||||||
- [my implementation of impermanence](./modules/persist/default.nix)
|
- [my implementation of impermanence](./modules/persist/default.nix)
|
||||||
- my way of deploying dotfiles/configuring programs per-user:
|
- my way of deploying dotfiles/configuring programs per-user:
|
||||||
- [modules/fs/](./modules/fs/default.nix)
|
- [modules/fs/](./modules/fs/default.nix)
|
||||||
|
96
TODO.md
96
TODO.md
@@ -2,20 +2,21 @@
|
|||||||
- `rmDbusServices` may break sandboxing
|
- `rmDbusServices` may break sandboxing
|
||||||
- e.g. if the package ships a systemd unit which references $out, then make-sandboxed won't properly update that unit.
|
- e.g. if the package ships a systemd unit which references $out, then make-sandboxed won't properly update that unit.
|
||||||
- `rmDbusServicesInPlace` is not affected
|
- `rmDbusServicesInPlace` is not affected
|
||||||
- when moby wlan is explicitly set down (via ip link set wlan0 down), /var/lib/trust-dns/dhcp-configs doesn't get reset
|
- when moby wlan is explicitly set down (via ip link set wlan0 down), /var/lib/hickory-dns/dhcp-configs doesn't get reset
|
||||||
- `ip monitor` can detect those manual link state changes (NM-dispatcher it seems cannot)
|
- `ip monitor` can detect those manual link state changes (NM-dispatcher it seems cannot)
|
||||||
- or try dnsmasq?
|
- or try dnsmasq?
|
||||||
- trust-dns: can't recursively resolve api.mangadex.org
|
- hickory-dns can't resolve `abs.twimg.com`
|
||||||
- and *sometimes* apple.com fails
|
- hickory-dns can't resolve `social.kernel.org`
|
||||||
- sandbox: link cache means that if i update ~/.config/... files inline, sandboxed programs still see the old version
|
- hickory-dns can't resolve `pe.usps.com`
|
||||||
|
- hickory-dns can't resolve `social.seattle.wa.us`
|
||||||
|
- hickory-dns can't resolve `support.mozilla.org`
|
||||||
|
- hickory-dns can't resolve `shows.acast.com`
|
||||||
|
- mpv: continues to play past the end of some audio files
|
||||||
- mpv: audiocast has mpv sending its output to the builtin speakers unless manually changed
|
- mpv: audiocast has mpv sending its output to the builtin speakers unless manually changed
|
||||||
- mpv: no way to exit fullscreen video on moby
|
|
||||||
- uosc hides controls on FS, and touch doesn't support unhiding
|
|
||||||
- Signal restart loop drains battery
|
|
||||||
- decrease s6 restart time?
|
|
||||||
- `ssh` access doesn't grant same linux capabilities as login
|
- `ssh` access doesn't grant same linux capabilities as login
|
||||||
- ringer (i.e. dino incoming call) doesn't prevent moby from sleeping
|
- syshud (volume overlay): when casting with `blast`, syshud doesn't react to volume changes
|
||||||
- sysvol (volume overlay): when casting with `blast`, sysvol doesn't react to volume changes
|
- moby: after bringing the modem up, powering it down loses *complete* net connectivity (i.e. wlan is gone as well)
|
||||||
|
- dissent: if i launch it without net connectivity, it gets stuck at the login, and never tries again
|
||||||
- moby: kaslr is effectively disabled
|
- moby: kaslr is effectively disabled
|
||||||
- `dmesg | grep "KASLR disabled due to lack of seed"`
|
- `dmesg | grep "KASLR disabled due to lack of seed"`
|
||||||
- fix by adding `kaslrseed` to uboot script before `booti`
|
- fix by adding `kaslrseed` to uboot script before `booti`
|
||||||
@@ -26,12 +27,24 @@
|
|||||||
- `dmesg | grep 'hid_bpf: error while preloading HID BPF dispatcher: -22'`
|
- `dmesg | grep 'hid_bpf: error while preloading HID BPF dispatcher: -22'`
|
||||||
- `s6` is not re-entrant
|
- `s6` is not re-entrant
|
||||||
- so if the desktop crashes, the login process from `unl0kr` fails to re-launch the GUI
|
- so if the desktop crashes, the login process from `unl0kr` fails to re-launch the GUI
|
||||||
|
- newflash on moby can't play videos
|
||||||
|
- "open in browser" works though -- in mpv
|
||||||
|
- gnome-maps can't use geoclue *and* openstreetmap at the same time
|
||||||
|
- get gnome-maps to speak xdg-desktop-portal, and this will be fixed
|
||||||
|
- epiphany can't save cookies
|
||||||
|
- see under "preferences", cookies are disabled
|
||||||
|
- prevents logging into websites (OpenStreetMap)
|
||||||
|
- works when sandbox is disabled
|
||||||
|
|
||||||
## REFACTORING:
|
## REFACTORING:
|
||||||
|
- get moby's kernel closer to mainline
|
||||||
|
- i.e. reduce the number of megi patches i apply
|
||||||
|
- don't use pmOS's defconfig, but nixpkgs default config + whatever extras i need
|
||||||
- add import checks to my Python nix-shell scripts
|
- add import checks to my Python nix-shell scripts
|
||||||
- consolidate ~/dev and ~/ref
|
- consolidate ~/dev and ~/ref
|
||||||
- ~/dev becomes a link to ~/ref/cat/mine
|
- ~/dev becomes a link to ~/ref/cat/mine
|
||||||
- fold hosts/common/home/ssh.nix -> hosts/common/users/colin.nix
|
- fold hosts/common/home/ssh.nix -> hosts/common/users/colin.nix
|
||||||
|
- don't hardcode IP addresses so much in servo
|
||||||
|
|
||||||
### sops/secrets
|
### sops/secrets
|
||||||
- rework secrets to leverage `sane.fs`
|
- rework secrets to leverage `sane.fs`
|
||||||
@@ -48,51 +61,41 @@
|
|||||||
|
|
||||||
#### upstreaming to non-nixpkgs repos
|
#### upstreaming to non-nixpkgs repos
|
||||||
- gtk: build schemas even on cross compilation: <https://github.com/NixOS/nixpkgs/pull/247844>
|
- gtk: build schemas even on cross compilation: <https://github.com/NixOS/nixpkgs/pull/247844>
|
||||||
|
- gnome-calls retry net connection when DNS is down
|
||||||
|
|
||||||
|
|
||||||
## IMPROVEMENTS:
|
## IMPROVEMENTS:
|
||||||
- systemd/journalctl: use a less shit pager
|
|
||||||
- there's an env var for it: SYSTEMD_PAGER? and a flag for journalctl
|
|
||||||
- kernels: ship the same kernel on every machine
|
|
||||||
- then i can tune the kernels for hardening, without duplicating that work 4 times
|
|
||||||
- zfs: replace this with something which doesn't require a custom kernel build
|
- zfs: replace this with something which doesn't require a custom kernel build
|
||||||
- mpv: add media looping controls (e.g. loop song, loop playlist)
|
- mpv: add media looping controls (e.g. loop song, loop playlist)
|
||||||
|
- curlftpfs: replace with something better
|
||||||
|
- safer (rust? actively maintained? sandboxable?)
|
||||||
|
- handles spaces/symbols in filenames
|
||||||
|
- has better multi-stream perf (e.g. `sane-sync-music` should be able to copy N items in parallel)
|
||||||
|
- firefox: open *all* links (http, https, ...) with system handler
|
||||||
|
- removes the need for open-in-mpv, firefox-xdg-open, etc.
|
||||||
|
- matrix room links *just work*.
|
||||||
|
- `network.protocol-handler.external.https = true` in about:config *seems* to do this,
|
||||||
|
but breaks some webpages (e.g. Pleroma)
|
||||||
|
|
||||||
### security/resilience
|
### security/resilience
|
||||||
- validate duplicity backups!
|
- enable `snapper` btrfs snapshots (`services.snapper`)
|
||||||
- encrypt more ~ dirs (~/archives, ~/records, ..?)
|
|
||||||
- best to do this after i know for sure i have good backups
|
|
||||||
- /mnt/desko/home, etc, shouldn't include secrets (~/private)
|
- /mnt/desko/home, etc, shouldn't include secrets (~/private)
|
||||||
- 95% of its use is for remote media access and stuff which isn't in VCS (~/records)
|
- 95% of its use is for remote media access and stuff which isn't in VCS (~/records)
|
||||||
- port all sane.programs to be sandboxed
|
- port all sane.programs to be sandboxed
|
||||||
|
- sandbox `nix`
|
||||||
- enforce that all `environment.packages` has a sandbox profile (or explicitly opts out)
|
- enforce that all `environment.packages` has a sandbox profile (or explicitly opts out)
|
||||||
- revisit "non-sandboxable" apps and check that i'm not actually just missing mountpoints
|
|
||||||
- LL_FS_RW=/ isn't enough -- need all mount points like `=/:/proc:/sys:...`.
|
|
||||||
- ensure non-bin package outputs are linked for sandboxed apps
|
|
||||||
- i.e. `outputs.man`, `outputs.debug`, `outputs.doc`, ...
|
|
||||||
- lock down dbus calls within the sandbox
|
- lock down dbus calls within the sandbox
|
||||||
- otherwise anyone can `systemd-run --user ...` to potentially escape a sandbox
|
- otherwise anyone can `systemd-run --user ...` to potentially escape a sandbox
|
||||||
- <https://github.com/flatpak/xdg-dbus-proxy>
|
- <https://github.com/flatpak/xdg-dbus-proxy>
|
||||||
- remove `.ssh` access from Firefox!
|
|
||||||
- limit access to `~/knowledge/secrets` through an agent that requires GUI approval, so a firefox exploit can't steal all my logins
|
|
||||||
- port sanebox to a compiled language (hare?)
|
|
||||||
- it adds like 50-70ms launch time _on my laptop_. i'd hate to know how much that is on the pinephone.
|
|
||||||
- make dconf stuff less monolithic
|
- make dconf stuff less monolithic
|
||||||
- i.e. per-app dconf profiles for those which need it. possible static config.
|
- i.e. per-app dconf profiles for those which need it. possible static config.
|
||||||
- flatpak/spectrum has some stuff to proxy dconf per-app
|
- flatpak/spectrum has some stuff to proxy dconf per-app
|
||||||
- canaries for important services
|
|
||||||
- e.g. daily email checks; daily backup checks
|
|
||||||
- integrate `nix check` into Gitea actions?
|
|
||||||
|
|
||||||
### user experience
|
### user experience
|
||||||
- rofi: sort items case-insensitively
|
- rofi: sort items case-insensitively
|
||||||
- xdg-desktop-portal shouldn't kill children on exit
|
|
||||||
- *maybe* a job for `setsid -f`?
|
|
||||||
- replace starship prompt with something more efficient
|
- replace starship prompt with something more efficient
|
||||||
- watch `forkstat`: it does way too much
|
- watch `forkstat`: it does way too much
|
||||||
- cleanup waybar/nwg-panel so that it's not invoking playerctl every 2 seconds
|
- cleanup waybar/nwg-panel so that it's not invoking playerctl every 2 seconds
|
||||||
- nwg-panel: swaync icon is stuck as the refresh icon
|
|
||||||
- nwg-panel: doesn't appear on all desktops
|
|
||||||
- nwg-panel: doesn't know that virtual-desktop 10/TV exists
|
- nwg-panel: doesn't know that virtual-desktop 10/TV exists
|
||||||
- install apps:
|
- install apps:
|
||||||
- display QR codes for WiFi endpoints: <https://linuxphoneapps.org/apps/noappid.wisperwind.wifi2qr/>
|
- display QR codes for WiFi endpoints: <https://linuxphoneapps.org/apps/noappid.wisperwind.wifi2qr/>
|
||||||
@@ -101,7 +104,7 @@
|
|||||||
- offline docs viewer (gtk): <https://github.com/workbenchdev/Biblioteca>
|
- offline docs viewer (gtk): <https://github.com/workbenchdev/Biblioteca>
|
||||||
- some type of games manager/launcher
|
- some type of games manager/launcher
|
||||||
- Gnome Highscore (retro games)?: <https://gitlab.gnome.org/World/highscore>
|
- Gnome Highscore (retro games)?: <https://gitlab.gnome.org/World/highscore>
|
||||||
- better maps for mobile (Osmin (QtQuick)? Pure Maps (Qt/Kirigami)?
|
- better maps for mobile (Osmin (QtQuick)? Pure Maps (Qt/Kirigami)?)
|
||||||
- note-taking app: <https://linuxphoneapps.org/categories/note-taking/>
|
- note-taking app: <https://linuxphoneapps.org/categories/note-taking/>
|
||||||
- Folio is nice, uses standard markdown, though it only supports flat repos
|
- Folio is nice, uses standard markdown, though it only supports flat repos
|
||||||
- OSK overlay specifically for mobile gaming
|
- OSK overlay specifically for mobile gaming
|
||||||
@@ -119,29 +122,28 @@
|
|||||||
|
|
||||||
#### moby
|
#### moby
|
||||||
- fix cpuidle (gets better power consumption): <https://xnux.eu/log/077.html>
|
- fix cpuidle (gets better power consumption): <https://xnux.eu/log/077.html>
|
||||||
|
- fix cpupower for better power/perf
|
||||||
|
- `journalctl -u cpupower --boot` (problem is present on lappy, at least)
|
||||||
- moby: tune keyboard layout
|
- moby: tune keyboard layout
|
||||||
- SwayNC:
|
- SwayNC: add option to change audio output
|
||||||
- don't show MPRIS if no players detected
|
|
||||||
- this is a problem of playerctld, i guess
|
|
||||||
- add option to change audio output
|
|
||||||
- fix colors (red alert) to match overall theme
|
|
||||||
- moby: tune GPS
|
- moby: tune GPS
|
||||||
- run only geoclue, and not gpsd, to save power?
|
- fix iio-sensor-proxy magnetometer scaling
|
||||||
- tune QGPS setting in eg25-control, for less jitter?
|
- tune QGPS setting in eg25-control, for less jitter?
|
||||||
- direct mepo to prefer gpsd, with fallback to geoclue, for better accuracy?
|
|
||||||
- configure geoclue to do some smoothing?
|
- configure geoclue to do some smoothing?
|
||||||
- manually do smoothing, as some layer between mepo and geoclue/gpsd?
|
- manually do smoothing, as some layer between mepo and geoclue?
|
||||||
|
- email wigle.net people to unlock API access
|
||||||
- moby: port `freshen-agps` timer service to s6 (maybe i want some `s6-cron` or something)
|
- moby: port `freshen-agps` timer service to s6 (maybe i want some `s6-cron` or something)
|
||||||
- moby: show battery state on ssh login
|
|
||||||
- moby: improve gPodder launch time
|
- moby: improve gPodder launch time
|
||||||
- moby: theme GTK apps (i.e. non-adwaita styles)
|
- moby: theme GTK apps (i.e. non-adwaita styles)
|
||||||
- especially, make the menubar collapsible
|
- especially, make the menubar collapsible
|
||||||
- try Gradience tool specifically for theming adwaita? <https://linuxphoneapps.org/apps/com.github.gradienceteam.gradience/>
|
- try Gradience tool specifically for theming adwaita? <https://linuxphoneapps.org/apps/com.github.gradienceteam.gradience/>
|
||||||
|
- moby: remove my use of modem-power, since it won't be mainlined (maybe eg25-manager does what i need?)
|
||||||
|
|
||||||
#### non-moby
|
#### non-moby
|
||||||
- RSS: integrate a paywall bypass
|
- RSS: integrate a paywall bypass
|
||||||
- e.g. self-hosted [ladder](https://github.com/everywall/ladder) (like 12ft.io)
|
- e.g. self-hosted [ladder](https://github.com/everywall/ladder) (like 12ft.io)
|
||||||
- neovim: set up language server (lsp; rnix-lsp; nvim-lspconfig)
|
- RSS: have podcasts get downloaded straight into ~/Videos/...
|
||||||
|
- and strip the ads out using Whisper transcription + asking a LLM where the ad breaks are
|
||||||
- neovim: integrate LLMs
|
- neovim: integrate LLMs
|
||||||
- Helix: make copy-to-system clipboard be the default
|
- Helix: make copy-to-system clipboard be the default
|
||||||
- firefox/librewolf: persist history
|
- firefox/librewolf: persist history
|
||||||
@@ -153,17 +155,15 @@
|
|||||||
- have xdg-open parse `<repo:...> URIs (or adjust them so that it _can_ parse)
|
- have xdg-open parse `<repo:...> URIs (or adjust them so that it _can_ parse)
|
||||||
- sane-bt-search: show details like 5.1 vs stereo, h264 vs h265
|
- sane-bt-search: show details like 5.1 vs stereo, h264 vs h265
|
||||||
- maybe just color these "keywords" in all search results?
|
- maybe just color these "keywords" in all search results?
|
||||||
|
- transmission: apply `sane-tag-media` path fix in `torrent-done` script
|
||||||
|
- many .mkv files do appear to be tagged: i'd just need to add support in my own tooling
|
||||||
- uninsane.org: make URLs relative to allow local use (and as offline homepage)
|
- uninsane.org: make URLs relative to allow local use (and as offline homepage)
|
||||||
- email: fix so that local mail doesn't go to junk
|
- email: fix so that local mail doesn't go to junk
|
||||||
- git sendmail flow adds the DKIM signatures, but gets delivered locally w/o having the sig checked, so goes into Junk
|
- git sendmail flow adds the DKIM signatures, but gets delivered locally w/o having the sig checked, so goes into Junk
|
||||||
- could change junk filter from "no DKIM success" to explicit "DKIM failed"
|
- could change junk filter from "no DKIM success" to explicit "DKIM failed"
|
||||||
|
- add an auto-reply address (e.g. `reply-test@uninsane.org`) which reflects all incoming mail; use this (or a friend running this) for liveness checks
|
||||||
|
|
||||||
### perf
|
### perf
|
||||||
- debug nixos-rebuild times
|
|
||||||
- use `systemctl list-jobs` to show what's being waited on
|
|
||||||
- i think it's `systemd-networkd-wait-online.service` that's blocking this?
|
|
||||||
- i wonder what interface it's waiting for. i should use `--ignore=...` to ignore interfaces i don't care about.
|
|
||||||
- also `wireguard-wg-home.target` when net is offline
|
|
||||||
- add `pkgs.impure-cached.<foo>` package set to build things with ccache enabled
|
- add `pkgs.impure-cached.<foo>` package set to build things with ccache enabled
|
||||||
- every package here can be auto-generated, and marked with some env var so that it doesn't pollute the pure package set
|
- every package here can be auto-generated, and marked with some env var so that it doesn't pollute the pure package set
|
||||||
- would be super handy for package prototyping!
|
- would be super handy for package prototyping!
|
||||||
|
70
default.nix
70
default.nix
@@ -1,67 +1,5 @@
|
|||||||
# limited, non-flake interface to this repo.
|
{ ... }@args:
|
||||||
# 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`
|
|
||||||
{ }:
|
|
||||||
let
|
let
|
||||||
mkPkgs = args: (import ./pkgs/additional/nixpkgs args).extend
|
sane-nix-files = import ./pkgs/additional/sane-nix-files { };
|
||||||
(import ./overlays/all.nix);
|
in
|
||||||
inherit (mkPkgs {}) lib;
|
import "${sane-nix-files}/impure.nix" args
|
||||||
|
|
||||||
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 {})
|
|
||||||
|
@@ -16,7 +16,7 @@
|
|||||||
sane.programs.calls.enableFor.user.colin = false;
|
sane.programs.calls.enableFor.user.colin = false;
|
||||||
sane.programs.consoleMediaUtils.enableFor.user.colin = true;
|
sane.programs.consoleMediaUtils.enableFor.user.colin = true;
|
||||||
sane.programs.epiphany.enableFor.user.colin = true;
|
sane.programs.epiphany.enableFor.user.colin = true;
|
||||||
sane.programs."gnome.geary".enableFor.user.colin = false;
|
sane.programs.geary.enableFor.user.colin = false;
|
||||||
# sane.programs.firefox.enableFor.user.colin = true;
|
# sane.programs.firefox.enableFor.user.colin = true;
|
||||||
sane.programs.portfolio-filemanager.enableFor.user.colin = true;
|
sane.programs.portfolio-filemanager.enableFor.user.colin = true;
|
||||||
sane.programs.signal-desktop.enableFor.user.colin = false;
|
sane.programs.signal-desktop.enableFor.user.colin = false;
|
||||||
@@ -25,20 +25,9 @@
|
|||||||
sane.programs.dino.config.autostart = false;
|
sane.programs.dino.config.autostart = false;
|
||||||
sane.programs.dissent.config.autostart = false;
|
sane.programs.dissent.config.autostart = false;
|
||||||
sane.programs.fractal.config.autostart = false;
|
sane.programs.fractal.config.autostart = false;
|
||||||
|
sane.programs.sway.config.mod = "Mod1"; #< alt key instead of Super
|
||||||
|
|
||||||
# sane.programs.guiApps.enableFor.user.colin = false;
|
# sane.programs.guiApps.enableFor.user.colin = false;
|
||||||
|
|
||||||
# sane.programs.pcGuiApps.enableFor.user.colin = false; #< errors!
|
# sane.programs.pcGuiApps.enableFor.user.colin = false; #< errors!
|
||||||
|
|
||||||
sane.programs.blueberry.enableFor.user.colin = false; # bluetooth manager: doesn't cross compile!
|
|
||||||
# sane.programs.brave.enableFor.user.colin = false; # 2024/06/03: fails eval if enabled on cross
|
|
||||||
# sane.programs.firefox.enableFor.user.colin = false; # 2024/06/03: this triggers an eval error in yarn stuff -- i'm doing IFD somewhere!!?
|
|
||||||
sane.programs.mepo.enableFor.user.colin = false; # 2024/06/04: doesn't cross compile (nodejs)
|
|
||||||
sane.programs.mercurial.enableFor.user.colin = false; # 2024/06/03: does not cross compile
|
|
||||||
sane.programs.nixpkgs-review.enableFor.user.colin = false; # 2024/06/03: OOMs when cross compiling
|
|
||||||
sane.programs.ntfy-sh.enableFor.user.colin = false; # 2024/06/04: doesn't cross compile (nodejs)
|
|
||||||
sane.programs.pwvucontrol.enableFor.user.colin = false; # 2024/06/03: doesn't cross compile (libspa-sys)
|
|
||||||
sane.programs."sane-scripts.bt-search".enableFor.user.colin = false; # 2024/06/03: does not cross compile
|
|
||||||
sane.programs.sequoia.enableFor.user.colin = false; # 2024/06/03: does not cross compile
|
|
||||||
sane.programs.zathura.enableFor.user.colin = false; # 2024/06/03: does not cross compile
|
|
||||||
}
|
}
|
||||||
|
@@ -1,18 +1,22 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
{ config, pkgs, ... }:
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
./fs.nix
|
./fs.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
sane.services.trust-dns.asSystemResolver = false; # TEMPORARY: TODO: re-enable trust-dns
|
sane.services.hickory-dns.asSystemResolver = false; # TEMPORARY: TODO: re-enable hickory-dns
|
||||||
# sane.programs.devPkgs.enableFor.user.colin = true;
|
# sane.programs.devPkgs.enableFor.user.colin = true;
|
||||||
# sane.guest.enable = true;
|
# sane.guest.enable = true;
|
||||||
|
|
||||||
# don't enable wifi by default: it messes with connectivity.
|
# don't enable wifi by default: it messes with connectivity.
|
||||||
# systemd.services.iwd.enable = false;
|
# systemd.services.iwd.enable = false;
|
||||||
|
# networking.wireless.enable = false;
|
||||||
# systemd.services.wpa_supplicant.enable = false;
|
# systemd.services.wpa_supplicant.enable = false;
|
||||||
sane.programs.wpa_supplicant.enableFor.user.colin = lib.mkForce false;
|
# sane.programs.wpa_supplicant.enableFor.user.colin = lib.mkForce false;
|
||||||
sane.programs.wpa_supplicant.enableFor.system = lib.mkForce false;
|
# sane.programs.wpa_supplicant.enableFor.system = lib.mkForce false;
|
||||||
|
# don't auto-connect to wifi networks
|
||||||
|
# see: <https://networkmanager.dev/docs/api/latest/NetworkManager.conf.html#device-spec>
|
||||||
|
networking.networkmanager.unmanaged = [ "type:wifi" ];
|
||||||
|
|
||||||
sops.secrets.colin-passwd.neededForUsers = true;
|
sops.secrets.colin-passwd.neededForUsers = true;
|
||||||
|
|
||||||
@@ -24,36 +28,41 @@
|
|||||||
sane.services.wg-home.ip = config.sane.hosts.by-name."desko".wg-home.ip;
|
sane.services.wg-home.ip = config.sane.hosts.by-name."desko".wg-home.ip;
|
||||||
sane.ovpn.addrV4 = "172.26.55.21";
|
sane.ovpn.addrV4 = "172.26.55.21";
|
||||||
# sane.ovpn.addrV6 = "fd00:0000:1337:cafe:1111:1111:20c1:a73c";
|
# sane.ovpn.addrV6 = "fd00:0000:1337:cafe:1111:1111:20c1:a73c";
|
||||||
sane.services.duplicity.enable = true;
|
sane.services.rsync-net.enable = true;
|
||||||
|
|
||||||
sane.nixcache.remote-builders.desko = false;
|
sane.nixcache.remote-builders.desko = false;
|
||||||
|
|
||||||
|
sane.programs.sane-private-unlock-remote.enableFor.user.colin = true;
|
||||||
|
sane.programs.sane-private-unlock-remote.config.hosts = [ "servo" ];
|
||||||
|
|
||||||
sane.programs.sway.enableFor.user.colin = true;
|
sane.programs.sway.enableFor.user.colin = true;
|
||||||
sane.programs.iphoneUtils.enableFor.user.colin = true;
|
sane.programs.iphoneUtils.enableFor.user.colin = true;
|
||||||
sane.programs.steam.enableFor.user.colin = true;
|
sane.programs.steam.enableFor.user.colin = true;
|
||||||
|
|
||||||
sane.programs."gnome.geary".config.autostart = true;
|
|
||||||
sane.programs.signal-desktop.config.autostart = true;
|
|
||||||
|
|
||||||
sane.programs.nwg-panel.config = {
|
sane.programs.nwg-panel.config = {
|
||||||
battery = false;
|
battery = false;
|
||||||
brightness = false;
|
brightness = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
sane.programs.mpv.config.defaultProfile = "high-quality";
|
||||||
|
|
||||||
sane.image.extraBootFiles = [ pkgs.bootpart-uefi-x86_64 ];
|
sane.image.extraBootFiles = [ pkgs.bootpart-uefi-x86_64 ];
|
||||||
|
|
||||||
# needed to use libimobiledevice/ifuse, for iphone sync
|
# needed to use libimobiledevice/ifuse, for iphone sync
|
||||||
services.usbmuxd.enable = true;
|
services.usbmuxd.enable = true;
|
||||||
|
|
||||||
|
# TODO: enable snapper (need to make `/nix` or `/nix/persist` a subvolume, somehow).
|
||||||
# default config: https://man.archlinux.org/man/snapper-configs.5
|
# default config: https://man.archlinux.org/man/snapper-configs.5
|
||||||
# defaults to something like:
|
# defaults to something like:
|
||||||
# - hourly snapshots
|
# - hourly snapshots
|
||||||
# - auto cleanup; keep the last 10 hourlies, last 10 daylies, last 10 monthlys.
|
# - auto cleanup; keep the last 10 hourlies, last 10 daylies, last 10 monthlys.
|
||||||
services.snapper.configs.nix = {
|
# to list snapshots: `sudo snapper --config nix list`
|
||||||
# TODO: for the impermanent setup, we'd prefer to just do /nix/persist,
|
# to take a snapshot: `sudo snapper --config nix create`
|
||||||
# but that also requires setting up the persist dir as a subvol
|
# services.snapper.configs.nix = {
|
||||||
SUBVOLUME = "/nix";
|
# # TODO: for the impermanent setup, we'd prefer to just do /nix/persist,
|
||||||
# TODO: ALLOW_USERS doesn't seem to work. still need `sudo snapper -c nix list`
|
# # but that also requires setting up the persist dir as a subvol
|
||||||
ALLOW_USERS = [ "colin" ];
|
# SUBVOLUME = "/nix";
|
||||||
};
|
# # TODO: ALLOW_USERS doesn't seem to work. still need `sudo snapper -c nix list`
|
||||||
|
# ALLOW_USERS = [ "colin" ];
|
||||||
|
# };
|
||||||
}
|
}
|
||||||
|
@@ -15,22 +15,28 @@
|
|||||||
# sane.guest.enable = true;
|
# sane.guest.enable = true;
|
||||||
sane.image.extraBootFiles = [ pkgs.bootpart-uefi-x86_64 ];
|
sane.image.extraBootFiles = [ pkgs.bootpart-uefi-x86_64 ];
|
||||||
|
|
||||||
|
sane.programs.sane-private-unlock-remote.enableFor.user.colin = true;
|
||||||
|
sane.programs.sane-private-unlock-remote.config.hosts = [ "servo" ];
|
||||||
|
|
||||||
sane.programs.stepmania.enableFor.user.colin = true;
|
sane.programs.stepmania.enableFor.user.colin = true;
|
||||||
sane.programs.sway.enableFor.user.colin = true;
|
sane.programs.sway.enableFor.user.colin = true;
|
||||||
|
|
||||||
sane.programs."gnome.geary".config.autostart = true;
|
|
||||||
sane.programs.signal-desktop.config.autostart = true;
|
|
||||||
|
|
||||||
sops.secrets.colin-passwd.neededForUsers = true;
|
sops.secrets.colin-passwd.neededForUsers = true;
|
||||||
|
|
||||||
|
sane.services.rsync-net.enable = true;
|
||||||
|
|
||||||
|
# TODO: enable snapper (need to make `/nix` or `/nix/persist` a subvolume, somehow).
|
||||||
# default config: https://man.archlinux.org/man/snapper-configs.5
|
# default config: https://man.archlinux.org/man/snapper-configs.5
|
||||||
# defaults to something like:
|
# defaults to something like:
|
||||||
# - hourly snapshots
|
# - hourly snapshots
|
||||||
# - auto cleanup; keep the last 10 hourlies, last 10 daylies, last 10 monthlys.
|
# - auto cleanup; keep the last 10 hourlies, last 10 daylies, last 10 monthlys.
|
||||||
services.snapper.configs.nix = {
|
# to list snapshots: `sudo snapper --config nix list`
|
||||||
# TODO: for the impermanent setup, we'd prefer to just do /nix/persist,
|
# to take a snapshot: `sudo snapper --config nix create`
|
||||||
# but that also requires setting up the persist dir as a subvol
|
# services.snapper.configs.nix = {
|
||||||
SUBVOLUME = "/nix";
|
# # TODO: for the impermanent setup, we'd prefer to just do /nix/persist,
|
||||||
ALLOW_USERS = [ "colin" ];
|
# # but that also requires setting up the persist dir as a subvol
|
||||||
};
|
# SUBVOLUME = "/nix";
|
||||||
|
# # TODO: ALLOW_USERS doesn't seem to work. still need `sudo snapper -c nix list`
|
||||||
|
# ALLOW_USERS = [ "colin" ];
|
||||||
|
# };
|
||||||
}
|
}
|
||||||
|
@@ -6,11 +6,10 @@
|
|||||||
# - Mobian wiki: <https://wiki.mobian-project.org/doku.php?id=start>
|
# - Mobian wiki: <https://wiki.mobian-project.org/doku.php?id=start>
|
||||||
# - recommended apps, chatrooms
|
# - recommended apps, chatrooms
|
||||||
|
|
||||||
{ config, pkgs, lib, ... }:
|
{ config, ... }:
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
./fs.nix
|
./fs.nix
|
||||||
./gps.nix
|
|
||||||
];
|
];
|
||||||
|
|
||||||
sane.hal.pine64.enable = true;
|
sane.hal.pine64.enable = true;
|
||||||
@@ -24,25 +23,24 @@
|
|||||||
# XXX colin: phosh doesn't work well with passwordless login,
|
# XXX colin: phosh doesn't work well with passwordless login,
|
||||||
# so set this more reliable default password should anything go wrong
|
# so set this more reliable default password should anything go wrong
|
||||||
users.users.colin.initialPassword = "147147";
|
users.users.colin.initialPassword = "147147";
|
||||||
# services.getty.autologinUser = "root"; # allows for emergency maintenance?
|
|
||||||
|
|
||||||
sops.secrets.colin-passwd.neededForUsers = true;
|
sops.secrets.colin-passwd.neededForUsers = true;
|
||||||
|
|
||||||
|
sane.services.rsync-net.enable = true;
|
||||||
|
|
||||||
sane.programs.sway.enableFor.user.colin = true;
|
sane.programs.sway.enableFor.user.colin = true;
|
||||||
sane.programs.blueberry.enableFor.user.colin = false; # bluetooth manager: doesn't cross compile!
|
sane.programs.sway.config.mod = "Mod1"; #< alt key instead of Super
|
||||||
sane.programs.fcitx5.enableFor.user.colin = false; # does not cross compile
|
|
||||||
sane.programs.mercurial.enableFor.user.colin = false; # does not cross compile
|
|
||||||
sane.programs.nvme-cli.enableFor.system = false; # does not cross compile (libhugetlbfs)
|
|
||||||
|
|
||||||
# enabled for easier debugging
|
# enabled for easier debugging
|
||||||
sane.programs.eg25-control.enableFor.user.colin = true;
|
sane.programs.eg25-control.enableFor.user.colin = true;
|
||||||
sane.programs.rtl8723cs-wowlan.enableFor.user.colin = true;
|
# sane.programs.rtl8723cs-wowlan.enableFor.user.colin = true;
|
||||||
|
|
||||||
|
sane.programs.eg25-manager.enableFor.user.colin = true;
|
||||||
|
|
||||||
# sane.programs.ntfy-sh.config.autostart = true;
|
# sane.programs.ntfy-sh.config.autostart = true;
|
||||||
sane.programs.dino.config.autostart = true;
|
sane.programs.dino.config.autostart = true;
|
||||||
# sane.programs.signal-desktop.config.autostart = true; # TODO: enable once electron stops derping.
|
sane.programs.signal-desktop.config.autostart = false;
|
||||||
# sane.programs."gnome.geary".config.autostart = true;
|
sane.programs.geary.config.autostart = false;
|
||||||
# sane.programs.calls.config.autostart = true;
|
|
||||||
|
|
||||||
sane.programs.pipewire.config = {
|
sane.programs.pipewire.config = {
|
||||||
# tune so Dino doesn't drop audio
|
# tune so Dino doesn't drop audio
|
||||||
@@ -60,6 +58,8 @@
|
|||||||
max-quantum = 8192;
|
max-quantum = 8192;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
sane.programs.mpv.config.defaultProfile = "fast";
|
||||||
|
|
||||||
# /boot space is at a premium. default was 20.
|
# /boot space is at a premium. default was 20.
|
||||||
# even 10 can be too much
|
# even 10 can be too much
|
||||||
boot.loader.generic-extlinux-compatible.configurationLimit = 8;
|
boot.loader.generic-extlinux-compatible.configurationLimit = 8;
|
||||||
|
@@ -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;
|
|
||||||
}
|
|
@@ -7,22 +7,21 @@
|
|||||||
./services
|
./services
|
||||||
];
|
];
|
||||||
|
|
||||||
sane.programs = {
|
|
||||||
# for administering services
|
# for administering services
|
||||||
freshrss.enableFor.user.colin = true;
|
sane.programs.clightning-sane.enableFor.user.colin = true;
|
||||||
matrix-synapse.enableFor.user.colin = true;
|
# sane.programs.freshrss.enableFor.user.colin = true;
|
||||||
signaldctl.enableFor.user.colin = true;
|
# sane.programs.signaldctl.enableFor.user.colin = true;
|
||||||
};
|
# sane.programs.matrix-synapse.enableFor.user.colin = true;
|
||||||
|
|
||||||
sane.roles.build-machine.enable = true;
|
sane.roles.build-machine.enable = true;
|
||||||
sane.programs.zsh.config.showDeadlines = false; # ~/knowledge doesn't always exist
|
sane.programs.sane-deadlines.config.showOnLogin = false; # ~/knowledge doesn't always exist
|
||||||
sane.programs.consoleUtils.suggestedPrograms = [
|
sane.programs.consoleUtils.suggestedPrograms = [
|
||||||
"consoleMediaUtils" # notably, for go2tv / casting
|
"consoleMediaUtils" # notably, for go2tv / casting
|
||||||
"pcConsoleUtils"
|
"pcConsoleUtils"
|
||||||
"sane-scripts.stop-all-servo"
|
"sane-scripts.stop-all-servo"
|
||||||
];
|
];
|
||||||
sane.services.dyn-dns.enable = true;
|
sane.services.dyn-dns.enable = true;
|
||||||
sane.services.trust-dns.asSystemResolver = false; # TODO: enable once it's all working well
|
sane.services.hickory-dns.asSystemResolver = false; # TODO: enable once it's all working well
|
||||||
sane.services.wg-home.enable = true;
|
sane.services.wg-home.enable = true;
|
||||||
sane.services.wg-home.visibleToWan = true;
|
sane.services.wg-home.visibleToWan = true;
|
||||||
sane.services.wg-home.forwardToWan = true;
|
sane.services.wg-home.forwardToWan = true;
|
||||||
@@ -32,11 +31,12 @@
|
|||||||
# sane.ovpn.addrV6 = "fd00:0000:1337:cafe:1111:1111:8df3:14b0";
|
# sane.ovpn.addrV6 = "fd00:0000:1337:cafe:1111:1111:8df3:14b0";
|
||||||
sane.nixcache.remote-builders.desko = false;
|
sane.nixcache.remote-builders.desko = false;
|
||||||
sane.nixcache.remote-builders.servo = false;
|
sane.nixcache.remote-builders.servo = false;
|
||||||
# sane.services.duplicity.enable = true; # TODO: re-enable after HW upgrade
|
sane.services.rsync-net.enable = true;
|
||||||
|
|
||||||
# automatically log in at the virtual consoles.
|
# automatically log in at the virtual consoles.
|
||||||
# using root here makes sure we always have an escape hatch
|
# using root here makes sure we always have an escape hatch.
|
||||||
services.getty.autologinUser = "root";
|
# XXX(2024-07-27): this is incompatible with my s6-rc stuff, which needs to auto-login as `colin` to start its user services.
|
||||||
|
# services.getty.autologinUser = "root";
|
||||||
|
|
||||||
sane.image.extraBootFiles = [ pkgs.bootpart-uefi-x86_64 ];
|
sane.image.extraBootFiles = [ pkgs.bootpart-uefi-x86_64 ];
|
||||||
|
|
||||||
|
@@ -14,7 +14,7 @@
|
|||||||
# show zfs datasets: `zfs list` (will be empty if haven't imported)
|
# show zfs datasets: `zfs list` (will be empty if haven't imported)
|
||||||
# show zfs properties (e.g. compression): `zfs get all pool`
|
# show zfs properties (e.g. compression): `zfs get all pool`
|
||||||
# set zfs properties: `zfs set compression=on pool`
|
# set zfs properties: `zfs set compression=on pool`
|
||||||
{ ... }:
|
{ lib, pkgs, ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
# hostId: not used for anything except zfs guardrail?
|
# hostId: not used for anything except zfs guardrail?
|
||||||
@@ -54,7 +54,7 @@
|
|||||||
options = [ "acl" ]; #< not sure if this `acl` flag is actually necessary. it mounts without it.
|
options = [ "acl" ]; #< not sure if this `acl` flag is actually necessary. it mounts without it.
|
||||||
};
|
};
|
||||||
# services.zfs.zed = ... # TODO: zfs can send me emails when disks fail
|
# services.zfs.zed = ... # TODO: zfs can send me emails when disks fail
|
||||||
sane.programs.sysadminUtils.suggestedPrograms = [ "zfs" ];
|
sane.programs.sysadminUtils.suggestedPrograms = [ "zfs-tools" ];
|
||||||
|
|
||||||
sane.persist.stores."ext" = {
|
sane.persist.stores."ext" = {
|
||||||
origin = "/mnt/pool/persist";
|
origin = "/mnt/pool/persist";
|
||||||
@@ -131,6 +131,20 @@
|
|||||||
the contents should be a subset of what's in ../media/datasets.
|
the contents should be a subset of what's in ../media/datasets.
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
systemd.services.dedupe-media = {
|
||||||
|
description = "transparently de-duplicate /var/media entries by using block-level hardlinks";
|
||||||
|
script = ''
|
||||||
|
${lib.getExe' pkgs.util-linux "hardlink"} /var/media --reflink=always --ignore-time --verbose
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
systemd.timers.dedupe-media = {
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
timerConfig = {
|
||||||
|
OnStartupSec = "23min";
|
||||||
|
OnUnitActiveSec = "720min";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
# btrfs doesn't easily support swapfiles
|
# btrfs doesn't easily support swapfiles
|
||||||
# swapDevices = [
|
# swapDevices = [
|
||||||
# { device = "/nix/persist/swapfile"; size = 4096; }
|
# { device = "/nix/persist/swapfile"; size = 4096; }
|
||||||
|
@@ -30,6 +30,14 @@ in
|
|||||||
|
|
||||||
config = {
|
config = {
|
||||||
networking.domain = "uninsane.org";
|
networking.domain = "uninsane.org";
|
||||||
|
systemd.network.networks."50-eth0" = {
|
||||||
|
matchConfig.Name = "eth0";
|
||||||
|
networkConfig.Address = [
|
||||||
|
"205.201.63.12/32"
|
||||||
|
"10.78.79.51/22"
|
||||||
|
];
|
||||||
|
networkConfig.DNS = [ "10.78.79.1" ];
|
||||||
|
};
|
||||||
|
|
||||||
sane.ports.openFirewall = true;
|
sane.ports.openFirewall = true;
|
||||||
sane.ports.openUpnp = true;
|
sane.ports.openUpnp = true;
|
||||||
|
@@ -1,34 +0,0 @@
|
|||||||
{ config, lib, ... }:
|
|
||||||
|
|
||||||
let
|
|
||||||
cweb-cfg = config.services.calibre-web;
|
|
||||||
inherit (cweb-cfg) user group;
|
|
||||||
inherit (cweb-cfg.listen) ip port;
|
|
||||||
svc-dir = "/var/lib/${cweb-cfg.dataDir}";
|
|
||||||
in
|
|
||||||
# XXX: disabled because of runtime errors like:
|
|
||||||
# > File "/nix/store/c7jqvx980nlg9xhxi065cba61r2ain9y-calibre-web-0.6.19/lib/python3.10/site-packages/calibreweb/cps/db.py", line 926, in speaking_language
|
|
||||||
# > languages = self.session.query(Languages) \
|
|
||||||
# > AttributeError: 'NoneType' object has no attribute 'query'
|
|
||||||
lib.mkIf false
|
|
||||||
{
|
|
||||||
sane.persist.sys.byStore.plaintext = [
|
|
||||||
{ inherit user group; mode = "0700"; path = svc-dir; method = "bind"; }
|
|
||||||
];
|
|
||||||
|
|
||||||
services.calibre-web.enable = true;
|
|
||||||
services.calibre-web.listen.ip = "127.0.0.1";
|
|
||||||
# XXX: externally populate `${svc-dir}/metadata.db` (once) from
|
|
||||||
# <https://github.com/janeczku/calibre-web/blob/master/library/metadata.db>
|
|
||||||
# i don't know why you have to do this??
|
|
||||||
# services.calibre-web.options.calibreLibrary = svc-dir;
|
|
||||||
|
|
||||||
services.nginx.virtualHosts."calibre.uninsane.org" = {
|
|
||||||
forceSSL = true;
|
|
||||||
enableACME = true;
|
|
||||||
locations."/" = {
|
|
||||||
proxyPass = "http://${ip}:${builtins.toString port}";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
sane.dns.zones."uninsane.org".inet.CNAME."calibre" = "native";
|
|
||||||
}
|
|
@@ -36,7 +36,8 @@
|
|||||||
# - rb = received bytes
|
# - rb = received bytes
|
||||||
# - sp = sent packets
|
# - sp = sent packets
|
||||||
# - sb = sent bytes
|
# - sb = sent bytes
|
||||||
{ lib, ... }:
|
|
||||||
|
{ config, lib, ... }:
|
||||||
let
|
let
|
||||||
# TURN port range (inclusive).
|
# TURN port range (inclusive).
|
||||||
# default coturn behavior is to use the upper quarter of all ports. i.e. 49152 - 65535.
|
# default coturn behavior is to use the upper quarter of all ports. i.e. 49152 - 65535.
|
||||||
@@ -130,11 +131,11 @@ in
|
|||||||
"verbose"
|
"verbose"
|
||||||
# "Verbose" #< even MORE verbosity than "verbose" (it's TOO MUCH verbosity really)
|
# "Verbose" #< even MORE verbosity than "verbose" (it's TOO MUCH verbosity really)
|
||||||
"no-multicast-peers" # disables sending to IPv4 broadcast addresses (e.g. 224.0.0.0/3)
|
"no-multicast-peers" # disables sending to IPv4 broadcast addresses (e.g. 224.0.0.0/3)
|
||||||
# "listening-ip=10.0.1.5" "external-ip=185.157.162.178" #< 2024/04/25: works, if running in root namespace
|
# "listening-ip=${config.sane.netns.ovpns.hostVethIpv4}" "external-ip=${config.sane.netns.ovpns.netnsPubIpv4}" #< 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.netnsPubIpv4}" "external-ip=${config.sane.netns.ovpns.netnsPubIpv4}"
|
||||||
|
|
||||||
# old attempts:
|
# 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 *
|
# "listening-ip=10.78.79.51" # can be specified multiple times; omit for *
|
||||||
# "external-ip=97.113.128.229/10.78.79.51"
|
# "external-ip=97.113.128.229/10.78.79.51"
|
||||||
# "external-ip=97.113.128.229"
|
# "external-ip=97.113.128.229"
|
||||||
|
@@ -16,14 +16,17 @@
|
|||||||
# - validate with `bitcoin-cli -netinfo`
|
# - validate with `bitcoin-cli -netinfo`
|
||||||
{ config, lib, pkgs, sane-lib, ... }:
|
{ config, lib, pkgs, sane-lib, ... }:
|
||||||
let
|
let
|
||||||
|
# bitcoind = config.sane.programs.bitcoind.packageUnwrapped;
|
||||||
|
bitcoind = pkgs.bitcoind;
|
||||||
# wrapper to run bitcoind with the tor onion address as externalip (computed at runtime)
|
# wrapper to run bitcoind with the tor onion address as externalip (computed at runtime)
|
||||||
_bitcoindWithExternalIp = with pkgs; writeShellScriptBin "bitcoind" ''
|
_bitcoindWithExternalIp = pkgs.writeShellScriptBin "bitcoind" ''
|
||||||
|
set -xeu
|
||||||
externalip="$(cat /var/lib/tor/onion/bitcoind/hostname)"
|
externalip="$(cat /var/lib/tor/onion/bitcoind/hostname)"
|
||||||
exec ${bitcoind}/bin/bitcoind "-externalip=$externalip" "$@"
|
exec ${bitcoind}/bin/bitcoind "-externalip=$externalip" "$@"
|
||||||
'';
|
'';
|
||||||
# the package i provide to services.bitcoind ends up on system PATH, and used by other tools like clightning.
|
# the package i provide to services.bitcoind ends up on system PATH, and used by other tools like clightning.
|
||||||
# therefore, even though services.bitcoind only needs `bitcoind` binary, provide all the other bitcoin-related binaries (notably `bitcoin-cli`) as well:
|
# therefore, even though services.bitcoind only needs `bitcoind` binary, provide all the other bitcoin-related binaries (notably `bitcoin-cli`) as well:
|
||||||
bitcoindWithExternalIp = with pkgs; symlinkJoin {
|
bitcoindWithExternalIp = pkgs.symlinkJoin {
|
||||||
name = "bitcoind-with-external-ip";
|
name = "bitcoind-with-external-ip";
|
||||||
paths = [ _bitcoindWithExternalIp bitcoind ];
|
paths = [ _bitcoindWithExternalIp bitcoind ];
|
||||||
};
|
};
|
||||||
@@ -61,23 +64,62 @@ in
|
|||||||
passwordHMAC = "30002c05d82daa210550e17a182db3f3$6071444151281e1aa8a2729f75e3e2d224e9d7cac3974810dab60e7c28ffaae4";
|
passwordHMAC = "30002c05d82daa210550e17a182db3f3$6071444151281e1aa8a2729f75e3e2d224e9d7cac3974810dab60e7c28ffaae4";
|
||||||
};
|
};
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
|
# checkblocks: default 6: how many blocks to verify on start
|
||||||
|
checkblocks=3
|
||||||
# don't load the wallet, and disable wallet RPC calls
|
# don't load the wallet, and disable wallet RPC calls
|
||||||
disablewallet=1
|
disablewallet=1
|
||||||
# proxy all outbound traffic through Tor
|
# proxy all outbound traffic through Tor
|
||||||
proxy=127.0.0.1:9050
|
proxy=127.0.0.1:9050
|
||||||
'';
|
'';
|
||||||
|
extraCmdlineOptions = [
|
||||||
|
# "-debug"
|
||||||
|
# "-debug=estimatefee"
|
||||||
|
# "-debug=http"
|
||||||
|
# "-debug=net"
|
||||||
|
"-debug=proxy"
|
||||||
|
"-debug=rpc"
|
||||||
|
# "-debug=validation"
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
users.users.bitcoind-mainnet.extraGroups = [ "tor" ];
|
users.users.bitcoind-mainnet.extraGroups = [ "tor" ];
|
||||||
|
|
||||||
systemd.services.bitcoind-mainnet.serviceConfig.RestartSec = "30s"; #< default is 0
|
systemd.services.bitcoind-mainnet = {
|
||||||
|
after = [ "tor.service" ];
|
||||||
|
requires = [ "tor.service" ];
|
||||||
|
serviceConfig.RestartSec = "30s"; #< default is 0
|
||||||
|
|
||||||
|
# hardening (systemd-analyze security bitcoind-mainnet)
|
||||||
|
serviceConfig.StateDirectory = "bitcoind-mainnet";
|
||||||
|
serviceConfig.LockPersonality = true;
|
||||||
|
serviceConfig.MemoryDenyWriteExecute = "true";
|
||||||
|
serviceConfig.NoNewPrivileges = "true";
|
||||||
|
serviceConfig.PrivateDevices = "true";
|
||||||
|
serviceConfig.PrivateMounts = true;
|
||||||
|
serviceConfig.PrivateTmp = "true";
|
||||||
|
serviceConfig.PrivateUsers = true;
|
||||||
|
serviceConfig.ProcSubset = "pid";
|
||||||
|
serviceConfig.ProtectControlGroups = true;
|
||||||
|
serviceConfig.ProtectHome = true;
|
||||||
|
serviceConfig.ProtectHostname = true;
|
||||||
|
serviceConfig.ProtectKernelLogs = true;
|
||||||
|
serviceConfig.ProtectKernelModules = true;
|
||||||
|
serviceConfig.ProtectKernelTunables = true;
|
||||||
|
serviceConfig.ProtectProc = "invisible";
|
||||||
|
serviceConfig.ProtectSystem = lib.mkForce "strict";
|
||||||
|
serviceConfig.RemoveIPC = true;
|
||||||
|
serviceConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6";
|
||||||
|
serviceConfig.RestrictNamespaces = true;
|
||||||
|
serviceConfig.RestrictSUIDSGID = true;
|
||||||
|
serviceConfig.SystemCallArchitectures = "native";
|
||||||
|
serviceConfig.SystemCallFilter = [ "@system-service" ];
|
||||||
|
};
|
||||||
|
|
||||||
sane.users.colin.fs.".bitcoin/bitcoin.conf" = sane-lib.fs.wantedSymlinkTo config.sops.secrets."bitcoin.conf".path;
|
|
||||||
sops.secrets."bitcoin.conf" = {
|
sops.secrets."bitcoin.conf" = {
|
||||||
mode = "0600";
|
mode = "0600";
|
||||||
owner = "colin";
|
owner = "colin";
|
||||||
group = "users";
|
group = "users";
|
||||||
};
|
};
|
||||||
|
|
||||||
sane.programs.bitcoind.enableFor.user.colin = true; # for debugging/administration: `bitcoin-cli`
|
sane.programs.bitcoin-cli.enableFor.user.colin = true; # for debugging/administration: `bitcoin-cli`
|
||||||
}
|
}
|
||||||
|
@@ -72,13 +72,11 @@
|
|||||||
|
|
||||||
{ config, pkgs, ... }:
|
{ config, pkgs, ... }:
|
||||||
{
|
{
|
||||||
sane.persist.sys.byStore.ext = [
|
sane.persist.sys.byStore.private = [
|
||||||
|
# clightning takes up only a few MB. but then several hundred MB of crash logs that i should probably GC.
|
||||||
{ user = "clightning"; group = "clightning"; mode = "0710"; path = "/var/lib/clightning"; method = "bind"; }
|
{ user = "clightning"; group = "clightning"; mode = "0710"; path = "/var/lib/clightning"; method = "bind"; }
|
||||||
];
|
];
|
||||||
|
|
||||||
# `lightning-cli` finds its RPC file via `~/.lightning/bitcoin/lightning-rpc`, to message the daemon
|
|
||||||
sane.user.fs.".lightning".symlink.target = "/var/lib/clightning";
|
|
||||||
|
|
||||||
# see bitcoin.nix for how to generate this
|
# see bitcoin.nix for how to generate this
|
||||||
services.bitcoind.mainnet.rpc.users.clightning.passwordHMAC =
|
services.bitcoind.mainnet.rpc.users.clightning.passwordHMAC =
|
||||||
"befcb82d9821049164db5217beb85439$2c31ac7db3124612e43893ae13b9527dbe464ab2d992e814602e7cb07dc28985";
|
"befcb82d9821049164db5217beb85439$2c31ac7db3124612e43893ae13b9527dbe464ab2d992e814602e7cb07dc28985";
|
||||||
@@ -105,6 +103,7 @@
|
|||||||
users.users.clightning.extraGroups = [ "tor" ];
|
users.users.clightning.extraGroups = [ "tor" ];
|
||||||
|
|
||||||
systemd.services.clightning.after = [ "tor.service" ];
|
systemd.services.clightning.after = [ "tor.service" ];
|
||||||
|
systemd.services.clightning.requires = [ "tor.service" ];
|
||||||
|
|
||||||
# lightning-config contains fields from here:
|
# lightning-config contains fields from here:
|
||||||
# - <https://docs.corelightning.org/docs/configuration>
|
# - <https://docs.corelightning.org/docs/configuration>
|
||||||
@@ -116,11 +115,16 @@
|
|||||||
# - fee-per-satoshi=<ppm>
|
# - fee-per-satoshi=<ppm>
|
||||||
# - feature configs (i.e. experimental-xyz options)
|
# - feature configs (i.e. experimental-xyz options)
|
||||||
sane.services.clightning.extraConfig = ''
|
sane.services.clightning.extraConfig = ''
|
||||||
log-level=debug:lightningd
|
# log levels: "io", "debug", "info", "unusual", "broken"
|
||||||
|
log-level=info
|
||||||
|
# log-level=info:lightningd
|
||||||
|
# log-level=debug:lightningd
|
||||||
|
# log-level=debug
|
||||||
|
|
||||||
# peerswap:
|
# peerswap:
|
||||||
# - config example: <https://github.com/fort-nix/nix-bitcoin/pull/462/files#diff-b357d832705b8ce8df1f41934d613f79adb77c4cd5cd9e9eb12a163fca3e16c6>
|
# - config example: <https://github.com/fort-nix/nix-bitcoin/pull/462/files#diff-b357d832705b8ce8df1f41934d613f79adb77c4cd5cd9e9eb12a163fca3e16c6>
|
||||||
# XXX: peerswap crashes clightning on launch. stacktrace is useless.
|
# XXX: peerswap crashes clightning on launch. stacktrace is useless.
|
||||||
# plugin=${pkgs.peerswap}/bin/peerswap
|
# plugin={pkgs.peerswap}/bin/peerswap
|
||||||
# peerswap-db-path=/var/lib/clightning/peerswap/swaps
|
# peerswap-db-path=/var/lib/clightning/peerswap/swaps
|
||||||
# peerswap-policy-path=...
|
# peerswap-policy-path=...
|
||||||
'';
|
'';
|
||||||
@@ -131,5 +135,5 @@
|
|||||||
group = "clightning";
|
group = "clightning";
|
||||||
};
|
};
|
||||||
|
|
||||||
sane.programs.clightning.enableFor.user.colin = true; # for debugging/admin: `lightning-cli`
|
sane.programs.lightning-cli.enableFor.user.colin = true; # for debugging/admin:
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
{ ... }:
|
{ lib, ... }:
|
||||||
|
lib.mkIf false #< 2024/07/27: i don't use it, too much surface-area for me to run it pro-bono (`systemd-analyze security monero`)
|
||||||
{
|
{
|
||||||
services.i2p.enable = true;
|
services.i2p.enable = true;
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
# as of 2023/11/26: complete downloaded blockchain should be 200GiB on disk, give or take.
|
# as of 2023/11/26: complete downloaded blockchain should be 200GiB on disk, give or take.
|
||||||
{ ... }:
|
{ lib, ... }:
|
||||||
|
lib.mkIf false #< 2024/07/27: i don't use it, too much surface-area for me to run it pro-bono (`systemd-analyze security monero`)
|
||||||
{
|
{
|
||||||
sane.persist.sys.byStore.ext = [
|
sane.persist.sys.byStore.ext = [
|
||||||
# /var/lib/monero/lmdb is what consumes most of the space
|
# /var/lib/monero/lmdb is what consumes most of the space
|
||||||
|
@@ -1,9 +1,9 @@
|
|||||||
# tor settings: <https://2019.www.torproject.org/docs/tor-manual.html.en>
|
# tor settings: <https://2019.www.torproject.org/docs/tor-manual.html.en>
|
||||||
{ lib, ... }:
|
{ lib, ... }:
|
||||||
{
|
{
|
||||||
# tor hidden service hostnames aren't deterministic, so persist.
|
sane.persist.sys.byStore.ephemeral = [
|
||||||
# might be able to get away with just persisting /var/lib/tor/onion, not sure.
|
# N.B.: tor hidden service hostnames aren't deterministic, so if you need them
|
||||||
sane.persist.sys.byStore.plaintext = [
|
# to be preserved across reboots then persist /var/lib/tor/onion in "private" store.
|
||||||
{ user = "tor"; group = "tor"; mode = "0710"; path = "/var/lib/tor"; method = "bind"; }
|
{ user = "tor"; group = "tor"; mode = "0710"; path = "/var/lib/tor"; method = "bind"; }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@@ -1,17 +1,17 @@
|
|||||||
{ ... }:
|
{ ... }:
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
./calibre.nix
|
|
||||||
./coturn.nix
|
./coturn.nix
|
||||||
./cryptocurrencies
|
./cryptocurrencies
|
||||||
./email
|
./email
|
||||||
./ejabberd.nix
|
./ejabberd.nix
|
||||||
./freshrss.nix
|
./freshrss.nix
|
||||||
./export
|
./export
|
||||||
|
./hickory-dns.nix
|
||||||
./gitea.nix
|
./gitea.nix
|
||||||
./goaccess.nix
|
./goaccess.nix
|
||||||
./ipfs.nix
|
./ipfs.nix
|
||||||
./jackett.nix
|
./jackett
|
||||||
./jellyfin.nix
|
./jellyfin.nix
|
||||||
./kiwix-serve.nix
|
./kiwix-serve.nix
|
||||||
./komga.nix
|
./komga.nix
|
||||||
@@ -21,13 +21,13 @@
|
|||||||
./nginx.nix
|
./nginx.nix
|
||||||
./nixos-prebuild.nix
|
./nixos-prebuild.nix
|
||||||
./ntfy
|
./ntfy
|
||||||
|
./ollama.nix
|
||||||
./pict-rs.nix
|
./pict-rs.nix
|
||||||
./pleroma.nix
|
./pleroma.nix
|
||||||
./postgres.nix
|
./postgres.nix
|
||||||
./prosody
|
./prosody
|
||||||
./slskd.nix
|
./slskd.nix
|
||||||
./transmission.nix
|
./transmission
|
||||||
./trust-dns.nix
|
|
||||||
./wikipedia.nix
|
./wikipedia.nix
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@@ -44,61 +44,61 @@ in
|
|||||||
# everything configured below was fine: used ejabberd for several months.
|
# everything configured below was fine: used ejabberd for several months.
|
||||||
lib.mkIf false
|
lib.mkIf false
|
||||||
{
|
{
|
||||||
sane.persist.sys.byStore.plaintext = [
|
sane.persist.sys.byStore.private = [
|
||||||
{ user = "ejabberd"; group = "ejabberd"; path = "/var/lib/ejabberd"; method = "bind"; }
|
{ user = "ejabberd"; group = "ejabberd"; path = "/var/lib/ejabberd"; method = "bind"; }
|
||||||
];
|
];
|
||||||
sane.ports.ports = lib.mkMerge ([
|
sane.ports.ports = lib.mkMerge ([
|
||||||
{
|
{
|
||||||
"3478" = {
|
"3478" = {
|
||||||
protocol = [ "tcp" "udp" ];
|
protocol = [ "tcp" "udp" ];
|
||||||
|
visibleTo.doof = true;
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
visibleTo.wan = true;
|
|
||||||
description = "colin-xmpp-stun-turn";
|
description = "colin-xmpp-stun-turn";
|
||||||
};
|
};
|
||||||
"5222" = {
|
"5222" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
|
visibleTo.doof = true;
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
visibleTo.wan = true;
|
|
||||||
description = "colin-xmpp-client-to-server";
|
description = "colin-xmpp-client-to-server";
|
||||||
};
|
};
|
||||||
"5223" = {
|
"5223" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
|
visibleTo.doof = true;
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
visibleTo.wan = true;
|
|
||||||
description = "colin-xmpps-client-to-server"; # XMPP over TLS
|
description = "colin-xmpps-client-to-server"; # XMPP over TLS
|
||||||
};
|
};
|
||||||
"5269" = {
|
"5269" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
visibleTo.wan = true;
|
visibleTo.doof = true;
|
||||||
description = "colin-xmpp-server-to-server";
|
description = "colin-xmpp-server-to-server";
|
||||||
};
|
};
|
||||||
"5270" = {
|
"5270" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
visibleTo.wan = true;
|
visibleTo.doof = true;
|
||||||
description = "colin-xmpps-server-to-server"; # XMPP over TLS
|
description = "colin-xmpps-server-to-server"; # XMPP over TLS
|
||||||
};
|
};
|
||||||
"5280" = {
|
"5280" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
|
visibleTo.doof = true;
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
visibleTo.wan = true;
|
|
||||||
description = "colin-xmpp-bosh";
|
description = "colin-xmpp-bosh";
|
||||||
};
|
};
|
||||||
"5281" = {
|
"5281" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
|
visibleTo.doof = true;
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
visibleTo.wan = true;
|
|
||||||
description = "colin-xmpp-bosh-https";
|
description = "colin-xmpp-bosh-https";
|
||||||
};
|
};
|
||||||
"5349" = {
|
"5349" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
|
visibleTo.doof = true;
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
visibleTo.wan = true;
|
|
||||||
description = "colin-xmpp-stun-turn-over-tls";
|
description = "colin-xmpp-stun-turn-over-tls";
|
||||||
};
|
};
|
||||||
"5443" = {
|
"5443" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
|
visibleTo.doof = true;
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
visibleTo.wan = true;
|
|
||||||
description = "colin-xmpp-web-services"; # file uploads, websockets, admin
|
description = "colin-xmpp-web-services"; # file uploads, websockets, admin
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -109,8 +109,8 @@ lib.mkIf false
|
|||||||
numPorts = turnPortHigh - turnPortLow + 1;
|
numPorts = turnPortHigh - turnPortLow + 1;
|
||||||
in {
|
in {
|
||||||
protocol = [ "tcp" "udp" ];
|
protocol = [ "tcp" "udp" ];
|
||||||
|
visibleTo.doof = true;
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
visibleTo.wan = true;
|
|
||||||
description = "colin-xmpp-turn-${builtins.toString count}-of-${builtins.toString numPorts}";
|
description = "colin-xmpp-turn-${builtins.toString count}-of-${builtins.toString numPorts}";
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
|
@@ -8,14 +8,14 @@
|
|||||||
{
|
{
|
||||||
sane.ports.ports."143" = {
|
sane.ports.ports."143" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
|
visibleTo.doof = true;
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
visibleTo.wan = true;
|
|
||||||
description = "colin-imap-imap.uninsane.org";
|
description = "colin-imap-imap.uninsane.org";
|
||||||
};
|
};
|
||||||
sane.ports.ports."993" = {
|
sane.ports.ports."993" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
|
visibleTo.doof = true;
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
visibleTo.wan = true;
|
|
||||||
description = "colin-imaps-imap.uninsane.org";
|
description = "colin-imaps-imap.uninsane.org";
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -83,8 +83,8 @@
|
|||||||
# sieve_plugins = sieve_imapsieve
|
# sieve_plugins = sieve_imapsieve
|
||||||
# }
|
# }
|
||||||
|
|
||||||
mail_debug = yes
|
# mail_debug = yes
|
||||||
auth_debug = yes
|
# auth_debug = yes
|
||||||
# verbose_ssl = yes
|
# verbose_ssl = yes
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
@@ -1,6 +1,13 @@
|
|||||||
# postfix config options: <https://www.postfix.org/postconf.5.html>
|
# postfix config options: <https://www.postfix.org/postconf.5.html>
|
||||||
|
# config files:
|
||||||
|
# - /etc/postfix/main.cf
|
||||||
|
# - /etc/postfix/master.cf
|
||||||
|
#
|
||||||
|
# logs:
|
||||||
|
# - postfix logs directly to *syslog*,
|
||||||
|
# so check e.g. ~/.local/share/rsyslog
|
||||||
|
|
||||||
{ lib, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
let
|
let
|
||||||
submissionOptions = {
|
submissionOptions = {
|
||||||
@@ -18,14 +25,14 @@ let
|
|||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
sane.persist.sys.byStore.plaintext = [
|
sane.persist.sys.byStore.private = [
|
||||||
# TODO: mode? could be more granular
|
# TODO: mode? could be more granular
|
||||||
{ user = "opendkim"; group = "opendkim"; path = "/var/lib/opendkim"; method = "bind"; }
|
{ user = "opendkim"; group = "opendkim"; path = "/var/lib/opendkim"; method = "bind"; } #< TODO: migrate to secrets
|
||||||
{ user = "root"; group = "root"; path = "/var/lib/postfix"; method = "bind"; }
|
|
||||||
{ user = "root"; group = "root"; path = "/var/spool/mail"; method = "bind"; }
|
{ user = "root"; group = "root"; path = "/var/spool/mail"; method = "bind"; }
|
||||||
# *probably* don't need these dirs:
|
# *probably* don't need these dirs:
|
||||||
# "/var/lib/dhparams" # https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/security/dhparams.nix
|
# "/var/lib/dhparams" # https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/security/dhparams.nix
|
||||||
# "/var/lib/dovecot"
|
# "/var/lib/dovecot"
|
||||||
|
# "/var/lib/postfix"
|
||||||
];
|
];
|
||||||
|
|
||||||
# XXX(2023/10/20): opening these ports in the firewall has the OPPOSITE effect as intended.
|
# XXX(2023/10/20): opening these ports in the firewall has the OPPOSITE effect as intended.
|
||||||
@@ -56,8 +63,7 @@ in
|
|||||||
|
|
||||||
sane.dns.zones."uninsane.org".inet = {
|
sane.dns.zones."uninsane.org".inet = {
|
||||||
MX."@" = "10 mx.uninsane.org.";
|
MX."@" = "10 mx.uninsane.org.";
|
||||||
# XXX: RFC's specify that the MX record CANNOT BE A CNAME
|
A."mx" = "%AOVPNS%"; #< XXX: RFC's specify that the MX record CANNOT BE A CNAME. TODO: use "%AOVPNS%?
|
||||||
A."mx" = "185.157.162.178";
|
|
||||||
|
|
||||||
# Sender Policy Framework:
|
# Sender Policy Framework:
|
||||||
# +mx => mail passes if it originated from the MX
|
# +mx => mail passes if it originated from the MX
|
||||||
@@ -96,6 +102,7 @@ in
|
|||||||
services.postfix.sslCert = "/var/lib/acme/mx.uninsane.org/fullchain.pem";
|
services.postfix.sslCert = "/var/lib/acme/mx.uninsane.org/fullchain.pem";
|
||||||
services.postfix.sslKey = "/var/lib/acme/mx.uninsane.org/key.pem";
|
services.postfix.sslKey = "/var/lib/acme/mx.uninsane.org/key.pem";
|
||||||
|
|
||||||
|
# see: `man 5 virtual`
|
||||||
services.postfix.virtual = ''
|
services.postfix.virtual = ''
|
||||||
notify.matrix@uninsane.org matrix-synapse
|
notify.matrix@uninsane.org matrix-synapse
|
||||||
@uninsane.org colin
|
@uninsane.org colin
|
||||||
@@ -136,6 +143,20 @@ in
|
|||||||
# smtpd_sender_restrictions = reject_unknown_sender_domain
|
# smtpd_sender_restrictions = reject_unknown_sender_domain
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# debugging options:
|
||||||
|
# services.postfix.masterConfig = {
|
||||||
|
# "proxymap".args = [ "-v" ];
|
||||||
|
# "proxywrite".args = [ "-v" ];
|
||||||
|
# "relay".args = [ "-v" ];
|
||||||
|
# "smtp".args = [ "-v" ];
|
||||||
|
# "smtp_inet".args = [ "-v" ];
|
||||||
|
# "submission".args = [ "-v" ];
|
||||||
|
# "submissions".args = [ "-v" ];
|
||||||
|
# "submissions".chroot = false;
|
||||||
|
# "submissions".private = false;
|
||||||
|
# "submissions".privileged = true;
|
||||||
|
# };
|
||||||
|
|
||||||
services.postfix.enableSubmission = true;
|
services.postfix.enableSubmission = true;
|
||||||
services.postfix.submissionOptions = submissionOptions;
|
services.postfix.submissionOptions = submissionOptions;
|
||||||
services.postfix.enableSubmissions = true;
|
services.postfix.enableSubmissions = true;
|
||||||
@@ -143,6 +164,10 @@ in
|
|||||||
|
|
||||||
systemd.services.postfix.after = [ "wireguard-wg-ovpns.service" ];
|
systemd.services.postfix.after = [ "wireguard-wg-ovpns.service" ];
|
||||||
systemd.services.postfix.partOf = [ "wireguard-wg-ovpns.service" ];
|
systemd.services.postfix.partOf = [ "wireguard-wg-ovpns.service" ];
|
||||||
|
systemd.services.postfix.unitConfig.RequiresMountsFor = [
|
||||||
|
"/var/spool/mail" # spooky errors when postfix is run w/o this: `warning: connect #1 to subsystem private/proxymap: Connection refused`
|
||||||
|
"/var/lib/opendkim"
|
||||||
|
];
|
||||||
systemd.services.postfix.serviceConfig = {
|
systemd.services.postfix.serviceConfig = {
|
||||||
# run this behind the OVPN static VPN
|
# run this behind the OVPN static VPN
|
||||||
NetworkNamespacePath = "/run/netns/ovpns";
|
NetworkNamespacePath = "/run/netns/ovpns";
|
||||||
@@ -176,23 +201,30 @@ in
|
|||||||
|
|
||||||
|
|
||||||
#### OUTGOING MESSAGE REWRITING:
|
#### OUTGOING MESSAGE REWRITING:
|
||||||
services.postfix.enableHeaderChecks = true;
|
# - `man 5 header_checks`
|
||||||
services.postfix.headerChecks = [
|
# - <https://www.postfix.org/header_checks.5.html>
|
||||||
# intercept gitea registration confirmations and manually screen them
|
# - populates `/var/lib/postfix/conf/header_checks`
|
||||||
{
|
# XXX(2024-08-06): registration gating via email matches is AWFUL:
|
||||||
# headerChecks are somehow ignorant of alias rules: have to redirect to a real user
|
# 1. bypassed if the service offers localization.
|
||||||
action = "REDIRECT colin@uninsane.org";
|
# 2. if i try to forward the registration request, it may match the filter again and get sent back to my inbox.
|
||||||
pattern = "/^Subject: Please activate your account/";
|
# 3. header checks are possibly under-used in the ecosystem, and may break postfix config.
|
||||||
}
|
# services.postfix.enableHeaderChecks = true;
|
||||||
# intercept Matrix registration confirmations
|
# services.postfix.headerChecks = [
|
||||||
{
|
# # intercept gitea registration confirmations and manually screen them
|
||||||
action = "REDIRECT colin@uninsane.org";
|
|
||||||
pattern = "/^Subject:.*Validate your email/";
|
|
||||||
}
|
|
||||||
# XXX postfix only supports performing ONE action per header.
|
|
||||||
# {
|
# {
|
||||||
# action = "REPLACE Subject: git application: Please activate your account";
|
# # headerChecks are somehow ignorant of alias rules: have to redirect to a real user
|
||||||
# pattern = "/^Subject:.*activate your account/";
|
# action = "REDIRECT colin@uninsane.org";
|
||||||
|
# pattern = "/^Subject: Please activate your account/";
|
||||||
# }
|
# }
|
||||||
];
|
# # intercept Matrix registration confirmations
|
||||||
|
# {
|
||||||
|
# action = "REDIRECT colin@uninsane.org";
|
||||||
|
# pattern = "/^Subject:.*Validate your email/";
|
||||||
|
# }
|
||||||
|
# # XXX postfix only supports performing ONE action per header.
|
||||||
|
# # {
|
||||||
|
# # action = "REPLACE Subject: git application: Please activate your account";
|
||||||
|
# # pattern = "/^Subject:.*activate your account/";
|
||||||
|
# # }
|
||||||
|
# ];
|
||||||
}
|
}
|
||||||
|
@@ -37,17 +37,25 @@
|
|||||||
wantedBy = [ "nfs.service" "sftpgo.service" ];
|
wantedBy = [ "nfs.service" "sftpgo.service" ];
|
||||||
file.text = ''
|
file.text = ''
|
||||||
- media/ read-only: Videos, Music, Books, etc
|
- media/ read-only: Videos, Music, Books, etc
|
||||||
- playground/ read-write: use it to share files with other users of this server
|
- playground/ read-write*: use it to share files with other users of this server, inaccessible from the www
|
||||||
|
*if you can't write to it, make sure you're connected to the WiFi and not mobile.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
sane.fs."/var/export/playground/README.md" = {
|
sane.fs."/var/export/playground/README.md" = {
|
||||||
wantedBy = [ "nfs.service" "sftpgo.service" ];
|
wantedBy = [ "nfs.service" "sftpgo.service" ];
|
||||||
file.text = ''
|
file.text = ''
|
||||||
this directory is intentionally read+write by anyone with access (i.e. on the LAN).
|
this directory is intentionally read+write by anyone with access.
|
||||||
- share files
|
- share files
|
||||||
- write poetry
|
- write poetry
|
||||||
- be a friendly troll
|
- be a friendly troll
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
sane.fs."/var/export/.public_for_test/test" = {
|
||||||
|
wantedBy = [ "nfs.service" "sftpgo.service" ];
|
||||||
|
file.text = ''
|
||||||
|
automated tests read this file to probe connectivity
|
||||||
|
'';
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@@ -9,10 +9,10 @@
|
|||||||
|
|
||||||
{ config, lib, pkgs, sane-lib, ... }:
|
{ config, lib, pkgs, sane-lib, ... }:
|
||||||
let
|
let
|
||||||
external_auth_hook = pkgs.static-nix-shell.mkPython3Bin {
|
external_auth_hook = pkgs.static-nix-shell.mkPython3 {
|
||||||
pname = "external_auth_hook";
|
pname = "external_auth_hook";
|
||||||
srcRoot = ./.;
|
srcRoot = ./.;
|
||||||
pyPkgs = [ "passlib" ];
|
pkgs = [ "python3.pkgs.passlib" ];
|
||||||
};
|
};
|
||||||
# Client initiates a FTP "control connection" on port 21.
|
# Client initiates a FTP "control connection" on port 21.
|
||||||
# - this handles the client -> server commands, and the server -> client status, but not the actual data
|
# - this handles the client -> server commands, and the server -> client status, but not the actual data
|
||||||
@@ -27,13 +27,12 @@ in
|
|||||||
"21" = {
|
"21" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
# visibleTo.wan = true;
|
|
||||||
description = "colin-FTP server";
|
description = "colin-FTP server";
|
||||||
};
|
};
|
||||||
"990" = {
|
"990" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
|
visibleTo.doof = true;
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
visibleTo.wan = true;
|
|
||||||
description = "colin-FTPS server";
|
description = "colin-FTPS server";
|
||||||
};
|
};
|
||||||
} // (sane-lib.mapToAttrs
|
} // (sane-lib.mapToAttrs
|
||||||
@@ -41,8 +40,8 @@ in
|
|||||||
name = builtins.toString port;
|
name = builtins.toString port;
|
||||||
value = {
|
value = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
|
visibleTo.doof = true;
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
visibleTo.wan = true;
|
|
||||||
description = "colin-FTP server data port range";
|
description = "colin-FTP server data port range";
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
@@ -81,12 +80,6 @@ in
|
|||||||
port = 21;
|
port = 21;
|
||||||
debug = true;
|
debug = true;
|
||||||
}
|
}
|
||||||
{
|
|
||||||
# binding this means any LAN client can connect (also WAN traffic forwarded from the gateway)
|
|
||||||
address = "10.78.79.51";
|
|
||||||
port = 21;
|
|
||||||
debug = true;
|
|
||||||
}
|
|
||||||
{
|
{
|
||||||
# binding this means any wireguard client can connect
|
# binding this means any wireguard client can connect
|
||||||
address = "10.0.10.5";
|
address = "10.0.10.5";
|
||||||
@@ -97,6 +90,26 @@ in
|
|||||||
{
|
{
|
||||||
# binding this means any LAN client can connect (also WAN traffic forwarded from the gateway)
|
# binding this means any LAN client can connect (also WAN traffic forwarded from the gateway)
|
||||||
address = "10.78.79.51";
|
address = "10.78.79.51";
|
||||||
|
port = 21;
|
||||||
|
debug = true;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
# binding this means any LAN client can connect (also WAN traffic forwarded from the gateway)
|
||||||
|
address = "10.78.79.51";
|
||||||
|
port = 990;
|
||||||
|
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.
|
||||||
|
}
|
||||||
|
{
|
||||||
|
# binding this means any LAN client can connect via `ftp.uninsane.org` (TLS only)
|
||||||
|
address = config.sane.netns.doof.netnsPubIpv4;
|
||||||
port = 990;
|
port = 990;
|
||||||
debug = true;
|
debug = true;
|
||||||
tls_mode = 2; # 2 = "implicit FTPS": client negotiates TLS before any FTP command.
|
tls_mode = 2; # 2 = "implicit FTPS": client negotiates TLS before any FTP command.
|
||||||
@@ -117,7 +130,7 @@ in
|
|||||||
banner = ''
|
banner = ''
|
||||||
Welcome, friends, to Colin's FTP server! Also available via NFS on the same host, but LAN-only.
|
Welcome, friends, to Colin's FTP server! Also available via NFS on the same host, but LAN-only.
|
||||||
|
|
||||||
Read-only access (LAN-restricted):
|
Read-only access (LAN clients see everything; WAN clients can only see /pub):
|
||||||
Username: "anonymous"
|
Username: "anonymous"
|
||||||
Password: "anonymous"
|
Password: "anonymous"
|
||||||
|
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env nix-shell
|
#!/usr/bin/env nix-shell
|
||||||
#!nix-shell -i python3 -p "python3.withPackages (ps: [ ps.passlib ])"
|
#!nix-shell -i python3 -p python3 -p python3.pkgs.passlib
|
||||||
# vim: set filetype=python :
|
# vim: set filetype=python :
|
||||||
#
|
#
|
||||||
# available environment variables:
|
# available environment variables:
|
||||||
@@ -45,6 +45,8 @@ from hmac import compare_digest
|
|||||||
|
|
||||||
authFail = dict(username="")
|
authFail = dict(username="")
|
||||||
|
|
||||||
|
PERM_DENY = []
|
||||||
|
PERM_LIST = [ "list" ]
|
||||||
PERM_RO = [ "list", "download" ]
|
PERM_RO = [ "list", "download" ]
|
||||||
PERM_RW = [
|
PERM_RW = [
|
||||||
# read-only:
|
# read-only:
|
||||||
@@ -69,6 +71,9 @@ TRUSTED_CREDS = [
|
|||||||
# $<method>$<salt>$<hash>
|
# $<method>$<salt>$<hash>
|
||||||
"$6$Zq3c2u4ghUH4S6EP$pOuRt13sEKfX31OqPbbd1LuhS21C9MICMc94iRdTAgdAcJ9h95gQH/6Jf6Ie4Obb0oxQtojRJ1Pd/9QHOlFMW." #< m. rocket boy
|
"$6$Zq3c2u4ghUH4S6EP$pOuRt13sEKfX31OqPbbd1LuhS21C9MICMc94iRdTAgdAcJ9h95gQH/6Jf6Ie4Obb0oxQtojRJ1Pd/9QHOlFMW." #< m. rocket boy
|
||||||
]
|
]
|
||||||
|
TRUSTED_VIEWING_OR_PLAYGROUND_CREDS = [
|
||||||
|
"$6$iikDajz5b.YH1.on$tfSzzBEtX8IeDiJJXCasOTxRTd7cFDKXU6dhlWYVhK6xDeJhV2fh6bmm1WIHItjIth9Eh9zNgUB8xibMIWCm/."
|
||||||
|
];
|
||||||
|
|
||||||
def mkAuthOk(username: str, permissions: dict[str, list[str]]) -> dict:
|
def mkAuthOk(username: str, permissions: dict[str, list[str]]) -> dict:
|
||||||
return dict(
|
return dict(
|
||||||
@@ -110,8 +115,8 @@ def isLan(ip: str) -> bool:
|
|||||||
def isWireguard(ip: str) -> bool:
|
def isWireguard(ip: str) -> bool:
|
||||||
return ip.startswith("10.0.10.")
|
return ip.startswith("10.0.10.")
|
||||||
|
|
||||||
def isTrustedCred(password: str) -> bool:
|
def isTrustedCred(password: str, credlist: list[str] = TRUSTED_CREDS) -> bool:
|
||||||
for cred in TRUSTED_CREDS:
|
for cred in credlist:
|
||||||
if passlib.hosts.linux_context.verify(password, cred):
|
if passlib.hosts.linux_context.verify(password, cred):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -127,12 +132,29 @@ def getAuthResponse(ip: str, username: str, password: str) -> dict:
|
|||||||
return mkAuthOk(username, permissions = {
|
return mkAuthOk(username, permissions = {
|
||||||
"/": PERM_RW,
|
"/": PERM_RW,
|
||||||
"/playground": PERM_RW,
|
"/playground": PERM_RW,
|
||||||
|
"/.public_for_test": PERM_RO,
|
||||||
|
})
|
||||||
|
if isTrustedCred(password, TRUSTED_VIEWING_OR_PLAYGROUND_CREDS) and username != "colin":
|
||||||
|
return mkAuthOk(username, permissions = {
|
||||||
|
# error prone, but... not the worst if i miss something
|
||||||
|
"/": PERM_LIST,
|
||||||
|
"/media/archive": PERM_DENY,
|
||||||
|
"/media/Books": PERM_RO,
|
||||||
|
"/media/collections": PERM_DENY,
|
||||||
|
"/media/games": PERM_RO,
|
||||||
|
"/media/Music": PERM_RO,
|
||||||
|
"/media/Pictures": PERM_RO,
|
||||||
|
"/media/torrents": PERM_DENY,
|
||||||
|
"/media/Videos": PERM_RO,
|
||||||
|
"/playground": PERM_RW,
|
||||||
|
"/.public_for_test": PERM_RO,
|
||||||
})
|
})
|
||||||
if isWireguard(ip):
|
if isWireguard(ip):
|
||||||
# allow any user from wireguard
|
# allow any user from wireguard
|
||||||
return mkAuthOk(username, permissions = {
|
return mkAuthOk(username, permissions = {
|
||||||
"/": PERM_RW,
|
"/": PERM_RW,
|
||||||
"/playground": PERM_RW,
|
"/playground": PERM_RW,
|
||||||
|
"/.public_for_test": PERM_RO,
|
||||||
})
|
})
|
||||||
if isLan(ip):
|
if isLan(ip):
|
||||||
if username == "anonymous":
|
if username == "anonymous":
|
||||||
@@ -140,6 +162,18 @@ def getAuthResponse(ip: str, username: str, password: str) -> dict:
|
|||||||
return mkAuthOk("anonymous", permissions = {
|
return mkAuthOk("anonymous", permissions = {
|
||||||
"/": PERM_RO,
|
"/": PERM_RO,
|
||||||
"/playground": PERM_RW,
|
"/playground": PERM_RW,
|
||||||
|
"/.public_for_test": 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,
|
||||||
|
"/.public_for_test": PERM_RO,
|
||||||
|
# "/README.md": PERM_RO, #< does not work
|
||||||
})
|
})
|
||||||
|
|
||||||
return authFail
|
return authFail
|
||||||
|
@@ -10,6 +10,7 @@
|
|||||||
# ```
|
# ```
|
||||||
|
|
||||||
{ config, lib, pkgs, sane-lib, ... }:
|
{ config, lib, pkgs, sane-lib, ... }:
|
||||||
|
lib.mkIf false #< 2024/07/04: i haven't actively used this for months
|
||||||
{
|
{
|
||||||
sops.secrets."freshrss_passwd" = {
|
sops.secrets."freshrss_passwd" = {
|
||||||
owner = config.users.users.freshrss.name;
|
owner = config.users.users.freshrss.name;
|
||||||
|
@@ -1,11 +1,14 @@
|
|||||||
# config options: <https://docs.gitea.io/en-us/administration/config-cheat-sheet/>
|
# config options: <https://docs.gitea.io/en-us/administration/config-cheat-sheet/>
|
||||||
|
# TODO: service shouldn't run as `git` user, but as `gitea`
|
||||||
{ config, pkgs, lib, ... }:
|
{ config, pkgs, lib, ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
sane.persist.sys.byStore.plaintext = [
|
sane.persist.sys.byStore.private = [
|
||||||
# TODO: mode? could be more granular
|
{ user = "git"; group = "gitea"; mode = "0750"; path = "/var/lib/gitea"; method = "bind"; }
|
||||||
{ user = "git"; group = "gitea"; path = "/var/lib/gitea"; method = "bind"; }
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
sane.programs.gitea.enableFor.user.colin = true; # for admin, and monitoring
|
||||||
|
|
||||||
services.gitea.enable = true;
|
services.gitea.enable = true;
|
||||||
services.gitea.user = "git"; # default is 'gitea'
|
services.gitea.user = "git"; # default is 'gitea'
|
||||||
services.gitea.database.type = "postgres";
|
services.gitea.database.type = "postgres";
|
||||||
@@ -38,17 +41,24 @@
|
|||||||
ROOT_URL = "https://git.uninsane.org/";
|
ROOT_URL = "https://git.uninsane.org/";
|
||||||
};
|
};
|
||||||
service = {
|
service = {
|
||||||
# timeout for email approval. 5760 = 4 days
|
# timeout for email approval. 5760 = 4 days. 10080 = 7 days
|
||||||
ACTIVE_CODE_LIVE_MINUTES = 5760;
|
ACTIVE_CODE_LIVE_MINUTES = 10080;
|
||||||
# REGISTER_EMAIL_CONFIRM = false;
|
# REGISTER_EMAIL_CONFIRM = false;
|
||||||
# REGISTER_MANUAL_CONFIRM = true;
|
# REGISTER_EMAIL_CONFIRM = true; #< override REGISTER_MANUAL_CONFIRM
|
||||||
REGISTER_EMAIL_CONFIRM = true;
|
REGISTER_MANUAL_CONFIRM = true;
|
||||||
# not sure what this notified on?
|
# not sure what this notifies *on*...
|
||||||
ENABLE_NOTIFY_MAIL = true;
|
ENABLE_NOTIFY_MAIL = true;
|
||||||
# defaults to image-based captcha.
|
# defaults to image-based captcha.
|
||||||
# also supports recaptcha (with custom URLs) or hCaptcha.
|
# also supports recaptcha (with custom URLs) or hCaptcha.
|
||||||
ENABLE_CAPTCHA = true;
|
ENABLE_CAPTCHA = true;
|
||||||
NOREPLY_ADDRESS = "noreply.anonymous.git@uninsane.org";
|
NOREPLY_ADDRESS = "noreply.anonymous.git@uninsane.org";
|
||||||
|
EMAIL_DOMAIN_BLOCKLIST = lib.concatStringsSep ", " [
|
||||||
|
"*.claychoen.top"
|
||||||
|
"*.gemmasmith.co.uk"
|
||||||
|
"*.jenniferlawrence.uk"
|
||||||
|
"*.sarahconnor.co.uk"
|
||||||
|
"*.marymarshall.co.uk"
|
||||||
|
];
|
||||||
};
|
};
|
||||||
session = {
|
session = {
|
||||||
COOKIE_SECURE = true;
|
COOKIE_SECURE = true;
|
||||||
@@ -64,8 +74,8 @@
|
|||||||
SHOW_FOOTER_TEMPLATE_LOAD_TIME = false;
|
SHOW_FOOTER_TEMPLATE_LOAD_TIME = false;
|
||||||
};
|
};
|
||||||
ui = {
|
ui = {
|
||||||
# options: "auto", "gitea", "arc-green"
|
# options: "gitea-auto" (adapt to system theme), "gitea-dark", "gitea-light"
|
||||||
DEFAULT_THEME = "arc-green";
|
# DEFAULT_THEME = "gitea-auto";
|
||||||
# cache frontend assets if true
|
# cache frontend assets if true
|
||||||
# USE_SERVICE_WORKER = true;
|
# USE_SERVICE_WORKER = true;
|
||||||
};
|
};
|
||||||
@@ -74,9 +84,10 @@
|
|||||||
# alternative is to use nixos-level config:
|
# alternative is to use nixos-level config:
|
||||||
# services.gitea.mailerPasswordFile = ...
|
# services.gitea.mailerPasswordFile = ...
|
||||||
ENABLED = true;
|
ENABLED = true;
|
||||||
MAILER_TYPE = "sendmail";
|
|
||||||
FROM = "notify.git@uninsane.org";
|
FROM = "notify.git@uninsane.org";
|
||||||
|
PROTOCOL = "sendmail";
|
||||||
SENDMAIL_PATH = "${pkgs.postfix}/bin/sendmail";
|
SENDMAIL_PATH = "${pkgs.postfix}/bin/sendmail";
|
||||||
|
SENDMAIL_ARGS = "--"; # most "sendmail" programs take options, "--" will prevent an email address being interpreted as an option.
|
||||||
};
|
};
|
||||||
time = {
|
time = {
|
||||||
# options: ANSIC, UnixDate, RubyDate, RFC822, RFC822Z, RFC850, RFC1123, RFC1123Z, RFC3339, RFC3339Nano, Kitchen, Stamp, StampMilli, StampMicro, StampNano
|
# options: ANSIC, UnixDate, RubyDate, RFC822, RFC822Z, RFC850, RFC1123, RFC1123Z, RFC3339, RFC3339Nano, Kitchen, Stamp, StampMilli, StampMicro, StampNano
|
||||||
@@ -108,6 +119,10 @@
|
|||||||
locations."/" = {
|
locations."/" = {
|
||||||
proxyPass = "http://127.0.0.1:3000";
|
proxyPass = "http://127.0.0.1:3000";
|
||||||
};
|
};
|
||||||
|
# fuck you @anthropic
|
||||||
|
locations."= /robots.txt".extraConfig = ''
|
||||||
|
return 200 "User-agent: *\nDisallow: /\n";
|
||||||
|
'';
|
||||||
# gitea serves all `raw` files as content-type: plain, but i'd like to serve them as their actual content type.
|
# gitea serves all `raw` files as content-type: plain, but i'd like to serve them as their actual content type.
|
||||||
# or at least, enough to make specific pages viewable (serving unoriginal content as arbitrary content type is dangerous).
|
# or at least, enough to make specific pages viewable (serving unoriginal content as arbitrary content type is dangerous).
|
||||||
locations."~ ^/colin/phone-case-cq/raw/.*.html" = {
|
locations."~ ^/colin/phone-case-cq/raw/.*.html" = {
|
||||||
@@ -133,7 +148,7 @@
|
|||||||
sane.ports.ports."22" = {
|
sane.ports.ports."22" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
visibleTo.wan = true;
|
visibleTo.doof = true;
|
||||||
description = "colin-git@git.uninsane.org";
|
description = "colin-git@git.uninsane.org";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
145
hosts/by-name/servo/services/hickory-dns.nix
Normal file
145
hosts/by-name/servo/services/hickory-dns.nix
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
# TODO: split this file apart into smaller files to make it easier to understand
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
dyn-dns = config.sane.services.dyn-dns;
|
||||||
|
nativeAddrs = lib.mapAttrs (_name: builtins.head) config.sane.dns.zones."uninsane.org".inet.A;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
sane.ports.ports."53" = {
|
||||||
|
protocol = [ "udp" "tcp" ];
|
||||||
|
visibleTo.lan = true;
|
||||||
|
# visibleTo.wan = true;
|
||||||
|
visibleTo.ovpns = true;
|
||||||
|
visibleTo.doof = true;
|
||||||
|
description = "colin-dns-hosting";
|
||||||
|
};
|
||||||
|
|
||||||
|
sane.dns.zones."uninsane.org".TTL = 900;
|
||||||
|
|
||||||
|
# SOA record structure: <https://en.wikipedia.org/wiki/SOA_record#Structure>
|
||||||
|
# SOA MNAME RNAME (... rest)
|
||||||
|
# MNAME = Master name server for this zone. this is where update requests should be sent.
|
||||||
|
# RNAME = admin contact (encoded email address)
|
||||||
|
# Serial = YYYYMMDDNN, where N is incremented every time this file changes, to trigger secondary NS to re-fetch it.
|
||||||
|
# Refresh = how frequently secondary NS should query master
|
||||||
|
# Retry = how long secondary NS should wait until re-querying master after a failure (must be < Refresh)
|
||||||
|
# Expire = how long secondary NS should continue to reply to queries after master fails (> Refresh + Retry)
|
||||||
|
sane.dns.zones."uninsane.org".inet = {
|
||||||
|
SOA."@" = ''
|
||||||
|
ns1.uninsane.org. admin-dns.uninsane.org. (
|
||||||
|
2023092101 ; Serial
|
||||||
|
4h ; Refresh
|
||||||
|
30m ; Retry
|
||||||
|
7d ; Expire
|
||||||
|
5m) ; Negative response TTL
|
||||||
|
'';
|
||||||
|
TXT."rev" = "2023092101";
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
# XXX NS records must also not be CNAME
|
||||||
|
# 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" = "%ADOOF%";
|
||||||
|
A."ovpns" = "%AOVPNS%";
|
||||||
|
NS."@" = [
|
||||||
|
"ns1.uninsane.org."
|
||||||
|
"ns2.uninsane.org."
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
services.hickory-dns.settings.zones = [ "uninsane.org" ];
|
||||||
|
|
||||||
|
|
||||||
|
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.hickory-dns.enable = true;
|
||||||
|
sane.services.hickory-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}";
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
doof = {
|
||||||
|
substitutions = mkSubstitutions "doof";
|
||||||
|
listenAddrsIpv4 = [
|
||||||
|
config.sane.netns.doof.hostVethIpv4
|
||||||
|
config.sane.netns.doof.netnsPubIpv4
|
||||||
|
nativeAddrs."servo.lan"
|
||||||
|
# config.sane.netns.ovpns.hostVethIpv4
|
||||||
|
];
|
||||||
|
};
|
||||||
|
hn = {
|
||||||
|
substitutions = mkSubstitutions "hn";
|
||||||
|
listenAddrsIpv4 = [ nativeAddrs."servo.hn" ];
|
||||||
|
enableRecursiveResolver = true; #< allow wireguard clients to use this as their DNS resolver
|
||||||
|
# extraConfig = {
|
||||||
|
# zones = [
|
||||||
|
# {
|
||||||
|
# # forward the root zone to the local DNS resolver
|
||||||
|
# # to allow wireguard clients to use this as their DNS resolver
|
||||||
|
# zone = ".";
|
||||||
|
# zone_type = "Forward";
|
||||||
|
# stores = {
|
||||||
|
# type = "forward";
|
||||||
|
# name_servers = [
|
||||||
|
# {
|
||||||
|
# socket_addr = "127.0.0.53:53";
|
||||||
|
# protocol = "udp";
|
||||||
|
# trust_nx_responses = true;
|
||||||
|
# }
|
||||||
|
# ];
|
||||||
|
# };
|
||||||
|
# }
|
||||||
|
# ];
|
||||||
|
# };
|
||||||
|
};
|
||||||
|
# lan = {
|
||||||
|
# substitutions = mkSubstitutions "lan";
|
||||||
|
# listenAddrsIpv4 = [ nativeAddrs."servo.lan" ];
|
||||||
|
# # port = 1053;
|
||||||
|
# };
|
||||||
|
# wan = {
|
||||||
|
# substitutions = mkSubstitutions "wan";
|
||||||
|
# listenAddrsIpv4 = [
|
||||||
|
# nativeAddrs."servo.lan"
|
||||||
|
# ];
|
||||||
|
# };
|
||||||
|
};
|
||||||
|
|
||||||
|
sane.services.dyn-dns.restartOnChange = lib.map (c: "${c.service}.service") (builtins.attrValues config.sane.services.hickory-dns.instances);
|
||||||
|
}
|
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
lib.mkIf false # i don't actively use ipfs anymore
|
lib.mkIf false # i don't actively use ipfs anymore
|
||||||
{
|
{
|
||||||
sane.persist.sys.byStore.plaintext = [
|
sane.persist.sys.byStore.private = [
|
||||||
# TODO: mode? could be more granular
|
# TODO: mode? could be more granular
|
||||||
{ user = "261"; group = "261"; path = "/var/lib/ipfs"; method = "bind"; }
|
{ user = "261"; group = "261"; path = "/var/lib/ipfs"; method = "bind"; }
|
||||||
];
|
];
|
||||||
|
@@ -1,36 +0,0 @@
|
|||||||
{ 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?
|
|
||||||
{ user = "root"; group = "root"; path = "/var/lib/jackett"; method = "bind"; }
|
|
||||||
];
|
|
||||||
services.jackett.enable = true;
|
|
||||||
|
|
||||||
systemd.services.jackett.after = [ "wireguard-wg-ovpns.service" ];
|
|
||||||
systemd.services.jackett.partOf = [ "wireguard-wg-ovpns.service" ];
|
|
||||||
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
|
|
||||||
|
|
||||||
# patch jackett to listen on the public interfaces
|
|
||||||
# ExecStart = lib.mkForce "${pkgs.jackett}/bin/Jackett --NoUpdates --DataFolder /var/lib/jackett/.config/Jackett --ListenPublic";
|
|
||||||
};
|
|
||||||
|
|
||||||
# jackett torrent search
|
|
||||||
services.nginx.virtualHosts."jackett.uninsane.org" = {
|
|
||||||
forceSSL = true;
|
|
||||||
enableACME = true;
|
|
||||||
# inherit kTLS;
|
|
||||||
locations."/" = {
|
|
||||||
# proxyPass = "http://ovpns.uninsane.org:9117";
|
|
||||||
proxyPass = "http://10.0.1.6:9117";
|
|
||||||
recommendedProxySettings = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
sane.dns.zones."uninsane.org".inet.CNAME."jackett" = "native";
|
|
||||||
}
|
|
||||||
|
|
68
hosts/by-name/servo/services/jackett/default.nix
Normal file
68
hosts/by-name/servo/services/jackett/default.nix
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.services.jackett;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
sane.persist.sys.byStore.private = [
|
||||||
|
# TODO: mode? we only need this to save Indexer creds ==> migrate to config?
|
||||||
|
{ user = "jackett"; group = "jackett"; path = "/var/lib/jackett"; method = "bind"; }
|
||||||
|
];
|
||||||
|
services.jackett.enable = true;
|
||||||
|
|
||||||
|
systemd.services.jackett.after = [ "wireguard-wg-ovpns.service" ];
|
||||||
|
systemd.services.jackett.partOf = [ "wireguard-wg-ovpns.service" ];
|
||||||
|
systemd.services.jackett = {
|
||||||
|
# run this behind the OVPN static VPN
|
||||||
|
serviceConfig.NetworkNamespacePath = "/run/netns/ovpns";
|
||||||
|
serviceConfig.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 in `--ListenPublic` so that it's reachable from the netns veth.
|
||||||
|
# this also makes it reachable from the VPN pub address. oh well.
|
||||||
|
serviceConfig.ExecStart = lib.mkForce "${cfg.package}/bin/Jackett --ListenPublic --NoUpdates --DataFolder '${cfg.dataDir}'";
|
||||||
|
serviceConfig.RestartSec = "30s";
|
||||||
|
|
||||||
|
# hardening (systemd-analyze security jackett)
|
||||||
|
# TODO: upstream into nixpkgs
|
||||||
|
serviceConfig.StateDirectory = "jackett";
|
||||||
|
serviceConfig.LockPersonality = true;
|
||||||
|
serviceConfig.NoNewPrivileges = true;
|
||||||
|
# serviceConfig.MemoryDenyWriteExecute = true; #< Failed to create CoreCLR, HRESULT: 0x80004005
|
||||||
|
serviceConfig.PrivateDevices = true;
|
||||||
|
serviceConfig.PrivateMounts = true;
|
||||||
|
serviceConfig.PrivateTmp = true;
|
||||||
|
serviceConfig.PrivateUsers = true;
|
||||||
|
serviceConfig.ProcSubset = "pid";
|
||||||
|
serviceConfig.ProtectClock = true;
|
||||||
|
serviceConfig.ProtectControlGroups = true;
|
||||||
|
serviceConfig.ProtectHome = true;
|
||||||
|
serviceConfig.ProtectHostname = true;
|
||||||
|
serviceConfig.ProtectKernelLogs = true;
|
||||||
|
serviceConfig.ProtectKernelModules = true;
|
||||||
|
serviceConfig.ProtectKernelTunables = true;
|
||||||
|
serviceConfig.ProtectProc = "invisible";
|
||||||
|
serviceConfig.ProtectSystem = "strict";
|
||||||
|
serviceConfig.RemoveIPC = true;
|
||||||
|
serviceConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6";
|
||||||
|
serviceConfig.RestrictNamespaces = true;
|
||||||
|
serviceConfig.RestrictSUIDSGID = true;
|
||||||
|
serviceConfig.SystemCallArchitectures = "native";
|
||||||
|
serviceConfig.SystemCallFilter = [ "@system-service" "~@privileged" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
# jackett torrent search
|
||||||
|
services.nginx.virtualHosts."jackett.uninsane.org" = {
|
||||||
|
forceSSL = true;
|
||||||
|
enableACME = true;
|
||||||
|
# inherit kTLS;
|
||||||
|
locations."/" = {
|
||||||
|
proxyPass = "http://${config.sane.netns.ovpns.netnsVethIpv4}:9117";
|
||||||
|
recommendedProxySettings = true;
|
||||||
|
};
|
||||||
|
locations."= /robots.txt".extraConfig = ''
|
||||||
|
return 200 "User-agent: *\nDisallow: /\n";
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
sane.dns.zones."uninsane.org".inet.CNAME."jackett" = "native";
|
||||||
|
}
|
||||||
|
|
@@ -21,6 +21,9 @@
|
|||||||
enableACME = true;
|
enableACME = true;
|
||||||
# inherit kTLS;
|
# inherit kTLS;
|
||||||
locations."/".proxyPass = "http://127.0.0.1:8013";
|
locations."/".proxyPass = "http://127.0.0.1:8013";
|
||||||
|
locations."= /robots.txt".extraConfig = ''
|
||||||
|
return 200 "User-agent: *\nDisallow: /\n";
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
sane.dns.zones."uninsane.org".inet.CNAME."w" = "native";
|
sane.dns.zones."uninsane.org".inet.CNAME."w" = "native";
|
||||||
|
@@ -17,6 +17,9 @@ in
|
|||||||
locations."/" = {
|
locations."/" = {
|
||||||
proxyPass = "http://127.0.0.1:${builtins.toString port}";
|
proxyPass = "http://127.0.0.1:${builtins.toString port}";
|
||||||
};
|
};
|
||||||
|
locations."= /robots.txt".extraConfig = ''
|
||||||
|
return 200 "User-agent: *\nDisallow: /\n";
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
sane.dns.zones."uninsane.org".inet.CNAME."komga" = "native";
|
sane.dns.zones."uninsane.org".inet.CNAME."komga" = "native";
|
||||||
}
|
}
|
||||||
|
@@ -38,14 +38,10 @@ in {
|
|||||||
nginx.enable = true;
|
nginx.enable = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.services.lemmy.serviceConfig = {
|
|
||||||
# fix to use a normal user so we can configure perms correctly
|
|
||||||
DynamicUser = mkForce false;
|
|
||||||
User = "lemmy";
|
|
||||||
Group = "lemmy";
|
|
||||||
};
|
|
||||||
systemd.services.lemmy.environment = {
|
systemd.services.lemmy.environment = {
|
||||||
RUST_BACKTRACE = "full";
|
RUST_BACKTRACE = "full";
|
||||||
|
RUST_LOG = "error";
|
||||||
|
# RUST_LOG = "warn";
|
||||||
# RUST_LOG = "debug";
|
# RUST_LOG = "debug";
|
||||||
# RUST_LOG = "trace";
|
# RUST_LOG = "trace";
|
||||||
# upstream defaults LEMMY_DATABASE_URL = "postgres:///lemmy?host=/run/postgresql";
|
# upstream defaults LEMMY_DATABASE_URL = "postgres:///lemmy?host=/run/postgresql";
|
||||||
@@ -72,6 +68,73 @@ in {
|
|||||||
|
|
||||||
sane.dns.zones."uninsane.org".inet.CNAME."lemmy" = "native";
|
sane.dns.zones."uninsane.org".inet.CNAME."lemmy" = "native";
|
||||||
|
|
||||||
|
systemd.services.lemmy = {
|
||||||
|
# fix to use a normal user so we can configure perms correctly
|
||||||
|
# XXX(2024-07-28): this hasn't been rigorously tested:
|
||||||
|
# possible that i've set something too strict and won't notice right away
|
||||||
|
serviceConfig.DynamicUser = mkForce false;
|
||||||
|
serviceConfig.User = "lemmy";
|
||||||
|
serviceConfig.Group = "lemmy";
|
||||||
|
|
||||||
|
# hardening (systemd-analyze security lemmy)
|
||||||
|
# a handful of these are specified in upstream nixpkgs, but mostly not
|
||||||
|
serviceConfig.LockPersonality = true;
|
||||||
|
serviceConfig.NoNewPrivileges = true;
|
||||||
|
serviceConfig.MemoryDenyWriteExecute = true;
|
||||||
|
serviceConfig.PrivateDevices = true;
|
||||||
|
serviceConfig.PrivateMounts = true;
|
||||||
|
serviceConfig.PrivateTmp = true;
|
||||||
|
serviceConfig.PrivateUsers = true;
|
||||||
|
serviceConfig.ProcSubset = "pid";
|
||||||
|
|
||||||
|
serviceConfig.ProtectClock = true;
|
||||||
|
serviceConfig.ProtectControlGroups = true;
|
||||||
|
serviceConfig.ProtectHome = true;
|
||||||
|
serviceConfig.ProtectHostname = true;
|
||||||
|
serviceConfig.ProtectKernelLogs = true;
|
||||||
|
serviceConfig.ProtectKernelModules = true;
|
||||||
|
serviceConfig.ProtectKernelTunables = true;
|
||||||
|
serviceConfig.ProtectProc = "invisible";
|
||||||
|
serviceConfig.ProtectSystem = "strict";
|
||||||
|
serviceConfig.RemoveIPC = true;
|
||||||
|
serviceConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6";
|
||||||
|
|
||||||
|
serviceConfig.RestrictNamespaces = true;
|
||||||
|
serviceConfig.RestrictSUIDSGID = true;
|
||||||
|
serviceConfig.SystemCallArchitectures = "native";
|
||||||
|
serviceConfig.SystemCallFilter = [ "@system-service" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.lemmy-ui = {
|
||||||
|
# hardening (systemd-analyze security lemmy-ui)
|
||||||
|
# TODO: upstream into nixpkgs
|
||||||
|
serviceConfig.LockPersonality = true;
|
||||||
|
serviceConfig.NoNewPrivileges = true;
|
||||||
|
# serviceConfig.MemoryDenyWriteExecute = true; #< it uses v8, JIT
|
||||||
|
serviceConfig.PrivateDevices = true;
|
||||||
|
serviceConfig.PrivateMounts = true;
|
||||||
|
serviceConfig.PrivateTmp = true;
|
||||||
|
serviceConfig.PrivateUsers = true;
|
||||||
|
serviceConfig.ProcSubset = "pid";
|
||||||
|
|
||||||
|
serviceConfig.ProtectClock = true;
|
||||||
|
serviceConfig.ProtectControlGroups = true;
|
||||||
|
serviceConfig.ProtectHome = true;
|
||||||
|
serviceConfig.ProtectHostname = true;
|
||||||
|
serviceConfig.ProtectKernelLogs = true;
|
||||||
|
serviceConfig.ProtectKernelModules = true;
|
||||||
|
serviceConfig.ProtectKernelTunables = true;
|
||||||
|
serviceConfig.ProtectProc = "invisible";
|
||||||
|
serviceConfig.ProtectSystem = "strict";
|
||||||
|
serviceConfig.RemoveIPC = true;
|
||||||
|
serviceConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6";
|
||||||
|
|
||||||
|
serviceConfig.RestrictNamespaces = true;
|
||||||
|
serviceConfig.RestrictSUIDSGID = true;
|
||||||
|
serviceConfig.SystemCallArchitectures = "native";
|
||||||
|
serviceConfig.SystemCallFilter = [ "@system-service" "@pkey" "@sandbox" ];
|
||||||
|
};
|
||||||
|
|
||||||
#v DO NOT REMOVE: defaults to 0.3, instead of latest, so always need to explicitly set this.
|
#v DO NOT REMOVE: defaults to 0.3, instead of latest, so always need to explicitly set this.
|
||||||
services.pict-rs.package = pict-rs;
|
services.pict-rs.package = pict-rs;
|
||||||
|
|
||||||
@@ -81,10 +144,38 @@ in {
|
|||||||
# - via CLI flags (overrides everything above)
|
# - via CLI flags (overrides everything above)
|
||||||
# some of the CLI flags have defaults, making it the only actual way to configure certain things even when docs claim otherwise.
|
# some of the CLI flags have defaults, making it the only actual way to configure certain things even when docs claim otherwise.
|
||||||
# CLI args: <https://git.asonix.dog/asonix/pict-rs#user-content-running>
|
# CLI args: <https://git.asonix.dog/asonix/pict-rs#user-content-running>
|
||||||
systemd.services.pict-rs.serviceConfig.ExecStart = lib.mkForce (lib.concatStringsSep " " [
|
systemd.services.pict-rs = {
|
||||||
|
serviceConfig.ExecStart = lib.mkForce (lib.concatStringsSep " " [
|
||||||
"${lib.getBin pict-rs}/bin/pict-rs run"
|
"${lib.getBin pict-rs}/bin/pict-rs run"
|
||||||
"--media-video-max-frame-count" (builtins.toString (30*60*60))
|
"--media-video-max-frame-count" (builtins.toString (30*60*60))
|
||||||
"--media-process-timeout 120"
|
"--media-process-timeout 120"
|
||||||
"--media-video-allow-audio" # allow audio
|
"--media-video-allow-audio" # allow audio
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
# hardening (systemd-analyze security pict-rs)
|
||||||
|
# TODO: upstream into nixpkgs
|
||||||
|
serviceConfig.LockPersonality = true;
|
||||||
|
serviceConfig.NoNewPrivileges = true;
|
||||||
|
serviceConfig.MemoryDenyWriteExecute = true;
|
||||||
|
serviceConfig.PrivateDevices = true;
|
||||||
|
serviceConfig.PrivateMounts = true;
|
||||||
|
serviceConfig.PrivateTmp = true;
|
||||||
|
serviceConfig.PrivateUsers = true;
|
||||||
|
serviceConfig.ProcSubset = "pid";
|
||||||
|
serviceConfig.ProtectClock = true;
|
||||||
|
serviceConfig.ProtectControlGroups = true;
|
||||||
|
serviceConfig.ProtectHome = true;
|
||||||
|
serviceConfig.ProtectHostname = true;
|
||||||
|
serviceConfig.ProtectKernelLogs = true;
|
||||||
|
serviceConfig.ProtectKernelModules = true;
|
||||||
|
serviceConfig.ProtectKernelTunables = true;
|
||||||
|
serviceConfig.ProtectProc = "invisible";
|
||||||
|
serviceConfig.ProtectSystem = "strict";
|
||||||
|
serviceConfig.RemoveIPC = true;
|
||||||
|
serviceConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6";
|
||||||
|
serviceConfig.RestrictNamespaces = true;
|
||||||
|
serviceConfig.RestrictSUIDSGID = true;
|
||||||
|
serviceConfig.SystemCallArchitectures = "native";
|
||||||
|
serviceConfig.SystemCallFilter = [ "@system-service" ];
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# docs: <https://nixos.wiki/wiki/Matrix>
|
# docs: <https://nixos.wiki/wiki/Matrix>
|
||||||
# docs: <https://nixos.org/manual/nixos/stable/index.html#module-services-matrix-synapse>
|
# docs: <https://nixos.org/manual/nixos/stable/index.html#module-services-matrix-synapse>
|
||||||
# example config: <https://github.com/matrix-org/synapse/blob/develop/docs/sample_config.yaml>
|
# example config: <https://github.com/element-hq/synapse/blob/develop/docs/sample_config.yaml>
|
||||||
#
|
#
|
||||||
# ENABLING PUSH NOTIFICATIONS (with UnifiedPush/ntfy):
|
# ENABLING PUSH NOTIFICATIONS (with UnifiedPush/ntfy):
|
||||||
# - Matrix "pushers" API spec: <https://spec.matrix.org/latest/client-server-api/#post_matrixclientv3pushersset>
|
# - Matrix "pushers" API spec: <https://spec.matrix.org/latest/client-server-api/#post_matrixclientv3pushersset>
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
# - `curl --header "Authorization: Bearer <your_access_token>" --data '{ "app_display_name": "<topic>", "app_id": "ntfy.uninsane.org", "data": { "url": "https://ntfy.uninsane.org/_matrix/push/v1/notify", "format": "event_id_only" }, "device_display_name": "<topic>", "kind": "http", "lang": "en-US", "profile_tag": "", "pushkey": "<topic>" }' localhost:8008/_matrix/client/v3/pushers/set`
|
# - `curl --header "Authorization: Bearer <your_access_token>" --data '{ "app_display_name": "<topic>", "app_id": "ntfy.uninsane.org", "data": { "url": "https://ntfy.uninsane.org/_matrix/push/v1/notify", "format": "event_id_only" }, "device_display_name": "<topic>", "kind": "http", "lang": "en-US", "profile_tag": "", "pushkey": "<topic>" }' localhost:8008/_matrix/client/v3/pushers/set`
|
||||||
# - delete a notification destination by setting `kind` to `null` (otherwise, request is identical to above)
|
# - delete a notification destination by setting `kind` to `null` (otherwise, request is identical to above)
|
||||||
#
|
#
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, pkgs, ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
@@ -20,19 +20,17 @@
|
|||||||
./signal.nix
|
./signal.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
sane.persist.sys.byStore.plaintext = [
|
sane.persist.sys.byStore.private = [
|
||||||
{ user = "matrix-synapse"; group = "matrix-synapse"; path = "/var/lib/matrix-synapse"; method = "bind"; }
|
{ user = "matrix-synapse"; group = "matrix-synapse"; path = "/var/lib/matrix-synapse"; method = "bind"; }
|
||||||
];
|
];
|
||||||
services.matrix-synapse.enable = true;
|
services.matrix-synapse.enable = true;
|
||||||
|
services.matrix-synapse.log.root.level = "ERROR"; # accepts "DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL" (?)
|
||||||
services.matrix-synapse.settings = {
|
services.matrix-synapse.settings = {
|
||||||
# this changes the default log level from INFO to WARN.
|
|
||||||
# maybe there's an easier way?
|
|
||||||
log_config = ./synapse-log_level.yaml;
|
|
||||||
server_name = "uninsane.org";
|
server_name = "uninsane.org";
|
||||||
|
|
||||||
# services.matrix-synapse.enable_registration_captcha = true;
|
# services.matrix-synapse.enable_registration_captcha = true;
|
||||||
# services.matrix-synapse.enable_registration_without_verification = true;
|
# services.matrix-synapse.enable_registration_without_verification = true;
|
||||||
enable_registration = true;
|
# enable_registration = true;
|
||||||
# services.matrix-synapse.registration_shared_secret = "<shared key goes here>";
|
# services.matrix-synapse.registration_shared_secret = "<shared key goes here>";
|
||||||
|
|
||||||
# default for listeners is port = 8448, tls = true, x_forwarded = false.
|
# default for listeners is port = 8448, tls = true, x_forwarded = false.
|
||||||
|
@@ -5,7 +5,7 @@
|
|||||||
# - recommended to use mautrix-discord: <https://github.com/NixOS/nixpkgs/pull/200462>
|
# - recommended to use mautrix-discord: <https://github.com/NixOS/nixpkgs/pull/200462>
|
||||||
lib.mkIf false
|
lib.mkIf false
|
||||||
{
|
{
|
||||||
sane.persist.sys.byStore.plaintext = [
|
sane.persist.sys.byStore.private = [
|
||||||
{ user = "matrix-synapse"; group = "matrix-synapse"; path = "/var/lib/mx-puppet-discord"; method = "bind"; }
|
{ user = "matrix-synapse"; group = "matrix-synapse"; path = "/var/lib/mx-puppet-discord"; method = "bind"; }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@@ -1,15 +1,13 @@
|
|||||||
# config docs:
|
# config docs:
|
||||||
# - <https://github.com/matrix-org/matrix-appservice-irc/blob/develop/config.sample.yaml>
|
# - <https://github.com/matrix-org/matrix-appservice-irc/blob/develop/config.sample.yaml>
|
||||||
# probably want to remove that.
|
{ lib, ... }:
|
||||||
{ config, lib, ... }:
|
|
||||||
|
|
||||||
let
|
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;
|
lowerName = lib.toLower name;
|
||||||
in {
|
in {
|
||||||
# XXX sasl: appservice doesn't support NickServ identification (only SASL, or PASS if sasl = false)
|
# XXX sasl: appservice doesn't support NickServ identification (only SASL, or PASS if sasl = false)
|
||||||
inherit name additionalAddresses sasl port;
|
inherit additionalAddresses name port sasl ssl;
|
||||||
ssl = true;
|
|
||||||
botConfig = {
|
botConfig = {
|
||||||
# bot has no presence in IRC channel; only real Matrix users
|
# bot has no presence in IRC channel; only real Matrix users
|
||||||
enabled = false;
|
enabled = false;
|
||||||
@@ -101,7 +99,7 @@ in
|
|||||||
})
|
})
|
||||||
];
|
];
|
||||||
|
|
||||||
sane.persist.sys.byStore.plaintext = [
|
sane.persist.sys.byStore.private = [
|
||||||
# TODO: mode?
|
# TODO: mode?
|
||||||
{ user = "matrix-appservice-irc"; group = "matrix-appservice-irc"; path = "/var/lib/matrix-appservice-irc"; method = "bind"; }
|
{ user = "matrix-appservice-irc"; group = "matrix-appservice-irc"; path = "/var/lib/matrix-appservice-irc"; method = "bind"; }
|
||||||
];
|
];
|
||||||
@@ -129,6 +127,8 @@ in
|
|||||||
};
|
};
|
||||||
|
|
||||||
ircService = {
|
ircService = {
|
||||||
|
logging.level = "warn"; # "error", "warn", "info", "debug"
|
||||||
|
mediaProxy.publicUrl = "https://irc.matrix.uninsane.org/media";
|
||||||
servers = {
|
servers = {
|
||||||
"irc.esper.net" = ircServer {
|
"irc.esper.net" = ircServer {
|
||||||
name = "esper";
|
name = "esper";
|
||||||
@@ -156,6 +156,10 @@ in
|
|||||||
# - #sxmo-offtopic
|
# - #sxmo-offtopic
|
||||||
};
|
};
|
||||||
"irc.rizon.net" = ircServer { name = "Rizon"; };
|
"irc.rizon.net" = ircServer { name = "Rizon"; };
|
||||||
|
"wigle.net" = ircServer {
|
||||||
|
name = "WiGLE";
|
||||||
|
ssl = false;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -165,4 +169,16 @@ in
|
|||||||
# the service actively uses at least one of these, and both of them are fairly innocuous
|
# the service actively uses at least one of these, and both of them are fairly innocuous
|
||||||
SystemCallFilter = lib.mkForce "~@clock @cpu-emulation @debug @keyring @module @mount @obsolete @raw-io @setuid @swap";
|
SystemCallFilter = lib.mkForce "~@clock @cpu-emulation @debug @keyring @module @mount @obsolete @raw-io @setuid @swap";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
services.nginx.virtualHosts."irc.matrix.uninsane.org" = {
|
||||||
|
forceSSL = true;
|
||||||
|
enableACME = true;
|
||||||
|
locations."/media" = {
|
||||||
|
proxyPass = "http://127.0.0.1:11111";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
sane.dns.zones."uninsane.org".inet = {
|
||||||
|
CNAME."irc.matrix" = "native";
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
lib.mkIf false # disabled 2024/01/11: i don't use it, and pkgs.mautrix-signal had some API changes
|
lib.mkIf false # disabled 2024/01/11: i don't use it, and pkgs.mautrix-signal had some API changes
|
||||||
{
|
{
|
||||||
sane.persist.sys.byStore.plaintext = [
|
sane.persist.sys.byStore.private = [
|
||||||
{ user = "mautrix-signal"; group = "mautrix-signal"; path = "/var/lib/mautrix-signal"; method = "bind"; }
|
{ user = "mautrix-signal"; group = "mautrix-signal"; path = "/var/lib/mautrix-signal"; method = "bind"; }
|
||||||
{ user = "signald"; group = "signald"; path = "/var/lib/signald"; method = "bind"; }
|
{ user = "signald"; group = "signald"; path = "/var/lib/signald"; method = "bind"; }
|
||||||
];
|
];
|
||||||
|
@@ -1,27 +0,0 @@
|
|||||||
version: 1
|
|
||||||
|
|
||||||
# In systemd's journal, loglevel is implicitly stored, so let's omit it
|
|
||||||
# from the message text.
|
|
||||||
formatters:
|
|
||||||
journal_fmt:
|
|
||||||
format: '%(name)s: [%(request)s] %(message)s'
|
|
||||||
|
|
||||||
filters:
|
|
||||||
context:
|
|
||||||
(): synapse.util.logcontext.LoggingContextFilter
|
|
||||||
request: ""
|
|
||||||
|
|
||||||
handlers:
|
|
||||||
journal:
|
|
||||||
class: systemd.journal.JournalHandler
|
|
||||||
formatter: journal_fmt
|
|
||||||
filters: [context]
|
|
||||||
SYSLOG_IDENTIFIER: synapse
|
|
||||||
|
|
||||||
# default log level: INFO
|
|
||||||
root:
|
|
||||||
level: WARN
|
|
||||||
handlers: [journal]
|
|
||||||
|
|
||||||
disable_existing_loggers: False
|
|
||||||
|
|
@@ -17,7 +17,6 @@ in
|
|||||||
sane.ports.ports."80" = {
|
sane.ports.ports."80" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
visibleTo.wan = true;
|
|
||||||
visibleTo.ovpns = true; # so that letsencrypt can procure a cert for the mx record
|
visibleTo.ovpns = true; # so that letsencrypt can procure a cert for the mx record
|
||||||
visibleTo.doof = true;
|
visibleTo.doof = true;
|
||||||
description = "colin-http-uninsane.org";
|
description = "colin-http-uninsane.org";
|
||||||
@@ -25,12 +24,17 @@ in
|
|||||||
sane.ports.ports."443" = {
|
sane.ports.ports."443" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
visibleTo.wan = true;
|
|
||||||
visibleTo.doof = true;
|
visibleTo.doof = true;
|
||||||
description = "colin-https-uninsane.org";
|
description = "colin-https-uninsane.org";
|
||||||
};
|
};
|
||||||
|
|
||||||
services.nginx.enable = true;
|
services.nginx.enable = true;
|
||||||
|
# nginxStable is one release behind nginxMainline.
|
||||||
|
# nginx itself recommends running mainline; nixos defaults to stable.
|
||||||
|
# services.nginx.package = pkgs.nginxMainline;
|
||||||
|
# XXX(2024-07-31): nixos defaults to zlib-ng -- supposedly more performant, but spams log with
|
||||||
|
# "gzip filter failed to use preallocated memory: ..."
|
||||||
|
services.nginx.package = pkgs.nginxMainline.override { zlib = pkgs.zlib; };
|
||||||
services.nginx.appendConfig = ''
|
services.nginx.appendConfig = ''
|
||||||
# use 1 process per core.
|
# use 1 process per core.
|
||||||
# may want to increase worker_connections too, but `ulimit -n` must be increased first.
|
# may want to increase worker_connections too, but `ulimit -n` must be increased first.
|
||||||
@@ -46,8 +50,10 @@ in
|
|||||||
log_format vcombined '$host:$server_port $remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referrer" "$http_user_agent"';
|
log_format vcombined '$host:$server_port $remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referrer" "$http_user_agent"';
|
||||||
access_log /var/log/nginx/private.log vcombined;
|
access_log /var/log/nginx/private.log vcombined;
|
||||||
'';
|
'';
|
||||||
# sets gzip_comp_level = 5
|
# enables gzip and sets gzip_comp_level = 5
|
||||||
services.nginx.recommendedGzipSettings = true;
|
services.nginx.recommendedGzipSettings = true;
|
||||||
|
# enables zstd and sets zstd_comp_level = 9
|
||||||
|
services.nginx.recommendedZstdSettings = true;
|
||||||
# enables OCSP stapling (so clients don't need contact the OCSP server -- i do instead)
|
# enables OCSP stapling (so clients don't need contact the OCSP server -- i do instead)
|
||||||
# - doesn't seem to, actually: <https://www.ssllabs.com/ssltest/analyze.html?d=uninsane.org>
|
# - doesn't seem to, actually: <https://www.ssllabs.com/ssltest/analyze.html?d=uninsane.org>
|
||||||
# caches TLS sessions for 10m
|
# caches TLS sessions for 10m
|
||||||
@@ -101,6 +107,16 @@ in
|
|||||||
disable_symlinks on;
|
disable_symlinks on;
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
locations."/share/Ubunchu/" = {
|
||||||
|
alias = "/var/media/Books/Visual/HiroshiSeo/Ubunchu/";
|
||||||
|
extraConfig = ''
|
||||||
|
# autoindex => render directory listings
|
||||||
|
autoindex on;
|
||||||
|
# don't follow any symlinks when serving files
|
||||||
|
# otherwise it allows a directory escape
|
||||||
|
disable_symlinks on;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
# allow matrix users to discover that @user:uninsane.org is reachable via matrix.uninsane.org
|
# allow matrix users to discover that @user:uninsane.org is reachable via matrix.uninsane.org
|
||||||
locations."= /.well-known/matrix/server".extraConfig =
|
locations."= /.well-known/matrix/server".extraConfig =
|
||||||
@@ -182,8 +198,15 @@ in
|
|||||||
|
|
||||||
sane.persist.sys.byStore.plaintext = [
|
sane.persist.sys.byStore.plaintext = [
|
||||||
{ user = "acme"; group = "acme"; path = "/var/lib/acme"; method = "bind"; }
|
{ user = "acme"; group = "acme"; path = "/var/lib/acme"; method = "bind"; }
|
||||||
|
];
|
||||||
|
sane.persist.sys.byStore.private = [
|
||||||
{ user = "colin"; group = "users"; path = "/var/www/sites"; method = "bind"; }
|
{ user = "colin"; group = "users"; path = "/var/www/sites"; method = "bind"; }
|
||||||
];
|
];
|
||||||
|
sane.persist.sys.byStore.ephemeral = [
|
||||||
|
# logs *could* be persisted to private storage, but then there's the issue of
|
||||||
|
# "what if servo boots, isn't unlocked, and the whole / tmpfs is consumed by logs"
|
||||||
|
{ user = "nginx"; group = "nginx"; path = "/var/log/nginx"; method = "bind"; }
|
||||||
|
];
|
||||||
|
|
||||||
# let's encrypt default chain looks like:
|
# let's encrypt default chain looks like:
|
||||||
# - End-entity certificate ← R3 ← ISRG Root X1 ← DST Root CA X3
|
# - End-entity certificate ← R3 ← ISRG Root X1 ← DST Root CA X3
|
||||||
|
@@ -30,7 +30,7 @@ let
|
|||||||
altPort = 2587;
|
altPort = 2587;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
sane.persist.sys.byStore.plaintext = [
|
sane.persist.sys.byStore.private = [
|
||||||
# not 100% necessary to persist this, but ntfy does keep a 12hr (by default) cache
|
# not 100% necessary to persist this, but ntfy does keep a 12hr (by default) cache
|
||||||
# for pushing notifications to users who become offline.
|
# for pushing notifications to users who become offline.
|
||||||
# ACLs also live here.
|
# ACLs also live here.
|
||||||
@@ -46,7 +46,7 @@ in
|
|||||||
# defaults to 45s.
|
# defaults to 45s.
|
||||||
# note that the client may still do its own TCP-level keepalives, typically every 30s
|
# note that the client may still do its own TCP-level keepalives, typically every 30s
|
||||||
keepalive-interval = "15m";
|
keepalive-interval = "15m";
|
||||||
log-level = "trace"; # trace, debug, info (default), warn, error
|
log-level = "info"; # trace, debug, info (default), warn, error
|
||||||
auth-default-access = "deny-all";
|
auth-default-access = "deny-all";
|
||||||
};
|
};
|
||||||
systemd.services.ntfy-sh.serviceConfig.DynamicUser = lib.mkForce false;
|
systemd.services.ntfy-sh.serviceConfig.DynamicUser = lib.mkForce false;
|
||||||
@@ -86,7 +86,7 @@ in
|
|||||||
sane.ports.ports."${builtins.toString altPort}" = {
|
sane.ports.ports."${builtins.toString altPort}" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
visibleTo.wan = true;
|
visibleTo.doof = true;
|
||||||
description = "colin-ntfy.uninsane.org";
|
description = "colin-ntfy.uninsane.org";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env nix-shell
|
#!/usr/bin/env nix-shell
|
||||||
#!nix-shell -i python3 -p "python3.withPackages (ps: [ ])" -p ntfy-sh
|
#!nix-shell -i python3 -p ntfy-sh -p python3
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import logging
|
import logging
|
||||||
|
@@ -47,7 +47,7 @@ in
|
|||||||
};
|
};
|
||||||
sane.ntfy-waiter.package = mkOption {
|
sane.ntfy-waiter.package = mkOption {
|
||||||
type = types.package;
|
type = types.package;
|
||||||
default = pkgs.static-nix-shell.mkPython3Bin {
|
default = pkgs.static-nix-shell.mkPython3 {
|
||||||
pname = "ntfy-waiter";
|
pname = "ntfy-waiter";
|
||||||
srcRoot = ./.;
|
srcRoot = ./.;
|
||||||
pkgs = [ "ntfy-sh" ];
|
pkgs = [ "ntfy-sh" ];
|
||||||
@@ -62,8 +62,8 @@ in
|
|||||||
sane.ports.ports = lib.mkMerge (lib.forEach portRange (port: {
|
sane.ports.ports = lib.mkMerge (lib.forEach portRange (port: {
|
||||||
"${builtins.toString port}" = {
|
"${builtins.toString port}" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
|
visibleTo.doof = true;
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
visibleTo.wan = true;
|
|
||||||
description = "colin-notification-waiter-${builtins.toString (port - portLow + 1)}-of-${builtins.toString numPorts}";
|
description = "colin-notification-waiter-${builtins.toString (port - portLow + 1)}-of-${builtins.toString numPorts}";
|
||||||
};
|
};
|
||||||
}));
|
}));
|
||||||
|
23
hosts/by-name/servo/services/ollama.nix
Normal file
23
hosts/by-name/servo/services/ollama.nix
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# ollama: <https://github.com/ollama/ollama>
|
||||||
|
# use: `ollama run llama3.1`
|
||||||
|
# or: `ollama run llama3.1:70b`
|
||||||
|
# or use a remote session: <https://github.com/ggozad/oterm>
|
||||||
|
{ lib, ... }:
|
||||||
|
lib.mkIf false #< WIP
|
||||||
|
{
|
||||||
|
sane.persist.sys.byStore.plaintext = [
|
||||||
|
{ user = "ollama"; group = "ollama"; path = "/var/lib/ollama"; method = "bind"; }
|
||||||
|
];
|
||||||
|
services.ollama.enable = true;
|
||||||
|
services.ollama.user = "ollama";
|
||||||
|
services.ollama.group = "ollama";
|
||||||
|
|
||||||
|
users.groups.ollama = {};
|
||||||
|
|
||||||
|
users.users.ollama = {
|
||||||
|
group = "ollama";
|
||||||
|
isSystemUser = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.ollama.serviceConfig.DynamicUser = lib.mkForce false;
|
||||||
|
}
|
@@ -7,14 +7,15 @@
|
|||||||
# to run it in a oci-container: <https://github.com/barrucadu/nixfiles/blob/master/services/pleroma.nix>
|
# to run it in a oci-container: <https://github.com/barrucadu/nixfiles/blob/master/services/pleroma.nix>
|
||||||
#
|
#
|
||||||
# admin frontend: <https://fed.uninsane.org/pleroma/admin>
|
# admin frontend: <https://fed.uninsane.org/pleroma/admin>
|
||||||
{ config, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
let
|
let
|
||||||
logLevel = "warn";
|
logLevel = "warn";
|
||||||
# logLevel = "debug";
|
# logLevel = "debug";
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
sane.persist.sys.byStore.plaintext = [
|
sane.persist.sys.byStore.private = [
|
||||||
|
# contains media i've uploaded to the server
|
||||||
{ user = "pleroma"; group = "pleroma"; path = "/var/lib/pleroma"; method = "bind"; }
|
{ user = "pleroma"; group = "pleroma"; path = "/var/lib/pleroma"; method = "bind"; }
|
||||||
];
|
];
|
||||||
services.pleroma.enable = true;
|
services.pleroma.enable = true;
|
||||||
@@ -135,25 +136,52 @@ in
|
|||||||
# something inside pleroma invokes `sh` w/o specifying it by path, so this is needed to allow pleroma to start
|
# something inside pleroma invokes `sh` w/o specifying it by path, so this is needed to allow pleroma to start
|
||||||
pkgs.bash
|
pkgs.bash
|
||||||
# used by Pleroma to strip geo tags from uploads
|
# used by Pleroma to strip geo tags from uploads
|
||||||
pkgs.exiftool
|
config.sane.programs.exiftool.package
|
||||||
# i saw some errors when pleroma was shutting down about it not being able to find `awk`. probably not critical
|
# i saw some errors when pleroma was shutting down about it not being able to find `awk`. probably not critical
|
||||||
pkgs.gawk
|
config.sane.programs.gawk.package
|
||||||
# needed for email operations like password reset
|
# needed for email operations like password reset
|
||||||
pkgs.postfix
|
pkgs.postfix
|
||||||
];
|
];
|
||||||
|
|
||||||
systemd.services.pleroma.serviceConfig = {
|
systemd.services.pleroma = {
|
||||||
# postgres can be slow to service early requests, preventing pleroma from starting on the first try
|
# postgres can be slow to service early requests, preventing pleroma from starting on the first try
|
||||||
Restart = "on-failure";
|
serviceConfig.Restart = "on-failure";
|
||||||
RestartSec = "10s";
|
serviceConfig.RestartSec = "10s";
|
||||||
};
|
|
||||||
|
|
||||||
# systemd.services.pleroma.serviceConfig = {
|
# hardening (systemd-analyze security pleroma)
|
||||||
# # required for sendmail. see https://git.pleroma.social/pleroma/pleroma/-/issues/2259
|
# XXX(2024-07-28): this hasn't been rigorously tested:
|
||||||
# NoNewPrivileges = lib.mkForce false;
|
# possible that i've set something too strict and won't notice right away
|
||||||
# PrivateTmp = lib.mkForce false;
|
# make sure to test:
|
||||||
# CapabilityBoundingSet = lib.mkForce "~";
|
# - image/media uploading
|
||||||
# };
|
serviceConfig.CapabilityBoundingSet = "~CAP_SYS_ADMIN"; #< TODO: reduce this. try: CAP_SYS_NICE CAP_DAC_READ_SEARCH CAP_SYS_CHROOT CAP_SETGID CAP_SETUID
|
||||||
|
serviceConfig.LockPersonality = true;
|
||||||
|
serviceConfig.NoNewPrivileges = true;
|
||||||
|
serviceConfig.MemoryDenyWriteExecute = true;
|
||||||
|
serviceConfig.PrivateDevices = lib.mkForce true; #< dunno why nixpkgs has this set false; it seems to work as true
|
||||||
|
serviceConfig.PrivateMounts = true;
|
||||||
|
serviceConfig.PrivateTmp = true;
|
||||||
|
serviceConfig.PrivateUsers = true;
|
||||||
|
|
||||||
|
serviceConfig.ProtectProc = "invisible";
|
||||||
|
serviceConfig.ProcSubset = "all"; #< needs /proc/sys/kernel/overflowuid for bwrap
|
||||||
|
|
||||||
|
serviceConfig.ProtectClock = true;
|
||||||
|
serviceConfig.ProtectControlGroups = true;
|
||||||
|
serviceConfig.ProtectHome = true;
|
||||||
|
serviceConfig.ProtectKernelModules = true;
|
||||||
|
serviceConfig.ProtectSystem = lib.mkForce "strict";
|
||||||
|
serviceConfig.RemoveIPC = true;
|
||||||
|
serviceConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6 AF_NETLINK";
|
||||||
|
|
||||||
|
serviceConfig.RestrictSUIDSGID = true;
|
||||||
|
serviceConfig.SystemCallArchitectures = "native";
|
||||||
|
serviceConfig.SystemCallFilter = [ "@system-service" "@mount" "@sandbox" ]; #< "sandbox" might not actually be necessary
|
||||||
|
|
||||||
|
serviceConfig.ProtectHostname = false; #< else brap can't mount /proc
|
||||||
|
serviceConfig.ProtectKernelLogs = false; #< else breaks exiftool ("bwrap: Can't mount proc on /newroot/proc: Operation not permitted")
|
||||||
|
serviceConfig.ProtectKernelTunables = false; #< else breaks exiftool
|
||||||
|
serviceConfig.RestrictNamespaces = false; # media uploads require bwrap
|
||||||
|
};
|
||||||
|
|
||||||
# this is required to allow pleroma to send email.
|
# this is required to allow pleroma to send email.
|
||||||
# raw `sendmail` works, but i think pleroma's passing it some funny flags or something, idk.
|
# raw `sendmail` works, but i think pleroma's passing it some funny flags or something, idk.
|
||||||
|
@@ -6,9 +6,9 @@ let
|
|||||||
KiB = n: 1024*n;
|
KiB = n: 1024*n;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
sane.persist.sys.byStore.plaintext = [
|
sane.persist.sys.byStore.private = [
|
||||||
# TODO: mode?
|
{ user = "postgres"; group = "postgres"; mode = "0750"; path = "/var/lib/postgresql"; method = "bind"; }
|
||||||
{ user = "postgres"; group = "postgres"; path = "/var/lib/postgresql"; method = "bind"; }
|
{ user = "postgres"; group = "postgres"; mode = "0750"; path = "/var/backup/postgresql"; method = "bind"; }
|
||||||
];
|
];
|
||||||
services.postgresql.enable = true;
|
services.postgresql.enable = true;
|
||||||
|
|
||||||
|
@@ -56,47 +56,48 @@ let
|
|||||||
enableDebug = false;
|
enableDebug = false;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
sane.persist.sys.byStore.plaintext = [
|
sane.persist.sys.byStore.private = [
|
||||||
|
# TODO: mode?
|
||||||
{ user = "prosody"; group = "prosody"; path = "/var/lib/prosody"; method = "bind"; }
|
{ user = "prosody"; group = "prosody"; path = "/var/lib/prosody"; method = "bind"; }
|
||||||
];
|
];
|
||||||
sane.ports.ports."5000" = {
|
sane.ports.ports."5000" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
|
visibleTo.doof = true;
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
visibleTo.wan = true;
|
|
||||||
description = "colin-xmpp-prosody-fileshare-proxy65";
|
description = "colin-xmpp-prosody-fileshare-proxy65";
|
||||||
};
|
};
|
||||||
sane.ports.ports."5222" = {
|
sane.ports.ports."5222" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
|
visibleTo.doof = true;
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
visibleTo.wan = true;
|
|
||||||
description = "colin-xmpp-client-to-server";
|
description = "colin-xmpp-client-to-server";
|
||||||
};
|
};
|
||||||
sane.ports.ports."5223" = {
|
sane.ports.ports."5223" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
|
visibleTo.doof = true;
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
visibleTo.wan = true;
|
|
||||||
description = "colin-xmpps-client-to-server"; # XMPP over TLS
|
description = "colin-xmpps-client-to-server"; # XMPP over TLS
|
||||||
};
|
};
|
||||||
sane.ports.ports."5269" = {
|
sane.ports.ports."5269" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
visibleTo.wan = true;
|
visibleTo.doof = true;
|
||||||
description = "colin-xmpp-server-to-server";
|
description = "colin-xmpp-server-to-server";
|
||||||
};
|
};
|
||||||
sane.ports.ports."5270" = {
|
sane.ports.ports."5270" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
visibleTo.wan = true;
|
visibleTo.doof = true;
|
||||||
description = "colin-xmpps-server-to-server"; # XMPP over TLS
|
description = "colin-xmpps-server-to-server"; # XMPP over TLS
|
||||||
};
|
};
|
||||||
sane.ports.ports."5280" = {
|
sane.ports.ports."5280" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
|
visibleTo.doof = true;
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
visibleTo.wan = true;
|
|
||||||
description = "colin-xmpp-bosh";
|
description = "colin-xmpp-bosh";
|
||||||
};
|
};
|
||||||
sane.ports.ports."5281" = {
|
sane.ports.ports."5281" = {
|
||||||
protocol = [ "tcp" ];
|
protocol = [ "tcp" ];
|
||||||
|
visibleTo.doof = true;
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
visibleTo.wan = true;
|
|
||||||
description = "colin-xmpp-prosody-https"; # necessary?
|
description = "colin-xmpp-prosody-https"; # necessary?
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -10,7 +10,9 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
sane.persist.sys.byStore.plaintext = [
|
sane.persist.sys.byStore.ephemeral = [
|
||||||
|
# {data,downloads,incomplete,logs}: contains logs, search history, and downloads
|
||||||
|
# so, move the downloaded data to persistent storage regularly, or configure the downloads/incomplete dirs to point to persisted storage (in nixpkgs slskd config)
|
||||||
{ user = "slskd"; group = "media"; path = "/var/lib/slskd"; method = "bind"; }
|
{ user = "slskd"; group = "media"; path = "/var/lib/slskd"; method = "bind"; }
|
||||||
];
|
];
|
||||||
sops.secrets."slskd_env" = {
|
sops.secrets."slskd_env" = {
|
||||||
@@ -32,7 +34,7 @@
|
|||||||
forceSSL = true;
|
forceSSL = true;
|
||||||
enableACME = true;
|
enableACME = true;
|
||||||
locations."/" = {
|
locations."/" = {
|
||||||
proxyPass = "http://10.0.1.6:5030";
|
proxyPass = "http://${config.sane.netns.ovpns.netnsVethIpv4}:5030";
|
||||||
proxyWebsockets = true;
|
proxyWebsockets = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -68,12 +70,20 @@
|
|||||||
# flags.volatile = true; # store searches and active transfers in RAM (completed transfers still go to disk). rec for btrfs/zfs
|
# flags.volatile = true; # store searches and active transfers in RAM (completed transfers still go to disk). rec for btrfs/zfs
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.services.slskd.serviceConfig = {
|
systemd.services.slskd = {
|
||||||
# run this behind the OVPN static VPN
|
# run this behind the OVPN static VPN
|
||||||
NetworkNamespacePath = "/run/netns/ovpns";
|
serviceConfig.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
|
serviceConfig.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
|
serviceConfig.Restart = lib.mkForce "always"; # exits "success" when it fails to connect to soulseek server
|
||||||
RestartSec = "60s";
|
serviceConfig.RestartSec = "60s";
|
||||||
|
|
||||||
|
# hardening (systemd-analyze security slskd)
|
||||||
|
# upstream nixpkgs specifies moderate defaults; these are supplementary
|
||||||
|
# serviceConfig.MemoryDenyWriteExecute = true;
|
||||||
|
# serviceConfig.ProcSubset = "pid";
|
||||||
|
# serviceConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6";
|
||||||
|
# serviceConfig.SystemCallArchitectures = "native";
|
||||||
|
# serviceConfig.SystemCallFilter = [ "@system-service" ];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -22,71 +22,23 @@ let
|
|||||||
--replace-fail 'set(TR_USER_AGENT_PREFIX "''${TR_SEMVER}")' 'set(TR_USER_AGENT_PREFIX "3.00")'
|
--replace-fail 'set(TR_USER_AGENT_PREFIX "''${TR_SEMVER}")' 'set(TR_USER_AGENT_PREFIX "3.00")'
|
||||||
'';
|
'';
|
||||||
});
|
});
|
||||||
download-dir = "/var/media/torrents";
|
download-dir = "/var/media/torrents"; #< keep in sync with consts embedded in `torrent-done`
|
||||||
torrent-done = pkgs.writeShellApplication {
|
torrent-done = pkgs.static-nix-shell.mkBash {
|
||||||
name = "torrent-done";
|
pname = "torrent-done";
|
||||||
runtimeInputs = with pkgs; [
|
srcRoot = ./.;
|
||||||
acl
|
pkgs = [
|
||||||
coreutils
|
"acl"
|
||||||
findutils
|
"coreutils"
|
||||||
rsync
|
"findutils"
|
||||||
util-linux
|
"rsync"
|
||||||
];
|
];
|
||||||
text = ''
|
|
||||||
destructive() {
|
|
||||||
if [ -n "''${TR_DRY_RUN-}" ]; then
|
|
||||||
echo "$*"
|
|
||||||
else
|
|
||||||
"$@"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
if [[ "$TR_TORRENT_DIR" =~ ^.*freeleech.*$ ]]; then
|
|
||||||
# freeleech torrents have no place in my permanent library
|
|
||||||
echo "freeleech: nothing to do"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
if ! [[ "$TR_TORRENT_DIR" =~ ^${download-dir}/.*$ ]]; then
|
|
||||||
echo "unexpected torrent dir, aborting: $TR_TORRENT_DIR"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
REL_DIR="''${TR_TORRENT_DIR#${download-dir}/}"
|
|
||||||
MEDIA_DIR="/var/media/$REL_DIR"
|
|
||||||
|
|
||||||
destructive mkdir -p "$(dirname "$MEDIA_DIR")"
|
|
||||||
destructive rsync -arv "$TR_TORRENT_DIR/" "$MEDIA_DIR/"
|
|
||||||
# make the media rwx by anyone in the group
|
|
||||||
destructive find "$MEDIA_DIR" -type d -exec setfacl --recursive --modify d:g::rwx,o::rx {} \;
|
|
||||||
destructive find "$MEDIA_DIR" -type d -exec chmod g+rw,a+rx {} \;
|
|
||||||
|
|
||||||
# if there's a single directory inside the media dir, then inline that
|
|
||||||
subdirs=("$MEDIA_DIR"/*)
|
|
||||||
if [ ''${#subdirs} -eq 1 ]; then
|
|
||||||
dirname="''${subdirs[0]}"
|
|
||||||
if [ -d "$dirname" ]; then
|
|
||||||
mv "$dirname"/* "$MEDIA_DIR/" && rmdir "$dirname"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# remove noisy files:
|
|
||||||
find "$MEDIA_DIR/" -type f \(\
|
|
||||||
-iname 'www.YTS.*.jpg' \
|
|
||||||
-o -iname 'WWW.YIFY*.COM.jpg' \
|
|
||||||
-o -iname 'YIFY*.com.txt' \
|
|
||||||
-o -iname 'YTS*.com.txt' \
|
|
||||||
\) -exec rm {} \;
|
|
||||||
|
|
||||||
# dedupe the whole media library.
|
|
||||||
# yeah, a bit excessive: move this to a cron job if that's problematic.
|
|
||||||
destructive hardlink /var/media --reflink=always --ignore-time --verbose
|
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
lib.mkIf false #< TODO: re-enable once confident of sandboxing
|
|
||||||
{
|
{
|
||||||
sane.persist.sys.byStore.plaintext = [
|
sane.persist.sys.byStore.private = [
|
||||||
# TODO: mode? we need this specifically for the stats tracking in .config/
|
# TODO: mode? we need this specifically for the stats tracking in .config/
|
||||||
{ user = "transmission"; group = config.users.users.transmission.group; path = "/var/lib/transmission"; method = "bind"; }
|
{ user = "transmission"; group = config.users.users.transmission.group; path = "/var/lib/transmission"; method = "bind"; }
|
||||||
|
{ user = "transmission"; group = config.users.users.transmission.group; path = "/var/backup/torrents"; method = "bind"; }
|
||||||
];
|
];
|
||||||
users.users.transmission.extraGroups = [ "media" ];
|
users.users.transmission.extraGroups = [ "media" ];
|
||||||
|
|
||||||
@@ -106,8 +58,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>
|
# DOCUMENTATION/options list: <https://github.com/transmission/transmission/blob/main/docs/Editing-Configuration-Files.md#options>
|
||||||
|
|
||||||
# message-level = 3; #< enable for debug logging. 0-3, default is 2.
|
# message-level = 3; #< enable for debug logging. 0-3, default is 2.
|
||||||
# 10.0.1.6 => allow rpc only from the root servo ns. it'll tunnel things to the net, if need be.
|
# ovpns.netnsVethIpv4 => 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";
|
rpc-bind-address = config.sane.netns.ovpns.netnsVethIpv4;
|
||||||
#rpc-host-whitelist = "bt.uninsane.org";
|
#rpc-host-whitelist = "bt.uninsane.org";
|
||||||
#rpc-whitelist = "*.*.*.*";
|
#rpc-whitelist = "*.*.*.*";
|
||||||
rpc-authentication-required = true;
|
rpc-authentication-required = true;
|
||||||
@@ -118,7 +70,7 @@ lib.mkIf false #< TODO: re-enable once confident of sandboxing
|
|||||||
rpc-whitelist-enabled = false;
|
rpc-whitelist-enabled = false;
|
||||||
|
|
||||||
# force behind ovpns in case the NetworkNamespace fails somehow
|
# force behind ovpns in case the NetworkNamespace fails somehow
|
||||||
bind-address-ipv4 = "185.157.162.178";
|
bind-address-ipv4 = config.sane.netns.ovpns.netnsPubIpv4;
|
||||||
port-forwarding-enabled = false;
|
port-forwarding-enabled = false;
|
||||||
|
|
||||||
# hopefully, make the downloads world-readable
|
# hopefully, make the downloads world-readable
|
||||||
@@ -155,16 +107,31 @@ lib.mkIf false #< TODO: re-enable once confident of sandboxing
|
|||||||
script-torrent-done-filename = "${torrent-done}/bin/torrent-done";
|
script-torrent-done-filename = "${torrent-done}/bin/torrent-done";
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.services.transmission.after = [ "wireguard-wg-ovpns.service" ];
|
systemd.services.transmission = {
|
||||||
systemd.services.transmission.partOf = [ "wireguard-wg-ovpns.service" ];
|
after = [ "wireguard-wg-ovpns.service" ];
|
||||||
systemd.services.transmission.serviceConfig = {
|
partOf = [ "wireguard-wg-ovpns.service" ];
|
||||||
|
environment.TR_DEBUG = "1";
|
||||||
# run this behind the OVPN static VPN
|
# run this behind the OVPN static VPN
|
||||||
NetworkNamespacePath = "/run/netns/ovpns";
|
serviceConfig.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
|
serviceConfig.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";
|
serviceConfig.Restart = "on-failure";
|
||||||
RestartSec = "30s";
|
serviceConfig.RestartSec = "30s";
|
||||||
BindPaths = [ "/var/media" ]; #< so it can move completed torrents into the media library
|
serviceConfig.BindPaths = [ "/var/media" ]; #< so it can move completed torrents into the media library
|
||||||
|
serviceConfig.SystemCallFilter = lib.mkForce [
|
||||||
|
# the torrent-done script does stuff which fails the nixos default syscall filter.
|
||||||
|
# allow a bunch of stuff, speculatively, to hopefully fix that:
|
||||||
|
"@aio"
|
||||||
|
"@basic-io"
|
||||||
|
"@chown"
|
||||||
|
"@file-system"
|
||||||
|
"@io-event"
|
||||||
|
"@process"
|
||||||
|
"@sandbox"
|
||||||
|
"@sync"
|
||||||
|
"@system-service"
|
||||||
|
"quotactl"
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
# service to automatically backup torrents i add to transmission
|
# service to automatically backup torrents i add to transmission
|
||||||
@@ -190,7 +157,7 @@ lib.mkIf false #< TODO: re-enable once confident of sandboxing
|
|||||||
# inherit kTLS;
|
# inherit kTLS;
|
||||||
locations."/" = {
|
locations."/" = {
|
||||||
# proxyPass = "http://ovpns.uninsane.org:9091";
|
# proxyPass = "http://ovpns.uninsane.org:9091";
|
||||||
proxyPass = "http://10.0.1.6:9091";
|
proxyPass = "http://${config.sane.netns.ovpns.netnsVethIpv4}:9091";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
70
hosts/by-name/servo/services/transmission/torrent-done
Executable file
70
hosts/by-name/servo/services/transmission/torrent-done
Executable file
@@ -0,0 +1,70 @@
|
|||||||
|
#!/usr/bin/env nix-shell
|
||||||
|
#!nix-shell -i bash -p acl -p bash -p coreutils -p findutils -p rsync
|
||||||
|
|
||||||
|
# transmission invokes this with no args, and the following env vars:
|
||||||
|
# - TR_TORRENT_DIR: full path to the folder i told transmission to download it to.
|
||||||
|
# e.g. /var/media/torrents/Videos/Film/Jason.Bourne-2016
|
||||||
|
# optionally:
|
||||||
|
# - TR_DRY_RUN=1
|
||||||
|
# - TR_DEBUG=1
|
||||||
|
|
||||||
|
DOWNLOAD_DIR=/var/media/torrents
|
||||||
|
|
||||||
|
destructive() {
|
||||||
|
if [ -n "${TR_DRY_RUN-}" ]; then
|
||||||
|
echo "[dry-run] $*"
|
||||||
|
else
|
||||||
|
debug "$@"
|
||||||
|
"$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
debug() {
|
||||||
|
if [ -n "${TR_DEBUG-}" ]; then
|
||||||
|
echo "$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "TR_TORRENT_DIR=$TR_TORRENT_DIR torrent-done $*"
|
||||||
|
|
||||||
|
if [[ "$TR_TORRENT_DIR" =~ ^.*freeleech.*$ ]]; then
|
||||||
|
# freeleech torrents have no place in my permanent library
|
||||||
|
echo "freeleech: nothing to do"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
if ! [[ "$TR_TORRENT_DIR" =~ ^$DOWNLOAD_DIR/.*$ ]]; then
|
||||||
|
echo "unexpected torrent dir, aborting: $TR_TORRENT_DIR"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
REL_DIR="${TR_TORRENT_DIR#$DOWNLOAD_DIR/}"
|
||||||
|
MEDIA_DIR="/var/media/$REL_DIR"
|
||||||
|
|
||||||
|
destructive mkdir -p "$(dirname "$MEDIA_DIR")"
|
||||||
|
destructive rsync -rlv "$TR_TORRENT_DIR/" "$MEDIA_DIR/"
|
||||||
|
# make the media rwx by anyone in the group
|
||||||
|
destructive find "$MEDIA_DIR" -type d -exec setfacl --recursive --modify d:g::rwx,o::rx {} \;
|
||||||
|
destructive find "$MEDIA_DIR" -type d -exec chmod g+rw,a+rx {} \;
|
||||||
|
destructive find "$MEDIA_DIR" -type f -exec chmod g+rw,a+r {} \;
|
||||||
|
|
||||||
|
# if there's a single directory inside the media dir, then inline that
|
||||||
|
subdirs=("$MEDIA_DIR"/*)
|
||||||
|
debug "top-level items in torrent dir:" "${subdirs[@]}"
|
||||||
|
if [ ${#subdirs[@]} -eq 1 ]; then
|
||||||
|
dirname="${subdirs[0]}"
|
||||||
|
debug "exactly one top-level item, checking if directory: $dirname"
|
||||||
|
if [ -d "$dirname" ]; then
|
||||||
|
destructive mv "$dirname"/* "$MEDIA_DIR/" && destructive rmdir "$dirname"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# remove noisy files:
|
||||||
|
# -iname means "insensitive", but the syntax is NOT regex -- more similar to shell matching
|
||||||
|
destructive find "$MEDIA_DIR/" -type f \(\
|
||||||
|
-iname '*downloaded?from*' \
|
||||||
|
-o -iname 'source.txt' \
|
||||||
|
-o -iname '*upcoming?releases*' \
|
||||||
|
-o -iname 'www.YTS*.jpg' \
|
||||||
|
-o -iname 'WWW.YIFY*.COM.jpg' \
|
||||||
|
-o -iname 'YIFY*.com.txt' \
|
||||||
|
-o -iname 'YTS*.com.txt' \
|
||||||
|
\) -exec rm {} \;
|
@@ -1,162 +0,0 @@
|
|||||||
# TODO: split this file apart into smaller files to make it easier to understand
|
|
||||||
{ config, lib, pkgs, ... }:
|
|
||||||
|
|
||||||
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.ovpns = true;
|
|
||||||
visibleTo.doof = true;
|
|
||||||
description = "colin-dns-hosting";
|
|
||||||
};
|
|
||||||
|
|
||||||
sane.dns.zones."uninsane.org".TTL = 900;
|
|
||||||
|
|
||||||
# SOA record structure: <https://en.wikipedia.org/wiki/SOA_record#Structure>
|
|
||||||
# SOA MNAME RNAME (... rest)
|
|
||||||
# MNAME = Master name server for this zone. this is where update requests should be sent.
|
|
||||||
# RNAME = admin contact (encoded email address)
|
|
||||||
# Serial = YYYYMMDDNN, where N is incremented every time this file changes, to trigger secondary NS to re-fetch it.
|
|
||||||
# Refresh = how frequently secondary NS should query master
|
|
||||||
# Retry = how long secondary NS should wait until re-querying master after a failure (must be < Refresh)
|
|
||||||
# Expire = how long secondary NS should continue to reply to queries after master fails (> Refresh + Retry)
|
|
||||||
sane.dns.zones."uninsane.org".inet = {
|
|
||||||
SOA."@" = ''
|
|
||||||
ns1.uninsane.org. admin-dns.uninsane.org. (
|
|
||||||
2023092101 ; Serial
|
|
||||||
4h ; Refresh
|
|
||||||
30m ; Retry
|
|
||||||
7d ; Expire
|
|
||||||
5m) ; Negative response TTL
|
|
||||||
'';
|
|
||||||
TXT."rev" = "2023092101";
|
|
||||||
|
|
||||||
CNAME."native" = "%CNAMENATIVE%";
|
|
||||||
A."@" = "%ANATIVE%";
|
|
||||||
A."servo.wan" = "%AWAN%";
|
|
||||||
A."servo.lan" = config.sane.hosts.by-name."servo".lan-ip;
|
|
||||||
A."servo.hn" = config.sane.hosts.by-name."servo".wg-home.ip;
|
|
||||||
|
|
||||||
# XXX NS records must also not be CNAME
|
|
||||||
# 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";
|
|
||||||
NS."@" = [
|
|
||||||
"ns1.uninsane.org."
|
|
||||||
"ns2.uninsane.org."
|
|
||||||
"ns3.uninsane.org."
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
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";
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
sane.services.trust-dns.enable = true;
|
|
||||||
sane.services.trust-dns.instances = let
|
|
||||||
mkSubstitutions = flavor: {
|
|
||||||
"%AWAN%" = "$(cat '${dyn-dns.ipPath}')";
|
|
||||||
"%CNAMENATIVE%" = "servo.${flavor}";
|
|
||||||
"%ANATIVE%" = nativeAddrs."servo.${flavor}";
|
|
||||||
"%AOVPNS%" = "185.157.162.178";
|
|
||||||
};
|
|
||||||
in
|
|
||||||
{
|
|
||||||
wan = {
|
|
||||||
substitutions = mkSubstitutions "wan";
|
|
||||||
listenAddrsIpv4 = [
|
|
||||||
nativeAddrs."servo.lan"
|
|
||||||
bindOvpn
|
|
||||||
bindDoof
|
|
||||||
];
|
|
||||||
};
|
|
||||||
lan = {
|
|
||||||
substitutions = mkSubstitutions "lan";
|
|
||||||
listenAddrsIpv4 = [ nativeAddrs."servo.lan" ];
|
|
||||||
port = 1053;
|
|
||||||
};
|
|
||||||
hn = {
|
|
||||||
substitutions = mkSubstitutions "hn";
|
|
||||||
listenAddrsIpv4 = [ nativeAddrs."servo.hn" ];
|
|
||||||
port = 1053;
|
|
||||||
};
|
|
||||||
# hn-resolver = {
|
|
||||||
# # don't need %AWAN% here because we forward to the hn instance.
|
|
||||||
# listenAddrsIpv4 = [ nativeAddrs."servo.hn" ];
|
|
||||||
# extraConfig = {
|
|
||||||
# zones = [
|
|
||||||
# {
|
|
||||||
# zone = "uninsane.org";
|
|
||||||
# zone_type = "Forward";
|
|
||||||
# stores = {
|
|
||||||
# type = "forward";
|
|
||||||
# name_servers = [
|
|
||||||
# {
|
|
||||||
# socket_addr = "${nativeAddrs."servo.hn"}:1053";
|
|
||||||
# protocol = "udp";
|
|
||||||
# trust_nx_responses = true;
|
|
||||||
# }
|
|
||||||
# ];
|
|
||||||
# };
|
|
||||||
# }
|
|
||||||
# {
|
|
||||||
# # forward the root zone to the local DNS resolver
|
|
||||||
# zone = ".";
|
|
||||||
# zone_type = "Forward";
|
|
||||||
# stores = {
|
|
||||||
# type = "forward";
|
|
||||||
# name_servers = [
|
|
||||||
# {
|
|
||||||
# socket_addr = "127.0.0.53:53";
|
|
||||||
# protocol = "udp";
|
|
||||||
# trust_nx_responses = true;
|
|
||||||
# }
|
|
||||||
# ];
|
|
||||||
# };
|
|
||||||
# }
|
|
||||||
# ];
|
|
||||||
# };
|
|
||||||
# };
|
|
||||||
};
|
|
||||||
|
|
||||||
sane.services.dyn-dns.restartOnChange = [
|
|
||||||
"trust-dns-wan.service"
|
|
||||||
"trust-dns-lan.service"
|
|
||||||
"trust-dns-hn.service"
|
|
||||||
# "trust-dns-hn-resolver.service" # doesn't need restart because it doesn't know about WAN IP
|
|
||||||
];
|
|
||||||
}
|
|
@@ -25,10 +25,14 @@
|
|||||||
|
|
||||||
# moby has to run recent kernels (defined elsewhere).
|
# moby has to run recent kernels (defined elsewhere).
|
||||||
# meanwhile, kernel variation plays some minor role in things like sandboxing (landlock) and capabilities.
|
# meanwhile, kernel variation plays some minor role in things like sandboxing (landlock) and capabilities.
|
||||||
|
# - as of 2024/08/xx, my boot fails on 6.6, but works on 6.9 and (probably; recently) 6.8.
|
||||||
# simpler to keep near the latest kernel on all devices,
|
# simpler to keep near the latest kernel on all devices,
|
||||||
# and also makes certain that any weird system-level bugs i see aren't likely to be stale kernel bugs.
|
# and also makes certain that any weird system-level bugs i see aren't likely to be stale kernel bugs.
|
||||||
# servo needs zfs though, which doesn't support every kernel.
|
# servo needs zfs though, which doesn't support every kernel.
|
||||||
boot.kernelPackages = lib.mkDefault pkgs.zfs.latestCompatibleLinuxPackages;
|
#
|
||||||
|
# further, `zfs.latestCompatibleLinuxPackage` ocassionally _downgrades_. e.g. when 6.8 EOL'd, it went back to 6.6.
|
||||||
|
# therefore, we have to use `zfs_unstable` (!!)
|
||||||
|
boot.kernelPackages = lib.mkDefault pkgs.zfs_unstable.latestCompatibleLinuxPackages;
|
||||||
|
|
||||||
# hack in the `boot.shell_on_fail` arg since that doesn't always seem to work.
|
# hack in the `boot.shell_on_fail` arg since that doesn't always seem to work.
|
||||||
boot.initrd.preFailCommands = "allowShell=1";
|
boot.initrd.preFailCommands = "allowShell=1";
|
||||||
@@ -46,5 +50,6 @@
|
|||||||
# manifests as spurious "No space left on device" when trying to install watches,
|
# manifests as spurious "No space left on device" when trying to install watches,
|
||||||
# e.g. in dyn-dns by `systemctl start dyn-dns-watcher.path`.
|
# e.g. in dyn-dns by `systemctl start dyn-dns-watcher.path`.
|
||||||
# see: <https://askubuntu.com/questions/828779/failed-to-add-run-systemd-ask-password-to-directory-watch-no-space-left-on-dev>
|
# see: <https://askubuntu.com/questions/828779/failed-to-add-run-systemd-ask-password-to-directory-watch-no-space-left-on-dev>
|
||||||
boot.kernel.sysctl."fs.inotify.max_user_watches" = 1048576;
|
boot.kernel.sysctl."fs.inotify.max_user_watches" = 4194304;
|
||||||
|
boot.kernel.sysctl."fs.inotify.max_user_instances" = 4194304;
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
{ lib, pkgs, ... }:
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
./boot.nix
|
./boot.nix
|
||||||
@@ -10,7 +10,6 @@
|
|||||||
./machine-id.nix
|
./machine-id.nix
|
||||||
./net
|
./net
|
||||||
./nix.nix
|
./nix.nix
|
||||||
./persist.nix
|
|
||||||
./polyunfill.nix
|
./polyunfill.nix
|
||||||
./programs
|
./programs
|
||||||
./quirks.nix
|
./quirks.nix
|
||||||
|
@@ -1,14 +1,11 @@
|
|||||||
# where to find good stuff?
|
# where to find good stuff?
|
||||||
# - universal search/directory: <https://podcastindex.org>
|
# - universal search/directory: <https://podcastindex.org>
|
||||||
|
# - list of lists: <https://en.wikipedia.org/wiki/Category:Lists_of_podcasts>
|
||||||
# - podcasts w/ a community: <https://lemmyverse.net/communities?query=podcast>
|
# - podcasts w/ a community: <https://lemmyverse.net/communities?query=podcast>
|
||||||
# - podcast rec thread: <https://lemmy.ml/post/1565858>
|
# - podcast recs:
|
||||||
|
# - active lemmy: <https://slrpnk.net/c/podcasts>
|
||||||
|
# - old thread: <https://lemmy.ml/post/1565858>
|
||||||
#
|
#
|
||||||
# candidates:
|
|
||||||
# - The Nonlinear Library (podcast): <https://forum.effectivealtruism.org/posts/JTZTBienqWEAjGDRv/listen-to-more-ea-content-with-the-nonlinear-library>
|
|
||||||
# - has ~10 posts per day, text-to-speech; i would need better tagging before adding this
|
|
||||||
# - <https://www.metaculus.com/questions/11102/introducing-the-metaculus-journal-podcast/>
|
|
||||||
# - dead since 2022/10 - 2023/03
|
|
||||||
|
|
||||||
{ lib, sane-data, ... }:
|
{ lib, sane-data, ... }:
|
||||||
let
|
let
|
||||||
hourly = { freq = "hourly"; };
|
hourly = { freq = "hourly"; };
|
||||||
@@ -60,8 +57,10 @@ let
|
|||||||
};
|
};
|
||||||
|
|
||||||
podcasts = [
|
podcasts = [
|
||||||
|
(fromDb "404media.co/the-404-media-podcast" // tech)
|
||||||
(fromDb "acquiredlpbonussecretsecret.libsyn.com" // tech) # ACQ2 - more "Acquired" episodes
|
(fromDb "acquiredlpbonussecretsecret.libsyn.com" // tech) # ACQ2 - more "Acquired" episodes
|
||||||
(fromDb "allinchamathjason.libsyn.com" // pol)
|
(fromDb "allinchamathjason.libsyn.com" // pol)
|
||||||
|
(fromDb "api.oyez.org/podcasts/oral-arguments/2015" // pol) # Supreme Court Oral Arguments ("2015" in URL means nothing -- it's still updated)
|
||||||
(fromDb "anchor.fm/s/34c7232c/podcast/rss" // tech) # Civboot -- https://anchor.fm/civboot
|
(fromDb "anchor.fm/s/34c7232c/podcast/rss" // tech) # Civboot -- https://anchor.fm/civboot
|
||||||
(fromDb "anchor.fm/s/2da69154/podcast/rss" // tech) # POD OF JAKE -- https://podofjake.com/
|
(fromDb "anchor.fm/s/2da69154/podcast/rss" // tech) # POD OF JAKE -- https://podofjake.com/
|
||||||
(fromDb "cast.postmarketos.org" // tech)
|
(fromDb "cast.postmarketos.org" // tech)
|
||||||
@@ -73,17 +72,22 @@ let
|
|||||||
(fromDb "feeds.feedburner.com/80000HoursPodcast" // rat)
|
(fromDb "feeds.feedburner.com/80000HoursPodcast" // rat)
|
||||||
(fromDb "feeds.feedburner.com/dancarlin/history" // rat)
|
(fromDb "feeds.feedburner.com/dancarlin/history" // rat)
|
||||||
(fromDb "feeds.feedburner.com/radiolab" // pol) # Radiolab -- also available here, but ONLY OVER HTTP: <http://feeds.wnyc.org/radiolab>
|
(fromDb "feeds.feedburner.com/radiolab" // pol) # Radiolab -- also available here, but ONLY OVER HTTP: <http://feeds.wnyc.org/radiolab>
|
||||||
|
(fromDb "feeds.megaphone.fm/GLT1412515089" // pol) # JRE: Joe Rogan Experience
|
||||||
(fromDb "feeds.megaphone.fm/behindthebastards" // pol) # also Maggie Killjoy
|
(fromDb "feeds.megaphone.fm/behindthebastards" // pol) # also Maggie Killjoy
|
||||||
|
(fromDb "feeds.megaphone.fm/cspantheweekly" // pol)
|
||||||
(fromDb "feeds.megaphone.fm/recodedecode" // tech) # The Verge - Decoder
|
(fromDb "feeds.megaphone.fm/recodedecode" // tech) # The Verge - Decoder
|
||||||
(fromDb "feeds.simplecast.com/54nAGcIl" // pol) # The Daily
|
|
||||||
(fromDb "feeds.simplecast.com/82FI35Px" // pol) # Ezra Klein Show
|
(fromDb "feeds.simplecast.com/82FI35Px" // pol) # Ezra Klein Show
|
||||||
(fromDb "feeds.simplecast.com/wgl4xEgL" // rat) # Econ Talk
|
(fromDb "feeds.simplecast.com/wgl4xEgL" // rat) # Econ Talk
|
||||||
(fromDb "feeds.simplecast.com/xKJ93w_w" // uncat) # Atlas Obscura
|
(fromDb "feeds.simplecast.com/xKJ93w_w" // uncat) # Atlas Obscura
|
||||||
(fromDb "feeds.transistor.fm/acquired" // tech)
|
(fromDb "feeds.transistor.fm/acquired" // tech)
|
||||||
|
(fromDb "feeds.transistor.fm/complex-systems-with-patrick-mckenzie-patio11" // tech) # Patrick Mackenzie (from Bits About Money)
|
||||||
|
(fromDb "feeds.twit.tv/floss.xml" // tech)
|
||||||
(fromDb "fulltimenix.com" // tech)
|
(fromDb "fulltimenix.com" // tech)
|
||||||
(fromDb "futureofcoding.org/episodes" // tech)
|
(fromDb "futureofcoding.org/episodes" // tech)
|
||||||
(fromDb "hackerpublicradio.org" // tech)
|
(fromDb "hackerpublicradio.org" // tech)
|
||||||
(fromDb "lexfridman.com/podcast" // rat)
|
(fromDb "lexfridman.com/podcast" // rat)
|
||||||
|
(fromDb "linktr.ee/betteroffline" // pol)
|
||||||
|
(fromDb "linuxdevtime.com" // tech)
|
||||||
(fromDb "mapspodcast.libsyn.com" // uncat) # Multidisciplinary Association for Psychedelic Studies
|
(fromDb "mapspodcast.libsyn.com" // uncat) # Multidisciplinary Association for Psychedelic Studies
|
||||||
(fromDb "microarch.club" // tech)
|
(fromDb "microarch.club" // tech)
|
||||||
(fromDb "mintcast.org" // tech)
|
(fromDb "mintcast.org" // tech)
|
||||||
@@ -91,8 +95,8 @@ let
|
|||||||
(fromDb "omny.fm/shows/cool-people-who-did-cool-stuff" // pol) # Maggie Killjoy -- referenced by Cory Doctorow
|
(fromDb "omny.fm/shows/cool-people-who-did-cool-stuff" // pol) # Maggie Killjoy -- referenced by Cory Doctorow
|
||||||
(fromDb "omny.fm/shows/money-stuff-the-podcast") # Matt Levine
|
(fromDb "omny.fm/shows/money-stuff-the-podcast") # Matt Levine
|
||||||
(fromDb "omny.fm/shows/the-dollop-with-dave-anthony-and-gareth-reynolds") # The Dollop history/comedy
|
(fromDb "omny.fm/shows/the-dollop-with-dave-anthony-and-gareth-reynolds") # The Dollop history/comedy
|
||||||
|
(fromDb "omny.fm/shows/weird-little-guys") # Cool Zone Media
|
||||||
(fromDb "originstories.libsyn.com" // uncat)
|
(fromDb "originstories.libsyn.com" // uncat)
|
||||||
(fromDb "podcast.posttv.com/itunes/post-reports.xml" // pol)
|
|
||||||
(fromDb "politicalorphanage.libsyn.com" // pol)
|
(fromDb "politicalorphanage.libsyn.com" // pol)
|
||||||
(fromDb "reverseengineering.libsyn.com/rss" // tech) # UnNamed Reverse Engineering Podcast
|
(fromDb "reverseengineering.libsyn.com/rss" // tech) # UnNamed Reverse Engineering Podcast
|
||||||
(fromDb "rss.acast.com/deconstructed") # The Intercept - Deconstructed
|
(fromDb "rss.acast.com/deconstructed") # The Intercept - Deconstructed
|
||||||
@@ -103,23 +107,26 @@ let
|
|||||||
(fromDb "seattlenice.buzzsprout.com" // pol)
|
(fromDb "seattlenice.buzzsprout.com" // pol)
|
||||||
(fromDb "srslywrong.com" // pol)
|
(fromDb "srslywrong.com" // pol)
|
||||||
(fromDb "sharkbytes.transistor.fm" // tech) # Wireshark Podcast o_0
|
(fromDb "sharkbytes.transistor.fm" // tech) # Wireshark Podcast o_0
|
||||||
|
(fromDb "sharptech.fm/feed/podcast" // tech)
|
||||||
(fromDb "sscpodcast.libsyn.com" // rat) # Astral Codex Ten
|
(fromDb "sscpodcast.libsyn.com" // rat) # Astral Codex Ten
|
||||||
(fromDb "talesfromthebridge.buzzsprout.com" // tech) # Sci-Fi? has Peter Watts; author of No Moods, Ads or Cutesy Fucking Icons (rifters.com)
|
(fromDb "talesfromthebridge.buzzsprout.com" // tech) # Sci-Fi? has Peter Watts; author of No Moods, Ads or Cutesy Fucking Icons (rifters.com)
|
||||||
(fromDb "theamphour.com" // tech)
|
(fromDb "theamphour.com" // tech)
|
||||||
(fromDb "techtalesshow.com" // tech) # Corbin Davenport
|
(fromDb "techtalesshow.com" // tech) # Corbin Davenport
|
||||||
(fromDb "techwontsave.us" // pol) # rec by Cory Doctorow
|
(fromDb "techwontsave.us" // pol) # rec by Cory Doctorow
|
||||||
(fromDb "wakingup.libsyn.com" // pol) # Sam Harris
|
|
||||||
(fromDb "werenotwrong.fireside.fm" // pol)
|
(fromDb "werenotwrong.fireside.fm" // pol)
|
||||||
(mkPod "https://sfconservancy.org/casts/the-corresponding-source/feeds/ogg/" // tech)
|
(mkPod "https://sfconservancy.org/casts/the-corresponding-source/feeds/ogg/" // tech)
|
||||||
|
|
||||||
# (fromDb "feeds.libsyn.com/421877" // rat) # Less Wrong Curated
|
# (fromDb "feeds.libsyn.com/421877" // rat) # Less Wrong Curated
|
||||||
# (fromDb "feeds.megaphone.fm/hubermanlab" // uncat) # Daniel Huberman on sleep
|
# (fromDb "feeds.megaphone.fm/hubermanlab" // uncat) # Daniel Huberman on sleep
|
||||||
|
# (fromDb "feeds.simplecast.com/54nAGcIl" // pol) # The Daily
|
||||||
# (fromDb "feeds.simplecast.com/l2i9YnTd" // tech // pol) # Hard Fork (NYtimes tech)
|
# (fromDb "feeds.simplecast.com/l2i9YnTd" // tech // pol) # Hard Fork (NYtimes tech)
|
||||||
|
# (fromDb "podcast.posttv.com/itunes/post-reports.xml" // pol)
|
||||||
# (fromDb "podcast.thelinuxexp.com" // tech) # low-brow linux/foss PR announcements
|
# (fromDb "podcast.thelinuxexp.com" // tech) # low-brow linux/foss PR announcements
|
||||||
# (fromDb "rss.art19.com/your-welcome" // pol) # Michael Malice - Your Welcome -- also available here: <https://origin.podcastone.com/podcast?categoryID2=2232>
|
# (fromDb "rss.art19.com/your-welcome" // pol) # Michael Malice - Your Welcome -- also available here: <https://origin.podcastone.com/podcast?categoryID2=2232>
|
||||||
# (fromDb "rss.prod.firstlook.media/deconstructed/podcast.rss" // pol) #< possible URL rot
|
# (fromDb "rss.prod.firstlook.media/deconstructed/podcast.rss" // pol) #< possible URL rot
|
||||||
# (fromDb "rss.prod.firstlook.media/intercepted/podcast.rss" // pol) #< possible URL rot
|
# (fromDb "rss.prod.firstlook.media/intercepted/podcast.rss" // pol) #< possible URL rot
|
||||||
# (fromDb "trashfuturepodcast.podbean.com" // pol) # rec by Cory Doctorow, but way rambly
|
# (fromDb "trashfuturepodcast.podbean.com" // pol) # rec by Cory Doctorow, but way rambly
|
||||||
|
# (fromDb "wakingup.libsyn.com" // pol) # Sam Harris, but he just repeats himself now
|
||||||
# (mkPod "https://anchor.fm/s/21bc734/podcast/rss" // pol // infrequent) # Emerge: making sense of what's next -- <https://www.whatisemerging.com/emergepodcast>
|
# (mkPod "https://anchor.fm/s/21bc734/podcast/rss" // pol // infrequent) # Emerge: making sense of what's next -- <https://www.whatisemerging.com/emergepodcast>
|
||||||
# (mkPod "https://audioboom.com/channels/5097784.rss" // tech) # Lateral with Tom Scott
|
# (mkPod "https://audioboom.com/channels/5097784.rss" // tech) # Lateral with Tom Scott
|
||||||
# (mkPod "https://feeds.megaphone.fm/RUNMED9919162779" // pol // infrequent) # The Witch Trials of J.K. Rowling: <https://www.thefp.com/witchtrials>
|
# (mkPod "https://feeds.megaphone.fm/RUNMED9919162779" // pol // infrequent) # The Witch Trials of J.K. Rowling: <https://www.thefp.com/witchtrials>
|
||||||
@@ -130,11 +137,13 @@ let
|
|||||||
(fromDb "acoup.blog/feed") # history, states. author: <https://historians.social/@bretdevereaux/following>
|
(fromDb "acoup.blog/feed") # history, states. author: <https://historians.social/@bretdevereaux/following>
|
||||||
(fromDb "amosbbatto.wordpress.com" // tech)
|
(fromDb "amosbbatto.wordpress.com" // tech)
|
||||||
(fromDb "anish.lakhwara.com" // tech)
|
(fromDb "anish.lakhwara.com" // tech)
|
||||||
|
(fromDb "antipope.org") # Charles Stross
|
||||||
(fromDb "apenwarr.ca/log/rss.php" // tech) # CEO of tailscale
|
(fromDb "apenwarr.ca/log/rss.php" // tech) # CEO of tailscale
|
||||||
(fromDb "applieddivinitystudies.com" // rat)
|
(fromDb "applieddivinitystudies.com" // rat)
|
||||||
(fromDb "artemis.sh" // tech)
|
(fromDb "artemis.sh" // tech)
|
||||||
(fromDb "ascii.textfiles.com" // tech) # Jason Scott
|
(fromDb "ascii.textfiles.com" // tech) # Jason Scott
|
||||||
(fromDb "austinvernon.site" // tech)
|
(fromDb "austinvernon.site" // tech)
|
||||||
|
(fromDb "buttondown.email" // tech)
|
||||||
(fromDb "ben-evans.com/benedictevans" // pol)
|
(fromDb "ben-evans.com/benedictevans" // pol)
|
||||||
(fromDb "bitbashing.io" // tech)
|
(fromDb "bitbashing.io" // tech)
|
||||||
(fromDb "bitsaboutmoney.com" // uncat)
|
(fromDb "bitsaboutmoney.com" // uncat)
|
||||||
@@ -143,6 +152,7 @@ let
|
|||||||
(fromDb "blog.jmp.chat" // tech)
|
(fromDb "blog.jmp.chat" // tech)
|
||||||
(fromDb "blog.rust-lang.org" // tech)
|
(fromDb "blog.rust-lang.org" // tech)
|
||||||
(fromDb "blog.thalheim.io" // tech) # Mic92
|
(fromDb "blog.thalheim.io" // tech) # Mic92
|
||||||
|
(fromDb "blog.brixit.nl" // tech) # Martijn Braam
|
||||||
(fromDb "bunniestudios.com" // tech) # Bunnie Juang
|
(fromDb "bunniestudios.com" // tech) # Bunnie Juang
|
||||||
(fromDb "capitolhillseattle.com" // pol)
|
(fromDb "capitolhillseattle.com" // pol)
|
||||||
(fromDb "edwardsnowden.substack.com" // pol // text)
|
(fromDb "edwardsnowden.substack.com" // pol // text)
|
||||||
@@ -155,6 +165,7 @@ let
|
|||||||
(fromDb "interconnected.org/home/feed" // rat) # Matt Webb -- engineering-ish, but dreamy
|
(fromDb "interconnected.org/home/feed" // rat) # Matt Webb -- engineering-ish, but dreamy
|
||||||
(fromDb "jeffgeerling.com" // tech)
|
(fromDb "jeffgeerling.com" // tech)
|
||||||
(fromDb "jefftk.com" // tech)
|
(fromDb "jefftk.com" // tech)
|
||||||
|
(fromDb "justine.lol" // tech)
|
||||||
(fromDb "jwz.org/blog" // tech // pol) # DNA lounge guy, loooong-time blogger
|
(fromDb "jwz.org/blog" // tech // pol) # DNA lounge guy, loooong-time blogger
|
||||||
(fromDb "kill-the-newsletter.com/feeds/joh91bv7am2pnznv.xml" // pol) # Matt Levine - Money Stuff
|
(fromDb "kill-the-newsletter.com/feeds/joh91bv7am2pnznv.xml" // pol) # Matt Levine - Money Stuff
|
||||||
(fromDb "kosmosghost.github.io/index.xml" // tech)
|
(fromDb "kosmosghost.github.io/index.xml" // tech)
|
||||||
@@ -196,6 +207,7 @@ let
|
|||||||
(fromDb "willow.phantoma.online") # wizard@xyzzy.link
|
(fromDb "willow.phantoma.online") # wizard@xyzzy.link
|
||||||
(fromDb "xn--gckvb8fzb.com" // tech)
|
(fromDb "xn--gckvb8fzb.com" // tech)
|
||||||
(fromDb "xorvoid.com" // tech)
|
(fromDb "xorvoid.com" // tech)
|
||||||
|
(fromDb "www.thebignewsletter.com" // pol)
|
||||||
(mkSubstack "astralcodexten" // rat // daily) # Scott Alexander
|
(mkSubstack "astralcodexten" // rat // daily) # Scott Alexander
|
||||||
(mkSubstack "eliqian" // rat // weekly)
|
(mkSubstack "eliqian" // rat // weekly)
|
||||||
(mkSubstack "oversharing" // pol // daily)
|
(mkSubstack "oversharing" // pol // daily)
|
||||||
@@ -232,15 +244,16 @@ let
|
|||||||
(fromDb "youtube.com/@Exurb1a")
|
(fromDb "youtube.com/@Exurb1a")
|
||||||
(fromDb "youtube.com/@hbomberguy")
|
(fromDb "youtube.com/@hbomberguy")
|
||||||
(fromDb "youtube.com/@JackStauber")
|
(fromDb "youtube.com/@JackStauber")
|
||||||
|
(fromDb "youtube.com/@mii_beta" // tech) # Baby Wogue / gnome reviewer
|
||||||
(fromDb "youtube.com/@NativLang")
|
(fromDb "youtube.com/@NativLang")
|
||||||
(fromDb "youtube.com/@PolyMatter")
|
(fromDb "youtube.com/@PolyMatter")
|
||||||
(fromDb "youtube.com/@TechnologyConnections" // tech)
|
(fromDb "youtube.com/@TechnologyConnections" // tech)
|
||||||
(fromDb "youtube.com/@TheB1M")
|
(fromDb "youtube.com/@TheB1M")
|
||||||
(fromDb "youtube.com/@TomScottGo")
|
(fromDb "youtube.com/@TomScottGo")
|
||||||
(fromDb "youtube.com/@Vihart")
|
(fromDb "youtube.com/@Vihart")
|
||||||
(fromDb "youtube.com/@Vox")
|
|
||||||
# (fromDb "youtube.com/@Vsauce") # they're all like 1-minute long videos now? what happened @Vsauce?
|
|
||||||
|
|
||||||
|
# (fromDb "youtube.com/@Vox")
|
||||||
|
# (fromDb "youtube.com/@Vsauce") # they're all like 1-minute long videos now? what happened @Vsauce?
|
||||||
# (fromDb "youtube.com/@rossmanngroup" // pol // tech) # Louis Rossmann
|
# (fromDb "youtube.com/@rossmanngroup" // pol // tech) # Louis Rossmann
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
# - x-systemd options: <https://www.freedesktop.org/software/systemd/man/systemd.mount.html>
|
# - x-systemd options: <https://www.freedesktop.org/software/systemd/man/systemd.mount.html>
|
||||||
# - fuse options: `man mount.fuse`
|
# - fuse options: `man mount.fuse`
|
||||||
|
|
||||||
{ config, lib, pkgs, sane-lib, utils, ... }:
|
{ config, lib, utils, ... }:
|
||||||
|
|
||||||
let
|
let
|
||||||
fsOpts = rec {
|
fsOpts = rec {
|
||||||
@@ -26,10 +26,6 @@ let
|
|||||||
# lazyMount: defer mounting until first access from userspace.
|
# lazyMount: defer mounting until first access from userspace.
|
||||||
# see: `man systemd.automount`, `man automount`, `man autofs`
|
# see: `man systemd.automount`, `man automount`, `man autofs`
|
||||||
lazyMount = noauto ++ automount;
|
lazyMount = noauto ++ automount;
|
||||||
wg = [
|
|
||||||
"x-systemd.requires=wireguard-wg-home.service"
|
|
||||||
"x-systemd.after=wireguard-wg-home.service"
|
|
||||||
];
|
|
||||||
|
|
||||||
fuse = [
|
fuse = [
|
||||||
"allow_other" # allow users other than the one who mounts it to access it. needed, if systemd is the one mounting this fs (as root)
|
"allow_other" # allow users other than the one who mounts it to access it. needed, if systemd is the one mounting this fs (as root)
|
||||||
@@ -49,7 +45,7 @@ let
|
|||||||
"gid=100"
|
"gid=100"
|
||||||
];
|
];
|
||||||
|
|
||||||
ssh = common ++ fuse ++ [
|
ssh = common ++ fuseColin ++ [
|
||||||
"identityfile=/home/colin/.ssh/id_ed25519"
|
"identityfile=/home/colin/.ssh/id_ed25519"
|
||||||
# i *think* idmap=user means that `colin` on `localhost` and `colin` on the remote are actually treated as the same user, even if their uid/gid differs?
|
# i *think* idmap=user means that `colin` on `localhost` and `colin` on the remote are actually treated as the same user, even if their uid/gid differs?
|
||||||
# i.e., local colin's id is translated to/from remote colin's id on every operation?
|
# i.e., local colin's id is translated to/from remote colin's id on every operation?
|
||||||
@@ -68,39 +64,6 @@ let
|
|||||||
# # we don't transform_symlinks because that breaks the validity of remote /nix stores
|
# # we don't transform_symlinks because that breaks the validity of remote /nix stores
|
||||||
# "sftp_server=/run/wrappers/bin/sudo\\040/run/current-system/sw/libexec/sftp-server"
|
# "sftp_server=/run/wrappers/bin/sudo\\040/run/current-system/sw/libexec/sftp-server"
|
||||||
# ];
|
# ];
|
||||||
# in the event of hunt NFS mounts, consider:
|
|
||||||
# - <https://unix.stackexchange.com/questions/31979/stop-broken-nfs-mounts-from-locking-a-directory>
|
|
||||||
|
|
||||||
# NFS options: <https://linux.die.net/man/5/nfs>
|
|
||||||
# actimeo=n = how long (in seconds) to cache file/dir attributes (default: 3-60s)
|
|
||||||
# bg = retry failed mounts in the background
|
|
||||||
# retry=n = for how many minutes `mount` will retry NFS mount operation
|
|
||||||
# intr = allow Ctrl+C to abort I/O (it will error with `EINTR`)
|
|
||||||
# soft = on "major timeout", report I/O error to userspace
|
|
||||||
# softreval = on "major timeout", service the request using known-stale cache results instead of erroring -- if such cache data exists
|
|
||||||
# retrans=n = how many times to retry a NFS request before giving userspace a "server not responding" error (default: 3)
|
|
||||||
# timeo=n = number of *deciseconds* to wait for a response before retrying it (default: 600)
|
|
||||||
# note: client uses a linear backup, so the second request will have double this timeout, then triple, etc.
|
|
||||||
# proto=udp = encapsulate protocol ops inside UDP packets instead of a TCP session.
|
|
||||||
# requires `nfsvers=3` and a kernel compiled with `NFS_DISABLE_UDP_SUPPORT=n`.
|
|
||||||
# UDP might be preferable to TCP because the latter is liable to hang for ~100s (kernel TCP timeout) after a link drop.
|
|
||||||
# however, even UDP has issues with `umount` hanging.
|
|
||||||
#
|
|
||||||
# N.B.: don't change these without first testing the behavior of sandboxed apps on a flaky network.
|
|
||||||
nfs = common ++ [
|
|
||||||
# "actimeo=5"
|
|
||||||
# "bg"
|
|
||||||
"retrans=1"
|
|
||||||
"retry=0"
|
|
||||||
# "intr"
|
|
||||||
"soft"
|
|
||||||
"softreval"
|
|
||||||
"timeo=30"
|
|
||||||
"nofail" # don't fail remote-fs.target when this mount fails (not an option for sshfs else would be common)
|
|
||||||
# "proto=udp" # default kernel config doesn't support NFS over UDP: <https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1964093> (see comment 11).
|
|
||||||
# "nfsvers=3" # NFSv4+ doesn't support UDP at *all*. it's ok to omit nfsvers -- server + client will negotiate v3 based on udp requirement. but omitting causes confusing mount errors when the server is *offline*, because the client defaults to v4 and thinks the udp option is a config error.
|
|
||||||
# "x-systemd.idle-timeout=10" # auto-unmount after this much inactivity
|
|
||||||
];
|
|
||||||
|
|
||||||
# manually perform a ftp mount via e.g.
|
# manually perform a ftp mount via e.g.
|
||||||
# curlftpfs -o ftpfs_debug=2,user=anonymous:anonymous,connect_timeout=10 -f -s ftp://servo-hn /mnt/my-ftp
|
# curlftpfs -o ftpfs_debug=2,user=anonymous:anonymous,connect_timeout=10 -f -s ftp://servo-hn /mnt/my-ftp
|
||||||
@@ -111,66 +74,207 @@ let
|
|||||||
"connect_timeout=20"
|
"connect_timeout=20"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
remoteHome = host: {
|
|
||||||
|
ifSshAuthorized = lib.mkIf config.sane.hosts.by-name."${config.networking.hostName}".ssh.authorized;
|
||||||
|
|
||||||
|
remoteHome = name: { host ? name }: {
|
||||||
sane.programs.sshfs-fuse.enableFor.system = true;
|
sane.programs.sshfs-fuse.enableFor.system = true;
|
||||||
fileSystems."/mnt/${host}/home" = {
|
system.fsPackages = [
|
||||||
device = "colin@${host}:/home/colin";
|
config.sane.programs.sshfs-fuse.package
|
||||||
fsType = "fuse.sshfs";
|
];
|
||||||
options = fsOpts.sshColin ++ fsOpts.lazyMount;
|
fileSystems."/mnt/${name}/home" = {
|
||||||
|
device = "sshfs#colin@${host}:/home/colin";
|
||||||
|
fsType = "fuse3";
|
||||||
|
options = fsOpts.sshColin ++ fsOpts.lazyMount ++ [
|
||||||
|
# drop_privileges: after `mount.fuse3` opens /dev/fuse, it will drop all capabilities before invoking sshfs
|
||||||
|
"drop_privileges"
|
||||||
|
"auto_unmount" #< ensures that when the fs exits, it releases its mountpoint. then systemd can recognize it as failed.
|
||||||
|
];
|
||||||
noCheck = true;
|
noCheck = true;
|
||||||
};
|
};
|
||||||
sane.fs."/mnt/${host}/home" = sane-lib.fs.wanted {
|
sane.fs."/mnt/${name}/home" = {
|
||||||
dir.acl.user = "colin";
|
dir.acl.user = "colin";
|
||||||
dir.acl.group = "users";
|
dir.acl.group = "users";
|
||||||
dir.acl.mode = "0700";
|
dir.acl.mode = "0700";
|
||||||
|
wantedBy = [ "default.target" ];
|
||||||
|
mount.depends = [ "network-online.target" ];
|
||||||
|
mount.mountConfig.ExecSearchPath = [ "/run/current-system/sw/bin" ];
|
||||||
|
mount.mountConfig.User = "colin";
|
||||||
|
mount.mountConfig.AmbientCapabilities = "CAP_SETPCAP CAP_SYS_ADMIN";
|
||||||
|
# hardening (systemd-analyze security mnt-desko-home.mount):
|
||||||
|
# TODO: i can't use ProtectSystem=full here, because i can't create a new mount space; but...
|
||||||
|
# with drop_privileges, i *could* sandbox the actual `sshfs` program using e.g. bwrap
|
||||||
|
mount.mountConfig.CapabilityBoundingSet = "CAP_SETPCAP CAP_SYS_ADMIN";
|
||||||
|
mount.mountConfig.LockPersonality = true;
|
||||||
|
mount.mountConfig.MemoryDenyWriteExecute = true;
|
||||||
|
mount.mountConfig.NoNewPrivileges = true;
|
||||||
|
mount.mountConfig.ProtectClock = true;
|
||||||
|
mount.mountConfig.ProtectHostname = true;
|
||||||
|
mount.mountConfig.RemoveIPC = true;
|
||||||
|
mount.mountConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6";
|
||||||
|
#VVV this includes anything it reads from, e.g. /bin/sh; /nix/store/...
|
||||||
|
# see `systemd-analyze filesystems` for a full list
|
||||||
|
mount.mountConfig.RestrictFileSystems = "@common-block @basic-api fuse";
|
||||||
|
mount.mountConfig.RestrictRealtime = true;
|
||||||
|
mount.mountConfig.RestrictSUIDSGID = true;
|
||||||
|
mount.mountConfig.SystemCallArchitectures = "native";
|
||||||
|
mount.mountConfig.SystemCallFilter = [
|
||||||
|
"@system-service"
|
||||||
|
"@mount"
|
||||||
|
"~@chown"
|
||||||
|
"~@cpu-emulation"
|
||||||
|
"~@keyring"
|
||||||
|
# could remove almost all io calls, however one has to keep `open`, and `write`, to communicate with the fuse device.
|
||||||
|
# so that's pretty useless as a way to prevent write access
|
||||||
|
];
|
||||||
|
mount.mountConfig.IPAddressDeny = "any";
|
||||||
|
mount.mountConfig.IPAddressAllow = "10.0.0.0/8";
|
||||||
|
mount.mountConfig.DevicePolicy = "closed"; # only allow /dev/{null,zero,full,random,urandom}
|
||||||
|
mount.mountConfig.DeviceAllow = "/dev/fuse";
|
||||||
|
# mount.mountConfig.RestrictNamespaces = true; #< my sshfs sandboxing uses bwrap
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
remoteServo = subdir: {
|
remoteServo = subdir: let
|
||||||
|
localPath = "/mnt/servo/${subdir}";
|
||||||
|
systemdName = utils.escapeSystemdPath localPath;
|
||||||
|
in {
|
||||||
sane.programs.curlftpfs.enableFor.system = true;
|
sane.programs.curlftpfs.enableFor.system = true;
|
||||||
sane.fs."/mnt/servo/${subdir}" = sane-lib.fs.wanted {
|
system.fsPackages = [
|
||||||
|
config.sane.programs.curlftpfs.package
|
||||||
|
];
|
||||||
|
fileSystems."${localPath}" = {
|
||||||
|
device = "curlftpfs#ftp://servo-hn:/${subdir}";
|
||||||
|
noCheck = true;
|
||||||
|
fsType = "fuse3";
|
||||||
|
options = fsOpts.ftp ++ fsOpts.noauto ++ [
|
||||||
|
# drop_privileges: after `mount.fuse3` opens /dev/fuse, it will drop all capabilities before invoking sshfs
|
||||||
|
"drop_privileges"
|
||||||
|
"auto_unmount" #< ensures that when the fs exits, it releases its mountpoint. then systemd can recognize it as failed.
|
||||||
|
];
|
||||||
|
};
|
||||||
|
sane.fs."${localPath}" = {
|
||||||
dir.acl.user = "colin";
|
dir.acl.user = "colin";
|
||||||
dir.acl.group = "users";
|
dir.acl.group = "users";
|
||||||
dir.acl.mode = "0750";
|
dir.acl.mode = "0750";
|
||||||
};
|
|
||||||
fileSystems."/mnt/servo/${subdir}" = {
|
|
||||||
device = "ftp://servo-hn:/${subdir}";
|
|
||||||
noCheck = true;
|
|
||||||
fsType = "fuse.curlftpfs";
|
|
||||||
options = fsOpts.ftp ++ fsOpts.noauto ++ fsOpts.wg;
|
|
||||||
# fsType = "nfs";
|
|
||||||
# options = fsOpts.nfs ++ fsOpts.lazyMount ++ fsOpts.wg;
|
|
||||||
};
|
|
||||||
systemd.services."automount-servo-${utils.escapeSystemdPath subdir}" = let
|
|
||||||
fs = config.fileSystems."/mnt/servo/${subdir}";
|
|
||||||
in {
|
|
||||||
# this is a *flaky* network mount, especially on moby.
|
|
||||||
# if done as a normal autofs mount, access will eternally block when network is dropped.
|
|
||||||
# notably, this would block *any* sandboxed app which allows media access, whether they actually try to use that media or not.
|
|
||||||
# a practical solution is this: mount as a service -- instead of autofs -- and unmount on timeout error, in a restart loop.
|
|
||||||
# until the ftp handshake succeeds, nothing is actually mounted to the vfs, so this doesn't slow down any I/O when network is down.
|
|
||||||
description = "automount /mnt/servo/${subdir} in a fault-tolerant and non-blocking manner";
|
|
||||||
after = [ "network-online.target" ];
|
|
||||||
requires = [ "network-online.target" ];
|
|
||||||
wantedBy = [ "default.target" ];
|
wantedBy = [ "default.target" ];
|
||||||
|
mount.depends = [ "network-online.target" "${systemdName}-reachable.service" ];
|
||||||
|
#VVV patch so that when the mount fails, we start a timer to remount it.
|
||||||
|
# and for a disconnection after a good mount (onSuccess), restart the timer to be more aggressive
|
||||||
|
mount.unitConfig.OnFailure = [ "${systemdName}.timer" ];
|
||||||
|
mount.unitConfig.OnSuccess = [ "${systemdName}-restart-timer.target" ];
|
||||||
|
|
||||||
serviceConfig.Type = "simple";
|
mount.mountConfig.TimeoutSec = "10s";
|
||||||
serviceConfig.ExecStart = lib.escapeShellArgs [
|
mount.mountConfig.ExecSearchPath = [ "/run/current-system/sw/bin" ];
|
||||||
"/usr/bin/env"
|
mount.mountConfig.User = "colin";
|
||||||
"PATH=/run/current-system/sw/bin"
|
mount.mountConfig.AmbientCapabilities = "CAP_SETPCAP CAP_SYS_ADMIN";
|
||||||
"mount.${fs.fsType}"
|
# hardening (systemd-analyze security mnt-servo-playground.mount)
|
||||||
"-f" # foreground (i.e. don't daemonize)
|
mount.mountConfig.CapabilityBoundingSet = "CAP_SETPCAP CAP_SYS_ADMIN";
|
||||||
"-s" # single-threaded (TODO: it's probably ok to disable this?)
|
mount.mountConfig.LockPersonality = true;
|
||||||
"-o"
|
mount.mountConfig.MemoryDenyWriteExecute = true;
|
||||||
(lib.concatStringsSep "," (lib.filter (o: !lib.hasPrefix "x-systemd." o) fs.options))
|
mount.mountConfig.NoNewPrivileges = true;
|
||||||
fs.device
|
mount.mountConfig.ProtectClock = true;
|
||||||
"/mnt/servo/${subdir}"
|
mount.mountConfig.ProtectHostname = true;
|
||||||
|
mount.mountConfig.RemoveIPC = true;
|
||||||
|
mount.mountConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6";
|
||||||
|
#VVV this includes anything it reads from, e.g. /bin/sh; /nix/store/...
|
||||||
|
# see `systemd-analyze filesystems` for a full list
|
||||||
|
mount.mountConfig.RestrictFileSystems = "@common-block @basic-api fuse";
|
||||||
|
mount.mountConfig.RestrictRealtime = true;
|
||||||
|
mount.mountConfig.RestrictSUIDSGID = true;
|
||||||
|
mount.mountConfig.SystemCallArchitectures = "native";
|
||||||
|
mount.mountConfig.SystemCallFilter = [
|
||||||
|
"@system-service"
|
||||||
|
"@mount"
|
||||||
|
"~@chown"
|
||||||
|
"~@cpu-emulation"
|
||||||
|
"~@keyring"
|
||||||
|
# could remove almost all io calls, however one has to keep `open`, and `write`, to communicate with the fuse device.
|
||||||
|
# so that's pretty useless as a way to prevent write access
|
||||||
];
|
];
|
||||||
# not sure if this configures a linear, or exponential backoff.
|
mount.mountConfig.IPAddressDeny = "any";
|
||||||
# but the first restart will be after `RestartSec`, and the n'th restart (n = RestartSteps) will be RestartMaxDelaySec after the n-1'th exit.
|
mount.mountConfig.IPAddressAllow = "10.0.10.5";
|
||||||
serviceConfig.Restart = "always";
|
mount.mountConfig.DevicePolicy = "closed"; # only allow /dev/{null,zero,full,random,urandom}
|
||||||
serviceConfig.RestartSec = "10s";
|
mount.mountConfig.DeviceAllow = "/dev/fuse";
|
||||||
serviceConfig.RestartMaxDelaySec = "120s";
|
# mount.mountConfig.RestrictNamespaces = true;
|
||||||
serviceConfig.RestartSteps = "5";
|
};
|
||||||
|
|
||||||
|
systemd.services."${systemdName}-reachable" = {
|
||||||
|
serviceConfig.ExecSearchPath = [ "/run/current-system/sw/bin" ];
|
||||||
|
serviceConfig.ExecStart = lib.escapeShellArgs [
|
||||||
|
"curlftpfs"
|
||||||
|
"ftp://servo-hn:/${subdir}"
|
||||||
|
"/dev/null"
|
||||||
|
"-o"
|
||||||
|
(lib.concatStringsSep "," ([
|
||||||
|
"exit_after_connect"
|
||||||
|
] ++ config.fileSystems."${localPath}".options))
|
||||||
|
];
|
||||||
|
serviceConfig.RemainAfterExit = true;
|
||||||
|
serviceConfig.Type = "oneshot";
|
||||||
|
unitConfig.BindsTo = [ "${systemdName}.mount" ];
|
||||||
|
# hardening (systemd-analyze security mnt-servo-playground-reachable.service)
|
||||||
|
serviceConfig.AmbientCapabilities = "";
|
||||||
|
serviceConfig.CapabilityBoundingSet = "";
|
||||||
|
serviceConfig.DynamicUser = true;
|
||||||
|
serviceConfig.LockPersonality = true;
|
||||||
|
serviceConfig.MemoryDenyWriteExecute = true;
|
||||||
|
serviceConfig.NoNewPrivileges = true;
|
||||||
|
serviceConfig.PrivateDevices = true;
|
||||||
|
serviceConfig.PrivateMounts = true;
|
||||||
|
serviceConfig.PrivateTmp = true;
|
||||||
|
serviceConfig.PrivateUsers = true;
|
||||||
|
serviceConfig.ProcSubset = "all";
|
||||||
|
serviceConfig.ProtectClock = true;
|
||||||
|
serviceConfig.ProtectControlGroups = true;
|
||||||
|
serviceConfig.ProtectHome = true;
|
||||||
|
serviceConfig.ProtectKernelModules = true;
|
||||||
|
serviceConfig.ProtectProc = "invisible";
|
||||||
|
serviceConfig.ProtectSystem = "strict";
|
||||||
|
serviceConfig.RemoveIPC = true;
|
||||||
|
serviceConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6";
|
||||||
|
# serviceConfig.RestrictFileSystems = "@common-block @basic-api"; #< NOPE
|
||||||
|
serviceConfig.RestrictRealtime = true;
|
||||||
|
serviceConfig.RestrictSUIDSGID = true;
|
||||||
|
serviceConfig.SystemCallArchitectures = "native";
|
||||||
|
serviceConfig.SystemCallFilter = [
|
||||||
|
"@system-service"
|
||||||
|
"@mount"
|
||||||
|
"~@chown"
|
||||||
|
"~@cpu-emulation"
|
||||||
|
"~@keyring"
|
||||||
|
# "~@privileged" #< NOPE
|
||||||
|
"~@resources"
|
||||||
|
# could remove some more probably
|
||||||
|
];
|
||||||
|
serviceConfig.IPAddressDeny = "any";
|
||||||
|
serviceConfig.IPAddressAllow = "10.0.10.5";
|
||||||
|
serviceConfig.DevicePolicy = "closed";
|
||||||
|
# exceptions
|
||||||
|
serviceConfig.ProtectHostname = false;
|
||||||
|
serviceConfig.ProtectKernelLogs = false;
|
||||||
|
serviceConfig.ProtectKernelTunables = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.targets."${systemdName}-restart-timer" = {
|
||||||
|
# hack unit which, when started, stops the timer (if running), and then starts it again.
|
||||||
|
after = [ "${systemdName}.timer" ];
|
||||||
|
conflicts = [ "${systemdName}.timer" ];
|
||||||
|
upholds = [ "${systemdName}.timer" ];
|
||||||
|
unitConfig.StopWhenUnneeded = true;
|
||||||
|
};
|
||||||
|
systemd.timers."${systemdName}" = {
|
||||||
|
timerConfig.Unit = "${systemdName}.mount";
|
||||||
|
timerConfig.AccuracySec = "2s";
|
||||||
|
timerConfig.OnActiveSec = [
|
||||||
|
# try to remount at these timestamps, backing off gradually
|
||||||
|
# there seems to be an implicit mount attempt at t=0.
|
||||||
|
"10s"
|
||||||
|
"30s"
|
||||||
|
"60s"
|
||||||
|
"120s"
|
||||||
|
];
|
||||||
|
# cap the backoff to a fixed interval.
|
||||||
|
timerConfig.OnUnitActiveSec = [ "120s" ];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
@@ -207,19 +311,14 @@ lib.mkMerge [
|
|||||||
# but it decreases working memory under the heaviest of loads by however much space the compressed memory occupies (e.g. 50% if 2:1; 25% if 4:1)
|
# but it decreases working memory under the heaviest of loads by however much space the compressed memory occupies (e.g. 50% if 2:1; 25% if 4:1)
|
||||||
zramSwap.memoryPercent = 100;
|
zramSwap.memoryPercent = 100;
|
||||||
|
|
||||||
# environment.pathsToLink = [
|
|
||||||
# # needed to achieve superuser access for user-mounted filesystems (see sshRoot above)
|
|
||||||
# # we can only link whole directories here, even though we're only interested in pkgs.openssh
|
|
||||||
# "/libexec"
|
|
||||||
# ];
|
|
||||||
|
|
||||||
programs.fuse.userAllowOther = true; #< necessary for `allow_other` or `allow_root` options.
|
programs.fuse.userAllowOther = true; #< necessary for `allow_other` or `allow_root` options.
|
||||||
}
|
}
|
||||||
|
|
||||||
(remoteHome "crappy")
|
(ifSshAuthorized (remoteHome "crappy" {}))
|
||||||
(remoteHome "desko")
|
(ifSshAuthorized (remoteHome "desko" {}))
|
||||||
(remoteHome "lappy")
|
(ifSshAuthorized (remoteHome "lappy" {}))
|
||||||
(remoteHome "moby")
|
(ifSshAuthorized (remoteHome "moby" { host = "moby-hn"; }))
|
||||||
|
(ifSshAuthorized (remoteHome "servo" {}))
|
||||||
# this granularity of servo media mounts is necessary to support sandboxing:
|
# this granularity of servo media mounts is necessary to support sandboxing:
|
||||||
# for flaky mounts, we can only bind the mountpoint itself into the sandbox,
|
# for flaky mounts, we can only bind the mountpoint itself into the sandbox,
|
||||||
# so it's either this or unconditionally bind all of media/.
|
# so it's either this or unconditionally bind all of media/.
|
||||||
|
@@ -1,31 +1,31 @@
|
|||||||
{ config, lib, ... }:
|
{ config, lib, ... }:
|
||||||
{
|
{
|
||||||
sane.user.persist.byStore.plaintext = [
|
sane.user.persist.byStore.plaintext = [
|
||||||
"archive"
|
# TODO: some of ~/dev should be private too, but maybe not all 800+ GB of it
|
||||||
|
# perhaps i ought to rethink how it's organized
|
||||||
"dev"
|
"dev"
|
||||||
# TODO: records should be private
|
|
||||||
"records"
|
|
||||||
"ref"
|
"ref"
|
||||||
"tmp"
|
|
||||||
"use"
|
"use"
|
||||||
"Books/local"
|
"Books/local"
|
||||||
"Music"
|
"Music"
|
||||||
|
|
||||||
|
# this is persisted simply to save on RAM. mesa_shader_cache is < 10 MB per boot.
|
||||||
|
# TODO: integrate with sane.programs.sandbox?
|
||||||
|
".cache/mesa_shader_cache"
|
||||||
|
".cache/mesa_shader_cache_db"
|
||||||
|
];
|
||||||
|
sane.user.persist.byStore.private = [
|
||||||
|
"archive"
|
||||||
"Pictures/albums"
|
"Pictures/albums"
|
||||||
"Pictures/cat"
|
"Pictures/cat"
|
||||||
"Pictures/from"
|
"Pictures/from"
|
||||||
"Pictures/Screenshots" #< XXX: something is case-sensitive about this?
|
"Pictures/Screenshots" #< XXX: something is case-sensitive about this?
|
||||||
"Pictures/Photos"
|
"Pictures/Photos"
|
||||||
"Videos/local"
|
"records"
|
||||||
|
"tmp"
|
||||||
|
|
||||||
# these are persisted simply to save on RAM.
|
|
||||||
# ~/.cache/nix can become several GB.
|
|
||||||
# mesa_shader_cache is < 10 MB.
|
|
||||||
# TODO: integrate with sane.programs.sandbox?
|
|
||||||
".cache/mesa_shader_cache"
|
|
||||||
".cache/nix"
|
|
||||||
];
|
|
||||||
sane.user.persist.byStore.private = [
|
|
||||||
"knowledge"
|
"knowledge"
|
||||||
|
"Videos/local"
|
||||||
];
|
];
|
||||||
|
|
||||||
# convenience
|
# convenience
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
in {
|
in {
|
||||||
".persist/private" = lib.mkIf persistEnabled { symlink.target = config.sane.persist.stores.private.origin; };
|
".persist/private" = lib.mkIf persistEnabled { symlink.target = config.sane.persist.stores.private.origin; };
|
||||||
".persist/plaintext" = lib.mkIf persistEnabled { symlink.target = config.sane.persist.stores.plaintext.origin; };
|
".persist/plaintext" = lib.mkIf persistEnabled { symlink.target = config.sane.persist.stores.plaintext.origin; };
|
||||||
".persist/ephemeral" = lib.mkIf persistEnabled { symlink.target = config.sane.persist.stores.cryptClearOnBoot.origin; };
|
".persist/ephemeral" = lib.mkIf persistEnabled { symlink.target = config.sane.persist.stores.ephemeral.origin; };
|
||||||
|
|
||||||
"nixos".symlink.target = "dev/nixos";
|
"nixos".symlink.target = "dev/nixos";
|
||||||
|
|
||||||
|
@@ -45,8 +45,8 @@
|
|||||||
sane.ids.pict-rs.gid = 2409;
|
sane.ids.pict-rs.gid = 2409;
|
||||||
sane.ids.sftpgo.uid = 2410;
|
sane.ids.sftpgo.uid = 2410;
|
||||||
sane.ids.sftpgo.gid = 2410;
|
sane.ids.sftpgo.gid = 2410;
|
||||||
sane.ids.trust-dns.uid = 2411;
|
sane.ids.hickory-dns.uid = 2411; #< previously "trust-dns"
|
||||||
sane.ids.trust-dns.gid = 2411;
|
sane.ids.hickory-dns.gid = 2411; #< previously "trust-dns"
|
||||||
sane.ids.export.gid = 2412;
|
sane.ids.export.gid = 2412;
|
||||||
sane.ids.nfsuser.uid = 2413;
|
sane.ids.nfsuser.uid = 2413;
|
||||||
sane.ids.media.gid = 2414;
|
sane.ids.media.gid = 2414;
|
||||||
@@ -62,6 +62,9 @@
|
|||||||
sane.ids.clightning.gid = 2419;
|
sane.ids.clightning.gid = 2419;
|
||||||
sane.ids.nix-serve.uid = 2420;
|
sane.ids.nix-serve.uid = 2420;
|
||||||
sane.ids.nix-serve.gid = 2420;
|
sane.ids.nix-serve.gid = 2420;
|
||||||
|
sane.ids.plugdev.gid = 2421;
|
||||||
|
sane.ids.ollama.uid = 2422;
|
||||||
|
sane.ids.ollama.gid = 2422;
|
||||||
|
|
||||||
sane.ids.colin.uid = 1000;
|
sane.ids.colin.uid = 1000;
|
||||||
sane.ids.guest.uid = 1100;
|
sane.ids.guest.uid = 1100;
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
{ lib, ... }:
|
{ ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
@@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
systemd.network.enable = true;
|
systemd.network.enable = true;
|
||||||
networking.useNetworkd = true;
|
networking.useNetworkd = true;
|
||||||
|
networking.usePredictableInterfaceNames = false; #< set false to get `eth0`, `wlan0`, etc instead of `enp3s0`/etc
|
||||||
|
|
||||||
# view refused/dropped packets with: `sudo journalctl -k`
|
# view refused/dropped packets with: `sudo journalctl -k`
|
||||||
# networking.firewall.logRefusedPackets = true;
|
# networking.firewall.logRefusedPackets = true;
|
||||||
|
@@ -20,19 +20,19 @@
|
|||||||
# - each namespace may use a different /etc/resolv.conf to specify different DNS servers
|
# - each namespace may use a different /etc/resolv.conf to specify different DNS servers
|
||||||
# - nscd breaks namespacing: the host nscd is unaware of the guest's /etc/resolv.conf, and so directs the guest's DNS requests to the host's servers.
|
# - nscd breaks namespacing: the host nscd is unaware of the guest's /etc/resolv.conf, and so directs the guest's DNS requests to the host's servers.
|
||||||
# - this is fixed by either removing `/var/run/nscd/socket` from the namespace, or disabling nscd altogether.
|
# - this is fixed by either removing `/var/run/nscd/socket` from the namespace, or disabling nscd altogether.
|
||||||
{ config, lib, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
lib.mkMerge [
|
lib.mkMerge [
|
||||||
{
|
{
|
||||||
sane.services.trust-dns.enable = lib.mkDefault config.sane.services.trust-dns.asSystemResolver;
|
sane.services.hickory-dns.enable = lib.mkDefault config.sane.services.hickory-dns.asSystemResolver;
|
||||||
sane.services.trust-dns.asSystemResolver = lib.mkDefault true;
|
sane.services.hickory-dns.asSystemResolver = lib.mkDefault true;
|
||||||
}
|
}
|
||||||
(lib.mkIf (!config.sane.services.trust-dns.asSystemResolver) {
|
(lib.mkIf (!config.sane.services.hickory-dns.asSystemResolver) {
|
||||||
# use systemd's stub resolver.
|
# use systemd's stub resolver.
|
||||||
# /etc/resolv.conf isn't sophisticated enough to use different servers per net namespace (or link).
|
# /etc/resolv.conf isn't sophisticated enough to use different servers per net namespace (or link).
|
||||||
# instead, running the stub resolver on a known address in the root ns lets us rewrite packets
|
# instead, running the stub resolver on a known address in the root ns lets us rewrite packets
|
||||||
# in servo's ovnps namespace to use the provider's DNS resolvers.
|
# in servo's ovnps namespace to use the provider's DNS resolvers.
|
||||||
# a weakness is we can only query 1 NS at a time (unless we were to clone the packets?)
|
# a weakness is we can only query 1 NS at a time (unless we were to clone the packets?)
|
||||||
# TODO: improve trust-dns recursive resolver and then remove this
|
# TODO: improve hickory-dns recursive resolver and then remove this
|
||||||
services.resolved.enable = true; #< to disable, set ` = lib.mkForce false`, as other systemd features default to enabling `resolved`.
|
services.resolved.enable = true; #< to disable, set ` = lib.mkForce false`, as other systemd features default to enabling `resolved`.
|
||||||
# without DNSSEC:
|
# without DNSSEC:
|
||||||
# - dig matrix.org => works
|
# - dig matrix.org => works
|
||||||
@@ -40,7 +40,7 @@ lib.mkMerge [
|
|||||||
# with default DNSSEC:
|
# with default DNSSEC:
|
||||||
# - dig matrix.org => works
|
# - dig matrix.org => works
|
||||||
# - curl https://matrix.org => fails
|
# - curl https://matrix.org => fails
|
||||||
# i don't know why. this might somehow be interfering with the DNS run on this device (trust-dns)
|
# i don't know why. this might somehow be interfering with the DNS run on this device (hickory-dns)
|
||||||
services.resolved.dnssec = "false";
|
services.resolved.dnssec = "false";
|
||||||
networking.nameservers = [
|
networking.nameservers = [
|
||||||
# use systemd-resolved resolver
|
# use systemd-resolved resolver
|
||||||
@@ -59,15 +59,35 @@ lib.mkMerge [
|
|||||||
# in the netns and we query upstream DNS more often than needed. hm.
|
# in the netns and we query upstream DNS more often than needed. hm.
|
||||||
# services.nscd.enableNsncd = true;
|
# services.nscd.enableNsncd = true;
|
||||||
|
|
||||||
# disabling nscd LOSES US SOME FUNCTIONALITY. in particular, only the glibc-builtin modules are accessible via /etc/resolv.conf.
|
# disabling nscd LOSES US SOME FUNCTIONALITY. in particular, only the glibc-builtin modules are accessible via /etc/resolv.conf (er, did i mean /etc/nsswitch.conf?).
|
||||||
# - dns: glibc-bultin
|
# - dns: glibc-bultin
|
||||||
# - files: glibc-builtin
|
# - files: glibc-builtin
|
||||||
# - myhostname: systemd
|
# - myhostname: systemd
|
||||||
# - mymachines: systemd
|
# - mymachines: systemd
|
||||||
# - resolve: systemd
|
# - resolve: systemd
|
||||||
# in practice, i see no difference with nscd disabled.
|
# in practice, i see no difference with nscd disabled.
|
||||||
|
# - the exception is when the system dns resolver doesn't do everything.
|
||||||
|
# for example, systemd-resolved does mDNS. hickory-dns does not. a hickory-dns system won't be mDNS-capable.
|
||||||
# disabling nscd VASTLY simplifies netns and process isolation. see explainer at top of file.
|
# disabling nscd VASTLY simplifies netns and process isolation. see explainer at top of file.
|
||||||
services.nscd.enable = false;
|
services.nscd.enable = false;
|
||||||
system.nssModules = lib.mkForce [];
|
# system.nssModules = lib.mkForce [];
|
||||||
|
sane.silencedAssertions = [''.*Loading NSS modules from system.nssModules.*requires services.nscd.enable being set to true.*''];
|
||||||
|
# add NSS modules into their own subdirectory.
|
||||||
|
# then i can add just the NSS modules library path to the global LD_LIBRARY_PATH, rather than ALL of /run/current-system/sw/lib.
|
||||||
|
# TODO: i'm doing this so as to achieve mdns DNS resolution (avahi). it would be better to just have hickory-dns delegate .local to avahi
|
||||||
|
# (except avahi doesn't act as a local resolver over DNS protocol -- only dbus).
|
||||||
|
environment.systemPackages = [(pkgs.symlinkJoin {
|
||||||
|
name = "nss-modules";
|
||||||
|
paths = config.system.nssModules.list;
|
||||||
|
postBuild = ''
|
||||||
|
mkdir nss
|
||||||
|
mv $out/lib/libnss_* nss
|
||||||
|
rm -rf $out
|
||||||
|
mkdir -p $out/lib
|
||||||
|
mv nss $out/lib
|
||||||
|
'';
|
||||||
|
})];
|
||||||
|
environment.variables.LD_LIBRARY_PATH = [ "/run/current-system/sw/lib/nss" ];
|
||||||
|
systemd.globalEnvironment.LD_LIBRARY_PATH = "/run/current-system/sw/lib/nss"; #< specifically for `geoclue.service`
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@@ -14,7 +14,6 @@
|
|||||||
# after = [ "polkit.service" ];
|
# after = [ "polkit.service" ];
|
||||||
# requires = [ "polkit.service" ];
|
# requires = [ "polkit.service" ];
|
||||||
wantedBy = [ "network.target" ]; #< default is `multi-user.target`, somehow it doesn't auto-start with that...
|
wantedBy = [ "network.target" ]; #< default is `multi-user.target`, somehow it doesn't auto-start with that...
|
||||||
# path = [ "/run/current-system/sw" ]; #< so it can find `sanebox`
|
|
||||||
|
|
||||||
# serviceConfig.Type = "dbus";
|
# serviceConfig.Type = "dbus";
|
||||||
# serviceConfig.BusName = "org.freedesktop.ModemManager1";
|
# serviceConfig.BusName = "org.freedesktop.ModemManager1";
|
||||||
@@ -38,7 +37,11 @@
|
|||||||
# serviceConfig.RestrictAddressFamilies = "AF_NETLINK AF_UNIX AF_QIPCRTR";
|
# serviceConfig.RestrictAddressFamilies = "AF_NETLINK AF_UNIX AF_QIPCRTR";
|
||||||
# serviceConfig.NoNewPrivileges = true;
|
# serviceConfig.NoNewPrivileges = true;
|
||||||
|
|
||||||
serviceConfig.CapabilityBoundingSet = [ "CAP_NET_ADMIN" ]; #< TODO: make sure this is *really* taking effect, and isn't supplemental to upstream's `CAP_SYS_ADMIN` setting
|
serviceConfig.CapabilityBoundingSet = [
|
||||||
|
"" #< reset upstream capabilities
|
||||||
|
"CAP_NET_ADMIN"
|
||||||
|
"CAP_SYS_ADMIN" #< TODO: remove CAP_SYS_ADMIN!
|
||||||
|
];
|
||||||
serviceConfig.LockPersonality = true;
|
serviceConfig.LockPersonality = true;
|
||||||
# serviceConfig.PrivateUsers = true; #< untried, not likely to work since it needs capabilities
|
# serviceConfig.PrivateUsers = true; #< untried, not likely to work since it needs capabilities
|
||||||
serviceConfig.PrivateTmp = true;
|
serviceConfig.PrivateTmp = true;
|
||||||
|
@@ -2,21 +2,28 @@
|
|||||||
let
|
let
|
||||||
# networkmanager = pkgs.networkmanager;
|
# networkmanager = pkgs.networkmanager;
|
||||||
networkmanager = pkgs.networkmanager.overrideAttrs (upstream: {
|
networkmanager = pkgs.networkmanager.overrideAttrs (upstream: {
|
||||||
src = pkgs.fetchFromGitea {
|
# src = pkgs.fetchFromGitea {
|
||||||
domain = "git.uninsane.org";
|
# domain = "git.uninsane.org";
|
||||||
owner = "colin";
|
# owner = "colin";
|
||||||
repo = "NetworkManager";
|
# repo = "NetworkManager";
|
||||||
# patched to fix polkit permissions (with `nmcli`) when NetworkManager runs as user networkmanager
|
# # patched to fix polkit permissions (with `nmcli`) when NetworkManager runs as user networkmanager
|
||||||
rev = "dev-sane-1.48.0";
|
# rev = "dev-sane-1.48.0";
|
||||||
hash = "sha256-vGmOKtwVItxjYioZJlb1og3K6u9s4rcmDnjAPLBC3ao=";
|
# hash = "sha256-vGmOKtwVItxjYioZJlb1og3K6u9s4rcmDnjAPLBC3ao=";
|
||||||
};
|
# };
|
||||||
# patches = [];
|
patches = (upstream.patches or []) ++ [
|
||||||
|
(pkgs.fetchpatch {
|
||||||
|
name = "polkit: add owner annotations to all actions";
|
||||||
|
url = "https://git.uninsane.org/colin/NetworkManager/commit/a01293861fa24201ffaeb84c07f1c71136c49759.patch";
|
||||||
|
hash = "sha256-th1/M2slo7rjkVBwETZII53Lmhyw8OMS0aT9QYI5Uvk=";
|
||||||
|
})
|
||||||
|
];
|
||||||
});
|
});
|
||||||
# split the package into `daemon` and `nmcli` outputs, because the networkmanager *service*
|
# split the package into `daemon` and `nmcli` outputs, because the networkmanager *service*
|
||||||
# doesn't need `nmcli`/`nmtui` tooling
|
# doesn't need `nmcli`/`nmtui` tooling
|
||||||
networkmanager-split = pkgs.networkmanager-split.override { inherit networkmanager; };
|
networkmanager-split = pkgs.networkmanager-split.override { inherit networkmanager; };
|
||||||
in {
|
in {
|
||||||
networking.networkmanager.enable = true;
|
networking.networkmanager.enable = true;
|
||||||
|
systemd.network.wait-online.enable = false; # systemd-networkd-wait-online.service reliably fails on lappy. docs don't match behavior. shit software.
|
||||||
# plugins mostly add support for establishing different VPN connections.
|
# plugins mostly add support for establishing different VPN connections.
|
||||||
# the default plugin set includes mostly proprietary VPNs:
|
# the default plugin set includes mostly proprietary VPNs:
|
||||||
# - fortisslvpn (Fortinet)
|
# - fortisslvpn (Fortinet)
|
||||||
@@ -41,7 +48,9 @@ in {
|
|||||||
# allow the bus to owned by either root or networkmanager users
|
# allow the bus to owned by either root or networkmanager users
|
||||||
# use the group here, that way ordinary users can be elevated to control networkmanager
|
# use the group here, that way ordinary users can be elevated to control networkmanager
|
||||||
# (via e.g. `nmcli`)
|
# (via e.g. `nmcli`)
|
||||||
for f in org.freedesktop.NetworkManager.conf nm-dispatcher.conf ; do
|
confs=(nm-dispatcher.conf)
|
||||||
|
confs+=(org.freedesktop.NetworkManager.conf)
|
||||||
|
for f in "''${confs[@]}" ; do
|
||||||
substitute $out/share/dbus-1/system.d/$f \
|
substitute $out/share/dbus-1/system.d/$f \
|
||||||
$out/share/dbus-1/system.d/networkmanager-$f \
|
$out/share/dbus-1/system.d/networkmanager-$f \
|
||||||
--replace-fail 'user="root"' 'group="networkmanager"'
|
--replace-fail 'user="root"' 'group="networkmanager"'
|
||||||
@@ -59,6 +68,11 @@ in {
|
|||||||
serviceConfig.User = "networkmanager";
|
serviceConfig.User = "networkmanager";
|
||||||
serviceConfig.Group = "networkmanager";
|
serviceConfig.Group = "networkmanager";
|
||||||
serviceConfig.AmbientCapabilities = [
|
serviceConfig.AmbientCapabilities = [
|
||||||
|
"CAP_NET_ADMIN"
|
||||||
|
"CAP_NET_RAW"
|
||||||
|
"CAP_NET_BIND_SERVICE"
|
||||||
|
];
|
||||||
|
serviceConfig.CapabilityBoundingSet = [
|
||||||
# "CAP_DAC_OVERRIDE"
|
# "CAP_DAC_OVERRIDE"
|
||||||
"CAP_NET_ADMIN"
|
"CAP_NET_ADMIN"
|
||||||
"CAP_NET_RAW" #< required, else `libndp: ndp_sock_open: Failed to create ICMP6 socket.`
|
"CAP_NET_RAW" #< required, else `libndp: ndp_sock_open: Failed to create ICMP6 socket.`
|
||||||
@@ -69,6 +83,7 @@ in {
|
|||||||
];
|
];
|
||||||
serviceConfig.LockPersonality = true;
|
serviceConfig.LockPersonality = true;
|
||||||
serviceConfig.NoNewPrivileges = true;
|
serviceConfig.NoNewPrivileges = true;
|
||||||
|
serviceConfig.MemoryDenyWriteExecute = true;
|
||||||
serviceConfig.PrivateDevices = true; # remount /dev with just the basics, syscall filter to block @raw-io
|
serviceConfig.PrivateDevices = true; # remount /dev with just the basics, syscall filter to block @raw-io
|
||||||
serviceConfig.PrivateIPC = true;
|
serviceConfig.PrivateIPC = true;
|
||||||
serviceConfig.PrivateTmp = true;
|
serviceConfig.PrivateTmp = true;
|
||||||
@@ -79,8 +94,11 @@ in {
|
|||||||
serviceConfig.ProtectHostname = true; # probably not upstreamable: prevents changing hostname
|
serviceConfig.ProtectHostname = true; # probably not upstreamable: prevents changing hostname
|
||||||
serviceConfig.ProtectKernelLogs = true; # disable /proc/kmsg, /dev/kmsg
|
serviceConfig.ProtectKernelLogs = true; # disable /proc/kmsg, /dev/kmsg
|
||||||
serviceConfig.ProtectKernelModules = true; # syscall filter to prevent module calls (probably not upstreamable: NM will want to load modules like `ppp`)
|
serviceConfig.ProtectKernelModules = true; # syscall filter to prevent module calls (probably not upstreamable: NM will want to load modules like `ppp`)
|
||||||
serviceConfig.ProtectKernelTunables = true; # but NM might need to write /proc/sys/net/...
|
# serviceConfig.ProtectKernelTunables = true; # causes errors/warnings when opening files in /proc/sys/net/...; also breaks IPv6 SLAAC / link-local address creation!
|
||||||
|
serviceConfig.ProtectProc = "invisible";
|
||||||
|
serviceConfig.ProcSubset = "all";
|
||||||
serviceConfig.ProtectSystem = "strict"; # makes read-only: all but /dev, /proc, /sys.
|
serviceConfig.ProtectSystem = "strict"; # makes read-only: all but /dev, /proc, /sys.
|
||||||
|
serviceConfig.RemoveIPC = true;
|
||||||
serviceConfig.RestrictAddressFamilies = [
|
serviceConfig.RestrictAddressFamilies = [
|
||||||
"AF_INET"
|
"AF_INET"
|
||||||
"AF_INET6"
|
"AF_INET6"
|
||||||
@@ -91,19 +109,25 @@ in {
|
|||||||
# AF_BLUETOOTH ?
|
# AF_BLUETOOTH ?
|
||||||
# AF_BRIDGE ?
|
# AF_BRIDGE ?
|
||||||
];
|
];
|
||||||
|
serviceConfig.RestrictNamespaces = true;
|
||||||
serviceConfig.RestrictSUIDSGID = true;
|
serviceConfig.RestrictSUIDSGID = true;
|
||||||
serviceConfig.SystemCallArchitectures = "native"; # prevents e.g. aarch64 syscalls in the event that the kernel is multi-architecture.
|
serviceConfig.SystemCallArchitectures = "native"; # prevents e.g. aarch64 syscalls in the event that the kernel is multi-architecture.
|
||||||
|
serviceConfig.SystemCallFilter = [
|
||||||
|
"@system-service"
|
||||||
|
# TODO: restrict SystemCallFilter more aggressively
|
||||||
|
];
|
||||||
|
# TODO: restrict `DeviceAllow`
|
||||||
# from earlier `landlock` sandboxing, i know it needs these directories:
|
# from earlier `landlock` sandboxing, i know it needs these directories:
|
||||||
# - "/proc/net"
|
# - "/proc/net"
|
||||||
# - "/proc/sys/net"
|
# - "/proc/sys/net"
|
||||||
# - "/run/NetworkManager"
|
# - "/run/NetworkManager"
|
||||||
# - "/run/systemd" # for trust-dns-nmhook
|
# - "/run/systemd" # for hickory-dns-nmhook
|
||||||
# - "/run/udev"
|
# - "/run/udev"
|
||||||
# - # "/run/wg-home.priv"
|
# - # "/run/wg-home.priv"
|
||||||
# - "/sys/class"
|
# - "/sys/class"
|
||||||
# - "/sys/devices"
|
# - "/sys/devices"
|
||||||
# - "/var/lib/NetworkManager"
|
# - "/var/lib/NetworkManager"
|
||||||
# - "/var/lib/trust-dns" #< for trust-dns-nmhook
|
# - "/var/lib/hickory-dns" #< for hickory-dns-nmhook
|
||||||
# - "/run/systemd"
|
# - "/run/systemd"
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -115,7 +139,12 @@ in {
|
|||||||
# fix NetworkManager-dispatcher to actually run as a daemon,
|
# fix NetworkManager-dispatcher to actually run as a daemon,
|
||||||
# and sandbox it a bit
|
# and sandbox it a bit
|
||||||
systemd.services.NetworkManager-dispatcher = {
|
systemd.services.NetworkManager-dispatcher = {
|
||||||
after = [ "trust-dns-localhost.service" ]; #< so that /var/lib/trust-dns will exist
|
#VVV so that /var/lib/hickory-dns will exist (the hook needs to write here).
|
||||||
|
# but this creates a cycle: hickory-dns-localhost > network.target > NetworkManager-dispatcher > hickory-dns-localhost.
|
||||||
|
# (seemingly) impossible to remove the network.target dep on NetworkManager-dispatcher.
|
||||||
|
# beffore would be to have the dispatcher not write hickory-dns files
|
||||||
|
# but rather just its own, and create a .path unit which restarts hickory-dns appropriately.
|
||||||
|
# after = [ "hickory-dns-localhost.service" ];
|
||||||
# serviceConfig.ExecStart = [
|
# serviceConfig.ExecStart = [
|
||||||
# "" # first blank line is to clear the upstream `ExecStart` field.
|
# "" # first blank line is to clear the upstream `ExecStart` field.
|
||||||
# "${cfg.package}/libexec/nm-dispatcher --persist" # --persist is needed for it to actually run as a daemon
|
# "${cfg.package}/libexec/nm-dispatcher --persist" # --persist is needed for it to actually run as a daemon
|
||||||
@@ -123,7 +152,7 @@ in {
|
|||||||
# serviceConfig.Restart = "always";
|
# serviceConfig.Restart = "always";
|
||||||
# serviceConfig.RestartSec = "1s";
|
# serviceConfig.RestartSec = "1s";
|
||||||
|
|
||||||
# serviceConfig.DynamicUser = true; #< not possible, else we lose group perms (so can't write to `trust-dns`'s files in the nm hook)
|
# serviceConfig.DynamicUser = true; #< not possible, else we lose group perms (so can't write to `hickory-dns`'s files in the nm hook)
|
||||||
serviceConfig.User = "networkmanager"; # TODO: should arguably use `DynamicUser`
|
serviceConfig.User = "networkmanager"; # TODO: should arguably use `DynamicUser`
|
||||||
serviceConfig.Group = "networkmanager";
|
serviceConfig.Group = "networkmanager";
|
||||||
serviceConfig.LockPersonality = true;
|
serviceConfig.LockPersonality = true;
|
||||||
@@ -139,7 +168,7 @@ in {
|
|||||||
serviceConfig.ProtectKernelLogs = true; # disable /proc/kmsg, /dev/kmsg
|
serviceConfig.ProtectKernelLogs = true; # disable /proc/kmsg, /dev/kmsg
|
||||||
serviceConfig.ProtectKernelModules = true; # syscall filter to prevent module calls
|
serviceConfig.ProtectKernelModules = true; # syscall filter to prevent module calls
|
||||||
serviceConfig.ProtectKernelTunables = true;
|
serviceConfig.ProtectKernelTunables = true;
|
||||||
serviceConfig.ProtectSystem = "full"; # makes read-only: /boot, /etc/, /usr. `strict` isn't possible due to trust-dns hook
|
serviceConfig.ProtectSystem = "full"; # makes read-only: /boot, /etc/, /usr. `strict` isn't possible due to hickory-dns hook
|
||||||
serviceConfig.RestrictAddressFamilies = [
|
serviceConfig.RestrictAddressFamilies = [
|
||||||
"AF_UNIX" # required, probably for dbus or systemd connectivity
|
"AF_UNIX" # required, probably for dbus or systemd connectivity
|
||||||
];
|
];
|
||||||
@@ -199,9 +228,15 @@ in {
|
|||||||
logging.level = "INFO";
|
logging.level = "INFO";
|
||||||
|
|
||||||
# main.dhcp = "internal"; #< default
|
# main.dhcp = "internal"; #< default
|
||||||
|
# main.dns controls what to do when NM gets a DNS server via DHCP
|
||||||
|
# - "none" (populate /run/NetworkManager/resolv.conf with DHCP settings)
|
||||||
|
# - "internal" (?)
|
||||||
|
# - "systemd-resolved" (tell systemd-resolved about it, and point /run/NetworkManager/resolv.conf -> systemd)
|
||||||
|
# without this, systemd-resolved won't be able to resolve anything (because it has no upstream servers)
|
||||||
|
# note that NM's resolv.conf isn't (necessarily) /etc/resolv.conf -- that is managed by nixos (via symlinking)
|
||||||
main.dns = if config.services.resolved.enable then
|
main.dns = if config.services.resolved.enable then
|
||||||
"systemd-resolved"
|
"systemd-resolved"
|
||||||
else if config.sane.services.trust-dns.enable && config.sane.services.trust-dns.asSystemResolver then
|
else if config.sane.services.hickory-dns.enable && config.sane.services.hickory-dns.asSystemResolver then
|
||||||
"none"
|
"none"
|
||||||
else
|
else
|
||||||
"internal"
|
"internal"
|
||||||
@@ -243,7 +278,7 @@ in {
|
|||||||
users.users.networkmanager = {
|
users.users.networkmanager = {
|
||||||
isSystemUser = true;
|
isSystemUser = true;
|
||||||
group = "networkmanager";
|
group = "networkmanager";
|
||||||
extraGroups = [ "trust-dns" ];
|
extraGroups = [ "hickory-dns" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
# there is, unfortunately, no proper interface by which to plumb wpa_supplicant into the NixOS service, except by overlay.
|
# there is, unfortunately, no proper interface by which to plumb wpa_supplicant into the NixOS service, except by overlay.
|
||||||
|
@@ -16,5 +16,9 @@
|
|||||||
${ipset}/bin/ipset create -! upnp hash:ip,port timeout 10
|
${ipset}/bin/ipset create -! upnp hash:ip,port timeout 10
|
||||||
${iptables}/bin/iptables -A OUTPUT -d 239.255.255.250/32 -p udp -m udp --dport 1900 -j SET --add-set upnp src,src --exist
|
${iptables}/bin/iptables -A OUTPUT -d 239.255.255.250/32 -p udp -m udp --dport 1900 -j SET --add-set upnp src,src --exist
|
||||||
${iptables}/bin/iptables -A INPUT -p udp -m set --match-set upnp dst,dst -j ACCEPT
|
${iptables}/bin/iptables -A INPUT -p udp -m set --match-set upnp dst,dst -j ACCEPT
|
||||||
|
# IPv6 ruleset. ff02::/16 means *any* link-local multicast group (so this is probably more broad than it needs to be)
|
||||||
|
${ipset}/bin/ipset create -! upnp6 hash:ip,port timeout 10 family inet6
|
||||||
|
${iptables}/bin/ip6tables -A OUTPUT -d ff02::/16 -p udp -m udp --dport 1900 -j SET --add-set upnp6 src,src --exist
|
||||||
|
${iptables}/bin/ip6tables -A INPUT -p udp -m set --match-set upnp6 dst,dst -j ACCEPT
|
||||||
'';
|
'';
|
||||||
}
|
}
|
||||||
|
@@ -5,7 +5,7 @@
|
|||||||
# - generate config @ OVPN.com
|
# - generate config @ OVPN.com
|
||||||
# - copy the Address, PublicKey, Endpoint from OVPN's config
|
# - copy the Address, PublicKey, Endpoint from OVPN's config
|
||||||
|
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, ... }:
|
||||||
let
|
let
|
||||||
# N.B.: OVPN issues each key (i.e. device) a different IP (addrV4), and requires you use it.
|
# N.B.: OVPN issues each key (i.e. device) a different IP (addrV4), and requires you use it.
|
||||||
# the IP it issues can be used to connect to any of their VPNs.
|
# the IP it issues can be used to connect to any of their VPNs.
|
||||||
|
@@ -64,7 +64,12 @@
|
|||||||
# it's an impurity that touches way more than i need and tends to cause hard-to-debug eval issues
|
# it's an impurity that touches way more than i need and tends to cause hard-to-debug eval issues
|
||||||
# when it goes wrong. should i port my `nix-shell` scripts to something more tailored to my uses
|
# when it goes wrong. should i port my `nix-shell` scripts to something more tailored to my uses
|
||||||
# and then delete `nixpkgs-overlays`?
|
# and then delete `nixpkgs-overlays`?
|
||||||
"nixpkgs-overlays=/home/colin/dev/nixos/integrations/nixpkgs/nixpkgs-overlays.nix"
|
# "nixpkgs-overlays=/home/colin/dev/nixos/integrations/nixpkgs/nixpkgs-overlays.nix"
|
||||||
|
# XXX(2024-09-02): nix 2.24.4 errors when nixpkgs-overlays includes a symlink component:
|
||||||
|
# "error: path '/home/colin/dev' is a symlink"
|
||||||
|
# apparently nix has to explicitly handle symlinks in every place it might encounter them,
|
||||||
|
# so the fixes inside nix for this are manual and fragile. dereference it ourselves:
|
||||||
|
"nixpkgs-overlays=${config.sane.fs."/home/colin/dev".symlink.target}/nixos/integrations/nixpkgs/nixpkgs-overlays.nix"
|
||||||
];
|
];
|
||||||
|
|
||||||
# ensure new deployments have a source of this repo with which they can bootstrap.
|
# ensure new deployments have a source of this repo with which they can bootstrap.
|
||||||
|
@@ -1,17 +0,0 @@
|
|||||||
{ ... }:
|
|
||||||
|
|
||||||
{
|
|
||||||
# store /home/colin/a/b in /mnt/persist/private/a/b instead of /mnt/persist/private/home/colin/a/b
|
|
||||||
sane.persist.stores.private.prefix = "/home/colin";
|
|
||||||
|
|
||||||
sane.persist.sys.byStore.initrd = [
|
|
||||||
"/var/log"
|
|
||||||
];
|
|
||||||
sane.persist.sys.byStore.plaintext = [
|
|
||||||
# TODO: these should be private.. somehow
|
|
||||||
"/var/backup" # for e.g. postgres dumps
|
|
||||||
];
|
|
||||||
sane.persist.sys.byStore.cryptClearOnBoot = [
|
|
||||||
"/var/lib/systemd/coredump"
|
|
||||||
];
|
|
||||||
}
|
|
@@ -1,12 +1,11 @@
|
|||||||
# strictly *decrease* the scope of the default nixos installation/config
|
# strictly *decrease* the scope of the default nixos installation/config
|
||||||
|
|
||||||
{ lib, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
let
|
let
|
||||||
suidlessPam = pkgs.pam.overrideAttrs (upstream: {
|
suidlessPam = pkgs.pam.overrideAttrs (upstream: {
|
||||||
# nixpkgs' pam hardcodes unix_chkpwd path to the /run/wrappers one,
|
# nixpkgs' pam hardcodes unix_chkpwd path to the /run/wrappers one,
|
||||||
# but i don't want the wrapper, so undo that.
|
# but i don't want the wrapper, so undo that.
|
||||||
# ideally i would patch this via an overlay, but pam is in the bootstrap so that forces a full rebuild.
|
# ideally i would patch this via an overlay, but pam is in the bootstrap so that forces a full rebuild.
|
||||||
# TODO: add a `package` option to the nixos' pam module and substitute it that way.
|
|
||||||
postPatch = (if upstream.postPatch != null then upstream.postPatch else "") + ''
|
postPatch = (if upstream.postPatch != null then upstream.postPatch else "") + ''
|
||||||
substituteInPlace modules/pam_unix/Makefile.am --replace-fail \
|
substituteInPlace modules/pam_unix/Makefile.am --replace-fail \
|
||||||
"/run/wrappers/bin/unix_chkpwd" "$out/bin/unix_chkpwd"
|
"/run/wrappers/bin/unix_chkpwd" "$out/bin/unix_chkpwd"
|
||||||
@@ -39,8 +38,7 @@ in
|
|||||||
]));
|
]));
|
||||||
};
|
};
|
||||||
options.security.pam.services = lib.mkOption {
|
options.security.pam.services = lib.mkOption {
|
||||||
apply = services: let
|
apply = lib.filterAttrs (name: _: !(builtins.elem name [
|
||||||
filtered = lib.filterAttrs (name: _: !(builtins.elem name [
|
|
||||||
# from <repo:nixos/nixpkgs:nixos/modules/security/pam.nix>
|
# from <repo:nixos/nixpkgs:nixos/modules/security/pam.nix>
|
||||||
"i3lock"
|
"i3lock"
|
||||||
"i3lock-color"
|
"i3lock-color"
|
||||||
@@ -62,13 +60,7 @@ in
|
|||||||
"usermod"
|
"usermod"
|
||||||
# from <repo:nixos/nixpkgs:nixos/modules/system/boot/systemd/user.nix>
|
# from <repo:nixos/nixpkgs:nixos/modules/system/boot/systemd/user.nix>
|
||||||
"systemd-user" #< N.B.: this causes the `systemd --user` service manager to not be started!
|
"systemd-user" #< N.B.: this causes the `systemd --user` service manager to not be started!
|
||||||
])) services;
|
]));
|
||||||
in lib.mapAttrs (_serviceName: service: service // {
|
|
||||||
# replace references with the old pam_unix, which calls into /run/wrappers/bin/unix_chkpwd,
|
|
||||||
# with a pam_unix that calls into unix_chkpwd via the nix store.
|
|
||||||
# TODO: use `security.pam.package` instead once <https://github.com/NixOS/nixpkgs/pull/314791> lands.
|
|
||||||
text = lib.replaceStrings [" pam_unix.so" ] [ " ${suidlessPam}/lib/security/pam_unix.so" ] service.text;
|
|
||||||
}) filtered;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
options.environment.systemPackages = lib.mkOption {
|
options.environment.systemPackages = lib.mkOption {
|
||||||
@@ -111,7 +103,11 @@ in
|
|||||||
# pkgs.which
|
# pkgs.which
|
||||||
# pkgs.zstd
|
# pkgs.zstd
|
||||||
];
|
];
|
||||||
in lib.filter (p: ! builtins.elem p requiredPackages);
|
conveniencePackages = [
|
||||||
|
config.boot.kernelPackages.cpupower # <repo:nixos/nixpkgs:nixos/modules/tasks/cpu-freq.nix> places it on PATH for convenience if powerManagement.cpuFreqGovernor is set
|
||||||
|
pkgs.kbd # <repo:nixos/nixpkgs:nixos/modules/config/console.nix> places it on PATH as part of console/virtual TTYs, but probably not needed unless you want to set console fonts
|
||||||
|
];
|
||||||
|
in lib.filter (p: ! builtins.elem p (requiredPackages ++ conveniencePackages));
|
||||||
};
|
};
|
||||||
|
|
||||||
options.system.fsPackages = lib.mkOption {
|
options.system.fsPackages = lib.mkOption {
|
||||||
@@ -212,5 +208,16 @@ in
|
|||||||
|
|
||||||
# see: <repo:nixos/nixpkgs:nixos/modules/virtualisation/nixos-containers.nix>
|
# see: <repo:nixos/nixpkgs:nixos/modules/virtualisation/nixos-containers.nix>
|
||||||
boot.enableContainers = lib.mkDefault false;
|
boot.enableContainers = lib.mkDefault false;
|
||||||
|
|
||||||
|
# see: <repo:nixos/nixpkgs:nixos/modules/tasks/lvm.nix>
|
||||||
|
# lvm places `pkgs.lvm2` onto PATH, which has like 100 binaries.
|
||||||
|
# it is, actually, needed for some userspace tools (cryptsetup). probably just the udev rules. try to reduce this set?
|
||||||
|
services.lvm.enable = lib.mkDefault false;
|
||||||
|
services.udev.packages = [ pkgs.lvm2.out ]; #< N.B. `lvm2.out` != `lvm2`
|
||||||
|
# systemd.packages = [ pkgs.lvm2 ];
|
||||||
|
# systemd.tmpfiles.packages = [ pkgs.lvm2.out ];
|
||||||
|
# environment.systemPackages = [ pkgs.lvm2 ];
|
||||||
|
|
||||||
|
security.pam.package = suidlessPam;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -3,8 +3,8 @@
|
|||||||
|
|
||||||
{
|
{
|
||||||
sane.programs.aerc = {
|
sane.programs.aerc = {
|
||||||
sandbox.method = "bwrap";
|
sandbox.method = "bunpen";
|
||||||
sandbox.wrapperType = "inplace"; #< /share/aerc/aerc.conf refers to other /share files by absolute path
|
sandbox.wrapperType = "inplace"; #< /share/aerc/aerc.conf mentions (in comments) other (non-sandboxed) /share files by absolute path
|
||||||
sandbox.net = "clearnet";
|
sandbox.net = "clearnet";
|
||||||
secrets.".config/aerc/accounts.conf" = ../../../secrets/common/aerc_accounts.conf.bin;
|
secrets.".config/aerc/accounts.conf" = ../../../secrets/common/aerc_accounts.conf.bin;
|
||||||
mime.associations."x-scheme-handler/mailto" = "aerc.desktop";
|
mime.associations."x-scheme-handler/mailto" = "aerc.desktop";
|
||||||
|
@@ -15,8 +15,9 @@ in
|
|||||||
};
|
};
|
||||||
|
|
||||||
# upstream alsa ships with PinePhone audio configs, but they don't actually produce sound.
|
# upstream alsa ships with PinePhone audio configs, but they don't actually produce sound.
|
||||||
# - still true as of 2024-05-26
|
# - still true as of 2024-08-20
|
||||||
# - see: <https://github.com/alsa-project/alsa-ucm-conf/pull/134>
|
# - see: <https://github.com/alsa-project/alsa-ucm-conf/pull/134>
|
||||||
|
# - see: <https://gitlab.com/postmarketOS/pmaports/-/issues/2115>
|
||||||
#
|
#
|
||||||
# we can substitute working UCM conf in two ways:
|
# we can substitute working UCM conf in two ways:
|
||||||
# 1. nixpkgs' override for the `alsa-ucm-conf` package
|
# 1. nixpkgs' override for the `alsa-ucm-conf` package
|
||||||
|
@@ -32,7 +32,7 @@
|
|||||||
|
|
||||||
buildCost = 1;
|
buildCost = 1;
|
||||||
|
|
||||||
sandbox.method = "bwrap";
|
sandbox.method = "bunpen";
|
||||||
sandbox.whitelistWayland = true;
|
sandbox.whitelistWayland = true;
|
||||||
|
|
||||||
persist.byStore.plaintext = [
|
persist.byStore.plaintext = [
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
buildCost = 1;
|
buildCost = 1;
|
||||||
|
|
||||||
sandbox.method = "bwrap";
|
sandbox.method = "bunpen";
|
||||||
sandbox.whitelistAudio = true;
|
sandbox.whitelistAudio = true;
|
||||||
sandbox.whitelistWayland = true;
|
sandbox.whitelistWayland = true;
|
||||||
sandbox.autodetectCliPaths = "existingFile";
|
sandbox.autodetectCliPaths = "existingFile";
|
||||||
|
@@ -2,9 +2,9 @@
|
|||||||
{ pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
{
|
{
|
||||||
sane.programs.ausyscall = {
|
sane.programs.ausyscall = {
|
||||||
packageUnwrapped = pkgs.linkIntoOwnPackage pkgs.audit "bin/ausyscall";
|
packageUnwrapped = pkgs.linkBinIntoOwnPackage pkgs.audit "ausyscall";
|
||||||
|
|
||||||
sandbox.method = "landlock";
|
sandbox.method = "bunpen";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
107
hosts/common/programs/avahi.nix
Normal file
107
hosts/common/programs/avahi.nix
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
# Avahi zeroconf (mDNS) implementation.
|
||||||
|
# runs as systemd `avahi-daemon.service`
|
||||||
|
#
|
||||||
|
# - <https://avahi.org/>
|
||||||
|
# - code: <https://github.com/avahi/avahi>
|
||||||
|
# - IRC: #avahi on irc.libera.chat
|
||||||
|
#
|
||||||
|
# - `avahi-browse --help` for usage
|
||||||
|
# - `man avahi-daemon.conf`
|
||||||
|
# - `LD_LIBRARY_PATH=/nix/store/ngwj3jqmxh8k4qji2z0lj7y1f8vzqrn2-nss-mdns-0.15.1/lib getent hosts desko.local`
|
||||||
|
# nss-mdns goes through avahi-daemon, so there IS caching here
|
||||||
|
#
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
let
|
||||||
|
cfg = config.sane.programs.avahi;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
sane.programs.avahi = {
|
||||||
|
packageUnwrapped = pkgs.avahi.overrideAttrs (upstream: {
|
||||||
|
# avahi wants to do its own sandboxing opaque to systemd & maybe in conflict with my bwrap.
|
||||||
|
# --no-drop-root disables that, so that i can e.g. run it as User=avahi, etc.
|
||||||
|
# do this here, because the nixos service isn't so easily patched.
|
||||||
|
postInstall = (upstream.postInstall or "") + ''
|
||||||
|
wrapProgram "$out/sbin/avahi-daemon" \
|
||||||
|
--add-flags --no-drop-root
|
||||||
|
'';
|
||||||
|
nativeBuildInputs = upstream.nativeBuildInputs ++ [
|
||||||
|
pkgs.makeBinaryWrapper
|
||||||
|
];
|
||||||
|
});
|
||||||
|
sandbox.method = "bunpen";
|
||||||
|
sandbox.whitelistDbus = [ "system" ];
|
||||||
|
sandbox.net = "all"; #< otherwise it will show 'null' in place of each interface name.
|
||||||
|
# sandbox.extraPaths = [ ]; #< may be missing some paths; only tried service discovery, not service advertisement.
|
||||||
|
};
|
||||||
|
|
||||||
|
services.avahi = lib.mkIf cfg.enabled {
|
||||||
|
enable = true;
|
||||||
|
package = cfg.packageUnwrapped; #< use systemd sandboxing... not my own
|
||||||
|
publish.enable = true;
|
||||||
|
publish.userServices = true;
|
||||||
|
nssmdns4 = true;
|
||||||
|
nssmdns6 = true;
|
||||||
|
# reflector = true;
|
||||||
|
allowInterfaces = [
|
||||||
|
# particularly, the default config disallows loopback, which is kinda fucking retarded, right?
|
||||||
|
"ens1" #< servo
|
||||||
|
"enp5s0" #< desko
|
||||||
|
"eth0"
|
||||||
|
"lo"
|
||||||
|
"wg-home"
|
||||||
|
"wlan0" #< moby
|
||||||
|
"wlp3s0" #< lappy
|
||||||
|
"wlp4s0" #< desko
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
# fix "rpfilter drop ..." dmesg logspam.
|
||||||
|
# this might not be necessary?
|
||||||
|
networking.firewall.extraCommands = lib.mkIf cfg.enabled (with pkgs; ''
|
||||||
|
# after an outgoing mDNS query to the multicast address, open FW for incoming responses.
|
||||||
|
# ipset -! means "don't fail if set already exists"
|
||||||
|
${ipset}/bin/ipset create -! mdns hash:ip,port timeout 10
|
||||||
|
${iptables}/bin/iptables -A OUTPUT -d 239.255.255.250/32 -p udp -m udp --dport 5353 -j SET --add-set mdns src,src --exist
|
||||||
|
${iptables}/bin/iptables -A INPUT -p udp -m set --match-set mdns dst,dst -j ACCEPT
|
||||||
|
# IPv6 ruleset. ff02::/16 means *any* link-local multicast group (so this is probably more broad than it needs to be)
|
||||||
|
${ipset}/bin/ipset create -! mdns6 hash:ip,port timeout 10 family inet6
|
||||||
|
${iptables}/bin/ip6tables -A OUTPUT -d ff02::/16 -p udp -m udp --dport 5353 -j SET --add-set mdns6 src,src --exist
|
||||||
|
${iptables}/bin/ip6tables -A INPUT -p udp -m set --match-set mdns6 dst,dst -j ACCEPT
|
||||||
|
'');
|
||||||
|
|
||||||
|
systemd.services.avahi-daemon = lib.mkIf cfg.enabled {
|
||||||
|
# hardening: see `systemd-analyze security avahi-daemon`
|
||||||
|
serviceConfig.User = "avahi";
|
||||||
|
serviceConfig.Group = "avahi";
|
||||||
|
serviceConfig.AmbientCapabilities = "";
|
||||||
|
serviceConfig.CapabilityBoundingSet = "";
|
||||||
|
serviceConfig.LockPersonality = true;
|
||||||
|
serviceConfig.MemoryDenyWriteExecute = true;
|
||||||
|
serviceConfig.NoNewPrivileges = true;
|
||||||
|
serviceConfig.PrivateDevices = true;
|
||||||
|
serviceConfig.PrivateMounts = true;
|
||||||
|
serviceConfig.PrivateTmp = true;
|
||||||
|
serviceConfig.PrivateUsers = true;
|
||||||
|
serviceConfig.ProcSubset = "all";
|
||||||
|
serviceConfig.ProtectClock = true;
|
||||||
|
serviceConfig.ProtectControlGroups = true;
|
||||||
|
serviceConfig.ProtectHome = true;
|
||||||
|
serviceConfig.ProtectHostname = true;
|
||||||
|
serviceConfig.ProtectKernelLogs = true;
|
||||||
|
serviceConfig.ProtectKernelModules = true;
|
||||||
|
serviceConfig.ProtectKernelTunables = true;
|
||||||
|
serviceConfig.ProtectProc = "noaccess";
|
||||||
|
serviceConfig.ProtectSystem = "strict";
|
||||||
|
serviceConfig.RemoveIPC = true; #< this *might* slow down the initial connection?
|
||||||
|
serviceConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6 AF_NETLINK";
|
||||||
|
serviceConfig.RestrictRealtime = true;
|
||||||
|
serviceConfig.RestrictSUIDSGID = true;
|
||||||
|
serviceConfig.SystemCallArchitectures = "native";
|
||||||
|
serviceConfig.SystemCallFilter = [
|
||||||
|
"@system-service"
|
||||||
|
"@mount"
|
||||||
|
"~@resources"
|
||||||
|
# "~@privileged"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
@@ -95,7 +95,7 @@ in
|
|||||||
|
|
||||||
packageUnwrapped = pkgs.bemenu.overrideAttrs (upstream: {
|
packageUnwrapped = pkgs.bemenu.overrideAttrs (upstream: {
|
||||||
nativeBuildInputs = (upstream.nativeBuildInputs or []) ++ [
|
nativeBuildInputs = (upstream.nativeBuildInputs or []) ++ [
|
||||||
pkgs.makeWrapper
|
pkgs.makeBinaryWrapper
|
||||||
];
|
];
|
||||||
# can alternatively be specified as CLI flags
|
# can alternatively be specified as CLI flags
|
||||||
postInstall = (upstream.postInstall or "") + ''
|
postInstall = (upstream.postInstall or "") + ''
|
||||||
|
13
hosts/common/programs/bitcoin-cli.nix
Normal file
13
hosts/common/programs/bitcoin-cli.nix
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{ pkgs, ... }:
|
||||||
|
{
|
||||||
|
sane.programs.bitcoin-cli = {
|
||||||
|
packageUnwrapped = pkgs.linkBinIntoOwnPackage pkgs.bitcoind "bitcoin-cli";
|
||||||
|
sandbox.method = "bwrap";
|
||||||
|
sandbox.autodetectCliPaths = "existing"; #< for `bitcoin-cli -datadir=/var/lib/...`
|
||||||
|
sandbox.extraHomePaths = [
|
||||||
|
".bitcoin/bitcoin.conf"
|
||||||
|
];
|
||||||
|
sandbox.net = "all"; # actually needs only localhost
|
||||||
|
secrets.".bitcoin/bitcoin.conf" = ../../../secrets/servo/bitcoin.conf.bin;
|
||||||
|
};
|
||||||
|
}
|
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env nix-shell
|
#!/usr/bin/env nix-shell
|
||||||
#!nix-shell -i python3 -p "python3.withPackages (ps: [ ])" -p blast-ugjka
|
#!nix-shell -i python3 -p blast-ugjka -p python3
|
||||||
# vim: set filetype=python :
|
# vim: set filetype=python :
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
@@ -24,24 +24,24 @@ let
|
|||||||
in
|
in
|
||||||
{
|
{
|
||||||
sane.programs.blast-ugjka = {
|
sane.programs.blast-ugjka = {
|
||||||
sandbox.method = "bwrap";
|
sandbox.method = "bunpen";
|
||||||
sandbox.whitelistAudio = true;
|
sandbox.whitelistAudio = true;
|
||||||
sandbox.net = "clearnet";
|
sandbox.net = "clearnet";
|
||||||
};
|
};
|
||||||
|
|
||||||
sane.programs.blast-to-default = {
|
sane.programs.blast-to-default = {
|
||||||
# helper to deal with blast's interactive CLI
|
# helper to deal with blast's interactive CLI
|
||||||
packageUnwrapped = pkgs.static-nix-shell.mkPython3Bin {
|
packageUnwrapped = pkgs.static-nix-shell.mkPython3 {
|
||||||
pname = "blast-to-default";
|
pname = "blast-to-default";
|
||||||
pkgs = [ "blast-ugjka" ];
|
pkgs = [ "blast-ugjka" ];
|
||||||
srcRoot = ./.;
|
srcRoot = ./.;
|
||||||
};
|
};
|
||||||
sandbox.method = "bwrap";
|
sandbox.method = "bunpen";
|
||||||
sandbox.whitelistAudio = true;
|
sandbox.whitelistAudio = true;
|
||||||
sandbox.net = "clearnet";
|
sandbox.net = "clearnet";
|
||||||
#v else it fails to reap its children (or, maybe, it fails to hook its parent's death signal?)
|
#v else it fails to reap its children (or, maybe, it fails to hook its parent's death signal?)
|
||||||
#v might be possible to remove this, but kinda hard to see a clean way.
|
#v might be possible to remove this, but kinda hard to see a clean way.
|
||||||
sandbox.isolatePids = false;
|
sandbox.keepPidsAndProc = true;
|
||||||
suggestedPrograms = [ "blast-ugjka" "sane-die-with-parent" ];
|
suggestedPrograms = [ "blast-ugjka" "sane-die-with-parent" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -111,9 +111,9 @@ 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.method = "bunpen";
|
||||||
sandbox.extraRuntimePaths = [
|
sandbox.extraRuntimePaths = [
|
||||||
"bonsai"
|
"bonsai"
|
||||||
];
|
];
|
||||||
|
@@ -3,12 +3,18 @@
|
|||||||
sane.programs.brave = {
|
sane.programs.brave = {
|
||||||
# convert eval error to build failure
|
# convert eval error to build failure
|
||||||
packageUnwrapped = if (builtins.tryEval pkgs.brave).success then
|
packageUnwrapped = if (builtins.tryEval pkgs.brave).success then
|
||||||
pkgs.brave
|
pkgs.brave.overrideAttrs (upstream: {
|
||||||
|
# brave does crimes with `$0` which break under transparent wrapping
|
||||||
|
preFixup = (upstream.preFixup or "") + ''
|
||||||
|
substituteInPlace $out/opt/brave.com/brave/brave-browser \
|
||||||
|
--replace '$0' "$out/opt/brave.com/brave/brave-browser"
|
||||||
|
'';
|
||||||
|
})
|
||||||
else
|
else
|
||||||
pkgs.runCommandLocal "brave-not-supported" {} "false"
|
pkgs.runCommandLocal "brave-not-supported" {} "false"
|
||||||
;
|
;
|
||||||
sandbox.method = "bwrap";
|
sandbox.method = "bunpen";
|
||||||
sandbox.wrapperType = "inplace"; # /opt/share/brave.com vendor-style packaging
|
sandbox.wrapperType = "inplace"; #< package contains dangling symlinks which my wrapper doesn't understand
|
||||||
sandbox.net = "all";
|
sandbox.net = "all";
|
||||||
sandbox.extraHomePaths = [
|
sandbox.extraHomePaths = [
|
||||||
"dev" # for developing anything web-related
|
"dev" # for developing anything web-related
|
||||||
@@ -21,7 +27,7 @@
|
|||||||
sandbox.whitelistDri = true;
|
sandbox.whitelistDri = true;
|
||||||
sandbox.whitelistWayland = true;
|
sandbox.whitelistWayland = true;
|
||||||
|
|
||||||
persist.byStore.cryptClearOnBoot = [
|
persist.byStore.ephemeral = [
|
||||||
".cache/BraveSoftware"
|
".cache/BraveSoftware"
|
||||||
".config/BraveSoftware"
|
".config/BraveSoftware"
|
||||||
];
|
];
|
||||||
|
@@ -4,7 +4,7 @@ let
|
|||||||
in
|
in
|
||||||
{
|
{
|
||||||
sane.programs.brightnessctl = {
|
sane.programs.brightnessctl = {
|
||||||
sandbox.method = "landlock"; # also bwrap, but landlock is more responsive
|
sandbox.method = "bunpen";
|
||||||
sandbox.extraPaths = [
|
sandbox.extraPaths = [
|
||||||
"/sys/class/backlight"
|
"/sys/class/backlight"
|
||||||
"/sys/class/leds"
|
"/sys/class/leds"
|
||||||
|
19
hosts/common/programs/bunpen.nix
Normal file
19
hosts/common/programs/bunpen.nix
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
let
|
||||||
|
cfg = config.sane.programs.bunpen;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
sane.programs.bunpen = {
|
||||||
|
packageUnwrapped = pkgs.bunpen.overrideAttrs (base: {
|
||||||
|
# create a directory which holds just the `bunpen` so that we
|
||||||
|
# can add bunpen as a dependency to binaries via `PATH=/run/current-system/libexec/bunpen` without forcing rebuild every time bunpen changes
|
||||||
|
postInstall = ''
|
||||||
|
mkdir -p $out/libexec/bunpen
|
||||||
|
ln -s $out/bin/bunpen $out/libexec/bunpen/bunpen
|
||||||
|
'';
|
||||||
|
});
|
||||||
|
sandbox.enable = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
environment.pathsToLink = lib.mkIf cfg.enabled [ "/libexec/bunpen" ];
|
||||||
|
}
|
@@ -13,7 +13,7 @@
|
|||||||
sane.programs.callaudiod = {
|
sane.programs.callaudiod = {
|
||||||
packageUnwrapped = pkgs.rmDbusServices pkgs.callaudiod;
|
packageUnwrapped = pkgs.rmDbusServices pkgs.callaudiod;
|
||||||
|
|
||||||
# probably more needed once i enable proper sandboxing, but for now this ensures the service isn't started too early!
|
sandbox.method = "bwrap";
|
||||||
sandbox.whitelistAudio = true;
|
sandbox.whitelistAudio = true;
|
||||||
sandbox.whitelistDbus = [ "user" ];
|
sandbox.whitelistDbus = [ "user" ];
|
||||||
|
|
||||||
|
@@ -8,6 +8,23 @@
|
|||||||
# - the bot will reply with auto-generated username/password plus a SIP server endpoint.
|
# - the bot will reply with auto-generated username/password plus a SIP server endpoint.
|
||||||
# just copy those into gnome-calls' GUI configurator
|
# just copy those into gnome-calls' GUI configurator
|
||||||
# - now gnome-calls can do outbound calls. inbound calls can be routed by messaging the bot: "configure calls"
|
# - now gnome-calls can do outbound calls. inbound calls can be routed by messaging the bot: "configure calls"
|
||||||
|
#
|
||||||
|
# user guide:
|
||||||
|
# - "Use for Calls" means, "when i click a tel: URI, use this account": <https://gitlab.gnome.org/GNOME/calls/-/issues/513>
|
||||||
|
# - `calls -vvv` for verbosity
|
||||||
|
# - `SOFIA_DEBUG=9 NEA_DEBUG=9 NUA_DEBUG=9 NTA_DEBUG=9 SU_DEBUG=8 gnome-calls` to debug SIP related stuff
|
||||||
|
#
|
||||||
|
# LIMITATIONS, COMPATIBILITY (as of 2024-08-20):
|
||||||
|
# - when switching from wifi -> wwan (4g), may experience about a minute of audio loss.
|
||||||
|
# the call stays alive, but no sound in either direction.
|
||||||
|
# this appears to be ~40s of general net loss to servo-hn (NetworkManager being slow to switch the default device? wireguard being slow to refresh?),
|
||||||
|
# unknown how much time is lost in the upper layers (e.g. dns being refreshed)
|
||||||
|
# - wwan -> wifi switching is (near) flawless. prefer to keep modem powered until end of call, because of audio routing, but OK to power it off.
|
||||||
|
# - audio is not always routed to a good device when the modem is powered.
|
||||||
|
# solve by opening `pavucontrol`, go to "configuration" tab, change "Built-in audio" to anything and then back to "Make a phone call (Earpiece, Mic)".
|
||||||
|
# i expect my eg25-control-powered script messes with the audio routing.
|
||||||
|
# - `gnome-calls` takes about 2 minutes after launch until it shows the UI.
|
||||||
|
# seems to be sandbox related.
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
let
|
let
|
||||||
cfg = config.sane.programs.calls;
|
cfg = config.sane.programs.calls;
|
||||||
@@ -24,19 +41,63 @@ in
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
packageUnwrapped = pkgs.calls.overrideAttrs (upstream: {
|
packageUnwrapped = pkgs.rmDbusServicesInPlace ((pkgs.calls.override {
|
||||||
|
gtk3 = pkgs.gtk4;
|
||||||
|
libpeas = pkgs.libpeas2;
|
||||||
|
wrapGAppsHook3 = pkgs.wrapGAppsHook4;
|
||||||
|
sofia_sip = pkgs.sofia_sip.overrideAttrs (upstream: {
|
||||||
|
# use linphone's sofia_sip.
|
||||||
|
# Freeswitch sofia_sip has a bug where a failed DNS query will never return to the caller.
|
||||||
|
# see `outgoing_answer_a`: in linphone's this already calls the user's callback; in Freeswitch there's a branch which leaves the caller hanging.
|
||||||
|
version = "1.13.45bc-unstable-2024-08-05";
|
||||||
|
src = pkgs.fetchFromGitLab {
|
||||||
|
domain = "gitlab.linphone.org";
|
||||||
|
owner = "BC/public/external";
|
||||||
|
repo = "sofia-sip";
|
||||||
|
rev = "b924a57e8eeb24e8b9afc5fd0fb9b51d5993fe5d";
|
||||||
|
hash = "sha256-1VbKV+eAJ80IMlubNl7774B7QvLv4hE8SXANDSD9sRU=";
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}).overrideAttrs (upstream: {
|
||||||
|
# XXX(2024-08-08): v46.3 has a bug where if it has no network connection on launch, it forever stays disconnected & never retries
|
||||||
|
version = "47_beta.0-unstable-2024-08-08";
|
||||||
|
src = lib.warnIf (lib.versionOlder "47.0" upstream.version) "gnome-calls outdated; remove src override? (keep UI patches though!)" pkgs.fetchFromGitLab {
|
||||||
|
domain = "gitlab.gnome.org";
|
||||||
|
owner = "GNOME";
|
||||||
|
repo = "calls";
|
||||||
|
fetchSubmodules = true;
|
||||||
|
# rev = "main";
|
||||||
|
rev = "ff213579a52222e7c95e585843d97b5b817b2a8b";
|
||||||
|
hash = "sha256-0QYC8FJpfg/X2lIjBDooba2idUfpJNQhcpv8Z5I/B4k=";
|
||||||
|
};
|
||||||
|
|
||||||
patches = (upstream.patches or []) ++ [
|
patches = (upstream.patches or []) ++ [
|
||||||
(pkgs.fetchpatch {
|
(pkgs.fetchpatch {
|
||||||
# usability improvement... if the UI is visible, then i can receive calls. otherwise, i can't!
|
# usability improvement... ties the UI visibility to the connection state, so if the UI is gone, then i can't receive calls (and will hopefully notice that more easily!)
|
||||||
url = "https://git.uninsane.org/colin/gnome-calls/commit/a19166d85927e59662fae189a780eed18bf876ce.patch";
|
url = "https://git.uninsane.org/colin/gnome-calls/commit/a19166d85927e59662fae189a780eed18bf876ce.patch";
|
||||||
name = "exit on close (i.e. never daemonize)";
|
name = "exit on close (i.e. never daemonize)";
|
||||||
hash = "sha256-NoVQV2TlkCcsBt0uwSyK82hBKySUW4pADrJVfLFvWgU=";
|
hash = "sha256-NoVQV2TlkCcsBt0uwSyK82hBKySUW4pADrJVfLFvWgU=";
|
||||||
})
|
})
|
||||||
|
(pkgs.fetchpatch {
|
||||||
|
# solves the issue where flakey DNS (especially at boot) could take down call connectivity indefinitely.
|
||||||
|
# see: <https://gitlab.gnome.org/GNOME/calls/-/issues/659>
|
||||||
|
url = "https://git.uninsane.org/colin/gnome-calls/commit/db9192a69cff2b20b5e8870e34a9b1e694a81c7f.patch";
|
||||||
|
name = "sip: attempt reconnection anytime network is routable, not just when routability changes";
|
||||||
|
hash = "sha256-agPM3XKXiP5Rxrl26DNA+pnhEPTBEBQBxZe3CoptgII=";
|
||||||
|
})
|
||||||
];
|
];
|
||||||
});
|
|
||||||
|
|
||||||
sandbox.method = "bwrap";
|
nativeBuildInputs = upstream.nativeBuildInputs ++ [
|
||||||
sandbox.net = "clearnet";
|
pkgs.dbus #< for dbus-run-session (should be test only, but it's not)
|
||||||
|
];
|
||||||
|
|
||||||
|
buildInputs = upstream.buildInputs ++ [
|
||||||
|
pkgs.libadwaita
|
||||||
|
];
|
||||||
|
}));
|
||||||
|
|
||||||
|
sandbox.method = "bunpen";
|
||||||
|
sandbox.net = "vpn.wg-home"; #< XXX(2024/07/05): my cell carrier seems to block RTP, so tunnel it.
|
||||||
sandbox.whitelistAudio = true;
|
sandbox.whitelistAudio = true;
|
||||||
sandbox.whitelistDbus = [ "user" ]; # necessary for secrets, at the minimum
|
sandbox.whitelistDbus = [ "user" ]; # necessary for secrets, at the minimum
|
||||||
sandbox.whitelistWayland = true;
|
sandbox.whitelistWayland = true;
|
||||||
@@ -55,6 +116,10 @@ in
|
|||||||
"gnome-keyring" # to remember the password
|
"gnome-keyring" # to remember the password
|
||||||
];
|
];
|
||||||
|
|
||||||
|
mime.associations."x-scheme-handler/tel" = "org.gnome.Calls.desktop";
|
||||||
|
mime.associations."x-scheme-handler/sip" = "org.gnome.Calls.desktop";
|
||||||
|
mime.associations."x-scheme-handler/sips" = "org.gnome.Calls.desktop";
|
||||||
|
|
||||||
services.gnome-calls = {
|
services.gnome-calls = {
|
||||||
description = "gnome-calls daemon to monitor incoming SIP calls";
|
description = "gnome-calls daemon to monitor incoming SIP calls";
|
||||||
partOf = lib.mkIf cfg.config.autostart [ "graphical-session" ];
|
partOf = lib.mkIf cfg.config.autostart [ "graphical-session" ];
|
||||||
|
7
hosts/common/programs/capsh.nix
Normal file
7
hosts/common/programs/capsh.nix
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{ pkgs, ... }:
|
||||||
|
{
|
||||||
|
sane.programs.capsh = {
|
||||||
|
packageUnwrapped = pkgs.linkBinIntoOwnPackage pkgs.libcap "capsh";
|
||||||
|
sandbox.enable = false; #< i use `capsh` as a sandboxer.
|
||||||
|
};
|
||||||
|
}
|
8
hosts/common/programs/captree.nix
Normal file
8
hosts/common/programs/captree.nix
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{ pkgs, ... }:
|
||||||
|
{
|
||||||
|
sane.programs.captree = {
|
||||||
|
packageUnwrapped = pkgs.linkBinIntoOwnPackage pkgs.libcap-with-captree "captree";
|
||||||
|
sandbox.method = "bunpen";
|
||||||
|
sandbox.keepPidsAndProc = true;
|
||||||
|
};
|
||||||
|
}
|
@@ -3,7 +3,7 @@
|
|||||||
sane.programs.celeste64 = {
|
sane.programs.celeste64 = {
|
||||||
buildCost = 1;
|
buildCost = 1;
|
||||||
|
|
||||||
sandbox.method = "bwrap";
|
sandbox.method = "bunpen";
|
||||||
sandbox.whitelistAudio = true;
|
sandbox.whitelistAudio = true;
|
||||||
sandbox.whitelistDri = true;
|
sandbox.whitelistDri = true;
|
||||||
sandbox.whitelistWayland = true;
|
sandbox.whitelistWayland = true;
|
||||||
|
@@ -66,6 +66,7 @@ end
|
|||||||
if vars.percent ~= nil then
|
if vars.percent ~= nil then
|
||||||
bat_args = bat_args .. " --percent-suffix '" .. vars.percent .. "'"
|
bat_args = bat_args .. " --percent-suffix '" .. vars.percent .. "'"
|
||||||
end
|
end
|
||||||
|
bat_args = bat_args .. " {bat}"
|
||||||
|
|
||||||
-- N.B.: `[[ <text> ]]` is Lua's multiline string literal
|
-- N.B.: `[[ <text> ]]` is Lua's multiline string literal
|
||||||
conky.text = [[
|
conky.text = [[
|
||||||
@@ -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}
|
${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=22:style=Bold}${alignc}${execp sane-sysload ]] .. bat_args .. [[ }${font}
|
||||||
${color1}${shadecolor}${font sans-serif:size=20:style=Bold}${alignc}${texeci 600 @weather@ }${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}
|
${color2}${shadecolor a4d7d0}${font sans-serif:size=16}${alignc}⇅ ${downspeedf wlan0}]] .. vars.kBps .. [[${font}
|
||||||
|
@@ -1,26 +1,22 @@
|
|||||||
{ pkgs, ... }:
|
{ ... }:
|
||||||
{
|
{
|
||||||
sane.programs.conky = {
|
sane.programs.conky = {
|
||||||
sandbox.method = "bwrap";
|
sandbox.method = "bunpen";
|
||||||
sandbox.net = "clearnet"; #< for the scripts it calls (weather)
|
sandbox.net = "clearnet"; #< for the scripts it calls (weather)
|
||||||
sandbox.extraPaths = [
|
sandbox.extraPaths = [
|
||||||
"/sys/class/power_supply"
|
"/sys/class/power_supply"
|
||||||
"/sys/devices" # needed by sane-sysinfo
|
"/sys/devices" # needed by sane-sysload
|
||||||
# "/sys/devices/cpu"
|
# "/sys/devices/cpu"
|
||||||
# "/sys/devices/system"
|
# "/sys/devices/system"
|
||||||
];
|
];
|
||||||
sandbox.whitelistWayland = true;
|
sandbox.whitelistWayland = true;
|
||||||
|
|
||||||
suggestedPrograms = [
|
suggestedPrograms = [
|
||||||
"sane-sysinfo"
|
"sane-sysload"
|
||||||
"sane-weather"
|
"sane-weather"
|
||||||
];
|
];
|
||||||
|
|
||||||
fs.".config/conky/conky.conf".symlink.target = pkgs.substituteAll {
|
fs.".config/conky/conky.conf".symlink.target = ./conky.conf;
|
||||||
src = ./conky.conf;
|
|
||||||
bat = "sane-sysinfo";
|
|
||||||
weather = "timeout 20 sane-weather";
|
|
||||||
};
|
|
||||||
|
|
||||||
services.conky = {
|
services.conky = {
|
||||||
description = "conky dynamic desktop background";
|
description = "conky dynamic desktop background";
|
||||||
|
@@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
buildCost = 1;
|
buildCost = 1;
|
||||||
|
|
||||||
sandbox.method = "bwrap"; # landlock gives: _multiprocessing.SemLock: Permission Denied
|
sandbox.method = "bwrap";
|
||||||
sandbox.whitelistAudio = true;
|
sandbox.whitelistAudio = true;
|
||||||
sandbox.whitelistDbus = [ "user" ]; # mpris
|
sandbox.whitelistDbus = [ "user" ]; # mpris
|
||||||
sandbox.whitelistWayland = true;
|
sandbox.whitelistWayland = true;
|
||||||
|
8
hosts/common/programs/curl.nix
Normal file
8
hosts/common/programs/curl.nix
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{ ... }:
|
||||||
|
{
|
||||||
|
sane.programs.curl = {
|
||||||
|
sandbox.method = "bunpen";
|
||||||
|
sandbox.net = "all";
|
||||||
|
sandbox.autodetectCliPaths = "parent"; #< for `-o` option
|
||||||
|
};
|
||||||
|
}
|
@@ -1,35 +1,10 @@
|
|||||||
{ pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
{
|
{
|
||||||
sane.programs.curlftpfs = {
|
sane.programs.curlftpfs = {
|
||||||
packageUnwrapped = pkgs.curlftpfs.overrideAttrs (upstream: {
|
packageUnwrapped = pkgs.curlftpfs-sane;
|
||||||
# my fork includes:
|
sandbox.method = "bunpen";
|
||||||
# - per-operation timeouts (CURLOPT_TIMEOUT; would use CURLOPT_LOW_SPEED_TIME/CURLOPT_LOW_SPEED_LIMIT but they don't apply)
|
sandbox.net = "all";
|
||||||
# - exit on timeout (so that one knows to abort the mount, instead of waiting indefinitely)
|
sandbox.autodetectCliPaths = "existing";
|
||||||
# - support for "meta" keys found in /etc/fstab
|
sandbox.keepPids = true;
|
||||||
src = pkgs.fetchFromGitea {
|
|
||||||
domain = "git.uninsane.org";
|
|
||||||
owner = "colin";
|
|
||||||
repo = "curlftpfs";
|
|
||||||
rev = "0890d32e709b5a01153f00d29ed4c00299744f5d";
|
|
||||||
hash = "sha256-M28PzHqEAkezQdtPeL16z56prwl3BfMZqry0dlpXJls=";
|
|
||||||
};
|
|
||||||
# `mount` clears PATH before calling the mount helper (see util-linux/lib/env.c),
|
|
||||||
# so the traditional /etc/fstab approach of fstype=fuse and device = curlftpfs#URI doesn't work.
|
|
||||||
# instead, install a `mount.curlftpfs` mount helper. this is what programs like `gocryptfs` do.
|
|
||||||
postInstall = (upstream.postInstall or "") + ''
|
|
||||||
ln -s curlftpfs $out/bin/mount.fuse.curlftpfs
|
|
||||||
ln -s curlftpfs $out/bin/mount.curlftpfs
|
|
||||||
'';
|
|
||||||
});
|
|
||||||
|
|
||||||
# TODO: try to sandbox this better? maybe i can have fuse (unsandboxed) invoke curlftpfs (sandboxed)?
|
|
||||||
# - landlock gives EPERM
|
|
||||||
# - bwrap just silently doesn't mount it, maybe because of setuid stuff around fuse?
|
|
||||||
# sandbox.method = "capshonly";
|
|
||||||
# sandbox.net = "all";
|
|
||||||
# sandbox.capabilities = [
|
|
||||||
# "sys_admin"
|
|
||||||
# "sys_module"
|
|
||||||
# ];
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -32,13 +32,13 @@ in
|
|||||||
'';
|
'';
|
||||||
});
|
});
|
||||||
|
|
||||||
sandbox.method = "bwrap";
|
sandbox.method = "bunpen";
|
||||||
sandbox.extraRuntimePaths = [
|
sandbox.extraRuntimePaths = [
|
||||||
"/" #< it needs to create a file in the root. TODO: move the bus handle into a sandboxable subdirectory
|
"dbus"
|
||||||
];
|
];
|
||||||
sandbox.isolatePids = false; #< not actually sure *why* this is necessary, but it is
|
sandbox.keepPids = true; #< not actually sure *why* this is necessary, but it is
|
||||||
|
|
||||||
env.DBUS_SESSION_BUS_ADDRESS = "unix:path=$XDG_RUNTIME_DIR/bus";
|
env.DBUS_SESSION_BUS_ADDRESS = "unix:path=$XDG_RUNTIME_DIR/dbus/bus";
|
||||||
|
|
||||||
# normally systemd would create a dbus session for us, but if you configure it not to do that
|
# normally systemd would create a dbus session for us, but if you configure it not to do that
|
||||||
# then we can create our own. not sure if there's a dependency ordering issue here: lots
|
# then we can create our own. not sure if there's a dependency ordering issue here: lots
|
||||||
@@ -47,8 +47,12 @@ in
|
|||||||
services.dbus = {
|
services.dbus = {
|
||||||
description = "dbus user session";
|
description = "dbus user session";
|
||||||
partOf = lib.mkIf cfg.config.autostart [ "default" ];
|
partOf = lib.mkIf cfg.config.autostart [ "default" ];
|
||||||
command = "dbus-daemon --session --nofork --address=$DBUS_SESSION_BUS_ADDRESS";
|
command = pkgs.writeShellScript "dbus-start" ''
|
||||||
readiness.waitExists = [ "$XDG_RUNTIME_DIR/bus" ];
|
# have to create the dbus directory before launching so that it's available in the sandbox
|
||||||
|
mkdir -p "$XDG_RUNTIME_DIR/dbus"
|
||||||
|
dbus-daemon --session --nofork --address="$DBUS_SESSION_BUS_ADDRESS"
|
||||||
|
'';
|
||||||
|
readiness.waitExists = [ "$XDG_RUNTIME_DIR/dbus/bus" ];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -25,8 +25,7 @@ in
|
|||||||
};
|
};
|
||||||
|
|
||||||
packageUnwrapped = pkgs.rmDbusServicesInPlace pkgs.dconf;
|
packageUnwrapped = pkgs.rmDbusServicesInPlace pkgs.dconf;
|
||||||
sandbox.method = "bwrap";
|
sandbox.method = "bunpen";
|
||||||
sandbox.wrapperType = "inplace"; #< dbus/systemd services live in `.out` but point to `.lib` data.
|
|
||||||
sandbox.whitelistDbus = [ "user" ];
|
sandbox.whitelistDbus = [ "user" ];
|
||||||
persist.byStore.private = [
|
persist.byStore.private = [
|
||||||
".config/dconf"
|
".config/dconf"
|
||||||
|
@@ -10,21 +10,27 @@
|
|||||||
./assorted.nix
|
./assorted.nix
|
||||||
./audacity.nix
|
./audacity.nix
|
||||||
./ausyscall.nix
|
./ausyscall.nix
|
||||||
|
./avahi.nix
|
||||||
./bemenu.nix
|
./bemenu.nix
|
||||||
|
./bitcoin-cli.nix
|
||||||
./blast-ugjka
|
./blast-ugjka
|
||||||
./bonsai.nix
|
./bonsai.nix
|
||||||
./brave.nix
|
./brave.nix
|
||||||
./brightnessctl.nix
|
./brightnessctl.nix
|
||||||
./bubblewrap.nix
|
./bubblewrap.nix
|
||||||
|
./bunpen.nix
|
||||||
./callaudiod.nix
|
./callaudiod.nix
|
||||||
./calls.nix
|
./calls.nix
|
||||||
./cantata.nix
|
./cantata.nix
|
||||||
|
./capsh.nix
|
||||||
|
./captree.nix
|
||||||
./catt.nix
|
./catt.nix
|
||||||
./celeste64.nix
|
./celeste64.nix
|
||||||
./chatty.nix
|
./chatty.nix
|
||||||
./conky
|
./conky
|
||||||
./cozy.nix
|
./cozy.nix
|
||||||
./cups.nix
|
./cups.nix
|
||||||
|
./curl.nix
|
||||||
./curlftpfs.nix
|
./curlftpfs.nix
|
||||||
./dbus.nix
|
./dbus.nix
|
||||||
./dconf.nix
|
./dconf.nix
|
||||||
@@ -34,15 +40,19 @@
|
|||||||
./dissent.nix
|
./dissent.nix
|
||||||
./dtrx.nix
|
./dtrx.nix
|
||||||
./eg25-control.nix
|
./eg25-control.nix
|
||||||
|
./eg25-manager.nix
|
||||||
./element-desktop.nix
|
./element-desktop.nix
|
||||||
./engrampa.nix
|
./engrampa.nix
|
||||||
./epiphany.nix
|
./epiphany.nix
|
||||||
./errno.nix
|
./errno.nix
|
||||||
./evince.nix
|
./evince.nix
|
||||||
|
./exiftool.nix
|
||||||
./fcitx5.nix
|
./fcitx5.nix
|
||||||
./feedbackd.nix
|
./feedbackd.nix
|
||||||
./firefox.nix
|
./firefox
|
||||||
|
./firefox-xdg-open.nix
|
||||||
./flare-signal.nix
|
./flare-signal.nix
|
||||||
|
./foliate.nix
|
||||||
./fontconfig.nix
|
./fontconfig.nix
|
||||||
./fractal.nix
|
./fractal.nix
|
||||||
./free.nix
|
./free.nix
|
||||||
@@ -50,8 +60,11 @@
|
|||||||
./fwupd.nix
|
./fwupd.nix
|
||||||
./g4music.nix
|
./g4music.nix
|
||||||
./gajim.nix
|
./gajim.nix
|
||||||
|
./gdb.nix
|
||||||
./gdbus.nix
|
./gdbus.nix
|
||||||
./geary.nix
|
./geary.nix
|
||||||
|
./geoclue-demo-agent.nix
|
||||||
|
./geoclue2.nix
|
||||||
./git.nix
|
./git.nix
|
||||||
./gnome-clocks.nix
|
./gnome-clocks.nix
|
||||||
./gnome-feeds.nix
|
./gnome-feeds.nix
|
||||||
@@ -59,38 +72,53 @@
|
|||||||
./gnome-maps.nix
|
./gnome-maps.nix
|
||||||
./gnome-weather.nix
|
./gnome-weather.nix
|
||||||
./go2tv.nix
|
./go2tv.nix
|
||||||
|
./gocryptfs.nix
|
||||||
./gpodder.nix
|
./gpodder.nix
|
||||||
|
./gpsd.nix
|
||||||
|
./gps-share.nix
|
||||||
./grimshot.nix
|
./grimshot.nix
|
||||||
./gst-device-monitor.nix
|
./gst-device-monitor.nix
|
||||||
|
./gst-launch.nix
|
||||||
./gthumb.nix
|
./gthumb.nix
|
||||||
./gvfs.nix
|
./gvfs.nix
|
||||||
./handbrake.nix
|
./handbrake.nix
|
||||||
|
./haredoc.nix
|
||||||
./helix.nix
|
./helix.nix
|
||||||
./htop
|
./htop
|
||||||
|
./iio-sensor-proxy.nix
|
||||||
./imagemagick.nix
|
./imagemagick.nix
|
||||||
|
./inkscape.nix
|
||||||
./jellyfin-media-player.nix
|
./jellyfin-media-player.nix
|
||||||
./kdenlive.nix
|
./kdenlive.nix
|
||||||
|
./keymapp.nix
|
||||||
./komikku.nix
|
./komikku.nix
|
||||||
./koreader
|
./koreader
|
||||||
|
./krita.nix
|
||||||
./less.nix
|
./less.nix
|
||||||
./lftp.nix
|
./lftp.nix
|
||||||
|
./lgtrombetta-compass.nix
|
||||||
|
./libcamera.nix
|
||||||
./libreoffice.nix
|
./libreoffice.nix
|
||||||
./lemoa.nix
|
./lemoa.nix
|
||||||
./loupe.nix
|
./loupe.nix
|
||||||
./mako.nix
|
./mako.nix
|
||||||
./megapixels.nix
|
./megapixels.nix
|
||||||
|
./megapixels-next.nix
|
||||||
./mepo.nix
|
./mepo.nix
|
||||||
./mimeo
|
./mimeo
|
||||||
|
./mimetype.nix
|
||||||
./mmcli.nix
|
./mmcli.nix
|
||||||
./mopidy.nix
|
./mopidy.nix
|
||||||
./mpv
|
./mpv
|
||||||
./msmtp.nix
|
./msmtp.nix
|
||||||
./nautilus.nix
|
./nautilus.nix
|
||||||
./neovim.nix
|
./neovim
|
||||||
|
./networkmanager_dmenu
|
||||||
./newsflash.nix
|
./newsflash.nix
|
||||||
./nheko.nix
|
./nheko.nix
|
||||||
./nicotine-plus.nix
|
./nicotine-plus.nix
|
||||||
./nix-index.nix
|
./nix-index.nix
|
||||||
|
./nix.nix
|
||||||
./nmcli.nix
|
./nmcli.nix
|
||||||
./notejot.nix
|
./notejot.nix
|
||||||
./ntfy-sh.nix
|
./ntfy-sh.nix
|
||||||
@@ -98,30 +126,43 @@
|
|||||||
./objdump.nix
|
./objdump.nix
|
||||||
./obsidian.nix
|
./obsidian.nix
|
||||||
./offlineimap.nix
|
./offlineimap.nix
|
||||||
|
./ols.nix
|
||||||
./open-in-mpv.nix
|
./open-in-mpv.nix
|
||||||
./pactl.nix
|
./pactl.nix
|
||||||
./pipewire.nix
|
./papers.nix
|
||||||
|
./pidof.nix
|
||||||
|
./pipewire
|
||||||
|
./pkill.nix
|
||||||
./planify.nix
|
./planify.nix
|
||||||
./portfolio-filemanager.nix
|
./portfolio-filemanager.nix
|
||||||
./playerctl.nix
|
./playerctl.nix
|
||||||
./ps.nix
|
./ps.nix
|
||||||
|
./qmk-udev-rules.nix
|
||||||
./rhythmbox.nix
|
./rhythmbox.nix
|
||||||
./ripgrep.nix
|
./ripgrep.nix
|
||||||
./rofi
|
./rofi
|
||||||
|
./rsyslog
|
||||||
./rtkit.nix
|
./rtkit.nix
|
||||||
./s6-rc.nix
|
./s6-rc.nix
|
||||||
|
./sane-deadlines.nix
|
||||||
./sane-input-handler
|
./sane-input-handler
|
||||||
./sane-open.nix
|
./sane-open.nix
|
||||||
|
./sane-private-unlock-remote.nix
|
||||||
./sane-screenshot.nix
|
./sane-screenshot.nix
|
||||||
./sane-scripts.nix
|
./sane-scripts.nix
|
||||||
./sane-sysinfo.nix
|
./sane-secrets-unlock.nix
|
||||||
|
./sane-sysload.nix
|
||||||
./sane-theme.nix
|
./sane-theme.nix
|
||||||
./sanebox.nix
|
./sanebox.nix
|
||||||
|
./satellite.nix
|
||||||
./schlock.nix
|
./schlock.nix
|
||||||
./seatd.nix
|
./seatd.nix
|
||||||
./sfeed.nix
|
./sfeed.nix
|
||||||
./shadow.nix
|
./shadow.nix
|
||||||
./signal-desktop.nix
|
./signal-desktop.nix
|
||||||
|
./sm64ex-coop.nix
|
||||||
|
./sm64ex-coop-deluxe.nix
|
||||||
|
./soundconverter.nix
|
||||||
./splatmoji.nix
|
./splatmoji.nix
|
||||||
./spot.nix
|
./spot.nix
|
||||||
./spotify.nix
|
./spotify.nix
|
||||||
@@ -136,14 +177,19 @@
|
|||||||
./swaylock.nix
|
./swaylock.nix
|
||||||
./swaynotificationcenter
|
./swaynotificationcenter
|
||||||
./switchboard.nix
|
./switchboard.nix
|
||||||
./sysvol.nix
|
./syshud.nix
|
||||||
./tangram.nix
|
./tangram.nix
|
||||||
./tor-browser.nix
|
./tor-browser.nix
|
||||||
./tuba.nix
|
./tuba.nix
|
||||||
./unl0kr
|
./unl0kr
|
||||||
|
./v4l-utils.nix
|
||||||
|
./via.nix
|
||||||
|
./visidata.nix
|
||||||
./vlc.nix
|
./vlc.nix
|
||||||
|
./wally-cli.nix
|
||||||
./waybar
|
./waybar
|
||||||
./waylock.nix
|
./waylock.nix
|
||||||
|
./where-am-i.nix
|
||||||
./wike.nix
|
./wike.nix
|
||||||
./wine.nix
|
./wine.nix
|
||||||
./wireplumber.nix
|
./wireplumber.nix
|
||||||
@@ -151,14 +197,19 @@
|
|||||||
./wvkbd.nix
|
./wvkbd.nix
|
||||||
./xarchiver.nix
|
./xarchiver.nix
|
||||||
./xdg-desktop-portal.nix
|
./xdg-desktop-portal.nix
|
||||||
|
./xdg-desktop-portal-gnome
|
||||||
./xdg-desktop-portal-gtk.nix
|
./xdg-desktop-portal-gtk.nix
|
||||||
./xdg-desktop-portal-wlr.nix
|
./xdg-desktop-portal-wlr.nix
|
||||||
./xdg-terminal-exec.nix
|
./xdg-terminal-exec.nix
|
||||||
./xdg-utils.nix
|
./xdg-utils.nix
|
||||||
|
./youtube-tui.nix
|
||||||
|
./yt-dlp.nix
|
||||||
./zathura.nix
|
./zathura.nix
|
||||||
./zeal.nix
|
./zeal.nix
|
||||||
./zecwallet-lite.nix
|
./zecwallet-lite.nix
|
||||||
./zulip.nix
|
./zulip.nix
|
||||||
|
./zsa-udev-rules.nix
|
||||||
|
./zfs-tools.nix
|
||||||
./zsh
|
./zsh
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
buildCost = 1;
|
buildCost = 1;
|
||||||
|
|
||||||
sandbox.method = "bwrap";
|
sandbox.method = "bunpen";
|
||||||
sandbox.wrapperType = "inplace"; # share/search_providers/ calls back into the binary, weird wrap semantics
|
sandbox.wrapperType = "inplace"; # share/search_providers/ calls back into the binary, weird wrap semantics
|
||||||
sandbox.whitelistWayland = true;
|
sandbox.whitelistWayland = true;
|
||||||
sandbox.net = "clearnet";
|
sandbox.net = "clearnet";
|
||||||
|
@@ -50,34 +50,15 @@ in
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
packageUnwrapped = (pkgs.dino.override {
|
packageUnwrapped = pkgs.dino.override {
|
||||||
# XXX(2024/04/24): build without echo cancelation (i.e. force WITH_VOICE_PROCESSOR to be undefined).
|
# XXX(2024/04/24): build without echo cancelation (i.e. force WITH_VOICE_PROCESSOR to be undefined).
|
||||||
# this means that if the other end of the call is on speaker phone, i'm liable to hear my own voice
|
# this means that if the other end of the call is on speaker phone, i'm liable to hear my own voice
|
||||||
# leave their speaker, enter their mic, and then return to me.
|
# leave their speaker, enter their mic, and then return to me.
|
||||||
# the benefit is a >50% reduction in CPU use. insignificant on any modern PC; make-or-break on a low-power Pinephone.
|
# the benefit is a >50% reduction in CPU use. insignificant on any modern PC; make-or-break on a low-power Pinephone.
|
||||||
webrtc-audio-processing = null;
|
webrtc-audio-processing = null;
|
||||||
}).overrideAttrs (upstream: {
|
|
||||||
# i'm updating experimentally to see if it improves call performance.
|
|
||||||
# i don't *think* this is actually necessary; i don't notice any difference.
|
|
||||||
version = "0.4.3-unstable-2024-04-28";
|
|
||||||
src = lib.warnIf (lib.versionOlder "0.4.3" upstream.version) "dino update: safe to remove sane patches" pkgs.fetchFromGitHub {
|
|
||||||
owner = "dino";
|
|
||||||
repo = "dino";
|
|
||||||
rev = "657502955567dd538e56f300e075c7db52e25d74";
|
|
||||||
hash = "sha256-SApJy9FgxxLOB5A/zGtpdFZtSqSiS03vggRrCte1tFE=";
|
|
||||||
};
|
};
|
||||||
# avoid double-application of upstreamed patches
|
|
||||||
# https://github.com/NixOS/nixpkgs/pull/309265
|
|
||||||
patches = [];
|
|
||||||
checkPhase = ''
|
|
||||||
runHook preCheck
|
|
||||||
./xmpp-vala-test
|
|
||||||
# ./signal-protocol-vala-test # doesn't exist anymore
|
|
||||||
runHook postCheck
|
|
||||||
'';
|
|
||||||
});
|
|
||||||
|
|
||||||
sandbox.method = "bwrap";
|
sandbox.method = "bunpen";
|
||||||
sandbox.net = "clearnet";
|
sandbox.net = "clearnet";
|
||||||
sandbox.whitelistAudio = true;
|
sandbox.whitelistAudio = true;
|
||||||
sandbox.whitelistDbus = [ "user" ]; # notifications
|
sandbox.whitelistDbus = [ "user" ]; # notifications
|
||||||
|
@@ -31,7 +31,7 @@ in
|
|||||||
--replace-fail '"login"' '"Default_keyring"'
|
--replace-fail '"login"' '"Default_keyring"'
|
||||||
'';
|
'';
|
||||||
});
|
});
|
||||||
sandbox.method = "bwrap";
|
sandbox.method = "bunpen";
|
||||||
sandbox.net = "clearnet";
|
sandbox.net = "clearnet";
|
||||||
sandbox.whitelistAudio = true;
|
sandbox.whitelistAudio = true;
|
||||||
sandbox.whitelistDbus = [ "user" ]; # notifications
|
sandbox.whitelistDbus = [ "user" ]; # notifications
|
||||||
|
@@ -9,7 +9,7 @@
|
|||||||
# build without rpm support, since `rpm` package doesn't cross-compile.
|
# build without rpm support, since `rpm` package doesn't cross-compile.
|
||||||
rpm = null;
|
rpm = null;
|
||||||
};
|
};
|
||||||
sandbox.method = "bwrap";
|
sandbox.method = "bunpen";
|
||||||
sandbox.whitelistPwd = true;
|
sandbox.whitelistPwd = true;
|
||||||
sandbox.autodetectCliPaths = "existing"; #< for the archive
|
sandbox.autodetectCliPaths = "existing"; #< for the archive
|
||||||
};
|
};
|
||||||
|
@@ -6,6 +6,18 @@ in
|
|||||||
sane.programs.eg25-control = {
|
sane.programs.eg25-control = {
|
||||||
suggestedPrograms = [ "mmcli" ];
|
suggestedPrograms = [ "mmcli" ];
|
||||||
|
|
||||||
|
sandbox.method = "bunpen";
|
||||||
|
sandbox.extraPaths = [
|
||||||
|
"/dev/gpiochip1"
|
||||||
|
"/sys/class/modem-power"
|
||||||
|
"/sys/devices"
|
||||||
|
# "/var/lib/eg25-control"
|
||||||
|
];
|
||||||
|
sandbox.net = "all"; #< for downloading the almanac
|
||||||
|
sandbox.whitelistDbus = [
|
||||||
|
"system" #< used by `mmcli`
|
||||||
|
];
|
||||||
|
|
||||||
services.eg25-control-powered = {
|
services.eg25-control-powered = {
|
||||||
description = "eg25-control-powered: power to the Qualcomm eg25 modem used by PinePhone";
|
description = "eg25-control-powered: power to the Qualcomm eg25 modem used by PinePhone";
|
||||||
startCommand = "eg25-control --power-on --verbose";
|
startCommand = "eg25-control --power-on --verbose";
|
||||||
@@ -21,6 +33,7 @@ in
|
|||||||
startCommand = "eg25-control --enable-gps --dump-debug-info --verbose";
|
startCommand = "eg25-control --enable-gps --dump-debug-info --verbose";
|
||||||
cleanupCommand = "eg25-control --disable-gps --dump-debug-info --verbose";
|
cleanupCommand = "eg25-control --disable-gps --dump-debug-info --verbose";
|
||||||
depends = [ "eg25-control-powered" ];
|
depends = [ "eg25-control-powered" ];
|
||||||
|
partOf = [ "gps" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
persist.byStore.plaintext = [ ".cache/eg25-control" ]; #< for cached agps data
|
persist.byStore.plaintext = [ ".cache/eg25-control" ]; #< for cached agps data
|
||||||
|
13
hosts/common/programs/eg25-manager.nix
Normal file
13
hosts/common/programs/eg25-manager.nix
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{ config, lib, ... }:
|
||||||
|
let
|
||||||
|
cfg = config.sane.programs.eg25-manager;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
sane.programs.eg25-manager = {
|
||||||
|
# it has to be enabled system-wide for its udev rules to make it into /run/current-system/sw/lib/udev/rules.d.
|
||||||
|
enableFor.system = lib.mkIf (builtins.any (en: en) (builtins.attrValues cfg.enableFor.user)) true;
|
||||||
|
};
|
||||||
|
|
||||||
|
# not sure if this is required or if it's enough that eg25-manager is on system.packages.
|
||||||
|
services.udev.packages = lib.mkIf cfg.enabled [ cfg.package ];
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user