Compare changes

Choose any two refs to compare.

-4
.git-crypt/.gitattributes
···
-
# Do not edit this file. To specify the files to encrypt, create your own
-
# .gitattributes file in the directory where your files are.
-
* !filter !diff
-
*.gpg binary
···
.git-crypt/keys/default/0/7595B36DF6C2E95E10E528662932BA0FA3DDD7D6.gpg

This is a binary file and will not be displayed.

-1
.gitattributes
···
-
*.cry filter=git-crypt diff=git-crypt
···
+4
.github/workflows/update-lockfile.yaml
···
name: "Update Flake Lockfile"
on:
workflow_dispatch:
schedule:
···
name: "Update Flake Lockfile"
+
permissions:
+
pull-requests: write
+
contents: write
+
on:
workflow_dispatch:
schedule:
+23
.sops.yaml
···
···
+
keys:
+
# maintainers
+
- &soopyc_mpxl7a age10rkyshu0lswdqyvun4cs9cekm9zt4fw5c8ssa38tn3lukgcahcvsltnqx2
+
- &soopyc_pgp302 8F3B277901484C6EA7E63F82D539637D518022C6
+
# - &soopyc_age302 age1yubikey1qgmfcf0vddslyza7djdekjjk3t3u29d474c5xscmcdye8x3spvhlxxj23xz
+
# failed to parse input as Bech32-encoded age public key: malformed recipient "age1yubikey1qgmfcf0vddslyza7djdekjjk3t3u29d474c5xscmcdye8x3spvhlxxj23xz": invalid type "age1yubikey"
+
+
# Hosts
+
- &koumakan_ssh age18h7hya5terghrwawgpny28swlat2nqkdrfd4clk0svujqlz9xfusd3zeqt
+
+
default_group: &default_group
+
pgp:
+
- *soopyc_pgp302
+
age:
+
# - *soopyc_age302
+
- *soopyc_mpxl7a
+
+
creation_rules:
+
- path_regex: creds/sops/koumakan.yaml
+
key_groups:
+
- <<: *default_group
+
age:
+
- *koumakan_ssh
+2
README.md
···
# Cow
![a yak on some grass](docs/quaritsch-photography-1_6rJHQ2Gmw-unsplash.jpg)
···
+
[![Check and Build configuration](https://github.com/soopyc/nix-on-koumakan/actions/workflows/build.yaml/badge.svg?branch=main)](https://github.com/soopyc/nix-on-koumakan/actions/workflows/build.yaml)
+
# Cow
![a yak on some grass](docs/quaritsch-photography-1_6rJHQ2Gmw-unsplash.jpg)
+3
creds/sops/.gitattributes
···
···
+
# to use, make sure `sops` is in your path and run
+
# git config diff.sopsdiff.textconv "sops -d"
+
*.yaml diff=sopsdiff
+68
creds/sops/koumakan.yaml
···
···
+
comment_unencrypted: See https://github.com/Mic92/sops-nix/issues/120 for synapse.yaml quirks
+
synapse.yaml: ENC[AES256_GCM,data:eQsUW4mwbSPzsoi8HIEngfU5x/PEaqPxvx1AXXJJj7WDX9RsPtQOqQJjuTAEPtz32Hm1nob+VVYuzAXXfCO8Cd0CIHG+xlV4cWNc4JB8wj1YgtMJu9J3yC7iv3HMULT0TL8MxmwWYKqSPKIVarLVN5gQl1G1SAfxEK3ET6qtmkmCD8y6ZVM/84fTR5lxpLe82CaplbUHXEHKk51XwGYLSp5IZsPwtMMFhYuaoqCsEVr65IiSozbD4LKddYNQKUlYmkSfThQsoPpe9ixE7+HS11S+LklyP1q3usWTfOPsQS8k5NJdcGkrCH2A4ddjWkDBAzdav3qauYoQEvbMd8BpoDqD/67lKuvoyXqDoPf5sLrQcxcUl8ObTI1I8zWhabGa9uTuiaTd3wYdMhvMvs/KIfPXNDqcBuIY9sR6LQmY2Zb9+FtYiQVnrr0XmzjB59oN023y1xC/xqkgRyXysndhnj4P1Q+PYbOMQi7hwAjM5xMk/mLkpLn41Ju4u0MqDwHSxA/NXbsEBp/u3Tim2jsrMZqjRZwQHt1n/gtMjm2cMTminM99c/fV2fcvAmcNB9u1KWgEte1JjQSRftg7pkaznYlfrQLyCQYghVu3kgeAJCaSPMewHVWOF/onTauNHYFMlJ8VDUuYOnt2LNJUk1Wap5dGfKm7661mTeYB8aw0h3111YEViuGkSp+oM5A8X6CBI6YsYYOWq5Qd+A3fFJVpcf9hhhdx0JsRmR3EZOupIVx5Y4ruuA6ipj/xMDRNfTZjqukpn3Y1s5xTjUYEo3moLdgd1PYxAVIY/KjPn31pmRThGG1NZpYHZ1yjmptVydtqf/tTd32i3e0WjIjUEZD1NE7Z5AiWJ+XAEaE3S804C6QxN1jHZvqIokA9C4HO+R/es1uDyf2KDvxf1It0hMLg7CAnq1AQcbLCDqXXZaqibSRNfv09lO4jZ3vBe3owvd1wGbK513nqC6m2gh8YDYiHdw7UlXMbMP9+,iv:fvaZQ66VKU+uzvn5AwTIFgzz+F2kJ8/QR2AfmynRfGU=,tag:8c/cAMZ6c7h3J+shh7l7tw==,type:str]
+
matrix-signing-key: ENC[AES256_GCM,data:u6miE2oM3TUXaQ7wc776SwSMaOAxJOVlpl2kBW+AjI/aDH5vcGBp0L0uTpZbVfOtIe+RDNEv5E/mKA==,iv:abvwkrNe324QCbWLwiPY0UwqezS0wbyk2Fvi0vs3SI0=,tag:ZmpDB9LHbezQrxuwHNgpRg==,type:str]
+
akkoma:
+
dist:
+
cookie: ENC[AES256_GCM,data:5jpsa4KsOAoCMGAt9laK9ioVTJfuT9+viKva8wDWRnAimVY6jDoNr4+hxVty6yQAAfSJYA7ddTxaSCEjnJtneg==,iv:V8+MpX/IEc57zEfhNGX5f+eMyipraaXDKPDNDOy0Ieo=,tag:+xCy18Ni8F5wYkO/4NbSzw==,type:str]
+
endpoint:
+
secret_base: ENC[AES256_GCM,data:l34Rj4iIQIykgzTLJolqWLQQz5pcfa0o5U/ZMKeNc2CBQedxiMXYrLSNOx6OuV38aqoOolccJEOSiVjfbTawtg==,iv:/x0ydo2gOPrhIZI7at877bzfFgMpraauozfLq95aHCk=,tag:RQI4aeLiAkAcWYlwLaTj5w==,type:str]
+
salt: ENC[AES256_GCM,data:CP4805tG05A=,iv:aSun7ABJdbDQrFcrGQMM9H1/7d5lJqeMwO08gUYrD2A=,tag:ikhxbijsqyBFJs02j2j/vw==,type:str]
+
live_view:
+
salt: ENC[AES256_GCM,data:4fKLclucoV0=,iv:ZvWKutuMTOm2X8w8a0fOTq+ldrXemayIUY2PUcurY80=,tag:qkIB1gPCI5HO0G0mLEsV+w==,type:str]
+
joken_default_signer: ENC[AES256_GCM,data:myCEFUkf8s1YNQAigjxygRYvbwkpsv7cqgs00fARe9nxSFl2wveWM5JcfOnoVPwVBVV2GaAjFe4oMWXkaTPtqg==,iv:Yk1f/fzzbruW64mvTTeiyTlbrOO/G47CKKfr9BLtQ5g=,tag:QLpM22ec+VWtkjx5U/mzCw==,type:str]
+
search:
+
meili:
+
host_unencrypted: https://megumin.soopy.moe/
+
key: ENC[AES256_GCM,data:00TLCUneHn7NcSK1joURfIzxNFWyOBf/0/fceOn4RMcMt59dZz9LOvbs3F8B0vcH7tf/eUi3SnhYJNyRdPklyw==,iv:t0kQUCmjhFw8Z2CTmYOPUNFvyiYfsXETU8GSxhRR5KE=,tag:CPjtd7jQzgHJDrsIjHlVFQ==,type:str]
+
vapid:
+
pub: ENC[AES256_GCM,data:HYMKjhVCW/7DsMfPPssEduuwWnFezH4OOq4hfAovI82RUPsfVEKhgvkI9INY8hArAb/AIfyyxZhVx+bd2QkPlnASz51L7MxPtkPfZNUKqafjlMmK0nwH,iv:154BP5EmBqnKyf9BND2laKV3caVxa34MCRzrsg6/dik=,tag:wHLYdI6oQXPUzbw8dSxgwg==,type:str]
+
key: ENC[AES256_GCM,data:t+da4NLEPZBMvq3MQkFEr+Fsj3XMGPMFKUWwbHDWNJAyuUZuiVcn3zX0kw==,iv:yQLu5CFl73GCojMBa2II6OhLrNNinsiVG1aPOAx+HtM=,tag:n0oelXaNFvilyee+MRSB8A==,type:str]
+
postgres:
+
hostname: ENC[AES256_GCM,data:rFEnhnn/Bw85,iv:GM2SH4Gkvt8tLG8AYIKxfHTZvB1sT+hgIoqkiViH6Es=,tag:yyGY9/nS9WFcJTGXlYpz6Q==,type:str]
+
database_unencrypted: akkoma
+
username: ENC[AES256_GCM,data:6skzOqv1,iv:OQ6zNmDn0uqKqNKEqOHWY6VBuT/4/CHog7b0Pf0TAPM=,tag:8HLmGykXg2V4t4RHzB8yaA==,type:str]
+
password: ENC[AES256_GCM,data:J3OewVKr2A3TlT7ZUTk7tQr4olFs7bKx47Lus4LGbwGAZfNEmyk9coFTeQ8L/EJ0hpLfPfD1OcGBc+p0ZWK/XQ==,iv:UFe/3H/AfTgSlJikHqE1IED3zINjDuOs5niXpGWXGYE=,tag:MvT0z3TMs1dehg4gp54MyQ==,type:str]
+
smtp:
+
username: ENC[AES256_GCM,data:N7XbQkngWcUGzn/SR4AXCQ==,iv:wBXWtRYawOkjumsvTPcKfvL95CCB+RbsEyJv0YUG3WA=,tag:vGQREe+Cv0ITTxszl21J2g==,type:str]
+
password: ENC[AES256_GCM,data:oU/aWkVmDU8WJhmwqOcXJ/EngiF7hvfUzPwpdjwkyh7Dw50dyG5AY7b2+hh6LIv9RZrN4yU+fXPAYr1W21OG/A==,iv:ds8Bg9JSJdNHUXh0FvD5a4pquyRnIXowcsJcVV1TyB4=,tag:JoYqas2RGSv8xyvJT9wHAQ==,type:str]
+
relay: ENC[AES256_GCM,data:F2NnRLSTO5kmbWy4fx0=,iv:omnyn+Xa/cjqK+9l5bI573aR2p7UsUvqGX5ZQGf3CD0=,tag:t4u/jLQ1nZchyxf3WrhW6w==,type:str]
+
sops:
+
kms: []
+
gcp_kms: []
+
azure_kv: []
+
hc_vault: []
+
age:
+
- recipient: age10rkyshu0lswdqyvun4cs9cekm9zt4fw5c8ssa38tn3lukgcahcvsltnqx2
+
enc: |
+
-----BEGIN AGE ENCRYPTED FILE-----
+
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBYMFBMZHdrR2ZMaEErZVlE
+
RmRZNnoxRVpVSDc5Rlg3MmhiVkxnK1NkNmljCjBsNE5oejcyOTRJRVVvdzJsMmw3
+
SGdyaUM1T0JvN3lDQjd4V054MWc1UjQKLS0tIDVvSndXZ29KSC8yUW5SRjdIcEZL
+
WkFkK1hsdzRnMmRBdDI0dWU3a1hBOEUKf+pJ6PAH1tPLXG14ghG4gxHpVN4D6TU1
+
GHCvsS5qNW8Cjis/Ubb3PHJfFiN4quN3rLaM/Ivkl5G1gzf9cGSDyQ==
+
-----END AGE ENCRYPTED FILE-----
+
- recipient: age18h7hya5terghrwawgpny28swlat2nqkdrfd4clk0svujqlz9xfusd3zeqt
+
enc: |
+
-----BEGIN AGE ENCRYPTED FILE-----
+
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBXbVhFQXJ5ZWVVZTJocmpn
+
Q1VFc01mcnZLRGtqQVF0VjB3RU1DL0phaFVVCkFmU2w3WlhuTDFHYnF5VC9TM0xz
+
VGdSSVpVbkN1Tlh4WnQxdHJkQU42dGMKLS0tIFVnVERoQWk1N1dmdWk0KzA0R1ZG
+
cHJ5aWIrQ2Zrb1dhbC9yZ1lIMU1jbzgK4mx+S5bF6KBMe6+TrSZfaBcuWEg9cHyd
+
tbJty1zxS9pndA/u3qz5EJxDouiAODvyAR07yeegtEcbw1FlG6W/gA==
+
-----END AGE ENCRYPTED FILE-----
+
lastmodified: "2023-09-14T17:13:38Z"
+
mac: ENC[AES256_GCM,data:Jyx0f+w9fJ+B1lz4jVVkcKxd1xUh3FzxDhk+KaxJLVh0BG/1d8Nx0/cOnxZV1FfJkn5Z2wYiLzBPSvJKe8MjlExOSH1mIAnuXcSP6dvXp21bgX17CXM6OP91Ny6IvwSZriqs6EIpWOkZNdxsEnySwtECoQfgs09ZnA4qmbtb01U=,iv:XHnY20d0WsnaECF1/68eu2/xcGLGeGnzba+/kBxDcc0=,tag:alo+8B2fVHon0lHGsQSUyQ==,type:str]
+
pgp:
+
- created_at: "2023-09-08T14:11:19Z"
+
enc: |-
+
-----BEGIN PGP MESSAGE-----
+
+
wV4DAxCcDC4ukRQSAQdA6IXTpPTgsoAuUSW0NqFw4MpqX4j3Wt9IqcGbrDobZGIw
+
FFZDSKuMgO7ADZCFoADJ9OWOQBUyE3htwkXWjT/NQdBbVX3nuANbsfRfTdPN5NJt
+
0lEB30Vck2fEXQsIGrIeg3pPRBl3U/z7F35tw+79EFZ5yOrAsOzSn3wzNA549/T7
+
dEVnej/86D4ZxtMqMjVB2NjsXrphqd7ENozlljMM6QKkjtg=
+
=juKF
+
-----END PGP MESSAGE-----
+
fp: 8F3B277901484C6EA7E63F82D539637D518022C6
+
unencrypted_suffix: _unencrypted
+
version: 3.7.3
+2 -1
creds/ssh/cassie
···
# SmartCards
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGvCpt7yWIptJ9XFBhwVIj9zR30OzkWI976B/P5+0whD cardno:13 901 056
-
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGvCpt7yWIptJ9XFBhwVIj9zR30OzkWI976B/P5+0whD cardno:19 302 295
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICMjRM3BNkLbU57RyfUx7kOlZeBEj/NByr1PfXri82aP cardno:19 302 432
# Static devices
···
+
# If I had an option, I would not use ecdsa keys.
# SmartCards
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGvCpt7yWIptJ9XFBhwVIj9zR30OzkWI976B/P5+0whD cardno:13 901 056
+
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBJxpXpPlPEZPfnw2mIuWJEy/C/5h1bb6pIMeFsHAICQ+lLdEkbBSeDXQuA8feLN0MJw8KaB9jqrJbYgFadV/nVA= YubiKey #19302295 PIV Slot 9a
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICMjRM3BNkLbU57RyfUx7kOlZeBEj/NByr1PfXri82aP cardno:19 302 432
# Static devices
+42 -2
docs/utils.md
···
# utility functions
## `_utils.mkVhost`
-
make virtual host with sensible defaults
pass in a set to override the defaults.
## `_utils.mkSimpleProxy`
make a simple reverse proxy
takes a set:
···
port,
protocol ? "http",
location ? "/",
-
websockets ? false
}
```
···
# utility functions
## `_utils.mkVhost`
+
`attrset -> attrset`
+
make a virtual host with sensible defaults
pass in a set to override the defaults.
+
### Example
+
```nix
+
services.nginx.virtualHosts."balls.example" = _utils.mkVhost {};
+
```
+
## `_utils.mkSimpleProxy`
+
`attrset -> attrset`
+
make a simple reverse proxy
takes a set:
···
port,
protocol ? "http",
location ? "/",
+
websockets ? false,
+
extraConfig ? {}
}
```
+
+
It is recommended to override/add attributes with `extraConfig` to
+
preserve defaults.
+
+
Items in `extraConfig` are merged verbatim to the base attrset with defaults.
+
They are overridden based on their order.
+
+
## `_utils.genSecrets`
+
`namespace[str] -> files[list[str]] -> value[attrset] -> attrset`
+
a
+
generate an attrset to be passed into sops.secrets.
+
+
### Example
+
```nix
+
{ _utils, ... }:
+
let
+
secrets = [
+
"secure_secret"
+
# this is a directory structure, so secrets will be stored as a file in /run/secrets/service/test/secret.
+
"service/test/secret"
+
];
+
in {
+
sops.secrets = _utils.genSecrets "" secrets {}; # it's recommended to use a namespace, but having none is still fine.
+
# -> sops.secrets."secure_secret" = {};
+
# sops.secrets."service/test/secret" = {};
+
sops.secrets = _utils.genSecrets "balls" ["balls_secret"] {owner = "balls"};
+
# -> sops.secrets."balls/balls_secret" = {owner = "balls";};
+
}
+
```
+
+
See https://github.com/soopyc/nix-on-koumakan/blob/b7983776143c15c91df69ef34ba4264a22047ec6/systems/koumakan/services/fedivese/akkoma.nix#L8-L34 for a more extensive example
+45 -7
flake.lock
···
]
},
"locked": {
-
"lastModified": 1693755599,
-
"narHash": "sha256-lNpiE6L0b1SKGTwQES8NNZErV6/rVMVgknpL8l3fv54=",
"owner": "soopyc",
"repo": "mystia",
-
"rev": "1c6c686d0d2e7504fc492b3649a303bb1448b625",
"type": "github"
},
"original": {
···
},
"nixpkgs": {
"locked": {
-
"lastModified": 1693755661,
-
"narHash": "sha256-rnAlLZJsk5z0GAJy+ebNSN9KHiAzE3Q46j2zicZ1dxw=",
"owner": "NixOS",
"repo": "nixpkgs",
-
"rev": "5f16b90e986bc5ae0c0fdaf1ccdbe100bdce6008",
"type": "github"
},
"original": {
···
"type": "github"
}
},
"pre-commit-hooks-nix": {
"inputs": {
"flake-compat": [
···
"home-manager": "home-manager",
"lanzaboote": "lanzaboote",
"mystia": "mystia",
-
"nixpkgs": "nixpkgs"
}
},
"rust-overlay": {
···
"original": {
"owner": "oxalica",
"repo": "rust-overlay",
"type": "github"
}
},
···
]
},
"locked": {
+
"lastModified": 1694357290,
+
"narHash": "sha256-Mai5saiiuBWlQzTreLtIeUJQJN9zMH/UBIKJPOqnasM=",
"owner": "soopyc",
"repo": "mystia",
+
"rev": "cfe783698ccd18cb27fb2e422917f14b82f7afc4",
"type": "github"
},
"original": {
···
},
"nixpkgs": {
"locked": {
+
"lastModified": 1694237756,
+
"narHash": "sha256-8T29BDnqRexwVy3jhEzIH9r7ROiF9I6ESVD0QLC6VXk=",
"owner": "NixOS",
"repo": "nixpkgs",
+
"rev": "1a5bda2b28ea75a96dda2c349fe6d5e7864950ee",
"type": "github"
},
"original": {
···
"type": "github"
}
},
+
"nixpkgs-stable_3": {
+
"locked": {
+
"lastModified": 1693675694,
+
"narHash": "sha256-2pIOyQwGyy2FtFAUIb8YeKVmOCcPOTVphbAvmshudLE=",
+
"owner": "NixOS",
+
"repo": "nixpkgs",
+
"rev": "5601118d39ca9105f8e7b39d4c221d3388c0419d",
+
"type": "github"
+
},
+
"original": {
+
"owner": "NixOS",
+
"ref": "release-23.05",
+
"repo": "nixpkgs",
+
"type": "github"
+
}
+
},
"pre-commit-hooks-nix": {
"inputs": {
"flake-compat": [
···
"home-manager": "home-manager",
"lanzaboote": "lanzaboote",
"mystia": "mystia",
+
"nixpkgs": "nixpkgs",
+
"sops-nix": "sops-nix"
}
},
"rust-overlay": {
···
"original": {
"owner": "oxalica",
"repo": "rust-overlay",
+
"type": "github"
+
}
+
},
+
"sops-nix": {
+
"inputs": {
+
"nixpkgs": [
+
"nixpkgs"
+
],
+
"nixpkgs-stable": "nixpkgs-stable_3"
+
},
+
"locked": {
+
"lastModified": 1693898833,
+
"narHash": "sha256-OIrMAGNYNeLs6IvBynxcXub7aSW3GEUvWNsb7zx6zuU=",
+
"owner": "Mic92",
+
"repo": "sops-nix",
+
"rev": "faf21ac162173c2deb54e5fdeed002a9bd6e8623",
+
"type": "github"
+
},
+
"original": {
+
"owner": "Mic92",
+
"repo": "sops-nix",
"type": "github"
}
},
+8 -2
flake.nix
···
url = "github:zhaofengli/attic";
inputs.nixpkgs.follows = "nixpkgs";
};
mystia = {
url = "github:soopyc/mystia";
inputs.nixpkgs.follows = "nixpkgs";
···
home-manager,
...
} @ inputs: let
-
_utils = import ./global/utils.nix {};
lib = nixpkgs.lib;
systems = [
···
forAllSystems = fn: lib.genAttrs systems (s: fn nixpkgs.legacyPackages.${s});
in {
nixosConfigurations = {
-
koumakan = import ./systems/koumakan {inherit _utils lib inputs;};
};
devShells = forAllSystems (pkgs: {
···
url = "github:zhaofengli/attic";
inputs.nixpkgs.follows = "nixpkgs";
};
+
+
sops-nix = {
+
url = "github:Mic92/sops-nix";
+
inputs.nixpkgs.follows = "nixpkgs";
+
};
+
mystia = {
url = "github:soopyc/mystia";
inputs.nixpkgs.follows = "nixpkgs";
···
home-manager,
...
} @ inputs: let
+
utils = import ./global/utils.nix;
lib = nixpkgs.lib;
systems = [
···
forAllSystems = fn: lib.genAttrs systems (s: fn nixpkgs.legacyPackages.${s});
in {
nixosConfigurations = {
+
koumakan = import ./systems/koumakan {inherit utils lib inputs;};
};
devShells = forAllSystems (pkgs: {
+2 -7
global/core.nix
···
{pkgs, ...}: {
imports = [
./upgrade-diff.nix
];
# Set default i18n configuration
i18n.defaultLocale = "en_US.UTF-8";
···
keyMap = "us";
};
-
hardware.enableRedistributableFirmware = true;
-
-
# # Enable crash dumps globally
-
# boot.crashDump = {
-
# enable = true;
-
# reservedMemory = "128M";
-
# };
# Lock root account
users.users.root.shell = pkgs.shadow; # basically /bin/nologin
···
{pkgs, ...}: {
imports = [
./upgrade-diff.nix
+
./system
];
# Set default i18n configuration
i18n.defaultLocale = "en_US.UTF-8";
···
keyMap = "us";
};
+
time.timeZone = "Asia/Hong_Kong";
# Lock root account
users.users.root.shell = pkgs.shadow; # basically /bin/nologin
+5
global/overlays/default.nix
···
···
+
inputs:
+
with inputs; [
+
mystia.overlays.default
+
attic.overlays.default
+
]
+1
global/programs/misc.nix
···
nvd
just
git-crypt
];
···
nvd
just
+
attic
git-crypt
];
+1
global/programs/nix.nix
···
experimental-features = [
"nix-command"
"flakes"
];
substituters = [
···
experimental-features = [
"nix-command"
"flakes"
+
"repl-flake"
];
substituters = [
+5
global/system/default.nix
···
···
+
{...}: {
+
imports = [
+
./firmware.nix
+
];
+
}
+4
global/system/firmware.nix
···
···
+
{...}: {
+
hardware.enableRedistributableFirmware = true;
+
services.fwupd.enable = true;
+
}
+39 -18
global/utils.nix
···
# see /docs/utils.md for a usage guide
-
{...}:
-
# let
-
# lib = pkgs.lib;
-
# in
-
rec {
mkVhost = opts:
-
{
-
# ideally mkOverride/mkDefault would be used, but i have 0 idea how it works.
-
forceSSL = true;
-
useACMEHost = "global.c.soopy.moe";
-
kTLS = true;
-
}
-
// opts;
mkSimpleProxy = {
port,
protocol ? "http",
location ? "/",
websockets ? false,
}:
-
mkVhost {
-
locations."${location}" = {
-
proxyPass = "${protocol}://localhost:${toString port}";
-
proxyWebsockets = websockets;
-
};
-
};
}
···
# see /docs/utils.md for a usage guide
+
{
+
inputs,
+
system,
+
...
+
}: let
+
lib = inputs.nixpkgs.lib;
+
in rec {
mkVhost = opts:
+
lib.mkMerge [
+
{
+
forceSSL = lib.mkDefault true;
+
useACMEHost = lib.mkDefault "global.c.soopy.moe";
+
kTLS = lib.mkDefault true;
+
+
locations."/_cgi/error/" = {
+
alias = "${inputs.mystia.packages.${system}.staticly}/nginx_error_pages/";
+
};
+
extraConfig = ''
+
error_page 503 /_cgi/error/503.html;
+
error_page 502 /_cgi/error/502.html;
+
error_page 404 /_cgi/error/404.html;
+
'';
+
}
+
opts
+
];
mkSimpleProxy = {
port,
protocol ? "http",
location ? "/",
websockets ? false,
+
extraConfig ? {},
}:
+
mkVhost (lib.mkMerge [
+
extraConfig
+
{
+
locations."${location}" = {
+
proxyPass = "${protocol}://localhost:${toString port}";
+
proxyWebsockets = websockets;
+
};
+
}
+
]);
+
+
genSecrets = namespace: files: value:
+
lib.genAttrs (
+
map (x: namespace + lib.optionalString (lib.stringLength namespace != 0) "/" + x) files
+
) (_: value);
}
+11 -4
justfile
···
# friendship ended with Makefile
# I LOVE justFILE!!!!!!
-
default: build
test:
nixos-rebuild test --flake .#
-
build:
-
nixos-rebuild build --flake .#
-
switch:
nixos-rebuild switch --flake .#
utils recipe="list":
@echo "Running utils/{{recipe}}"
@cd utils && just {{recipe}}
ebuild system:
nix build -j8 .#nixosConfigurations."{{system}}".config.system.build.toplevel
···
# friendship ended with Makefile
# I LOVE justFILE!!!!!!
+
# build the current configuration
+
build:
+
nixos-rebuild build --flake .#
+
# build and test the configuration, but don't switch
test:
nixos-rebuild test --flake .#
+
# switch to the current configuration
switch:
nixos-rebuild switch --flake .#
+
# run utility programs
utils recipe="list":
@echo "Running utils/{{recipe}}"
@cd utils && just {{recipe}}
+
# update an input in the flake lockfile
+
update-input input:
+
nix flake lock --update-input {{input}}
+
+
# build the flake on a non-nixos platform
ebuild system:
nix build -j8 .#nixosConfigurations."{{system}}".config.system.build.toplevel
-1
overlays/default.nix
···
-
[]
···
+1
systems/koumakan/certificates/default.nix
···
imports = [
./global.nix
./postgresql.nix
];
security.acme = {
···
imports = [
./global.nix
./postgresql.nix
+
./fediverse.nix
];
security.acme = {
+11
systems/koumakan/certificates/fediverse.nix
···
···
+
{...}: {
+
# Certificate for fedi services
+
security.acme.certs."fedi.c.soopy.moe" = {
+
group = "nginx";
+
extraDomainNames = [
+
"a.soopy.moe"
+
"m.soopy.moe"
+
"pixie.soopy.moe"
+
];
+
};
+
}
+15 -24
systems/koumakan/configuration.nix
···
-
# Edit this configuration file to define what should be installed on
-
# your system. Help is available in the configuration.nix(5) man page
-
# and in the NixOS manual (accessible by running `nixos-help`).
{inputs, ...}: {
imports = [
# Include the results of the hardware scan.
···
./services
];
-
nixpkgs.overlays =
-
import ../../overlays
-
++ (with inputs; [
-
mystia.overlays.default
-
attic.overlays.default
-
]);
-
boot.loader.efi = {
-
canTouchEfiVariables = true;
-
efiSysMountPoint = "/boot/efi";
-
};
-
-
boot.loader.systemd-boot = {
-
enable = true;
-
graceful = true;
-
netbootxyz.enable = true;
};
-
boot.loader.grub = {
-
enable = false;
-
};
-
-
time.timeZone = "Asia/Hong_Kong";
-
# Define a user account. Don't forget to set a password with โ€˜passwdโ€™.
users.users.cassie = {
isNormalUser = true;
···
};
# packages = with pkgs; [];
};
# Just don't change this :p
system.stateVersion = "23.05"; # Did you read the comment?
···
{inputs, ...}: {
imports = [
# Include the results of the hardware scan.
···
./services
];
+
nixpkgs.overlays = import ../../global/overlays inputs;
+
boot.loader = {
+
efi = {
+
canTouchEfiVariables = true;
+
efiSysMountPoint = "/boot/efi";
+
};
+
systemd-boot = {
+
enable = true;
+
graceful = true;
+
netbootxyz.enable = true;
+
};
+
grub.enable = false;
};
# Define a user account. Don't forget to set a password with โ€˜passwdโ€™.
users.users.cassie = {
isNormalUser = true;
···
};
# packages = with pkgs; [];
};
+
+
sops.age.sshKeyPaths = ["/etc/ssh/ssh_host_ed25519_key"];
+
sops.defaultSopsFile = ../../creds/sops/koumakan.yaml;
# Just don't change this :p
system.stateVersion = "23.05"; # Did you read the comment?
+7 -2
systems/koumakan/default.nix
···
{
lib,
-
_utils,
inputs,
...
}:
···
# see docs/tips_n_tricks.md#extra_opts for syntax
# see docs/utils.md for functions
specialArgs = {
-
inherit inputs _utils;
};
modules = [
inputs.lanzaboote.nixosModules.lanzaboote
inputs.attic.nixosModules.atticd
./configuration.nix
];
···
{
lib,
+
utils,
inputs,
...
}:
···
# see docs/tips_n_tricks.md#extra_opts for syntax
# see docs/utils.md for functions
specialArgs = {
+
inherit inputs;
+
_utils = utils {
+
inherit inputs;
+
system = "x86_64-linux";
+
};
};
modules = [
inputs.lanzaboote.nixosModules.lanzaboote
inputs.attic.nixosModules.atticd
+
inputs.sops-nix.nixosModules.sops
./configuration.nix
];
+1 -1
systems/koumakan/networking/interface.nix
···
{...}: {
-
networking.networkmanager.ethernet.macAddress = builtins.readFile ./nma.cry;
}
···
{...}: {
+
networking.networkmanager.ethernet.macAddress = "stable";
}
systems/koumakan/networking/nma.cry

This is a binary file and will not be displayed.

+1 -1
systems/koumakan/security/pam.nix
···
{...}: {
security.pam.yubico = {
enable = true;
-
id = builtins.readFile ./ykid.cry;
mode = "client";
control = "requisite";
};
···
{...}: {
security.pam.yubico = {
enable = true;
+
id = "91582";
mode = "client";
control = "requisite";
};
systems/koumakan/security/ykid.cry

This is a binary file and will not be displayed.

+4 -3
systems/koumakan/services/attic.nix
···
};
};
-
services.nginx.virtualHosts."nonbunary.soopy.moe" =
-
_utils.mkSimpleProxy {port = 38191;}
-
// {
extraConfig = ''
client_max_body_size 1G;
proxy_read_timeout 3h;
···
proxy_send_timeout 3h;
'';
};
}
···
};
};
+
services.nginx.virtualHosts."nonbunary.soopy.moe" = _utils.mkSimpleProxy {
+
port = 38191;
+
extraConfig = {
extraConfig = ''
client_max_body_size 1G;
proxy_read_timeout 3h;
···
proxy_send_timeout 3h;
'';
};
+
};
}
+6
systems/koumakan/services/databases/default.nix
···
···
+
{...}: {
+
imports = [
+
./postgresql.nix
+
./redis.nix
+
];
+
}
+40
systems/koumakan/services/databases/postgresql.nix
···
···
+
{pkgs, ...}: {
+
services.postgresql = {
+
enable = true;
+
+
package = pkgs.postgresql_15;
+
dataDir = "/var/lib/postgresql/15";
+
logLinePrefix = "%m [%p] %h ";
+
+
authentication = ''
+
# unix socket connection
+
local all all peer
+
# local ipv4/6 tcp connection
+
host all all 127.0.0.1/32 scram-sha-256
+
host all all ::1/128 scram-sha-256
+
# world (encrypted) tcp traffic
+
hostssl all all all scram-sha-256
+
'';
+
+
settings = let
+
credsDir = "/run/credentials/postgresql.service";
+
in {
+
listen_addresses = pkgs.lib.mkForce "*";
+
max_connections = 200;
+
password_encryption = "scram-sha-256";
+
+
ssl = "on";
+
ssl_cert_file = "${credsDir}/cert.pem";
+
ssl_key_file = "${credsDir}/key.pem";
+
+
log_hostname = true;
+
datestyle = "iso, dmy";
+
log_timezone = "Asia/Hong_Kong";
+
timezone = "Asia/Hong_Kong";
+
default_text_search_config = "pc_catalog.english";
+
+
max_wal_size = "2GB";
+
min_wal_size = "80MB";
+
};
+
};
+
}
+5
systems/koumakan/services/databases/redis.nix
···
···
+
{...}: {
+
services.redis.servers."" = {
+
enable = true;
+
};
+
}
+5 -3
systems/koumakan/services/default.nix
···
imports = [
./nginx.nix
-
# databases
-
./postgresql.nix
-
./redis.nix
./attic.nix
./proxies
./static-sites
···
imports = [
./nginx.nix
+
./databases
./attic.nix
+
+
# fediverse
+
./matrix
+
./fediverse
./proxies
./static-sites
+150
systems/koumakan/services/fediverse/akkoma.nix
···
···
+
{
+
_utils,
+
pkgs,
+
config,
+
lib,
+
...
+
}: let
+
mkRaw = (pkgs.formats.elixirConf {}).lib.mkRaw;
+
# I don't know what i did but i made this abomination
+
mkSecret = file:
+
if !lib.elem file secrets
+
then throw "Provided secret file ${file} is not in the list of defined secrets."
+
else {_secret = "/run/secrets/akkoma/${file}";};
+
secrets = [
+
"joken_default_signer" # can't think of any better name spacing
+
"dist/cookie"
+
"search/meili/host_unencrypted"
+
"search/meili/key"
+
"endpoint/secret_base"
+
"endpoint/salt"
+
"endpoint/live_view/salt"
+
"vapid/pub"
+
"vapid/key"
+
"postgres/hostname"
+
"postgres/database_unencrypted"
+
"postgres/username"
+
"postgres/password"
+
"smtp/username"
+
"smtp/password"
+
"smtp/relay"
+
];
+
in {
+
# secrets definition
+
sops.secrets = _utils.genSecrets "akkoma" secrets {};
+
+
services.akkoma = {
+
enable = true;
+
initSecrets = false;
+
initDb.enable = false;
+
# TODO: figure out how to add swagger ui
+
# frontends = {
+
# swagger
+
# };
+
+
# TODO: Issue #5
+
dist.cookie = mkSecret "dist/cookie";
+
config = {
+
":joken".":default_signer" = mkSecret "joken_default_signer";
+
+
":pleroma" = {
+
":http_security" = {
+
sts = true;
+
};
+
+
":configurable_from_database" = true;
+
":instance" = {
+
name = "CassieAkko";
+
description = "You should not see this here...";
+
email = "me@soopy.moe";
+
notify_email = "noreply@a.soopy.moe";
+
limit = 5000;
+
registrations_open = true;
+
};
+
+
# TODO: add proper proxy support
+
# also refer to https://meta.akkoma.dev/t/another-vector-for-the-injection-vulnerability-found/483
+
":media_proxy" = {
+
enabled = true;
+
redirect_on_failure = true;
+
};
+
+
"Pleroma.Repo" = {
+
adapter = mkRaw "Ecto.Adapters.Postgres";
+
database = mkSecret "postgres/database_unencrypted";
+
hostname = mkSecret "postgres/hostname";
+
username = mkSecret "postgres/username";
+
password = mkSecret "postgres/password";
+
};
+
+
"Pleroma.Upload" = {
+
filters = [
+
(mkRaw "Pleroma.Upload.Filter.Exiftool")
+
(mkRaw "Pleroma.Upload.Filter.Dedupe")
+
];
+
};
+
+
"Pleroma.Web.Endpoint" = {
+
# We don't need to specify http ip/ports here because we use unix sockets
+
# ok we do because it's broken
+
http = {
+
ip = "127.0.0.1";
+
port = 35378;
+
};
+
url = {
+
host = "a.soopy.moe";
+
scheme = "https";
+
port = 443;
+
};
+
secure_cookie_flag = true;
+
+
secret_key_base = mkSecret "endpoint/secret_base";
+
signing_salt = mkSecret "endpoint/salt";
+
live_view = {
+
signing_salt = mkSecret "endpoint/live_view/salt";
+
};
+
};
+
+
"Pleroma.Emails.Mailer" = {
+
adapter = mkRaw "Swoosh.Adapters.SMTP";
+
relay = mkSecret "smtp/relay";
+
username = mkSecret "smtp/username";
+
password = mkSecret "smtp/password";
+
};
+
+
"Pleroma.Search.Meilisearch" = {
+
url = mkSecret "search/meili/host_unencrypted";
+
private_key = mkSecret "search/meili/key";
+
initial_indexing_chunk_size = 100000;
+
};
+
};
+
+
":web_push_encryption".":vapid_details" = {
+
subject = "mailto:me@soopy.moe";
+
public_key = mkSecret "vapid/pub";
+
private_key = mkSecret "vapid/key";
+
};
+
};
+
+
nginx = _utils.mkVhost {
+
useACMEHost = "fedi.c.soopy.moe";
+
extraConfig = ''
+
client_max_body_size 100M;
+
'';
+
};
+
+
extraStatic = {
+
"static/terms-of-service.html" = pkgs.writeText "terms-of-service.html" ''
+
<h1>Terms of Service</h1><p>Please refer to this ToS:
+
<a href="https://m.soopy.moe/@admin/pages/tos" rel="noopener noreferrer nofollow">
+
https://m.soopy.moe/@admin/pages/tos</a></p>
+
'';
+
# refer to https://github.com/NixOS/nixpkgs/blob/nixos-unstable/pkgs/servers/akkoma/emoji/blobs_gg.nix#L29
+
# "emoji/Cat_girls_Emoji" = ...
+
};
+
};
+
+
systemd.services.akkoma-config = {
+
serviceConfig.SupplementaryGroups = [config.users.groups.keys.name];
+
};
+
}
+5
systems/koumakan/services/fediverse/default.nix
···
···
+
{...}: {
+
imports = [
+
./akkoma.nix
+
];
+
}
+5
systems/koumakan/services/matrix/default.nix
···
···
+
{...}: {
+
imports = [
+
./synapse.nix
+
];
+
}
+116
systems/koumakan/services/matrix/synapse.nix
···
···
+
{
+
_utils,
+
pkgs,
+
config,
+
...
+
}: {
+
sops.secrets."synapse.yaml" = {
+
mode = "0400";
+
owner = config.users.users.matrix-synapse.name;
+
};
+
+
sops.secrets.matrix-signing-key = {
+
mode = "0400";
+
owner = config.users.users.matrix-synapse.name;
+
};
+
+
users.users.matrix-synapse.extraGroups = [config.users.groups.keys.name];
+
+
services.matrix-synapse = {
+
enable = true;
+
withJemalloc = true;
+
extras = [
+
"jwt"
+
"oidc"
+
];
+
+
extraConfigFiles = [
+
"/run/secrets/synapse.yaml"
+
];
+
+
settings = {
+
server_name = "nue.soopy.moe";
+
serve_server_wellknown = true;
+
allow_public_rooms_over_federation = true;
+
federation_client_minimum_tls_version = 1.2;
+
# TODO: Setup TURN servers
+
# TODO: Setup OIDC providers
+
# TODO: Configure email
+
# TODO: Setup opentracing
+
url_preview_enabled = true;
+
enable_registration = false;
+
session_lifetime = "99y";
+
+
max_upload_size = "100M";
+
signing_key_path = "/run/secrets/matrix-signing-key";
+
+
server_notices = {
+
system_mxid_localpart = "server";
+
system_mxid_display_name = "Server Notices";
+
room_name = "Server Notices";
+
};
+
+
trusted_key_servers = [
+
{
+
server_name = "matrix.org";
+
verify_keys = {
+
"ed25519:auto" = "Noi6WqcDj0QmPxCNQqgezwTlBKrfqehY1u2FyWP9uYw";
+
};
+
}
+
{
+
server_name = "m.lea.moe";
+
}
+
];
+
+
password_config = {
+
policy = {
+
enabled = true;
+
minimum_length = 12;
+
};
+
};
+
};
+
};
+
+
services.postgresql = {
+
ensureDatabases = ["synapse"];
+
ensureUsers = [
+
{
+
name = "synapse";
+
ensurePermissions = {
+
"database \"synapse\"" = "all privileges";
+
};
+
}
+
];
+
};
+
+
services.nginx.virtualHosts."nue.soopy.moe" = _utils.mkVhost {
+
locations."= /config.json" = {
+
alias = "${pkgs.staticly}/configs/";
+
tryFiles = "cinny.json =404";
+
extraConfig = ''
+
add_header access_control_allow_origin "*";
+
'';
+
};
+
+
locations."= /.well-known/matrix/server" = {
+
return = "200 '{\"m.server\": \"nue.soopy.moe:443\"}'";
+
};
+
+
locations."~ ^(/_matrix|/_synapse/client)" = {
+
proxyPass = "http://localhost:8008";
+
extraConfig = ''
+
client_max_body_size 100M;
+
'';
+
};
+
+
locations."= /.well-known/matrix/client" = {
+
alias = "${pkgs.staticly}/configs/matrix/";
+
tryFiles = "stable.json =404";
+
};
+
+
locations."/" = {
+
root = "${pkgs.staticly}/pages/matrix/landing/";
+
tryFiles = "$uri $uri/index.html $uri.html =404";
+
};
+
};
+
}
-40
systems/koumakan/services/postgresql.nix
···
-
{pkgs, ...}: {
-
services.postgresql = {
-
enable = true;
-
-
package = pkgs.postgresql_15;
-
dataDir = "/var/lib/postgresql/15";
-
logLinePrefix = "%m [%p] %h ";
-
-
authentication = ''
-
# unix socket connection
-
local all all trust
-
# local ipv4/6 tcp connection
-
host all all 127.0.0.1/32 scram-sha-256
-
host all all ::1/128 scram-sha-256
-
# world (encrypted) tcp traffic
-
hostssl all all all scram-sha-256
-
'';
-
-
settings = let
-
credsDir = "/run/credentials/postgresql.service";
-
in {
-
listen_addresses = pkgs.lib.mkForce "*";
-
max_connections = 200;
-
password_encryption = "scram-sha-256";
-
-
ssl = "on";
-
ssl_cert_file = "${credsDir}/cert.pem";
-
ssl_key_file = "${credsDir}/key.pem";
-
-
log_hostname = true;
-
datestyle = "iso, dmy";
-
log_timezone = "Asia/Hong_Kong";
-
timezone = "Asia/Hong_Kong";
-
default_text_search_config = "pc_catalog.english";
-
-
max_wal_size = "2GB";
-
min_wal_size = "80MB";
-
};
-
};
-
}
···
-5
systems/koumakan/services/redis.nix
···
-
{...}: {
-
services.redis.servers."" = {
-
enable = true;
-
};
-
}
···
+3 -3
systems/koumakan/services/static-sites/keine.nix
···
-
{...}: {
-
services.nginx.virtualHosts."keine.soopy.moe" = {
-
useACMEHost = "global.c.soopy.moe";
addSSL = true; # Don't force SSL on a mirror (implications TBD)
root = "/srv/www/keine";
···
+
{_utils, ...}: {
+
services.nginx.virtualHosts."keine.soopy.moe" = _utils.mkVhost {
+
forceSSL = false;
addSSL = true; # Don't force SSL on a mirror (implications TBD)
root = "/srv/www/keine";
+1
utils/justfile
···
list:
just -l
nitter-token:
{{python_executable}} nitter-guest-account.py tokens.json
···
list:
just -l
+
# grab a new nitter guest account and save it
nitter-token:
{{python_executable}} nitter-guest-account.py tokens.json
+78 -64
utils/nitter-guest-account.py
···
# thank you!
import sys
import json
import typing
import traceback
from base64 import b64encode
···
success(f'flow token => {flow_token}')
info('Fetching final account object...')
-
tasks = send_req('post', TASKS_ENDPOINT, headers=request_headers, json=get_tasks_body(flow_token)).json()
-
try:
try:
-
open_account_task = next(filter(lambda i: i.get('subtask_id') == "OpenAccount", tasks['subtasks']))
-
account = open_account_task['open_account']
-
except StopIteration:
-
debug("resulting tasks =>", format_json(tasks), override=True)
-
error("Unable to acquire guest account credentials as it isn't present in the API response.")
-
error("This might be because of a wide variety of reasons, but it most likely is due to your IP being rate-limited.")
-
error("Try again with a new IP address or in 24 hours after this attempt.")
-
return 1
-
if args.outfile == "-":
-
debug("outfile is `-`, printing to stdout")
-
print(format_json(account))
-
return 0
-
# Sanity checks
-
try:
-
debug(f"attempting to read file: {args.outfile}")
-
with open(args.outfile) as f:
-
old_data = json.load(f)
-
except FileNotFoundError:
-
# that's okay, we might be able to create it later.
-
old_data = []
-
except PermissionError:
-
# that's not okay. we will need to access the file later anyways.
-
error("unable to read file due to a permission error.")
-
error("please make sure this script has read and write access to the file.")
-
print(format_json(account))
-
return 1
-
except json.JSONDecodeError:
-
error("could not parse the provided JSON file.")
-
if not prompt_bool("Do you want to overwrite the file?", default=None):
-
warn("Not overwriting file, printing to stdout instead.")
print(format_json(account))
return 1
-
debug('assuming old data is an empty array because we are overwriting')
-
old_data = []
-
if type(old_data) != list:
-
error("top-level object of the existing JSON file is not a list.")
-
error("due to the implementation, the file must be overwritten.")
-
if not (prompt_bool("Do you want to overwrite?", default=None)):
-
warn("Not overwriting existing data, printing to stdout instead.")
print(format_json(account))
return 1
-
debug("assuming old data is an empty array because we are overwriting")
-
old_data = []
-
-
old_data.append(account)
-
try:
-
debug("attempting to write file")
-
with open(args.outfile, 'w+') as f:
-
f.write(format_json(old_data))
-
success(f"successfully written to file {args.outfile}")
-
return 0
-
except PermissionError:
-
error("unable to write to file due to permission error.")
-
error("please make sure this script has write access to the file.")
-
print(format_json(account))
-
return 1
-
except Exception as e:
-
error("Unable to write to file due to an uncaught error:", e)
-
tb = ''.join(traceback.TracebackException.from_exception(e).format())
-
debug("exception stacktrace\n" + tb)
-
print(format_json(account))
-
except Exception:
-
debug("resulting tasks =>", format_json(tasks), override=True)
-
error("an unhandled error occurred. the tasks object is printed to avoid losing otherwise successful data.")
-
error("please file a bug report and attach the traceback below.")
-
raise
return 0
···
# thank you!
import sys
import json
+
import time
+
import random
import typing
import traceback
from base64 import b64encode
···
success(f'flow token => {flow_token}')
info('Fetching final account object...')
+
backoff_time = 0
+
exception = None
+
for attempt in range(0, 6):
+
debug(f"Attempt #{attempt + 1}")
+
tasks = send_req('post', TASKS_ENDPOINT, headers=request_headers, json=get_tasks_body(flow_token)).json()
try:
+
try:
+
open_account_task = next(filter(lambda i: i.get('subtask_id') == "OpenAccount", tasks['subtasks']))
+
account = open_account_task['open_account']
+
except StopIteration as e:
+
backoff_time += random.randint(5000,10000) / 1000
+
exception = e
+
warn(f"attempt #{attempt + 1} failed to acquire token, retrying in {backoff_time}s.")
+
time.sleep(backoff_time)
+
continue
+
info(f"Attempt #{attempt + 1} succeeded")
+
if args.outfile == "-":
+
debug("outfile is `-`, printing to stdout")
+
print(format_json(account))
+
return 0
+
# Sanity checks
+
try:
+
debug(f"attempting to read file: {args.outfile}")
+
with open(args.outfile) as f:
+
old_data = json.load(f)
+
except FileNotFoundError:
+
# that's okay, we might be able to create it later.
+
old_data = []
+
except PermissionError:
+
# that's not okay. we will need to access the file later anyways.
+
error("unable to read file due to a permission error.")
+
error("please make sure this script has read and write access to the file.")
print(format_json(account))
return 1
+
except json.JSONDecodeError:
+
error("could not parse the provided JSON file.")
+
if not prompt_bool("Do you want to overwrite the file?", default=None):
+
warn("Not overwriting file, printing to stdout instead.")
+
print(format_json(account))
+
return 1
+
debug('assuming old data is an empty array because we are overwriting')
+
old_data = []
+
if type(old_data) != list:
+
error("top-level object of the existing JSON file is not a list.")
+
error("due to the implementation, the file must be overwritten.")
+
if not (prompt_bool("Do you want to overwrite?", default=None)):
+
warn("Not overwriting existing data, printing to stdout instead.")
+
print(format_json(account))
+
return 1
+
debug("assuming old data is an empty array because we are overwriting")
+
old_data = []
+
+
old_data.append(account)
+
+
try:
+
debug("attempting to write file")
+
with open(args.outfile, 'w+') as f:
+
f.write(format_json(old_data))
+
success(f"successfully written to file {args.outfile}")
+
return 0
+
except PermissionError:
+
error("unable to write to file due to permission error.")
+
error("please make sure this script has write access to the file.")
print(format_json(account))
return 1
+
except Exception as e:
+
error("Unable to write to file due to an uncaught error:", e)
+
tb = ''.join(traceback.TracebackException.from_exception(e).format())
+
debug("exception stacktrace\n" + tb)
+
print(format_json(account))
+
except Exception:
+
debug("resulting tasks =>", format_json(tasks), override=True)
+
error("an unhandled error occurred. the tasks object is printed to avoid losing otherwise successful data.")
+
error("please file a bug report and attach the traceback below.")
+
raise
+
if exception != None:
+
debug("resulting tasks =>", format_json(tasks))
+
error("Unable to acquire guest account credentials with 5 attempts as it isn't present in any of the API responses.")
+
error("This might be because of a wide variety of reasons, but it most likely is due to your IP being rate-limited.")
+
error("Try again with a new IP address or in 24 hours after this attempt.")
+
return 1
return 0