Compare commits

..

32 Commits

Author SHA1 Message Date
ab25c07f69 An attempt was made 2024-01-09 21:56:10 +00:00
aad8adf5da nixos/middleman: Add hack for working Gitea Docker image pull
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 26m52s
2024-01-09 18:50:11 +00:00
205a948486 nixos/middleman: Fix HedgeDoc websockets 2024-01-09 17:35:34 +00:00
39e7c703ba pkgs: Add modrinth-app
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 34m35s
2024-01-09 17:19:13 +00:00
d07ef96d28 envrc: Use watch_file instead of nix_direnv_watch_file 2024-01-09 13:33:00 +00:00
1a29a7d589 nixos/simpcraft: Staging server running
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 26m57s
2024-01-09 00:22:17 +00:00
ca6fe534dc nixos/git: Use separate nginx 2024-01-08 23:31:06 +00:00
e277cce3bc nixos/object: Add HedgeDoc
Some checks failed
CI / Check, build and cache Nix flake (push) Has been cancelled
2024-01-08 21:40:20 +00:00
c9ce57e2c5 nixos/middleman: Add public directory
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 24m53s
2024-01-07 03:40:33 +00:00
04dfc89f07 nixos/simpcraft: Add ToTheMoonStar to whitelist
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 24m53s
2024-01-06 14:59:57 +00:00
cfbbed8285 nixos/simpcraft: Upgrade to 0.1.1 2024-01-05 20:07:48 +00:00
066c87d3d6 nixos/simpcraft: Add mods
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 23m39s
2024-01-05 02:13:15 +00:00
e24ac05bb2 nixos/home/routing-common: Add vibe DNS
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 23m7s
2024-01-03 03:10:44 +00:00
a2b146e8ba nixos: Add librespeed
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 22m56s
2024-01-03 01:07:12 +00:00
a03fdbdbdd nixos/simpcraft: Add Eefah98 to whitelist
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 23m44s
2024-01-02 22:13:06 +00:00
5915f664cc nixos/simpcraft: Add hynge_ to whitelist 2024-01-02 20:49:08 +00:00
42111c530e nixos/colony: Reduce memory for mail VM
Some checks failed
CI / Check, build and cache Nix flake (push) Failing after 35m28s
2024-01-01 21:45:54 +00:00
a741e3eea2 nixos/whale2: Minecraft server updates
Some checks failed
CI / Check, build and cache Nix flake (push) Failing after 1h14m44s
2024-01-01 20:32:15 +00:00
7a4372dfe7 nixos/whale2: Add Minecraft server
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 25m30s
2024-01-01 16:28:04 +00:00
65917bad5c nixos/kelder: Disable minecraft-server 2024-01-01 16:26:45 +00:00
16c7fd7659 nixos/kelder: Update Minecraft and Nextcloud
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 23m55s
2023-12-31 20:21:02 +00:00
2fffefd22d Update river public IP
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 23m24s
2023-12-31 15:15:22 +00:00
c14aebf4a3 nixos/colony: Only start needed LVs in initrd to prevent race
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 23m2s
2023-12-30 21:07:12 +00:00
677f3f26ab home-manager/common: Use vi bindings for tmux 2023-12-29 21:04:07 +00:00
c55600c5af lib: Make awaitPostgres code early in preStart 2023-12-29 19:05:28 +00:00
64c3e2d720 nixos/colony: Give 8GiB more RAM to git
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 53m46s
Installer / Build installer (push) Successful in 4m43s
2023-12-28 18:54:43 +00:00
20d5fa29ae nixos/deploy: Minor improvements 2023-12-28 18:33:55 +00:00
046937de27 Update inputs and add custom NixOS branding
Some checks failed
CI / Check, build and cache Nix flake (push) Failing after 34m39s
2023-12-28 17:39:14 +00:00
bba87ef73b nixos/home/routing-common: Add trusted AS211024 to input chain
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 20m12s
2023-12-23 12:33:10 +00:00
4e3ff0a466 nixos/home/routing-common: Add dynamic DNS update script
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 20m48s
2023-12-23 01:22:41 +00:00
b1af3dbf18 nixos/tower: Add wireshark and Tailscale shell abbrev 2023-12-23 00:49:24 +00:00
f58b71e8d3 nixos/britway: Use internal addresses for DNS 2023-12-23 00:49:02 +00:00
49 changed files with 7726 additions and 208 deletions

2
.envrc
View File

@@ -1,2 +1,2 @@
nix_direnv_watch_file devshell/{default,commands,install,vm-tasks}.nix
watch_file devshell/{default,commands,install,vm-tasks}.nix
use flake

View File

@@ -33,18 +33,18 @@ jobs:
- name: Build installer ISO
run: |
nix build .#nixfiles.config.nixos.systems.installer.configuration.config.my.buildAs.iso
ln -s "$(readlink result)"/iso/nixos-installer-devplayer0.iso \
nixos-installer-devplayer0-${{ steps.setup.outputs.short_rev }}.iso
ln -s "$(readlink result)"/iso/jackos-installer.iso \
jackos-installer-${{ steps.setup.outputs.short_rev }}.iso
- name: Build installer netboot archive
run: |
nix build .#nixfiles.config.nixos.systems.installer.configuration.config.my.buildAs.netbootArchive
ln -s "$(readlink result)" \
nixos-installer-devplayer0-netboot-${{ steps.setup.outputs.short_rev }}.tar
jackos-installer-netboot-${{ steps.setup.outputs.short_rev }}.tar
- name: Create release
uses: https://gitea.com/actions/release-action@main
with:
title: Latest installer
files: |
nixos-installer-devplayer0-${{ steps.setup.outputs.short_rev }}.iso
nixos-installer-devplayer0-netboot-${{ steps.setup.outputs.short_rev }}.tar
jackos-installer-${{ steps.setup.outputs.short_rev }}.iso
jackos-installer-netboot-${{ steps.setup.outputs.short_rev }}.tar

154
flake.lock generated
View File

