Compare commits
907 Commits
wip-secure
...
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 |
@@ -17,8 +17,6 @@ the only hard dependency for my exported pkgs/modules should be [nixpkgs][nixpkg
|
||||
building [hosts/](./hosts/) will require [sops][sops].
|
||||
|
||||
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 way of deploying dotfiles/configuring programs per-user:
|
||||
- [modules/fs/](./modules/fs/default.nix)
|
||||
|
61
TODO.md
61
TODO.md
@@ -2,18 +2,21 @@
|
||||
- `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.
|
||||
- `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)
|
||||
- or try dnsmasq?
|
||||
- trust-dns can't resolve `abs.twimg.com`
|
||||
- trust-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 `abs.twimg.com`
|
||||
- hickory-dns can't resolve `social.kernel.org`
|
||||
- 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: no way to exit fullscreen video on moby
|
||||
- uosc hides controls on FS, and touch doesn't support unhiding
|
||||
- `ssh` access doesn't grant same linux capabilities as login
|
||||
- syshud (volume overlay): when casting with `blast`, syshud 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
|
||||
- `dmesg | grep "KASLR disabled due to lack of seed"`
|
||||
- fix by adding `kaslrseed` to uboot script before `booti`
|
||||
@@ -24,8 +27,19 @@
|
||||
- `dmesg | grep 'hid_bpf: error while preloading HID BPF dispatcher: -22'`
|
||||
- `s6` is not re-entrant
|
||||
- so if the desktop crashes, the login process from `unl0kr` fails to re-launch the GUI
|
||||
- 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:
|
||||
- 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
|
||||
- consolidate ~/dev and ~/ref
|
||||
- ~/dev becomes a link to ~/ref/cat/mine
|
||||
@@ -47,40 +61,32 @@
|
||||
|
||||
#### upstreaming to non-nixpkgs repos
|
||||
- gtk: build schemas even on cross compilation: <https://github.com/NixOS/nixpkgs/pull/247844>
|
||||
- gnome-calls retry net connection when DNS is down
|
||||
|
||||
|
||||
## 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
|
||||
- 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
|
||||
- validate duplicity backups!
|
||||
- encrypt more ~ dirs (~/archives, ~/records, ..?)
|
||||
- best to do this after i know for sure i have good backups
|
||||
- enable `snapper` btrfs snapshots (`services.snapper`)
|
||||
- /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)
|
||||
- port all sane.programs to be sandboxed
|
||||
- sandbox `curlftpfs`
|
||||
- sandbox `nix`
|
||||
- sandbox `sshfs-fuse`
|
||||
- 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
|
||||
- otherwise anyone can `systemd-run --user ...` to potentially escape a sandbox
|
||||
- <https://github.com/flatpak/xdg-dbus-proxy>
|
||||
- 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
|
||||
- i.e. per-app dconf profiles for those which need it. possible static config.
|
||||
- flatpak/spectrum has some stuff to proxy dconf per-app
|
||||
@@ -116,27 +122,28 @@
|
||||
|
||||
#### moby
|
||||
- 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
|
||||
- SwayNC:
|
||||
- don't show MPRIS if no players detected
|
||||
- this is a problem of playerctld, i guess
|
||||
- add option to change audio output
|
||||
- SwayNC: add option to change audio output
|
||||
- moby: tune GPS
|
||||
- fix iio-sensor-proxy magnetometer scaling
|
||||
- tune QGPS setting in eg25-control, for less jitter?
|
||||
- configure geoclue to do some smoothing?
|
||||
- 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: show battery state on ssh login
|
||||
- moby: improve gPodder launch time
|
||||
- moby: theme GTK apps (i.e. non-adwaita styles)
|
||||
- especially, make the menubar collapsible
|
||||
- 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
|
||||
- RSS: integrate a paywall bypass
|
||||
- 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
|
||||
- Helix: make copy-to-system clipboard be the default
|
||||
- firefox/librewolf: persist history
|
||||
|
@@ -30,16 +30,4 @@
|
||||
# sane.programs.guiApps.enableFor.user.colin = false;
|
||||
|
||||
# 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,10 +1,10 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
{ config, pkgs, ... }:
|
||||
{
|
||||
imports = [
|
||||
./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.guest.enable = true;
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
sane.services.wg-home.ip = config.sane.hosts.by-name."desko".wg-home.ip;
|
||||
sane.ovpn.addrV4 = "172.26.55.21";
|
||||
# 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;
|
||||
@@ -40,28 +39,30 @@
|
||||
sane.programs.iphoneUtils.enableFor.user.colin = true;
|
||||
sane.programs.steam.enableFor.user.colin = true;
|
||||
|
||||
sane.programs.geary.config.autostart = true;
|
||||
sane.programs.signal-desktop.config.autostart = true;
|
||||
|
||||
sane.programs.nwg-panel.config = {
|
||||
battery = false;
|
||||
brightness = false;
|
||||
};
|
||||
|
||||
sane.programs.mpv.config.defaultProfile = "high-quality";
|
||||
|
||||
sane.image.extraBootFiles = [ pkgs.bootpart-uefi-x86_64 ];
|
||||
|
||||
# needed to use libimobiledevice/ifuse, for iphone sync
|
||||
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
|
||||
# defaults to something like:
|
||||
# - hourly snapshots
|
||||
# - auto cleanup; keep the last 10 hourlies, last 10 daylies, last 10 monthlys.
|
||||
services.snapper.configs.nix = {
|
||||
# TODO: for the impermanent setup, we'd prefer to just do /nix/persist,
|
||||
# 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" ];
|
||||
};
|
||||
# to list snapshots: `sudo snapper --config nix list`
|
||||
# to take a snapshot: `sudo snapper --config nix create`
|
||||
# services.snapper.configs.nix = {
|
||||
# # TODO: for the impermanent setup, we'd prefer to just do /nix/persist,
|
||||
# # 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" ];
|
||||
# };
|
||||
}
|
||||
|
@@ -21,21 +21,22 @@
|
||||
sane.programs.stepmania.enableFor.user.colin = true;
|
||||
sane.programs.sway.enableFor.user.colin = true;
|
||||
|
||||
sane.programs.geary.config.autostart = true;
|
||||
sane.programs.signal-desktop.config.autostart = 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
|
||||
# defaults to something like:
|
||||
# - hourly snapshots
|
||||
# - auto cleanup; keep the last 10 hourlies, last 10 daylies, last 10 monthlys.
|
||||
services.snapper.configs.nix = {
|
||||
# TODO: for the impermanent setup, we'd prefer to just do /nix/persist,
|
||||
# but that also requires setting up the persist dir as a subvol
|
||||
SUBVOLUME = "/nix";
|
||||
ALLOW_USERS = [ "colin" ];
|
||||
};
|
||||
# to list snapshots: `sudo snapper --config nix list`
|
||||
# to take a snapshot: `sudo snapper --config nix create`
|
||||
# services.snapper.configs.nix = {
|
||||
# # TODO: for the impermanent setup, we'd prefer to just do /nix/persist,
|
||||
# # 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,7 +6,7 @@
|
||||
# - Mobian wiki: <https://wiki.mobian-project.org/doku.php?id=start>
|
||||
# - recommended apps, chatrooms
|
||||
|
||||
{ config, pkgs, lib, ... }:
|
||||
{ config, ... }:
|
||||
{
|
||||
imports = [
|
||||
./fs.nix
|
||||
@@ -30,20 +30,17 @@
|
||||
|
||||
sane.programs.sway.enableFor.user.colin = true;
|
||||
sane.programs.sway.config.mod = "Mod1"; #< alt key instead of Super
|
||||
sane.programs.blueberry.enableFor.user.colin = false; # bluetooth manager: doesn't cross compile!
|
||||
sane.programs.fcitx5.enableFor.user.colin = false; # does not cross compile
|
||||
sane.programs.mercurial.enableFor.user.colin = false; # does not cross compile
|
||||
sane.programs.nvme-cli.enableFor.system = false; # does not cross compile (libhugetlbfs)
|
||||
|
||||
# enabled for easier debugging
|
||||
sane.programs.eg25-control.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.dino.config.autostart = true;
|
||||
sane.programs.signal-desktop.config.autostart = true;
|
||||
# sane.programs.geary.config.autostart = true;
|
||||
# sane.programs.calls.config.autostart = true;
|
||||
sane.programs.signal-desktop.config.autostart = false;
|
||||
sane.programs.geary.config.autostart = false;
|
||||
|
||||
sane.programs.pipewire.config = {
|
||||
# tune so Dino doesn't drop audio
|
||||
@@ -61,6 +58,8 @@
|
||||
max-quantum = 8192;
|
||||
};
|
||||
|
||||
sane.programs.mpv.config.defaultProfile = "fast";
|
||||
|
||||
# /boot space is at a premium. default was 20.
|
||||
# even 10 can be too much
|
||||
boot.loader.generic-extlinux-compatible.configurationLimit = 8;
|
||||
|
@@ -21,7 +21,7 @@
|
||||
"sane-scripts.stop-all-servo"
|
||||
];
|
||||
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.visibleToWan = true;
|
||||
sane.services.wg-home.forwardToWan = true;
|
||||
@@ -31,7 +31,6 @@
|
||||
# sane.ovpn.addrV6 = "fd00:0000:1337:cafe:1111:1111:8df3:14b0";
|
||||
sane.nixcache.remote-builders.desko = 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.
|
||||
|
@@ -7,6 +7,7 @@
|
||||
./ejabberd.nix
|
||||
./freshrss.nix
|
||||
./export
|
||||
./hickory-dns.nix
|
||||
./gitea.nix
|
||||
./goaccess.nix
|
||||
./ipfs.nix
|
||||
@@ -20,13 +21,13 @@
|
||||
./nginx.nix
|
||||
./nixos-prebuild.nix
|
||||
./ntfy
|
||||
./ollama.nix
|
||||
./pict-rs.nix
|
||||
./pleroma.nix
|
||||
./postgres.nix
|
||||
./prosody
|
||||
./slskd.nix
|
||||
./transmission
|
||||
./trust-dns.nix
|
||||
./wikipedia.nix
|
||||
];
|
||||
}
|
||||
|
@@ -1,4 +1,11 @@
|
||||
# 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
|
||||
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
@@ -20,12 +27,12 @@ in
|
||||
{
|
||||
sane.persist.sys.byStore.private = [
|
||||
# TODO: mode? could be more granular
|
||||
{ user = "opendkim"; group = "opendkim"; path = "/var/lib/opendkim"; method = "bind"; }
|
||||
{ user = "root"; group = "root"; path = "/var/lib/postfix"; method = "bind"; } #< probably not *all* of postfix needs to actually be persisted (e.g. not the conf dir)
|
||||
{ user = "opendkim"; group = "opendkim"; path = "/var/lib/opendkim"; method = "bind"; } #< TODO: migrate to secrets
|
||||
{ user = "root"; group = "root"; path = "/var/spool/mail"; method = "bind"; }
|
||||
# *probably* don't need these dirs:
|
||||
# "/var/lib/dhparams" # https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/security/dhparams.nix
|
||||
# "/var/lib/dovecot"
|
||||
# "/var/lib/postfix"
|
||||
];
|
||||
|
||||
# XXX(2023/10/20): opening these ports in the firewall has the OPPOSITE effect as intended.
|
||||
@@ -95,6 +102,7 @@ in
|
||||
services.postfix.sslCert = "/var/lib/acme/mx.uninsane.org/fullchain.pem";
|
||||
services.postfix.sslKey = "/var/lib/acme/mx.uninsane.org/key.pem";
|
||||
|
||||
# see: `man 5 virtual`
|
||||
services.postfix.virtual = ''
|
||||
notify.matrix@uninsane.org matrix-synapse
|
||||
@uninsane.org colin
|
||||
@@ -135,6 +143,20 @@ in
|
||||
# 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.submissionOptions = submissionOptions;
|
||||
services.postfix.enableSubmissions = true;
|
||||
@@ -142,6 +164,10 @@ in
|
||||
|
||||
systemd.services.postfix.after = [ "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 = {
|
||||
# run this behind the OVPN static VPN
|
||||
NetworkNamespacePath = "/run/netns/ovpns";
|
||||
@@ -175,23 +201,30 @@ in
|
||||
|
||||
|
||||
#### OUTGOING MESSAGE REWRITING:
|
||||
services.postfix.enableHeaderChecks = true;
|
||||
services.postfix.headerChecks = [
|
||||
# intercept gitea registration confirmations and manually screen them
|
||||
{
|
||||
# headerChecks are somehow ignorant of alias rules: have to redirect to a real user
|
||||
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/";
|
||||
# }
|
||||
];
|
||||
# - `man 5 header_checks`
|
||||
# - <https://www.postfix.org/header_checks.5.html>
|
||||
# - populates `/var/lib/postfix/conf/header_checks`
|
||||
# XXX(2024-08-06): registration gating via email matches is AWFUL:
|
||||
# 1. bypassed if the service offers localization.
|
||||
# 2. if i try to forward the registration request, it may match the filter again and get sent back to my inbox.
|
||||
# 3. header checks are possibly under-used in the ecosystem, and may break postfix config.
|
||||
# services.postfix.enableHeaderChecks = true;
|
||||
# services.postfix.headerChecks = [
|
||||
# # intercept gitea registration confirmations and manually screen them
|
||||
# {
|
||||
# # headerChecks are somehow ignorant of alias rules: have to redirect to a real user
|
||||
# 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,15 +37,15 @@
|
||||
wantedBy = [ "nfs.service" "sftpgo.service" ];
|
||||
file.text = ''
|
||||
- media/ read-only: Videos, Music, Books, etc
|
||||
- playground/ read-write: use it to share files with other users of this server, inaccessible from the www
|
||||
- pub/ read-only: content made to be shared with the www
|
||||
- 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" = {
|
||||
wantedBy = [ "nfs.service" "sftpgo.service" ];
|
||||
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
|
||||
- write poetry
|
||||
- be a friendly troll
|
||||
|
@@ -71,6 +71,9 @@ TRUSTED_CREDS = [
|
||||
# $<method>$<salt>$<hash>
|
||||
"$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:
|
||||
return dict(
|
||||
@@ -112,8 +115,8 @@ def isLan(ip: str) -> bool:
|
||||
def isWireguard(ip: str) -> bool:
|
||||
return ip.startswith("10.0.10.")
|
||||
|
||||
def isTrustedCred(password: str) -> bool:
|
||||
for cred in TRUSTED_CREDS:
|
||||
def isTrustedCred(password: str, credlist: list[str] = TRUSTED_CREDS) -> bool:
|
||||
for cred in credlist:
|
||||
if passlib.hosts.linux_context.verify(password, cred):
|
||||
return True
|
||||
|
||||
@@ -131,6 +134,21 @@ def getAuthResponse(ip: str, username: str, password: str) -> dict:
|
||||
"/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):
|
||||
# allow any user from wireguard
|
||||
return mkAuthOk(username, permissions = {
|
||||
|
@@ -1,10 +1,14 @@
|
||||
# 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, ... }:
|
||||
|
||||
{
|
||||
sane.persist.sys.byStore.private = [
|
||||
{ user = "git"; group = "gitea"; mode = "0750"; path = "/var/lib/gitea"; method = "bind"; }
|
||||
];
|
||||
|
||||
sane.programs.gitea.enableFor.user.colin = true; # for admin, and monitoring
|
||||
|
||||
services.gitea.enable = true;
|
||||
services.gitea.user = "git"; # default is 'gitea'
|
||||
services.gitea.database.type = "postgres";
|
||||
@@ -40,14 +44,21 @@
|
||||
# timeout for email approval. 5760 = 4 days. 10080 = 7 days
|
||||
ACTIVE_CODE_LIVE_MINUTES = 10080;
|
||||
# REGISTER_EMAIL_CONFIRM = false;
|
||||
# REGISTER_MANUAL_CONFIRM = true;
|
||||
REGISTER_EMAIL_CONFIRM = true;
|
||||
# REGISTER_EMAIL_CONFIRM = true; #< override REGISTER_MANUAL_CONFIRM
|
||||
REGISTER_MANUAL_CONFIRM = true;
|
||||
# not sure what this notifies *on*...
|
||||
ENABLE_NOTIFY_MAIL = true;
|
||||
# defaults to image-based captcha.
|
||||
# also supports recaptcha (with custom URLs) or hCaptcha.
|
||||
ENABLE_CAPTCHA = true;
|
||||
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 = {
|
||||
COOKIE_SECURE = true;
|
||||
|
@@ -55,7 +55,7 @@ in
|
||||
];
|
||||
};
|
||||
|
||||
services.trust-dns.settings.zones = [ "uninsane.org" ];
|
||||
services.hickory-dns.settings.zones = [ "uninsane.org" ];
|
||||
|
||||
|
||||
networking.nat.enable = true; #< TODO: try removing this?
|
||||
@@ -83,8 +83,8 @@ in
|
||||
# };
|
||||
|
||||
|
||||
sane.services.trust-dns.enable = true;
|
||||
sane.services.trust-dns.instances = let
|
||||
sane.services.hickory-dns.enable = true;
|
||||
sane.services.hickory-dns.instances = let
|
||||
mkSubstitutions = flavor: {
|
||||
"%ADOOF%" = config.sane.netns.doof.netnsPubIpv4;
|
||||
"%ANATIVE%" = nativeAddrs."servo.${flavor}";
|
||||
@@ -141,5 +141,5 @@ in
|
||||
# };
|
||||
};
|
||||
|
||||
sane.services.dyn-dns.restartOnChange = lib.map (c: "${c.service}.service") (builtins.attrValues config.sane.services.trust-dns.instances);
|
||||
sane.services.dyn-dns.restartOnChange = lib.map (c: "${c.service}.service") (builtins.attrValues config.sane.services.hickory-dns.instances);
|
||||
}
|
@@ -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`
|
||||
# - delete a notification destination by setting `kind` to `null` (otherwise, request is identical to above)
|
||||
#
|
||||
{ config, lib, pkgs, ... }:
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
{
|
||||
imports = [
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
# services.matrix-synapse.enable_registration_captcha = 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>";
|
||||
|
||||
# default for listeners is port = 8448, tls = true, x_forwarded = false.
|
||||
|
@@ -1,6 +1,6 @@
|
||||
# config docs:
|
||||
# - <https://github.com/matrix-org/matrix-appservice-irc/blob/develop/config.sample.yaml>
|
||||
{ config, lib, ... }:
|
||||
{ lib, ... }:
|
||||
|
||||
let
|
||||
ircServer = { name, additionalAddresses ? [], ssl ? true, sasl ? true, port ? if ssl then 6697 else 6667 }: let
|
||||
@@ -128,6 +128,7 @@ in
|
||||
|
||||
ircService = {
|
||||
logging.level = "warn"; # "error", "warn", "info", "debug"
|
||||
mediaProxy.publicUrl = "https://irc.matrix.uninsane.org/media";
|
||||
servers = {
|
||||
"irc.esper.net" = ircServer {
|
||||
name = "esper";
|
||||
@@ -168,4 +169,16 @@ in
|
||||
# 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";
|
||||
};
|
||||
|
||||
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";
|
||||
};
|
||||
}
|
||||
|
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;
|
||||
}
|
@@ -40,10 +40,11 @@ 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/"
|
||||
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"/*)
|
||||
|
@@ -25,10 +25,14 @@
|
||||
|
||||
# moby has to run recent kernels (defined elsewhere).
|
||||
# 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,
|
||||
# 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.
|
||||
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.
|
||||
boot.initrd.preFailCommands = "allowShell=1";
|
||||
|
@@ -1,4 +1,4 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
{ lib, pkgs, ... }:
|
||||
{
|
||||
imports = [
|
||||
./boot.nix
|
||||
|
@@ -57,8 +57,10 @@ let
|
||||
};
|
||||
|
||||
podcasts = [
|
||||
(fromDb "404media.co/the-404-media-podcast" // tech)
|
||||
(fromDb "acquiredlpbonussecretsecret.libsyn.com" // tech) # ACQ2 - more "Acquired" episodes
|
||||
(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/2da69154/podcast/rss" // tech) # POD OF JAKE -- https://podofjake.com/
|
||||
(fromDb "cast.postmarketos.org" // tech)
|
||||
@@ -70,7 +72,9 @@ let
|
||||
(fromDb "feeds.feedburner.com/80000HoursPodcast" // 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.megaphone.fm/GLT1412515089" // pol) # JRE: Joe Rogan Experience
|
||||
(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.simplecast.com/82FI35Px" // pol) # Ezra Klein Show
|
||||
(fromDb "feeds.simplecast.com/wgl4xEgL" // rat) # Econ Talk
|
||||
@@ -83,6 +87,7 @@ let
|
||||
(fromDb "hackerpublicradio.org" // tech)
|
||||
(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 "microarch.club" // tech)
|
||||
(fromDb "mintcast.org" // tech)
|
||||
@@ -90,6 +95,7 @@ let
|
||||
(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/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 "politicalorphanage.libsyn.com" // pol)
|
||||
(fromDb "reverseengineering.libsyn.com/rss" // tech) # UnNamed Reverse Engineering Podcast
|
||||
@@ -107,7 +113,6 @@ let
|
||||
(fromDb "theamphour.com" // tech)
|
||||
(fromDb "techtalesshow.com" // tech) # Corbin Davenport
|
||||
(fromDb "techwontsave.us" // pol) # rec by Cory Doctorow
|
||||
(fromDb "wakingup.libsyn.com" // pol) # Sam Harris
|
||||
(fromDb "werenotwrong.fireside.fm" // pol)
|
||||
(mkPod "https://sfconservancy.org/casts/the-corresponding-source/feeds/ogg/" // tech)
|
||||
|
||||
@@ -121,6 +126,7 @@ let
|
||||
# (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 "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://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>
|
||||
@@ -131,6 +137,7 @@ let
|
||||
(fromDb "acoup.blog/feed") # history, states. author: <https://historians.social/@bretdevereaux/following>
|
||||
(fromDb "amosbbatto.wordpress.com" // tech)
|
||||
(fromDb "anish.lakhwara.com" // tech)
|
||||
(fromDb "antipope.org") # Charles Stross
|
||||
(fromDb "apenwarr.ca/log/rss.php" // tech) # CEO of tailscale
|
||||
(fromDb "applieddivinitystudies.com" // rat)
|
||||
(fromDb "artemis.sh" // tech)
|
||||
@@ -145,6 +152,7 @@ let
|
||||
(fromDb "blog.jmp.chat" // tech)
|
||||
(fromDb "blog.rust-lang.org" // tech)
|
||||
(fromDb "blog.thalheim.io" // tech) # Mic92
|
||||
(fromDb "blog.brixit.nl" // tech) # Martijn Braam
|
||||
(fromDb "bunniestudios.com" // tech) # Bunnie Juang
|
||||
(fromDb "capitolhillseattle.com" // pol)
|
||||
(fromDb "edwardsnowden.substack.com" // pol // text)
|
||||
@@ -157,6 +165,7 @@ let
|
||||
(fromDb "interconnected.org/home/feed" // rat) # Matt Webb -- engineering-ish, but dreamy
|
||||
(fromDb "jeffgeerling.com" // tech)
|
||||
(fromDb "jefftk.com" // tech)
|
||||
(fromDb "justine.lol" // tech)
|
||||
(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 "kosmosghost.github.io/index.xml" // tech)
|
||||
@@ -235,6 +244,7 @@ let
|
||||
(fromDb "youtube.com/@Exurb1a")
|
||||
(fromDb "youtube.com/@hbomberguy")
|
||||
(fromDb "youtube.com/@JackStauber")
|
||||
(fromDb "youtube.com/@mii_beta" // tech) # Baby Wogue / gnome reviewer
|
||||
(fromDb "youtube.com/@NativLang")
|
||||
(fromDb "youtube.com/@PolyMatter")
|
||||
(fromDb "youtube.com/@TechnologyConnections" // tech)
|
||||
|
@@ -2,7 +2,7 @@
|
||||
# - x-systemd options: <https://www.freedesktop.org/software/systemd/man/systemd.mount.html>
|
||||
# - fuse options: `man mount.fuse`
|
||||
|
||||
{ config, lib, pkgs, sane-lib, utils, ... }:
|
||||
{ config, lib, utils, ... }:
|
||||
|
||||
let
|
||||
fsOpts = rec {
|
||||
@@ -45,7 +45,7 @@ let
|
||||
"gid=100"
|
||||
];
|
||||
|
||||
ssh = common ++ fuse ++ [
|
||||
ssh = common ++ fuseColin ++ [
|
||||
"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.e., local colin's id is translated to/from remote colin's id on every operation?
|
||||
@@ -64,39 +64,6 @@ let
|
||||
# # 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"
|
||||
# ];
|
||||
# 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.
|
||||
# curlftpfs -o ftpfs_debug=2,user=anonymous:anonymous,connect_timeout=10 -f -s ftp://servo-hn /mnt/my-ftp
|
||||
@@ -107,18 +74,64 @@ let
|
||||
"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;
|
||||
fileSystems."/mnt/${host}/home" = {
|
||||
device = "colin@${host}:/home/colin";
|
||||
fsType = "fuse.sshfs";
|
||||
options = fsOpts.sshColin ++ fsOpts.lazyMount;
|
||||
system.fsPackages = [
|
||||
config.sane.programs.sshfs-fuse.package
|
||||
];
|
||||
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;
|
||||
};
|
||||
sane.fs."/mnt/${host}/home" = sane-lib.fs.wanted {
|
||||
sane.fs."/mnt/${name}/home" = {
|
||||
dir.acl.user = "colin";
|
||||
dir.acl.group = "users";
|
||||
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: let
|
||||
@@ -126,36 +139,122 @@ let
|
||||
systemdName = utils.escapeSystemdPath localPath;
|
||||
in {
|
||||
sane.programs.curlftpfs.enableFor.system = true;
|
||||
sane.fs."${localPath}" = 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.group = "users";
|
||||
dir.acl.mode = "0750";
|
||||
};
|
||||
fileSystems."${localPath}" = {
|
||||
device = "ftp://servo-hn:/${subdir}";
|
||||
noCheck = true;
|
||||
fsType = "fuse.curlftpfs";
|
||||
options = fsOpts.ftp ++ fsOpts.noauto;
|
||||
# fsType = "nfs";
|
||||
# options = fsOpts.nfs ++ fsOpts.lazyMount;
|
||||
};
|
||||
|
||||
systemd.mounts = let
|
||||
fsEntry = config.fileSystems."${localPath}";
|
||||
in [{
|
||||
#VVV repeat what systemd would ordinarily scrape from /etc/fstab
|
||||
where = localPath;
|
||||
what = fsEntry.device;
|
||||
type = fsEntry.fsType;
|
||||
options = lib.concatStringsSep "," fsEntry.options;
|
||||
after = [ "network-online.target" ];
|
||||
requires = [ "network-online.target" ];
|
||||
wantedBy = [ "default.target" ]; #< TODO: move this into nixos fileSystems
|
||||
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
|
||||
onFailure = [ "${systemdName}.timer" ];
|
||||
onSuccess = [ "${systemdName}-restart-timer.target" ];
|
||||
}];
|
||||
mount.unitConfig.OnFailure = [ "${systemdName}.timer" ];
|
||||
mount.unitConfig.OnSuccess = [ "${systemdName}-restart-timer.target" ];
|
||||
|
||||
mount.mountConfig.TimeoutSec = "10s";
|
||||
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-servo-playground.mount)
|
||||
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.10.5";
|
||||
mount.mountConfig.DevicePolicy = "closed"; # only allow /dev/{null,zero,full,random,urandom}
|
||||
mount.mountConfig.DeviceAllow = "/dev/fuse";
|
||||
# mount.mountConfig.RestrictNamespaces = true;
|
||||
};
|
||||
|
||||
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" ];
|
||||
@@ -212,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)
|
||||
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.
|
||||
}
|
||||
|
||||
(remoteHome "crappy")
|
||||
(remoteHome "desko")
|
||||
(remoteHome "lappy")
|
||||
(remoteHome "moby")
|
||||
(ifSshAuthorized (remoteHome "crappy" {}))
|
||||
(ifSshAuthorized (remoteHome "desko" {}))
|
||||
(ifSshAuthorized (remoteHome "lappy" {}))
|
||||
(ifSshAuthorized (remoteHome "moby" { host = "moby-hn"; }))
|
||||
(ifSshAuthorized (remoteHome "servo" {}))
|
||||
# this granularity of servo media mounts is necessary to support sandboxing:
|
||||
# for flaky mounts, we can only bind the mountpoint itself into the sandbox,
|
||||
# so it's either this or unconditionally bind all of media/.
|
||||
|
@@ -9,12 +9,10 @@
|
||||
"Books/local"
|
||||
"Music"
|
||||
|
||||
# these are persisted simply to save on RAM.
|
||||
# ~/.cache/nix can become several GB.
|
||||
# mesa_shader_cache is < 10 MB.
|
||||
# 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/nix"
|
||||
".cache/mesa_shader_cache_db"
|
||||
];
|
||||
sane.user.persist.byStore.private = [
|
||||
"archive"
|
||||
|
@@ -45,8 +45,8 @@
|
||||
sane.ids.pict-rs.gid = 2409;
|
||||
sane.ids.sftpgo.uid = 2410;
|
||||
sane.ids.sftpgo.gid = 2410;
|
||||
sane.ids.trust-dns.uid = 2411;
|
||||
sane.ids.trust-dns.gid = 2411;
|
||||
sane.ids.hickory-dns.uid = 2411; #< previously "trust-dns"
|
||||
sane.ids.hickory-dns.gid = 2411; #< previously "trust-dns"
|
||||
sane.ids.export.gid = 2412;
|
||||
sane.ids.nfsuser.uid = 2413;
|
||||
sane.ids.media.gid = 2414;
|
||||
@@ -63,6 +63,8 @@
|
||||
sane.ids.nix-serve.uid = 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.guest.uid = 1100;
|
||||
|
@@ -1,4 +1,4 @@
|
||||
{ lib, ... }:
|
||||
{ ... }:
|
||||
|
||||
{
|
||||
imports = [
|
||||
|
@@ -23,16 +23,16 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
lib.mkMerge [
|
||||
{
|
||||
sane.services.trust-dns.enable = lib.mkDefault config.sane.services.trust-dns.asSystemResolver;
|
||||
sane.services.trust-dns.asSystemResolver = lib.mkDefault true;
|
||||
sane.services.hickory-dns.enable = lib.mkDefault config.sane.services.hickory-dns.asSystemResolver;
|
||||
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.
|
||||
# /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
|
||||
# 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?)
|
||||
# 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`.
|
||||
# without DNSSEC:
|
||||
# - dig matrix.org => works
|
||||
@@ -40,7 +40,7 @@ lib.mkMerge [
|
||||
# with default DNSSEC:
|
||||
# - dig matrix.org => works
|
||||
# - 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";
|
||||
networking.nameservers = [
|
||||
# use systemd-resolved resolver
|
||||
@@ -74,7 +74,7 @@ lib.mkMerge [
|
||||
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 trust-dns delegate .local to avahi
|
||||
# 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";
|
||||
|
@@ -37,7 +37,11 @@
|
||||
# serviceConfig.RestrictAddressFamilies = "AF_NETLINK AF_UNIX AF_QIPCRTR";
|
||||
# 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.PrivateUsers = true; #< untried, not likely to work since it needs capabilities
|
||||
serviceConfig.PrivateTmp = true;
|
||||
|
@@ -48,7 +48,9 @@ in {
|
||||
# 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
|
||||
# (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 \
|
||||
$out/share/dbus-1/system.d/networkmanager-$f \
|
||||
--replace-fail 'user="root"' 'group="networkmanager"'
|
||||
@@ -66,6 +68,11 @@ in {
|
||||
serviceConfig.User = "networkmanager";
|
||||
serviceConfig.Group = "networkmanager";
|
||||
serviceConfig.AmbientCapabilities = [
|
||||
"CAP_NET_ADMIN"
|
||||
"CAP_NET_RAW"
|
||||
"CAP_NET_BIND_SERVICE"
|
||||
];
|
||||
serviceConfig.CapabilityBoundingSet = [
|
||||
# "CAP_DAC_OVERRIDE"
|
||||
"CAP_NET_ADMIN"
|
||||
"CAP_NET_RAW" #< required, else `libndp: ndp_sock_open: Failed to create ICMP6 socket.`
|
||||
@@ -76,6 +83,7 @@ in {
|
||||
];
|
||||
serviceConfig.LockPersonality = true;
|
||||
serviceConfig.NoNewPrivileges = true;
|
||||
serviceConfig.MemoryDenyWriteExecute = true;
|
||||
serviceConfig.PrivateDevices = true; # remount /dev with just the basics, syscall filter to block @raw-io
|
||||
serviceConfig.PrivateIPC = true;
|
||||
serviceConfig.PrivateTmp = true;
|
||||
@@ -86,8 +94,11 @@ in {
|
||||
serviceConfig.ProtectHostname = true; # probably not upstreamable: prevents changing hostname
|
||||
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.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.RemoveIPC = true;
|
||||
serviceConfig.RestrictAddressFamilies = [
|
||||
"AF_INET"
|
||||
"AF_INET6"
|
||||
@@ -98,19 +109,25 @@ in {
|
||||
# AF_BLUETOOTH ?
|
||||
# AF_BRIDGE ?
|
||||
];
|
||||
serviceConfig.RestrictNamespaces = true;
|
||||
serviceConfig.RestrictSUIDSGID = true;
|
||||
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:
|
||||
# - "/proc/net"
|
||||
# - "/proc/sys/net"
|
||||
# - "/run/NetworkManager"
|
||||
# - "/run/systemd" # for trust-dns-nmhook
|
||||
# - "/run/systemd" # for hickory-dns-nmhook
|
||||
# - "/run/udev"
|
||||
# - # "/run/wg-home.priv"
|
||||
# - "/sys/class"
|
||||
# - "/sys/devices"
|
||||
# - "/var/lib/NetworkManager"
|
||||
# - "/var/lib/trust-dns" #< for trust-dns-nmhook
|
||||
# - "/var/lib/hickory-dns" #< for hickory-dns-nmhook
|
||||
# - "/run/systemd"
|
||||
};
|
||||
|
||||
@@ -122,7 +139,12 @@ in {
|
||||
# fix NetworkManager-dispatcher to actually run as a daemon,
|
||||
# and sandbox it a bit
|
||||
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 = [
|
||||
# "" # 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
|
||||
@@ -130,7 +152,7 @@ in {
|
||||
# serviceConfig.Restart = "always";
|
||||
# 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.Group = "networkmanager";
|
||||
serviceConfig.LockPersonality = true;
|
||||
@@ -146,7 +168,7 @@ in {
|
||||
serviceConfig.ProtectKernelLogs = true; # disable /proc/kmsg, /dev/kmsg
|
||||
serviceConfig.ProtectKernelModules = true; # syscall filter to prevent module calls
|
||||
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 = [
|
||||
"AF_UNIX" # required, probably for dbus or systemd connectivity
|
||||
];
|
||||
@@ -214,7 +236,7 @@ in {
|
||||
# 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
|
||||
"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"
|
||||
else
|
||||
"internal"
|
||||
@@ -256,7 +278,7 @@ in {
|
||||
users.users.networkmanager = {
|
||||
isSystemUser = true;
|
||||
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.
|
||||
|
@@ -16,5 +16,9 @@
|
||||
${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 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
|
||||
# - copy the Address, PublicKey, Endpoint from OVPN's config
|
||||
|
||||
{ config, lib, pkgs, ... }:
|
||||
{ config, lib, ... }:
|
||||
let
|
||||
# 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.
|
||||
|
@@ -64,7 +64,12 @@
|
||||
# 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
|
||||
# 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.
|
||||
|
@@ -6,7 +6,6 @@ let
|
||||
# nixpkgs' pam hardcodes unix_chkpwd path to the /run/wrappers one,
|
||||
# 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.
|
||||
# TODO: add a `package` option to the nixos' pam module and substitute it that way.
|
||||
postPatch = (if upstream.postPatch != null then upstream.postPatch else "") + ''
|
||||
substituteInPlace modules/pam_unix/Makefile.am --replace-fail \
|
||||
"/run/wrappers/bin/unix_chkpwd" "$out/bin/unix_chkpwd"
|
||||
@@ -39,36 +38,29 @@ in
|
||||
]));
|
||||
};
|
||||
options.security.pam.services = lib.mkOption {
|
||||
apply = services: let
|
||||
filtered = lib.filterAttrs (name: _: !(builtins.elem name [
|
||||
# from <repo:nixos/nixpkgs:nixos/modules/security/pam.nix>
|
||||
"i3lock"
|
||||
"i3lock-color"
|
||||
"vlock"
|
||||
"xlock"
|
||||
"xscreensaver"
|
||||
"runuser"
|
||||
"runuser-l"
|
||||
# from ??
|
||||
"chfn"
|
||||
"chpasswd"
|
||||
"chsh"
|
||||
"groupadd"
|
||||
"groupdel"
|
||||
"groupmems"
|
||||
"groupmod"
|
||||
"useradd"
|
||||
"userdel"
|
||||
"usermod"
|
||||
# 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!
|
||||
])) 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;
|
||||
apply = lib.filterAttrs (name: _: !(builtins.elem name [
|
||||
# from <repo:nixos/nixpkgs:nixos/modules/security/pam.nix>
|
||||
"i3lock"
|
||||
"i3lock-color"
|
||||
"vlock"
|
||||
"xlock"
|
||||
"xscreensaver"
|
||||
"runuser"
|
||||
"runuser-l"
|
||||
# from ??
|
||||
"chfn"
|
||||
"chpasswd"
|
||||
"chsh"
|
||||
"groupadd"
|
||||
"groupdel"
|
||||
"groupmems"
|
||||
"groupmod"
|
||||
"useradd"
|
||||
"userdel"
|
||||
"usermod"
|
||||
# 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!
|
||||
]));
|
||||
};
|
||||
|
||||
options.environment.systemPackages = lib.mkOption {
|
||||
@@ -225,5 +217,7 @@ in
|
||||
# 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 = {
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.wrapperType = "inplace"; #< /share/aerc/aerc.conf refers to other /share files by absolute path
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.wrapperType = "inplace"; #< /share/aerc/aerc.conf mentions (in comments) other (non-sandboxed) /share files by absolute path
|
||||
sandbox.net = "clearnet";
|
||||
secrets.".config/aerc/accounts.conf" = ../../../secrets/common/aerc_accounts.conf.bin;
|
||||
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.
|
||||
# - 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://gitlab.com/postmarketOS/pmaports/-/issues/2115>
|
||||
#
|
||||
# we can substitute working UCM conf in two ways:
|
||||
# 1. nixpkgs' override for the `alsa-ucm-conf` package
|
||||
|
@@ -32,7 +32,7 @@
|
||||
|
||||
buildCost = 1;
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.whitelistWayland = true;
|
||||
|
||||
persist.byStore.plaintext = [
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -16,7 +16,7 @@
|
||||
|
||||
buildCost = 1;
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.whitelistAudio = true;
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.autodetectCliPaths = "existingFile";
|
||||
|
@@ -4,7 +4,7 @@
|
||||
sane.programs.ausyscall = {
|
||||
packageUnwrapped = pkgs.linkBinIntoOwnPackage pkgs.audit "ausyscall";
|
||||
|
||||
sandbox.method = "landlock";
|
||||
sandbox.method = "bunpen";
|
||||
};
|
||||
}
|
||||
|
||||
|
@@ -10,19 +10,33 @@
|
||||
# - `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, ... }:
|
||||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
cfg = config.sane.programs.avahi;
|
||||
in
|
||||
{
|
||||
sane.programs.avahi = {
|
||||
sandbox.method = "bwrap";
|
||||
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 = [
|
||||
"/" #< else the daemon exits immediately. TODO: decrease this scope.
|
||||
];
|
||||
# sandbox.extraPaths = [ ]; #< may be missing some paths; only tried service discovery, not service advertisement.
|
||||
};
|
||||
services.avahi = lib.mkIf config.sane.programs.avahi.enabled {
|
||||
|
||||
services.avahi = lib.mkIf cfg.enabled {
|
||||
enable = true;
|
||||
package = config.sane.programs.avahi.package;
|
||||
package = cfg.packageUnwrapped; #< use systemd sandboxing... not my own
|
||||
publish.enable = true;
|
||||
publish.userServices = true;
|
||||
nssmdns4 = true;
|
||||
@@ -40,4 +54,54 @@
|
||||
"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"
|
||||
];
|
||||
};
|
||||
}
|
||||
|
@@ -24,7 +24,7 @@ let
|
||||
in
|
||||
{
|
||||
sane.programs.blast-ugjka = {
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.whitelistAudio = true;
|
||||
sandbox.net = "clearnet";
|
||||
};
|
||||
@@ -36,12 +36,12 @@ in
|
||||
pkgs = [ "blast-ugjka" ];
|
||||
srcRoot = ./.;
|
||||
};
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.whitelistAudio = true;
|
||||
sandbox.net = "clearnet";
|
||||
#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.
|
||||
sandbox.isolatePids = false;
|
||||
sandbox.keepPidsAndProc = true;
|
||||
suggestedPrograms = [ "blast-ugjka" "sane-die-with-parent" ];
|
||||
};
|
||||
|
||||
|
@@ -113,7 +113,7 @@ in
|
||||
|
||||
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 = [
|
||||
"bonsai"
|
||||
];
|
||||
|
@@ -3,12 +3,18 @@
|
||||
sane.programs.brave = {
|
||||
# convert eval error to build failure
|
||||
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
|
||||
pkgs.runCommandLocal "brave-not-supported" {} "false"
|
||||
;
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.wrapperType = "inplace"; # /opt/share/brave.com vendor-style packaging
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.wrapperType = "inplace"; #< package contains dangling symlinks which my wrapper doesn't understand
|
||||
sandbox.net = "all";
|
||||
sandbox.extraHomePaths = [
|
||||
"dev" # for developing anything web-related
|
||||
|
@@ -4,7 +4,7 @@ let
|
||||
in
|
||||
{
|
||||
sane.programs.brightnessctl = {
|
||||
sandbox.method = "landlock"; # also bwrap, but landlock is more responsive
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.extraPaths = [
|
||||
"/sys/class/backlight"
|
||||
"/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" ];
|
||||
}
|
@@ -8,6 +8,23 @@
|
||||
# - the bot will reply with auto-generated username/password plus a SIP server endpoint.
|
||||
# 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"
|
||||
#
|
||||
# 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, ... }:
|
||||
let
|
||||
cfg = config.sane.programs.calls;
|
||||
@@ -24,18 +41,62 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
packageUnwrapped = pkgs.rmDbusServicesInPlace (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 []) ++ [
|
||||
(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";
|
||||
name = "exit on close (i.e. never daemonize)";
|
||||
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=";
|
||||
})
|
||||
];
|
||||
|
||||
nativeBuildInputs = upstream.nativeBuildInputs ++ [
|
||||
pkgs.dbus #< for dbus-run-session (should be test only, but it's not)
|
||||
];
|
||||
|
||||
buildInputs = upstream.buildInputs ++ [
|
||||
pkgs.libadwaita
|
||||
];
|
||||
}));
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
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.whitelistDbus = [ "user" ]; # necessary for secrets, at the minimum
|
||||
@@ -55,6 +116,10 @@ in
|
||||
"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 = {
|
||||
description = "gnome-calls daemon to monitor incoming SIP calls";
|
||||
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 = {
|
||||
buildCost = 1;
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.whitelistAudio = true;
|
||||
sandbox.whitelistDri = true;
|
||||
sandbox.whitelistWayland = true;
|
||||
|
@@ -1,7 +1,7 @@
|
||||
{ pkgs, ... }:
|
||||
{ ... }:
|
||||
{
|
||||
sane.programs.conky = {
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.net = "clearnet"; #< for the scripts it calls (weather)
|
||||
sandbox.extraPaths = [
|
||||
"/sys/class/power_supply"
|
||||
|
@@ -15,7 +15,7 @@
|
||||
|
||||
buildCost = 1;
|
||||
|
||||
sandbox.method = "bwrap"; # landlock gives: _multiprocessing.SemLock: Permission Denied
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.whitelistAudio = true;
|
||||
sandbox.whitelistDbus = [ "user" ]; # mpris
|
||||
sandbox.whitelistWayland = true;
|
||||
|
@@ -1,7 +1,7 @@
|
||||
{ ... }:
|
||||
{
|
||||
sane.programs.curl = {
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.net = "all";
|
||||
sandbox.autodetectCliPaths = "parent"; #< for `-o` option
|
||||
};
|
||||
|
@@ -1,35 +1,10 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
sane.programs.curlftpfs = {
|
||||
packageUnwrapped = pkgs.curlftpfs.overrideAttrs (upstream: {
|
||||
# my fork includes:
|
||||
# - per-operation timeouts (CURLOPT_TIMEOUT; would use CURLOPT_LOW_SPEED_TIME/CURLOPT_LOW_SPEED_LIMIT but they don't apply)
|
||||
# - exit on timeout (so that one knows to abort the mount, instead of waiting indefinitely)
|
||||
# - support for "meta" keys found in /etc/fstab
|
||||
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"
|
||||
# ];
|
||||
packageUnwrapped = pkgs.curlftpfs-sane;
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.net = "all";
|
||||
sandbox.autodetectCliPaths = "existing";
|
||||
sandbox.keepPids = true;
|
||||
};
|
||||
}
|
||||
|
@@ -32,13 +32,13 @@ in
|
||||
'';
|
||||
});
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.method = "bunpen";
|
||||
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
|
||||
# then we can create our own. not sure if there's a dependency ordering issue here: lots
|
||||
@@ -47,8 +47,12 @@ in
|
||||
services.dbus = {
|
||||
description = "dbus user session";
|
||||
partOf = lib.mkIf cfg.config.autostart [ "default" ];
|
||||
command = "dbus-daemon --session --nofork --address=$DBUS_SESSION_BUS_ADDRESS";
|
||||
readiness.waitExists = [ "$XDG_RUNTIME_DIR/bus" ];
|
||||
command = pkgs.writeShellScript "dbus-start" ''
|
||||
# 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;
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.wrapperType = "inplace"; #< dbus/systemd services live in `.out` but point to `.lib` data.
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.whitelistDbus = [ "user" ];
|
||||
persist.byStore.private = [
|
||||
".config/dconf"
|
||||
|
@@ -18,9 +18,12 @@
|
||||
./brave.nix
|
||||
./brightnessctl.nix
|
||||
./bubblewrap.nix
|
||||
./bunpen.nix
|
||||
./callaudiod.nix
|
||||
./calls.nix
|
||||
./cantata.nix
|
||||
./capsh.nix
|
||||
./captree.nix
|
||||
./catt.nix
|
||||
./celeste64.nix
|
||||
./chatty.nix
|
||||
@@ -37,6 +40,7 @@
|
||||
./dissent.nix
|
||||
./dtrx.nix
|
||||
./eg25-control.nix
|
||||
./eg25-manager.nix
|
||||
./element-desktop.nix
|
||||
./engrampa.nix
|
||||
./epiphany.nix
|
||||
@@ -45,8 +49,10 @@
|
||||
./exiftool.nix
|
||||
./fcitx5.nix
|
||||
./feedbackd.nix
|
||||
./firefox.nix
|
||||
./firefox
|
||||
./firefox-xdg-open.nix
|
||||
./flare-signal.nix
|
||||
./foliate.nix
|
||||
./fontconfig.nix
|
||||
./fractal.nix
|
||||
./free.nix
|
||||
@@ -66,31 +72,38 @@
|
||||
./gnome-maps.nix
|
||||
./gnome-weather.nix
|
||||
./go2tv.nix
|
||||
./gocryptfs.nix
|
||||
./gpodder.nix
|
||||
./gpsd.nix
|
||||
./gps-share.nix
|
||||
./grimshot.nix
|
||||
./gst-device-monitor.nix
|
||||
./gst-launch.nix
|
||||
./gthumb.nix
|
||||
./gvfs.nix
|
||||
./handbrake.nix
|
||||
./haredoc.nix
|
||||
./helix.nix
|
||||
./htop
|
||||
./iio-sensor-proxy.nix
|
||||
./imagemagick.nix
|
||||
./inkscape.nix
|
||||
./jellyfin-media-player.nix
|
||||
./kdenlive.nix
|
||||
./keymapp.nix
|
||||
./komikku.nix
|
||||
./koreader
|
||||
./krita.nix
|
||||
./less.nix
|
||||
./lftp.nix
|
||||
./lgtrombetta-compass.nix
|
||||
./libcamera.nix
|
||||
./libreoffice.nix
|
||||
./lemoa.nix
|
||||
./loupe.nix
|
||||
./mako.nix
|
||||
./megapixels.nix
|
||||
./megapixels-next.nix
|
||||
./mepo.nix
|
||||
./mimeo
|
||||
./mimetype.nix
|
||||
@@ -99,7 +112,7 @@
|
||||
./mpv
|
||||
./msmtp.nix
|
||||
./nautilus.nix
|
||||
./neovim.nix
|
||||
./neovim
|
||||
./networkmanager_dmenu
|
||||
./newsflash.nix
|
||||
./nheko.nix
|
||||
@@ -116,6 +129,7 @@
|
||||
./ols.nix
|
||||
./open-in-mpv.nix
|
||||
./pactl.nix
|
||||
./papers.nix
|
||||
./pidof.nix
|
||||
./pipewire
|
||||
./pkill.nix
|
||||
@@ -146,6 +160,9 @@
|
||||
./sfeed.nix
|
||||
./shadow.nix
|
||||
./signal-desktop.nix
|
||||
./sm64ex-coop.nix
|
||||
./sm64ex-coop-deluxe.nix
|
||||
./soundconverter.nix
|
||||
./splatmoji.nix
|
||||
./spot.nix
|
||||
./spotify.nix
|
||||
@@ -165,6 +182,7 @@
|
||||
./tor-browser.nix
|
||||
./tuba.nix
|
||||
./unl0kr
|
||||
./v4l-utils.nix
|
||||
./via.nix
|
||||
./visidata.nix
|
||||
./vlc.nix
|
||||
@@ -179,11 +197,13 @@
|
||||
./wvkbd.nix
|
||||
./xarchiver.nix
|
||||
./xdg-desktop-portal.nix
|
||||
./xdg-desktop-portal-gnome
|
||||
./xdg-desktop-portal-gtk.nix
|
||||
./xdg-desktop-portal-wlr.nix
|
||||
./xdg-terminal-exec.nix
|
||||
./xdg-utils.nix
|
||||
./youtube-tui.nix
|
||||
./yt-dlp.nix
|
||||
./zathura.nix
|
||||
./zeal.nix
|
||||
./zecwallet-lite.nix
|
||||
|
@@ -14,7 +14,7 @@
|
||||
|
||||
buildCost = 1;
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.wrapperType = "inplace"; # share/search_providers/ calls back into the binary, weird wrap semantics
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.net = "clearnet";
|
||||
|
@@ -58,7 +58,7 @@ in
|
||||
webrtc-audio-processing = null;
|
||||
};
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.net = "clearnet";
|
||||
sandbox.whitelistAudio = true;
|
||||
sandbox.whitelistDbus = [ "user" ]; # notifications
|
||||
|
@@ -31,7 +31,7 @@ in
|
||||
--replace-fail '"login"' '"Default_keyring"'
|
||||
'';
|
||||
});
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.net = "clearnet";
|
||||
sandbox.whitelistAudio = true;
|
||||
sandbox.whitelistDbus = [ "user" ]; # notifications
|
||||
|
@@ -9,7 +9,7 @@
|
||||
# build without rpm support, since `rpm` package doesn't cross-compile.
|
||||
rpm = null;
|
||||
};
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.whitelistPwd = true;
|
||||
sandbox.autodetectCliPaths = "existing"; #< for the archive
|
||||
};
|
||||
|
@@ -6,8 +6,9 @@ in
|
||||
sane.programs.eg25-control = {
|
||||
suggestedPrograms = [ "mmcli" ];
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.extraPaths = [
|
||||
"/dev/gpiochip1"
|
||||
"/sys/class/modem-power"
|
||||
"/sys/devices"
|
||||
# "/var/lib/eg25-control"
|
||||
|
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 ];
|
||||
}
|
@@ -27,7 +27,7 @@
|
||||
|
||||
buildCost = 1;
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.net = "clearnet";
|
||||
sandbox.whitelistAudio = true;
|
||||
sandbox.whitelistDbus = [ "user" ]; # notifications
|
||||
|
@@ -2,7 +2,7 @@
|
||||
{
|
||||
sane.programs."mate.engrampa" = {
|
||||
packageUnwrapped = pkgs.rmDbusServices pkgs.mate.engrampa;
|
||||
sandbox.method = "bwrap"; # TODO:sandbox: untested
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.autodetectCliPaths = "existingOrParent";
|
||||
sandbox.extraHomePaths = [
|
||||
|
@@ -8,7 +8,7 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
sane.programs.epiphany = {
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.wrapperType = "inplace"; # /share/epiphany/default-bookmarks.rdf refers back to /share; dbus files to /libexec
|
||||
sandbox.net = "clearnet";
|
||||
sandbox.whitelistAudio = true;
|
||||
|
@@ -12,6 +12,6 @@
|
||||
buildInputs = []; #< errno has no runtime perl deps, and they don't cross compile, so disable them.
|
||||
});
|
||||
|
||||
sandbox.method = "landlock";
|
||||
sandbox.method = "bunpen";
|
||||
};
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
{ ... }:
|
||||
{
|
||||
sane.programs.exiftool = {
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.autodetectCliPaths = "existingFile";
|
||||
};
|
||||
}
|
||||
|
@@ -24,7 +24,7 @@
|
||||
# - nixpkgs has a few themes: `fcitx5-{material-color,nord,rose-pine}`
|
||||
# - NUR has a few themes
|
||||
# - <https://github.com/catppuccin/fcitx5>
|
||||
{ lib, pkgs, ... }:
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
sane.programs.fcitx5 = {
|
||||
packageUnwrapped = pkgs.fcitx5-with-addons.override {
|
||||
@@ -34,7 +34,7 @@
|
||||
];
|
||||
};
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.whitelistDbus = [ "user" ];
|
||||
sandbox.whitelistWayland = true; # for `fcitx5-configtool, if nothing else`
|
||||
sandbox.extraHomePaths = [
|
||||
|
13
hosts/common/programs/firefox-xdg-open.nix
Normal file
13
hosts/common/programs/firefox-xdg-open.nix
Normal file
@@ -0,0 +1,13 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
sane.programs.firefox-xdg-open = {
|
||||
packageUnwrapped = pkgs.firefox-extensions.firefox-xdg-open.systemComponent;
|
||||
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.whitelistDbus = [ "user" ]; # for xdg-open/portals
|
||||
|
||||
mime.associations."x-scheme-handler/xdg-open" = "xdg-open.desktop";
|
||||
|
||||
suggestedPrograms = [ "xdg-utils" ];
|
||||
};
|
||||
}
|
@@ -1,405 +0,0 @@
|
||||
# common settings to toggle (at runtime, in about:config):
|
||||
# > security.ssl.require_safe_negotiation
|
||||
|
||||
# librewolf is a forked firefox which patches firefox to allow more things
|
||||
# (like default search engines) to be configurable at runtime.
|
||||
# many of the settings below won't have effect without those patches.
|
||||
# see: https://gitlab.com/librewolf-community/settings/-/blob/master/distribution/policies.json
|
||||
|
||||
{ config, lib, pkgs, ...}:
|
||||
with lib;
|
||||
let
|
||||
cfg = config.sane.programs.firefox.config;
|
||||
mobile-prefs = lib.optionals false pkgs.librewolf-pmos-mobile.extraPrefsFiles;
|
||||
# allow easy switching between firefox and librewolf with `defaultSettings`, below
|
||||
librewolfSettings = {
|
||||
browser = pkgs.librewolf-unwrapped.overrideAttrs (upstream: {
|
||||
# TEMP(2023/11/21): fix eval bug in wrapFirefox
|
||||
# see: <https://github.com/NixOS/nixpkgs/pull/244591>
|
||||
passthru = upstream.passthru // {
|
||||
requireSigning = false;
|
||||
allowAddonSideload = true;
|
||||
};
|
||||
});
|
||||
extraPrefsFiles = pkgs.librewolf-unwrapped.extraPrefsFiles ++ mobile-prefs;
|
||||
libName = "librewolf";
|
||||
dotDir = ".librewolf";
|
||||
cacheDir = ".cache/librewolf";
|
||||
desktop = "librewolf.desktop";
|
||||
};
|
||||
firefoxSettings = {
|
||||
browser = pkgs.firefox-esr-unwrapped;
|
||||
extraPrefsFiles = mobile-prefs;
|
||||
libName = "firefox";
|
||||
dotDir = ".mozilla/firefox";
|
||||
cacheDir = ".cache/mozilla";
|
||||
desktop = "firefox.desktop";
|
||||
};
|
||||
# defaultSettings = firefoxSettings;
|
||||
defaultSettings = librewolfSettings;
|
||||
|
||||
packageUnwrapped = (pkgs.wrapFirefox cfg.browser.browser {
|
||||
# inherit the default librewolf.cfg
|
||||
# it can be further customized via ~/.librewolf/librewolf.overrides.cfg
|
||||
inherit (cfg.browser) extraPrefsFiles libName;
|
||||
|
||||
nativeMessagingHosts = lib.optionals cfg.addons.browserpass-extension.enable [
|
||||
pkgs.browserpass
|
||||
] ++ lib.optionals cfg.addons.fxCast.enable [
|
||||
pkgs.fx-cast-bridge
|
||||
];
|
||||
|
||||
nixExtensions = concatMap (ext: optional ext.enable ext.package) (attrValues cfg.addons);
|
||||
|
||||
extraPolicies = {
|
||||
FirefoxHome = {
|
||||
Search = true;
|
||||
Pocket = false;
|
||||
Snippets = false;
|
||||
TopSites = false;
|
||||
Highlights = false;
|
||||
};
|
||||
NoDefaultBookmarks = true;
|
||||
OfferToSaveLogins = false;
|
||||
OfferToSaveLoginsDefault = false;
|
||||
PasswordManagerEnabled = false;
|
||||
SearchEngines = {
|
||||
Default = "DuckDuckGo";
|
||||
};
|
||||
UserMessaging = {
|
||||
ExtensionRecommendations = false;
|
||||
FeatureRecommendations = false;
|
||||
SkipOnboarding = true;
|
||||
UrlbarInterventions = false;
|
||||
WhatsNew = false;
|
||||
};
|
||||
|
||||
# these were taken from Librewolf
|
||||
AppUpdateURL = "https://localhost";
|
||||
DisableAppUpdate = true;
|
||||
OverrideFirstRunPage = "";
|
||||
OverridePostUpdatePage = "";
|
||||
DisableSystemAddonUpdate = true;
|
||||
DisableFirefoxStudies = true;
|
||||
DisableTelemetry = true;
|
||||
DisableFeedbackCommands = true;
|
||||
DisablePocket = true;
|
||||
DisableSetDesktopBackground = false;
|
||||
|
||||
# remove many default search providers
|
||||
# XXX this seems to prevent the `nixExtensions` from taking effect
|
||||
# Extensions.Uninstall = [
|
||||
# "google@search.mozilla.org"
|
||||
# "bing@search.mozilla.org"
|
||||
# "amazondotcom@search.mozilla.org"
|
||||
# "ebay@search.mozilla.org"
|
||||
# "twitter@search.mozilla.org"
|
||||
# ];
|
||||
# XXX doesn't seem to have any effect...
|
||||
# docs: https://github.com/mozilla/policy-templates#homepage
|
||||
# Homepage = {
|
||||
# HomepageURL = "https://uninsane.org/";
|
||||
# StartPage = "homepage";
|
||||
# };
|
||||
# NewTabPage = true;
|
||||
};
|
||||
# extraPrefs = ...
|
||||
}).overrideAttrs (base: {
|
||||
nativeBuildInputs = (base.nativeBuildInputs or []) ++ [
|
||||
pkgs.copyDesktopItems
|
||||
];
|
||||
desktopItems = (base.desktopItems or []) ++ [
|
||||
(pkgs.makeDesktopItem {
|
||||
name = "${cfg.browser.libName}-in-vpn";
|
||||
desktopName = "${cfg.browser.libName} (VPN)";
|
||||
genericName = "Web Browser";
|
||||
# N.B.: --new-instance ensures we don't reuse an existing non-vpn instance.
|
||||
# OTOH, it may error about "only one instance can run at a time": close the non-VPN instance if you see that.
|
||||
exec = "${lib.getExe pkgs.sane-scripts.vpn} do - -- ${cfg.browser.libName} --new-instance";
|
||||
icon = cfg.browser.libName;
|
||||
categories = [ "Network" "WebBrowser" ];
|
||||
type = "Application";
|
||||
})
|
||||
];
|
||||
# de-associate `ctrl+shift+c` from activating the devtools.
|
||||
# based on <https://stackoverflow.com/a/54260938>
|
||||
# TODO: could use `zip -f` to only update the one changed file, instead of rezipping everything.
|
||||
buildCommand = (base.buildCommand or "") + ''
|
||||
mkdir omni
|
||||
|
||||
echo "omni.ja BEFORE:"
|
||||
ls -l $(readlink $out/lib/${cfg.browser.libName}/browser/omni.ja)
|
||||
|
||||
echo "unzipping omni.ja"
|
||||
# N.B. `zip` exits non-zero even on successful extraction, if the file didn't 100% obey spec
|
||||
${pkgs.buildPackages.unzip}/bin/unzip $out/lib/${cfg.browser.libName}/browser/omni.ja -d omni || true
|
||||
|
||||
echo "removing old omni.ja"
|
||||
rm $out/lib/${cfg.browser.libName}/browser/omni.ja
|
||||
|
||||
echo "patching omni.ja"
|
||||
${pkgs.buildPackages.gnused}/bin/sed -i s'/devtools-commandkey-inspector = C/devtools-commandkey-inspector = VK_F12/' omni/localization/en-US/devtools/startup/key-shortcuts.ftl
|
||||
|
||||
echo "re-zipping omni.ja"
|
||||
pushd omni; ${pkgs.buildPackages.zip}/bin/zip $out/lib/${cfg.browser.libName}/browser/omni.ja -r ./*; popd
|
||||
|
||||
echo "omni.ja AFTER:"
|
||||
ls -l $out/lib/${cfg.browser.libName}/browser/omni.ja
|
||||
|
||||
runHook postBuild
|
||||
runHook postInstall
|
||||
runHook postFixup
|
||||
'';
|
||||
});
|
||||
|
||||
addonOpts = types.submodule {
|
||||
options = {
|
||||
package = mkOption {
|
||||
type = types.package;
|
||||
};
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
configOpts = {
|
||||
options = {
|
||||
browser = mkOption {
|
||||
default = defaultSettings;
|
||||
type = types.anything;
|
||||
};
|
||||
persistData = mkOption {
|
||||
description = "optional store name to which persist browsing data (like history)";
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
};
|
||||
persistCache = mkOption {
|
||||
description = "optional store name to which persist browser cache";
|
||||
type = types.nullOr types.str;
|
||||
default = "ephemeral";
|
||||
};
|
||||
addons = mkOption {
|
||||
type = types.attrsOf addonOpts;
|
||||
default = {};
|
||||
};
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
config = mkMerge [
|
||||
({
|
||||
sane.programs.firefox.configOption = mkOption {
|
||||
type = types.submodule configOpts;
|
||||
default = {};
|
||||
};
|
||||
sane.programs.firefox.config.addons = {
|
||||
fxCast = {
|
||||
# add a menu to cast to chromecast devices, but it doesn't seem to work very well.
|
||||
# right click (or shift+rc) a video, then select "cast".
|
||||
# - asciinema.org: icon appears, but glitches when clicked.
|
||||
# - youtube.com: no icon appears, even when site is whitelisted.
|
||||
# future: maybe better to have browser open all videos in mpv, and then use mpv for casting.
|
||||
# see e.g. `ff2mpv`, `open-in-mpv` (both are packaged in nixpkgs)
|
||||
package = pkgs.firefox-extensions.fx_cast;
|
||||
enable = lib.mkDefault false;
|
||||
};
|
||||
browserpass-extension = {
|
||||
package = pkgs.firefox-extensions.browserpass-extension;
|
||||
enable = lib.mkDefault true;
|
||||
};
|
||||
bypass-paywalls-clean = {
|
||||
package = pkgs.firefox-extensions.bypass-paywalls-clean;
|
||||
enable = lib.mkDefault true;
|
||||
};
|
||||
ctrl-shift-c-should-copy = {
|
||||
package = pkgs.firefox-extensions.ctrl-shift-c-should-copy;
|
||||
enable = lib.mkDefault false; # prefer patching firefox source code, so it works in more places
|
||||
};
|
||||
ether-metamask = {
|
||||
package = pkgs.firefox-extensions.ether-metamask;
|
||||
enable = lib.mkDefault false; # until i can disable the first-run notification
|
||||
};
|
||||
i2p-in-private-browsing = {
|
||||
package = pkgs.firefox-extensions.i2p-in-private-browsing;
|
||||
enable = lib.mkDefault config.services.i2p.enable;
|
||||
};
|
||||
i-still-dont-care-about-cookies = {
|
||||
package = pkgs.firefox-extensions.i-still-dont-care-about-cookies;
|
||||
enable = lib.mkDefault false; #< obsoleted by uBlock Origin annoyances/cookies lists
|
||||
};
|
||||
open-in-mpv = {
|
||||
# test: `open-in-mpv 'mpv:///open?url=https://www.youtube.com/watch?v=dQw4w9WgXcQ'`
|
||||
package = pkgs.firefox-extensions.open-in-mpv;
|
||||
enable = lib.mkDefault config.sane.programs.open-in-mpv.enabled;
|
||||
};
|
||||
sidebery = {
|
||||
package = pkgs.firefox-extensions.sidebery;
|
||||
enable = lib.mkDefault true;
|
||||
};
|
||||
sponsorblock = {
|
||||
package = pkgs.firefox-extensions.sponsorblock;
|
||||
enable = lib.mkDefault true;
|
||||
};
|
||||
ublacklist = {
|
||||
package = pkgs.firefox-extensions.ublacklist;
|
||||
enable = lib.mkDefault false;
|
||||
};
|
||||
ublock-origin = {
|
||||
package = pkgs.firefox-extensions.ublock-origin;
|
||||
enable = lib.mkDefault true;
|
||||
};
|
||||
};
|
||||
})
|
||||
({
|
||||
sane.programs.firefox = {
|
||||
inherit packageUnwrapped;
|
||||
sandbox.method = "bwrap"; # landlock works, but requires all of /proc to be linked
|
||||
sandbox.wrapperType = "inplace"; # trivial package; cheap enough to wrap inplace
|
||||
sandbox.net = "all";
|
||||
sandbox.whitelistAudio = true;
|
||||
sandbox.whitelistDbus = [ "user" ]; # mpris
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.extraHomePaths = [
|
||||
"dev" # for developing anything web-related
|
||||
# for uploads/downloads.
|
||||
# it still needs these paths despite using the portal's file-chooser :?
|
||||
"tmp"
|
||||
"Pictures/albums"
|
||||
"Pictures/cat"
|
||||
"Pictures/from"
|
||||
"Pictures/Photos"
|
||||
"Pictures/Screenshots"
|
||||
"Pictures/servo-macros"
|
||||
] ++ lib.optionals cfg.addons.browserpass-extension.enable [
|
||||
# browserpass needs these paths:
|
||||
# - knowledge/secrets/accounts: where the encrypted account secrets live
|
||||
# at least one of:
|
||||
# - .config/sops: for the sops key which can decrypt account secrets
|
||||
# - .ssh: to unlock the sops key, if not unlocked (`sane-secrets-unlock`)
|
||||
# TODO: find a way to not expose ~/.ssh to firefox
|
||||
# - unlock sops at login (or before firefox launch)?
|
||||
# - see if ssh has a more formal type of subkey system?
|
||||
# ".ssh/id_ed25519"
|
||||
# ".config/sops"
|
||||
"knowledge/secrets/accounts"
|
||||
];
|
||||
fs.".config/sops".dir = lib.mkIf cfg.addons.browserpass-extension.enable {}; #< needs to be created, not *just* added to the sandbox
|
||||
|
||||
suggestedPrograms = [
|
||||
"open-in-mpv"
|
||||
];
|
||||
|
||||
mime.associations = let
|
||||
inherit (cfg.browser) desktop;
|
||||
in {
|
||||
"text/html" = desktop;
|
||||
"x-scheme-handler/http" = desktop;
|
||||
"x-scheme-handler/https" = desktop;
|
||||
"x-scheme-handler/about" = desktop;
|
||||
"x-scheme-handler/unknown" = desktop;
|
||||
};
|
||||
|
||||
# env.BROWSER = "${package}/bin/${cfg.browser.libName}";
|
||||
env.BROWSER = cfg.browser.libName; # used by misc tools like xdg-email, as fallback
|
||||
|
||||
# uBlock configuration:
|
||||
fs."${cfg.browser.dotDir}/managed-storage/uBlock0@raymondhill.net.json".symlink.target = cfg.addons.ublock-origin.package.makeConfig {
|
||||
# more filter lists are available here:
|
||||
# - <https://easylist.to>
|
||||
# - <https://github.com/easylist/easylist.git>
|
||||
# - <https://github.com/yokoffing/filterlists>
|
||||
filterFiles = let
|
||||
getUasset = n: "${pkgs.uassets}/share/filters/${n}.txt";
|
||||
in [
|
||||
# default ublock filters:
|
||||
(getUasset "ublock-filters")
|
||||
(getUasset "ublock-badware")
|
||||
(getUasset "ublock-privacy")
|
||||
(getUasset "ublock-quick-fixes")
|
||||
(getUasset "ublock-unbreak")
|
||||
(getUasset "easylist")
|
||||
(getUasset "easyprivacy")
|
||||
# (getUasset "urlhaus-1") #< TODO: i think this is the same as urlhaus-filter-online
|
||||
(getUasset "urlhaus-filter-online")
|
||||
# (getUasset "plowe-0") #< TODO: where does this come from?
|
||||
# (getUasset "ublock-cookies-adguard") #< TODO: where does this come from?
|
||||
# filters i've added:
|
||||
(getUasset "easylist-annoyances") #< blocks in-page popups, "social media content" (e.g. FB like button; improves loading time)
|
||||
(getUasset "easylist-cookies") #< blocks GDPR cookie consent popovers (e.g. at stackoverflow.com)
|
||||
# (getUasset "ublock-annoyances-others")
|
||||
# (getUasset "ublock-annoyances-cookies")
|
||||
];
|
||||
};
|
||||
|
||||
# TODO: this is better suited in `extraPrefs` during `wrapFirefox` call
|
||||
fs."${cfg.browser.dotDir}/${cfg.browser.libName}.overrides.cfg".symlink.text = ''
|
||||
// if we can't query the revocation status of a SSL cert because the issuer is offline,
|
||||
// treat it as unrevoked.
|
||||
// see: <https://librewolf.net/docs/faq/#im-getting-sec_error_ocsp_server_error-what-can-i-do>
|
||||
defaultPref("security.OCSP.require", false);
|
||||
|
||||
// scrollbar configuration, see: <https://artemis.sh/2023/10/12/scrollbars.html>
|
||||
// style=4 gives rectangular scrollbars
|
||||
// could also enable "always show scrollbars" in about:preferences -- not sure what the actual pref name for that is
|
||||
// note that too-large scrollbars (like 50px wide, even 20px) tend to obscure content (and make buttons unclickable)
|
||||
defaultPref("widget.non-native-theme.scrollbar.size.override", 14);
|
||||
defaultPref("widget.non-native-theme.scrollbar.style", 4);
|
||||
|
||||
// disable inertial/kinetic/momentum scrolling because it just gets in the way on touchpads
|
||||
// source: <https://kparal.wordpress.com/2019/10/31/disabling-kinetic-scrolling-in-firefox/>
|
||||
defaultPref("apz.gtk.kinetic_scroll.enabled", false);
|
||||
|
||||
// open external URIs/files via xdg-desktop-portal.
|
||||
defaultPref("widget.use-xdg-desktop-portal.mime-handler", 1);
|
||||
defaultPref("widget.use-xdg-desktop-portal.open-uri", 1);
|
||||
|
||||
defaultPref("browser.toolbars.bookmarks.visibility", "never");
|
||||
// configure which extensions are visible by default (TODO: requires a lot of trial and error)
|
||||
// defaultPref("browser.uiCustomization.state", ...);
|
||||
|
||||
// auto-open mpv:// URIs without prompting.
|
||||
// can do this with other protocols too (e.g. matrix?). see about:config for common handlers.
|
||||
defaultPref("network.protocol-handler.external.mpv", true);
|
||||
// element:// for Element matrix client
|
||||
defaultPref("network.protocol-handler.external.element", true);
|
||||
// matrix: for Nheko matrix client
|
||||
defaultPref("network.protocol-handler.external.matrix", true);
|
||||
'';
|
||||
# instruct Firefox to put the profile in a predictable directory (so we can do things like persist just it).
|
||||
# XXX: the directory *must* exist, even if empty; Firefox will not create the directory itself.
|
||||
fs."${cfg.browser.dotDir}/profiles.ini".symlink.text = ''
|
||||
[Profile0]
|
||||
Name=default
|
||||
IsRelative=1
|
||||
Path=default
|
||||
Default=1
|
||||
|
||||
[General]
|
||||
StartWithLastProfile=1
|
||||
'';
|
||||
|
||||
# TODO: env.PASSWORD_STORE_DIR only needs to be present within the browser session.
|
||||
env.PASSWORD_STORE_DIR = "/home/colin/knowledge/secrets/accounts";
|
||||
# alternative to PASSWORD_STORE_DIR:
|
||||
# fs.".password-store".symlink.target = lib.mkIf cfg.addons.browserpass-extension.enable "knowledge/secrets/accounts";
|
||||
|
||||
# flush the cache to disk to avoid it taking up too much tmp.
|
||||
persist.byPath."${cfg.browser.cacheDir}".store =
|
||||
if (cfg.persistData != null) then
|
||||
cfg.persistData
|
||||
else
|
||||
"ephemeral"
|
||||
;
|
||||
|
||||
persist.byPath."${cfg.browser.dotDir}/default".store =
|
||||
if (cfg.persistData != null) then
|
||||
cfg.persistData
|
||||
else
|
||||
"ephemeral"
|
||||
;
|
||||
};
|
||||
|
||||
})
|
||||
];
|
||||
}
|
128
hosts/common/programs/firefox/addons.nix
Normal file
128
hosts/common/programs/firefox/addons.nix
Normal file
@@ -0,0 +1,128 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
cfg = config.sane.programs.firefox.config;
|
||||
in
|
||||
{
|
||||
sane.programs.firefox = {
|
||||
config.addons = {
|
||||
fxCast = {
|
||||
# add a menu to cast to chromecast devices, but it doesn't seem to work very well.
|
||||
# right click (or shift+rc) a video, then select "cast".
|
||||
# - asciinema.org: icon appears, but glitches when clicked.
|
||||
# - youtube.com: no icon appears, even when site is whitelisted.
|
||||
# future: maybe better to have browser open all videos in mpv, and then use mpv for casting.
|
||||
# see e.g. `ff2mpv`, `open-in-mpv` (both are packaged in nixpkgs)
|
||||
package = pkgs.firefox-extensions.fx_cast;
|
||||
enable = lib.mkDefault false;
|
||||
};
|
||||
browserpass-extension = {
|
||||
package = pkgs.firefox-extensions.browserpass-extension;
|
||||
enable = lib.mkDefault true;
|
||||
};
|
||||
bypass-paywalls-clean = {
|
||||
package = pkgs.firefox-extensions.bypass-paywalls-clean;
|
||||
enable = lib.mkDefault true;
|
||||
};
|
||||
ctrl-shift-c-should-copy = {
|
||||
package = pkgs.firefox-extensions.ctrl-shift-c-should-copy;
|
||||
enable = lib.mkDefault false; # prefer patching firefox source code, so it works in more places
|
||||
};
|
||||
ether-metamask = {
|
||||
package = pkgs.firefox-extensions.ether-metamask;
|
||||
enable = lib.mkDefault false; # until i can disable the first-run notification
|
||||
};
|
||||
firefox-xdg-open = {
|
||||
# test: `xdg-open xdg-open:https://uninsane.org`
|
||||
package = pkgs.firefox-extensions.firefox-xdg-open;
|
||||
enable = lib.mkDefault true;
|
||||
};
|
||||
i2p-in-private-browsing = {
|
||||
package = pkgs.firefox-extensions.i2p-in-private-browsing;
|
||||
enable = lib.mkDefault config.services.i2p.enable;
|
||||
};
|
||||
i-still-dont-care-about-cookies = {
|
||||
package = pkgs.firefox-extensions.i-still-dont-care-about-cookies;
|
||||
enable = lib.mkDefault false; #< obsoleted by uBlock Origin annoyances/cookies lists
|
||||
};
|
||||
open-in-mpv = {
|
||||
# test: `open-in-mpv 'mpv:///open?url=https://www.youtube.com/watch?v=dQw4w9WgXcQ'`
|
||||
package = pkgs.firefox-extensions.open-in-mpv;
|
||||
enable = lib.mkDefault false;
|
||||
};
|
||||
sidebery = {
|
||||
package = pkgs.firefox-extensions.sidebery;
|
||||
enable = lib.mkDefault true;
|
||||
};
|
||||
sponsorblock = {
|
||||
package = pkgs.firefox-extensions.sponsorblock;
|
||||
enable = lib.mkDefault true;
|
||||
};
|
||||
ublacklist = {
|
||||
package = pkgs.firefox-extensions.ublacklist;
|
||||
enable = lib.mkDefault false;
|
||||
};
|
||||
ublock-origin = {
|
||||
package = pkgs.firefox-extensions.ublock-origin;
|
||||
enable = lib.mkDefault true;
|
||||
};
|
||||
};
|
||||
|
||||
suggestedPrograms = lib.optionals cfg.addons.firefox-xdg-open.enable [
|
||||
"firefox-xdg-open"
|
||||
] ++ lib.optionals cfg.addons.open-in-mpv.enable [
|
||||
"open-in-mpv"
|
||||
];
|
||||
|
||||
sandbox.extraHomePaths = lib.optionals cfg.addons.browserpass-extension.enable [
|
||||
# browserpass needs these paths:
|
||||
# - knowledge/secrets/accounts: where the encrypted account secrets live
|
||||
# at least one of:
|
||||
# - .config/sops: for the sops key which can decrypt account secrets
|
||||
# - .ssh: to unlock the sops key, if not unlocked (`sane-secrets-unlock`)
|
||||
# TODO: find a way to not expose ~/.ssh to firefox
|
||||
# - unlock sops at login (or before firefox launch)?
|
||||
# - see if ssh has a more formal type of subkey system?
|
||||
# ".ssh/id_ed25519"
|
||||
# ".config/sops"
|
||||
"knowledge/secrets/accounts"
|
||||
];
|
||||
|
||||
fs.".config/sops".dir = lib.mkIf cfg.addons.browserpass-extension.enable {}; #< needs to be created, not *just* added to the sandbox
|
||||
|
||||
# uBlock configuration:
|
||||
fs.".mozilla/firefox/managed-storage/uBlock0@raymondhill.net.json".symlink.target = cfg.addons.ublock-origin.package.makeConfig {
|
||||
# more filter lists are available here:
|
||||
# - <https://easylist.to>
|
||||
# - <https://github.com/easylist/easylist.git>
|
||||
# - <https://github.com/yokoffing/filterlists>
|
||||
filterFiles = let
|
||||
getUasset = n: "${pkgs.uassets}/share/filters/${n}.txt";
|
||||
in [
|
||||
# default ublock filters:
|
||||
(getUasset "ublock-filters")
|
||||
(getUasset "ublock-badware")
|
||||
(getUasset "ublock-privacy")
|
||||
(getUasset "ublock-quick-fixes")
|
||||
(getUasset "ublock-unbreak")
|
||||
(getUasset "easylist")
|
||||
(getUasset "easyprivacy")
|
||||
# (getUasset "urlhaus-1") #< TODO: i think this is the same as urlhaus-filter-online
|
||||
(getUasset "urlhaus-filter-online")
|
||||
# (getUasset "plowe-0") #< TODO: where does this come from?
|
||||
# (getUasset "ublock-cookies-adguard") #< TODO: where does this come from?
|
||||
# filters i've added:
|
||||
(getUasset "easylist-annoyances") #< blocks in-page popups, "social media content" (e.g. FB like button; improves loading time)
|
||||
(getUasset "easylist-cookies") #< blocks GDPR cookie consent popovers (e.g. at stackoverflow.com)
|
||||
# (getUasset "ublock-annoyances-others")
|
||||
# (getUasset "ublock-annoyances-cookies")
|
||||
];
|
||||
};
|
||||
|
||||
env = lib.mkIf cfg.addons.browserpass-extension.enable {
|
||||
# TODO: env.PASSWORD_STORE_DIR only needs to be present within the browser session.
|
||||
# alternative to PASSWORD_STORE_DIR:
|
||||
# fs.".password-store".symlink.target = lib.mkIf cfg.addons.browserpass-extension.enable "knowledge/secrets/accounts";
|
||||
PASSWORD_STORE_DIR = "/home/colin/knowledge/secrets/accounts";
|
||||
};
|
||||
};
|
||||
}
|
25
hosts/common/programs/firefox/bookmarks.html
Normal file
25
hosts/common/programs/firefox/bookmarks.html
Normal file
@@ -0,0 +1,25 @@
|
||||
<!DOCTYPE NETSCAPE-Bookmark-file-1>
|
||||
<!-- This is an automatically generated file.
|
||||
It will be read and overwritten.
|
||||
DO NOT EDIT! -->
|
||||
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8">
|
||||
<meta http-equiv="Content-Security-Policy"
|
||||
content="default-src 'self'; script-src 'none'; img-src data: *; object-src 'none'"></meta>
|
||||
<TITLE>Bookmarks</TITLE>
|
||||
<H1>Bookmarks Menu</H1>
|
||||
|
||||
<DL><p>
|
||||
<DT><H3 ADD_DATE="1" LAST_MODIFIED="1" UNFILED_BOOKMARKS_FOLDER="true">Other Bookmarks</H3>
|
||||
<DL><p>
|
||||
<DT><A HREF="https://en.wikipedia.org/wiki/Special:Search?search=%s" ADD_DATE="1" LAST_MODIFIED="1" SHORTCUTURL="w">Search Wikipedia</A>
|
||||
<DT><A HREF="https://duckduckgo.com/?t=h_&q=%s" ADD_DATE="1" LAST_MODIFIED="1" SHORTCUTURL="ddg">Search DuckDuckGo</A>
|
||||
<DT><A HREF="https://www.youtube.com/results?search_query=%s" ADD_DATE="1" LAST_MODIFIED="1" SHORTCUTURL="yt">Search YouTube</A>
|
||||
<DT><A HREF="https://search.nixos.org/options?channel=unstable&query=%s" ADD_DATE="1" LAST_MODIFIED="1" SHORTCUTURL="opt">Search NixOS Options</A>
|
||||
<DT><A HREF="https://wiki.archlinux.org/index.php?title=Special%3ASearch&search=%s" ADD_DATE="1" LAST_MODIFIED="1" SHORTCUTURL="arch">Search ArchWiki</A>
|
||||
<DT><A HREF="https://www.amazon.com/s/?url=search-alias%3Daps&field-keywords=%s" ADD_DATE="1" LAST_MODIFIED="1" SHORTCUTURL="am">Search Amazon.com</A>
|
||||
<DT><A HREF="https://www.ebay.com/sch/i.html?_sacat=0&_nkw=%s" ADD_DATE="1" LAST_MODIFIED="1" SHORTCUTURL="ebay">Search eBay</A>
|
||||
<DT><A HREF="https://github.com/nixos/nixpkgs/pulls?q=%s" ADD_DATE="1" LAST_MODIFIED="1" SHORTCUTURL="pr">Search nixpkgs PRs</A>
|
||||
<DT><A HREF="https://repology.org/projects/?maintainer=&category=&inrepo=¬inrepo=&repos=&families=&repos_newest=&families_newest=&search=%s" ADD_DATE="1" LAST_MODIFIED="1" SHORTCUTURL="repo">Search Repology - packages</A>
|
||||
<DT><A HREF="https://myanimelist.net/?type=all&topkeyword=%s" ADD_DATE="1" LAST_MODIFIED="1" SHORTCUTURL="mal">Search MyAnimeList.net</A>
|
||||
</DL><p>
|
||||
</DL>
|
319
hosts/common/programs/firefox/default.nix
Normal file
319
hosts/common/programs/firefox/default.nix
Normal file
@@ -0,0 +1,319 @@
|
||||
# common settings to toggle (at runtime, in about:config):
|
||||
# > security.ssl.require_safe_negotiation
|
||||
|
||||
# librewolf is a forked firefox which patches firefox to allow more things
|
||||
# (like default search engines) to be configurable at runtime.
|
||||
# many of the settings below won't have effect without those patches.
|
||||
# see: https://gitlab.com/librewolf-community/settings/-/blob/master/distribution/policies.json
|
||||
|
||||
{ config, lib, pkgs, ...}:
|
||||
with lib;
|
||||
let
|
||||
cfg = config.sane.programs.firefox.config;
|
||||
mobile-prefs = lib.optionals false pkgs.librewolf-pmos-mobile.extraPrefsFiles;
|
||||
# allow easy switching between firefox and librewolf with `defaultSettings`, below
|
||||
librewolfSettings = {
|
||||
browser = pkgs.librewolf-unwrapped;
|
||||
extraPrefsFiles = pkgs.librewolf-unwrapped.extraPrefsFiles ++ mobile-prefs;
|
||||
libName = "librewolf";
|
||||
dotDir = ".librewolf";
|
||||
cacheDir = ".cache/librewolf";
|
||||
desktop = "librewolf.desktop";
|
||||
};
|
||||
firefoxSettings = {
|
||||
browser = pkgs.firefox-esr-unwrapped;
|
||||
extraPrefsFiles = mobile-prefs;
|
||||
libName = "firefox";
|
||||
dotDir = ".mozilla/firefox";
|
||||
cacheDir = ".cache/mozilla";
|
||||
desktop = "firefox.desktop";
|
||||
};
|
||||
# defaultSettings = firefoxSettings;
|
||||
defaultSettings = librewolfSettings;
|
||||
|
||||
packageUnwrapped = (pkgs.wrapFirefox cfg.browser.browser {
|
||||
# inherit the default librewolf.cfg
|
||||
# it can be further customized via ~/.librewolf/librewolf.overrides.cfg
|
||||
inherit (cfg.browser) extraPrefsFiles libName;
|
||||
|
||||
nativeMessagingHosts = lib.optionals cfg.addons.browserpass-extension.enable [
|
||||
pkgs.browserpass
|
||||
] ++ lib.optionals cfg.addons.fxCast.enable [
|
||||
pkgs.fx-cast-bridge
|
||||
];
|
||||
|
||||
nixExtensions = concatMap (ext: optional ext.enable ext.package) (attrValues cfg.addons);
|
||||
|
||||
# extraPolicies: only really required if using firefox; else, easier to configure this via overrides.cfg.
|
||||
# extraPolicies = {
|
||||
# FirefoxHome = {
|
||||
# Search = true;
|
||||
# Pocket = false;
|
||||
# Snippets = false;
|
||||
# TopSites = false;
|
||||
# Highlights = false;
|
||||
# };
|
||||
# NoDefaultBookmarks = true;
|
||||
# OfferToSaveLogins = false;
|
||||
# OfferToSaveLoginsDefault = false;
|
||||
# PasswordManagerEnabled = false;
|
||||
# SearchEngines = {
|
||||
# Default = "DuckDuckGo";
|
||||
# };
|
||||
# UserMessaging = {
|
||||
# ExtensionRecommendations = false;
|
||||
# FeatureRecommendations = false;
|
||||
# SkipOnboarding = true;
|
||||
# UrlbarInterventions = false;
|
||||
# WhatsNew = false;
|
||||
# };
|
||||
|
||||
# # these were taken from Librewolf
|
||||
# AppUpdateURL = "https://localhost";
|
||||
# DisableAppUpdate = true;
|
||||
# OverrideFirstRunPage = "";
|
||||
# OverridePostUpdatePage = "";
|
||||
# DisableSystemAddonUpdate = true;
|
||||
# DisableFirefoxStudies = true;
|
||||
# DisableTelemetry = true;
|
||||
# DisableFeedbackCommands = true;
|
||||
# DisablePocket = true;
|
||||
# DisableSetDesktopBackground = false;
|
||||
|
||||
# # remove many default search providers
|
||||
# # XXX this seems to prevent the `nixExtensions` from taking effect
|
||||
# # Extensions.Uninstall = [
|
||||
# # "google@search.mozilla.org"
|
||||
# # "bing@search.mozilla.org"
|
||||
# # "amazondotcom@search.mozilla.org"
|
||||
# # "ebay@search.mozilla.org"
|
||||
# # "twitter@search.mozilla.org"
|
||||
# # ];
|
||||
# # XXX doesn't seem to have any effect...
|
||||
# # docs: https://github.com/mozilla/policy-templates#homepage
|
||||
# # Homepage = {
|
||||
# # HomepageURL = "https://uninsane.org/";
|
||||
# # StartPage = "homepage";
|
||||
# # };
|
||||
# # NewTabPage = true;
|
||||
# };
|
||||
# extraPrefs = ...
|
||||
}).overrideAttrs (base: {
|
||||
nativeBuildInputs = (base.nativeBuildInputs or []) ++ [
|
||||
pkgs.copyDesktopItems
|
||||
];
|
||||
desktopItems = (base.desktopItems or []) ++ [
|
||||
(pkgs.makeDesktopItem {
|
||||
name = "${cfg.browser.libName}-in-vpn";
|
||||
desktopName = "${cfg.browser.libName} (VPN)";
|
||||
genericName = "Web Browser";
|
||||
# N.B.: --new-instance ensures we don't reuse an existing differenty-namespaced instance.
|
||||
# OTOH, it may error about "only one instance can run at a time": close the other instance if you see that.
|
||||
exec = "${lib.getExe pkgs.sane-scripts.vpn} do default -- ${cfg.browser.libName} --new-instance";
|
||||
icon = cfg.browser.libName;
|
||||
categories = [ "Network" "WebBrowser" ];
|
||||
type = "Application";
|
||||
})
|
||||
(pkgs.makeDesktopItem {
|
||||
name = "${cfg.browser.libName}-stub-dns";
|
||||
desktopName = "${cfg.browser.libName} (stub DNS)";
|
||||
genericName = "Web Browser";
|
||||
# N.B.: --new-instance ensures we don't reuse an existing differently-namespaced instance.
|
||||
# OTOH, it may error about "only one instance can run at a time": close the other instance if you see that.
|
||||
exec = "${lib.getExe pkgs.sane-scripts.vpn} do none -- ${cfg.browser.libName} --new-instance";
|
||||
icon = cfg.browser.libName;
|
||||
categories = [ "Network" "WebBrowser" ];
|
||||
type = "Application";
|
||||
})
|
||||
];
|
||||
|
||||
# TODO: could use `zip -f` to only update the one changed file, instead of rezipping everything.
|
||||
buildCommand = (base.buildCommand or "") + ''
|
||||
mkdir omni
|
||||
|
||||
echo "omni.ja BEFORE:"
|
||||
ls -l $(readlink $out/lib/${cfg.browser.libName}/browser/omni.ja)
|
||||
|
||||
echo "unzipping omni.ja"
|
||||
# N.B. `zip` exits non-zero even on successful extraction, if the file didn't 100% obey spec
|
||||
${pkgs.buildPackages.unzip}/bin/unzip $out/lib/${cfg.browser.libName}/browser/omni.ja -d omni || true
|
||||
|
||||
echo "removing old omni.ja"
|
||||
rm $out/lib/${cfg.browser.libName}/browser/omni.ja
|
||||
|
||||
echo "patching omni.ja"
|
||||
# de-associate `ctrl+shift+c` from activating the devtools.
|
||||
# see: <https://stackoverflow.com/a/54260938>
|
||||
${lib.getExe pkgs.buildPackages.gnused} -i s'/devtools-commandkey-inspector = C/devtools-commandkey-inspector = VK_F12/' omni/localization/en-US/devtools/startup/key-shortcuts.ftl
|
||||
# remap Close Tab shortcut from Ctrl+W to Ctrl+Shift+W
|
||||
# see: <https://www.math.cmu.edu/~gautam/sj/blog/20220329-firefox-disable-ctrl-w.html>
|
||||
${lib.getExe pkgs.buildPackages.gnused} -i s'/command="cmd_close" modifiers="accel"/command="cmd_close" modifiers="accel,shift"/' omni/chrome/browser/content/browser/browser.xhtml
|
||||
|
||||
echo "re-zipping omni.ja"
|
||||
pushd omni; ${pkgs.buildPackages.zip}/bin/zip $out/lib/${cfg.browser.libName}/browser/omni.ja -r ./*; popd
|
||||
|
||||
echo "omni.ja AFTER:"
|
||||
ls -l $out/lib/${cfg.browser.libName}/browser/omni.ja
|
||||
|
||||
runHook postBuild
|
||||
runHook postInstall
|
||||
runHook postFixup
|
||||
'';
|
||||
});
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
./addons.nix
|
||||
];
|
||||
|
||||
sane.programs.firefox = {
|
||||
configOption = mkOption {
|
||||
default = {};
|
||||
type = types.submodule {
|
||||
options = {
|
||||
browser = mkOption {
|
||||
default = defaultSettings;
|
||||
type = types.anything;
|
||||
};
|
||||
persistData = mkOption {
|
||||
description = "optional store name to which persist browsing data (like history)";
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
};
|
||||
persistCache = mkOption {
|
||||
description = "optional store name to which persist browser cache";
|
||||
type = types.nullOr types.str;
|
||||
default = "ephemeral";
|
||||
};
|
||||
addons = mkOption {
|
||||
default = {};
|
||||
type = types.attrsOf (types.submodule {
|
||||
options = {
|
||||
package = mkOption {
|
||||
type = types.package;
|
||||
};
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
};
|
||||
};
|
||||
});
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
inherit packageUnwrapped;
|
||||
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.net = "all";
|
||||
sandbox.whitelistAudio = true;
|
||||
sandbox.whitelistAvDev = true; #< it doesn't seem to use pipewire, but direct /dev/videoN (as of 2024/09/12)
|
||||
sandbox.whitelistDbus = [ "user" ]; # mpris
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.extraHomePaths = [
|
||||
"dev" # for developing anything web-related
|
||||
# for uploads/downloads.
|
||||
# it still needs these paths despite using the portal's file-chooser :?
|
||||
"tmp"
|
||||
"Pictures/albums"
|
||||
"Pictures/cat"
|
||||
"Pictures/from"
|
||||
"Pictures/Photos"
|
||||
"Pictures/Screenshots"
|
||||
"Pictures/servo-macros"
|
||||
];
|
||||
|
||||
mime.associations = let
|
||||
inherit (cfg.browser) desktop;
|
||||
in {
|
||||
"text/html" = desktop;
|
||||
"x-scheme-handler/http" = desktop;
|
||||
"x-scheme-handler/https" = desktop;
|
||||
"x-scheme-handler/about" = desktop;
|
||||
"x-scheme-handler/unknown" = desktop;
|
||||
};
|
||||
|
||||
env.BROWSER = cfg.browser.libName; # used by misc tools like xdg-email, as fallback
|
||||
|
||||
# redirect librewolf configs to the firefox configs; this way addons don't have to care about the firefox/librewolf distinction.
|
||||
fs.".librewolf/librewolf.overrides.cfg".symlink.target = "../.mozilla/firefox/firefox.overrides.cfg";
|
||||
fs.".librewolf/profiles.ini".symlink.target = "../.mozilla/firefox/profiles.ini";
|
||||
fs.".librewolf/managed-storage".symlink.target = "../.mozilla/firefox/managed-storage";
|
||||
|
||||
# N.B.: `overrides.cfg` might be librewolf-specific -- not supported by mainline firefox.
|
||||
# firefox does support per-profile `user.js` files which have similar functionality.
|
||||
fs.".mozilla/firefox/firefox.overrides.cfg".symlink.text = ''
|
||||
// use `pref(...)` to force a preference
|
||||
// use `defaultPref(...)` to allow runtime reconfiguration
|
||||
// discover preference names via the `about:config` page
|
||||
//
|
||||
// if we can't query the revocation status of a SSL cert because the issuer is offline,
|
||||
// treat it as unrevoked.
|
||||
// see: <https://librewolf.net/docs/faq/#im-getting-sec_error_ocsp_server_error-what-can-i-do>
|
||||
defaultPref("security.OCSP.require", false);
|
||||
|
||||
// scrollbar configuration, see: <https://artemis.sh/2023/10/12/scrollbars.html>
|
||||
// style=4 gives rectangular scrollbars
|
||||
// could also enable "always show scrollbars" in about:preferences -- not sure what the actual pref name for that is
|
||||
// note that too-large scrollbars (like 50px wide, even 20px) tend to obscure content (and make buttons unclickable)
|
||||
defaultPref("widget.non-native-theme.scrollbar.size.override", 14);
|
||||
defaultPref("widget.non-native-theme.scrollbar.style", 4);
|
||||
|
||||
// disable inertial/kinetic/momentum scrolling because it just gets in the way on touchpads
|
||||
// source: <https://kparal.wordpress.com/2019/10/31/disabling-kinetic-scrolling-in-firefox/>
|
||||
defaultPref("apz.gtk.kinetic_scroll.enabled", false);
|
||||
|
||||
// open external URIs/files via xdg-desktop-portal.
|
||||
defaultPref("widget.use-xdg-desktop-portal.mime-handler", 1);
|
||||
defaultPref("widget.use-xdg-desktop-portal.open-uri", 1);
|
||||
|
||||
defaultPref("browser.toolbars.bookmarks.visibility", "never");
|
||||
// configure which extensions are visible by default (TODO: requires a lot of trial and error)
|
||||
// defaultPref("browser.uiCustomization.state", ...);
|
||||
|
||||
// auto-open specific URI schemes without prompting:
|
||||
defaultPref("network.protocol-handler.external.xdg-open", true); // for firefox-xdg-open extension
|
||||
defaultPref("network.protocol-handler.external.mpv", true); // for open-in-mpv extension
|
||||
defaultPref("network.protocol-handler.external.element", true); // for Element matrix client
|
||||
defaultPref("network.protocol-handler.external.matrix", true); // for Nheko matrix client
|
||||
|
||||
// statically configure bookmarks.
|
||||
// notably, these bookmarks have "shortcut url" fields:
|
||||
// - type `w thing` into the URL bar to search "thing" on Wikipedia.
|
||||
// - to add a search shortcut: right-click any search box => "Add a keyword for this search".
|
||||
// - to update the static bookmarks, export via Hamburger => bookmarks => manage bookmarks => Import and Backup => Export Bookmarks To HTML
|
||||
defaultPref("browser.places.importBookmarksHTML", true);
|
||||
defaultPref("browser.bookmarks.file", "${./bookmarks.html}");
|
||||
|
||||
defaultPref("browser.startup.homepage", "https://uninsane.org/places");
|
||||
'';
|
||||
|
||||
# instruct Firefox to put the profile in a predictable directory (so we can do things like persist just it).
|
||||
# XXX: the directory *must* exist, even if empty; Firefox will not create the directory itself.
|
||||
fs.".mozilla/firefox/profiles.ini".symlink.text = ''
|
||||
[Profile0]
|
||||
Name=default
|
||||
IsRelative=1
|
||||
Path=default
|
||||
Default=1
|
||||
|
||||
[General]
|
||||
StartWithLastProfile=1
|
||||
'';
|
||||
|
||||
# flush the cache to disk to avoid it taking up too much tmp.
|
||||
persist.byPath."${cfg.browser.cacheDir}".store =
|
||||
if (cfg.persistData != null) then
|
||||
cfg.persistData
|
||||
else
|
||||
"ephemeral"
|
||||
;
|
||||
|
||||
persist.byPath."${cfg.browser.dotDir}/default".store =
|
||||
if (cfg.persistData != null) then
|
||||
cfg.persistData
|
||||
else
|
||||
"ephemeral"
|
||||
;
|
||||
};
|
||||
}
|
@@ -1,12 +1,16 @@
|
||||
# Flare is a 3rd-party GTK4 Signal app.
|
||||
# UI is effectively a clone of Fractal.
|
||||
#
|
||||
### compatibility:
|
||||
### compatibility (2023-10-30):
|
||||
# - desko: works fine. pairs, and exchanges contact list (but not message history) with the paired device. exchanges future messages fine.
|
||||
# - moby (cross compiled flare-signal-nixified): nope. it pairs, but can only *receive* messages and never *send* them.
|
||||
# - even `rsync`ing the data and keyrings from desko -> moby, still fails in that same manner.
|
||||
# - console shows error messages. quite possibly an endianness mismatch somewhere
|
||||
# - moby (partially-emulated flare-signal): works! pairs and can send/receive messages, same as desko.
|
||||
### compatibility (2024-08-07):
|
||||
# - linking flare to iOS signal "works", but neither side can exchange messages nor contacts
|
||||
# in iOS i see "A message from Colin could not be delivered"
|
||||
# - registering as primary device does not work ("you are not authorized", or some such)
|
||||
#
|
||||
### debugging:
|
||||
# - `RUST_LOG=flare=trace flare`
|
||||
@@ -18,7 +22,7 @@
|
||||
# ERROR presage::manager] Error opening envelope: ProtobufDecodeError(DecodeError { description: "invalid tag value: 0", stack: [("Content", "data_message")] }), message will be skipped!
|
||||
# ERROR presage::manager] Error opening envelope: ProtobufDecodeError(DecodeError { description: "invalid tag value: 0", stack: [("Content", "data_message")] }), message will be skipped!
|
||||
# ```
|
||||
# - this occurs on moby, desko, `flare-signal` and `flare-signal-nixified`
|
||||
# - this occurs on moby, desko, `flare-signal` and `flare-signal-nixified` (2023-12-14)
|
||||
# - the Websocket error seems to be unrelated, occurs during normal/good operation
|
||||
# - related issues: <https://github.com/whisperfish/presage/issues/152>
|
||||
#
|
||||
@@ -28,7 +32,7 @@
|
||||
# No current session
|
||||
# ERROR presage::manager] Error opening envelope: SignalProtocolError(InvalidKyberPreKeyId), message will be skipped!
|
||||
# ```
|
||||
# - but signal iOS will still read it.
|
||||
# - but signal iOS will still read it (2023-12-14).
|
||||
#
|
||||
#### HTTP 405 when linking flare to iOS signal:
|
||||
# [DEBUG libsignal_service_hyper::push_service] HTTP request PUT https://chat.signal.org/v1/devices/{uuid}.{timestamp?}:{b64-string}
|
||||
@@ -43,7 +47,7 @@
|
||||
# ),
|
||||
# ),
|
||||
# )
|
||||
# flare matrix suggests the signal endpoint has changed:
|
||||
# flare matrix suggests the signal endpoint has changed (2023-12-14):
|
||||
# - "/v1/device/link instead of confirming via /v1/devices/{I'd}"
|
||||
# - this endpoint is declared in libsignal-service-rs (used both by flare and presage)
|
||||
# - libsignal-service/src/provisioning/manager.rs
|
||||
@@ -73,5 +77,13 @@
|
||||
# and it persists some dconf settings (e.g. device name). reset with:
|
||||
# - `dconf reset -f /de/schmidhuberj/Flare/`.
|
||||
];
|
||||
#VVV flare complains if its data directory is a symlink, so put it in a subdirectory behind my persistence symlink.
|
||||
env.FLARE_DATA_PATH = "$HOME/.local/share/flare/data";
|
||||
# sandbox.method = "bwrap";
|
||||
# sandbox.net = "clearnet";
|
||||
# sandbox.whitelistWayland = true;
|
||||
# sandbox.whitelistDbus = [
|
||||
# "user" # so i can click on links, at least
|
||||
# ];
|
||||
};
|
||||
}
|
||||
|
42
hosts/common/programs/foliate.nix
Normal file
42
hosts/common/programs/foliate.nix
Normal file
@@ -0,0 +1,42 @@
|
||||
# foliate: <https://johnfactotum.github.io/foliate/>
|
||||
{ ... }:
|
||||
{
|
||||
sane.programs.foliate = {
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.net = "clearnet"; #< for dictionary, wikipedia, online book libraries
|
||||
sandbox.whitelistDbus = [ "user" ]; #< when clicking on links
|
||||
sandbox.whitelistDri = true; # reduces startup time and subjective page flip time
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.extraHomePaths = [
|
||||
"Books/local"
|
||||
"Books/servo"
|
||||
"tmp" #< for downloaded files
|
||||
];
|
||||
sandbox.extraPaths = [
|
||||
# foliate sandboxes itself with bwrap, which needs these.
|
||||
# but it actually only cares that /sys/{block,bus,class/block} *exist*: it doesn't care if there's anything in them.
|
||||
# so bind empty (sub)directories
|
||||
# and it looks like i might need to keep IPC namespace if i want TTS.
|
||||
"/sys/block/loop7"
|
||||
"/sys/bus/container/devices"
|
||||
"/sys/class/block/loop7"
|
||||
];
|
||||
sandbox.autodetectCliPaths = "existing";
|
||||
|
||||
persist.byStore.plaintext = [
|
||||
".local/share/com.github.johnfactotum.Foliate" #< books added, reading position
|
||||
".cache/com.github.johnfactotum.Foliate" #< webkit cache
|
||||
];
|
||||
|
||||
buildCost = 2; #< webkitgtk 6.0
|
||||
# these associations were taken from its .desktop file
|
||||
mime.associations."application/epub+zip" = "com.github.johnfactotum.Foliate.desktop";
|
||||
mime.associations."application/x-mobipocket-ebook" = "com.github.johnfactotum.Foliate.desktop";
|
||||
mime.associations."application/vnd.amazon.mobi8-ebook" = "com.github.johnfactotum.Foliate.desktop";
|
||||
mime.associations."application/x-fictionbook+xml" = "com.github.johnfactotum.Foliate.desktop";
|
||||
mime.associations."application/x-zip-compressed-fb2" = "com.github.johnfactotum.Foliate.desktop";
|
||||
mime.associations."application/vnd.comicbook+zip" = "com.github.johnfactotum.Foliate.desktop"; # .cbz
|
||||
mime.associations."x-scheme-handler/opds" = "com.github.johnfactotum.Foliate.desktop";
|
||||
mime.priority = 120; #< default is 100; fallback to more specialized cbz handlers, e.g., but keep specializations for epub
|
||||
};
|
||||
}
|
@@ -55,7 +55,7 @@ let
|
||||
in
|
||||
{
|
||||
sane.programs.fontconfig = {
|
||||
sandbox.method = "bwrap"; # TODO:sandbox: untested
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.autodetectCliPaths = "existingOrParent"; #< this might be overkill; or, how many programs reference fontconfig internally?
|
||||
|
||||
# persist.byStore.plaintext = [
|
||||
|
@@ -26,7 +26,7 @@ in
|
||||
packageUnwrapped = pkgs.fractal-nixified.optimized;
|
||||
# packageUnwrapped = pkgs.fractal;
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.net = "clearnet";
|
||||
sandbox.whitelistAudio = true;
|
||||
sandbox.whitelistDbus = [ "user" ]; # notifications
|
||||
@@ -65,6 +65,9 @@ in
|
||||
|
||||
suggestedPrograms = [ "gnome-keyring" ];
|
||||
|
||||
# direct room links opened from other programs, to fractal.
|
||||
mime.urlAssociations."^https?://matrix.to/#/.+$" = "org.gnome.Fractal.desktop";
|
||||
|
||||
services.fractal = {
|
||||
description = "fractal Matrix client";
|
||||
partOf = lib.mkIf cfg.config.autostart [ "graphical-session" ];
|
||||
|
@@ -2,8 +2,7 @@
|
||||
{
|
||||
sane.programs.free = {
|
||||
packageUnwrapped = pkgs.linkBinIntoOwnPackage pkgs.procps "free";
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.isolatePids = false;
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.extraPaths = [ "/proc/meminfo" ];
|
||||
};
|
||||
}
|
||||
|
||||
|
@@ -11,7 +11,7 @@
|
||||
});
|
||||
buildCost = 1;
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.net = "clearnet"; # net play
|
||||
sandbox.whitelistAudio = true;
|
||||
sandbox.whitelistWayland = true;
|
||||
|
@@ -10,7 +10,7 @@
|
||||
sane.programs.g4music = {
|
||||
buildCost = 1;
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.whitelistAudio = true;
|
||||
sandbox.whitelistDbus = [ "user" ]; # mpris
|
||||
sandbox.whitelistWayland = true;
|
||||
|
@@ -3,8 +3,7 @@
|
||||
sane.programs.gdbus = {
|
||||
packageUnwrapped = pkgs.linkBinIntoOwnPackage pkgs.glib "gdbus";
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.whitelistDbus = [ "user" ]; #< XXX: maybe future users will also want system access
|
||||
};
|
||||
}
|
||||
|
||||
|
@@ -14,15 +14,23 @@ in
|
||||
type = types.submodule {
|
||||
options.autostart = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
default = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.wrapperType = "inplace"; #< XXX(2024-08-20): if executed from a directory different than the configured prefix, it fails to locate its sql migration files
|
||||
sandbox.net = "clearnet";
|
||||
sandbox.whitelistDbus = [ "user" ]; # notifications
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.extraHomePaths = [
|
||||
# it shouldn't need these, but portal integration seems incomplete?
|
||||
"tmp"
|
||||
"Pictures/from"
|
||||
"Pictures/Photos"
|
||||
"Pictures/Screenshots"
|
||||
];
|
||||
sandbox.extraPaths = [
|
||||
# geary sandboxes *itself* with bwrap, and dbus-proxy which, confusingly, causes it to *require* these paths.
|
||||
# TODO: these could maybe be mounted empty. or maybe there's an env-var to disable geary's dbus-proxy.
|
||||
|
@@ -7,7 +7,7 @@
|
||||
path = "${config.sane.programs.geoclue2.packageUnwrapped}/libexec/geoclue-2.0/demos/agent";
|
||||
}];
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.whitelistDbus = [
|
||||
"system"
|
||||
];
|
||||
|
@@ -18,7 +18,7 @@ in
|
||||
rm "$out/bin/git-jump"
|
||||
'';
|
||||
});
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.net = "clearnet";
|
||||
sandbox.whitelistPwd = true;
|
||||
sandbox.autodetectCliPaths = true; # necessary for git-upload-pack
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{ pkgs, ... }: {
|
||||
sane.programs."gnome.gnome-clocks" = {
|
||||
packageUnwrapped = pkgs.gnome.gnome-clocks.overrideAttrs (upstream: {
|
||||
sane.programs.gnome-clocks = {
|
||||
packageUnwrapped = pkgs.gnome-clocks.overrideAttrs (upstream: {
|
||||
# TODO: upstream this
|
||||
buildInputs = upstream.buildInputs ++ (with pkgs; [
|
||||
# gnome-clocks needs `playbin` (gst-plugins-base) and `scaletempo` (gst-plugins-good)
|
||||
@@ -12,7 +12,7 @@
|
||||
});
|
||||
|
||||
buildCost = 1;
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.whitelistAudio = true;
|
||||
sandbox.whitelistDbus = [ "user" ]; #< required (alongside .config/dconf) to remember timers
|
||||
sandbox.whitelistWayland = true;
|
||||
|
@@ -1,8 +1,9 @@
|
||||
{ lib, pkgs, ... }:
|
||||
# TODO: gnome-keyring has portal integration? ($out/share/xdg-desktop-portal)
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
sane.programs.gnome-keyring = {
|
||||
packageUnwrapped = pkgs.rmDbusServices pkgs.gnome-keyring;
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.whitelistDbus = [ "user" ];
|
||||
sandbox.extraRuntimePaths = [
|
||||
"keyring" #< only needs keyring/control, but has to *create* that.
|
||||
@@ -10,16 +11,12 @@
|
||||
];
|
||||
sandbox.capabilities = [
|
||||
# ipc_lock: used to `mlock` the secrets so they don't get swapped out.
|
||||
# this is optional, and systemd likely doesn't propagate it anyway
|
||||
# this is optional, and user namespacing (bwrap) likely doesn't propagate it anyway
|
||||
"ipc_lock"
|
||||
];
|
||||
|
||||
persist.byStore.private = [
|
||||
# N.B.: BE CAREFUL WITH THIS.
|
||||
# gnome-keyring-daemon likes to turn symlinks into dirs. i.e. if it detects that `~/.local/share/keyrings` is a symlink
|
||||
# it WILL try to `unlink` it and recreate it as an empty directory.
|
||||
# the only reason i can get away with a symlink here is because gkd is sandboxed... with ~/.local/share/keyrings as an explicit mountpoint instead of as a symlink.
|
||||
# remove the sandbox, and this breaks.
|
||||
# N.B.: gnome-keyring-daemon used to remove symlinks and replace them with empty directories, but as of 2024-09-05 that seems no longer the case.
|
||||
".local/share/keyrings"
|
||||
];
|
||||
|
||||
@@ -51,6 +48,9 @@
|
||||
partOf = [ "graphical-session" ];
|
||||
command = let
|
||||
gkr-start = pkgs.writeShellScriptBin "gnome-keyring-daemon-start" ''
|
||||
set -eu
|
||||
# XXX(2024-09-05): this service races with the creation of the keyrings directory, so wait for it to appear
|
||||
test -e ~/.local/share/keyrings
|
||||
mkdir -m 0700 -p $XDG_RUNTIME_DIR/keyring
|
||||
exec gnome-keyring-daemon --start --foreground --components=secrets
|
||||
'';
|
||||
|
@@ -10,22 +10,34 @@
|
||||
# TIPS:
|
||||
# - use "Northwest" instead of "NW", and "Street" instead of "St", etc.
|
||||
# otherwise, it might not find your destination!
|
||||
#
|
||||
# TODO:
|
||||
# - get gnome-maps to access location services via the xdg-desktop-portal.
|
||||
# with it not using the portal, it can't open links via the web browser.
|
||||
# additionally, that prevents OpenStreetMap sign-in.
|
||||
# even temporarily enabling the portal for OSM doesn't work *after* the portal has been disabled -- because then gnome-maps can't access its passwords (?)
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
sane.programs."gnome.gnome-maps" = {
|
||||
packageUnwrapped = pkgs.rmDbusServicesInPlace (pkgs.gnome.gnome-maps.overrideAttrs (base: {
|
||||
sane.programs.gnome-maps = {
|
||||
packageUnwrapped = pkgs.rmDbusServicesInPlace (pkgs.gnome-maps.overrideAttrs (base: {
|
||||
# default .desktop file is trying to do some dbus launch (?) which fails even *if* i install `gapplication` (glib.bin)
|
||||
postPatch = (base.postPatch or "") + ''
|
||||
substituteInPlace data/org.gnome.Maps.desktop.in.in \
|
||||
--replace-fail 'Exec=gapplication launch @app-id@ %U' 'Exec=gnome-maps %U'
|
||||
'';
|
||||
# TODO: set up portal-based location services, but until that works, explicitly disable portals here.
|
||||
preFixup = (base.preFixup or "") + ''
|
||||
gappsWrapperArgs+=(
|
||||
--unset GIO_USE_PORTALS
|
||||
)
|
||||
'';
|
||||
}));
|
||||
suggestedPrograms = [
|
||||
"geoclue2"
|
||||
];
|
||||
|
||||
sandbox.wrapperType = "inplace"; #< /share directory contains Gir info which references libgnome-maps.so by path
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.whitelistDri = true; # for perf
|
||||
sandbox.whitelistDbus = [
|
||||
"system" # system is required for non-portal location services
|
||||
@@ -33,11 +45,10 @@
|
||||
];
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.net = "clearnet";
|
||||
sandbox.usePortal = false; # TODO: set up portal-based location services
|
||||
|
||||
persist.byStore.plaintext = [ ".cache/shumate" ];
|
||||
persist.byStore.private = [
|
||||
({ path = ".local/share/maps-places.json"; type = "file"; })
|
||||
{ path = ".local/share/maps-places.json"; type = "file"; }
|
||||
];
|
||||
};
|
||||
}
|
||||
|
@@ -2,10 +2,10 @@
|
||||
# cache dir is just for weather data (or maybe a http cache)
|
||||
{ ... }:
|
||||
{
|
||||
sane.programs."gnome.gnome-weather" = {
|
||||
sane.programs.gnome-weather = {
|
||||
buildCost = 1;
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.wrapperType = "inplace"; #< /share/org.gnome.Weather/org.gnome.Weather file refers to bins by full path
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.net = "clearnet";
|
||||
|
@@ -42,13 +42,13 @@
|
||||
# - mkv container + H.265 video + E-AC-3/48k stereo audio:
|
||||
# - LGTV: no transcoding needed
|
||||
#
|
||||
{ config, lib, pkgs, ... }:
|
||||
{ config, lib, ... }:
|
||||
let
|
||||
cfg = config.sane.programs.go2tv;
|
||||
in
|
||||
{
|
||||
sane.programs.go2tv = {
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.net = "clearnet";
|
||||
sandbox.autodetectCliPaths = "existingFile";
|
||||
# for GUI invocation, allow the common media directories
|
||||
|
27
hosts/common/programs/gocryptfs.nix
Normal file
27
hosts/common/programs/gocryptfs.nix
Normal file
@@ -0,0 +1,27 @@
|
||||
{ ... }:
|
||||
{
|
||||
sane.programs.gocryptfs = {
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.autodetectCliPaths = "existing";
|
||||
sandbox.capabilities = [
|
||||
# CAP_SYS_ADMIN is only required if directly invoking gocryptfs.
|
||||
# it's not *necessarily* required if using a mount helper like `mount.fuse3-sane`
|
||||
# however if using a namespace-based sandbox method (bunpen, bwrap), and you wish
|
||||
# to preserve user mappings, it's still required.
|
||||
"sys_admin"
|
||||
"chown"
|
||||
"dac_override"
|
||||
"dac_read_search"
|
||||
"fowner"
|
||||
"lease"
|
||||
"mknod"
|
||||
"setgid"
|
||||
"setuid"
|
||||
];
|
||||
sandbox.tryKeepUsers = true;
|
||||
sandbox.keepPids = true;
|
||||
suggestedPrograms = [
|
||||
"util-linux" #< gocryptfs complains that it can't exec `logger`, otherwise. TODO(2024-09-09): is this still needed?
|
||||
];
|
||||
};
|
||||
}
|
@@ -22,7 +22,7 @@ in {
|
||||
];
|
||||
});
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.whitelistDbus = [ "user" ]; # it won't launch without it, dunno exactly why.
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.net = "clearnet";
|
||||
|
@@ -25,6 +25,12 @@ in
|
||||
"jq"
|
||||
# and systemd, for udevadm
|
||||
];
|
||||
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.net = "all";
|
||||
sandbox.autodetectCliPaths = "existing"; #< N.B.: `test -f /dev/ttyUSB1` fails, we can't use `existingFile`
|
||||
sandbox.whitelistDbus = [ "system" ]; #< to register with Avahi
|
||||
|
||||
services.gps-share = {
|
||||
description = "gps-share: make local GPS serial readings available over Avahi";
|
||||
# usage:
|
||||
@@ -46,10 +52,6 @@ in
|
||||
partOf = [ "gps" ];
|
||||
depends = [ "eg25-control-powered" ];
|
||||
};
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.net = "all";
|
||||
sandbox.autodetectCliPaths = "existing"; #< N.B.: `test -f /dev/ttyUSB1` fails, we can't use `existingFile`
|
||||
};
|
||||
|
||||
# TODO: restrict this to just LAN devices!!
|
||||
|
@@ -3,7 +3,7 @@
|
||||
sane.programs."sway-contrib.grimshot" = {
|
||||
packageUnwrapped = pkgs.sway-contrib.grimshot.override {
|
||||
# my `sway` is heavily patched to be cross compatible
|
||||
sway-unwrapped = config.sane.programs.sway.package.sway-unwrapped;
|
||||
sway-unwrapped = config.sane.programs.sway.package;
|
||||
};
|
||||
suggestedPrograms = [
|
||||
# runtime dependencies (grimshot is just a trivial shell script)
|
||||
@@ -14,7 +14,8 @@
|
||||
# "sway"
|
||||
"wl-clipboard"
|
||||
];
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.keepPids = true; #< needed by wl-clipboard
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.whitelistDbus = [ "user" ];
|
||||
sandbox.autodetectCliPaths = "existingFileOrParent";
|
||||
|
@@ -2,6 +2,9 @@
|
||||
# - `gst-device-monitor-1.0 Audio/Sink` #< show all audio sinks
|
||||
# - `gst-device-monitor-1.0 Audio/Source` #< show all audio sources (microphones)
|
||||
# - `gst-device-monitor-1.0 Video/Source` #< show all video sources (cameras)
|
||||
# the output will include things like
|
||||
# `gst-launch-1.0 pipewiresrc target-object=90 ! ...`
|
||||
# in which case, view it like (for a camera): `gst-launch-1.0 pipewiresrc target-object=90 ! glimagesink`
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
sane.programs.gst-device-monitor = {
|
||||
@@ -20,7 +23,7 @@
|
||||
];
|
||||
});
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.whitelistAudio = true;
|
||||
sandbox.extraPaths = [
|
||||
"/dev" # tried, but failed to narrow this down (moby)
|
||||
|
24
hosts/common/programs/gst-launch.nix
Normal file
24
hosts/common/programs/gst-launch.nix
Normal file
@@ -0,0 +1,24 @@
|
||||
# basic environment tests:
|
||||
# - `gst-launch-1.0 audiotestsrc ! autoaudiosink`
|
||||
# - `gst-launch-1.0 videotestsrc ! videoconvert ! autovideosink`
|
||||
# more usage here: <https://github.com/matthew1000/gstreamer-cheat-sheet>
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
sane.programs.gst-launch = {
|
||||
packageUnwrapped = (
|
||||
pkgs.linkBinIntoOwnPackage pkgs.gst_all_1.gstreamer "gst-launch-1.0"
|
||||
).overrideAttrs (base: {
|
||||
# XXX the binaries need `GST_PLUGIN_SYSTEM_PATH_1_0` set to function,
|
||||
# but nixpkgs doesn't set those.
|
||||
nativeBuildInputs = (base.nativeBuildInputs or []) ++ [
|
||||
pkgs.wrapGAppsNoGuiHook
|
||||
];
|
||||
buildInputs = (base.buildInputs or []) ++ (with pkgs; [
|
||||
gst_all_1.gst-plugins-base
|
||||
gst_all_1.gst-plugins-good
|
||||
gst_all_1.gst-libav # for H.264 decoding
|
||||
pipewire
|
||||
]);
|
||||
});
|
||||
};
|
||||
}
|
@@ -3,7 +3,7 @@
|
||||
sane.programs.handbrake = {
|
||||
buildCost = 1;
|
||||
|
||||
sandbox.method = "landlock"; #< also supports bwrap, but landlock ensures we don't write to non-mounted tmpfs dir
|
||||
sandbox.method = "bunpen"; #< untested
|
||||
sandbox.whitelistDbus = [ "user" ]; # notifications
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.extraHomePaths = [
|
||||
|
9
hosts/common/programs/haredoc.nix
Normal file
9
hosts/common/programs/haredoc.nix
Normal file
@@ -0,0 +1,9 @@
|
||||
# use like `haredoc bufio::read_line`
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
sane.programs.haredoc = {
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.whitelistPwd = true; #< search for function documentation below the current directory
|
||||
env.HAREPATH = "${pkgs.hare}/src/hare/stdlib";
|
||||
};
|
||||
}
|
@@ -1,9 +1,9 @@
|
||||
{ ... }:
|
||||
{
|
||||
sane.programs.htop = {
|
||||
sandbox.method = "landlock";
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.keepPidsAndProc = true;
|
||||
sandbox.extraPaths = [
|
||||
"/proc"
|
||||
"/sys/devices"
|
||||
];
|
||||
fs.".config/htop/htoprc".symlink.target = ./htoprc;
|
||||
|
@@ -3,7 +3,7 @@
|
||||
sane.programs.imagemagick = {
|
||||
buildCost = 1;
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.wrapperType = "inplace"; # /etc/ImageMagick-7/delegates.xml refers to bins by absolute path
|
||||
sandbox.whitelistPwd = true;
|
||||
sandbox.autodetectCliPaths = "existingOrParent"; #< arg formatting is complicated enough that this won't always work.
|
||||
|
21
hosts/common/programs/inkscape.nix
Normal file
21
hosts/common/programs/inkscape.nix
Normal file
@@ -0,0 +1,21 @@
|
||||
{ ... }:
|
||||
{
|
||||
sane.programs.inkscape = {
|
||||
buildCost = 1;
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.extraHomePaths = [
|
||||
".config/dconf" #< else opening images fails
|
||||
"Pictures/albums"
|
||||
"Pictures/cat"
|
||||
"Pictures/from"
|
||||
"Pictures/Photos"
|
||||
"Pictures/Screenshots"
|
||||
"Pictures/servo-macros"
|
||||
"dev"
|
||||
"ref"
|
||||
"tmp"
|
||||
];
|
||||
sandbox.autodetectCliPaths = true;
|
||||
};
|
||||
}
|
@@ -1,9 +1,9 @@
|
||||
{ pkgs, ... }:
|
||||
{ ... }:
|
||||
{
|
||||
sane.programs.kdenlive = {
|
||||
buildCost = 1;
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.extraHomePaths = [
|
||||
"Music"
|
||||
"Pictures/from" # e.g. Videos taken from my phone
|
||||
@@ -16,5 +16,6 @@
|
||||
sandbox.whitelistDbus = [ "user" ]; # notifications
|
||||
sandbox.whitelistDri = true;
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.whitelistX = true;
|
||||
};
|
||||
}
|
||||
|
@@ -10,13 +10,13 @@
|
||||
'' + (upstream.preFixup or "");
|
||||
});
|
||||
|
||||
sandbox.method = "bwrap"; # TODO:sandbox untested
|
||||
sandbox.method = "bunpen";
|
||||
sandbox.net = "clearnet";
|
||||
sandbox.whitelistDbus = [ "user" ]; # needs to connect to dconf via dbus
|
||||
sandbox.whitelistDri = true; #< required
|
||||
sandbox.whitelistWayland = true;
|
||||
|
||||
buildCost = 2;
|
||||
buildCost = 2; # webkitgtk
|
||||
|
||||
secrets.".local/share/komikku/keyrings/plaintext.keyring" = ../../../secrets/common/komikku_accounts.json.bin;
|
||||
# downloads end up here, and without the toplevel database komikku doesn't know they exist.
|
||||
@@ -27,5 +27,8 @@
|
||||
persist.byStore.ephemeral = [
|
||||
".cache/komikku"
|
||||
];
|
||||
|
||||
# XXX(2024-08-08): komikku can handle URLs from sources it understands (maybe), but not files (even if encoded as file:// URI)
|
||||
# mime.associations."application/vnd.comicbook+zip" = "info.febvre.Komikku.desktop"; # .cbz
|
||||
};
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user