diff --git a/nixos/configurations/Cape/default.nix b/nixos/configurations/Cape/default.nix index ee13b5c..33450fc 100644 --- a/nixos/configurations/Cape/default.nix +++ b/nixos/configurations/Cape/default.nix @@ -31,6 +31,7 @@ enable = true; baseDomain = "youthlic.fun"; }; + juicity.server.enable = true; }; }; diff --git a/nixos/configurations/Tytonidae/default.nix b/nixos/configurations/Tytonidae/default.nix index ef6a3c4..0e9a4da 100644 --- a/nixos/configurations/Tytonidae/default.nix +++ b/nixos/configurations/Tytonidae/default.nix @@ -39,6 +39,7 @@ open-webui.enable = true; transmission.enable = true; nix-ld.enable = true; + juicity.client.enable = true; }; gui.enabled = "niri"; }; diff --git a/nixos/modules/programs/dae/config.dae b/nixos/modules/programs/dae/config.dae index 55afa6c..f77c842 100644 --- a/nixos/modules/programs/dae/config.dae +++ b/nixos/modules/programs/dae/config.dae @@ -1,5 +1,6 @@ include { proxy.d/*.dae + local.d/*.dae } global { @@ -43,10 +44,12 @@ dns { group { proxy { filter: subtag(wget) + filter: name(local) policy: min_moving_avg } us { filter: subtag(wget) && name(keyword: "美国") + filter: name(local) policy: min_moving_avg } hk { @@ -59,6 +62,7 @@ group { routing { pname(hickory-dns) && dport(53) -> must_direct pname(mihomo) -> must_direct + pname(juicity-client) -> must_direct # pname(systemd-resolve) -> must_direct dip(107.174.145.140) -> must_direct diff --git a/nixos/modules/programs/dae/default.nix b/nixos/modules/programs/dae/default.nix index 44b7024..08b0b3f 100644 --- a/nixos/modules/programs/dae/default.nix +++ b/nixos/modules/programs/dae/default.nix @@ -14,114 +14,126 @@ in enable = lib.mkEnableOption "dae"; }; }; - config = lib.mkIf cfg.enable { - services.dae = { - enable = true; - openFirewall = { + config = lib.mkMerge [ + (lib.mkIf cfg.enable { + services.dae = { enable = true; - port = 12345; + openFirewall = { + enable = true; + port = 12345; + }; + disableTxChecksumIpGeneric = false; + config = builtins.readFile ./config.dae; }; - disableTxChecksumIpGeneric = false; - config = builtins.readFile ./config.dae; - }; - sops.secrets.url = { - mode = "0444"; - sopsFile = rootPath + "/secrets/general.yaml"; - }; - systemd.services = - let - update = '' - head="user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.182 Safari/537.36" - new_proxy=/etc/dae/proxy.d.new - num=0 - check=1 - urls="$(cat ${config.sops.secrets.url.path})" - mkdir -p ''${new_proxy} - for url in ''${urls}; do - txt=''${new_proxy}/''${num}.txt - config="''${new_proxy}/''${num}.dae" - echo \'curl -LH \""''${head}"\" \""''${url}"\" -o \""''${txt}"\"\' - curl -LH "''${head}" "''${url}" -o "''${txt}" - echo End curl - echo "" > ''${config} - { - echo 'subscription {' - echo \ \ wget:\ \"file://proxy.d/''${num}.txt\" - echo "}" - } >> ''${config} - if [[ ! -s ''${txt} ]]; then - check=0 - fi - chmod 0640 ''${txt} - chmod 0640 ''${config} - num=$((num+1)) + sops.secrets.url = { + mode = "0444"; + sopsFile = rootPath + "/secrets/general.yaml"; + }; + systemd.services = + let + update = '' + head="user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.182 Safari/537.36" + new_proxy=/etc/dae/proxy.d.new + num=0 + check=1 + urls="$(cat ${config.sops.secrets.url.path})" + mkdir -p ''${new_proxy} + for url in ''${urls}; do + txt=''${new_proxy}/''${num}.txt + config="''${new_proxy}/''${num}.dae" + echo \'curl -LH \""''${head}"\" \""''${url}"\" -o \""''${txt}"\"\' + curl -LH "''${head}" "''${url}" -o "''${txt}" + echo End curl + echo "" > ''${config} + { + echo 'subscription {' + echo \ \ wget:\ \"file://proxy.d/''${num}.txt\" + echo "}" + } >> ''${config} + if [[ ! -s ''${txt} ]]; then + check=0 + fi + chmod 0640 ''${txt} + chmod 0640 ''${config} + num=$((num+1)) - if [[ ''${check} -eq 0 ]]; then - echo "''${txt}" is empty - exit 103 + if [[ ''${check} -eq 0 ]]; then + echo "''${txt}" is empty + exit 103 + fi + done + if [[ -d /etc/dae/proxy.d ]]; then + mv /etc/dae/proxy.d /etc/dae/proxy.d.old fi - done - if [[ -d /etc/dae/proxy.d ]]; then - mv /etc/dae/proxy.d /etc/dae/proxy.d.old - fi - mv ''${new_proxy} /etc/dae/proxy.d - ''; - updateScript = pkgs.writeShellApplication { - name = "update.sh"; - runtimeInputs = with pkgs; [ - coreutils - curl - ]; - text = '' - mkdir -p /etc/proxy.d - if [ -z "$(ls -A /etc/dae/proxy.d 2>/dev/null)" ]; then - echo "No subscription file found in /etc/dae/proxy.d. Update now..." + mv ''${new_proxy} /etc/dae/proxy.d + ''; + updateScript = pkgs.writeShellApplication { + name = "update.sh"; + runtimeInputs = with pkgs; [ + coreutils + curl + ]; + text = '' + mkdir -p /etc/proxy.d + if [ -z "$(ls -A /etc/dae/proxy.d 2>/dev/null)" ]; then + echo "No subscription file found in /etc/dae/proxy.d. Update now..." + ${update} + else + echo "Found existing subscription files. Skipping immediate update." + fi + ''; + }; + updateForceScript = pkgs.writeShellApplication { + name = "update-force.sh"; + runtimeInputs = with pkgs; [ + coreutils + curl + ]; + text = '' ${update} - else - echo "Found existing subscription files. Skipping immediate update." - fi - ''; - }; - updateForceScript = pkgs.writeShellApplication { - name = "update-force.sh"; - runtimeInputs = with pkgs; [ - coreutils - curl - ]; - text = '' - ${update} - ''; - }; - in - { - "update-dae-subscription-immediate" = { - after = [ "network-online.target" ]; - wants = [ "network-online.target" ]; - before = [ "dae.service" ]; - serviceConfig = { - Type = "oneshot"; - User = "root"; - ExecStart = [ - "${updateScript}/bin/update.sh" - ]; + ''; }; - wantedBy = [ "multi-user.target" ]; - }; - "update-dae-subscription-force" = { - serviceConfig = { - Type = "oneshot"; - User = "root"; - ExecStartPre = [ - "-${pkgs.systemd}/bin/systemctl stop dae.service" - ]; - ExecStartPost = [ - "-${pkgs.systemd}/bin/systemctl start dae.service" - ]; - ExecStart = [ - "${updateForceScript}/bin/update-force.sh" - ]; + in + { + "update-dae-subscription-immediate" = { + after = [ "network-online.target" ]; + wants = [ "network-online.target" ]; + before = [ "dae.service" ]; + serviceConfig = { + Type = "oneshot"; + User = "root"; + ExecStart = [ + "${updateScript}/bin/update.sh" + ]; + }; + wantedBy = [ "multi-user.target" ]; + }; + "update-dae-subscription-force" = { + serviceConfig = { + Type = "oneshot"; + User = "root"; + ExecStartPre = [ + "-${pkgs.systemd}/bin/systemctl stop dae.service" + ]; + ExecStartPost = [ + "-${pkgs.systemd}/bin/systemctl start dae.service" + ]; + ExecStart = [ + "${updateForceScript}/bin/update-force.sh" + ]; + }; }; }; + }) + (lib.mkIf (cfg.enable && config.youthlic.programs.juicity.client.enable) { + environment.etc."dae/local.d/0.dae" = { + text = '' + node { + local: 'socks5://127.0.0.1:7890/' + } + ''; + mode = "0440"; }; - }; + }) + ]; } diff --git a/nixos/modules/programs/default.nix b/nixos/modules/programs/default.nix index 88fedc8..42d2af1 100644 --- a/nixos/modules/programs/default.nix +++ b/nixos/modules/programs/default.nix @@ -16,5 +16,6 @@ ./transmission.nix ./conduwuit.nix ./nix-ld.nix + ./juicity ]; } diff --git a/nixos/modules/programs/juicity/default.nix b/nixos/modules/programs/juicity/default.nix new file mode 100644 index 0000000..09047f3 --- /dev/null +++ b/nixos/modules/programs/juicity/default.nix @@ -0,0 +1,106 @@ +{ + pkgs, + lib, + config, + ... +}: +let + cfg = config.youthlic.programs.juicity; +in +{ + imports = [ + ./template.nix + ]; + options = { + youthlic.programs.juicity = { + client = { + enable = lib.mkEnableOption "juicity-client"; + }; + server = { + enable = lib.mkEnableOption "juicity-server"; + }; + }; + }; + config = lib.mkMerge [ + (lib.mkIf cfg.client.enable { + users.groups.juicity.members = [ "root" ]; + sops = { + secrets = { + "juicity/serverIp" = { }; + "juicity/sni" = { }; + "juicity/certchainSha256" = { }; + }; + templates."juicity-client-config.json" = { + group = "juicity"; + mode = "0440"; + content = '' + { + "listen": ":7890", + "server": "${config.sops.placeholder."juicity/serverIp"}:23182", + "uuid": "${config.sops.placeholder."juicity/uuid"}", + "password": "${config.sops.placeholder."juicity/password"}", + "sni": "${config.sops.placeholder."juicity/sni"}", + "allow_insecure": false, + "pinned_certchain_sha256": "${config.sops.placeholder."juicity/certchainSha256"}", + "log_level": "info" + } + ''; + }; + }; + services.juicity.client = { + enable = true; + package = pkgs.juicity; + configFile = "${config.sops.templates."juicity-client-config.json".path}"; + allowedOpenFirewallPorts = [ + 7890 + ]; + group = "juicity"; + }; + }) + (lib.mkIf cfg.server.enable { + users.groups.juicity.members = [ "root" ]; + sops = { + secrets = { + "juicity/certificate" = { + group = "juicity"; + mode = "0440"; + }; + "juicity/private_key" = { + group = "juicity"; + mode = "0440"; + }; + }; + templates."juicity-server-config.json" = { + group = "juicity"; + mode = "0440"; + content = '' + { + "listen": ":23182", + "users": { + "${config.sops.placeholder."juicity/uuid"}": "${config.sops.placeholder."juicity/password"}" + }, + "certificate": "${config.sops.secrets."juicity/certificate".path}", + "private_key": "${config.sops.secrets."juicity/private_key".path}", + "log_level": "info" + } + ''; + }; + }; + services.juicity.server = { + enable = true; + package = pkgs.juicity; + configFile = "${config.sops.templates."juicity-server-config.json".path}"; + allowedOpenFirewallPorts = [ + 23182 + ]; + group = "juicity"; + }; + }) + (lib.mkIf (cfg.server.enable || cfg.client.enable) { + sops.secrets = { + "juicity/uuid" = { }; + "juicity/password" = { }; + }; + }) + ]; +} diff --git a/nixos/modules/programs/juicity/template.nix b/nixos/modules/programs/juicity/template.nix new file mode 100644 index 0000000..1d3cefc --- /dev/null +++ b/nixos/modules/programs/juicity/template.nix @@ -0,0 +1,206 @@ +{ + config, + lib, + pkgs, + ... +}: +let + cfg = config.services.juicity; + settingsFormat = pkgs.formats.json { }; + clientConfigFile = + if (cfg.client.configFile != null) then + cfg.client.configFile + else + settingsFormat cfg.client.settings; + serverConfigFile = + if (cfg.server.configFile != null) then + cfg.server.configFile + else + settingsFormat cfg.server.settings; +in +{ + options = { + services.juicity = { + client = { + enable = lib.mkEnableOption "juicity-client"; + package = lib.mkPackageOption pkgs "juicity" { }; + group = lib.mkOption { + type = lib.types.nullOr lib.types.str; + example = "juicity"; + default = null; + }; + settings = lib.mkOption { + type = settingsFormat.type; + default = { }; + example = { + listen = ":1000"; + server = "112.32.62.11:23182"; + uuid = "00000000-0000-0000-0000-000000000000"; + password = "my_password"; + sni = "www.example.com"; + allow_insecure = false; + congestion_control = "bbr"; + log_level = "info"; + }; + description = '' + Juicity client configuration, for configuration options + see example of [client](https://github.com/juicity/juicity/blob/main/install/example-client.json) on github. + ''; + }; + configFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; + example = "/run/juicity/config.json"; + default = null; + description = '' + A file which JSON configurations for juicity client. See the {option}`settings` option for more information. + + Note: this file will override {options}`settings` option, which is recommanded. + ''; + }; + allowedOpenFirewallPorts = lib.mkOption { + type = lib.types.nullOr (lib.types.listOf lib.types.port); + example = [ 23182 ]; + default = null; + description = '' + the ports should be open + ''; + }; + }; + server = { + enable = lib.mkEnableOption "juicity-server"; + package = lib.mkPackageOption pkgs "juicity" { }; + group = lib.mkOption { + type = lib.types.nullOr lib.types.str; + example = "juicity"; + default = null; + }; + settings = lib.mkOption { + type = settingsFormat.type; + default = { }; + description = '' + Juicity server configuration, for configuration options + see example of [server](https://github.com/juicity/juicity/blob/main/install/example-server.json) on github. + ''; + example = { + listen = ":23182"; + users = { + "00000000-0000-0000-0000-000000000000" = "my_password"; + }; + certificate = "/path/to/fullchain.cer"; + private_key = "/path/to/private.key"; + congestion_control = "bbr"; + log_level = "info"; + }; + }; + configFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; + example = "/run/juicity/config.json"; + default = null; + description = '' + A file which JSON configurations for juicity server. See the {option}`settings` option for more information. + + Note: this file will override {options}`settings` option, which is recommanded. + ''; + }; + allowedOpenFirewallPorts = lib.mkOption { + type = lib.types.nullOr (lib.types.listOf lib.types.port); + example = [ 23182 ]; + default = null; + description = '' + the ports should be open + ''; + }; + }; + }; + }; + config = lib.mkMerge [ + (lib.mkIf (cfg.client.enable && (cfg.client.allowedOpenFirewallPorts != null)) { + networking.firewall.allowedTCPPorts = cfg.client.allowedOpenFirewallPorts; + networking.firewall.allowedUDPPorts = cfg.client.allowedOpenFirewallPorts; + }) + (lib.mkIf (cfg.server.enable && (cfg.server.allowedOpenFirewallPorts != null)) { + networking.firewall.allowedTCPPorts = cfg.server.allowedOpenFirewallPorts; + networking.firewall.allowedUDPPorts = cfg.server.allowedOpenFirewallPorts; + }) + (lib.mkIf (cfg.server.enable && (cfg.server.group != null)) { + systemd.services."juicity-server".serviceConfig = { + Group = cfg.server.group; + }; + }) + (lib.mkIf (cfg.client.enable && (cfg.client.group != null)) { + systemd.services."juicity-client".serviceConfig = { + Group = cfg.client.group; + }; + }) + (lib.mkIf cfg.client.enable { + environment.systemPackages = [ + cfg.client.package + ]; + systemd.services.juicity-client = { + description = '' + juicity-client Service + ''; + documentation = [ + "https://github.com/juicity/juicity" + ]; + after = [ + "network.target" + "nss-lookup.target" + ]; + wantedBy = [ + "multi-user.target" + ]; + serviceConfig = { + Type = "simple"; + DynamicUser = true; + CapabilityBoundingSet = [ + "CAP_NET_ADMIN" + "CAP_NET_BIND_SERVICE" + "CAP_NET_RAW" + ]; + AmbientCapabilities = [ + "CAP_NET_ADMIN" + "CAP_NET_BIND_SERVICE" + "CAP_NET_RAW" + ]; + ExecStart = '' + ${lib.getExe' cfg.client.package "juicity-client"} run --disable-timestamp --config ${clientConfigFile} + ''; + Restart = "on-failure"; + LimitNPROC = 512; + LimitNOFILE = "infinity"; + }; + }; + }) + (lib.mkIf cfg.server.enable { + environment.systemPackages = [ + cfg.server.package + ]; + systemd.services.juicity-server = { + description = '' + juicity-server Service + ''; + documentation = [ + "https://github.com/juicity/juicity" + ]; + after = [ + "network.target" + "nss-lookup.target" + ]; + wantedBy = [ + "multi-user.target" + ]; + serviceConfig = { + Type = "simple"; + DynamicUser = true; + ExecStart = '' + ${lib.getExe' cfg.server.package "juicity-server"} run --disable-timestamp --config ${serverConfigFile} + ''; + Restart = "on-failure"; + LimitNPROC = 512; + LimitNOFILE = "infinity"; + }; + }; + }) + ]; +} diff --git a/pkgs/juicity.nix b/pkgs/juicity.nix index 7787cae..a182c33 100644 --- a/pkgs/juicity.nix +++ b/pkgs/juicity.nix @@ -16,9 +16,13 @@ pkgs.buildGoModule rec { "cmd/client" ]; vendorHash = "sha256-uULJKg1nh6jU0uIgDf4GMu8O00zifLvU2wv65dlHLAs="; - postInstallPhase = '' + fixupPhase = '' + runHook preFixup + mv $out/bin/server $out/bin/juicity-server mv $out/bin/client $out/bin/juicity-client + + runHook postFixup ''; ldflags = [ diff --git a/secrets/general.yaml b/secrets/general.yaml index 716e0b3..379ea97 100644 --- a/secrets/general.yaml +++ b/secrets/general.yaml @@ -9,6 +9,14 @@ ssh-private-key: git-credential: ENC[AES256_GCM,data:V86tQJC9Anoe1GEooDZTRsE/n7MPkOIlUYiS4dEYykhnwYtCM8jGPLEYerIwWVhg31zC5JJzhuShDZjj,iv:3D/WmMm3ZLPh8IDChjnruJjKOKvuReB3fjV14B087Ms=,tag:MfjfrqKunGyreM7U1H0MbQ==,type:str] url: ENC[AES256_GCM,data:snv3FaeR8t30rOX9klSNdY/xqcHGXO1DnVi4GMkvyqaII9l/l8AeSlfOVM4qZq8Mqvn01FaiINOE8WPjhyUs9uYp5pfD7X5EXK+5vWwBYmE/isWlHHHNUhuz3UTV/xiSad4n4MiD8wxlF5u8cImwhDyO+SoG,iv:Tay4S5ZFMEIW6MrHnlen85FGvDJ5ZqfVBlgO5MQWufs=,tag:Njywn0i8W7g6cdDvPeJWEg==,type:str] open-webui_env: ENC[AES256_GCM,data:HUoNzOqVuu9MtW4VZJfrh4DbzQCtVYa+FzhDs21FpvImuVz9cue0X8s2MXKqYH0LD1US/DJKL4QLLeNTKVMGxmBOCGxSIgeFejnqK5k/r0GF54SBOURWZn/TyzqxZKAym01DUvfNIe68LhvW1LOHaCDK4zsI9BnhkBVjV8/Vmsc=,iv:4aUgQ6HoLqeuUp01fg+yXQRbH6mS/dakZ1ZUdCZzvAM=,tag:GlFnN5bqIcIZadXmFBkSXA==,type:str] +juicity: + serverIp: ENC[AES256_GCM,data:503ZXoFgXMHBslsuhxgt,iv:mQ9e7w41sLyxd+VLfPIx3vRTOZ5+dhLP17ne0hRqb0k=,tag:h5B6QHXNIhj8o7+9vDMUeg==,type:str] + sni: ENC[AES256_GCM,data:aklDmiQFWinfz2JH0fGdU4gXewg=,iv:HxfJvCS3LaFSZP9jTvVLhqheWxLZy2nXoo6HlxDVJNM=,tag:624zVOOVtMzsASQwHeGBuA==,type:str] + uuid: ENC[AES256_GCM,data:D3TSe0Nn2XLn2vWGlrs0Aem6PFN1J7w4J004IKdEXpT/UexM,iv:f0IdDFAdLkAtjYq/Xs3g0eDDDF0srVqjAc6onVPz3yA=,tag:XV8MdOuSSIfpxixO3xkx3w==,type:str] + password: ENC[AES256_GCM,data:kROa/0HCTFdPXLzbV6AEY3PMyg==,iv:jYunQbnA39BkWuytqgvvgX7G6pCTJQVwL8U+9IzXYqM=,tag:B73rxzXhXVSh7Gz+5ACBuw==,type:str] + certchainSha256: ENC[AES256_GCM,data:HH9ZvGxRAfQ4iS92wK0aLSdTCTlVs2kxczecYbtERmnLFPYX+9MZtsa/JTI=,iv:YCOerzGz2QmxI2CIirOldlzoE3eH33xtOqvT/w/UkJs=,tag:jlecqBa+mkvjva5fCZy8rQ==,type:str] + private_key: ENC[AES256_GCM,data:iCz4zjfAZS7QMmkXAOjgD8qhscbM1cclV66Y6r7NokjRgyCtqzicpD5ndGzacl/EMiE3w2oZ1rABbz4lea5NkQl57zxw+XqclieB6OWy1oHO6Nd1bICt4OiO1plCd3T6MuoN5J33oR7/gywlbwyX+Cw7OsCJWc7fv6pYWe9aSDmUWeugCB/jETZ1tSfmUnQ4KQ6VUPSKGEp5tfDhxwvJ9yqRPMaIMfLz6oK+uEnOvAwgow7v8zjygoZtU5SCJitk014kZEbvnKnGmXPWjz1a/44UZYO/I7bhYiHnQwyoTj8QLue3O3oZ625tSEmoPVfQ9F4CRFm/6bd85r/WbyF44lSPcHNUisnUp3K34F7uLIqqALoK09arCoagYoLiPGyOrtbw+s/KEp6jQHF1WtHy1mY=,iv:V5ElPmaU3TJtLBlZT9lLyutR4Y7IoOmQ0N3k0Vuo1ZM=,tag:JRLyJ71+I1fUL70WtBxaGg==,type:str] + certificate: ENC[AES256_GCM,data:Ed//o+qwlSRI2/VlShb/jKHeQgJkH5hlAM85k8ituty+z619HwBLyBma0OqfmHOpZctyjesIz7Y8nnG1jb8Cju12dyPy9Z5sMbvWgKwLH3k/TTU+e42ZhLFT/ZLpo0HMQo52XXyknJHf4hDbfluSpw/rA6Yp79KGLGtEBGZ2BUIWKSs7W/9KOz9yTX+TGVyU2J4jFuTbCDvPwtpotbVRQkqkNSyc/bvuZCJEyAx8B6y3CfkZPNKw8RHJE43Kyh98BtxoIEv3AJB58qPfhL+1jgLWeKfiCZR9VMAZkI2iXmXrxVc2CV9q8d/FMhUhlZkoGO+5Cg6LooBsurIxm+HZ764zYT1OQJoLw/a4jvxiCjoDSC8eTjTTmRUi0f5le8hSapw/GpVGpvFPGXvmQuintnBjYireLFn6QbeEvgPRQigSUiY4TBRypcD1mEpUdKmfk1UMqyvnRsNwBK2kFf1ji9aW7Afj8ukuI3bZ1yv86OeS1bIDmvXM+OsX6xDZ1w+XLnLWTNGg8xP4iLQszNP4d8mEVfJUa0Df5RTSIfnhyMqC6ByGRLzx2nwkya/AX/LNIjSWIrfxTQ0vt60UQUWgpRVkMsAMNBnMUcAcac0JaWdf0X7y47q9ZQ3LEzYGA9u/s6ZDmabbPD/jnIgfk5SDJ42hMhWHPGA6hsno4OAx+DsBj8V2/FqB3Xntru4wevKFgBCYBLlk6fMrya/atoWee9qYDVKj2OTCGwsU5OZNteVtL0GhqMkQL+VqFOIsYGBNBiRbcJL5FQEpn/mES8o9EDPb5foxpIf2yMx5fbwiHMg3wXCGdZP31wLtdbmojmumIQAGdYhM1LXWy6rVW2T6Uf6myQiijjw8Hcb+v9rnnM+l6idwA4E1OVJCOz8wXBhPXjTwSeJT2TeLRQtlAvdK8hk9Ab9bya8yaixpYZO4QgoaEhRyLv095y99vsI0/4V0vsn4yBpIL7+vuiwKCSQ0lQ==,iv:jXIsYPhSM4NaWcsSS0uANsL9NuMXsVjpgVG8AVq/8KE=,tag:u5y6uH2WlKEbFr0EOopq0w==,type:str] sops: kms: [] gcp_kms: [] @@ -42,8 +50,8 @@ sops: a1Y1NU9CK2h1SS83VW42bzBMa01yMXMKI1DBtgNlkNCrxUQvnD6a45mQKNfg5gM4 Zb5buo9Jofj4dn/HFwng3T3gxKTrP2Dh74CAH4L0M5yrF9fzk5TCcQ== -----END AGE ENCRYPTED FILE----- - lastmodified: "2025-02-01T06:13:38Z" - mac: ENC[AES256_GCM,data:mved7T7oQeafIv0BWDHj3C5KaDLKSlxji93xMxunl39ApbtGjQjDqpQwVQ4z4dcMeggJo0SlX+o0tTi8KzruIjgywR0hQvGJFl8Iq7zyC5YB7ojukRI3ZO71ry1+BWNLOSCrnzIxbX3LijbDkXZ4pkC2lwrqy63P8BUPYNySTQQ=,iv:ukjQB5Ax6GASPXdXJAy+yqiTxtxQxa+wNMo2RYZFEgk=,tag:Z/5ImiyIHFXMozZsY6L9Dw==,type:str] + lastmodified: "2025-02-03T11:00:21Z" + mac: ENC[AES256_GCM,data:tWVQhBcoXzdlC5wQkJ3WHxVSMLOGRqQXjvvNA94BnAgqJgTHymuvLik/8zR2OIskZqzYL0lTXq4OFbm8r552fkx+3+ip45wrtjB0hiSp7lq4lITWnjfZDWr3dBkbFfO2aFij37slpwbVmzGmsM1WaIlfRcauwjOD5IkewiBDY9Y=,iv:GK1WcUSK2WPPplo3uoRJNSmEAPpFObDi784kLuYWtww=,tag:M7YLy1o/bhZPV+bUJ/AQow==,type:str] pgp: [] unencrypted_suffix: _unencrypted version: 3.9.4