summaryrefslogtreecommitdiff
path: root/hosts/surtr
diff options
context:
space:
mode:
Diffstat (limited to 'hosts/surtr')
-rw-r--r--hosts/surtr/default.nix2
-rw-r--r--hosts/surtr/dns/default.nix2
-rw-r--r--hosts/surtr/dns/keys/mta-sts.bouncy.email_acme.yaml26
-rw-r--r--hosts/surtr/dns/zones/email.bouncy.soa10
-rw-r--r--hosts/surtr/email/default.nix20
-rw-r--r--hosts/surtr/http/default.nix (renamed from hosts/surtr/http.nix)58
-rw-r--r--hosts/surtr/http/webdav/default.nix96
-rw-r--r--hosts/surtr/http/webdav/py-webdav/.gitignore1
-rw-r--r--hosts/surtr/http/webdav/py-webdav/VERSION1
-rw-r--r--hosts/surtr/http/webdav/py-webdav/setup.py17
-rw-r--r--hosts/surtr/http/webdav/py-webdav/webdav/__init__.py1
-rw-r--r--hosts/surtr/http/webdav/py-webdav/webdav/webdav.py5
-rw-r--r--hosts/surtr/matrix/default.nix8
-rw-r--r--hosts/surtr/tls/tsig_keys/mta-sts.bouncy.email26
14 files changed, 218 insertions, 55 deletions
diff --git a/hosts/surtr/default.nix b/hosts/surtr/default.nix
index c9ecc945..87dd27b0 100644
--- a/hosts/surtr/default.nix
+++ b/hosts/surtr/default.nix
@@ -2,7 +2,7 @@
2{ 2{
3 imports = with flake.nixosModules.systemProfiles; [ 3 imports = with flake.nixosModules.systemProfiles; [
4 qemu-guest openssh rebuild-machines zfs 4 qemu-guest openssh rebuild-machines zfs
5 ./zfs.nix ./dns ./tls ./http.nix ./bifrost ./matrix ./postgresql.nix ./prometheus ./email 5 ./zfs.nix ./dns ./tls ./http ./bifrost ./matrix ./postgresql.nix ./prometheus ./email
6 ]; 6 ];
7 7
8 config = { 8 config = {
diff --git a/hosts/surtr/dns/default.nix b/hosts/surtr/dns/default.nix
index 5b439a8f..808c56da 100644
--- a/hosts/surtr/dns/default.nix
+++ b/hosts/surtr/dns/default.nix
@@ -184,7 +184,7 @@ in {
184 addACLs = { "rheperire.org" = ["ymir_acme_acl"]; }; 184 addACLs = { "rheperire.org" = ["ymir_acme_acl"]; };
185 } 185 }
186 { domain = "bouncy.email"; 186 { domain = "bouncy.email";
187 acmeDomains = ["mailin.bouncy.email" "mailsub.bouncy.email" "imap.bouncy.email" "spm.bouncy.email" "bouncy.email"]; 187 acmeDomains = ["mailin.bouncy.email" "mailsub.bouncy.email" "imap.bouncy.email" "spm.bouncy.email" "mta-sts.bouncy.email" "bouncy.email"];
188 } 188 }
189 ]} 189 ]}
190 ''; 190 '';
diff --git a/hosts/surtr/dns/keys/mta-sts.bouncy.email_acme.yaml b/hosts/surtr/dns/keys/mta-sts.bouncy.email_acme.yaml
new file mode 100644
index 00000000..ee78810d
--- /dev/null
+++ b/hosts/surtr/dns/keys/mta-sts.bouncy.email_acme.yaml
@@ -0,0 +1,26 @@
1{
2 "data": "ENC[AES256_GCM,data:MKHoCzI9odlwPov5Ci9r2IaFCCT7DhOB8EJIFNdgG8xLwdk67SkTQ3kMGXM52EDPWdZ6a90HyKVDgL3O2vl8wbRu49jAIxCYr4t3QhLserNpMikxvAqItivtJKvBL0ah8B4mbjEH1KLou8DZgpDPdL8s+MxTOuYuLBvu/LPGRyabhKVSXmSRIL1iYx7RShe6r2PxiHN6wPmISj9YcwuuWygQRxkEqpybjUQzJe8tYFzuJ19rIUCZ26hI+k3khtFVET4TnouQAdTYXx6I/t/8Q8P7oILPFq4c,iv:w85RawhDWoLtTpWcbHo8W7bXCMa6apQNa4pQLd/whZc=,tag:z3WELFieEDeP9Zrna5brfQ==,type:str]",
3 "sops": {
4 "kms": null,
5 "gcp_kms": null,
6 "azure_kv": null,
7 "hc_vault": null,
8 "age": null,
9 "lastmodified": "2022-07-10T09:38:55Z",
10 "mac": "ENC[AES256_GCM,data:w2Ir2YQgkH0+5jNFW7mHyFVW2VEh98ADI99v6e55U7jKdEn70oF8cv787kMHNqpbwYamO9pSAz14is5Po+n11MH0UxESuU0cE7tfvoaUDIDgHNFVENB9dlKrKmnzXyEbN0+p33EP+/QmKYu4yLGc8t33NqoeD7Mc2McnmXJUvm0=,iv:7N480RaBLjIBXWJZG76VzIEyxm2eIxOi9GoZbGm2H50=,tag:JceWZoMQMwqxTYBRMPRnzA==,type:str]",
11 "pgp": [
12 {
13 "created_at": "2022-07-10T09:38:54Z",
14 "enc": "-----BEGIN PGP MESSAGE-----\n\nhF4DyFKFNkTVG5oSAQdAYwPoDNsPVr3pUAih0sMWoebzWi8KQk6nthYKrBvc5mAw\nnuAjBhLc6Tzr8/vf5JbYcPiopd4qgIbPwqW8KAK28EdAz1+VrfM/mpI3wy0lO2YT\n0l4BQBjlvteoUfgV3nYDVbma7hh78Ip7vn0ebzeYCXbGqfCmhZXuZVG9k9rQ+v5t\nenIL1aLxLOBZSbcuDF415MZvKndU5LoQdciVfsFrex8TVzrYKQ62dBr00uysEgTz\n=TPo8\n-----END PGP MESSAGE-----\n",
15 "fp": "7ED22F4AA7BB55728B643DC5471B7D88E4EF66F8"
16 },
17 {
18 "created_at": "2022-07-10T09:38:54Z",
19 "enc": "-----BEGIN PGP MESSAGE-----\n\nhF4DXxoViZlp6dISAQdAxFqsAJsqWvEmwQiLdSmcVP29dwQF9uLgGCwQCTtjuQYw\njFRrmwCYoCAMM0J7jExm6h7bVwy3pyGeIuya8X1sf6ZRJczGXvGwByK16kVdfgN2\n0l4BAlEaxS/5F6pMNJ0TMdYBMMGJWEa4H0xSE8DkF4Ep5bdxjaY3Pz09m8HWzJRA\nelshtXB8QcFLRG9BQRcPYd4ZEM+HqUCWF1C+7hBJ2SytDSHNZlXtxfd7ey3Jxg8+\n=oqf0\n-----END PGP MESSAGE-----\n",
20 "fp": "30D3453B8CD02FE2A3E7C78C0FB536FB87AE8F51"
21 }
22 ],
23 "unencrypted_suffix": "_unencrypted",
24 "version": "3.7.3"
25 }
26} \ No newline at end of file
diff --git a/hosts/surtr/dns/zones/email.bouncy.soa b/hosts/surtr/dns/zones/email.bouncy.soa
index 77acee8b..271a061e 100644
--- a/hosts/surtr/dns/zones/email.bouncy.soa
+++ b/hosts/surtr/dns/zones/email.bouncy.soa
@@ -1,7 +1,7 @@
1$ORIGIN bouncy.email. 1$ORIGIN bouncy.email.
2$TTL 3600 2$TTL 3600
3@ IN SOA ns.yggdrasil.li. root.yggdrasil.li. ( 3@ IN SOA ns.yggdrasil.li. root.yggdrasil.li. (
4 2022051500 ; serial 4 2022071000 ; serial
5 10800 ; refresh 5 10800 ; refresh
6 3600 ; retry 6 3600 ; retry
7 604800 ; expire 7 604800 ; expire
@@ -63,3 +63,11 @@ spm IN AAAA 2a03:4000:52:ada::
63spm IN MX 0 mailin.bouncy.email. 63spm IN MX 0 mailin.bouncy.email.
64spm IN TXT "v=spf1 redirect=bouncy.email" 64spm IN TXT "v=spf1 redirect=bouncy.email"
65_acme-challenge.spm IN NS ns.yggdrasil.li. 65_acme-challenge.spm IN NS ns.yggdrasil.li.
66
67_mta-sts IN TXT "v=STSv1; id=2022071000"
68_smtp._tls IN TXT "v=TLSRPTv1; rua=mailto:postmaster@bouncy.email"
69mta-sts IN A 202.61.241.61
70mta-sts IN AAAA 2a03:4000:52:ada::
71mta-sts IN MX 0 mailin.bouncy.email.
72mta-sts IN TXT "v=spf1 redirect=bouncy.email"
73_acme-challenge.mta-sts IN NS ns.yggdrasil.li.
diff --git a/hosts/surtr/email/default.nix b/hosts/surtr/email/default.nix
index b952070b..e3437a6b 100644
--- a/hosts/surtr/email/default.nix
+++ b/hosts/surtr/email/default.nix
@@ -580,6 +580,7 @@ in {
580 "mailin.bouncy.email" = {}; 580 "mailin.bouncy.email" = {};
581 "mailsub.bouncy.email" = {}; 581 "mailsub.bouncy.email" = {};
582 "imap.bouncy.email" = {}; 582 "imap.bouncy.email" = {};
583 "mta-sts.bouncy.email" = {};
583 "surtr.yggdrasil.li" = {}; 584 "surtr.yggdrasil.li" = {};
584 } // listToAttrs (map (domain: nameValuePair "spm.${domain}" {}) spmDomains); 585 } // listToAttrs (map (domain: nameValuePair "spm.${domain}" {}) spmDomains);
585 586
@@ -637,13 +638,28 @@ in {
637 proxy_set_header SPM-DOMAIN "${domain}"; 638 proxy_set_header SPM-DOMAIN "${domain}";
638 ''; 639 '';
639 }; 640 };
640 }) spmDomains); 641 }) spmDomains) // {
642 "mta-sts.bouncy.email" = {
643 locations."/".root = pkgs.runCommand "mta-sts" {} ''
644 mkdir -p $out/.well-known
645 cp ${pkgs.writeText "mta-sts.txt" ''
646 version: STSv1
647 mode: testing
648 mx: mailin.bouncy.email
649 max_age: 604800
650 ''} $out/.well-known/mta-sts.txt
651 '';
652 };
653 };
641 }; 654 };
642 655
643 systemd.services.nginx.serviceConfig.LoadCredential = concatMap (domain: [ 656 systemd.services.nginx.serviceConfig.LoadCredential = concatMap (domain: [
644 "spm.${domain}.key.pem:${config.security.acme.certs."spm.${domain}".directory}/key.pem" 657 "spm.${domain}.key.pem:${config.security.acme.certs."spm.${domain}".directory}/key.pem"
645 "spm.${domain}.pem:${config.security.acme.certs."spm.${domain}".directory}/fullchain.pem" 658 "spm.${domain}.pem:${config.security.acme.certs."spm.${domain}".directory}/fullchain.pem"
646 ]) spmDomains; 659 ]) spmDomains ++ [
660 "mta-sts.bouncy.email.key.pem:${config.security.acme.certs."mta-sts.bouncy.email".directory}/key.pem"
661 "mta-sts.bouncy.email.pem:${config.security.acme.certs."mta-sts.bouncy.email".directory}/fullchain.pem"
662 ];
647 663
648 systemd.services.spm = { 664 systemd.services.spm = {
649 serviceConfig = { 665 serviceConfig = {
diff --git a/hosts/surtr/http.nix b/hosts/surtr/http/default.nix
index af27f178..a77252ff 100644
--- a/hosts/surtr/http.nix
+++ b/hosts/surtr/http/default.nix
@@ -1,13 +1,10 @@
1{ config, lib, pkgs, ... }: 1{ config, lib, pkgs, ... }:
2{ 2{
3 imports = [
4 ./webdav
5 ];
6
3 config = { 7 config = {
4 security.pam.services."webdav".text = ''
5 auth requisite pam_succeed_if.so user ingroup webdav quiet_success
6 auth required pam_unix.so likeauth nullok nodelay quiet
7 account sufficient pam_unix.so quiet
8 '';
9 users.groups."webdav" = {};
10
11 services.nginx = { 8 services.nginx = {
12 enable = true; 9 enable = true;
13 # package = pkgs.nginxQuic; 10 # package = pkgs.nginxQuic;
@@ -30,50 +27,12 @@
30 client_body_temp_path /run/nginx-client-bodies; 27 client_body_temp_path /run/nginx-client-bodies;
31 ''; 28 '';
32 additionalModules = with pkgs.nginxModules; [ dav pam ]; 29 additionalModules = with pkgs.nginxModules; [ dav pam ];
33 virtualHosts = {
34 "webdav.141.li" = {
35 forceSSL = true;
36 sslCertificate = "/run/credentials/nginx.service/webdav.141.li.pem";
37 sslCertificateKey = "/run/credentials/nginx.service/webdav.141.li.key.pem";
38 sslTrustedCertificate = "/run/credentials/nginx.service/webdav.141.li.chain.pem";
39 locations."/".extraConfig = ''
40 root /srv/files/$remote_user;
41
42 auth_pam "WebDAV";
43 auth_pam_service_name "webdav";
44 '';
45 extraConfig = ''
46 dav_methods PUT DELETE MKCOL COPY MOVE;
47 dav_ext_methods PROPFIND OPTIONS;
48 dav_access user:rw;
49 autoindex on;
50
51 client_max_body_size 0;
52 create_full_put_path on;
53
54 add_header Strict-Transport-Security "max-age=63072000" always;
55 '';
56 };
57 };
58 };
59 security.acme.domains."webdav.141.li" = {
60 zone = "141.li";
61 certCfg = {
62 postRun = ''
63 ${pkgs.systemd}/bin/systemctl try-restart nginx.service
64 '';
65 };
66 }; 30 };
67 systemd.services.nginx = { 31 systemd.services.nginx = {
68 preStart = lib.mkForce config.services.nginx.preStart; 32 preStart = lib.mkForce config.services.nginx.preStart;
69 serviceConfig = { 33 serviceConfig = {
70 SupplementaryGroups = [ "shadow" ]; 34 SupplementaryGroups = [ "shadow" ];
71 ExecReload = lib.mkForce "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; 35 ExecReload = lib.mkForce "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
72 LoadCredential = [
73 "webdav.141.li.key.pem:${config.security.acme.certs."webdav.141.li".directory}/key.pem"
74 "webdav.141.li.pem:${config.security.acme.certs."webdav.141.li".directory}/fullchain.pem"
75 "webdav.141.li.chain.pem:${config.security.acme.certs."webdav.141.li".directory}/chain.pem"
76 ];
77 RuntimeDirectory = lib.mkForce [ "nginx" "nginx-client-bodies" ]; 36 RuntimeDirectory = lib.mkForce [ "nginx" "nginx-client-bodies" ];
78 RuntimeDirectoryMode = "0750"; 37 RuntimeDirectoryMode = "0750";
79 38
@@ -95,5 +54,14 @@
95 ReadWritePaths = [ "/srv/files" ]; 54 ReadWritePaths = [ "/srv/files" ];
96 }; 55 };
97 }; 56 };
57
58 services.uwsgi = {
59 enable = true;
60 plugins = ["python3"];
61 instance = {
62 type = "emperor";
63 vassals = {};
64 };
65 };
98 }; 66 };
99} 67}
diff --git a/hosts/surtr/http/webdav/default.nix b/hosts/surtr/http/webdav/default.nix
new file mode 100644
index 00000000..f0aec1e9
--- /dev/null
+++ b/hosts/surtr/http/webdav/default.nix
@@ -0,0 +1,96 @@
1{ config, libs, pkgs, flakeInputs, ... }:
2let
3 webdavSocket = config.services.uwsgi.runDir + "/webdav.sock";
4
5 webdavApp = flakeInputs.mach-nix.lib.${config.nixpkgs.system}.buildPythonPackage {
6 ignoreDataOutdated = true;
7 pname = "py-webdav";
8 version = builtins.readFile ./py-webdav/VERSION;
9 src = ./py-webdav;
10 python = "python3";
11 requirements = ''
12 PyNaCl ==1.5.*
13 psycopg ==3.0.*
14 WsgiDAV ==4.0.*
15 '';
16 };
17in {
18 config = {
19 security.pam.services."webdav".text = ''
20 auth requisite pam_succeed_if.so user ingroup webdav quiet_success
21 auth required pam_unix.so likeauth nullok nodelay quiet
22 account sufficient pam_unix.so quiet
23 '';
24 users.groups."webdav" = {};
25
26 services.nginx = {
27 upstreams."py-webdav" = {
28 servers = {
29 "unix://${webdavSocket}" = {};
30 };
31 };
32
33 virtualHosts."webdav.141.li" = {
34 forceSSL = true;
35 sslCertificate = "/run/credentials/nginx.service/webdav.141.li.pem";
36 sslCertificateKey = "/run/credentials/nginx.service/webdav.141.li.key.pem";
37 sslTrustedCertificate = "/run/credentials/nginx.service/webdav.141.li.chain.pem";
38 locations = {
39 "/".extraConfig = ''
40 root /srv/files/$remote_user;
41
42 auth_pam "WebDAV";
43 auth_pam_service_name "webdav";
44 '';
45
46 "/py/".extraConfig = ''
47 rewrite ^/py(.*) $1 break;
48
49 include ${config.services.nginx.package}/conf/uwsgi_params;
50 uwsgi_param SCRIPT_NAME /py;
51 uwsgi_pass py-webdav;
52 '';
53 };
54 extraConfig = ''
55 dav_methods PUT DELETE MKCOL COPY MOVE;
56 dav_ext_methods PROPFIND OPTIONS;
57 dav_access user:rw;
58 autoindex on;
59
60 client_max_body_size 0;
61 create_full_put_path on;
62
63 add_header Strict-Transport-Security "max-age=63072000" always;
64 '';
65 };
66 };
67 security.acme.domains."webdav.141.li" = {
68 certCfg = {
69 postRun = ''
70 ${pkgs.systemd}/bin/systemctl try-restart nginx.service
71 '';
72 };
73 };
74
75 systemd.services.nginx.serviceConfig.LoadCredential = [
76 "webdav.141.li.key.pem:${config.security.acme.certs."webdav.141.li".directory}/key.pem"
77 "webdav.141.li.pem:${config.security.acme.certs."webdav.141.li".directory}/fullchain.pem"
78 "webdav.141.li.chain.pem:${config.security.acme.certs."webdav.141.li".directory}/chain.pem"
79 ];
80
81
82 services.uwsgi.instance.vassals.webdav = {
83 type = "normal";
84 socket = webdavSocket;
85 listen = 1024;
86 master = true;
87 vacuum = true;
88 chown-socket = "${config.services.nginx.user}:${config.services.uwsgi.group}";
89
90 plugins = ["python3"];
91 pythonPackages = self: [webdavApp];
92 module = "webdav";
93 callable = "app";
94 };
95 };
96}
diff --git a/hosts/surtr/http/webdav/py-webdav/.gitignore b/hosts/surtr/http/webdav/py-webdav/.gitignore
new file mode 100644
index 00000000..ed8ebf58
--- /dev/null
+++ b/hosts/surtr/http/webdav/py-webdav/.gitignore
@@ -0,0 +1 @@
__pycache__ \ No newline at end of file
diff --git a/hosts/surtr/http/webdav/py-webdav/VERSION b/hosts/surtr/http/webdav/py-webdav/VERSION
new file mode 100644
index 00000000..6e8bf73a
--- /dev/null
+++ b/hosts/surtr/http/webdav/py-webdav/VERSION
@@ -0,0 +1 @@
0.1.0
diff --git a/hosts/surtr/http/webdav/py-webdav/setup.py b/hosts/surtr/http/webdav/py-webdav/setup.py
new file mode 100644
index 00000000..dbe345c1
--- /dev/null
+++ b/hosts/surtr/http/webdav/py-webdav/setup.py
@@ -0,0 +1,17 @@
1import setuptools
2
3with open('VERSION', 'r', encoding='utf-8') as version_file:
4 version = version_file.read().strip()
5
6setuptools.setup(
7 name="py-webdav",
8 version=version,
9 package_dir={"": "."},
10 packages=setuptools.find_packages(),
11 python_requires=">=3.8",
12 install_requires=[
13 "PyNaCl ==1.5.*",
14 "psycopg ==3.0.*",
15 "WsgiDAV ==4.0.*",
16 ],
17)
diff --git a/hosts/surtr/http/webdav/py-webdav/webdav/__init__.py b/hosts/surtr/http/webdav/py-webdav/webdav/__init__.py
new file mode 100644
index 00000000..398378e2
--- /dev/null
+++ b/hosts/surtr/http/webdav/py-webdav/webdav/__init__.py
@@ -0,0 +1 @@
from .webdav import app
diff --git a/hosts/surtr/http/webdav/py-webdav/webdav/webdav.py b/hosts/surtr/http/webdav/py-webdav/webdav/webdav.py
new file mode 100644
index 00000000..783f5d82
--- /dev/null
+++ b/hosts/surtr/http/webdav/py-webdav/webdav/webdav.py
@@ -0,0 +1,5 @@
1def app(env, start_response):
2 start_response('200 Success', [('Content-Type', 'text/plain; charset=utf-8')])
3 return [ bytes(f'{key}: {value}\n', 'utf8')
4 for key, value in env.items()
5 ]
diff --git a/hosts/surtr/matrix/default.nix b/hosts/surtr/matrix/default.nix
index 9c9c3565..a469be69 100644
--- a/hosts/surtr/matrix/default.nix
+++ b/hosts/surtr/matrix/default.nix
@@ -140,11 +140,9 @@ with lib;
140 services.nginx = { 140 services.nginx = {
141 recommendedProxySettings = true; 141 recommendedProxySettings = true;
142 142
143 upstreams = { 143 upstreams."matrix-synapse" = {
144 "matrix-synapse" = { 144 servers = {
145 servers = { 145 "127.0.0.1:8008" = {};
146 "127.0.0.1:8008" = {};
147 };
148 }; 146 };
149 }; 147 };
150 148
diff --git a/hosts/surtr/tls/tsig_keys/mta-sts.bouncy.email b/hosts/surtr/tls/tsig_keys/mta-sts.bouncy.email
new file mode 100644
index 00000000..ce10db57
--- /dev/null
+++ b/hosts/surtr/tls/tsig_keys/mta-sts.bouncy.email
@@ -0,0 +1,26 @@
1{
2 "data": "ENC[AES256_GCM,data:v0QhyJhcbR+ouKYAxvTYWltoA7vmltvb8oTYs0vecTVMx2j2+UkAjw8xJ4qD,iv:007nDkrj4kvYJMa+W3YysDOXws9UZspC3w5vaTGI/II=,tag:Gzpj7bubRknVBNOfQYvoYg==,type:str]",
3 "sops": {
4 "kms": null,
5 "gcp_kms": null,
6 "azure_kv": null,
7 "hc_vault": null,
8 "age": null,
9 "lastmodified": "2022-07-10T09:39:02Z",
10 "mac": "ENC[AES256_GCM,data:7dvWXtZd++BwWH6Qaw0WzRhxVVT9U8PFyE9MJ1E/NssSfkAZHaxDpV1kgRaHJav4lIjvUq83oWxBkEcnasfg6zF12xawxbCckf597r3ctndGtyyHLk0b0xBciiJRR8rFKeB81nKTiDzEA7ydfgbkPIktB/4xgi4vke5WHWPQ2Xs=,iv:NTTWRPUFvhDL5KndTwPEB4c3NCw6X9nDdWVPcowVN+Y=,tag:BO+TEaTY0RvptmlF9yhQfQ==,type:str]",
11 "pgp": [
12 {
13 "created_at": "2022-07-10T09:39:02Z",
14 "enc": "-----BEGIN PGP MESSAGE-----\n\nhF4DyFKFNkTVG5oSAQdA1eY+DFYwuexG+2C53SzO1qsn60d1UOeBgeBojLbKwSQw\n55k9cM4vYE50bRrnqEfEXn45u2qYj4NIl2WhfJ4luwvNcmLmqvQCKDOKblOEe6Qi\n0l4B6zMGpHNTSkbaKB/Y2zRpczJxRBJz/cEuimbHs57nMQKpFGst5tMvsGilq4tq\nE8iC77K6S+OFJmJulJ/Rw4Yrg+raZ0KkpVKo+hOOKEi2QaWdBLf6dL+NdH2Qpxqu\n=iJRT\n-----END PGP MESSAGE-----\n",
15 "fp": "7ED22F4AA7BB55728B643DC5471B7D88E4EF66F8"
16 },
17 {
18 "created_at": "2022-07-10T09:39:02Z",
19 "enc": "-----BEGIN PGP MESSAGE-----\n\nhF4DXxoViZlp6dISAQdAMl+sivtfp0HDutQ2ENSGsoqeIG1//4F0TrmX3GlFVysw\nSA3Env4jdFAtHplG9/6J6PTtnRZNvnqlwoq3Gz1kEIdf8DhQP7/8uPzi2mJz916n\n0l4BOuQfwtJn/M6a7T4xWW4fPh/CgTD8e0TNV4lYboW/YwAhCgOSaRKnObMzGquR\nJ6Fx6q7+y2Be3zpHdOMHpQ1OmEVmysLRo4DeuV6WYDqSOqSklNMVi6D9b+KIQAJo\n=jbRk\n-----END PGP MESSAGE-----\n",
20 "fp": "30D3453B8CD02FE2A3E7C78C0FB536FB87AE8F51"
21 }
22 ],
23 "unencrypted_suffix": "_unencrypted",
24 "version": "3.7.3"
25 }
26} \ No newline at end of file