Compare commits
14
Commits
dd37b43078
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8d830eab1e | ||
|
|
9f371b6ab1 | ||
|
|
2666a84516 | ||
|
|
6d699a2cfa | ||
|
|
66714d0675 | ||
|
|
33956f2edf | ||
|
|
03160f1c60 | ||
|
|
c2599707b6 | ||
|
|
e2d2ce6c6c | ||
|
|
b3913c9c9b | ||
|
|
9d9c429033 | ||
|
|
e1672d7cbe | ||
|
|
9e44cb4c99 | ||
|
|
d7a7627163 |
No files matched your search
+11
@@ -0,0 +1,11 @@
|
|||||||
|
keys:
|
||||||
|
- &key age1tx6jdr6535xxeygpwkkgvdwc24tulr420cm7gk56xzfp0slzeqks2nwpyg
|
||||||
|
creation_rules:
|
||||||
|
- path_regex: host/[^/]+/secrets/.+$
|
||||||
|
key_groups:
|
||||||
|
- age:
|
||||||
|
- *key
|
||||||
|
- path_regex: user/[^/]+/secrets\.yaml$
|
||||||
|
key_groups:
|
||||||
|
- age:
|
||||||
|
- *key
|
||||||
Generated
+93
-49
@@ -80,11 +80,11 @@
|
|||||||
"tg_owt": "tg_owt"
|
"tg_owt": "tg_owt"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1790620039,
|
"lastModified": 1792306878,
|
||||||
"narHash": "sha256-vFY8jKgUupRGrcO9ZfVyVNwOLxRa7dqitXYwDUQqUaU=",
|
"narHash": "sha256-x9gB1qSAWKDKiX3uW0Z5asE2XzxkCfdVk5B/Og+fDlo=",
|
||||||
"owner": "ayugram-port",
|
"owner": "ayugram-port",
|
||||||
"repo": "ayugram-desktop",
|
"repo": "ayugram-desktop",
|
||||||
"rev": "3015ae5439dd2c14f15c76c3d451610456fa140d",
|
"rev": "5aafef7f62261f9dacb4e95aed950a4cc379273e",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -268,6 +268,28 @@
|
|||||||
"type": "gitlab"
|
"type": "gitlab"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"helix-steel": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"rust-overlay": "rust-overlay"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1792336814,
|
||||||
|
"narHash": "sha256-FU4WIMHhIyvEMxHeN8+Qgb3VHsU6DP74ylsyZACLzM8=",
|
||||||
|
"owner": "mattwparas",
|
||||||
|
"repo": "helix",
|
||||||
|
"rev": "16a26934f39152b5cd81bf2f6944e18e680314d0",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "mattwparas",
|
||||||
|
"ref": "steel-event-system",
|
||||||
|
"repo": "helix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"home-manager": {
|
"home-manager": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
@@ -275,11 +297,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1791569574,
|
"lastModified": 1792495086,
|
||||||
"narHash": "sha256-5sViLmjhTCtBTvhjSXXvd5LDrAFMydFFKZQisjE8Vds=",
|
"narHash": "sha256-TyoYH983Nsc++1scw0SoOEKshPSJWJDxK7tTmuZ974M=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "home-manager",
|
"repo": "home-manager",
|
||||||
"rev": "6b88c12cc6d234de4888f5d21076fb11199d0844",
|
"rev": "ec80131710bffcdf3b8498cf41f3a0579833b023",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -440,11 +462,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1791378645,
|
"lastModified": 1792508453,
|
||||||
"narHash": "sha256-9Eix+ZUcI9IUklrtJAD9l/nTcS/Byz7fi94Y3InxS2Y=",
|
"narHash": "sha256-y+V5RFJcjnV1+ZzImkfiSJ97iDIflanjP2OR9lemvTs=",
|
||||||
"owner": "hyprwm",
|
"owner": "hyprwm",
|
||||||
"repo": "hyprland-plugins",
|
"repo": "hyprland-plugins",
|
||||||
"rev": "428bfcd1c9ee34965400bb359349f518140c9920",
|
"rev": "d2427d4d15b36df40468f5a58bbd67cdba19835d",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -672,11 +694,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs-stable": {
|
"nixpkgs-stable": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1791426274,
|
"lastModified": 1792503283,
|
||||||
"narHash": "sha256-MWhktfFtFE8Jl7bf9Pkp7TR5MSdYCjCswSo0Gkb4ywc=",
|
"narHash": "sha256-vhe2jyvRCgufWPqDuDq1S3t3ypE+ka46IFutV02xKso=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "7c8764b7c7b09b34f632464276218ef9090eaa11",
|
"rev": "cd4ea8d57de16f4810bc5f14207bac45fbf19f67",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -688,11 +710,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs_2": {
|
"nixpkgs_2": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1790463110,
|
"lastModified": 1792094642,
|
||||||
"narHash": "sha256-hKlVl12B1dF0Q5vd9dY3lIJM5mFGWYSlXwSLAqHZ1+s=",
|
"narHash": "sha256-zp8ToDMnqZcu4o4IH9pdwXFXGp7yLm/M0dEnNWnyd7I=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "e158d9ed9b51c98974c5e66e1ba1c9e0255fecaa",
|
"rev": "fe13242281a67641c0102cdb1087f0ebe586c7df",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -720,11 +742,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs_4": {
|
"nixpkgs_4": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1791456040,
|
"lastModified": 1792502884,
|
||||||
"narHash": "sha256-H83yz/do+hjOO0uujHyH8RgtIQP2v7Mw+cLwcZK/xKc=",
|
"narHash": "sha256-IoNisKcGbUjdd45qCqywGMCYmZ5EnkxezvLII0FWwNA=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "e7439b6b14ad3cc35d05608ebca9bce01a25f5f8",
|
"rev": "02c087f3fe673c9e317f206a627cb6b910336dbe",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -736,11 +758,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs_5": {
|
"nixpkgs_5": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1790769526,
|
"lastModified": 1791487292,
|
||||||
"narHash": "sha256-5AIVFLRcx8YAwbFTVPTs7YhwJH7JyHfAQsvXmpovcXI=",
|
"narHash": "sha256-tqM7xDEsaeK1p6VvRygeZ9LkQRpUUkbRT02BHv6hnTM=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "c9fe7d12cd78d1adcd12dd15e24432dde5b155a0",
|
"rev": "8edc0c72e3a38faf5434e40d1f19431125fe4b30",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -784,11 +806,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs_8": {
|
"nixpkgs_8": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1791456040,
|
"lastModified": 1792502884,
|
||||||
"narHash": "sha256-H83yz/do+hjOO0uujHyH8RgtIQP2v7Mw+cLwcZK/xKc=",
|
"narHash": "sha256-IoNisKcGbUjdd45qCqywGMCYmZ5EnkxezvLII0FWwNA=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "e7439b6b14ad3cc35d05608ebca9bce01a25f5f8",
|
"rev": "02c087f3fe673c9e317f206a627cb6b910336dbe",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -849,6 +871,7 @@
|
|||||||
"inputs": {
|
"inputs": {
|
||||||
"ags": "ags",
|
"ags": "ags",
|
||||||
"ayugram-desktop": "ayugram-desktop",
|
"ayugram-desktop": "ayugram-desktop",
|
||||||
|
"helix-steel": "helix-steel",
|
||||||
"home-manager": "home-manager",
|
"home-manager": "home-manager",
|
||||||
"hyprland": "hyprland",
|
"hyprland": "hyprland",
|
||||||
"hyprland-plugins": "hyprland-plugins",
|
"hyprland-plugins": "hyprland-plugins",
|
||||||
@@ -866,11 +889,11 @@
|
|||||||
"russia-blocked-geoip": {
|
"russia-blocked-geoip": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1791541118,
|
"lastModified": 1792592746,
|
||||||
"narHash": "sha256-nFzXcNfeaujgzCkwTVxk+FJO5fpnGjN0iFjoO+rSHpI=",
|
"narHash": "sha256-hDb67lqlxWt3iBsRvxWdE7G4Eg+JEyNRQo7OTqzaDRI=",
|
||||||
"owner": "runetfreedom",
|
"owner": "runetfreedom",
|
||||||
"repo": "russia-blocked-geoip",
|
"repo": "russia-blocked-geoip",
|
||||||
"rev": "8a0bb95551940aa0f88e1699687160d19ac1ea51",
|
"rev": "8898c3b0d779b8aa05b933b97022d7458af2df8d",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -881,6 +904,27 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rust-overlay": {
|
"rust-overlay": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"helix-steel",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1775358767,
|
||||||
|
"narHash": "sha256-f2eC+WIfhjevCPQILuV08i/kmKZzYZpUvkom/33VxCA=",
|
||||||
|
"owner": "oxalica",
|
||||||
|
"repo": "rust-overlay",
|
||||||
|
"rev": "20fd44bc663daa53a2575e01293e24e681d62244",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "oxalica",
|
||||||
|
"repo": "rust-overlay",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rust-overlay_2": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
"yazi",
|
"yazi",
|
||||||
@@ -906,11 +950,11 @@
|
|||||||
"nixpkgs": "nixpkgs_5"
|
"nixpkgs": "nixpkgs_5"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1791103873,
|
"lastModified": 1792056300,
|
||||||
"narHash": "sha256-nFxM+pKoZ8LJAEnUXARyCaOAloWgaW9kZQOSjWzKcTE=",
|
"narHash": "sha256-YU1LjDe1o2Ymg5zEiCHbmMXLkDCtxHQRiVqZ3nC5GGk=",
|
||||||
"owner": "Mic92",
|
"owner": "Mic92",
|
||||||
"repo": "sops-nix",
|
"repo": "sops-nix",
|
||||||
"rev": "dcd241ba97088c22569d1573286e1b9daad340c0",
|
"rev": "44931708c62937c2b1bf7953902989fa5bb9ee1b",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -937,11 +981,11 @@
|
|||||||
"tinted-zed": "tinted-zed"
|
"tinted-zed": "tinted-zed"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1790880877,
|
"lastModified": 1791574276,
|
||||||
"narHash": "sha256-j42XqSKOAtuqtfHiElyHre2YS/h3Y3q1DjFnKODN1/k=",
|
"narHash": "sha256-UMnLnZ3JlA7UTBNNNx1rNsXYoPP/cirXLCKGiQ/yDx8=",
|
||||||
"owner": "danth",
|
"owner": "danth",
|
||||||
"repo": "stylix",
|
"repo": "stylix",
|
||||||
"rev": "7c065d1ed05381fceb2403b963c5ad150f32fe39",
|
"rev": "2856c4c6a845b9bec98828ef197abe176e4806bb",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -1004,11 +1048,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1789877109,
|
"lastModified": 1791698670,
|
||||||
"narHash": "sha256-gFYDctvZQdqpKkSYf/QJZwRkQM2YPQ3wHfUxHIP8cDM=",
|
"narHash": "sha256-D4GTULEDsGmk4ue01cetWZ6E/emb3FrUys612rg7a5E=",
|
||||||
"owner": "ndfined-crp",
|
"owner": "ndfined-crp",
|
||||||
"repo": "tg_owt",
|
"repo": "tg_owt",
|
||||||
"rev": "25a781fb72647a14adee9f764761c5c8b773c6b0",
|
"rev": "29330d167ede474885e8aa87b037769cb1cabfc9",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -1126,14 +1170,14 @@
|
|||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-utils": "flake-utils",
|
"flake-utils": "flake-utils",
|
||||||
"nixpkgs": "nixpkgs_7",
|
"nixpkgs": "nixpkgs_7",
|
||||||
"rust-overlay": "rust-overlay"
|
"rust-overlay": "rust-overlay_2"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1791533868,
|
"lastModified": 1792507858,
|
||||||
"narHash": "sha256-KcNMm4C+07B4ukgs23tQYUi8DDGljSdQBZl3+Ibt0Pk=",
|
"narHash": "sha256-EEfOrxveuFcXigE5frf6U5rzw1JdzRZ9IcSZzysnHGA=",
|
||||||
"owner": "sxyazi",
|
"owner": "sxyazi",
|
||||||
"repo": "yazi",
|
"repo": "yazi",
|
||||||
"rev": "1091972581e0d23ed575be967e9a6ef75a17474b",
|
"rev": "7c45837d553b6cb8032bd7fec2106fdb628e4017",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -1145,11 +1189,11 @@
|
|||||||
"yazi-plugins": {
|
"yazi-plugins": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1790956605,
|
"lastModified": 1792088615,
|
||||||
"narHash": "sha256-/BNGoWziHIZ9i+RoTWGq/q3ZowNCyHGBOWiz8v2/vOE=",
|
"narHash": "sha256-3ddGRQSzxyurNcyYJA+9LTLXTCjBFGATTqdkuGKixzA=",
|
||||||
"owner": "yazi-rs",
|
"owner": "yazi-rs",
|
||||||
"repo": "plugins",
|
"repo": "plugins",
|
||||||
"rev": "6229767f7fef39a2a78f5cee9122cc4dfb43f327",
|
"rev": "9166202cc1694c98bac3a639874d6f4c0eaa2dab",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -1164,11 +1208,11 @@
|
|||||||
"zapret-flowseal": "zapret-flowseal"
|
"zapret-flowseal": "zapret-flowseal"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1790422884,
|
"lastModified": 1792489877,
|
||||||
"narHash": "sha256-va22R1zFF7JmibmFwezLYfRup8PfVO3pV7toQH+cbL0=",
|
"narHash": "sha256-4/g+qlw4G+2ACSww4vaRsJVLihREjf0eBwofDmeuTns=",
|
||||||
"owner": "kartavkun",
|
"owner": "kartavkun",
|
||||||
"repo": "zapret-discord-youtube",
|
"repo": "zapret-discord-youtube",
|
||||||
"rev": "b82f45c363506588afbb45fefe41fe4670ae1480",
|
"rev": "69b88b5e51242ddacd87109f31e028e1bef553f6",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -1180,11 +1224,11 @@
|
|||||||
"zapret-flowseal": {
|
"zapret-flowseal": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1790845315,
|
"lastModified": 1792471264,
|
||||||
"narHash": "sha256-zhyCW0LFkWkByHu2Vfgita8Bh3lIexUemGyz9elekUQ=",
|
"narHash": "sha256-5qKg2BvW4XcjY+Az9ocvwACcfsfBpG4I3Xh6SCPksIM=",
|
||||||
"owner": "Flowseal",
|
"owner": "Flowseal",
|
||||||
"repo": "zapret-discord-youtube",
|
"repo": "zapret-discord-youtube",
|
||||||
"rev": "eb16c1419057e36b8a36fbe7c959483450e6ac8b",
|
"rev": "176f56dc3f11ce5915c26abcdde903f93d835b64",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|||||||
@@ -52,6 +52,11 @@
|
|||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
helix-steel = {
|
||||||
|
url = "github:mattwparas/helix/steel-event-system";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
};
|
||||||
|
|
||||||
russia-blocked-geoip = {
|
russia-blocked-geoip = {
|
||||||
url = "github:runetfreedom/russia-blocked-geoip/release";
|
url = "github:runetfreedom/russia-blocked-geoip/release";
|
||||||
flake = false;
|
flake = false;
|
||||||
|
|||||||
@@ -11,6 +11,8 @@
|
|||||||
./modules/grab.nix
|
./modules/grab.nix
|
||||||
./modules/thinkpad.nix
|
./modules/thinkpad.nix
|
||||||
./modules/fingerprint.nix
|
./modules/fingerprint.nix
|
||||||
|
./secrets/secrets.nix
|
||||||
|
./modules/bottles.nix
|
||||||
|
|
||||||
(import ../modules/common.nix {
|
(import ../modules/common.nix {
|
||||||
inherit lib;
|
inherit lib;
|
||||||
@@ -32,7 +34,6 @@
|
|||||||
|
|
||||||
host.laptop = true;
|
host.laptop = true;
|
||||||
|
|
||||||
programs.gamemode.enable = true;
|
|
||||||
hardware.bluetooth.enable = true;
|
hardware.bluetooth.enable = true;
|
||||||
services.printing.enable = true;
|
services.printing.enable = true;
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{pkgs-stable, ...}: {
|
||||||
|
environment.systemPackages = with pkgs-stable; [
|
||||||
|
bottles
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -1,20 +1,315 @@
|
|||||||
{ config, ... }: {
|
{ lib, pkgs, ... }: let
|
||||||
services.fprintd.enable = true;
|
pythonValidityPatch = pkgs.writeText "python-validity-python-3.14.patch" ''
|
||||||
|
diff --git a/validitysensor/flash.py b/validitysensor/flash.py
|
||||||
|
index d37f15a..be3d4a1 100644
|
||||||
|
--- a/validitysensor/flash.py
|
||||||
|
+++ b/validitysensor/flash.py
|
||||||
|
@@ -34,6 +34,10 @@ def get_flash_info():
|
||||||
|
rsp = tls.cmd(unhex('3e'))
|
||||||
|
assert_status(rsp)
|
||||||
|
rsp = rsp[2:]
|
||||||
|
+ if len(rsp) < 0xe:
|
||||||
|
+ # An uninitialised 06cb:009a returns only the success status word.
|
||||||
|
+ # Let init_flash() format it instead of failing in struct.unpack().
|
||||||
|
+ return FlashInfo(None, 0, 0, 0, 0, [])
|
||||||
|
hdr = rsp[:0xe]
|
||||||
|
rsp = rsp[0xe:]
|
||||||
|
jid0, jid1, blocks, unknown0, blocksize, unknown1, pcnt = unpack('<HHHHHHH', hdr)
|
||||||
|
diff --git a/validitysensor/init.py b/validitysensor/init.py
|
||||||
|
index 18890c5..710668c 100644
|
||||||
|
--- a/validitysensor/init.py
|
||||||
|
+++ b/validitysensor/init.py
|
||||||
|
@@ -25,8 +25,8 @@ def close():
|
||||||
|
|
||||||
security.pam.services = {
|
def open_common():
|
||||||
sudo.fprintAuth = true;
|
init_data_dir()
|
||||||
login.fprintAuth = false;
|
- init_flash()
|
||||||
hyprlock.fprintAuth = false;
|
usb.send_init()
|
||||||
};
|
+ init_flash()
|
||||||
|
tls.parse_tls_flash(read_tls_flash())
|
||||||
security.polkit.extraConfig = ''
|
tls.open()
|
||||||
polkit.addRule(function(action, subject) {
|
upload_fwext()
|
||||||
if (action.id == "net.reactivated.fprint.device.enroll" &&
|
diff --git a/validitysensor/usb.py b/validitysensor/usb.py
|
||||||
subject.isInGroup("fprint")) {
|
index 9db2b07..353b2c7 100644
|
||||||
return polkit.Result.YES;
|
--- a/validitysensor/usb.py
|
||||||
}
|
+++ b/validitysensor/usb.py
|
||||||
});
|
@@ -1,6 +1,7 @@
|
||||||
|
import errno
|
||||||
|
import logging
|
||||||
|
+import time
|
||||||
|
import typing
|
||||||
|
from binascii import hexlify, unhexlify
|
||||||
|
from enum import Enum
|
||||||
|
from struct import unpack
|
||||||
|
@@ -68,22 +69,32 @@ class Usb:
|
||||||
|
def close(self):
|
||||||
|
if self.dev is not None:
|
||||||
|
try:
|
||||||
|
self.dev.reset()
|
||||||
|
self.dev = None
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
${" "}
|
||||||
|
def usb_dev(self):
|
||||||
|
return self.dev
|
||||||
|
${" "}
|
||||||
|
+ def cmd_retry_busy(self, command: bytes):
|
||||||
|
+ # Metallica sensors can report 0x0104 for a few seconds after wake-up.
|
||||||
|
+ for _ in range(20):
|
||||||
|
+ rsp = self.cmd(command)
|
||||||
|
+ status, = unpack('<H', rsp[:2])
|
||||||
|
+ if status != 0x0104:
|
||||||
|
+ return rsp
|
||||||
|
+ time.sleep(0.5)
|
||||||
|
+ return rsp
|
||||||
|
+
|
||||||
|
def send_init(self):
|
||||||
|
# self.dev.set_configuration()
|
||||||
|
${" "}
|
||||||
|
# TODO analyse responses, detect hardware type
|
||||||
|
- assert_status(self.cmd(unhexlify('01'))) # RomInfo.get()
|
||||||
|
+ assert_status(self.cmd_retry_busy(unhexlify('01'))) # RomInfo.get()
|
||||||
|
assert_status(self.cmd(unhexlify('19')))
|
||||||
|
${" "}
|
||||||
|
# 43 -- get partition header(?) (02 -- fwext partition)
|
||||||
|
# c28c745a in response is a FwextBuildtime = 0x5A748CC2
|
||||||
|
- rsp = self.cmd(unhexlify('4302')) # get_fw_info()
|
||||||
|
+ rsp = self.cmd_retry_busy(unhexlify('4302')) # get_fw_info()
|
||||||
|
${" "}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
users.users.kirill.extraGroups = [ "fprint" ];
|
python-validity = pkgs.python3Packages.buildPythonApplication rec {
|
||||||
|
pname = "python-validity";
|
||||||
|
version = "0.15-unstable-2020-12-14";
|
||||||
|
pyproject = true;
|
||||||
|
|
||||||
|
src = pkgs.fetchFromGitHub {
|
||||||
|
owner = "uunicorn";
|
||||||
|
repo = "python-validity";
|
||||||
|
rev = "a6bbc21dce7b8b3c3cd92378a0b2579a2fb45920";
|
||||||
|
hash = "sha256-RflX7e6nd11pSg8mh3mjZiVGNUSdox/SKXHR4W+PhMs=";
|
||||||
|
};
|
||||||
|
|
||||||
|
postPatch = ''
|
||||||
|
${lib.getExe pkgs.gitMinimal} apply ${pythonValidityPatch}
|
||||||
|
'';
|
||||||
|
|
||||||
|
build-system = [ pkgs.python3Packages.setuptools ];
|
||||||
|
|
||||||
|
dependencies = with pkgs.python3Packages; [
|
||||||
|
cryptography
|
||||||
|
dbus-python
|
||||||
|
pygobject3
|
||||||
|
pyusb
|
||||||
|
pyyaml
|
||||||
|
];
|
||||||
|
|
||||||
|
nativeBuildInputs = [ pkgs.makeWrapper ];
|
||||||
|
|
||||||
|
postInstall = ''
|
||||||
|
install -Dm755 dbus_service/dbus-service \
|
||||||
|
"$out/lib/python-validity/dbus-service"
|
||||||
|
install -Dm644 dbus_service/io.github.uunicorn.Fprint.conf \
|
||||||
|
"$out/share/dbus-1/system.d/io.github.uunicorn.Fprint.conf"
|
||||||
|
|
||||||
|
install -Dm755 dbus_service/dbus-service \
|
||||||
|
"$out/bin/python-validity-service"
|
||||||
|
install -Dm755 scripts/factory-reset.py \
|
||||||
|
"$out/bin/validity-factory-reset"
|
||||||
|
|
||||||
|
install -d "$out/share/python-validity/playground"
|
||||||
|
install -m755 \
|
||||||
|
scripts/dbus-cmd.py \
|
||||||
|
scripts/lsdbus.py \
|
||||||
|
scripts/factory-reset.py \
|
||||||
|
scripts/prototype.py \
|
||||||
|
"$out/share/python-validity/playground/"
|
||||||
|
'';
|
||||||
|
|
||||||
|
postFixup = ''
|
||||||
|
wrapProgram "$out/bin/validity-sensors-firmware" \
|
||||||
|
--prefix PATH : ${lib.makeBinPath [
|
||||||
|
pkgs.findutils
|
||||||
|
pkgs.innoextract
|
||||||
|
]}
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Upstream does not have an automated test suite.
|
||||||
|
doCheck = false;
|
||||||
|
|
||||||
|
meta = {
|
||||||
|
description = "Userspace driver for Validity and Synaptics fingerprint sensors";
|
||||||
|
homepage = "https://github.com/uunicorn/python-validity";
|
||||||
|
license = lib.licenses.mit;
|
||||||
|
platforms = lib.platforms.linux;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
fprintd-clients = pkgs.runCommand "fprintd-clients" { } ''
|
||||||
|
mkdir -p "$out/bin"
|
||||||
|
for client in fprintd-delete fprintd-enroll fprintd-list fprintd-verify; do
|
||||||
|
ln -s "${pkgs.fprintd}/bin/$client" "$out/bin/$client"
|
||||||
|
done
|
||||||
|
'';
|
||||||
|
|
||||||
|
systemctl = lib.getExe' pkgs.systemd "systemctl";
|
||||||
|
busctl = lib.getExe' pkgs.systemd "busctl";
|
||||||
|
timeout = lib.getExe' pkgs.coreutils "timeout";
|
||||||
|
sleep = lib.getExe' pkgs.coreutils "sleep";
|
||||||
|
fprintdList = lib.getExe' pkgs.fprintd "fprintd-list";
|
||||||
|
|
||||||
|
# python-validity initializes the sensor before it registers with
|
||||||
|
# open-fprintd, so a successful ListEnrolledFingers call means the sensor is
|
||||||
|
# usable. This is used as ExecStartPost and by greetd ordering.
|
||||||
|
waitForFprint = pkgs.writeShellScript "wait-for-fprint" ''
|
||||||
|
for ((i = 0; i < 120; i++)); do
|
||||||
|
|
||||||
|
devices="$(${timeout} 1 ${busctl} --system call \
|
||||||
|
net.reactivated.Fprint \
|
||||||
|
/net/reactivated/Fprint/Manager \
|
||||||
|
net.reactivated.Fprint.Manager GetDevices 2>/dev/null || true)"
|
||||||
|
|
||||||
|
if [[ "$devices" =~ ^ao\ [1-9] ]]; then
|
||||||
|
echo "wait-for-fprint: sensor initialized: $devices"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
${sleep} 0.5
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "wait-for-fprint: sensor initialization timeout" >&2
|
||||||
|
exit 1
|
||||||
|
'';
|
||||||
|
|
||||||
|
# The xHCI controller is reset during resume, which invalidates
|
||||||
|
# python-validity's USB handle. Restart it from a systemd-sleep hook: the
|
||||||
|
# hook runs before logind emits PrepareForSleep(false), so hyprlock's
|
||||||
|
# built-in fingerprint auth sees a working sensor as soon as it resumes.
|
||||||
|
fprintResumeHook = pkgs.writeShellScript "fprint-resume" ''
|
||||||
|
if [ "$1" != "post" ]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Stop the old instance first so its stale D-Bus target cannot be selected
|
||||||
|
# by the readiness checks below. Start without blocking because
|
||||||
|
# python-validity's ExecStartPost waits for fprintd, but open-fprintd is
|
||||||
|
# still suspended until Resume is called below.
|
||||||
|
${timeout} 10 ${systemctl} stop python3-validity.service || true
|
||||||
|
${systemctl} start --no-block python3-validity.service || true
|
||||||
|
|
||||||
|
# Clear open-fprintd's suspended flag. This also unblocks the new
|
||||||
|
# python-validity instance's ExecStartPost.
|
||||||
|
${timeout} 10 ${busctl} call net.reactivated.Fprint /net/reactivated/Fprint/Manager \
|
||||||
|
net.reactivated.Fprint.Manager Resume || true
|
||||||
|
|
||||||
|
# Wait for the new backend to register.
|
||||||
|
for ((i = 0; i < 30; i++)); do
|
||||||
|
if ${timeout} 0.5 ${fprintdList} root >/dev/null 2>&1; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
${sleep} 0.1
|
||||||
|
done
|
||||||
|
|
||||||
|
# The target now exists, so Resume reinitializes the sensor. Wait for it
|
||||||
|
# to become responsive before logind starts hyprlock's fingerprint auth.
|
||||||
|
${timeout} 10 ${busctl} call net.reactivated.Fprint /net/reactivated/Fprint/Manager \
|
||||||
|
net.reactivated.Fprint.Manager Resume || true
|
||||||
|
|
||||||
|
for ((i = 0; i < 30; i++)); do
|
||||||
|
if ${timeout} 0.5 ${fprintdList} root >/dev/null 2>&1; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
${sleep} 0.1
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "fprint-resume: fingerprint backend did not become ready" >&2
|
||||||
|
'';
|
||||||
|
|
||||||
|
sleepTargets = [
|
||||||
|
"suspend.target"
|
||||||
|
"hibernate.target"
|
||||||
|
"hybrid-sleep.target"
|
||||||
|
"suspend-then-hibernate.target"
|
||||||
|
];
|
||||||
|
in {
|
||||||
|
services = {
|
||||||
|
# The 06cb:009a sensor is driven by python-validity through open-fprintd;
|
||||||
|
# stock fprintd/libfprint cannot handle it.
|
||||||
|
fprintd.enable = false;
|
||||||
|
|
||||||
|
dbus.packages = [
|
||||||
|
pkgs.open-fprintd
|
||||||
|
python-validity
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
security.pam.services = {
|
||||||
|
greetd.fprintAuth = true;
|
||||||
|
polkit-1.fprintAuth = true;
|
||||||
|
sudo.fprintAuth = true;
|
||||||
|
login.fprintAuth = true;
|
||||||
|
|
||||||
|
# hyprlock still needs a PAM service for password authentication, but it
|
||||||
|
# must not run pam_fprintd: its own D-Bus fingerprint implementation is
|
||||||
|
# used instead. Two implementations would fight over the device, and the
|
||||||
|
# PAM one breaks when the sensor is reset across suspend.
|
||||||
|
hyprlock = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
environment.etc."systemd/system-sleep/50-fprint-resume".source = fprintResumeHook;
|
||||||
|
|
||||||
|
systemd.services = {
|
||||||
|
open-fprintd = {
|
||||||
|
description = "Open FPrint daemon";
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "dbus";
|
||||||
|
BusName = "net.reactivated.Fprint";
|
||||||
|
ExecStart = "${pkgs.open-fprintd}/lib/open-fprintd/open-fprintd";
|
||||||
|
Restart = "on-failure";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
python3-validity = {
|
||||||
|
description = "python-validity fingerprint sensor backend";
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
after = [ "open-fprintd.service" ];
|
||||||
|
wants = [ "open-fprintd.service" ];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "simple";
|
||||||
|
ExecStart = "${python-validity}/bin/python-validity-service";
|
||||||
|
ExecStartPost = "-${waitForFprint}";
|
||||||
|
Restart = "always";
|
||||||
|
RestartSec = 2;
|
||||||
|
RuntimeDirectory = "python-validity";
|
||||||
|
RuntimeDirectoryMode = "0700";
|
||||||
|
RuntimeDirectoryPreserve = "yes";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
open-fprintd-suspend = {
|
||||||
|
description = "Suspend open-fprintd backends";
|
||||||
|
wantedBy = sleepTargets;
|
||||||
|
before = sleepTargets;
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
ExecStart = "${pkgs.open-fprintd}/lib/open-fprintd/suspend.py";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# The sleep hook above resumes open-fprintd before logind wakes the
|
||||||
|
# graphical session. The stock open-fprintd-resume unit runs later and
|
||||||
|
# resets the sensor while hyprlock is already verifying, so it must not be
|
||||||
|
# enabled. Order greetd (and therefore Hyprland/hyprlock) after the
|
||||||
|
# fingerprint backend so the first lock screen can use the sensor.
|
||||||
|
systemd.services.greetd = {
|
||||||
|
after = [ "python3-validity.service" ];
|
||||||
|
wants = [ "python3-validity.service" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
environment.systemPackages = [
|
||||||
|
fprintd-clients
|
||||||
|
python-validity
|
||||||
|
];
|
||||||
}
|
}
|
||||||
@@ -13,7 +13,6 @@
|
|||||||
services = {
|
services = {
|
||||||
fwupd.enable = true;
|
fwupd.enable = true;
|
||||||
thermald.enable = true;
|
thermald.enable = true;
|
||||||
fprintd.enable = true;
|
|
||||||
|
|
||||||
logind.settings.Login = {
|
logind.settings.Login = {
|
||||||
HandleLidSwitch = "suspend-then-hibernate";
|
HandleLidSwitch = "suspend-then-hibernate";
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
sops = {
|
||||||
|
age.keyFile = "/root/age.key";
|
||||||
|
|
||||||
|
secrets = { };
|
||||||
|
};
|
||||||
|
}
|
||||||
+3
-2
@@ -5,14 +5,15 @@
|
|||||||
./user/sleepMode.nix
|
./user/sleepMode.nix
|
||||||
./user/ghostty.nix
|
./user/ghostty.nix
|
||||||
./user/qt.nix
|
./user/qt.nix
|
||||||
./user/zed-idea.nix
|
./user/helix.nix
|
||||||
|
#./user/zed-idea.nix
|
||||||
./user/walker.nix
|
./user/walker.nix
|
||||||
./user/btop.nix
|
./user/btop.nix
|
||||||
./user/zsh.nix
|
./user/zsh.nix
|
||||||
./user/packages/utils.nix
|
./user/packages/utils.nix
|
||||||
./user/packages/desktop.nix
|
./user/packages/desktop.nix
|
||||||
./user/packages/kdenlive.nix
|
|
||||||
./user/quickshell.nix
|
./user/quickshell.nix
|
||||||
./user/wob.nix
|
./user/wob.nix
|
||||||
|
./user/secrets.nix
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,192 @@
|
|||||||
|
{ inputs, pkgs, lib, config, ... }: let
|
||||||
|
# glibc >= 2.44 defines bsearch() as a C23 const-generic macro, which clashes
|
||||||
|
# with the copy vendored by some tree-sitter grammars (tree-sitter-perl).
|
||||||
|
# Drop the vendored implementation, same as nixpkgs does for upstream helix.
|
||||||
|
patchedStdenv = pkgs.stdenv // {
|
||||||
|
mkDerivation = args: pkgs.stdenv.mkDerivation (args // {
|
||||||
|
postPatch = (args.postPatch or "") + ''
|
||||||
|
if [ -e src/bsearch.c ]; then
|
||||||
|
rm src/bsearch.c
|
||||||
|
substituteInPlace src/tsp_unicode.h \
|
||||||
|
--replace-fail '#include "bsearch.c"' ""
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
helixGrammars = pkgs.callPackage "${inputs.helix-steel}/grammars.nix" {
|
||||||
|
stdenv = patchedStdenv;
|
||||||
|
};
|
||||||
|
|
||||||
|
helixSteel =
|
||||||
|
(
|
||||||
|
pkgs.callPackage "${inputs.helix-steel}/default.nix" {
|
||||||
|
gitRev = inputs.helix-steel.rev;
|
||||||
|
|
||||||
|
# The upstream flake builds the grammars with its own callPackage,
|
||||||
|
# swap in the patched ones.
|
||||||
|
callPackage = path: args:
|
||||||
|
if toString path == toString "${inputs.helix-steel}/grammars.nix" then helixGrammars
|
||||||
|
else pkgs.callPackage path args;
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.overrideAttrs (old: {
|
||||||
|
cargoBuildFlags = (old.cargoBuildFlags or []) ++ [
|
||||||
|
"--features"
|
||||||
|
"steel,git"
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
comment-headers = pkgs.fetchurl {
|
||||||
|
url = "https://github.com/codingvivi/comment-dividers.hx/raw/refs/heads/main/comment_headers.scm";
|
||||||
|
name = "comment_headers.scm";
|
||||||
|
hash = "sha256-ohgn6DFJl0rdRJuri6Frs/uUlUsPxMvPHDuw4FS3qEE=";
|
||||||
|
};
|
||||||
|
|
||||||
|
patched-comment-headers = pkgs.runCommand "comment_headers.scm" { } ''
|
||||||
|
install -m 0644 ${comment-headers} "$out"
|
||||||
|
|
||||||
|
${pkgs.python3}/bin/python3 - <<'PY'
|
||||||
|
from pathlib import Path
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
p = Path(os.environ["out"])
|
||||||
|
s = p.read_text()
|
||||||
|
|
||||||
|
start_marker = "(define (get-block-delims)"
|
||||||
|
end_marker = "(define (delete_till_first_nonwhitespace!)"
|
||||||
|
|
||||||
|
try:
|
||||||
|
start = s.index(start_marker)
|
||||||
|
end = s.index(end_marker, start)
|
||||||
|
except ValueError as e:
|
||||||
|
sys.exit(f"failed to find function markers: {e}")
|
||||||
|
|
||||||
|
new_get_block_delims = """(define (get-block-delims)
|
||||||
|
(helix.static.open_above)
|
||||||
|
(helix.static.insert_string "test_string")
|
||||||
|
(helix.static.normal_mode)
|
||||||
|
(helix.static.extend_to_line_bounds)
|
||||||
|
(helix.static.trim_selections)
|
||||||
|
(helix.static.toggle_comments)
|
||||||
|
(let* ([commented-test-string (helix.static.current-highlighted-text!)]
|
||||||
|
[strings-without-whitespace (split-whitespace commented-test-string)])
|
||||||
|
(delete-line-noyank!)
|
||||||
|
(cond
|
||||||
|
[(and (> (length strings-without-whitespace) 1)
|
||||||
|
(equal? (last strings-without-whitespace) "test_string"))
|
||||||
|
(list (first strings-without-whitespace) "")]
|
||||||
|
[(> (length strings-without-whitespace) 2)
|
||||||
|
(list (first strings-without-whitespace) (last strings-without-whitespace))]
|
||||||
|
[else
|
||||||
|
(list "" "")])))
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
s = s[:start] + new_get_block_delims + s[end:]
|
||||||
|
|
||||||
|
old = "(make-line line-length fill-pattern #f padding-pattern)"
|
||||||
|
new = "(make-line line-length \"\" fill-pattern padding-pattern)"
|
||||||
|
|
||||||
|
if old not in s:
|
||||||
|
sys.exit("failed to find insert-divider make-line call")
|
||||||
|
|
||||||
|
s = s.replace(old, new)
|
||||||
|
|
||||||
|
p.write_text(s)
|
||||||
|
PY
|
||||||
|
'';
|
||||||
|
in {
|
||||||
|
home.packages = with pkgs; [
|
||||||
|
steel
|
||||||
|
wakatime-cli
|
||||||
|
];
|
||||||
|
|
||||||
|
# Wakapi is WakaTime-compatible, so the same plugin/client works.
|
||||||
|
sops.templates.".wakatime.cfg" = {
|
||||||
|
path = "${config.home.homeDirectory}/.wakatime.cfg";
|
||||||
|
mode = "0600";
|
||||||
|
content = ''
|
||||||
|
[settings]
|
||||||
|
api_url = https://coding.srcoder.moe/api
|
||||||
|
api_key = ${config.sops.placeholder."tokens/apis/wakapi"}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
home.activation.installWakatimeHx = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
|
||||||
|
export PATH="${pkgs.steel}/bin:$PATH"
|
||||||
|
export STEEL_HOME="${config.xdg.dataHome}/steel"
|
||||||
|
|
||||||
|
if [ ! -f "$STEEL_HOME/cogs/wakatime/wakatime.scm" ]; then
|
||||||
|
forge pkg install --git https://github.com/Xerxes-2/wakatime.hx.git
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
|
||||||
|
programs.helix = {
|
||||||
|
enable = true;
|
||||||
|
package = helixSteel;
|
||||||
|
defaultEditor = true;
|
||||||
|
|
||||||
|
settings = {
|
||||||
|
# theme = "catppuccin-mocha";
|
||||||
|
editor = {
|
||||||
|
insert-final-newline = false;
|
||||||
|
indent-guides.render = true;
|
||||||
|
|
||||||
|
whitespace.render = {
|
||||||
|
space = "all";
|
||||||
|
tab = "all";
|
||||||
|
nbsp = "none";
|
||||||
|
nnbsp = "none";
|
||||||
|
newline = "none";
|
||||||
|
};
|
||||||
|
|
||||||
|
cursor-shape = {
|
||||||
|
normal = "block";
|
||||||
|
insert = "bar";
|
||||||
|
select = "underline";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
keys.normal = {
|
||||||
|
space = {
|
||||||
|
C-c = {
|
||||||
|
h = ":comment-h1";
|
||||||
|
j = ":comment-h2";
|
||||||
|
k = ":comment-h3";
|
||||||
|
d = ":comment-divider";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
S-down = ["extend_to_line_bounds" "delete_selection" "paste_after"];
|
||||||
|
S-up = ["extend_to_line_bounds" "delete_selection" "move_line_up" "paste_before"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
xdg.configFile = {
|
||||||
|
"helix/cogs/comment_headers.scm".source = patched-comment-headers;
|
||||||
|
"helix/helix.scm".text = ''
|
||||||
|
(require (prefix-in div. "cogs/comment_headers.scm"))
|
||||||
|
|
||||||
|
(provide comment-h1 comment-h2 comment-h3 comment-divider)
|
||||||
|
|
||||||
|
(define (comment-h1)
|
||||||
|
(div.insert-h1!))
|
||||||
|
|
||||||
|
(define (comment-h2)
|
||||||
|
(div.insert-h2!))
|
||||||
|
|
||||||
|
(define (comment-h3)
|
||||||
|
(div.insert-h3!))
|
||||||
|
|
||||||
|
(define (comment-divider)
|
||||||
|
(div.insert-divider! 80 "~"))
|
||||||
|
'';
|
||||||
|
"helix/init.scm".text = ''
|
||||||
|
;; Steel init file
|
||||||
|
(require "wakatime/wakatime.scm")
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{ pkgs, ... }: {
|
|
||||||
home.packages = with pkgs; [
|
|
||||||
heroic
|
|
||||||
];
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{ pkgs, ... }: {
|
|
||||||
home.packages = with pkgs; [
|
|
||||||
kdePackages.kdenlive
|
|
||||||
];
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{ config, ... }: {
|
||||||
|
sops = {
|
||||||
|
defaultSopsFile = ../../user/${config.home.username}/secrets.yaml;
|
||||||
|
age.keyFile = "${config.home.homeDirectory}/.config/sops/age/keys.txt";
|
||||||
|
|
||||||
|
secrets."tokens/apis/wallhaven" = {};
|
||||||
|
secrets."tokens/apis/wakapi" = {};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,8 +1,50 @@
|
|||||||
{ pkgs, lib, ... }:
|
{ config, pkgs, lib, ... }:
|
||||||
let
|
let
|
||||||
hyprLua = import ./hyprland/lua.nix { inherit lib; };
|
hyprLua = import ./hyprland/lua.nix { inherit lib; };
|
||||||
|
|
||||||
|
hyprlock = lib.getExe pkgs.hyprlock;
|
||||||
|
hyprctl = lib.getExe' config.wayland.windowManager.hyprland.package "hyprctl";
|
||||||
|
loginctl = lib.getExe' pkgs.systemd "loginctl";
|
||||||
|
pidof = lib.getExe' pkgs.procps "pidof";
|
||||||
|
fprintdList = lib.getExe' pkgs.fprintd "fprintd-list";
|
||||||
|
timeout = lib.getExe' pkgs.coreutils "timeout";
|
||||||
|
sleepCmd = lib.getExe' pkgs.coreutils "sleep";
|
||||||
|
sh = lib.getExe pkgs.bash;
|
||||||
|
|
||||||
|
hyprlockWait = pkgs.writeShellScript "hyprlock-wait-fprint" ''
|
||||||
|
for i in $(seq 1 60); do
|
||||||
|
if ${timeout} 1 ${fprintdList} kirill >/dev/null 2>&1; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
${sleepCmd} 1
|
||||||
|
done
|
||||||
|
exec ${hyprlock}
|
||||||
|
'';
|
||||||
in {
|
in {
|
||||||
wayland.windowManager.hyprland.settings.on = [ (hyprLua.onStart [ "hyprlock" ]) ];
|
wayland.windowManager.hyprland.settings.on = [ (hyprLua.onStart [ "${hyprlockWait}" ]) ];
|
||||||
|
|
||||||
|
# Hypridle listens to logind's PrepareForSleep signal: it locks the session
|
||||||
|
# before suspend and makes sure hyprlock is running (and the display is on)
|
||||||
|
# after resume.
|
||||||
|
services.hypridle = {
|
||||||
|
enable = true;
|
||||||
|
settings = {
|
||||||
|
general = {
|
||||||
|
lock_cmd = "${pidof} hyprlock >/dev/null || ${hyprlockWait}";
|
||||||
|
before_sleep_cmd = "${loginctl} lock-session";
|
||||||
|
after_sleep_cmd = "${pidof} hyprlock >/dev/null || ${hyprlockWait} & ${hyprctl} dispatch 'hl.dsp.dpms({action = \"on\"})'";
|
||||||
|
};
|
||||||
|
|
||||||
|
# Hypridle requires at least one listener, so keep a no-op timer that
|
||||||
|
# practically never fires. Screen locking is driven by sleep/resume only.
|
||||||
|
listener = [
|
||||||
|
{
|
||||||
|
timeout = 604800; # 7 days
|
||||||
|
on-timeout = "";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
programs.hyprlock = let
|
programs.hyprlock = let
|
||||||
image = pkgs.fetchurl {
|
image = pkgs.fetchurl {
|
||||||
@@ -14,6 +56,17 @@ in {
|
|||||||
enable = true;
|
enable = true;
|
||||||
|
|
||||||
settings = {
|
settings = {
|
||||||
|
# Hyprlock's built-in fingerprint support watches logind's
|
||||||
|
# PrepareForSleep signal and re-arms itself after resume. PAM-based
|
||||||
|
# fingerprint auth (security.pam.services.hyprlock.fprintAuth) does not
|
||||||
|
# survive the fingerprint device being reset during suspend.
|
||||||
|
auth.fingerprint = {
|
||||||
|
enabled = true;
|
||||||
|
ready_message = "Scan fingerprint to unlock";
|
||||||
|
present_message = "Scanning...";
|
||||||
|
retry_delay = 250;
|
||||||
|
};
|
||||||
|
|
||||||
background = {
|
background = {
|
||||||
path = lib.mkForce "${image}";
|
path = lib.mkForce "${image}";
|
||||||
blur_passes = 0;
|
blur_passes = 0;
|
||||||
|
|||||||
@@ -91,6 +91,8 @@
|
|||||||
swichWalls = "wallpaper_changer";
|
swichWalls = "wallpaper_changer";
|
||||||
shell = "nix-shell . --run zsh";
|
shell = "nix-shell . --run zsh";
|
||||||
testZapret = "sudo zapret-test-strategies";
|
testZapret = "sudo zapret-test-strategies";
|
||||||
|
|
||||||
|
charge = "sudo tlp setcharge 90 95 BAT0 && sudo tlp setcharge 90 95 BAT1 && echo 'Зарядка обеих батарей до 95% запущена (только на текущую сессию)'";
|
||||||
};
|
};
|
||||||
|
|
||||||
initContent = ''
|
initContent = ''
|
||||||
|
|||||||
@@ -0,0 +1,279 @@
|
|||||||
|
# Секреты (sops-nix)
|
||||||
|
|
||||||
|
Кратко: как всё устроено, как добавить новый секрет и как поднять рабочий sops на новом устройстве.
|
||||||
|
|
||||||
|
## Как устроено
|
||||||
|
|
||||||
|
- `.sops.yaml` в корне репозитория — список age-реципиентов и правила выбора ключа по пути файла.
|
||||||
|
- Секреты делятся на два уровня:
|
||||||
|
- **host** (системные, читает root): зашифрованные файлы в `host/<Host>/secrets/<файл>`, метаданные в `host/<Host>/secrets/secrets.nix`, подключается из `host/<Host>/configuration.nix` через `imports`. При активации расшифровываются в `/run/secrets/<имя>`.
|
||||||
|
- **user** (пользовательские, читает home-manager): один файл `user/<username>/secrets.yaml`, метаданные в `modules/user/secrets.nix`, подключается из `modules/user.nix` через `imports`. При активации расшифровываются в `~/.config/sops-nix/secrets/<имя>`.
|
||||||
|
- Расшифровка идёт в runtime, в `/nix/store` секреты не попадают.
|
||||||
|
- age-ключи выводятся из существующих SSH-ключей:
|
||||||
|
- host — `/root/age.key` (читает root при активации),
|
||||||
|
- user — `~/.config/sops/age/keys.txt` (читает пользователь при активации home-manager).
|
||||||
|
|
||||||
|
Текущие правила в `.sops.yaml`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
keys:
|
||||||
|
- &key age1tx6jdr6535xxeygpwkkgvdwc24tulr420cm7gk56xzfp0slzeqks2nwpyg
|
||||||
|
|
||||||
|
creation_rules:
|
||||||
|
- path_regex: host/[^/]+/secrets/.+$
|
||||||
|
key_groups:
|
||||||
|
- age:
|
||||||
|
- *key
|
||||||
|
- path_regex: user/[^/]+/secrets\.yaml$
|
||||||
|
key_groups:
|
||||||
|
- age:
|
||||||
|
- *key
|
||||||
|
```
|
||||||
|
|
||||||
|
Правило выбирается по пути файла. Важно: `path_regex` проверяется против пути **входного** файла относительно корня репозитория, поэтому открытое значение нужно создавать по целевому пути (см. примеры ниже).
|
||||||
|
|
||||||
|
## Host-секрет (системный)
|
||||||
|
|
||||||
|
### Добавить новый
|
||||||
|
|
||||||
|
1. Придумай имя, дальше для примера — `mysecret`.
|
||||||
|
|
||||||
|
2. Положи открытое значение во временный файл **внутри** `host/<Host>/secrets/` (путь важен — см. `path_regex`):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
printf '%s' 'СЕКРЕТНОЕ_ЗНАЧЕНИЕ' > host/ThinkPad/secrets/mysecret.plain
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Зашифруй (приватный ключ не нужен — sops берёт публичного реципиента из `.sops.yaml`). Флаги указываются **до** позиционных аргументов:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nix-shell -p sops --run \
|
||||||
|
"sops --input-type binary --output-type binary \
|
||||||
|
--encrypt --output host/ThinkPad/secrets/mysecret.enc \
|
||||||
|
host/ThinkPad/secrets/mysecret.plain"
|
||||||
|
rm host/ThinkPad/secrets/mysecret.plain
|
||||||
|
```
|
||||||
|
|
||||||
|
`--input-type`/`--output-type` обязательны для бинарных данных, иначе sops пытается определить тип по расширению.
|
||||||
|
|
||||||
|
4. Опиши секрет в `host/<Host>/secrets/secrets.nix`:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
sops = {
|
||||||
|
age.keyFile = "/root/age.key";
|
||||||
|
|
||||||
|
secrets = {
|
||||||
|
mysecret = {
|
||||||
|
format = "binary"; # yaml | json | binary | dotenv | ini
|
||||||
|
sopsFile = ./mysecret.enc;
|
||||||
|
owner = "kirill"; # владелец расшифрованного файла
|
||||||
|
mode = "0400";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`format = "binary"` — для произвольных байтов (`.pem`, токены). Для структурированных данных используй `yaml`/`json`.
|
||||||
|
`owner`/`mode` нужны, если секрет читает пользовательский процесс (а не root-сервис).
|
||||||
|
|
||||||
|
5. `git add` — **Nix видит только файлы, добавленные в git** — и ребилд:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add host/ThinkPad/secrets/
|
||||||
|
sudo nixos-rebuild switch --flake .#ThinkPad
|
||||||
|
```
|
||||||
|
|
||||||
|
6. Проверка:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo ls -l /run/secrets/mysecret
|
||||||
|
```
|
||||||
|
|
||||||
|
### Изменить или посмотреть существующий секрет
|
||||||
|
|
||||||
|
Используется приватный ключ (`/root/age.key`), поэтому нужен root:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo SOPS_AGE_KEY_FILE=/root/age.key nix-shell -p sops --run \
|
||||||
|
"sops --input-type binary --output-type binary host/ThinkPad/secrets/mysecret.enc"
|
||||||
|
```
|
||||||
|
|
||||||
|
`sops` сам не ищет `/root/age.key`, путь передаётся через `SOPS_AGE_KEY_FILE`.
|
||||||
|
Для бинарных файлов нужны `--input-type`/`--output-type`, иначе sops не сможет определить формат.
|
||||||
|
|
||||||
|
## User-секрет (home-manager)
|
||||||
|
|
||||||
|
Все пользовательские секреты лежат в одном файле `user/<username>/secrets.yaml`. Значения — вложенные ключи YAML, а имя секрета в nix-коде совпадает с путём этого ключа (`/` = вложенность). Например, секрет `tokens/apis/wallhaven` читается из:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
tokens:
|
||||||
|
apis:
|
||||||
|
wallhaven: ЗНАЧЕНИЕ
|
||||||
|
```
|
||||||
|
|
||||||
|
Путь расшифрованного файла: `~/.config/sops-nix/secrets/tokens/apis/wallhaven`.
|
||||||
|
|
||||||
|
### Добавить новый
|
||||||
|
|
||||||
|
1. Придумай имя, дальше для примера — `tokens/apis/wallhaven`.
|
||||||
|
|
||||||
|
2. Добавь значение в общий файл секретов (sops откроет расшифрованное содержимое в `$EDITOR` и зашифрует при сохранении; путь совпадает с `path_regex`, поэтому правило применится автоматически):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nix-shell -p sops --run "sops user/kirill/secrets.yaml"
|
||||||
|
```
|
||||||
|
|
||||||
|
Если файла ещё нет, создай его сразу по целевому пути и зашифруй на месте:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
printf 'tokens:\n apis:\n wallhaven: ЗНАЧЕНИЕ\n' > user/kirill/secrets.yaml
|
||||||
|
nix-shell -p sops --run "sops --encrypt --in-place user/kirill/secrets.yaml"
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Опиши секрет в `modules/user/secrets.nix`:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{ config, ... }: {
|
||||||
|
sops = {
|
||||||
|
defaultSopsFile = ../../user/${config.home.username}/secrets.yaml;
|
||||||
|
age.keyFile = "${config.home.homeDirectory}/.config/sops/age/keys.txt";
|
||||||
|
|
||||||
|
secrets."tokens/apis/wallhaven" = {};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Используй в home-manager конфиге через путь:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
config.sops.secrets."tokens/apis/wallhaven".path
|
||||||
|
```
|
||||||
|
|
||||||
|
5. `git add` — **Nix видит только файлы, добавленные в git** — и ребилд:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add user/kirill/secrets.yaml modules/user/secrets.nix modules/user.nix
|
||||||
|
sudo nixos-rebuild switch --flake .#ThinkPad
|
||||||
|
```
|
||||||
|
|
||||||
|
6. Проверка:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ls -l ~/.config/sops-nix/secrets/tokens/apis/wallhaven
|
||||||
|
```
|
||||||
|
|
||||||
|
### Изменить или посмотреть существующий секрет
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nix-shell -p sops --run "sops user/kirill/secrets.yaml"
|
||||||
|
```
|
||||||
|
|
||||||
|
sops подхватывает `~/.config/sops/age/keys.txt` автоматически. Если путь другой — задай `SOPS_AGE_KEY_FILE`.
|
||||||
|
|
||||||
|
## Новое устройство
|
||||||
|
|
||||||
|
1. Убедись, что на устройстве есть приватный SSH-ключ, из которого выводится age-ключ. Ключ должен быть **без пароля** — иначе расшифровка при активации будет требовать ввода. На текущей машине это `~/.ssh/id_ed25519_sops`.
|
||||||
|
|
||||||
|
2. Создай age-ключ хоста (root читает его при активации):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo nix-shell -p ssh-to-age --run \
|
||||||
|
"ssh-to-age -private-key -i /home/kirill/.ssh/id_ed25519_sops -o /root/age.key"
|
||||||
|
sudo chmod 600 /root/age.key
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Создай age-ключ пользователя (home-manager читает его при активации):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir -p ~/.config/sops/age
|
||||||
|
nix-shell -p ssh-to-age --run \
|
||||||
|
"ssh-to-age -private-key -i ~/.ssh/id_ed25519_sops -o ~/.config/sops/age/keys.txt"
|
||||||
|
chmod 700 ~/.config/sops/age
|
||||||
|
chmod 600 ~/.config/sops/age/keys.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Проверь, что публичный age-реципиент устройства совпадает с тем, что в `.sops.yaml`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nix-shell -p ssh-to-age --run \
|
||||||
|
"ssh-to-age -i ~/.ssh/id_ed25519_sops.pub"
|
||||||
|
```
|
||||||
|
|
||||||
|
Должно вывести:
|
||||||
|
|
||||||
|
```
|
||||||
|
age1tx6jdr6535xxeygpwkkgvdwc24tulr420cm7gk56xzfp0slzeqks2nwpyg
|
||||||
|
```
|
||||||
|
|
||||||
|
Если вывод другой — добавь новый реципиент (см. следующий раздел).
|
||||||
|
|
||||||
|
5. Создай структуру секретов хоста:
|
||||||
|
|
||||||
|
```
|
||||||
|
host/<Host>/secrets/secrets.nix
|
||||||
|
host/<Host>/secrets/<файлы секретов>
|
||||||
|
```
|
||||||
|
|
||||||
|
Минимальный `secrets.nix`:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
sops = {
|
||||||
|
age.keyFile = "/root/age.key";
|
||||||
|
secrets = { };
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
И добавь `./secrets/secrets.nix` в `imports` в `host/<Host>/configuration.nix`.
|
||||||
|
|
||||||
|
6. Для пользовательских секретов создай `user/<username>/secrets.yaml` (см. раздел «User-секрет») и убедись, что `modules/user.nix` подключает `./user/secrets.nix`.
|
||||||
|
|
||||||
|
7. `git add` + ребилд:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add host/<Host>/secrets/ user/<username>/secrets.yaml modules/user/secrets.nix
|
||||||
|
sudo nixos-rebuild switch --flake .#<Host>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Добавить устройство к существующим секретам
|
||||||
|
|
||||||
|
1. Получи age-реципиент устройства (шаг 4 выше).
|
||||||
|
|
||||||
|
2. Добавь его в `.sops.yaml` в оба правила:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
keys:
|
||||||
|
- &key age1tx6jdr6535xxeygpwkkgvdwc24tulr420cm7gk56xzfp0slzeqks2nwpyg
|
||||||
|
- &newdevice age1...новый_реципиент... # замени на реальный
|
||||||
|
|
||||||
|
creation_rules:
|
||||||
|
- path_regex: host/[^/]+/secrets/.+$
|
||||||
|
key_groups:
|
||||||
|
- age:
|
||||||
|
- *key
|
||||||
|
- *newdevice
|
||||||
|
- path_regex: user/[^/]+/secrets\.yaml$
|
||||||
|
key_groups:
|
||||||
|
- age:
|
||||||
|
- *key
|
||||||
|
- *newdevice
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Перешифруй существующие секреты под новый список реципиентов (нужен приватный ключ). Для host-секретов — root и `/root/age.key`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo SOPS_AGE_KEY_FILE=/root/age.key nix-shell -p sops --run \
|
||||||
|
"sops updatekeys host/ThinkPad/secrets/mysecret.enc"
|
||||||
|
```
|
||||||
|
|
||||||
|
Для user-секретов — пользовательский ключ:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
SOPS_AGE_KEY_FILE=~/.config/sops/age/keys.txt nix-shell -p sops --run \
|
||||||
|
"sops updatekeys user/kirill/secrets.yaml"
|
||||||
|
```
|
||||||
|
|
||||||
|
4. `git add` + ребилд на этом устройстве.
|
||||||
@@ -1,12 +1,14 @@
|
|||||||
{ pkgs, lib, config, inputs, host, ... }:
|
{ pkgs, lib, config, inputs, host, ... }:
|
||||||
let
|
let
|
||||||
|
secretPath = config.sops.secrets."tokens/apis/wallhaven".path;
|
||||||
|
|
||||||
wallpaper_changer = pkgs.writers.writePython3Bin "wallpaper_changer" {
|
wallpaper_changer = pkgs.writers.writePython3Bin "wallpaper_changer" {
|
||||||
libraries = [ pkgs.python3Packages.requests ];
|
libraries = [ pkgs.python3Packages.requests ];
|
||||||
flakeIgnore = [ "E111" "E121" "E241" "E501" "E701" "E731" ];
|
flakeIgnore = [ "E111" "E121" "E241" "E501" "E701" "E731" ];
|
||||||
} /*py*/ ''
|
} /*py*/ ''
|
||||||
import requests as requests
|
import requests as requests
|
||||||
from random import choice
|
from random import choice
|
||||||
from os import listdir, makedirs, remove, replace, system
|
from os import environ, getuid, listdir, makedirs, remove, replace, system
|
||||||
from os.path import exists, getmtime, isfile
|
from os.path import exists, getmtime, isfile
|
||||||
from subprocess import run
|
from subprocess import run
|
||||||
|
|
||||||
@@ -88,18 +90,61 @@ let
|
|||||||
remove(f"{folder}/{name}")
|
remove(f"{folder}/{name}")
|
||||||
|
|
||||||
|
|
||||||
|
def read_history(path):
|
||||||
|
try:
|
||||||
|
with open(path) as file:
|
||||||
|
return [line.strip() for line in file if line.strip()]
|
||||||
|
except OSError:
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
def write_history(path, ids):
|
||||||
|
try:
|
||||||
|
with open(path, "w") as file:
|
||||||
|
file.write("\n".join(dict.fromkeys(ids)) + "\n")
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
folder = "${config.home.homeDirectory}/wallpapers"
|
folder = "${config.home.homeDirectory}/wallpapers"
|
||||||
url = "https://wallhaven.cc/api/v1/collections/BlackRaven21/2284568"
|
url = "https://wallhaven.cc/api/v1/collections/BlackRaven21/2284568"
|
||||||
|
runtime = environ.get("XDG_RUNTIME_DIR") or f"/run/user/{getuid()}"
|
||||||
|
history = f"{runtime}/wallpaper_changer_history"
|
||||||
|
|
||||||
|
token = None
|
||||||
|
try:
|
||||||
|
with open("${secretPath}") as file:
|
||||||
|
token = file.read().strip() or None
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
|
||||||
filename = None
|
filename = None
|
||||||
notify("Updating wallpaper...", 0)
|
notify("Updating wallpaper...", 0)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
response = requests.get(url, timeout=10)
|
params = {}
|
||||||
response.raise_for_status()
|
if token:
|
||||||
json = response.json()
|
params["apikey"] = token
|
||||||
|
|
||||||
wallpaper = choice(json['data'])
|
response = requests.get(url, params=params, timeout=10)
|
||||||
|
response.raise_for_status()
|
||||||
|
page_json = response.json()
|
||||||
|
|
||||||
|
walls = list(page_json['data'])
|
||||||
|
for page in range(2, page_json['meta']['last_page'] + 1):
|
||||||
|
params['page'] = page
|
||||||
|
response = requests.get(url, params=params, timeout=10)
|
||||||
|
response.raise_for_status()
|
||||||
|
walls.extend(response.json()['data'])
|
||||||
|
|
||||||
|
seen = read_history(history)
|
||||||
|
candidates = [wall for wall in walls if wall['id'] not in seen]
|
||||||
|
|
||||||
|
if not candidates:
|
||||||
|
seen = []
|
||||||
|
candidates = walls
|
||||||
|
|
||||||
|
wallpaper = choice(candidates)
|
||||||
link = wallpaper['path']
|
link = wallpaper['path']
|
||||||
format = wallpaper['file_type']
|
format = wallpaper['file_type']
|
||||||
id = wallpaper['id']
|
id = wallpaper['id']
|
||||||
@@ -119,6 +164,8 @@ let
|
|||||||
else:
|
else:
|
||||||
notify("Using cached wallpaper", 100)
|
notify("Using cached wallpaper", 100)
|
||||||
|
|
||||||
|
write_history(history, seen + [id])
|
||||||
|
|
||||||
except requests.exceptions.RequestException:
|
except requests.exceptions.RequestException:
|
||||||
notify("Offline mode")
|
notify("Offline mode")
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
tokens:
|
||||||
|
apis:
|
||||||
|
wallhaven: ENC[AES256_GCM,data:yO+thw4xgpMBuNx2LyxguDxAzoKSeDCyAAOcgtTxx74=,iv:j3LGKXnmykTamSuuIFbACT0kRDFazOhNEgWtVoxiWK4=,tag:jLaJrcUmDuxVj1D65NZhyg==,type:str]
|
||||||
|
wakapi: ENC[AES256_GCM,data:B4BOqy6TyZj4qPB9H7Ne+XaW701tX+ho8dMn0EGvqzdVOKq+,iv:/P6KZV9KgIBXslB3yZD5G3XER279iJ6/R2n+ZdTaBLs=,tag:r/SDXjofl8DdDlzP9Xo5mQ==,type:str]
|
||||||
|
sops:
|
||||||
|
age:
|
||||||
|
- enc: |
|
||||||
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA1MXcwbkFxZ2R4V0ppOGo3
|
||||||
|
UmFsTTJGekQ0NGVtTFpCRm50ekxJcEZUUW1FCkF5aStVckVNaVJndmptdnhtNjgx
|
||||||
|
Z056TVF5ZVRuMWJZKzk1WlRZTXN3bjAKLS0tIEhHd1JyTkhIdjJuZVZtSFlTRXIy
|
||||||
|
cTRWRkZXUmcrcHRXU2pyTzh1OGhaSkkKiqYLrPm1zS0PfrIeUnZHXvvHcY15PxDS
|
||||||
|
01jUzubGavkuOXb0hJmr6oBkEkSMBW+GLewduqj0SxGF2yxTSkM0kQ==
|
||||||
|
-----END AGE ENCRYPTED FILE-----
|
||||||
|
recipient: age1tx6jdr6535xxeygpwkkgvdwc24tulr420cm7gk56xzfp0slzeqks2nwpyg
|
||||||
|
lastmodified: "2026-10-21T17:46:52Z"
|
||||||
|
mac: ENC[AES256_GCM,data:mLdD78pb0Qf30+l/igb+jXMHxNXTXJPNtsi3cGeEgYLKxnx02OVBuOnncMZvN351yh7h5if9pCqwCJeOISWU8uFZrQdJeDjdmIPlP1eqzBQ7fK4fhEeRzAcn4dTQ5tcmu3uXmWElKcBYhMFEPr3/etyfDcX5ZFwOra8wUqU8nq4=,iv:TydKNjO5stupovtCF/rHMtr1Da2IFafMZiLQxsln1uA=,tag:kXl5eELy9I5APJkAQ8tk3w==,type:str]
|
||||||
|
unencrypted_suffix: _unencrypted
|
||||||
|
version: 3.13.3
|
||||||
Reference in new issue
Block a user