@@ -35,11 +35,11 @@
]
},
"locked": {
"lastModified": 1698258239,
"narHash": "sha256-qnhoYYIJ0L/P7H/f56lQUEvpzNlXh4sxuHpRERV+B44=",
"lastModified": 1702969472,
"narHash": "sha256-IJP9sC+/gLUdWhm6TsnWpw6A1zQWUfn53ym63KeLXvU=",
"owner": "zhaofengli",
"repo": "attic",
"rev": "e9918bc6be268da6fa97af6ced15193d8a0421c0",
"rev": "bdafd64910bb2b861cf90fa15f1fc93318b6fbf6",
"type": "github"
},
"original": {
@@ -95,26 +95,17 @@
},
"crane": {
"inputs": {
"flake-compat": [
"attic",
"flake-compat"
],
"flake-utils": [
"attic",
"flake-utils"
],
"nixpkgs": [
"attic",
"nixpkgs"
],
"rust-overlay": "rust-overlay"
]
},
"locked": {
"lastModified": 1677892403,
"narHash": "sha256-/Wi0L1spSWLFj+UQxN3j0mPYMoc7ZoAujpUF/juFVII=",
"lastModified": 1702918879,
"narHash": "sha256-tWJqzajIvYcaRWxn+cLUB9L9Pv4dQ3Bfit/YjU5ze3g=",
"owner": "ipetkov",
"repo": "crane",
"rev": "105e27adb70a9890986b6d543a67761cbc1964a2",
"rev": "7195c00c272fdd92fc74e7d5a0a2844b9fadb2fb",
"type": "github"
},
"original": {
@@ -185,11 +176,11 @@
"utils": "utils"
},
"locked": {
"lastModified": 1698921442,
"narHash": "sha256-7KmvhQ7FuXlT/wG4zjTssap6maVqeAMBdtel+VjClSM=",
"lastModified": 1703087360,
"narHash": "sha256-0VUbWBW8VyiDRuimMuLsEO4elGuUw/nc2WDeuO1eN1M=",
"owner": "serokell",
"repo": "deploy-rs",
"rev": "660180bbbeae7d60dad5a92b30858306945fd427",
"rev": "b709d63debafce9f5645a5ba550c9e0983b3d1f7",
"type": "github"
},
"original": {
@@ -241,14 +232,14 @@
"nixpkgs": [
"nixpkgs-unstable"
],
"systems": "systems_3"
"systems": "systems_4"
},
"locked": {
"lastModified": 1698410321,
"narHash": "sha256-MphuSlgpmKwtJncGMohryHiK55J1n6WzVQ/OAfmfoMc=",
"lastModified": 1701787589,
"narHash": "sha256-ce+oQR4Zq9VOsLoh9bZT8Ip9PaMLcjjBUHVPzW5d7Cw=",
"owner": "numtide",
"repo": "devshell",
"rev": "1aed986e3c81a4f6698e85a7452cbfcc4b31a36e",
"rev": "44ddedcbcfc2d52a76b64fb6122f209881bd3e1e",
"type": "github"
},
"original": {
@@ -276,11 +267,11 @@
"flake-compat_2": {
"flake": false,
"locked": {
"lastModified": 1668681692,
"narHash": "sha256-Ht91NGdewz8IQLtWZ9LCeNXMSXHUss+9COoqu6JLmXU=",
"lastModified": 1696426674,
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "009399224d5e398d03b22badca40a37ac85412a1",
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
"type": "github"
},
"original": {
@@ -418,14 +409,14 @@
},
"flake-utils_7": {
"inputs": {
"systems": "systems_4"
"systems": "systems_5"
},
"locked": {
"lastModified": 1694529238,
"narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
"lastModified": 1701680307,
"narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
"rev": "4022d587cbbfd70fe950c1e2083a02621806a725",
"type": "github"
},
"original": {
@@ -451,7 +442,7 @@
},
"flake-utils_9": {
"inputs": {
"systems": "systems_5"
"systems": "systems_6"
},
"locked": {
"lastModified": 1681202837,
@@ -474,11 +465,11 @@
]
},
"locked": {
"lastModified": 1700814205,
"narHash": "sha256-lWqDPKHRbQfi+zNIivf031BUeyciVOtwCwTjyrhDB5g=",
"lastModified": 1703367386,
"narHash": "sha256-FMbm48UGrBfOWGt8+opuS+uLBLQlRfhiYXhHNcYMS5k=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "aeb2232d7a32530d3448318790534d196bf9427a",
"rev": "d5824a76bc6bb93d1dce9ebbbcb09a9b6abcc224",
"type": "github"
},
"original": {
@@ -494,11 +485,11 @@
]
},
"locked": {
"lastModified": 1701433070,
"narHash": "sha256-Gf9JStfENaUQ7YWFz3V7x/srIwr4nlnVteqaAxtwpgM=",
"lastModified": 1703754036,
"narHash": "sha256-JpJdcj9Tg4lMuYikXDpajA8wOp+rHyn9RD2rKBEM4cQ=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "4a8545f5e737a6338814a4676dc8e18c7f43fc57",
"rev": "c24c298562fe41b39909f632c5a7151bbf6b4628",
"type": "github"
},
"original": {
@@ -508,11 +499,11 @@
},
"impermanence": {
"locked": {
"lastModified": 1697303681,
"narHash": "sha256-caJ0rXeagaih+xTgRduYtYKL1rZ9ylh06CIrt1w5B4g=",
"lastModified": 1703656108,
"narHash": "sha256-hCSUqdFJKHHbER8Cenf5JRzjMlBjIdwdftGQsO0xoJs=",
"owner": "nix-community",
"repo": "impermanence",
"rev": "0f317c2e9e56550ce12323eb39302d251618f5b5",
"rev": "033643a45a4a920660ef91caa391fbffb14da466",
"type": "github"
},
"original": {
@@ -531,13 +522,13 @@
"locked": {
"lastModified": 1685908677,
"narHash": "sha256-E4zUPEUFyVWjVm45zICaHRpfGepfkE9Z2OECV9HXfA4=",
"owner": "guibou",
"owner": "nix-community",
"repo": "nixGL",
"rev": "489d6b095ab9d289fe11af0219a9ff00fe87c7c5",
"type": "github"
},
"original": {
"owner": "guibou",
"owner": "nix-community",
"repo": "nixGL",
"type": "github"
}
@@ -560,11 +551,11 @@
},
"nixpkgs-mine": {
"locked": {
"lastModified": 1701607327,
"narHash": "sha256-pHX6S1mrUSFVq6v0HiZuShfXLL01wiWvgivCabX2x+M=",
"lastModified": 1703756459,
"narHash": "sha256-ztEMyPQZh3Pb+LOoWl5lbIK2LenP59sOUBC86CDmLio=",
"owner": "devplayer0",
"repo": "nixpkgs",
"rev": "c8af66cb9046a65cbab33563f804b7bad46173af",
"rev": "e80160eb2ac3a7111d07cc43a15c16b9edca01ea",
"type": "github"
},
"original": {
@@ -576,11 +567,11 @@
},
"nixpkgs-mine-stable": {
"locked": {
"lastModified": 1701607437,
"narHash": "sha256-ozMDOyJtxr/CznI6lrwtt9JkU32Y2cLr2B4vlW85Tfw=",
"lastModified": 1703756491,
"narHash": "sha256-9VL34e0gzomwqRnryRn23V2ImYcaZIQdp7CsWg5TmlE=",
"owner": "devplayer0",
"repo": "nixpkgs",
"rev": "67ef05e2dd98d1fd856028eba1bb4edb847f6c6e",
"rev": "36611f5f7cfd401f51ad4ca76fd6ee85a714bb74",
"type": "github"
},
"original": {
@@ -592,11 +583,11 @@
},
"nixpkgs-stable": {
"locked": {
"lastModified": 1701389149,
"narHash": "sha256-rU1suTIEd5DGCaAXKW6yHoCfR1mnYjOXQFOaH7M23js=",
"lastModified": 1703467016,
"narHash": "sha256-/5A/dNPhbQx/Oa2d+Get174eNI3LERQ7u6WTWOlR1eQ=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "5de0b32be6e85dc1a9404c75131316e4ffbc634c",
"rev": "d02d818f22c777aa4e854efc3242ec451e5d462a",
"type": "github"
},
"original": {
@@ -607,11 +598,11 @@
},
"nixpkgs-unstable": {
"locked": {
"lastModified": 1701253981,
"narHash": "sha256-ztaDIyZ7HrTAfEEUt9AtTDNoCYxUdSd6NrRHaYOIxtk=",
"lastModified": 1703438236,
"narHash": "sha256-aqVBq1u09yFhL7bj1/xyUeJjzr92fXVvQSSEx6AdB1M=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "e92039b55bcd58469325ded85d4f58dd5a4eaf58",
"rev": "5f64a12a728902226210bf01d25ec6cbb9d9265b",
"type": "github"
},
"original": {
@@ -678,7 +669,7 @@
"nixpkgs": [
"nixpkgs-unstable"
],
"rust-overlay": "rust-overlay_2"
"rust-overlay": "rust-overlay"
},
"locked": {
"lastModified": 1682237245,
@@ -715,33 +706,6 @@
}
},
"rust-overlay": {
"inputs": {
"flake-utils": [
"attic",
"crane",
"flake-utils"
],
"nixpkgs": [
"attic",
"crane",
"nixpkgs"
]
},
"locked": {
"lastModified": 1675391458,
"narHash": "sha256-ukDKZw922BnK5ohL9LhwtaDAdCsJL7L6ScNEyF1lO9w=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "383a4acfd11d778d5c2efcf28376cbd845eeaedf",
"type": "github"
},
"original": {
"owner": "oxalica",
"repo": "rust-overlay",
"type": "github"
}
},
"rust-overlay_2": {
"inputs": {
"flake-utils": [
"ragenix",
@@ -862,13 +826,31 @@
"type": "github"
}
},
"utils": {
"systems_6": {
"locked": {
"lastModified": 1667395993,
"narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"utils": {
"inputs": {
"systems": "systems_3"
},
"locked": {
"lastModified": 1701680307,
"narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
"rev": "4022d587cbbfd70fe950c1e2083a02621806a725",
"type": "github"
},
"original": {

View File

@@ -26,7 +26,7 @@
impermanence.url = "github:nix-community/impermanence";
boardie.url = "github:devplayer0/boardie";
boardie.inputs.nixpkgs.follows = "nixpkgs-unstable";
nixGL.url = "github:guibou/nixGL";
nixGL.url = "github:nix-community/nixGL";
nixGL.inputs.nixpkgs.follows = "nixpkgs-unstable";
# Packages not in nixpkgs
@@ -63,7 +63,7 @@
flake = flake-utils.lib;
};
pkgsLibOverlay = final: prev: { lib = prev.lib.extend libOverlay; };
myPkgsOverlay = final: prev: import ./pkgs { lib = prev.lib; pkgs = prev; };
myPkgsOverlay = final: prev: import ./pkgs { lib = final.lib; pkgs = prev; };
# Override the flake-level lib since we're going to use it for non-config specific stuff
pkgsFlakes = mapAttrs (_: pkgsFlake: pkgsFlake // { lib = pkgsFlake.lib.extend libOverlay; }) {
@@ -129,7 +129,7 @@
modules = [
{
_module.args = {
inherit lib pkgsFlakes hmFlakes inputs;
inherit lib pkgsFlakes hmFlakes self inputs;
pkgs' = configPkgs';
};

View File

@@ -80,6 +80,7 @@ in
tmux = {
enable = true;
keyMode = "vi";
};
bash = {

View File

@@ -169,6 +169,18 @@ rec {
port = 8448;
dst = aa.middleman.internal.ipv4.address;
}
{
port = 25565;
dst = aa.simpcraft-oci.internal.ipv4.address;
}
{
port = 25566;
dst = aa.simpcraft-staging-oci.internal.ipv4.address;
}
{
port = 25575;
dst = aa.simpcraft-oci.internal.ipv4.address;
}
{
port = 2456;
@@ -186,6 +198,12 @@ rec {
dst = aa.waffletail.internal.ipv4.address;
proto = "udp";
}
{
port = 25565;
dst = aa.simpcraft-oci.internal.ipv4.address;
proto = "udp";
}
];
fstrimConfig = {
@@ -209,7 +227,7 @@ rec {
"stream"
];
routersPubV4 = [
"109.255.31.25"
"109.255.1.246"
"109.255.252.63"
];

View File

@@ -1,10 +1,11 @@
{ lib }:
let
inherit (builtins) length match elemAt filter replaceStrings;
inherit (builtins) length match elemAt filter replaceStrings substring;
inherit (lib)
genAttrs mapAttrsToList filterAttrsRecursive nameValuePair types
mkOption mkOverride mkForce mkIf mergeEqualOption optional
showWarnings concatStringsSep flatten unique optionalAttrs;
showWarnings concatStringsSep flatten unique optionalAttrs
mkBefore;
inherit (lib.flake) defaultSystems;
in
rec {
@@ -166,7 +167,7 @@ rec {
systemdAwaitPostgres = pkg: host: {
after = [ "systemd-networkd-wait-online.service" ];
preStart = ''
preStart = mkBefore ''
until ${pkg}/bin/pg_isready -h ${host}; do
sleep 0.5
done
@@ -239,4 +240,18 @@ rec {
filterOpts = filterAttrsRecursive (_: v: v != null);
};
versionOverlay = { self, pkgsFlake }: final: prev:
let
date = substring 0 8 (self.lastModifiedDate or self.lastModified or "19700101");
revCode = flake: flake.shortRev or "dirty";
in
{
trivial = prev.trivial // {
release = "23.12:u-${prev.trivial.release}";
codeName = "Amogus";
revisionWithDefault = default: self.rev or default;
versionSuffix = ".${date}.${revCode self}:u-${revCode pkgsFlake}";
};
};
}

View File

@@ -49,15 +49,19 @@ in
noise.private_key_path = "/var/lib/headscale/noise_private.key";
ip_prefixes = with lib.my.c.tailscale.prefix; [ v4 v6 ];
dns_config = {
# Use IPs that will route inside the VPN to prevent interception
# (e.g. DNS rebinding filtering)
restricted_nameservers = {
"${domain}" = pubNameservers;
"${lib.my.c.colony.domain}" = with allAssignments.estuary.internal; [
"${lib.my.c.colony.domain}" = with allAssignments.estuary.base; [
ipv4.address ipv6.address
];
"${lib.my.c.home.domain}" = lib.my.c.home.routersPubV4 ++ ([
allAssignments.river.as211024.ipv6.address
allAssignments.stream.as211024.ipv6.address
]);
"${lib.my.c.home.domain}" = with allAssignments; [
river.hi.ipv4.address
river.hi.ipv6.address
stream.hi.ipv4.address
stream.hi.ipv6.address
];
};
magic_dns = true;
base_domain = "ts.${pubDomain}";

View File

@@ -66,10 +66,21 @@ in
};
});
kernelModules = [ "kvm-amd" ];
kernelParams = [ "amd_iommu=on" "console=ttyS0,115200n8" "console=ttyS1,115200n8" "console=tty0" ];
kernelParams = [
"amd_iommu=on"
"console=ttyS0,115200n8" "console=ttyS1,115200n8" "console=tty0"
"systemd.setenv=SYSTEMD_SULOGIN_FORCE=1"
];
initrd = {
kernelModules = [ "dm-raid" ];
availableKernelModules = [ "nvme" "xhci_pci" "ahci" "usb_storage" "usbhid" "sd_mod" "sr_mod" ];
systemd = {
enable = true;
# Onlu activate volumes needed for boot to prevent thin check from getting killed while switching root
contents."/etc/lvm/lvm.conf".text = ''
activation/auto_activation_volume_list = [ "main/colony-nix" "main/colony-persist" ]
'';
};
};
};
@@ -137,6 +148,15 @@ in
services = {
"serial-getty@ttyS0".enable = true;
"serial-getty@ttyS1".enable = true;
lvm-activate-main = {
description = "Activate remaining LVs";
before = [ "local-fs-pre.target" ];
serviceConfig = {
Type = "oneshot";
ExecStart = "${pkgs.lvm2.bin}/bin/vgchange -aay main";
};
wantedBy = [ "sysinit.target" ];
};
rsync-lvm-meta = {
description = "rsync lvm metadata backups / archives to rsync.net";

View File

@@ -120,7 +120,7 @@
cpus = 12;
threads = 2;
};
memory = 49152;
memory = 40960;
networks.vms.mac = "52:54:00:27:3d:5c";
cleanShutdown.timeout = 120;
drives = [ ] ++ (optionals (!config.my.build.isDevVM) [
@@ -160,7 +160,7 @@
cpus = 12;
threads = 2;
};
memory = 32768;
memory = 40960;
networks.vms.mac = "52:54:00:75:78:a8";
cleanShutdown.timeout = 120;
drives = [
@@ -181,7 +181,7 @@
cpus = 3;
threads = 2;
};
memory = 8192;
memory = 6144;
networks.public = {
bridge = null;
mac = "52:54:00:a8:d1:03";

View File

@@ -393,12 +393,16 @@ in
# Safe enough to allow all SSH
tcp dport ssh accept
${matchInet "tcp dport { http, https, 8448 } accept" "middleman"}
ip6 daddr ${aa.middleman.internal.ipv6.address} tcp dport { http, https, 8448 } accept
${matchInet "tcp dport { http, https } accept" "git"}
ip6 daddr ${aa.simpcraft-oci.internal.ipv6.address} tcp dport { 25565, 25575 } accept
ip6 daddr ${aa.simpcraft-staging-oci.internal.ipv6.address} tcp dport 25565 accept
return
}
chain routing-udp {
ip6 daddr ${aa.valheim-oci.internal.ipv6.address} udp dport { 2456-2457 } accept
ip6 daddr ${aa.waffletail.internal.ipv6.address} udp dport 41641 accept
ip6 daddr ${aa.simpcraft-oci.internal.ipv6.address} udp dport 25565 accept
return
}
chain filter-routing {
@@ -429,8 +433,6 @@ in
table inet nat {
chain prerouting {
${matchInet "meta l4proto { udp, tcp } th dport domain redirect to :5353" "estuary"}
ip daddr ${aa.git.internal.ipv4.address} tcp dport { http, https } dnat to ${aa.middleman.internal.ipv4.address}
ip6 daddr ${aa.git.internal.ipv6.address} tcp dport { http, https } dnat to ${aa.middleman.internal.ipv6.address}
}
chain postrouting {
ip saddr ${prefixes.all.v4} oifname != as211024 snat to ${assignments.internal.ipv4.address}

View File

@@ -52,7 +52,7 @@ in
allowFrom = [
"127.0.0.0/8" "::1/128"
prefixes.all.v4 prefixes.all.v6
];
] ++ (with lib.my.c.tailscale.prefix; [ v4 v6 ]);
};
settings = {
@@ -145,9 +145,14 @@ in
http IN A ${assignments.internal.ipv4.address}
http IN AAAA ${allAssignments.middleman.internal.ipv6.address}
librespeed IN CNAME http.${config.networking.domain}.
valheim IN A ${assignments.internal.ipv4.address}
valheim IN AAAA ${allAssignments.valheim-oci.internal.ipv6.address}
simpcraft IN A ${assignments.internal.ipv4.address}
simpcraft IN AAAA ${allAssignments.simpcraft-oci.internal.ipv6.address}
simpcraft-staging IN A ${assignments.internal.ipv4.address}
simpcraft-staging IN AAAA ${allAssignments.simpcraft-staging-oci.internal.ipv6.address}
mail-vm IN A ${net.cidr.host 0 prefixes.mail.v4}
mail-vm IN AAAA ${net.cidr.host 1 prefixes.mail.v6}

View File

@@ -1,8 +1,11 @@
{ lib, ... }:
let
inherit (builtins) mapAttrs;
inherit (lib) mkMerge mkDefault;
inherit (lib.my) net;
inherit (lib.my.c) pubDomain;
inherit (lib.my.c.colony) domain prefixes;
inherit (lib.my.c.nginx) baseHttpConfig proxyHeaders;
in
{
nixos.systems.git = {
@@ -72,9 +75,109 @@ in
};
};
users = {
users = {
nginx.extraGroups = [ "acme" ];
};
};
security.acme = {
acceptTerms = true;
defaults = {
email = "dev@nul.ie";
server = "https://acme-v02.api.letsencrypt.org/directory";
reloadServices = [ "nginx" ];
dnsResolver = "8.8.8.8";
};
certs = {
"${pubDomain}" = {
extraDomainNames = [
"*.${pubDomain}"
];
dnsProvider = "cloudflare";
credentialsFile = config.age.secrets."middleman/cloudflare-credentials.conf".path;
};
};
};
services = {
fstrim = lib.my.c.colony.fstrimConfig;
# Hacks for Jsch (Minecraft FastBack) to work
openssh = {
hostKeys = [
{
bits = 4096;
path = "/etc/ssh/ssh_host_rsa_key";
type = "rsa";
}
{
path = "/etc/ssh/ssh_host_ed25519_key";
type = "ed25519";
}
{
type = "ecdsa-sha2-nistp256";
path = "/etc/ssh/ssh_host_ecdsa_key";
}
];
settings = {
Macs = [
"hmac-sha2-512-etm@openssh.com"
"hmac-sha2-256-etm@openssh.com"
"umac-128-etm@openssh.com"
"hmac-sha2-256"
];
};
};
netdata.enable = true;
nginx = {
enable = true;
enableReload = true;
logError = "stderr info";
recommendedTlsSettings = true;
clientMaxBodySize = "0";
serverTokens = true;
sslDhparam = config.age.secrets."dhparams.pem".path;
# Based on recommended*Settings, but probably better to be explicit about these
appendHttpConfig = ''
${baseHttpConfig}
# caching
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=CACHE:10m inactive=7d max_size=512m;
'';
virtualHosts =
let
hosts = {
"_" = {
default = true;
forceSSL = true;
onlySSL = false;
locations = {
"/".root = "${pkgs.nginx}/html";
};
};
"git.${pubDomain}" = {
locations."/".proxyPass = "http://localhost:3000";
};
};
defaultsFor = mapAttrs (n: _: {
onlySSL = mkDefault true;
useACMEHost = mkDefault pubDomain;
kTLS = mkDefault true;
http2 = mkDefault true;
});
in
mkMerge [
hosts
(defaultsFor hosts)
];
};
};
virtualisation = {
@@ -104,11 +207,24 @@ in
};
my = {
secrets.key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIP+KINpHLMduBuW96JzfSRDLUzkI+XaCBghu5/wHiW5R";
secrets = {
key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIP+KINpHLMduBuW96JzfSRDLUzkI+XaCBghu5/wHiW5R";
files = {
"dhparams.pem" = {
owner = "acme";
group = "acme";
mode = "440";
};
"middleman/cloudflare-credentials.conf" = {
owner = "acme";
group = "acme";
};
};
};
server.enable = true;
firewall = {
tcp.allowed = [ 19999 ];
tcp.allowed = [ 19999 "http" "https" ];
extraRules = ''
table inet filter {
chain forward {

View File

@@ -26,18 +26,6 @@ in
systemd = {
services = {
# TODO: Figure out a way to do this properly... redirecting localhost is awkward...
local-http-forward = {
description = "Forward local HTTP connections";
serviceConfig.ExecStart = "${pkgs.socat}/bin/socat tcp-listen:80,fork tcp:${allAssignments.middleman.internal.ipv4.address}:80";
wantedBy = [ "multi-user.target" ];
};
local-https-forward = {
description = "Forward local HTTPS connections";
serviceConfig.ExecStart = "${pkgs.socat}/bin/socat tcp-listen:443,fork tcp:${allAssignments.middleman.internal.ipv4.address}:443";
wantedBy = [ "multi-user.target" ];
};
gitea = mkMerge [
(lib.my.systemdAwaitPostgres pkgs.postgresql "colony-psql")
{
@@ -141,21 +129,6 @@ in
"gitea/minio.txt" = ownedByGit;
};
};
firewall.extraRules = ''
table inet filter {
chain input {
ip saddr ${prefixes.all.v4} tcp dport 3000 accept
ip6 saddr ${prefixes.all.v6} tcp dport 3000 accept
}
}
table inet nat {
chain prerouting {
ip daddr ${assignments.internal.ipv4.address} tcp dport { http, https } dnat to ${allAssignments.middleman.internal.ipv4.address}
ip6 daddr ${assignments.internal.ipv6.address} tcp dport { http, https } dnat to ${allAssignments.middleman.internal.ipv6.address}
}
}
'';
};
};
}

View File

@@ -66,6 +66,7 @@ in
owner = "nginx";
group = "nginx";
};
"librespeed.toml" = { };
};
};
@@ -122,6 +123,19 @@ in
baseURL = "https://sso.${pubDomain}";
};
};
librespeed = {
frontend.servers = [
{
name = "Amsterdam, Netherlands";
server = "//librespeed.${domain}";
}
];
backend = {
enable = true;
extraSettingsFile = config.age.secrets."librespeed.toml".path;
};
};
};
users = {

View File

@@ -347,9 +347,41 @@ in
};
useACMEHost = pubDomain;
};
"public.${pubDomain}" = {
serverAliases = [ "p.${pubDomain}" ];
locations."/" = {
root = "/mnt/media/public";
extraConfig = ''
fancyindex on;
fancyindex_show_dotfiles on;
'';
};
useACMEHost = pubDomain;
};
"git.${pubDomain}" = {
locations."/".proxyPass = "http://git-vm.${domain}:3000";
"mc-map.${pubDomain}" = {
locations."/".proxyPass = "http://simpcraft-oci.${domain}:8100";
useACMEHost = pubDomain;
};
"mc-rail.${pubDomain}" = {
locations."/".proxyPass = "http://simpcraft-staging-oci.${domain}:3876";
useACMEHost = pubDomain;
};
"librespeed.${domain}" = {
locations."/".proxyPass = "http://localhost:8989";
};
"speed.${pubDomain}" = {
locations."/".proxyPass = "http://localhost:8989";
useACMEHost = pubDomain;
};
"md.${pubDomain}" = {
locations."/" = {
proxyPass = "http://object-ctr.${domain}:3000";
proxyWebsockets = true;
extraConfig = proxyHeaders;
};
useACMEHost = pubDomain;
};
};
@@ -387,7 +419,22 @@ in
"s3.${pubDomain}" = {
serverAliases = [ "*.s3.${pubDomain}" ];
inherit extraConfig;
locations."/".proxyPass = s3Upstream;
locations = {
"/".proxyPass = s3Upstream;
"/gitea/packages/" = {
proxyPass = s3Upstream;
# HACK: Docker images need the MIME type to be correct for the manifest but Gitea
# doesn't tell S3... By hiding the header we can use add_header to set Content-Type
# (normally can't be set directly)
extraConfig = ''
proxy_hide_header Content-Type;
add_header Content-Type $upstream_http_content_type always;
if ($args ~ "response-content-disposition=.+filename%3D%22manifest\.json%22") {
add_header Content-Type "application/vnd.docker.distribution.manifest.v2+json";
}
'';
};
};
useACMEHost = pubDomain;
};

View File

@@ -48,11 +48,17 @@ in
group = config.my.user.config.group;
};
"object/atticd.env" = {};
"object/hedgedoc.env" = {};
};
};
firewall = {
tcp.allowed = [ 9000 9001 config.services.sharry.config.bind.port 8069 ];
tcp.allowed = [
9000 9001
config.services.sharry.config.bind.port
8069
config.services.hedgedoc.settings.port
];
};
user.homeConfig = {
@@ -194,6 +200,26 @@ in
};
};
};
hedgedoc = {
enable = true;
environmentFile = config.age.secrets."object/hedgedoc.env".path;
settings = {
domain = "md.${pubDomain}";
protocolUseSSL = true;
db = {
dialect = "postgresql";
username = "hedgedoc";
database = "hedgedoc";
host = "colony-psql";
};
host = "::";
allowAnonymous = false;
allowAnonymousEdits = true;
email = true;
allowEmailRegister = false;
};
};
};
}
(mkIf config.my.build.isDevVM {

View File

@@ -50,6 +50,8 @@ in
};
}) {
valheim-oci = 2;
simpcraft-oci = 3;
simpcraft-staging-oci = 4;
};
configuration = { lib, pkgs, modulesPath, config, assignments, allAssignments, ... }:
@@ -63,6 +65,7 @@ in
"${modulesPath}/profiles/qemu-guest.nix"
./valheim.nix
./minecraft
];
config = mkMerge [

View File

@@ -0,0 +1,121 @@
{ lib, pkgs, config, allAssignments, ... }:
let
inherit (lib) concatStringsSep;
inherit (lib.my) dockerNetAssignment;
# devplayer0
op = "6d7d971b-ce10-435b-85c5-c99c0d8d288c";
whitelist = concatStringsSep "," [
op
"dcd2ecb9-2b5e-49cb-9d4f-f5a76162df56" # Elderlypug
"fcb26db2-c3ce-41aa-b588-efec79d37a8a" # Jesthral_
"1d366062-12c0-4e29-aba7-6ab5d8c6bb05" # shr3kas0ras
"703b378a-09f9-4c1d-9876-1c9305728c49" # OROURKEIRE
"f105bbe6-eda6-4a13-a8cf-894e77cab77b" # Adzerq
"1fc94979-41fb-497a-81e9-34ae24ca537a" # johnnyscrims
"d53c91df-b6e6-4463-b106-e8427d7a8d01" # BossLonus
"f439f64d-91c9-4c74-9ce5-df4d24cd8e05" # hynge_
"d6ec4c91-5da2-44eb-b89d-71dc8fe017a0" # Eefah98
"096a7348-fabe-4b2d-93fc-fd1fd5608fb0" # ToTheMoonStar
];
fastback = {
gitConfig = pkgs.writeText "git-config" ''
[user]
email = "simpcraft@nul.ie"
name = "Simpcraft bot"
'';
knownHosts = pkgs.writeText "known_hosts" ''
git.nul.ie ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBD023ECzYmLeXIpcGVaciPjq6UN/Sjmsys5HP/Nei5GkrUZqPa3OJ2uSXKLUSKGYdeNhxaFTPJe8Yx3TsZxMme8=
'';
};
in
{
config = {
virtualisation.oci-containers.containers = {
simpcraft = {
image = "ghcr.io/itzg/minecraft-server:2023.12.2-java17-alpine";
environment = {
TYPE = "MODRINTH";
EULA = "true";
ENABLE_QUERY = "true";
MOTD = "§4§k----- §9S§ai§bm§cp§dc§er§fa§6f§5t §4§k-----";
ICON = "/ext/icon.png";
EXISTING_WHITELIST_FILE = "SYNCHRONIZE";
WHITELIST = whitelist;
EXISTING_OPS_FILE = "SYNCHRONIZE";
OPS = op;
DIFFICULTY = "normal";
SPAWN_PROTECTION = "0";
VIEW_DISTANCE = "20";
MAX_MEMORY = "6G";
MODRINTH_MODPACK = "https://cdn.modrinth.com/data/CIYf3Hk8/versions/cdj2bSKg/Simpcraft-0.1.2.mrpack";
TZ = "Europe/Dublin";
};
volumes = [
"minecraft_data:/data"
"${./icon.png}:/ext/icon.png:ro"
];
extraOptions = [
''--network=colony:${dockerNetAssignment allAssignments "simpcraft-oci"}''
];
};
simpcraft-staging = {
image = "git.nul.ie/dev/craftblock:2024.1.0-java17-alpine";
environment = {
TYPE = "MODRINTH";
EULA = "true";
ENABLE_QUERY = "true";
ENABLE_RCON = "true";
MOTD = "§4§k----- §9S§ai§bm§cp§dc§er§fa§6f§5t [staging] §4§k-----";
ICON = "/ext/icon.png";
EXISTING_WHITELIST_FILE = "SYNCHRONIZE";
WHITELIST = whitelist;
EXISTING_OPS_FILE = "SYNCHRONIZE";
OPS = op;
DIFFICULTY = "normal";
SPAWN_PROTECTION = "0";
VIEW_DISTANCE = "20";
MAX_MEMORY = "4G";
MODRINTH_MODPACK = "https://cdn.modrinth.com/data/CIYf3Hk8/versions/Ym3sIi6H/Simpcraft-0.2.0.mrpack";
TZ = "Europe/Dublin";
};
environmentFiles = [ config.age.secrets."whale2/simpcraft.env".path ];
volumes = [
"minecraft_staging_data:/data"
"${./icon.png}:/ext/icon.png:ro"
"${fastback.gitConfig}:/data/.config/git/config:ro"
"${fastback.knownHosts}:/data/.ssh/known_hosts:ro"
"${config.age.secrets."whale2/simpcraft-git.key".path}:/data/.ssh/id_rsa"
];
extraOptions = [
''--network=colony:${dockerNetAssignment allAssignments "simpcraft-staging-oci"}''
];
};
};
my = {
secrets.files = {
"whale2/simpcraft.env" = {};
"whale2/simpcraft-git.key" = {
owner = "1000";
};
};
};
};
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

@@ -325,6 +325,7 @@ in
''
table inet filter {
chain input {
${lib.my.c.as211024.nftTrust}
iifname base meta l4proto { udp, tcp } th dport domain accept
iifname lan-core meta l4proto vrrp accept
}

View File

@@ -2,6 +2,7 @@ index: { lib, pkgs, config, assignments, allAssignments, ... }:
let
inherit (builtins) attrNames elemAt;
inherit (lib.my) net;
inherit (lib.my.c) pubDomain;
inherit (lib.my.c.home) prefixes vips routers;
name = elemAt routers index;
@@ -22,6 +23,7 @@ in
owner = "pdns-recursor";
group = "pdns-recursor";
};
"home/ddclient-cloudflare.key" = {};
};
pdns.recursor = {
@@ -42,7 +44,7 @@ in
"127.0.0.0/8" "::1/128"
prefixes.hi.v4 prefixes.hi.v6
prefixes.lo.v4 prefixes.lo.v6
];
] ++ (with lib.my.c.tailscale.prefix; [ v4 v6 ]);
};
settings = {
@@ -63,9 +65,36 @@ in
};
};
systemd.services = {
# Add AF_NETLINK to allow pulling IP from network interfaces
pdns.serviceConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6 AF_NETLINK";
systemd = {
services = {
# Add AF_NETLINK to allow pulling IP from network interfaces
pdns.serviceConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6 AF_NETLINK";
ddns-update = {
description = "DNS update script";
after = [ "network.target" ];
path = [
(pkgs.python3.withPackages (ps: [ ps.cloudflare ]))
pkgs.ldns
];
serviceConfig = {
Type = "oneshot";
ExecStart =
''${./dns_update.py} -k ${config.age.secrets."home/ddclient-cloudflare.key".path} '' +
''${pubDomain} ns${toString (index + 1)}.${config.networking.domain}'';
};
wantedBy = [ "multi-user.target" ];
};
};
timers = {
ddns-update = {
description = "Periodically update DNS";
wantedBy = [ "timers.target" ];
timerConfig = {
OnBootSec = "5min";
OnUnitInactiveSec = "5min";
};
};
};
};
environment.systemPackages = with pkgs; [
@@ -153,6 +182,11 @@ in
dave-lo IN A ${net.cidr.host 11 prefixes.lo.v4}
dave-lo IN AAAA ${net.cidr.host (65536+2) prefixes.lo.v6}
;ap0 IN A ${net.cidr.host 12 prefixes.hi.v4}
;ap0 IN AAAA ${net.cidr.host (65536+3) prefixes.hi.v6}
vibe IN A ${net.cidr.host 13 prefixes.hi.v4}
vibe IN AAAA ${net.cidr.host (65536+4) prefixes.hi.v6}
ups IN A ${net.cidr.host 20 prefixes.lo.v4}
palace-kvm IN A ${net.cidr.host 21 prefixes.lo.v4}

View File

@@ -0,0 +1,35 @@
#!/usr/bin/env python3
import argparse
import subprocess
import CloudFlare
def main():
parser = argparse.ArgumentParser(description='Cloudflare DNS update script')
parser.add_argument('-k', '--api-token-file', help='Cloudflare API token file')
parser.add_argument('zone', help='Cloudflare Zone')
parser.add_argument('record', help='Cloudflare record name')
args = parser.parse_args()
address = subprocess.check_output(
['drill', '-Q', '-p5353', '@127.0.0.1', args.record, 'A'],
encoding='utf8').strip()
cf_token = None
if args.api_token_file:
with open(args.api_token_file) as f:
cf_token = f.readline().strip()
cf = CloudFlare.CloudFlare(token=cf_token)
zones = cf.zones.get(params={'name': args.zone})
assert zones, f'Zone {args.zone} not found'
records = cf.zones.dns_records.get(zones[0]['id'], params={'name': args.record})
assert records, f'Record {args.record} not found in zone {args.zone}'
print(f'Updating {args.record} -> {address}')
cf.zones.dns_records.patch(
zones[0]['id'], records[0]['id'],
data={'type': 'A', 'name': args.record, 'content': address})
if __name__ == '__main__':
main()

View File

@@ -55,7 +55,7 @@ in
}
{
name = "domain-search";
data = "${domain}, dyn.${domain}";
data = "${domain}, dyn.${domain}, ${lib.my.c.colony.domain}, ${lib.my.c.britway.domain}";
always-send = true;
}
];

View File

@@ -11,7 +11,7 @@ let
AdvLinkMTU ${toString prefixes."${name}".mtu};
prefix ${prefixes."${name}".v6} {};
RDNSS ${net.cidr.host 1 prefixes."${name}".v6} ${net.cidr.host 2 prefixes."${name}".v6} {};
DNSSL ${domain} dyn.${domain} {};
DNSSL ${domain} dyn.${domain} ${lib.my.c.colony.domain} ${lib.my.c.britway.domain} {};
};
'';
in

View File

@@ -92,7 +92,7 @@ in
nextcloud = {
enable = true;
package = pkgs.nextcloud27;
package = pkgs.nextcloud28;
datadir = "/mnt/storage/nextcloud";
hostName = "cloud.${domain}";
https = true;

View File

@@ -135,12 +135,14 @@ in
samba-wsdd.enable = true;
minecraft-server = {
enable = true;
package = pkgs.minecraftServers.vanilla-1-19;
enable = false;
package = pkgs.minecraftServers.vanilla-1-20;
declarative = true;
eula = true;
whitelist = {
devplayer0 = "6d7d971b-ce10-435b-85c5-c99c0d8d288c";
Elderlypug = "dcd2ecb9-2b5e-49cb-9d4f-f5a76162df56";
shr3kas0ras = "1d366062-12c0-4e29-aba7-6ab5d8c6bb05";
};
serverProperties = {
motd = "Simpcraft";

View File

@@ -116,6 +116,10 @@
programs = {
steam.enable = true;
wireshark = {
enable = true;
package = pkgs.wireshark-qt;
};
};
networking = {
@@ -171,6 +175,14 @@
packages = with pkgs; [ ];
};
programs = {
fish = {
shellAbbrs = {
tsup = "doas tailscale up --login-server=https://ts.nul.ie --accept-routes";
};
};
};
services = {
blueman-applet.enable = true;
};

View File

@@ -1,4 +1,4 @@
{ lib, pkgsFlakes, hmFlakes, inputs, pkgs', config, ... }:
{ self, lib, pkgsFlakes, hmFlakes, inputs, pkgs', config, ... }:
let
inherit (builtins) attrValues mapAttrs;
inherit (lib)
@@ -25,10 +25,14 @@ let
modules' = [ hmFlakes.${config'.home-manager}.nixosModule ] ++ (attrValues cfg.modules);
in
pkgsFlake.lib.nixosSystem {
# Import eval-config ourselves since the flake now force-sets lib
import "${pkgsFlake}/nixos/lib/eval-config.nix" {
# Gotta override lib here unforunately, eval-config.nix likes to import its own (unextended) lib. We explicitly
# don't pass pkgs so that it'll be imported with modularly applied config and overlays.
lib = pkgs.lib;
lib = pkgs.lib.extend (lib.my.versionOverlay { inherit self pkgsFlake; });
# Set to null since we pass modularly
system = null;
# Put the inputs in specialArgs to avoid infinite recursion when modules try to do imports
specialArgs = { inherit inputs pkgsFlakes pkgsFlake allAssignments; inherit (cfg) systems; };
@@ -51,7 +55,7 @@ let
pkgs' = allPkgs;
};
system.name = name;
system = { inherit name; };
networking = {
domain = let d = config'.assignments.internal.domain or null; in mkIf (d != null) (mkDefault' d);
hostName = mkDefault (config'.assignments.internal.name or name);
@@ -86,6 +90,8 @@ let
pkgsPath = toString pkgsFlakes.${config'.hmNixpkgs};
pkgs' = allPkgs;
};
home.enableNixpkgsReleaseCheck = false;
}
(homeStateVersion config'.home-manager)
];

View File

@@ -32,7 +32,8 @@
};
isoImage = {
isoBaseName = "nixos-installer-devplayer0";
isoBaseName = "jackos-installer";
volumeID = "jackos-${config.system.nixos.release}-${pkgs.stdenv.hostPlatform.uname.processor}";
edition = "devplayer0";
appendToMenuLabel = " /dev/player0 Installer";
};

View File

@@ -19,5 +19,6 @@
borgthin = ./borgthin.nix;
nvme = ./nvme;
spdk = ./spdk.nix;
librespeed = ./librespeed;
};
}

View File

@@ -92,6 +92,7 @@ in
};
isoImage = {
isoBaseName = dummyOption;
volumeID = dummyOption;
edition = dummyOption;
appendToMenuLabel = dummyOption;
};

View File

@@ -1,7 +1,7 @@
{ lib, pkgs, pkgs', inputs, config, ... }:
let
inherit (lib) mkIf mkDefault mkMerge;
inherit (lib.my) mkBoolOpt' dummyOption;
inherit (lib.my) mkDefault';
in
{
options = with lib.types; {
@@ -121,6 +121,11 @@ in
services.lvm.enable = mkDefault true;
};
};
system = {
nixos = {
distroName = mkDefault' "JackOS";
};
};
environment.systemPackages = with pkgs; mkMerge [
[
@@ -151,6 +156,7 @@ in
font-name=SauceCodePro Nerd Font Mono
'';
};
getty.greetingLine = mkDefault' ''<<< Welcome to ${config.system.nixos.distroName} ${config.system.nixos.label} (\m) - \l >>>'';
openssh = {
enable = mkDefault true;

View File

@@ -15,16 +15,20 @@ let
# Based on https://github.com/serokell/deploy-rs/blob/master/flake.nix
nixosActivate = cfg': base: (pkgs.deploy-rs.lib.activate.custom // {
dryActivate = "$PROFILE/bin/switch-to-configuration dry-activate";
boot = "$PROFILE/bin/switch-to-configuration boot";
boot = ''
$PROFILE/bin/switch-to-configuration boot
${keepGensSnippet "$PROFILE" cfg'.keepGenerations}
'';
}) base.config.system.build.toplevel ''
# work around https://github.com/NixOS/nixpkgs/issues/73404
cd /tmp
"$PROFILE"/bin/switch-to-configuration ${cfg'.mode}
"$PROFILE"/bin/switch-to-configuration switch
# https://github.com/serokell/deploy-rs/issues/31
${with base.config.boot.loader;
optionalString ((cfg'.mode == "switch" || cfg'.mode == "boot") && systemd-boot.enable)
optionalString systemd-boot.enable
"sed -i '/^default /d' ${efi.efiSysMountPoint}/loader/loader.conf"}
${keepGensSnippet "$PROFILE" cfg'.keepGenerations}
@@ -59,7 +63,11 @@ let
{
name = "container-${n}";
value = {
path = pkgs.deploy-rs.lib.activate.custom ctrConfig.my.buildAs.container ''
path = (pkgs.deploy-rs.lib.activate.custom // {
boot = ''
echo "Next systemd-nspawn@${n}.service restart / reload will load config"
'';
}) ctrConfig.my.buildAs.container ''
source ${systemdUtil}/bin/systemd-util.sh
${if c.hotReload then ''
if (! systemctl show -p ActiveState systemd-nspawn@${n} | grep -q "ActiveState=active") || \

View File

@@ -222,7 +222,7 @@ in
"iifname ${cfg.nat.externalInterface} jump filter-iif-port-forwards"}
${optionalString
dipForward
(concatMapStringsSep "\n " (ip: "${ipK ip} daddr ${ip} jump ${natFilterChain ip}") (attrNames cfg.nat.forwardPorts))}
(concatMapStringsSep "\n " (ip: "jump ${natFilterChain ip}") (attrNames cfg.nat.forwardPorts))}
}
}

View File

@@ -0,0 +1,76 @@
{ lib, pkgs, config, ... }:
let
inherit (builtins) toJSON;
inherit (lib) mkOption mkMerge mkIf mkDefault;
inherit (lib.my) mkOpt' mkBoolOpt';
cfg = config.my.librespeed;
serversConf = map (s: s // {
dlURL = "backend/garbage";
ulURL = "backend/empty";
pingURL = "backend/empty";
getIpURL = "backend/getIP";
}) cfg.frontend.servers;
frontendTree = pkgs.runCommand "librespeed-frontend" {
speedtestServers = toJSON serversConf;
} ''
mkdir "$out"
cp "${pkgs.librespeed-go}"/assets/* "$out"/
substitute ${./index.html} "$out"/index.html --subst-var speedtestServers
'';
backendConf = pkgs.writers.writeTOML "librespeed.toml" cfg.backend.settings;
generateBackendSettings = base: dst: if (cfg.backend.extraSettingsFile != null) then ''
oldUmask="$(umask)"
umask 006
cat "${base}" "${cfg.backend.extraSettingsFile}" > "${dst}"
umask "$oldUmask"
'' else ''
cp "${base}" "${dst}"
'';
in
{
options.my.librespeed = with lib.types; {
frontend = {
servers = mkOpt' (listOf (attrsOf unspecified)) { } "Server configs.";
webroot = mkOption {
description = "Frontend webroot.";
type = package;
readOnly = true;
};
};
backend = {
enable = mkBoolOpt' false "Whether to enable librespeed backend.";
settings = mkOpt' (attrsOf unspecified) { } "Backend settings.";
extraSettingsFile = mkOpt' (nullOr str) null "Extra settings file.";
};
};
config = mkMerge [
(mkIf (cfg.frontend.servers != { }) {
my.librespeed.frontend.webroot = frontendTree;
})
(mkIf cfg.backend.enable {
my.librespeed.backend.settings = {
assets_path = frontendTree;
database_type = mkDefault "bolt";
database_file = mkDefault "/var/lib/librespeed-go/speedtest.db";
};
systemd.services.librespeed = {
description = "LibreSpeed Go backend";
wants = [ "network-online.target" ];
after = [ "network-online.target" ];
preStart = generateBackendSettings backendConf "/run/librespeed-go/settings.toml";
serviceConfig = {
ExecStart = "${pkgs.librespeed-go}/bin/speedtest -c /run/librespeed-go/settings.toml";
RuntimeDirectory = "librespeed-go";
StateDirectory = "librespeed-go";
};
wantedBy = [ "multi-user.target" ];
};
})
];
}

View File

@@ -0,0 +1,491 @@
<!DOCTYPE html>
<html>
<head>
<link rel="shortcut icon" href="favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, user-scalable=no" />
<meta charset="UTF-8" />
<script type="text/javascript" src="speedtest.js"></script>
<script type="text/javascript">
function I(i){return document.getElementById(i);}
//LIST OF TEST SERVERS. See documentation for details if needed
var SPEEDTEST_SERVERS=@speedtestServers@;
// var SPEEDTEST_SERVERS=[
// { //this server doesn't actually exist, remove it
// name:"Example Server 1", //user friendly name for the server
// server:"//test1.mydomain.com/", //URL to the server. // at the beginning will be replaced with http:// or https:// automatically
// dlURL:"backend/garbage.php", //path to download test on this server (garbage.php or replacement)
// ulURL:"backend/empty.php", //path to upload test on this server (empty.php or replacement)
// pingURL:"backend/empty.php", //path to ping/jitter test on this server (empty.php or replacement)
// getIpURL:"backend/getIP.php" //path to getIP on this server (getIP.php or replacement)
// },
// { //this server doesn't actually exist, remove it
// name:"Example Server 2", //user friendly name for the server
// server:"//test2.example.com/", //URL to the server. // at the beginning will be replaced with http:// or https:// automatically
// dlURL:"garbage.php", //path to download test on this server (garbage.php or replacement)
// ulURL:"empty.php", //path to upload test on this server (empty.php or replacement)
// pingURL:"empty.php", //path to ping/jitter test on this server (empty.php or replacement)
// getIpURL:"getIP.php" //path to getIP on this server (getIP.php or replacement)
// }
// //add other servers here, comma separated
// ];
//INITIALIZE SPEEDTEST
var s=new Speedtest(); //create speed test object
s.setParameter("telemetry_level","basic"); //enable telemetry
//SERVER AUTO SELECTION
function initServers(){
var noServersAvailable=function(){
I("message").innerHTML="No servers available";
}
var runServerSelect=function(){
s.selectServer(function(server){
if(server!=null){ //at least 1 server is available
I("loading").className="hidden"; //hide loading message
//populate server list for manual selection
for(var i=0;i<SPEEDTEST_SERVERS.length;i++){
if(SPEEDTEST_SERVERS[i].pingT==-1) continue;
var option=document.createElement("option");
option.value=i;
option.textContent=SPEEDTEST_SERVERS[i].name;
if(SPEEDTEST_SERVERS[i]===server) option.selected=true;
I("server").appendChild(option);
}
//show test UI
I("testWrapper").className="visible";
initUI();
}else{ //no servers are available, the test cannot proceed
noServersAvailable();
}
});
}
if(typeof SPEEDTEST_SERVERS === "string"){
//need to fetch list of servers from specified URL
s.loadServerList(SPEEDTEST_SERVERS,function(servers){
if(servers==null){ //failed to load server list
noServersAvailable();
}else{ //server list loaded
SPEEDTEST_SERVERS=servers;
runServerSelect();
}
});
}else{
//hardcoded server list
s.addTestPoints(SPEEDTEST_SERVERS);
runServerSelect();
}
}
var meterBk=/Trident.*rv:(\d+\.\d+)/i.test(navigator.userAgent)?"#EAEAEA":"#80808040";
var dlColor="#6060AA",
ulColor="#616161";
var progColor=meterBk;
//CODE FOR GAUGES
function drawMeter(c,amount,bk,fg,progress,prog){
var ctx=c.getContext("2d");
var dp=window.devicePixelRatio||1;
var cw=c.clientWidth*dp, ch=c.clientHeight*dp;
var sizScale=ch*0.0055;
if(c.width==cw&&c.height==ch){
ctx.clearRect(0,0,cw,ch);
}else{
c.width=cw;
c.height=ch;
}
ctx.beginPath();
ctx.strokeStyle=bk;
ctx.lineWidth=12*sizScale;
ctx.arc(c.width/2,c.height-58*sizScale,c.height/1.8-ctx.lineWidth,-Math.PI*1.1,Math.PI*0.1);
ctx.stroke();
ctx.beginPath();
ctx.strokeStyle=fg;
ctx.lineWidth=12*sizScale;
ctx.arc(c.width/2,c.height-58*sizScale,c.height/1.8-ctx.lineWidth,-Math.PI*1.1,amount*Math.PI*1.2-Math.PI*1.1);
ctx.stroke();
if(typeof progress !== "undefined"){
ctx.fillStyle=prog;
ctx.fillRect(c.width*0.3,c.height-16*sizScale,c.width*0.4*progress,4*sizScale);
}
}
function mbpsToAmount(s){
return 1-(1/(Math.pow(1.3,Math.sqrt(s))));
}
function format(d){
d=Number(d);
if(d<10) return d.toFixed(2);
if(d<100) return d.toFixed(1);
return d.toFixed(0);
}
//UI CODE
var uiData=null;
function startStop(){
if(s.getState()==3){
//speed test is running, abort
s.abort();
data=null;
I("startStopBtn").className="";
I("server").disabled=false;
initUI();
}else{
//test is not running, begin
I("startStopBtn").className="running";
I("shareArea").style.display="none";
I("server").disabled=true;
s.onupdate=function(data){
uiData=data;
};
s.onend=function(aborted){
I("startStopBtn").className="";
I("server").disabled=false;
updateUI(true);
if(!aborted){
//if testId is present, show sharing panel, otherwise do nothing
try{
var testId=uiData.testId;
if(testId!=null){
var shareURL=window.location.href.substring(0,window.location.href.lastIndexOf("/"))+"/results/?id="+testId;
I("resultsImg").src=shareURL;
I("resultsURL").value=shareURL;
I("testId").innerHTML=testId;
I("shareArea").style.display="";
}
}catch(e){}
}
};
s.start();
}
}
//this function reads the data sent back by the test and updates the UI
function updateUI(forced){
if(!forced&&s.getState()!=3) return;
if(uiData==null) return;
var status=uiData.testState;
I("ip").textContent=uiData.clientIp;
I("dlText").textContent=(status==1&&uiData.dlStatus==0)?"...":format(uiData.dlStatus);
drawMeter(I("dlMeter"),mbpsToAmount(Number(uiData.dlStatus*(status==1?oscillate():1))),meterBk,dlColor,Number(uiData.dlProgress),progColor);
I("ulText").textContent=(status==3&&uiData.ulStatus==0)?"...":format(uiData.ulStatus);
drawMeter(I("ulMeter"),mbpsToAmount(Number(uiData.ulStatus*(status==3?oscillate():1))),meterBk,ulColor,Number(uiData.ulProgress),progColor);
I("pingText").textContent=format(uiData.pingStatus);
I("jitText").textContent=format(uiData.jitterStatus);
}
function oscillate(){
return 1+0.02*Math.sin(Date.now()/100);
}
//update the UI every frame
window.requestAnimationFrame=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.msRequestAnimationFrame||(function(callback,element){setTimeout(callback,1000/60);});
function frame(){
requestAnimationFrame(frame);
updateUI();
}
frame(); //start frame loop
//function to (re)initialize UI
function initUI(){
drawMeter(I("dlMeter"),0,meterBk,dlColor,0);
drawMeter(I("ulMeter"),0,meterBk,ulColor,0);
I("dlText").textContent="";
I("ulText").textContent="";
I("pingText").textContent="";
I("jitText").textContent="";
I("ip").textContent="";
}
</script>
<style type="text/css">
html,body{
border:none; padding:0; margin:0;
background:#FFFFFF;
color:#202020;
}
body{
text-align:center;
font-family:"Roboto",sans-serif;
}
h1{
color:#404040;
}
#loading{
background-color:#FFFFFF;
color:#404040;
text-align:center;
}
span.loadCircle{
display:inline-block;
width:2em;
height:2em;
vertical-align:middle;
background:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAMAAAD04JH5AAAAP1BMVEUAAAB2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZyFzwnAAAAFHRSTlMAEvRFvX406baecwbf0casimhSHyiwmqgAAADpSURBVHja7dbJbQMxAENRahnN5lkc//5rDRAkDeRgHszXgACJoKiIiIiIiIiIiIiIiIiIiIj4HHspsrpAVhdVVguzrA4OWc10WcEqpwKbnBo0OU1Q5NSpsoJFTgOecrrdEag85DRgktNqfoEdTjnd7hrEHMEJvmRUYJbTYk5Agy6nau6Abp5Cm7mDBtRdPi9gyKdU7w4p1fsLvyqs8hl4z9/w3n/Hmr9WoQ65lAU4d7lMYOz//QboRR5jBZibLMZdAR6O/Vfa1PlxNr3XdS3HzK/HVPRu/KnLs8iAOh993VpRRERERMT/fAN60wwWaVyWwAAAAABJRU5ErkJggg==');
background-size:2em 2em;
margin-right:0.5em;
animation: spin 0.6s linear infinite;
}
@keyframes spin{
0%{transform:rotate(0deg);}
100%{transform:rotate(359deg);}
}
#startStopBtn{
display:inline-block;
margin:0 auto;
color:#6060AA;
background-color:rgba(0,0,0,0);
border:0.15em solid #6060FF;
border-radius:0.3em;
transition:all 0.3s;
box-sizing:border-box;
width:8em; height:3em;
line-height:2.7em;
cursor:pointer;
box-shadow: 0 0 0 rgba(0,0,0,0.1), inset 0 0 0 rgba(0,0,0,0.1);
}
#startStopBtn:hover{
box-shadow: 0 0 2em rgba(0,0,0,0.1), inset 0 0 1em rgba(0,0,0,0.1);
}
#startStopBtn.running{
background-color:#FF3030;
border-color:#FF6060;
color:#FFFFFF;
}
#startStopBtn:before{
content:"Start";
}
#startStopBtn.running:before{
content:"Abort";
}
#serverArea{
margin-top:1em;
}
#server{
font-size:1em;
padding:0.2em;
}
#test{
margin-top:2em;
margin-bottom:12em;
}
div.testArea{
display:inline-block;
width:16em;
height:12.5em;
position:relative;
box-sizing:border-box;
}
div.testArea2{
display:inline-block;
width:14em;
height:7em;
position:relative;
box-sizing:border-box;
text-align:center;
}
div.testArea div.testName{
position:absolute;
top:0.1em; left:0;
width:100%;
font-size:1.4em;
z-index:9;
}
div.testArea2 div.testName{
display:block;
text-align:center;
font-size:1.4em;
}
div.testArea div.meterText{
position:absolute;
bottom:1.55em; left:0;
width:100%;
font-size:2.5em;
z-index:9;
}
div.testArea2 div.meterText{
display:inline-block;
font-size:2.5em;
}
div.meterText:empty:before{
content:"0.00";
}
div.testArea div.unit{
position:absolute;
bottom:2em; left:0;
width:100%;
z-index:9;
}
div.testArea2 div.unit{
display:inline-block;
}
div.testArea canvas{
position:absolute;
top:0; left:0; width:100%; height:100%;
z-index:1;
}
div.testGroup{
display:block;
margin: 0 auto;
}
#shareArea{
width:95%;
max-width:40em;
margin:0 auto;
margin-top:2em;
}
#shareArea > *{
display:block;
width:100%;
height:auto;
margin: 0.25em 0;
}
#privacyPolicy{
position:fixed;
top:2em;
bottom:2em;
left:2em;
right:2em;
overflow-y:auto;
width:auto;
height:auto;
box-shadow:0 0 3em 1em #000000;
z-index:999999;
text-align:left;
background-color:#FFFFFF;
padding:1em;
}
a.privacy{
text-align:center;
font-size:0.8em;
color:#808080;
padding: 0 3em;
}
div.closePrivacyPolicy {
width: 100%;
text-align: center;
}
div.closePrivacyPolicy a.privacy {
padding: 1em 3em;
}
@media all and (max-width:40em){
body{
font-size:0.8em;
}
}
div.visible{
animation: fadeIn 0.4s;
display:block;
}
div.hidden{
animation: fadeOut 0.4s;
display:none;
}
@keyframes fadeIn{
0%{
opacity:0;
}
100%{
opacity:1;
}
}
@keyframes fadeOut{
0%{
display:block;
opacity:1;
}
100%{
display:block;
opacity:0;
}
}
</style>
<title>/dev/player0's speedtest</title>
</head>
<body onload="initServers()">
<h1>/dev/player0's speedtest</h1>
<div id="loading" class="visible">
<p id="message"><span class="loadCircle"></span>Selecting a server...</p>
</div>
<div id="testWrapper" class="hidden">
<div id="startStopBtn" onclick="startStop()"></div><br/>
<a class="privacy" href="#" onclick="I('privacyPolicy').style.display=''">Privacy</a>
<div id="serverArea">
Server: <select id="server" onchange="s.setSelectedServer(SPEEDTEST_SERVERS[this.value])"></select>
</div>
<div id="test">
<div class="testGroup">
<div class="testArea2">
<div class="testName">Ping</div>
<div id="pingText" class="meterText" style="color:#AA6060"></div>
<div class="unit">ms</div>
</div>
<div class="testArea2">
<div class="testName">Jitter</div>
<div id="jitText" class="meterText" style="color:#AA6060"></div>
<div class="unit">ms</div>
</div>
</div>
<div class="testGroup">
<div class="testArea">
<div class="testName">Download</div>
<canvas id="dlMeter" class="meter"></canvas>
<div id="dlText" class="meterText"></div>
<div class="unit">Mbit/s</div>
</div>
<div class="testArea">
<div class="testName">Upload</div>
<canvas id="ulMeter" class="meter"></canvas>
<div id="ulText" class="meterText"></div>
<div class="unit">Mbit/s</div>
</div>
</div>
<div id="ipArea">
<span id="ip"></span>
</div>
<div id="shareArea" style="display:none">
<h3>Share results</h3>
<p>Test ID: <span id="testId"></span></p>
<input type="text" value="" id="resultsURL" readonly="readonly" onclick="this.select();this.focus();this.select();document.execCommand('copy');alert('Link copied')"/>
<img src="" id="resultsImg" />
</div>
</div>
<a href="https://github.com/librespeed/speedtest">Source code</a>
</div>
<div id="privacyPolicy" style="display:none">
<h2>Privacy Policy</h2>
<p>This HTML5 speed test server is configured with telemetry enabled.</p>
<h4>What data we collect</h4>
<p>
At the end of the test, the following data is collected and stored:
<ul>
<li>Test ID</li>
<li>Time of testing</li>
<li>Test results (download and upload speed, ping and jitter)</li>
<li>IP address</li>
<li>ISP information</li>
<li>Approximate location (inferred from IP address, not GPS)</li>
<li>User agent and browser locale</li>
<li>Test log (contains no personal information)</li>
</ul>
</p>
<h4>How we use the data</h4>
<p>
Data collected through this service is used to:
<ul>
<li>Allow sharing of test results (sharable image for forums, etc.)</li>
<li>To improve the service offered to you (for instance, to detect problems on our side)</li>
</ul>
No personal information is disclosed to third parties.
</p>
<h4>Your consent</h4>
<p>
By starting the test, you consent to the terms of this privacy policy.
</p>
<h4>Data removal</h4>
<p>
If you want to have your information deleted, you need to provide either the ID of the test or your IP address. This is the only way to identify your data, without this information we won't be able to comply with your request.<br/><br/>
Contact this email address for all deletion requests: <a href="mailto:dev@nul.ie">dev@nul.ie</a>.
</p>
<br/><br/>
<div class="closePrivacyPolicy">
<a class="privacy" href="#" onclick="I('privacyPolicy').style.display='none'">Close</a>
</div>
<br/>
</div>
</body>
</html>

View File

@@ -480,6 +480,18 @@ in
(mkIf config.services.tailscale.enable {
my.tmproot.persistence.config.directories = [ "/var/lib/tailscale" ];
})
(mkIf config.my.librespeed.backend.enable {
my.tmproot.persistence.config.directories = [ "/var/lib/librespeed-go" ];
})
(mkIf config.services.hedgedoc.enable {
my.tmproot.persistence.config.directories = [
{
directory = "/var/lib/hedgedoc";
user = "hedgedoc";
group = "hedgedoc";
}
];
})
]))
]);

View File

@@ -6,4 +6,6 @@ in
# yeah turns out this is in nixpkgs now... we'll leave it as a sample i guess lol
monocraft' = callPackage ./monocraft.nix { };
vfio-pci-bind = callPackage ./vfio-pci-bind.nix { };
librespeed-go = callPackage ./librespeed-go.nix { };
modrinth-app = callPackage ./modrinth-app { };
}

26
pkgs/librespeed-go.nix Normal file
View File

@@ -0,0 +1,26 @@
{ lib, fetchFromGitHub, buildGoModule, ... }:
let
webSrc = fetchFromGitHub {
owner = "librespeed";
repo = "speedtest";
rev = "5.3.0";
hash = "sha256-OgKGLQcfWX/sBLzaHI6TcJHxX1Wol6K7obLf0+CHrC8=";
};
in
buildGoModule rec {
pname = "librespeed-go";
version = "1.1.5";
src = fetchFromGitHub {
owner = "librespeed";
repo = "speedtest-go";
rev = "v${version}";
hash = "sha256-ywGrodl/mj/WB25F0TKVvaV0PV4lgc+KEj0x/ix9HT8=";
};
vendorHash = "sha256-ev5TEv8u+tx7xIvNaK8b5iq2XXF6I37Fnrr8mb+N2WM=";
postInstall = ''
mkdir -p "$out"/assets
cp "${webSrc}"/{speedtest.js,speedtest_worker.js,favicon.ico} "$out"/assets/
'';
}

6239
pkgs/modrinth-app/Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,97 @@
{ lib
, fetchFromGitHub
, rustPlatform
, pkg-config
, openssl
, libsoup
, dbus
, glib
, glib-networking
, gtk3
, webkitgtk
, libayatana-appindicator
, librsvg
, wrapGAppsHook
, stdenvNoCC
, jq
, moreutils
, nodePackages
, cacert
}:
rustPlatform.buildRustPackage rec {
pname = "modrinth-app";
version = "0.6.3";
src = fetchFromGitHub {
owner = "modrinth";
repo = "theseus";
rev = "v${version}";
hash = "sha256-gFQXcTqHgSKfne6+v837ENXYYiEYu/Yks9TpnfBCPnA=";
};
cargoLock = {
lockFile = ./Cargo.lock;
outputHashes = {
"tauri-plugin-single-instance-0.0.0" = "sha256-G4h2OXKPpZMmradutdUWxGG5axL9XMz2ACAe8AQ40eg=";
};
};
nativeBuildInputs = [
pkg-config
nodePackages.pnpm
wrapGAppsHook
];
buildInputs = [
openssl
libsoup
dbus
glib
glib-networking
gtk3
webkitgtk
libayatana-appindicator
librsvg
];
pnpm-deps = stdenvNoCC.mkDerivation {
pname = "${pname}-pnpm-deps";
inherit src version;
sourceRoot = "${src.name}/theseus_gui";
nativeBuildInputs = [
jq
moreutils
nodePackages.pnpm
cacert
];
installPhase = ''
export HOME=$(mktemp -d)
pnpm config set store-dir $out
pnpm install --ignore-scripts
# Remove timestamp and sort the json files
rm -rf $out/v3/tmp
for f in $(find $out -name "*.json"); do
sed -i -E -e 's/"checkedAt":[0-9]+,//g' $f
jq --sort-keys . $f | sponge $f
done
'';
dontFixup = true;
outputHashMode = "recursive";
outputHash = "sha256-9HtTdIotG3sNIlWhd76v7Ia6P69ufp/FFqZfINXSkVc=";
};
preBuild = ''
cd theseus_gui
export HOME=$(mktemp -d)
pnpm config set store-dir ${pnpm-deps}
pnpm install --ignore-scripts --offline
chmod -R +w node_modules
pnpm rebuild
pnpm build
cd ..
'';
}

View File

@@ -1,30 +1,35 @@
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IERMTWVGZyBMQkxo
YUpuOW5hSFdZYzhBaU5oeFZPRlVoMmNWMEVhQ1VVclJwT2dtdEV3CmIyYStQeFMr
VkI3UjhSVFA1eDRZWXBjVXVxamx3ZDFaOTF0YS9ZVVk1eFEKLT4gc3NoLWVkMjU1
MTkgZ1N4UDBRIEdReTZqdlZkSloyTTV6ZFl1QU1hbU53QlVpM3dFVUlNM25MRFhm
Uk96eHcKbWFOYytZbHd1d21xN2JEdE9xQlU2MDQ1dVNvQmlEQ1dCdDJUdXdNSURG
awotPiBzc2gtZWQyNTUxOSBWRmN3NWcgTURZWU01WS8wZnA0ZXh5L2h3ZHhPUUcy
NEhPUDdUcjVRZjRDUWlJRWJCZwpNakpPdFprVUxoWG1ESi9uZWFxV3RDbEJrbUc5
Q2NsVmx5UnhBclhHSjlZCi0+IFgyNTUxOSArS3JYaklMR3RtSEVhbU5OR2EyY0s4
OW12V09mZGVYYzdtbEdWL1NTdjJFCmU3c25iNG53d21pTHQvTW1TM2hDcG1xZkZq
M2R3QkZyMnMweFdTeVNFLzAKLT4gMz4sWF5JLWdyZWFzZQpmOU9PTTFieDQvbVhL
ZwotLS0gd0R2OHhrekNrWndZQVR4TTg1L21TM09hUWFzU3lLKzg4QXdHbWRhUWFE
dwoRz4OWxG6yPNFZtBgIuHT8fNp9LRfE7KoD4HcpZtnSIIhgjfs6Bw1KTJtDMRM/
EbfhxdRuiRs9GES5RQw1n5+kFjZxD9X2ExbnsOhoqc9fY5w/BWcg467ExIt1svDh
wwXGKxsf7upC0NsvywpArY+FeAslYdpfsbwE7TlmnHSG4ZfvJq42RsMiz2VsoKxl
vgdK97lKWUD9xoWM1KJ0ujej8srRWjQQrWo3m28avgUr7LUHPYNbXcOALn60jsKE
N4pBf9pTO5DD6RHTltpXVPyNU6tewUXbyAFWYEPTF5c18Gsl1sjWxKX9mEHcK9VG
hK+5Bg1ygBJ3Rz0o9IROw/cnE8ukHvutZFzSg/d4VOoRvKxhBCxQfr/dy12e33RN
i3jkTqR8Op3279q5Fpi3Z3Ca23Ts32omRRKHt1wQWg9LnI7MonngJpSV1mWk6Lln
RfSxmMtE2DZ64FUCngV17nPXsNqsJxL/edecRaSYFuHWUSEaJvYxHbRN3/QZgKEi
PKUJ7n4hlVrHM9Dk1ktvgVUhf9bucywMiJZUE5bxP6iIlcdTJQsAbd3FzqM+KUD2
FNEOY28RWPCBhbHtRK8w6a0hSfH3x6/1yBbVWrF7RyJayV6tSUyPMoSKobqSVgZ5
LMZXaZXfvznBdmRHVyZjVtQM+SKcvY7+jguNCHWOltoCOosT1pdN6XWYyi8piNgQ
3nQDScaiEb61z7juzBlwsbFZ1xVRyMYrNeeg3y9JKjJEImxUae59ieSy+JLkIBYC
LtEwCmyvtcxyRtj1uki2DXtnbPP54vA0BIF0g0bw3FCNcjDslt7ruPN6YWPQjWOY
nCeONk9/JoA0ejG8AHK26W/YlvelQVF+qQJv/ODTdQIjjpM/6ftQZrb++m5hIQHD
p8pCNgta3bXYz58XyeM2WPqBKgU/OAC24AeOLgiTW8PdlTPy31Ylb/wNtsUFYqSW
2cPM/hM7Qjq+OAuuhgf2cOxRsx6cX1y9BnWJVRDUwwBTDjVsF+It8AK6RJ9CUL/p
gRI16087ZRMsfYi0qolVX80IQnJnTl6K8hjWhhc0KAUXZSc=
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IERMTWVGZyB3QTU1
TEdvbFNaUmE4U1lCNzI1dlloVDBTNXdURjZ2akRMV0R6dm5ST0FNCk9YclRSakhT
NlV2UVJwak9Fa3dQNTNBK0xKWGlkNXdwZTBEMm4xZzc3azQKLT4gc3NoLWVkMjU1
MTkgakk4UkFnIGNBMHNrdG84cUQxd1lqQmJIczlScU1jNk52Y3BtR2tXeDNWdWRX
cEFCR0UKVU5vem5MZUFPbGhoQzJTYnF4OTd3OW9jYTRkazdocVJkZ0pRRGNLek93
cwotPiBzc2gtZWQyNTUxOSBnU3hQMFEgQ2RUaEUyV1ZGbGRtZnlIUEtTQXk5MUZF
djYxZ0hBUThlV2tXTHNvdXpVSQpMdiswMy9QNUtCb1hkbGRqR0Nia3FXTzE1ajZL
UXljSTZqM2YvbzVuWUFzCi0+IHNzaC1lZDI1NTE5IFZGY3c1ZyBYL1NrRjRaRnFn
RlNLdWJ3cThteDM3WmNaY210d3RmZzhCYmNpVXBwVGlVCjBkM0IzZC9zNjhmTTZV
R25ySkVoQWxQQ252WWFlWWZFMlc5dWtUN3VvVTgKLT4gWDI1NTE5IE8yUU1pWGFr
NzUvZVpwalB6aklkWmJGWUQzTnJiRjNzdzY2MUp6MkY5M1UKR1VIWDVyTFpxem5F
TmRNWE9zZStLanRTdlU5d0NOSEJKdWhDUjBCdy9vOAotPiBTJCd2NyFYey1ncmVh
c2UgfE4mYSBXfms0TC5FPiBiYmx8IGRFV35mciNoCjVZdHRiVUtMMWxEMlJ4b1F1
TGgxY01XTlZpTEtndkg0T0hRVjlqVUJGMUpSaE5tVlZWR3VGenpkUXY2eXJtbmkK
ZCtqRVN4dnZENXdoYkpjNHRWYXkvN2laY1p4YjV0WQotLS0gOHlEVTVOSmlNemNQ
TW5ISk1DeDlEM1RoQ2JtUFlyTXRKQjdnT0hiend2VQqrUFvr+76sKn0ldBmZMlEW
U2k85DLo2KU+/+GtbkZwVXxxIZHMLpoJgghHk9ptdalUgLGcl0X15x9jVaw8aeta
hbeOHotRHY7bC3z0S74riTk3xDMR1eT0QGhDMWHjfo8SkCftOYBlFfhTftevdep3
pKMZsuQMwH9JzxgUfcxIcWE975cZzrEJ85nfWMGvdSjcg51KNxP/UUPRxDlcbCEf
9XX5apSzNsTI3ibGD1n6Qwq8bdVYDMHmy5pAhw4l8L+SdoU1tGdw7JOA16sMCJbx
T4bV0ky/PGRonjJuCyDBj8oe9vMe1ZI1O/ITtktekS+wocxBs6QXlY7pIZMlGUn2
6m59ZEEaf7R4/MdnmBDNDkQuyXaKc7SaTc6h5sKWzXdYScGUKvgUQ7U/WJ2ItUTC
N/Xq07GkZZMt5MYBlyEr+/mKWlcy+ylJPGb7EswvQWaHoeM1QF0XLZ1v+W/Xsso0
seIoz+geSu9a02kwfsa8WvWXdIAT5X2pNGPClVNzjQ23pfQfQuW8ZQrGmIFR4g5A
58T1K+vGLdShqqVGyJFMVrSuOzqX5FVmZalu7/++1IQfiRGUlrHKoPlKWnCfFEOu
AYjaPeEFX2ByxcqfMK1YVPvUufdISUQeaQOO7mXGE3FqB0oUqmRIUiWZATwhq3Pw
p5QdcySTnmMpD/w05hvwski77kCdmYuHlMlLZez/kfhTnIGXris+Vwi/V19bsZ8G
zwaZ/Xr6WNC+df5JqSfTGREnXZPFRDkaTt3ri5/eEm6BqliuYjGbuiKsDECi4+JX
bHpH6LBBoKQ6ms7jCAn0Ls4cUKF37PcjGAOuWnzCSBU+REht1EDfHzx4C7hNiP8X
87NjEqJbwE9lORho0hQJRTn8uriQcidlVoB3se2SYKbMy8UA4NNnxN9PTj0TuQjL
OD3LtqHBElqNPbGNyyEAAJmMBmmkUvPPXlGQ0D99b1+jIdHzYSRtOLshBFykqWYQ
LJD61duhGqcQqcLx4+JdQ+oVcfAI2nG7YINnHB0OmS2DOZvvwqQ7ASScSujUWIjA
LNQxu3ruMz+bw/G0tYZBBiE=
-----END AGE ENCRYPTED FILE-----

View File

@@ -0,0 +1,13 @@
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IFpOcUlvZyBNalB5
RUZRNE1CTUJsbW1kSkxBSWVIcG1RUnBKd1gvcnRQVkZCUXFOQmhvClJUN2ltbnNk
T1grdVJSTzIyNTBTTGVEckVGQXdYNHdwOU5NbW1md3lGM0kKLT4gc3NoLWVkMjU1
MTkgcytxUmZnIHZ4bFZSS0huWFBDbUhNcTd2MFhvV0lOY1l3d3ZXNU4vT3dwMmlI
emhoV0kKcDF4M0FPK0JpclI5Q3Q5WGxpZWVYbHVWbkNWdTArclZsN09XK3VJSXc1
awotPiBYMjU1MTkgRjRCNVZmcXVnQnJ4KzZoM1ZkdWxYUkJTM1JuK3ZlRWJYdkFR
WXpFSmR4NApTbU5qR3ZuN0ZmbzIvMTFsMkdNSGJXSVlrVmZPdnZvcHFiZW45SW9I
endJCi0+IDEoIjlcJi1ncmVhc2UgJUE4IWl5ODkgfGVdLihEfT4gWCAreSduPS4K
bkI2Wm9LRGJXdW11aDl2VgotLS0gTENqYjZEUUZaWVZEcWQvWW5yTzJEdHRLeDJm
QUl5aytXdDE5QVMwVHZVSQo+aDbaGNOrz+hTSUQ4IAjDC9EfNwrlXDZtBqw8HkRv
1/Rr737scjrM7Bgt9zuKn6CB0zdeHTW5u685V2hCW/3aTy1eppWMWj3r
-----END AGE ENCRYPTED FILE-----

View File

@@ -0,0 +1,13 @@
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IFZGY3c1ZyA4N0Qw
bFd4Q01yb3M3M05Ua1BPZjNsK2cwYlBuSUM3TXRaa2hPU2wxb1hzCnhoTzNMYVNT
bjRUTzFJdjdZVG1IVWJNa29PNjVVQ2NWbFdnNWNjcDk1bk0KLT4gWDI1NTE5IGVu
d2x5N21ZaW5MeHBzWkw5QnV0SUNiZTJBVlhXOFZacUFJVktNQXI4MTgKYmxQYmlC
YXJvYjhKbWVZWGRPWWh0eTlIZTJPSFZTZmt4UHJ1M2thNHRCMAotPiBvPls2N3ct
Z3JlYXNlIGowLGEgUFNKKWljTX4gInUKMkFwNGRiZUJCbUZhN2Z3YnZnZ3Nna0tD
UCtrODlldWZ0Rk5INmxTd0tmTGx1NS8rQUtTdVFwSVROcjVqeUJaWAplNWd3SUR5
MjRzeXlyemtka2EwdVZDTkowTk5NMk1rdUxCdkR5ZUJOCi0tLSA4bWVKMXFTalg4
ODFIN0hsTS9lekdWZVI2VTNKYlE3UzhXNk5nM1ZCMlowCn3ZLml2b8qDs+A2W8Nn
YGCfDV+aes39ef/2wu6EMISradXZQrzhSj8JHn7HqsarqSQmOhYP5juawEFxAuZJ
kUc=
-----END AGE ENCRYPTED FILE-----

View File

@@ -1,17 +1,19 @@
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IFZGY3c1ZyBVMkFi
Zkd0SHI1L2M0YTNKU1RXVnFZYlB6T1hFK1B5RWwxYlpkSU9ZVlFRCmRPdWVyNkJ5
VGw0K3ZBeW9mYmVteEt6aW9BaCtiTzhpb0lxdDZMTkJ6NFUKLT4gWDI1NTE5IGlW
UCtQeXg0bXZNMTlBQUVvTXBScDFRcHFSMzVBd2x5ZDJuVTg2cGx0MXMKTFNDbkN4
SDlEcG9BOCt3Nk1yNENxKy9EU1dXVC9yalJ0ekRmc2FvQldmZwotPiA3JzZefHFp
LWdyZWFzZSAlQjUmCmV0dUJQU01RdlZraVdPNFN2YzE2Y3d6eW00RmlZd3Y0eVdu
bHUyVDlCb3dsZSszOFhNb1BIUGZUK2hqaFNkV3oKZDRZMU9UbUZUSURkakNvYU9N
WHJRVVhFT1VUczljZlpiVEZ4bSs0NGhYM0k3N0F5UEVWRXd1blFXZwotLS0gWTIv
NXVUb1RQL2ZhajFnSlJuaVp5c1hOUENnTkloOFJ3ZkFTY3pvdktCOAoFB6muUkj5
xjLe5AQ9bHB2f8DL1U0ijCeHPMHv7fk41jpNAGc0KMxpNboGXxROEu2ZsLN2WJOm
z7LEGHh6bSGP/sBgJnnUMWdsaqToa/JK3d07LzZMevlNxAXOpe/SE3rAEFUnbPKr
UuNYoO2FmyDCAhmdB+HAhb1JUDmmGWEVftrwoCeRg97RE5Rgh/+GT6QJcAct6e3+
QrJqZ9045L644rDqhMHGHAWTjsLX9s8i10WNhFS4x5J5+C9u32eC2xZ/ZjMj4vHU
xkNg/HCL6iDnm/jlSfmrbuTWu70IofWz9gPZy++/Gbf8uM7cICWXU1ujCI+4TIQm
we8GEP0lO4wrGYnzXgXs5cT0V0dV4Jn5
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IGpJOFJBZyA2NGhR
aGJ3RjRaTjlFeUtWa1FZbmdQcGJmbVdxNVkveURqbmdwL2x1RGpVCnY5eTFZRjV3
QVNMZ2xGMHVBek1BaklxUUtiRU5pTU9kWFk1VHhGNE81SFUKLT4gc3NoLWVkMjU1
MTkgVkZjdzVnIElYUmkwbUFPeEExZnJGVWwvUFZsRTdhYkJsSC9CM3hMbGtuSVFs
UGJXQkUKQnc4MGNMM0JZcC9FeG5HeHpLUVFlNE9xelo4Qk1mam5WNlBITnF3WnJs
WQotPiBYMjU1MTkgVkpmUVdBY1p2UDdLcFpXVnJOZGUyZ1VXNVYrUmxkZlpqazRn
cVlLYkt5YwpZSUtIN0RwSEdOSUFYQ0Zsc1NzeUhiQ2Q0T296dmZ3UW5hY1Y1MEJn
MzF3Ci0+ICV5Qy1ncmVhc2UgXSggRWprMCBuCkdKVldUMHozVXlqTVNrUVdyUVd0
MFdSN0dPSVdnT3hMN2NNYVBRSGZnV2k2cVp4NGdjMHBHS0xadC96YmNObEIKUWVH
YWk1Q2tuQUpsV01JWVozbG4rd0ZiN1JHOHRFYVFIenVxOFhXRndrN09lODkvaVhB
eDBoVmxvbU1FbWJrCi0tLSBSeU5TaVZUbmdwdmh1TDVzb0s1eDFvNkVrK1dqTmZG
cDJobU1DZkdHRWhnCvEtMAlEC+BPPYX1YvvcmvRjeOgbuuxzjkGjuB+tT1pBKfYR
9gsHtkPWibhCk546Q1w+fY4StxKmaoxPddBjeQNXh9W6cCQ/vSmxAFya3w5SEtPd
QjozqEVsiwBmBrZgt0UJ96e5hmhmD6zU7fp/RhpFpZv1JrEkhYEz8+jk5Ai96mSg
0pKDAU8xtCnyBBaPiaj2jU/6kiKoGaVXCEuIv0uayRhRp0wap/kf+ToHA/oXVXbl
TZsalOEKH38udhBJiMjRgemqyHQEEpjmYIMWdiTvH6PGZ0yp/09iiEyBCMwzcJAk
nr8HyZKcuzswBcVjRak/raM9lAbpdWWktHxAZa67wsCH017FDrN9e15B2MI8
-----END AGE ENCRYPTED FILE-----

View File

@@ -0,0 +1,14 @@
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IGhrYnR2ZyA3MjM3
dytZeGQ1VmFtdmtEdFlQWG9zMzZLY3psY1NBaVloeUh2VG4xbVVrCjdua1BHajdT
WEpvdTRoTVdTUGpqTzhQWXpEMkxEVzBwQkwwZ21qNkdMVkEKLT4gWDI1NTE5IG9x
d0ViazRzcG1qSDNFR29GcFJtMWxabWRqdnBjQUZBWklyNUZvdjBmMlkKcWhDUGxu
YTZUbEhtMW5pajdpQXYrdEp4NllXRkQ0NWRhc2p5Y1Vub2VjTQotPiBMSTgtZ3Jl
YXNlIHQ3Ngo3enhCRVhiV3N0TlkzdHNMMHJTZ3F5ckc0UUlUa3hCVEZQdTUxaW9p
R2hJRmlxWTZPU2VVbEpvZDZpKzN2NXh0CndxRVM4ZkEKLS0tIHMyTEZJUVRGWlB0
bS9hbjduWWJuVW5KVXpnYlRkMFdCK052RkUvSEdMV1kK4fjaE0yBZXu55Kn1j/yG
PRwEhA9QyNbas21qCikGh8RxCUfoobhlKHpYxyvOMenhv0+8gb3ceXzSUR/3a98Y
orARTVFlOvVZolCwoyC86kUExIBubJxO3EpH2UxrvQoCOrAf5XdD+qzt/G71wpYk
jGUknUWUyPbj9HWoVo2aRmC//bCnena9DUVicAXbDwqr5/KCHHFlkT9UI5Vqvgfw
rPpyZ+De
-----END AGE ENCRYPTED FILE-----

View File

@@ -0,0 +1,64 @@
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IC9FSlh2ZyB2T0Ft
R1o5bEVYRzk3VnpzRDAzK3kzTlNuSTdPVkkrT0l5RjFYT1RuZm5vCjYxN1A1ZFU5
TEE5R01RcnQ2T1k4NXZuc25RTUlvc3NBNnAwemE4YXp2NUUKLT4gWDI1NTE5IGk3
M2lSMXhDWjEvVVBtZnFJdmlnT25OZ1NlOGJwVWo2Qm84L2UxRGxlbU0KaFNzR0sy
clllVC9QSHU2ZDEvQW1KTDlXYlF4aDdUNW5RampTbGtsaHZCUQotPiA4XHJETy1n
cmVhc2UgM1xTMnYmIHJqbEogKgpoVWg1V1ZubElOZVNhazNzdGRrS0tyZFZKNWlo
YW80Ci0tLSBZZXdFT25VVTRnaE5jNnpyaU5OTUdXeE1FZ3djRmpKMG9hdDdodUIw
Z25JCmaCCdtWJR+6PZbGMCKLAYmG2j/YxlrZzAjLR6g3KFQjDhJA6zTCDy8UHQyH
7A0+1Ozu5RBt0kVJiejX+osYYBhFHMEqBJnuB79lmrAg/Pyss3396b1C9hMCZqdo
mkt0knv8wWSI78eMP9DtUQXK0NW4rDf2Wyis9/U4IImlVk5QgkcR1mheF1bgyJt0
t8rr4UBpT8EU85aSGhXC45IkVtAtgA3hsNcptwwcyJT9Hz9obYUnov6tlwD6p4oJ
8tvpTC5p212LBvndr6dvsg3zwlqFfVbkDgsidnIpTTaxqbFi2nHl0F67Ofu17J/l
AWj/5SeiK7k8vDQt+TSTuAF3tuhYvSBYVT/7EHCFzLAnNj/TJFWZf//gH7S/byZW
1XbEqOaUK1mzOESLbwR61hDNfRRRrr85CTx/n8KXvJFzQ+mi1hHJmEbrGzd2tObm
EmCCzcCsupjgFH/exS/o83lleR5zN/BW96Sjh12MbE3OuMjcjZJ7noDv6q9p0gmq
hHMmocC53xxOB00dlUBLmheo6aGyfF+XE7m5FYHVjlIdu2ol43BGGF1Wv13xJ+w+
G5cI+jahrkRpmIk2sLeV+BoCMnEYjOnFc24uya9km0Vz7fo92tK037+kdaFUXjvX
JmWkbbcSb8YcgKzZLhFJiscY+P0xN2hmoai0fNC48Oneu0GqQdftfjiQYJMhp18o
T3IERTLt/JoNIhqZrssg0lKHyt6N47S2A6/X2cT6eMgRrRn43KthPjsmGhRjdFDT
qCuUJJl1L9NX4EqZjXHBZo/bjsbErx2XixN1YbXGnLwN4yUEjE2A/hMbWumzZxp+
ATJgbTYuzim6lachbXsrf4f9sRjDjufMR+evD4lMTmFx+Mg6edBJN6Z2lvLyxJh4
qtw0Uejxn5mYPX1otpTa5tTD5ZSGvMXikDO05ItVcfWKQ7Uohck9cRRbNoJn+dlL
8UuNwmXixH7CkC11w51HTM7HkDW3G3aRTftN2mdfEC2Qr1aGKM+tqLEddja+vDPJ
9Ty8m9nXC5armWO9ewNji4oBEmi0QQK5kasLdQfPBMFupL1a0H2FxtucW2BVW5/K
RQTgJ6ACitcd36+FWtof3HoKyOBqoezguh6P5ImvKgz3mGcq/2AdosgSZ82m4eZp
Ug2KAEgZkR8mdNLujJHD7TZyW2FFq9DAF0Qshg7eD2cK4QA1BdpOrMUTKS5yCHFb
wXJWefnUK5Z9fvGeIN3L4bBjzYBwBfqopBmfDguGx3P7o3Zk42mJ5Z53NTqW0HaF
CN805HzFmNFt9/WV5I4jzVlVgNeep7b3wnH3pLITfz2FpDYU0/URuUNV/th2nJ2+
qH0tTbl1sql/i+kPGHQbyuCbM4IsFo6dZMgCGaovv9jmbJuS3ZmrRQhE/8CUMK6V
YsKi7Heyeza4HDzh9tlddNG+jwkT9/pIWvXChGa3JPokDtJrOoa7P6dV78opfGcT
XJFQbOm0KIH0rISbuWV7I4XEmkEim5TtmaGmsC8NIqgsY7Wjv0pap6vevevU6ImF
w7pxeU0J+5Npm88B+Nyd95Shy/pjRou31W7qTpE95/z89tLKmN3EKL1iDOWhWdCW
VsFS0XC1x7LIpnCXKf1QbnxmQzndSH/oMXmWetCUQ9RPbp8BpiIi+aULe6wzArPb
0Kxs+EEKMhswp4wbZNCmC5X3RRmm4CrmPryb4+rMqWhhTRXri2QvfuOb3IyM46wa
vKZJsCwlb7/2KR+DTwGJDcV9ArX85Yxb6lhHyQqMyHfL8XmnctmejVA+aacWc+dl
2YAwoUo/NnZ28GVjZsImt8ltJlcc8bIW8GwXqqOKPyqdShU6ExxdFRLUhq7o82uK
1oDtxyqI77IbVgQMlrdqL9XRuM3OvGt3rjg51EpDVqY/PUDrFuBkk0eQDNVjaI9e
k5vbMCTjECdiEjQq+ZJsSeVfnEs3pJVqD+vtSIMC2oodxPc2rClrRuhHaCzvUVP0
7LR/2PZlIHzkbwy5sT9W8HOPV3PO/4jPwKRtZQvz8kFiEh2gj8ZfRDELVAV6BOKd
kLrGAEs+dmFOkwfzH7/Mb3hakHe7wqVjSBB4yZqd87zxYK91b8D4io7CemDUidiO
5+6ms829MCro5+ZmS0+ALnc2LTnFWc/bS0TkOdTtwpfCCF/9gbSea85PwDNaB8Vl
M41t15H3oXwjYIwpxvVN/1AWUn3NjbYE7a4ndLccJs//Wyj6nmmnIYc5H5r/BeTD
cHnue35twb4LmiL0MubjQNIyCHdnupCauorfZI6G3yLMXo9Y+Kf8FtkBEZdgD3TB
DC6264ZOkjEtBfYQ2gj2MXDsKGYVRuz7xn80NnvRr0O/KRpN7h8WNw2qmYKMt9Uk
qBgEIe5vyVcAl5cbEcZCQxMKGK6WY96IYmgCV30Bv61hUx9fn6Wc+86o00N/LJY/
O4e8QnRwVntY4IS6hYz3W1BjdzPAB9Bsz33UCznEyreaetRQlOTgg+sEZb1/EbsD
Ia5dDIjmxBc8Lpf3xLTHZkUYKZt4RlNdKCOhn8Ka+0bfpaW3AVWvEolgDl+e66E0
Mk2FzJy5w/+Rgav+Btf1Ol038OcvY2V/5KRcqXK244LIRpHfAd26eXx95DsN5vzc
Ulkt5aWt4awfxnz1SRUZChdoctJlOuiT/pH8S76FpeY+HXbD3vmTW25jHKXq0qqu
9HEuMRbNLcRcIrXoxpI7nfvfLOmtrEkHH+vVQdLauIGOUQKgaKc5PvvOU0ARerUn
1wbu8dSJvrzH2LYKhLZIYONmNaRLLlrGolw+vII3MvZYFTst6TyyXLcVwWcacL/9
k694FKX3TH5Rtbf3SjpJCNhiez/kWcDuWJ4k5hwfpU0MTQPYJRHrrWbHNrq7T0Iv
M40eTeN4mGn0ldcrkMObmMwMWEnPbmNPCsd4RnRG3jsf81UBFTZmMBe6oqW04OI0
u8h9Afhv9JZNx41FHY06WQUWk29Bo++0mWUiRJcDvDFFlnWlied8Fp9iU6ijJjp+
Fma/e3jc88/1rX8FKvYX5d6KEz+VmVW6PWLI2oQz5ydm7zDzJJ9zwzVrBpg3B6hX
m5Q/BfNdAKck4PB9rGfqs+/lPDNgHN7iUVPB95wYf1/jNAqY/I+OT36Hl1LFuSF8
kvOpb4w87BSTFIYBXBQff8xCwyhPHnyuQcSa7qgJDKdUqqMIG9sauzO+a316ZhqG
6LW2eEw1ZLuNl3Tk2ix3WhZWu42pf/uDGTu3DXJC05hGg1KuyvGWDGsIkI6yfNYg
MaHwIg6U+m1+Gva1rcv74vSH0OH4LIcco0F0V8wDA2IdbvPTduNIb4OheWPvReZy
zZZ12JjLSkKZI/qH1kGQTN6GN+NaUdtkr1ElX4H6IRue28Jtrm7pi39WO3J6/xZv
SC80sm3k/emvQ/1RiQbXXjxl3Ma+zcGFqkB93OaG+TbGiNRL5KkXWpP1fDF8zOKV
UkPletJkwnR6wsdEjd6q1ysRTHiDVf1uuSmdGep18QnRqQ==
-----END AGE ENCRYPTED FILE-----

View File

@@ -0,0 +1,10 @@
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IC9FSlh2ZyBEb2hB
cnZBRFZ5OFlvR1ZtSm4zWG1MMjFhQ0VONkk4M2hPQmlaV0tkS21vCm9pWTA4UGtE
dXd4SnFCd3JMeGg3c0ZXZm5Fc1hWdkhxbEQzYVZyMHkyM00KLT4gWDI1NTE5IEwr
MXpubG9nMk1wNFczQ2dUY0NSKzZoR3ZkQlBkbEtOclg3YklWeEYwR1kKZE8wTFND
eDgrbDhNL0ZYYVNCSGRSN1dNSHlmdEVFSnVENnFMVjlOL3k3UQotPiBpNUpIRC1n
cmVhc2UKV0JWMGdmZldNUyswR2tLdUVFRQotLS0gK0E3VFRlVXZqSDQ0ZDBvdjdl
YU1UQkltNUw5ZndVTU1kbVZ6bDlCQjU3NAp0czfiB+B6CH87gdHFh4i6ssbAtjEC
RnlqGXKkw3Lxa66DU0KYewcXcnTQZQSXbaVHin1KXndG7F0Jvz0po70=
-----END AGE ENCRYPTED FILE-----