From 41d82ae436fbb8f83b21d10b2ec5e13af0723848 Mon Sep 17 00:00:00 2001 From: stuebinm Date: Thu, 11 Jan 2024 22:53:02 +0100 Subject: [PATCH] meta: new structure we decided to: - get rid of unused packages - simpify the directory layout since we only have one host anyways - move our docs (such as they are) in-tree --- README.md | 45 ++--- docs/_index.md | 7 + docs/auth.md | 10 ++ docs/domains.md | 20 +++ docs/hostnames.md | 16 ++ docs/lxc.md | 17 ++ docs/rebooting.md | 18 ++ docs/secrets.md | 21 +++ docs/services/_index.md | 5 + docs/services/acme.md | 19 ++ docs/services/hedgedoc.md | 68 +++++++ docs/services/mail.md | 65 +++++++ docs/services/mumble.md | 40 +++++ docs/services/service.template.md | 18 ++ docs/snapshots.md | 24 +++ flake.nix | 7 +- {hosts/parsons => parsons}/configuration.nix | 33 ++-- {services => parsons}/gitea.nix | 0 {hosts/parsons => parsons}/hardware.nix | 0 {services => parsons}/hedgedoc-hacc.nix | 0 {services => parsons}/hedgedoc-i4f.nix | 0 {hosts/parsons => parsons}/lxc.nix | 0 {services => parsons}/mail.nix | 0 {services => parsons}/mattermost.nix | 0 {services => parsons}/murmur.nix | 0 {services => parsons}/nextcloud.nix | 0 {services => parsons}/nginx-pages.nix | 0 {services => parsons}/tracktrain.nix | 0 {services => parsons}/uffd.nix | 0 {services => parsons}/vaultwarden.nix | 0 pkgs/default.nix | 33 +--- .../default.nix => mattermost.nix} | 0 .../netbox/0001-add-uffd-oauth2-backend.patch | 70 -------- pkgs/thelounge/css-patch.css | 24 --- services/thelounge.nix | 65 ------- websites/docs.hacc.space/Readme.md | 44 +++++ websites/docs.hacc.space/config.toml | 35 ++++ websites/docs.hacc.space/content | 1 + websites/docs.hacc.space/default.nix | 19 ++ websites/docs.hacc.space/sass/style.scss | 168 ++++++++++++++++++ .../static/ShareTech-Regular.ttf | Bin 0 -> 29536 bytes websites/docs.hacc.space/static/favicon.png | Bin 0 -> 3798 bytes .../docs.hacc.space/static/favicon_color.png | Bin 0 -> 5334 bytes websites/docs.hacc.space/static/search.js | 52 ++++++ websites/docs.hacc.space/templates/base.html | 43 +++++ websites/docs.hacc.space/templates/blog.html | 12 ++ .../templates/categories/list.html | 17 ++ .../templates/categories/single.html | 12 ++ .../docs.hacc.space/templates/doc-page.html | 15 ++ websites/docs.hacc.space/templates/index.html | 23 +++ .../templates/post_macros.html | 15 ++ .../docs.hacc.space/templates/section.html | 15 ++ 52 files changed, 854 insertions(+), 242 deletions(-) create mode 100644 docs/_index.md create mode 100644 docs/auth.md create mode 100644 docs/domains.md create mode 100644 docs/hostnames.md create mode 100644 docs/lxc.md create mode 100644 docs/rebooting.md create mode 100644 docs/secrets.md create mode 100644 docs/services/_index.md create mode 100644 docs/services/acme.md create mode 100644 docs/services/hedgedoc.md create mode 100644 docs/services/mail.md create mode 100644 docs/services/mumble.md create mode 100644 docs/services/service.template.md create mode 100644 docs/snapshots.md rename {hosts/parsons => parsons}/configuration.nix (78%) rename {services => parsons}/gitea.nix (100%) rename {hosts/parsons => parsons}/hardware.nix (100%) rename {services => parsons}/hedgedoc-hacc.nix (100%) rename {services => parsons}/hedgedoc-i4f.nix (100%) rename {hosts/parsons => parsons}/lxc.nix (100%) rename {services => parsons}/mail.nix (100%) rename {services => parsons}/mattermost.nix (100%) rename {services => parsons}/murmur.nix (100%) rename {services => parsons}/nextcloud.nix (100%) rename {services => parsons}/nginx-pages.nix (100%) rename {services => parsons}/tracktrain.nix (100%) rename {services => parsons}/uffd.nix (100%) rename {services => parsons}/vaultwarden.nix (100%) rename pkgs/{mattermost/default.nix => mattermost.nix} (100%) delete mode 100644 pkgs/netbox/0001-add-uffd-oauth2-backend.patch delete mode 100644 pkgs/thelounge/css-patch.css delete mode 100644 services/thelounge.nix create mode 100644 websites/docs.hacc.space/Readme.md create mode 100644 websites/docs.hacc.space/config.toml create mode 120000 websites/docs.hacc.space/content create mode 100644 websites/docs.hacc.space/default.nix create mode 100644 websites/docs.hacc.space/sass/style.scss create mode 100644 websites/docs.hacc.space/static/ShareTech-Regular.ttf create mode 100644 websites/docs.hacc.space/static/favicon.png create mode 100644 websites/docs.hacc.space/static/favicon_color.png create mode 100644 websites/docs.hacc.space/static/search.js create mode 100644 websites/docs.hacc.space/templates/base.html create mode 100644 websites/docs.hacc.space/templates/blog.html create mode 100644 websites/docs.hacc.space/templates/categories/list.html create mode 100644 websites/docs.hacc.space/templates/categories/single.html create mode 100644 websites/docs.hacc.space/templates/doc-page.html create mode 100644 websites/docs.hacc.space/templates/index.html create mode 100644 websites/docs.hacc.space/templates/post_macros.html create mode 100644 websites/docs.hacc.space/templates/section.html diff --git a/README.md b/README.md index 0b24852..7894f1b 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,26 @@ # hacc nixfiles -welcome to hacc nixfiles (haccfiles). this is the code describing our nix-based infrastructure. +Welcome to the hacc nixfiles (haccfiles). This is how we configure (most of) +our infrastructure. -## structure +## General layout - `flake.nix`: Entrypoint & dependencies -- `common/`: configuration common to all hosts - `modules/`: home-grown modules for hacc-specific services -- `pkgs/`: packages we built and don't want to upstream -- `hosts/`: configuration.nix per host (currently there's only one of those) -- `services/`: all services we run; imported in appropriate host config -- `websites/`: static websites we deploy somewhere +- `pkgs/`: packages we need which aren't in nixpkgs +- `websites/`: static websites hosted by us +- `common/`: meta-level config, reusable across machines +- `parsons/`: our sole server, its config & the services it runs -## working with the haccfiles +Right now, we only have a single host. We might add more again in the future. + +## Working with this repo You will need a flake-enabled nix installation, and have your ssh config set up so that `ssh parsons` will connect to `parsons.hacc.space`. +### Deploying remotely + It's recommended to use [deploy_rs](https://github.com/serokell/deploy-rs): ~~~shell deploy .#parsons -k [--dry-activate] @@ -28,30 +32,13 @@ nixos-rebuild --flake .#parsons --target-host parsons \ --use-remote-sudo --use-substitutes [test|switch|dry-activate] ~~~ -If for some reason you have `nix` but not `nixos-rebuild`, you can still build the -system closure using: +### Re-deploying on parsons itself + +Simply do: ~~~shell -nix build .#nixosConfigurations.parsons.config.system.build.toplevel +nixos-rebuild --flake .#parsons [test|switch|dry-activate] ~~~ -(but you might have trouble deploying it) - -## Secret management - -We use [sops-nix](https://github.com/Mic92/sops-nix) to manage secrets which we'd -like to have in Git but don't want to be public. Entires in `secrets.yaml` are -encrypted for each of the age keys listed in `.sops.yaml`, which are themselves -derived from ssh keys. - -For the initial set up, please take a look at the sops-nix Readme file. - -To edit the secrets file, just use `sops secrets.yaml`, which will decrypt the -file & open it in your $EDITOR, then re-encrypt it when you're done. - -To add a new key, use `ssh-to-age` to convert your ssh key to age, and add it to -`sops.yaml`. Then do `sops updatekeys secrets.yaml` to re-encrypt the file for -the new set of keys. - ## Working on websites Websites are exposed as flake outputs: if you're working on a website & want to diff --git a/docs/_index.md b/docs/_index.md new file mode 100644 index 0000000..9cf3041 --- /dev/null +++ b/docs/_index.md @@ -0,0 +1,7 @@ ++++ +title = "hacc infra documentation" +page_template = "doc-page.html" +sort_by="title" ++++ + + diff --git a/docs/auth.md b/docs/auth.md new file mode 100644 index 0000000..6efed0e --- /dev/null +++ b/docs/auth.md @@ -0,0 +1,10 @@ ++++ +title = "Authentication" +categories = [ "services", "uffd" ] ++++ + +We use [uffd](https://git.cccv.de/uffd/uffd) for our SSO, for better or worse. +Mostly for worse. + + + diff --git a/docs/domains.md b/docs/domains.md new file mode 100644 index 0000000..237a876 --- /dev/null +++ b/docs/domains.md @@ -0,0 +1,20 @@ ++++ +title = "Domains" +categories = [ "domains", "meta" ] ++++ + +Perhaps too many of them. + +## Domains + +| domain | mc | status | date | reseller | owner | custody | +| :------------------- | :-: | :-----: | :------: | :---------- | :--------- | :-----: | +| 4future.dev | yes | | | | | hacc e.V. | +| infra4future.de | yes | | | | | hacc e.V. | +| hacc.space | yes | | | | | hacc e.V. | +| hacc.earth | yes | | | | | hacc e.V. | +| hacc.media | yes | | | | | hacc e.V. | +| hacc.wiki | no | | | | | | + +mc = managed by cloudflare +status = (renewl | autorenewl | expires) diff --git a/docs/hostnames.md b/docs/hostnames.md new file mode 100644 index 0000000..ea1dcf8 --- /dev/null +++ b/docs/hostnames.md @@ -0,0 +1,16 @@ ++++ +title = "Hostname schema" ++++ + +[Badass Anarchist Women](https://listverse.com/2018/09/27/10-absolutely-badass-anarchist-women-who-challenged-the-system/) +- keller +- deCleyre +- davidNeel +- leGuin +- [parsons](../parsons) +- ohair +- berneri +- michel +- sanger +- goldman + diff --git a/docs/lxc.md b/docs/lxc.md new file mode 100644 index 0000000..a4d354f --- /dev/null +++ b/docs/lxc.md @@ -0,0 +1,17 @@ ++++ +title = "LXC" +categories = [ "lxc" ] ++++ + +Some things don't easily run on NixOS. For these we have LXC containers running +debian. + +Right now, only onlyoffice is left. + +## Useful commands + - login to a container as root with a usable shell + `lxc-attach -n -- /usr/bin/sudo -i` + - restarting the keycloak and ldap containers + `lxc-stop -n && lxc-start -n ` + - restarting their network bridge: + `systemctl restart lxcbr0-netdev.services` diff --git a/docs/rebooting.md b/docs/rebooting.md new file mode 100644 index 0000000..c7b57e1 --- /dev/null +++ b/docs/rebooting.md @@ -0,0 +1,18 @@ ++++ +title = "Rebooting Parsons" +categories = [ "nix" ] ++++ + +## Check integrity after unexpected shutdown +These steps are only required if the server shut down unexpectedly or you suspect tampering. + +TODO + +## Unlock full disk encryption +Connection to the server via the command listed in the shared password manager. +Only the Vorstand has access to it! + +Enter the passwords for dpool and zroot. + +If both are correct, you will be disconnected and the server continues the boot sequence. +The server should be up after about minute. Please check all services for availability. diff --git a/docs/secrets.md b/docs/secrets.md new file mode 100644 index 0000000..31df55b --- /dev/null +++ b/docs/secrets.md @@ -0,0 +1,21 @@ ++++ +title = "Secrets" +categories = [ "services", "sops" ] ++++ + +## Secret management + +We use [sops-nix](https://github.com/Mic92/sops-nix) to manage secrets which we'd +like to have in Git but don't want to be public. Entries in `secrets.yaml` are +encrypted for each of the age keys listed in `.sops.yaml`, which are themselves +derived from ssh keys. + +For the initial set up, please take a look at the sops-nix Readme file. + +To edit the secrets file, run `sops secrets.yaml`, which will decrypt the +file & open it in your $EDITOR, then re-encrypt it when you're done. + +To add a new key, use `ssh-to-age` to convert your ssh key to age, and add it to +`sops.yaml`. Then do `sops updatekeys secrets.yaml` to re-encrypt the file for +the new set of keys. + diff --git a/docs/services/_index.md b/docs/services/_index.md new file mode 100644 index 0000000..59a0b1e --- /dev/null +++ b/docs/services/_index.md @@ -0,0 +1,5 @@ ++++ +title = "Services" +sort_by = "title" +page_template = "doc-page.html" ++++ diff --git a/docs/services/acme.md b/docs/services/acme.md new file mode 100644 index 0000000..f1c8a82 --- /dev/null +++ b/docs/services/acme.md @@ -0,0 +1,19 @@ ++++ +title = "ACME / letsencrypt" +categories = [ "domain", "https", "ssl", "tls", "Certificates" ] ++++ + + +# Usage + +We use the ACME module's nginx integration for basically everything. Beware of +rate limits when redeploying lots of things at once! Let's Encrypt is a little +picky about those. + + +## Workarounds & peculiar configuration choices + +Certs live under `/var/lib/acme/` + +If you need to remove a cert for whatever reason, be aware that there is a +hidden `.lego` folder, that contains state as well diff --git a/docs/services/hedgedoc.md b/docs/services/hedgedoc.md new file mode 100644 index 0000000..83b6d42 --- /dev/null +++ b/docs/services/hedgedoc.md @@ -0,0 +1,68 @@ ++++ +title = "hedgedoc" +taxonomies.categories = [ "services" ] ++++ + + +hegedoc was once called codiMD, so container, config and users are still called codimd. + +**Do NOT change this** unless you're sure what you're doing. + +We have two instances: + - `pad-hacc`/pad.hacc.space is connected to our SSO/uffd + - `pad-i4f`/pad.infra4future.de is not connected to our SSO and meant to be more public + +## Basic Troubleshooting + +Usually if hedgedoc dies, it's because postgresql wasn't there yet. Just restart +hedgedoc. + +## More Troubles +log into the container and take a look at the logs + +~~~shell +sudo nixos-container root-login codimd +journalctl -e +~~~ + +### fixing failed database upgrades + +see https://docs.hedgedoc.org/guides/migration-troubleshooting/ (copied below +for convenience?): + +In some cases, HedgeDoc might apply migrations without correctly saving the +progress. It will then refuse to start with "already exists"-errors like +ERROR: type "enum_Notes_permission" already exists. + +Get the name of the failing migration and append .js to it. For example, if +you encounter this error: + +~~~ +== 20180306150303-fix-enum: migrating ======= + +ERROR: type "enum_Notes_permission" already exists +~~~ + +the name of the failed migration would be 20180306150303-fix-enum.js. + +The SQL-statement may look like this: + +~~~ +INSERT INTO "SequelizeMeta" (name) VALUES ('20180306150303-fix-enum.js'); +~~~ + +Make sure HedgeDoc does not run and insert the name into the SequelizeMeta table. +Enter the container switch to the postgres user, open psql and commect to the +codimd database: + +~~~shell +su postgres +psql +\l +\c codimd +UN adjusted SQL STAMEMENT from above ] +\q +~~~ + +Start HedgeDoc again and observe if it starts correctly. It may be necessary to +repeat this process and insert multiple migrations into the SequelizeMeta table. diff --git a/docs/services/mail.md b/docs/services/mail.md new file mode 100644 index 0000000..b6814a2 --- /dev/null +++ b/docs/services/mail.md @@ -0,0 +1,65 @@ ++++ +title = "mail" +taxonomies.categories = [ "services" ] ++++ + +Mail is not connected to our SSO! + +## adding a mail account +- We use `@hacc.space` for our mails +- `@infra4future.de` is reserved for services, old user accounts will be + forwarded & logins disabled +- choose a name (no aliases or other names can be the same) +- generate a sha-512 password hash ```mkpasswd -m sha-512``` - **never add an + unhashed password!** +- add your account to `loginAccounts =` in `//parsons/mail.nix` +- build and redeploy parsons + +**example:** +``` +zwoelfontheshelf@hacc.space" = { + hashedPassword = "$6$ISAaU8X6D$oGKe9WXDWrRpGzHUEdxrxdtgvzuGOkBMuDc82IZhegpsv1bqd550FhZZrI40IjZTA5Hy2MZ8j/0efpnQ4fOQH0"; +}; +``` + +## adding to a forward address +- add the mail address to the corresponding `extraVirtualAliases =` +- build and redeploy parsons + +## adding a forward address +- add the address to `extraVirtualAliases =` +- add the addresses it should forward to +- build and redeploy parsons + +**example:** +``` +"himmel@hacc.space" = [ + "hexchen@hacc.space" + "zauberberg@hacc.space" +]; +``` + +## sending & receiving mail + +### as a user +- Your mail client should auto configure correctly + +~~~ +mailserver: mail.hacc.space (everywhere) +username: $your_mail_address +sending via smtp: port 587 or 465 +recieving + imap: port 993 +TLS and STARTTLS are supported +~~~ + +- You can send mail as you and any alias you receive mail from. Set a second Identity in your e-mail client + +### as an application +- mailserver: `mail.hacc.space` +- Do **not** use port 25. It's for server to server communication only. +- Use smtp ports `587` or `465` +- enable TLS if possible +- only send mail from `noreply@infra4future.de` +- Password is somewhere (TODO!) + diff --git a/docs/services/mumble.md b/docs/services/mumble.md new file mode 100644 index 0000000..7591723 --- /dev/null +++ b/docs/services/mumble.md @@ -0,0 +1,40 @@ ++++ +title = "mumble" +taxonomies.categories = [ "mumble" ] ++++ + + +[offical Docmuentation](https://wiki.mumble.info/wiki/Main_Page) + +Mumble's server is called murmur, but the naming is inconsistent. Sometimes +it's also just called mumble server. + +# Usage + +## registration +Users need to be registered to join any other channel than public. +An already registered user has to register them with the server. +1. right click on the username +2. choose register in the menu. Done. + +## restricted channels +Every channel in the hacc category except for plenum can only be accessed by +members of the hacc group. + +## adding users to a group +Only admins can edit groups, and only registered users can be added to groups. +1. right click on the Root channel +2. select Edit... +2. In Groups select $groupname +3. make the change you want to make +4. click "OK" + +# Config details +- the server is not registered with mumble & not on the public server list +- the bitrate is set to 128kb/s; otherwise the client would complain that the + server bitrate is less then the configured (default) in its local settings + +# Hacks +- murmur needs a TLS cert, which we get via the ACME module +- there's a funny group setup so that hopefully murmurd can read the cert +- this seems to work fine now, but was some source of trouble in the past diff --git a/docs/services/service.template.md b/docs/services/service.template.md new file mode 100644 index 0000000..b8a2517 --- /dev/null +++ b/docs/services/service.template.md @@ -0,0 +1,18 @@ ++++ +title = "$Service Name" +draft = true ## Remove this line to make file appear on website ++++ + + + +# Usage + + +# Config Notes + + +## Updating + + +# Hacks + diff --git a/docs/snapshots.md b/docs/snapshots.md new file mode 100644 index 0000000..23f506c --- /dev/null +++ b/docs/snapshots.md @@ -0,0 +1,24 @@ ++++ +title = "Use ZFS snapshot" +taxonomies.categories = [ "zfs", "snapshot", "filesystem", "backup", "update", "upgrade" ] ++++ + +## Make a ZFS snapshot +~~~shell +sudo zfs snapshot zroot/safe/persist@ +~~~ + +## Rollback + +### single files +The snapshots can be accessed under `/.zfs/snapshot/...` + +### fully +~~~shell +sudo zfs rollback zroot/safe/persist@ +~~~ + +## Delete a ZFS snapshot +~~~shell +sudo zfs destroy zroot/safe/persist@ +~~~ diff --git a/flake.nix b/flake.nix index bfc8dd8..c57ae6e 100644 --- a/flake.nix +++ b/flake.nix @@ -71,7 +71,7 @@ nixosConfigurations.parsons = nixpkgs.lib.nixosSystem { system = "x86_64-linux"; modules = [ - ./hosts/parsons/configuration.nix + ./parsons/configuration.nix sops-nix.nixosModules.sops { nixpkgs.pkgs = pkgs; } { environment.etc."haccfiles".source = self.outPath; } @@ -98,7 +98,10 @@ deploy-rs.lib; packages.x86_64-linux = - self.nixosConfigurations.parsons.config.hacc.websites.builders; + let + websites = self.nixosConfigurations.parsons.config.hacc.websites.builders; + in + { docs = websites."docs.hacc.space"; } // websites; }; } diff --git a/hosts/parsons/configuration.nix b/parsons/configuration.nix similarity index 78% rename from hosts/parsons/configuration.nix rename to parsons/configuration.nix index 31381d4..9366ef2 100644 --- a/hosts/parsons/configuration.nix +++ b/parsons/configuration.nix @@ -2,34 +2,27 @@ { imports = [ - ../../common + ../common ./hardware.nix modules.encboot modules.network.nftables modules.nftnat sources.nix-hexchen.nixosModules.profiles.nopersist - - ../../services/nextcloud.nix - ../../services/mattermost.nix - ../../services/thelounge.nix - ../../services/murmur.nix - ../../services/hedgedoc-hacc.nix - ../../services/hedgedoc-i4f.nix - ../../services/mail.nix - ../../services/gitea.nix - ../../services/nginx-pages.nix - ../../services/vaultwarden.nix - ../../services/tracktrain.nix - ../../services/uffd.nix - + ./nextcloud.nix + ./mattermost.nix + ./murmur.nix + ./hedgedoc-hacc.nix + ./hedgedoc-i4f.nix + ./mail.nix + ./gitea.nix + ./nginx-pages.nix + ./vaultwarden.nix + ./tracktrain.nix + ./uffd.nix ./lxc.nix ]; hexchen.bindmounts."/var/lib/acme" = "/persist/var/lib/acme"; - # fileSystems."/var/lib/acme" = { - # device = "/persist/var/lib/acme"; - # fsType = "bind"; - # }; hexchen.encboot = { enable = true; @@ -37,7 +30,7 @@ networkDrivers = [ "igb" ]; }; - sops.defaultSopsFile = ../../secrets.yaml; + sops.defaultSopsFile = ../secrets.yaml; sops.age.sshKeyPaths = [ "/persist/ssh/ssh_host_ed25519_key" ]; boot.loader.grub.enable = true; diff --git a/services/gitea.nix b/parsons/gitea.nix similarity index 100% rename from services/gitea.nix rename to parsons/gitea.nix diff --git a/hosts/parsons/hardware.nix b/parsons/hardware.nix similarity index 100% rename from hosts/parsons/hardware.nix rename to parsons/hardware.nix diff --git a/services/hedgedoc-hacc.nix b/parsons/hedgedoc-hacc.nix similarity index 100% rename from services/hedgedoc-hacc.nix rename to parsons/hedgedoc-hacc.nix diff --git a/services/hedgedoc-i4f.nix b/parsons/hedgedoc-i4f.nix similarity index 100% rename from services/hedgedoc-i4f.nix rename to parsons/hedgedoc-i4f.nix diff --git a/hosts/parsons/lxc.nix b/parsons/lxc.nix similarity index 100% rename from hosts/parsons/lxc.nix rename to parsons/lxc.nix diff --git a/services/mail.nix b/parsons/mail.nix similarity index 100% rename from services/mail.nix rename to parsons/mail.nix diff --git a/services/mattermost.nix b/parsons/mattermost.nix similarity index 100% rename from services/mattermost.nix rename to parsons/mattermost.nix diff --git a/services/murmur.nix b/parsons/murmur.nix similarity index 100% rename from services/murmur.nix rename to parsons/murmur.nix diff --git a/services/nextcloud.nix b/parsons/nextcloud.nix similarity index 100% rename from services/nextcloud.nix rename to parsons/nextcloud.nix diff --git a/services/nginx-pages.nix b/parsons/nginx-pages.nix similarity index 100% rename from services/nginx-pages.nix rename to parsons/nginx-pages.nix diff --git a/services/tracktrain.nix b/parsons/tracktrain.nix similarity index 100% rename from services/tracktrain.nix rename to parsons/tracktrain.nix diff --git a/services/uffd.nix b/parsons/uffd.nix similarity index 100% rename from services/uffd.nix rename to parsons/uffd.nix diff --git a/services/vaultwarden.nix b/parsons/vaultwarden.nix similarity index 100% rename from services/vaultwarden.nix rename to parsons/vaultwarden.nix diff --git a/pkgs/default.nix b/pkgs/default.nix index e45732a..3c14078 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -8,46 +8,15 @@ let newpkgs = { - mattermost = callPackage ./mattermost {inherit sources;}; + mattermost = callPackage ./mattermost.nix {inherit sources;}; tracktrain = import sources.tracktrain { nixpkgs = pkgs; compiler = "default"; }; - # a version of the lounge with some extra css that - # hides things the hacc-voc doesn't need - thelounge = pkgs.stdenv.mkDerivation { - name = "thelounge-hacked"; - src = pkgs.thelounge; - - phases = [ "buildPhase" "installPhase" ]; - buildPhase = '' - cp $src/* -r . - chmod 777 lib/node_modules/thelounge/public/css/style.css - cat ${./thelounge/css-patch.css} >> lib/node_modules/thelounge/public/css/style.css - ''; - - installPhase = '' - mkdir -p $out - cp * -r $out - ''; - meta.mainProgram = "thelounge"; - }; - uffd = oldstable.callPackage ./uffd { }; - netbox = pkgs.netbox.override (super: rec { - python3 = super.python3.override (oldpy: { - packageOverrides = self: super: { - social-auth-core = super.social-auth-core.overrideAttrs ( old: { - name = "social-auth-with-uffd"; - patches = [ ./netbox/0001-add-uffd-oauth2-backend.patch ]; - }); - }; - }); - }); - inherit (oldstable) uwsgi flask; }; diff --git a/pkgs/mattermost/default.nix b/pkgs/mattermost.nix similarity index 100% rename from pkgs/mattermost/default.nix rename to pkgs/mattermost.nix diff --git a/pkgs/netbox/0001-add-uffd-oauth2-backend.patch b/pkgs/netbox/0001-add-uffd-oauth2-backend.patch deleted file mode 100644 index 07e9507..0000000 --- a/pkgs/netbox/0001-add-uffd-oauth2-backend.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 00e282e32b46bb4b6040dc3810599c693306c0ec Mon Sep 17 00:00:00 2001 -From: David Croft -Date: Thu, 24 Mar 2022 11:09:14 +0000 -Subject: [PATCH] add uffd oauth2 backend - ---- - social_core/backends/uffd.py | 51 ++++++++++++++++++++++++++++++++++++ - 1 file changed, 51 insertions(+) - create mode 100644 social_core/backends/uffd.py - -diff --git a/social_core/backends/uffd.py b/social_core/backends/uffd.py -new file mode 100644 -index 00000000..fb8ffb62 ---- /dev/null -+++ b/social_core/backends/uffd.py -@@ -0,0 +1,51 @@ -+from urllib.parse import urlencode -+ -+from .oauth import BaseOAuth2 -+ -+ -+class UffdOAuth2(BaseOAuth2): -+ """Uffd OAuth2 authentication backend -+ -+ You need to set the following config: -+ SOCIAL_AUTH_UFFD_KEY - client id -+ SOCIAL_AUTH_UFFD_SECRET - client secret -+ SOCIAL_AUTH_UFFD_BASE_URL - base url to uffd installation -+ """ -+ -+ name = 'uffd' -+ ACCESS_TOKEN_METHOD = 'POST' -+ REFRESH_TOKEN_METHOD = 'POST' -+ SCOPE_SEPARATOR = ' ' -+ STATE_PARAMETER = True -+ REDIRECT_STATE = False -+ EXTRA_DATA = [ -+ ('id', 'id'), -+ ] -+ -+ def get_user_details(self, response): -+ """Return user details from a Uffd account""" -+ fullname, first_name, last_name = self.get_user_names(fullname=response.get('name')) -+ return { -+ 'username': response.get('nickname'), -+ 'email': response.get('email') or '', -+ 'fullname': fullname, -+ 'first_name': first_name, -+ 'last_name': last_name, -+ } -+ -+ def user_data(self, access_token, *args, **kwargs): -+ """Loads user data from service""" -+ url = self.userinfo_url() + '?' + urlencode({'access_token': access_token}) -+ try: -+ return self.get_json(url) -+ except ValueError: -+ return None -+ -+ def authorization_url(self): -+ return self.setting('BASE_URL') + '/oauth2/authorize' -+ -+ def access_token_url(self): -+ return self.setting('BASE_URL') + '/oauth2/token' -+ -+ def userinfo_url(self): -+ return self.setting('BASE_URL') + '/oauth2/userinfo' --- -2.38.1 - diff --git a/pkgs/thelounge/css-patch.css b/pkgs/thelounge/css-patch.css deleted file mode 100644 index 0d058b6..0000000 --- a/pkgs/thelounge/css-patch.css +++ /dev/null @@ -1,24 +0,0 @@ - -/* Hides extra fields on connect screen */ -.connect-row:nth-of-type(4) { - display: none !important; -} - -.connect-row:nth-of-type(2) { - display: none !important; -} - -.connect-row:nth-of-type(5) { - display: none !important; -} - - -/* Hides side panel button */ -.header > button:first-child { - display: none !important; -} - -/* Hides channel options button (includes leave option) */ -.header > button:nth-last-child(2) { - display: none !important; -} diff --git a/services/thelounge.nix b/services/thelounge.nix deleted file mode 100644 index be7b556..0000000 --- a/services/thelounge.nix +++ /dev/null @@ -1,65 +0,0 @@ -{ config, lib, pkgs, evalConfig, ... }: - -{ - containers.thelounge = { - autoStart = true; - privateNetwork = true; - hostAddress = "192.168.100.1"; - localAddress = "192.168.100.4"; - bindMounts = { - "/var/lib/thelounge" = { - hostPath = "/persist/containers/thelounge"; - isReadOnly = false; - }; - }; - - path = evalConfig ({ config, lib, ... }: { - services.thelounge = { - enable = true; - - extraConfig = { - public = true; - package = pkgs.thelounge; - - # respect X-Forwarded-For - reverseProxy = true; - defaults = { - name = "libera chat"; - host = "irc.eu.libera.chat"; - port = 6697; - # encrypt things! - tls = true; - # yes, please do actually check the cert … - rejectUnauthorized = true; - nick = "haccGuest%%%%"; - join = "#hacc-webchat"; - }; - lockNetwork = true; - - # don't log messages (default is text / sqlite) - messageStorage = []; - - # darker theme - #theme = "morning"; - - # these three should result in having link previews - # which are fetched only by the server, then proxied - # (i.e. clients won't directly connect to arbitrary - # domains to get previews) - prefetch = true; - prefetchStorage = true; - disableMediaPreview = true; - - leaveMessage = "happy haccing"; - }; - }; - }); - }; - - services.nginx.virtualHosts."webchat.voc.hacc.space" = { - locations."/".proxyPass = - "http://${config.containers.thelounge.localAddress}:9000"; - enableACME = true; - forceSSL = true; - }; -} diff --git a/websites/docs.hacc.space/Readme.md b/websites/docs.hacc.space/Readme.md new file mode 100644 index 0000000..536c2c7 --- /dev/null +++ b/websites/docs.hacc.space/Readme.md @@ -0,0 +1,44 @@ +# Markdown docs with zola. + +[Zola](https://www.getzola.org/) is a static site generated written in Rust +(which you'll notice since sometimes it panics). + +To run the site locally: + +``` +zola serve +``` + +## Directory Layout + +All the important stuff goes into `content`. If you create subdirectories, make +sure you remembered to also create an `_index.md` file for it (if in doubt, just +copy the one at `content/_index.md`); otherwise pages in there won't work. + +`templates` is *not* for site templates, but specifies how markdown files should +be turned into html. If an autogenerated link broke, you'll probably have to +change something in there. `sass` and `static` do exactly what they sound like. + +It usually shouldn't be necessary to change `config.toml`, but if it is, [here +is the list of all available options](https://www.getzola.org/documentation/getting-started/configuration/). + + +## File Layout + +Markdown files start with a frontmatter that should look something like so: + +```markdown ++++ +title = "blåhaj" +taxonomies.categories = [ "flausch" ] ++++ + +[actual markdown goes here] +``` + +The frontmatter is TOML; the `taxonomies.*` keys are special and can be used to +aggregate posts if enabled in `config.toml` (currently that's only the case for +`categories`, though). See also the [list of all available keys](https://www.getzola.org/documentation/content/page/). + +Please don't repeat the page's title in markdown, otherwise it'll appear twice +in the html. diff --git a/websites/docs.hacc.space/config.toml b/websites/docs.hacc.space/config.toml new file mode 100644 index 0000000..c890821 --- /dev/null +++ b/websites/docs.hacc.space/config.toml @@ -0,0 +1,35 @@ +# Zola's configuration file, +# +# see https://www.getzola.org/documentation/getting-started/configuration/ +# for available keys. + +# The URL the site will be built for +base_url = "https://docs.hacc.space" + +compile_sass = true +default_language = "en" + +# might be useful — this isn't a blog, obviously, but updates for new entries +# could still be nice, I guess +generate_feed = true +feed_filename = "atom.xml" + +build_search_index = true + +taxonomies = [ + { name = "categories", feed = false}, +] + +[markdown] +highlight_code = true + +[extra] # user-defined keys + +# site title text +main_title = "haccfiles documentation" + +# navbar entries +main_menu = [ + {url = "$BASE_URL", name = "Home"}, + {url = "$BASE_URL/categories", name = "Categories"} +] diff --git a/websites/docs.hacc.space/content b/websites/docs.hacc.space/content new file mode 120000 index 0000000..92a7f82 --- /dev/null +++ b/websites/docs.hacc.space/content @@ -0,0 +1 @@ +../../docs \ No newline at end of file diff --git a/websites/docs.hacc.space/default.nix b/websites/docs.hacc.space/default.nix new file mode 100644 index 0000000..c1c5453 --- /dev/null +++ b/websites/docs.hacc.space/default.nix @@ -0,0 +1,19 @@ +{ stdenvNoCC, zola, writeScriptBin }: + +stdenvNoCC.mkDerivation rec { + name = "docs.hacc.space-static"; + + src = ./.; + + phases = [ "buildPhase" ]; + buildInputs = [ zola ]; + buildPhase = '' + cd $src + mkdir -p $out + zola build --output-dir $out + ''; + + watch = writeScriptBin "watch" '' + ${zola}/bin/zola serve ${src} "$@" + ''; +} diff --git a/websites/docs.hacc.space/sass/style.scss b/websites/docs.hacc.space/sass/style.scss new file mode 100644 index 0000000..2fd384b --- /dev/null +++ b/websites/docs.hacc.space/sass/style.scss @@ -0,0 +1,168 @@ + +@font-face { + font-family: 'share-tech'; + src: url('ShareTech-Regular.ttf') format('truetype'); +} + +html { + overflow: hidden; + height: 100%; +} + +body { + background-color: #000; + color: #fff; + + overflow-y: auto; + overflow-x: hidden; + height: 100%; +} + +#content { + font-family: 'share-tech'; + margin-left: auto; + margin-right: auto; + max-width: 60em; + font-size: 16pt; + position: relative; +} + +p.subtitle { + font-size: 14pt; + font-style: normal; + color: gray; +} + +article { + margin-bottom: 4em; +} + +#searchresults { + width: 90%; + text-align: right; + right: 0; + position: absolute; + background-color: black; + top: 5em; + color: gray; +} + +#searchresults div { + padding: 0.5em; + border-top: 1px dashed gray; +} + +#searchresults div:last-child { + border-bottom: 1px dashed gray; +} + +.searchresultprevtext { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + display: inline-block; + width: 40em; + float: left; +} + +footer.content { + top: 50px; + color: #cccccc; + font-size: 14px; + margin-bottom: 4em; +} + +footer a { + color: #cccccc; +} + +.logo { + position: relative; + width: 100%; +} +.logo > img { + width: 300px; + max-width: 100%; +} + +h1 { + font-size: 32pt; +} + +#headernav { + text-align: right; + margin: 1em; +} + +#headernav > a { + padding: 0.2em; + font-size: 20pt; + font-family: share-tech; +} + +h1, h2, h3, h4, h5, h6{ + font-weight: 600; + display: inline; + font-family: share-tech; + background: rgb(59,115,185); + background: linear-gradient(90deg, rgb(59, 115, 185) 0%, rgb(229, 35, 33) 100%); + background-clip: border-box; + color: transparent; + -webkit-background-clip: text; + background-clip: text; +} +/* +h4 { + //font-weight: 600; + //display: inline; + font-family: share-tech; + //background: rgb(59,115,185); + //background: linear-gradient(90deg, rgb(59, 115, 185) 0%, rgb(229, 35, 33) 100%); + //background-clip: border-box; + color: #fff; + //-webkit-background-clip: text; + //background-clip: text; +} +*/ +a { + text-decoration: none; + color: #3b73b9; + transition: color .1s linear; +} +a:hover { + /*color: #e52321;*/ + color: #4e9af9; +} + +ul { + margin-top: 0; +} + + +pre { + padding: 1rem; + overflow: auto; + font-size: 16px; +} +// The line numbers already provide some kind of left/right padding +pre[data-linenos] { + padding: 1rem 0; +} +pre table td { + padding: 0; +} +// The line number cells +pre table td:nth-of-type(1) { + text-align: center; + user-select: none; +} +pre mark { + // If you want your highlights to take the full width. + display: block; + // The default background colour of a mark is bright yellow + background-color: rgba(254, 252, 232, 0.9); +} +pre table { + width: 100%; + border-collapse: collapse; +} diff --git a/websites/docs.hacc.space/static/ShareTech-Regular.ttf b/websites/docs.hacc.space/static/ShareTech-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..787ba839aaf259b220c4360211ca6a71536cccdd GIT binary patch literal 29536 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 literal 0 HcmV?d00001 diff --git a/websites/docs.hacc.space/static/search.js b/websites/docs.hacc.space/static/search.js new file mode 100644 index 0000000..183095d --- /dev/null +++ b/websites/docs.hacc.space/static/search.js @@ -0,0 +1,52 @@ + +function mkDiv (res) { + let div = document.createElement("div"); + let a = document.createElement("a"); + a.innerText = res.doc.title; + a.href = res.ref; + let text = document.createElement("span"); + text.innerText = res.doc.body.slice(0,400).replaceAll("\n", " "); + text.classList.add("searchresultprevtext"); + + div.appendChild(text); + div.appendChild(a); + return div; +} + +window.onload = () => { + console.log("hello!") + let searchbox = document.getElementById("searchbox"); + searchbox.innerHTML = + " \ + "; + + let searchinput = document.getElementById("searchinput"); + let searchresults = document.getElementById("searchresults"); + + let index = elasticlunr.Index.load(window.searchIndex); + + searchinput.addEventListener("keyup", () => { + let term = searchinput.value.trim(); + let results = []; + if (term !== "") { + results = index.search(term, {}); + console.log(results); + + while (searchresults.lastChild) { + searchresults.removeChild(searchresults.lastChild) + } + if (results.length !== 0) { + let resultdivs = results.map(mkDiv); + resultdivs.map((div) => searchresults.appendChild(div)); + } else { + searchresults.innerHTML = + term.length <= 4 ? + "
Need at least four characters to search.
" + : "
No results here.
"; + } + searchresults.style.display = "initial"; + } else { + searchresults.style.display = "none"; + } + }); +} diff --git a/websites/docs.hacc.space/templates/base.html b/websites/docs.hacc.space/templates/base.html new file mode 100644 index 0000000..2810c83 --- /dev/null +++ b/websites/docs.hacc.space/templates/base.html @@ -0,0 +1,43 @@ + + + + + {{ config.extra.main_title }} + + + + + + + {% block head_extra %} + {% endblock head_extra %} + + +
+
+

{{ config.extra.main_title }}

+ +
+ + {% block content %} {% endblock %} + + + +
+ + diff --git a/websites/docs.hacc.space/templates/blog.html b/websites/docs.hacc.space/templates/blog.html new file mode 100644 index 0000000..63775bc --- /dev/null +++ b/websites/docs.hacc.space/templates/blog.html @@ -0,0 +1,12 @@ +{% extends "base.html" %} + +{% block content %} +

+ {{ section.title }} +

+ +{% endblock content %} diff --git a/websites/docs.hacc.space/templates/categories/list.html b/websites/docs.hacc.space/templates/categories/list.html new file mode 100644 index 0000000..1394c85 --- /dev/null +++ b/websites/docs.hacc.space/templates/categories/list.html @@ -0,0 +1,17 @@ +{% extends "base.html" %} + +{% block content %} +
+ +

Categories

+

+ {% if terms %} +

    + {% for term in terms %} +
  • {{ term.name }} ({{ term.pages | length }})
  • + {% endfor %} +
+ {% endif %} +

+
+{% endblock content %} diff --git a/websites/docs.hacc.space/templates/categories/single.html b/websites/docs.hacc.space/templates/categories/single.html new file mode 100644 index 0000000..69133a4 --- /dev/null +++ b/websites/docs.hacc.space/templates/categories/single.html @@ -0,0 +1,12 @@ +{% extends "base.html" %} + +{% import "post_macros.html" as post_macros %} +{% block content %} + +

Posts in category "{{ term.name }}"

+ {% for page in term.pages %} +

+

{{ page.title }}

+

+ {% endfor %} +{% endblock content %} diff --git a/websites/docs.hacc.space/templates/doc-page.html b/websites/docs.hacc.space/templates/doc-page.html new file mode 100644 index 0000000..f433657 --- /dev/null +++ b/websites/docs.hacc.space/templates/doc-page.html @@ -0,0 +1,15 @@ +{% extends "base.html" %} + +{% import "post_macros.html" as post_macros %} +{% block content %} +
+ +
+{% endblock content %} diff --git a/websites/docs.hacc.space/templates/index.html b/websites/docs.hacc.space/templates/index.html new file mode 100644 index 0000000..8fae414 --- /dev/null +++ b/websites/docs.hacc.space/templates/index.html @@ -0,0 +1,23 @@ +{% extends "base.html" %} + +{% block content %} +
+ {% for page in section.pages %} +

+

{{ page.title }}

+

+ {% endfor %} + + {% for sub in section.subsections %} + {% set subsection = get_section(path=sub) %} +

+

{{ subsection.title }}

+ {% for page in subsection.pages %} +

+

{{ page.title }}

+

+ {% endfor %} +

+ {% endfor %} +
+{% endblock content %} diff --git a/websites/docs.hacc.space/templates/post_macros.html b/websites/docs.hacc.space/templates/post_macros.html new file mode 100644 index 0000000..1fb7e9b --- /dev/null +++ b/websites/docs.hacc.space/templates/post_macros.html @@ -0,0 +1,15 @@ +{% macro paginator_nav(paginator) %} + + + +{% endmacro paginator_nav %} diff --git a/websites/docs.hacc.space/templates/section.html b/websites/docs.hacc.space/templates/section.html new file mode 100644 index 0000000..d3a223b --- /dev/null +++ b/websites/docs.hacc.space/templates/section.html @@ -0,0 +1,15 @@ +{% extends "index.html" %} + +{% block content %} +

{{ section.title }}

+

{{ section.content | safe }}

+

Pages in section

+ + +{% endblock content %}