summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--sys/auth/default.nix7
-rw-r--r--sys/auth/login.nix22
-rw-r--r--sys/auth/oath.nix38
-rw-r--r--sys/auth/openssh.nix193
-rw-r--r--sys/auth/ssh-key.pub1
-rw-r--r--sys/baseline/default.nix95
-rw-r--r--sys/boot/chain.nix41
-rw-r--r--sys/boot/default.nix14
-rw-r--r--sys/boot/detached-luks.nix117
-rw-r--r--sys/boot/efi.nix49
-rw-r--r--sys/boot/firmware.nix33
-rw-r--r--sys/boot/fscrypt.nix30
-rw-r--r--sys/boot/impermanence.nix56
-rw-r--r--sys/boot/namespaced.nix33
-rw-r--r--sys/boot/secure-boot.nix51
-rw-r--r--sys/boot/stack/btrfs-toplevel-multidrive.nix99
-rw-r--r--sys/boot/stack/default.nix6
-rw-r--r--sys/boot/stack/luks-ext4-fscrypt-impermanence.nix98
-rw-r--r--sys/boot/tpm.nix128
-rw-r--r--sys/btrfs/default.nix6
-rw-r--r--sys/btrfs/mounts.nix47
-rw-r--r--sys/btrfs/snapper.nix76
-rw-r--r--sys/default.nix38
-rw-r--r--sys/env/default.nix8
-rw-r--r--sys/env/domains.nix1
-rw-r--r--sys/env/maps.nix1
-rw-r--r--sys/env/users.nix1
-rw-r--r--sys/env/virtual.nix1
-rw-r--r--sys/gitea/default.nix41
-rw-r--r--sys/hardware/altera.nix25
-rw-r--r--sys/hardware/apc.nix33
-rw-r--r--sys/hardware/athena.nix48
-rw-r--r--sys/hardware/bluetooth.nix19
-rw-r--r--sys/hardware/default.nix13
-rw-r--r--sys/hardware/epson.nix38
-rw-r--r--sys/hardware/laptop.nix19
-rw-r--r--sys/hardware/printing.nix50
-rw-r--r--sys/hardware/thinkpad.nix42
-rw-r--r--sys/hardware/yubico.nix24
-rw-r--r--sys/home-assistant/default.nix6
-rw-r--r--sys/home-assistant/hass.nix79
-rw-r--r--sys/home-assistant/yaml-extra.nix23
-rw-r--r--sys/jobs/default.nix5
-rw-r--r--sys/jobs/pki-expiry/default.nix60
-rw-r--r--sys/jobs/pki-expiry/pki-expiry.sh108
-rw-r--r--sys/kiosk/default.nix48
-rw-r--r--sys/mail/default.nix246
-rw-r--r--sys/mta/default.nix269
-rw-r--r--sys/net/default.nix9
-rw-r--r--sys/net/fail2ban.nix37
-rw-r--r--sys/net/interfaces.nix119
-rw-r--r--sys/net/nets.nix1
-rw-r--r--sys/net/options.nix278
-rw-r--r--sys/net/vsock.nix63
-rw-r--r--sys/ns/default.nix10
-rw-r--r--sys/ns/dkim/README.md1
-rw-r--r--sys/ns/mx.nix60
-rw-r--r--sys/ns/ns.nix153
-rw-r--r--sys/ns/nsd.nix87
-rw-r--r--sys/ns/ptr/default.nix9
-rw-r--r--sys/ns/ptr/gate-public-v4/default.nix14
-rw-r--r--sys/ns/ptr/gate-public-v4/serial.nix6
-rw-r--r--sys/ns/ptr/gate-public-v6/default.nix14
-rw-r--r--sys/ns/ptr/gate-public-v6/serial.nix6
-rw-r--r--sys/ns/ptr/static-prefix-v6/default.nix14
-rw-r--r--sys/ns/ptr/static-prefix-v6/serial.nix6
-rw-r--r--sys/ns/rr.nix520
-rw-r--r--sys/ns/zones/README.md1
-rw-r--r--sys/nspawn/default.nix5
-rw-r--r--sys/nspawn/dmz.nix229
-rw-r--r--sys/platform/README.md1
-rw-r--r--sys/preset/default.nix6
-rw-r--r--sys/preset/dmz.nix64
-rw-r--r--sys/preset/user.nix73
-rw-r--r--sys/seat/default.nix142
-rw-r--r--sys/syncthing/default.nix45
-rw-r--r--sys/virt/default.nix5
-rw-r--r--sys/virt/dom/README.md1
-rw-r--r--sys/virt/libvirt.nix64
-rw-r--r--sys/web/default.nix7
-rw-r--r--sys/web/nginx.nix94
-rw-r--r--sys/web/php-fpm.nix154
-rw-r--r--sys/web/sites/default.nix7
-rw-r--r--sys/web/sites/home.nix38
-rw-r--r--sys/web/sites/host.nix106
-rw-r--r--sys/web/sites/portal.nix42
-rw-r--r--sysret.org/.gitignore1
-rw-r--r--sysret.org/README.updating.txt (renamed from README.updating.txt)0
-rw-r--r--sysret.org/config.toml (renamed from config.toml)0
-rw-r--r--sysret.org/themes/tabi-lean/.gitignore (renamed from themes/tabi-lean/.gitignore)0
-rw-r--r--sysret.org/themes/tabi-lean/LICENSE (renamed from themes/tabi-lean/LICENSE)0
-rw-r--r--sysret.org/themes/tabi-lean/config.toml (renamed from themes/tabi-lean/config.toml)0
-rw-r--r--sysret.org/themes/tabi-lean/i18n/ar.toml (renamed from themes/tabi-lean/i18n/ar.toml)0
-rw-r--r--sysret.org/themes/tabi-lean/i18n/ca.toml (renamed from themes/tabi-lean/i18n/ca.toml)0
-rw-r--r--sysret.org/themes/tabi-lean/i18n/de.toml (renamed from themes/tabi-lean/i18n/de.toml)0
-rw-r--r--sysret.org/themes/tabi-lean/i18n/en.toml (renamed from themes/tabi-lean/i18n/en.toml)0
-rw-r--r--sysret.org/themes/tabi-lean/i18n/es.toml (renamed from themes/tabi-lean/i18n/es.toml)0
-rw-r--r--sysret.org/themes/tabi-lean/i18n/et.toml (renamed from themes/tabi-lean/i18n/et.toml)0
-rw-r--r--sysret.org/themes/tabi-lean/i18n/fa.toml (renamed from themes/tabi-lean/i18n/fa.toml)0
-rw-r--r--sysret.org/themes/tabi-lean/i18n/fi.toml (renamed from themes/tabi-lean/i18n/fi.toml)0
-rw-r--r--sysret.org/themes/tabi-lean/i18n/fr.toml (renamed from themes/tabi-lean/i18n/fr.toml)0
-rw-r--r--sysret.org/themes/tabi-lean/i18n/hi.toml (renamed from themes/tabi-lean/i18n/hi.toml)0
-rw-r--r--sysret.org/themes/tabi-lean/i18n/it.toml (renamed from themes/tabi-lean/i18n/it.toml)0
-rw-r--r--sysret.org/themes/tabi-lean/i18n/ja.toml (renamed from themes/tabi-lean/i18n/ja.toml)0
-rw-r--r--sysret.org/themes/tabi-lean/i18n/ko.toml (renamed from themes/tabi-lean/i18n/ko.toml)0
-rw-r--r--sysret.org/themes/tabi-lean/i18n/nl.toml (renamed from themes/tabi-lean/i18n/nl.toml)0
-rw-r--r--sysret.org/themes/tabi-lean/i18n/or.toml (renamed from themes/tabi-lean/i18n/or.toml)0
-rw-r--r--sysret.org/themes/tabi-lean/i18n/pt-PT.toml (renamed from themes/tabi-lean/i18n/pt-PT.toml)0
-rw-r--r--sysret.org/themes/tabi-lean/i18n/ru.toml (renamed from themes/tabi-lean/i18n/ru.toml)0
-rw-r--r--sysret.org/themes/tabi-lean/i18n/uk.toml (renamed from themes/tabi-lean/i18n/uk.toml)0
-rw-r--r--sysret.org/themes/tabi-lean/i18n/zh-Hans.toml (renamed from themes/tabi-lean/i18n/zh-Hans.toml)0
-rw-r--r--sysret.org/themes/tabi-lean/i18n/zh-Hant.toml (renamed from themes/tabi-lean/i18n/zh-Hant.toml)0
-rw-r--r--sysret.org/themes/tabi-lean/sass/main.scss (renamed from themes/tabi-lean/sass/main.scss)0
-rw-r--r--sysret.org/themes/tabi-lean/sass/parts/_admonitions.scss (renamed from themes/tabi-lean/sass/parts/_admonitions.scss)0
-rw-r--r--sysret.org/themes/tabi-lean/sass/parts/_archive.scss (renamed from themes/tabi-lean/sass/parts/_archive.scss)0
-rw-r--r--sysret.org/themes/tabi-lean/sass/parts/_aside.scss (renamed from themes/tabi-lean/sass/parts/_aside.scss)0
-rw-r--r--sysret.org/themes/tabi-lean/sass/parts/_cards.scss (renamed from themes/tabi-lean/sass/parts/_cards.scss)0
-rw-r--r--sysret.org/themes/tabi-lean/sass/parts/_code.scss (renamed from themes/tabi-lean/sass/parts/_code.scss)0
-rw-r--r--sysret.org/themes/tabi-lean/sass/parts/_comments.scss (renamed from themes/tabi-lean/sass/parts/_comments.scss)0
-rw-r--r--sysret.org/themes/tabi-lean/sass/parts/_footer.scss (renamed from themes/tabi-lean/sass/parts/_footer.scss)0
-rw-r--r--sysret.org/themes/tabi-lean/sass/parts/_header-anchor.scss (renamed from themes/tabi-lean/sass/parts/_header-anchor.scss)0
-rw-r--r--sysret.org/themes/tabi-lean/sass/parts/_header.scss (renamed from themes/tabi-lean/sass/parts/_header.scss)0
-rw-r--r--sysret.org/themes/tabi-lean/sass/parts/_home-banner.scss (renamed from themes/tabi-lean/sass/parts/_home-banner.scss)0
-rw-r--r--sysret.org/themes/tabi-lean/sass/parts/_iine.scss (renamed from themes/tabi-lean/sass/parts/_iine.scss)0
-rw-r--r--sysret.org/themes/tabi-lean/sass/parts/_image-hover.scss (renamed from themes/tabi-lean/sass/parts/_image-hover.scss)0
-rw-r--r--sysret.org/themes/tabi-lean/sass/parts/_image-toggler.scss (renamed from themes/tabi-lean/sass/parts/_image-toggler.scss)0
-rw-r--r--sysret.org/themes/tabi-lean/sass/parts/_image.scss (renamed from themes/tabi-lean/sass/parts/_image.scss)0
-rw-r--r--sysret.org/themes/tabi-lean/sass/parts/_misc.scss (renamed from themes/tabi-lean/sass/parts/_misc.scss)0
-rw-r--r--sysret.org/themes/tabi-lean/sass/parts/_multilingual_quote.scss (renamed from themes/tabi-lean/sass/parts/_multilingual_quote.scss)0
-rw-r--r--sysret.org/themes/tabi-lean/sass/parts/_pagination.scss (renamed from themes/tabi-lean/sass/parts/_pagination.scss)0
-rw-r--r--sysret.org/themes/tabi-lean/sass/parts/_posts_list.scss (renamed from themes/tabi-lean/sass/parts/_posts_list.scss)0
-rw-r--r--sysret.org/themes/tabi-lean/sass/parts/_quick_navigation_buttons.scss (renamed from themes/tabi-lean/sass/parts/_quick_navigation_buttons.scss)0
-rw-r--r--sysret.org/themes/tabi-lean/sass/parts/_search.scss (renamed from themes/tabi-lean/sass/parts/_search.scss)0
-rw-r--r--sysret.org/themes/tabi-lean/sass/parts/_spoiler.scss (renamed from themes/tabi-lean/sass/parts/_spoiler.scss)0
-rw-r--r--sysret.org/themes/tabi-lean/sass/parts/_syntax_theme.scss (renamed from themes/tabi-lean/sass/parts/_syntax_theme.scss)0
-rw-r--r--sysret.org/themes/tabi-lean/sass/parts/_table.scss (renamed from themes/tabi-lean/sass/parts/_table.scss)0
-rw-r--r--sysret.org/themes/tabi-lean/sass/parts/_tags.scss (renamed from themes/tabi-lean/sass/parts/_tags.scss)0
-rw-r--r--sysret.org/themes/tabi-lean/sass/parts/_theme-switch.scss (renamed from themes/tabi-lean/sass/parts/_theme-switch.scss)0
-rw-r--r--sysret.org/themes/tabi-lean/sass/parts/_webmention.scss (renamed from themes/tabi-lean/sass/parts/_webmention.scss)0
-rw-r--r--sysret.org/themes/tabi-lean/sass/parts/_zola-error.scss (renamed from themes/tabi-lean/sass/parts/_zola-error.scss)0
-rw-r--r--sysret.org/themes/tabi-lean/sass/skins/blue.scss (renamed from themes/tabi-lean/sass/skins/blue.scss)0
-rw-r--r--sysret.org/themes/tabi-lean/sass/skins/evangelion.scss (renamed from themes/tabi-lean/sass/skins/evangelion.scss)0
-rw-r--r--sysret.org/themes/tabi-lean/sass/skins/indigo_ingot.scss (renamed from themes/tabi-lean/sass/skins/indigo_ingot.scss)0
-rw-r--r--sysret.org/themes/tabi-lean/sass/skins/lavender.scss (renamed from themes/tabi-lean/sass/skins/lavender.scss)0
-rw-r--r--sysret.org/themes/tabi-lean/sass/skins/lowcontrast_orange.scss (renamed from themes/tabi-lean/sass/skins/lowcontrast_orange.scss)0
-rw-r--r--sysret.org/themes/tabi-lean/sass/skins/lowcontrast_peach.scss (renamed from themes/tabi-lean/sass/skins/lowcontrast_peach.scss)0
-rw-r--r--sysret.org/themes/tabi-lean/sass/skins/lowcontrast_pink.scss (renamed from themes/tabi-lean/sass/skins/lowcontrast_pink.scss)0
-rw-r--r--sysret.org/themes/tabi-lean/sass/skins/mint.scss (renamed from themes/tabi-lean/sass/skins/mint.scss)0
-rw-r--r--sysret.org/themes/tabi-lean/sass/skins/monochrome.scss (renamed from themes/tabi-lean/sass/skins/monochrome.scss)0
-rw-r--r--sysret.org/themes/tabi-lean/sass/skins/posixlycorrect.scss (renamed from themes/tabi-lean/sass/skins/posixlycorrect.scss)0
-rw-r--r--sysret.org/themes/tabi-lean/sass/skins/red.scss (renamed from themes/tabi-lean/sass/skins/red.scss)0
-rw-r--r--sysret.org/themes/tabi-lean/sass/skins/sakura.scss (renamed from themes/tabi-lean/sass/skins/sakura.scss)0
-rw-r--r--sysret.org/themes/tabi-lean/sass/skins/teal.scss (renamed from themes/tabi-lean/sass/skins/teal.scss)0
-rw-r--r--sysret.org/themes/tabi-lean/static/custom_subset.css (renamed from themes/tabi-lean/static/custom_subset.css)0
-rw-r--r--sysret.org/themes/tabi-lean/static/feed_style.xsl (renamed from themes/tabi-lean/static/feed_style.xsl)0
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-Bold.ttf (renamed from themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-Bold.ttf)bin2389020 -> 2389020 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-BoldItalic.ttf (renamed from themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-BoldItalic.ttf)bin2392132 -> 2392132 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-ExtraBold.ttf (renamed from themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-ExtraBold.ttf)bin2391492 -> 2391492 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-ExtraBoldItalic.ttf (renamed from themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-ExtraBoldItalic.ttf)bin2393472 -> 2393472 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-ExtraLight.ttf (renamed from themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-ExtraLight.ttf)bin2387208 -> 2387208 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-ExtraLightItalic.ttf (renamed from themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-ExtraLightItalic.ttf)bin2387952 -> 2387952 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-Italic.ttf (renamed from themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-Italic.ttf)bin2389592 -> 2389592 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-Light.ttf (renamed from themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-Light.ttf)bin2388892 -> 2388892 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-LightItalic.ttf (renamed from themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-LightItalic.ttf)bin2390312 -> 2390312 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-Medium.ttf (renamed from themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-Medium.ttf)bin2386364 -> 2386364 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-MediumItalic.ttf (renamed from themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-MediumItalic.ttf)bin2389596 -> 2389596 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-Regular.ttf (renamed from themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-Regular.ttf)bin2386636 -> 2386636 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-SemiBold.ttf (renamed from themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-SemiBold.ttf)bin2387944 -> 2387944 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-SemiBoldItalic.ttf (renamed from themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-SemiBoldItalic.ttf)bin2392048 -> 2392048 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-Thin.ttf (renamed from themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-Thin.ttf)bin2384112 -> 2384112 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-ThinItalic.ttf (renamed from themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-ThinItalic.ttf)bin2387148 -> 2387148 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_AMS-Regular.ttf (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_AMS-Regular.ttf)bin63632 -> 63632 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_AMS-Regular.woff (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_AMS-Regular.woff)bin33516 -> 33516 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_AMS-Regular.woff2 (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_AMS-Regular.woff2)bin28076 -> 28076 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Caligraphic-Bold.ttf (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Caligraphic-Bold.ttf)bin12368 -> 12368 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Caligraphic-Bold.woff (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Caligraphic-Bold.woff)bin7716 -> 7716 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Caligraphic-Bold.woff2 (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Caligraphic-Bold.woff2)bin6912 -> 6912 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Caligraphic-Regular.ttf (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Caligraphic-Regular.ttf)bin12344 -> 12344 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Caligraphic-Regular.woff (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Caligraphic-Regular.woff)bin7656 -> 7656 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Caligraphic-Regular.woff2 (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Caligraphic-Regular.woff2)bin6908 -> 6908 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Fraktur-Bold.ttf (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Fraktur-Bold.ttf)bin19584 -> 19584 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Fraktur-Bold.woff (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Fraktur-Bold.woff)bin13296 -> 13296 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Fraktur-Bold.woff2 (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Fraktur-Bold.woff2)bin11348 -> 11348 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Fraktur-Regular.ttf (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Fraktur-Regular.ttf)bin19572 -> 19572 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Fraktur-Regular.woff (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Fraktur-Regular.woff)bin13208 -> 13208 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Fraktur-Regular.woff2 (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Fraktur-Regular.woff2)bin11316 -> 11316 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Bold.ttf (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Bold.ttf)bin51336 -> 51336 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Bold.woff (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Bold.woff)bin29912 -> 29912 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Bold.woff2 (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Bold.woff2)bin25324 -> 25324 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-BoldItalic.ttf (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-BoldItalic.ttf)bin32968 -> 32968 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-BoldItalic.woff (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-BoldItalic.woff)bin19412 -> 19412 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-BoldItalic.woff2 (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-BoldItalic.woff2)bin16780 -> 16780 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Italic.ttf (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Italic.ttf)bin33580 -> 33580 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Italic.woff (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Italic.woff)bin19676 -> 19676 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Italic.woff2 (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Italic.woff2)bin16988 -> 16988 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Regular.ttf (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Regular.ttf)bin53580 -> 53580 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Regular.woff (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Regular.woff)bin30772 -> 30772 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Regular.woff2 (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Regular.woff2)bin26272 -> 26272 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Math-BoldItalic.ttf (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Math-BoldItalic.ttf)bin31196 -> 31196 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Math-BoldItalic.woff (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Math-BoldItalic.woff)bin18668 -> 18668 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Math-BoldItalic.woff2 (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Math-BoldItalic.woff2)bin16400 -> 16400 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Math-Italic.ttf (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Math-Italic.ttf)bin31308 -> 31308 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Math-Italic.woff (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Math-Italic.woff)bin18748 -> 18748 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Math-Italic.woff2 (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Math-Italic.woff2)bin16440 -> 16440 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Bold.ttf (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Bold.ttf)bin24504 -> 24504 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Bold.woff (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Bold.woff)bin14408 -> 14408 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Bold.woff2 (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Bold.woff2)bin12216 -> 12216 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Italic.ttf (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Italic.ttf)bin22364 -> 22364 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Italic.woff (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Italic.woff)bin14112 -> 14112 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Italic.woff2 (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Italic.woff2)bin12028 -> 12028 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Regular.ttf (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Regular.ttf)bin19436 -> 19436 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Regular.woff (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Regular.woff)bin12316 -> 12316 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Regular.woff2 (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Regular.woff2)bin10344 -> 10344 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Script-Regular.ttf (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Script-Regular.ttf)bin16648 -> 16648 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Script-Regular.woff (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Script-Regular.woff)bin10588 -> 10588 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Script-Regular.woff2 (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Script-Regular.woff2)bin9644 -> 9644 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size1-Regular.ttf (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size1-Regular.ttf)bin12228 -> 12228 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size1-Regular.woff (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size1-Regular.woff)bin6496 -> 6496 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size1-Regular.woff2 (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size1-Regular.woff2)bin5468 -> 5468 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size2-Regular.ttf (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size2-Regular.ttf)bin11508 -> 11508 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size2-Regular.woff (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size2-Regular.woff)bin6188 -> 6188 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size2-Regular.woff2 (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size2-Regular.woff2)bin5208 -> 5208 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size3-Regular.ttf (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size3-Regular.ttf)bin7588 -> 7588 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size3-Regular.woff (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size3-Regular.woff)bin4420 -> 4420 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size3-Regular.woff2 (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size3-Regular.woff2)bin3624 -> 3624 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size4-Regular.ttf (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size4-Regular.ttf)bin10364 -> 10364 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size4-Regular.woff (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size4-Regular.woff)bin5980 -> 5980 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size4-Regular.woff2 (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size4-Regular.woff2)bin4928 -> 4928 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Typewriter-Regular.ttf (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Typewriter-Regular.ttf)bin27556 -> 27556 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Typewriter-Regular.woff (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Typewriter-Regular.woff)bin16028 -> 16028 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Typewriter-Regular.woff2 (renamed from themes/tabi-lean/static/fonts/KaTeX/KaTeX_Typewriter-Regular.woff2)bin13568 -> 13568 bytes
-rw-r--r--sysret.org/themes/tabi-lean/static/inter_subset_en.css (renamed from themes/tabi-lean/static/inter_subset_en.css)0
-rw-r--r--sysret.org/themes/tabi-lean/static/inter_subset_es.css (renamed from themes/tabi-lean/static/inter_subset_es.css)0
-rw-r--r--sysret.org/themes/tabi-lean/static/isso.css (renamed from themes/tabi-lean/static/isso.css)0
-rw-r--r--sysret.org/themes/tabi-lean/static/isso.min.css (renamed from themes/tabi-lean/static/isso.min.css)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/codeBlockNameLinks.js (renamed from themes/tabi-lean/static/js/codeBlockNameLinks.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/codeBlockNameLinks.min.js (renamed from themes/tabi-lean/static/js/codeBlockNameLinks.min.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/copyCodeToClipboard.js (renamed from themes/tabi-lean/static/js/copyCodeToClipboard.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/copyCodeToClipboard.min.js (renamed from themes/tabi-lean/static/js/copyCodeToClipboard.min.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/decodeMail.js (renamed from themes/tabi-lean/static/js/decodeMail.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/decodeMail.min.js (renamed from themes/tabi-lean/static/js/decodeMail.min.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/filterCards.js (renamed from themes/tabi-lean/static/js/filterCards.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/filterCards.min.js (renamed from themes/tabi-lean/static/js/filterCards.min.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/footnoteBacklinks.js (renamed from themes/tabi-lean/static/js/footnoteBacklinks.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/footnoteBacklinks.min.js (renamed from themes/tabi-lean/static/js/footnoteBacklinks.min.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/giscus.js (renamed from themes/tabi-lean/static/js/giscus.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/giscus.min.js (renamed from themes/tabi-lean/static/js/giscus.min.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/hyvortalk.js (renamed from themes/tabi-lean/static/js/hyvortalk.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/hyvortalk.min.js (renamed from themes/tabi-lean/static/js/hyvortalk.min.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/initializeTheme.js (renamed from themes/tabi-lean/static/js/initializeTheme.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/initializeTheme.min.js (renamed from themes/tabi-lean/static/js/initializeTheme.min.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/isso.js (renamed from themes/tabi-lean/static/js/isso.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/isso.min.js (renamed from themes/tabi-lean/static/js/isso.min.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/katex.min.js (renamed from themes/tabi-lean/static/js/katex.min.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/loadComments.js (renamed from themes/tabi-lean/static/js/loadComments.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/loadComments.min.js (renamed from themes/tabi-lean/static/js/loadComments.min.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/lunr/lunr.da.js (renamed from themes/tabi-lean/static/js/lunr/lunr.da.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/lunr/lunr.da.min.js (renamed from themes/tabi-lean/static/js/lunr/lunr.da.min.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/lunr/lunr.de.js (renamed from themes/tabi-lean/static/js/lunr/lunr.de.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/lunr/lunr.de.min.js (renamed from themes/tabi-lean/static/js/lunr/lunr.de.min.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/lunr/lunr.du.js (renamed from themes/tabi-lean/static/js/lunr/lunr.du.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/lunr/lunr.du.min.js (renamed from themes/tabi-lean/static/js/lunr/lunr.du.min.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/lunr/lunr.es.js (renamed from themes/tabi-lean/static/js/lunr/lunr.es.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/lunr/lunr.es.min.js (renamed from themes/tabi-lean/static/js/lunr/lunr.es.min.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/lunr/lunr.fi.js (renamed from themes/tabi-lean/static/js/lunr/lunr.fi.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/lunr/lunr.fi.min.js (renamed from themes/tabi-lean/static/js/lunr/lunr.fi.min.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/lunr/lunr.fr.js (renamed from themes/tabi-lean/static/js/lunr/lunr.fr.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/lunr/lunr.fr.min.js (renamed from themes/tabi-lean/static/js/lunr/lunr.fr.min.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/lunr/lunr.hu.js (renamed from themes/tabi-lean/static/js/lunr/lunr.hu.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/lunr/lunr.hu.min.js (renamed from themes/tabi-lean/static/js/lunr/lunr.hu.min.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/lunr/lunr.it.js (renamed from themes/tabi-lean/static/js/lunr/lunr.it.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/lunr/lunr.it.min.js (renamed from themes/tabi-lean/static/js/lunr/lunr.it.min.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/lunr/lunr.jp.js (renamed from themes/tabi-lean/static/js/lunr/lunr.jp.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/lunr/lunr.jp.min.js (renamed from themes/tabi-lean/static/js/lunr/lunr.jp.min.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/lunr/lunr.no.js (renamed from themes/tabi-lean/static/js/lunr/lunr.no.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/lunr/lunr.no.min.js (renamed from themes/tabi-lean/static/js/lunr/lunr.no.min.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/lunr/lunr.pt.js (renamed from themes/tabi-lean/static/js/lunr/lunr.pt.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/lunr/lunr.pt.min.js (renamed from themes/tabi-lean/static/js/lunr/lunr.pt.min.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/lunr/lunr.ro.js (renamed from themes/tabi-lean/static/js/lunr/lunr.ro.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/lunr/lunr.ro.min.js (renamed from themes/tabi-lean/static/js/lunr/lunr.ro.min.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/lunr/lunr.ru.js (renamed from themes/tabi-lean/static/js/lunr/lunr.ru.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/lunr/lunr.ru.min.js (renamed from themes/tabi-lean/static/js/lunr/lunr.ru.min.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/lunr/lunr.sv.js (renamed from themes/tabi-lean/static/js/lunr/lunr.sv.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/lunr/lunr.sv.min.js (renamed from themes/tabi-lean/static/js/lunr/lunr.sv.min.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/lunr/lunr.tr.js (renamed from themes/tabi-lean/static/js/lunr/lunr.tr.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/lunr/lunr.tr.min.js (renamed from themes/tabi-lean/static/js/lunr/lunr.tr.min.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/lunr/lunr.zh.js (renamed from themes/tabi-lean/static/js/lunr/lunr.zh.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/lunr/lunr.zh.min.js (renamed from themes/tabi-lean/static/js/lunr/lunr.zh.min.js)0
-rwxr-xr-xsysret.org/themes/tabi-lean/static/js/lunr/lunrStemmerSupport.js (renamed from themes/tabi-lean/static/js/lunr/lunrStemmerSupport.js)0
-rwxr-xr-xsysret.org/themes/tabi-lean/static/js/lunr/lunrStemmerSupport.min.js (renamed from themes/tabi-lean/static/js/lunr/lunrStemmerSupport.min.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/mermaid.min.js (renamed from themes/tabi-lean/static/js/mermaid.min.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/searchElasticlunr.js (renamed from themes/tabi-lean/static/js/searchElasticlunr.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/searchElasticlunr.min.js (renamed from themes/tabi-lean/static/js/searchElasticlunr.min.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/sortTable.js (renamed from themes/tabi-lean/static/js/sortTable.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/sortTable.min.js (renamed from themes/tabi-lean/static/js/sortTable.min.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/themeSwitcher.js (renamed from themes/tabi-lean/static/js/themeSwitcher.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/themeSwitcher.min.js (renamed from themes/tabi-lean/static/js/themeSwitcher.min.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/utterances.js (renamed from themes/tabi-lean/static/js/utterances.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/utterances.min.js (renamed from themes/tabi-lean/static/js/utterances.min.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/webmention.js (renamed from themes/tabi-lean/static/js/webmention.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/js/webmention.min.js (renamed from themes/tabi-lean/static/js/webmention.min.js)0
-rw-r--r--sysret.org/themes/tabi-lean/static/katex.min.css (renamed from themes/tabi-lean/static/katex.min.css)0
-rw-r--r--sysret.org/themes/tabi-lean/static/no_js.css (renamed from themes/tabi-lean/static/no_js.css)0
-rw-r--r--sysret.org/themes/tabi-lean/static/sitemap_style.xsl (renamed from themes/tabi-lean/static/sitemap_style.xsl)0
-rw-r--r--sysret.org/themes/tabi-lean/static/social_icons/LICENSE (renamed from themes/tabi-lean/static/social_icons/LICENSE)0
-rw-r--r--sysret.org/themes/tabi-lean/static/social_icons/apple.svg (renamed from themes/tabi-lean/static/social_icons/apple.svg)0
-rw-r--r--sysret.org/themes/tabi-lean/static/social_icons/bitcoin.svg (renamed from themes/tabi-lean/static/social_icons/bitcoin.svg)0
-rw-r--r--sysret.org/themes/tabi-lean/static/social_icons/bluesky.svg (renamed from themes/tabi-lean/static/social_icons/bluesky.svg)0
-rwxr-xr-xsysret.org/themes/tabi-lean/static/social_icons/calckey.svg (renamed from themes/tabi-lean/static/social_icons/calckey.svg)0
-rwxr-xr-xsysret.org/themes/tabi-lean/static/social_icons/castopod.svg (renamed from themes/tabi-lean/static/social_icons/castopod.svg)0
-rw-r--r--sysret.org/themes/tabi-lean/static/social_icons/codeberg.svg (renamed from themes/tabi-lean/static/social_icons/codeberg.svg)0
-rw-r--r--sysret.org/themes/tabi-lean/static/social_icons/debian.svg (renamed from themes/tabi-lean/static/social_icons/debian.svg)0
-rw-r--r--sysret.org/themes/tabi-lean/static/social_icons/deviantart.svg (renamed from themes/tabi-lean/static/social_icons/deviantart.svg)0
-rw-r--r--sysret.org/themes/tabi-lean/static/social_icons/diaspora.svg (renamed from themes/tabi-lean/static/social_icons/diaspora.svg)0
-rw-r--r--sysret.org/themes/tabi-lean/static/social_icons/discord.svg (renamed from themes/tabi-lean/static/social_icons/discord.svg)0
-rw-r--r--sysret.org/themes/tabi-lean/static/social_icons/discourse.svg (renamed from themes/tabi-lean/static/social_icons/discourse.svg)0
-rw-r--r--sysret.org/themes/tabi-lean/static/social_icons/email.svg (renamed from themes/tabi-lean/static/social_icons/email.svg)0
-rw-r--r--sysret.org/themes/tabi-lean/static/social_icons/ethereum.svg (renamed from themes/tabi-lean/static/social_icons/ethereum.svg)0
-rw-r--r--sysret.org/themes/tabi-lean/static/social_icons/etsy.svg (renamed from themes/tabi-lean/static/social_icons/etsy.svg)0
-rw-r--r--sysret.org/themes/tabi-lean/static/social_icons/facebook.svg (renamed from themes/tabi-lean/static/social_icons/facebook.svg)0
-rwxr-xr-xsysret.org/themes/tabi-lean/static/social_icons/forgejo.svg (renamed from themes/tabi-lean/static/social_icons/forgejo.svg)0
-rwxr-xr-xsysret.org/themes/tabi-lean/static/social_icons/friendica.svg (renamed from themes/tabi-lean/static/social_icons/friendica.svg)0
-rwxr-xr-xsysret.org/themes/tabi-lean/static/social_icons/funkwhale.svg (renamed from themes/tabi-lean/static/social_icons/funkwhale.svg)0
-rwxr-xr-xsysret.org/themes/tabi-lean/static/social_icons/gitea.svg (renamed from themes/tabi-lean/static/social_icons/gitea.svg)0
-rw-r--r--sysret.org/themes/tabi-lean/static/social_icons/github.svg (renamed from themes/tabi-lean/static/social_icons/github.svg)0
-rw-r--r--sysret.org/themes/tabi-lean/static/social_icons/gitlab.svg (renamed from themes/tabi-lean/static/social_icons/gitlab.svg)0
-rw-r--r--sysret.org/themes/tabi-lean/static/social_icons/google-scholar.svg (renamed from themes/tabi-lean/static/social_icons/google-scholar.svg)0
-rw-r--r--sysret.org/themes/tabi-lean/static/social_icons/google.svg (renamed from themes/tabi-lean/static/social_icons/google.svg)0
-rwxr-xr-xsysret.org/themes/tabi-lean/static/social_icons/greatape.svg (renamed from themes/tabi-lean/static/social_icons/greatape.svg)0
-rw-r--r--sysret.org/themes/tabi-lean/static/social_icons/hacker-news.svg (renamed from themes/tabi-lean/static/social_icons/hacker-news.svg)0
-rwxr-xr-xsysret.org/themes/tabi-lean/static/social_icons/hubzilla.svg (renamed from themes/tabi-lean/static/social_icons/hubzilla.svg)0
-rw-r--r--sysret.org/themes/tabi-lean/static/social_icons/instagram.svg (renamed from themes/tabi-lean/static/social_icons/instagram.svg)0
-rw-r--r--sysret.org/themes/tabi-lean/static/social_icons/itchio.svg (renamed from themes/tabi-lean/static/social_icons/itchio.svg)0
-rw-r--r--sysret.org/themes/tabi-lean/static/social_icons/keybase.svg (renamed from themes/tabi-lean/static/social_icons/keybase.svg)0
-rwxr-xr-xsysret.org/themes/tabi-lean/static/social_icons/lemmy.svg (renamed from themes/tabi-lean/static/social_icons/lemmy.svg)0
-rw-r--r--sysret.org/themes/tabi-lean/static/social_icons/letterboxd.svg (renamed from themes/tabi-lean/static/social_icons/letterboxd.svg)0
-rw-r--r--sysret.org/themes/tabi-lean/static/social_icons/linkedin.svg (renamed from themes/tabi-lean/static/social_icons/linkedin.svg)0
-rw-r--r--sysret.org/themes/tabi-lean/static/social_icons/mastodon.svg (renamed from themes/tabi-lean/static/social_icons/mastodon.svg)0
-rw-r--r--sysret.org/themes/tabi-lean/static/social_icons/matrix.svg (renamed from themes/tabi-lean/static/social_icons/matrix.svg)0
-rwxr-xr-xsysret.org/themes/tabi-lean/static/social_icons/misskey.svg (renamed from themes/tabi-lean/static/social_icons/misskey.svg)0
-rwxr-xr-xsysret.org/themes/tabi-lean/static/social_icons/nostr.svg (renamed from themes/tabi-lean/static/social_icons/nostr.svg)0
-rw-r--r--sysret.org/themes/tabi-lean/static/social_icons/orcid.svg (renamed from themes/tabi-lean/static/social_icons/orcid.svg)0
-rw-r--r--sysret.org/themes/tabi-lean/static/social_icons/paypal.svg (renamed from themes/tabi-lean/static/social_icons/paypal.svg)0
-rwxr-xr-xsysret.org/themes/tabi-lean/static/social_icons/peertube.svg (renamed from themes/tabi-lean/static/social_icons/peertube.svg)0
-rw-r--r--sysret.org/themes/tabi-lean/static/social_icons/pinterest.svg (renamed from themes/tabi-lean/static/social_icons/pinterest.svg)0
-rwxr-xr-xsysret.org/themes/tabi-lean/static/social_icons/pixelfed.svg (renamed from themes/tabi-lean/static/social_icons/pixelfed.svg)0
-rwxr-xr-xsysret.org/themes/tabi-lean/static/social_icons/pleroma.svg (renamed from themes/tabi-lean/static/social_icons/pleroma.svg)0
-rw-r--r--sysret.org/themes/tabi-lean/static/social_icons/quora.svg (renamed from themes/tabi-lean/static/social_icons/quora.svg)0
-rw-r--r--sysret.org/themes/tabi-lean/static/social_icons/reddit.svg (renamed from themes/tabi-lean/static/social_icons/reddit.svg)0
-rw-r--r--sysret.org/themes/tabi-lean/static/social_icons/rss.svg (renamed from themes/tabi-lean/static/social_icons/rss.svg)0
-rw-r--r--sysret.org/themes/tabi-lean/static/social_icons/signal.svg (renamed from themes/tabi-lean/static/social_icons/signal.svg)0
-rw-r--r--sysret.org/themes/tabi-lean/static/social_icons/skype.svg (renamed from themes/tabi-lean/static/social_icons/skype.svg)0
-rw-r--r--sysret.org/themes/tabi-lean/static/social_icons/slack.svg (renamed from themes/tabi-lean/static/social_icons/slack.svg)0
-rw-r--r--sysret.org/themes/tabi-lean/static/social_icons/snapchat.svg (renamed from themes/tabi-lean/static/social_icons/snapchat.svg)0
-rw-r--r--sysret.org/themes/tabi-lean/static/social_icons/soundcloud.svg (renamed from themes/tabi-lean/static/social_icons/soundcloud.svg)0
-rw-r--r--sysret.org/themes/tabi-lean/static/social_icons/spotify.svg (renamed from themes/tabi-lean/static/social_icons/spotify.svg)0
-rw-r--r--sysret.org/themes/tabi-lean/static/social_icons/stack-exchange.svg (renamed from themes/tabi-lean/static/social_icons/stack-exchange.svg)0
-rw-r--r--sysret.org/themes/tabi-lean/static/social_icons/stack-overflow.svg (renamed from themes/tabi-lean/static/social_icons/stack-overflow.svg)0
-rw-r--r--sysret.org/themes/tabi-lean/static/social_icons/steam.svg (renamed from themes/tabi-lean/static/social_icons/steam.svg)0
-rw-r--r--sysret.org/themes/tabi-lean/static/social_icons/telegram.svg (renamed from themes/tabi-lean/static/social_icons/telegram.svg)0
-rw-r--r--sysret.org/themes/tabi-lean/static/social_icons/twitter.svg (renamed from themes/tabi-lean/static/social_icons/twitter.svg)0
-rw-r--r--sysret.org/themes/tabi-lean/static/social_icons/vimeo.svg (renamed from themes/tabi-lean/static/social_icons/vimeo.svg)0
-rw-r--r--sysret.org/themes/tabi-lean/static/social_icons/whatsapp.svg (renamed from themes/tabi-lean/static/social_icons/whatsapp.svg)0
-rwxr-xr-xsysret.org/themes/tabi-lean/static/social_icons/wordpress.svg (renamed from themes/tabi-lean/static/social_icons/wordpress.svg)0
-rwxr-xr-xsysret.org/themes/tabi-lean/static/social_icons/writefreely.svg (renamed from themes/tabi-lean/static/social_icons/writefreely.svg)0
-rw-r--r--sysret.org/themes/tabi-lean/static/social_icons/x.svg (renamed from themes/tabi-lean/static/social_icons/x.svg)0
-rw-r--r--sysret.org/themes/tabi-lean/static/social_icons/youtube.svg (renamed from themes/tabi-lean/static/social_icons/youtube.svg)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/404.html (renamed from themes/tabi-lean/templates/404.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/anchor-link.html (renamed from themes/tabi-lean/templates/anchor-link.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/archive.html (renamed from themes/tabi-lean/templates/archive.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/atom.xml (renamed from themes/tabi-lean/templates/atom.xml)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/base.html (renamed from themes/tabi-lean/templates/base.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/cards.html (renamed from themes/tabi-lean/templates/cards.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/index.html (renamed from themes/tabi-lean/templates/index.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/info-page.html (renamed from themes/tabi-lean/templates/info-page.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/internal/alias.html (renamed from themes/tabi-lean/templates/internal/alias.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/macros/feed_utils.html (renamed from themes/tabi-lean/templates/macros/feed_utils.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/macros/format_date.html (renamed from themes/tabi-lean/templates/macros/format_date.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/macros/list_posts.html (renamed from themes/tabi-lean/templates/macros/list_posts.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/macros/page_header.html (renamed from themes/tabi-lean/templates/macros/page_header.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/macros/rel_attributes.html (renamed from themes/tabi-lean/templates/macros/rel_attributes.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/macros/series_page.html (renamed from themes/tabi-lean/templates/macros/series_page.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/macros/settings.html (renamed from themes/tabi-lean/templates/macros/settings.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/macros/table_of_contents.html (renamed from themes/tabi-lean/templates/macros/table_of_contents.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/macros/target_attribute.html (renamed from themes/tabi-lean/templates/macros/target_attribute.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/macros/translate.html (renamed from themes/tabi-lean/templates/macros/translate.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/page.html (renamed from themes/tabi-lean/templates/page.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/partials/analytics.html (renamed from themes/tabi-lean/templates/partials/analytics.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/partials/cards_pages.html (renamed from themes/tabi-lean/templates/partials/cards_pages.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/partials/comments.html (renamed from themes/tabi-lean/templates/partials/comments.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/partials/content_security_policy.html (renamed from themes/tabi-lean/templates/partials/content_security_policy.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/partials/copyright.html (renamed from themes/tabi-lean/templates/partials/copyright.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/partials/extra_features.html (renamed from themes/tabi-lean/templates/partials/extra_features.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/partials/filter_card_tags.html (renamed from themes/tabi-lean/templates/partials/filter_card_tags.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/partials/footer.html (renamed from themes/tabi-lean/templates/partials/footer.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/partials/hcard.html (renamed from themes/tabi-lean/templates/partials/hcard.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/partials/hcard_small.html (renamed from themes/tabi-lean/templates/partials/hcard_small.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/partials/header.html (renamed from themes/tabi-lean/templates/partials/header.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/partials/history_url.html (renamed from themes/tabi-lean/templates/partials/history_url.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/partials/home_banner.html (renamed from themes/tabi-lean/templates/partials/home_banner.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/partials/iine_button.html (renamed from themes/tabi-lean/templates/partials/iine_button.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/partials/language_switcher.html (renamed from themes/tabi-lean/templates/partials/language_switcher.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/partials/main_page_posts_list.html (renamed from themes/tabi-lean/templates/partials/main_page_posts_list.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/partials/main_page_projects_list.html (renamed from themes/tabi-lean/templates/partials/main_page_projects_list.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/partials/multilingual_tags.html (renamed from themes/tabi-lean/templates/partials/multilingual_tags.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/partials/nav.html (renamed from themes/tabi-lean/templates/partials/nav.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/partials/paginate.html (renamed from themes/tabi-lean/templates/partials/paginate.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/partials/search_modal.html (renamed from themes/tabi-lean/templates/partials/search_modal.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/partials/social_media_images.html (renamed from themes/tabi-lean/templates/partials/social_media_images.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/partials/theme_switcher.html (renamed from themes/tabi-lean/templates/partials/theme_switcher.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/partials/title.html (renamed from themes/tabi-lean/templates/partials/title.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/partials/webmentions.html (renamed from themes/tabi-lean/templates/partials/webmentions.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/section.html (renamed from themes/tabi-lean/templates/section.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/series.html (renamed from themes/tabi-lean/templates/series.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/shortcodes/add_src_to_code_block.html (renamed from themes/tabi-lean/templates/shortcodes/add_src_to_code_block.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/shortcodes/admonition.html (renamed from themes/tabi-lean/templates/shortcodes/admonition.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/shortcodes/aside.html (renamed from themes/tabi-lean/templates/shortcodes/aside.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/shortcodes/dimmable_image.html (renamed from themes/tabi-lean/templates/shortcodes/dimmable_image.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/shortcodes/dual_theme_image.html (renamed from themes/tabi-lean/templates/shortcodes/dual_theme_image.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/shortcodes/force_text_direction.html (renamed from themes/tabi-lean/templates/shortcodes/force_text_direction.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/shortcodes/full_width_image.html (renamed from themes/tabi-lean/templates/shortcodes/full_width_image.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/shortcodes/iine.html (renamed from themes/tabi-lean/templates/shortcodes/iine.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/shortcodes/image_hover.html (renamed from themes/tabi-lean/templates/shortcodes/image_hover.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/shortcodes/image_toggler.html (renamed from themes/tabi-lean/templates/shortcodes/image_toggler.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/shortcodes/invertible_image.html (renamed from themes/tabi-lean/templates/shortcodes/invertible_image.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/shortcodes/mermaid.html (renamed from themes/tabi-lean/templates/shortcodes/mermaid.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/shortcodes/multilingual_quote.html (renamed from themes/tabi-lean/templates/shortcodes/multilingual_quote.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/shortcodes/references.html (renamed from themes/tabi-lean/templates/shortcodes/references.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/shortcodes/remote_text.html (renamed from themes/tabi-lean/templates/shortcodes/remote_text.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/shortcodes/spoiler.html (renamed from themes/tabi-lean/templates/shortcodes/spoiler.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/shortcodes/toc.html (renamed from themes/tabi-lean/templates/shortcodes/toc.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/shortcodes/wide_container.html (renamed from themes/tabi-lean/templates/shortcodes/wide_container.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/sitemap.xml (renamed from themes/tabi-lean/templates/sitemap.xml)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/tags/list.html (renamed from themes/tabi-lean/templates/tags/list.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/tags/single.html (renamed from themes/tabi-lean/templates/tags/single.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/taxonomy_list.html (renamed from themes/tabi-lean/templates/taxonomy_list.html)0
-rw-r--r--sysret.org/themes/tabi-lean/templates/taxonomy_single.html (renamed from themes/tabi-lean/templates/taxonomy_single.html)0
-rw-r--r--sysret.org/themes/tabi-lean/theme.toml (renamed from themes/tabi-lean/theme.toml)0
438 files changed, 4978 insertions, 0 deletions
diff --git a/sys/auth/default.nix b/sys/auth/default.nix
new file mode 100644
index 0000000..ca2778a
--- /dev/null
+++ b/sys/auth/default.nix
@@ -0,0 +1,7 @@
+{
+ imports = [
+ ./login.nix
+ ./oath.nix
+ ./openssh.nix
+ ];
+}
diff --git a/sys/auth/login.nix b/sys/auth/login.nix
new file mode 100644
index 0000000..f252c1c
--- /dev/null
+++ b/sys/auth/login.nix
@@ -0,0 +1,22 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; {
+ # TODO
+ config = mkIf true {
+ security.pam = {
+ # TODO: altamente inseguro, ver problema con ~/.ssh/authorized_keys
+ # si es editado por un proceso malicioso
+ rssh = {
+ enable = true;
+
+ settings = {
+ cue = true;
+ };
+ };
+ };
+ };
+}
diff --git a/sys/auth/oath.nix b/sys/auth/oath.nix
new file mode 100644
index 0000000..6b00680
--- /dev/null
+++ b/sys/auth/oath.nix
@@ -0,0 +1,38 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.auth.oath;
+in {
+ options.local.auth.oath = {
+ enable = lib.mkEnableOption "pam-oath";
+ };
+
+ config = lib.mkIf cfg.enable {
+ security.pam = {
+ oath = {
+ digits = 6;
+ window = 30;
+
+ usersFile = "/var/trust/auth/users.oath";
+ };
+
+ services.sshd.oathAuth = true;
+ };
+
+ users.users.tunnel = {
+ uid = 1100;
+ group = "nogroup";
+ isSystemUser = true;
+
+ # Requiere oath
+ password = "tunnel";
+
+ home = "/var/empty";
+ shell = "${pkgs.coreutils}/bin/true";
+ };
+ };
+}
diff --git a/sys/auth/openssh.nix b/sys/auth/openssh.nix
new file mode 100644
index 0000000..d278dc0
--- /dev/null
+++ b/sys/auth/openssh.nix
@@ -0,0 +1,193 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.auth.openssh;
+ withOath = config.local.auth.oath.enable;
+ withPassword = config.local.auth.openssh.passwordAuthentication;
+
+ port =
+ if cfg.shiftPortNumber
+ then 2234
+ else 22;
+ restrict = cfg.restrictListen;
+
+ exemptList = optionals config.local.net.fail2ban.enable config.services.fail2ban.ignoreIP;
+in {
+ options.local.auth.openssh = {
+ enable = mkEnableOption "openssh";
+ tunnel.enable = mkEnableOption "ssh tunnel user";
+
+ #TODO: Desfasar ecdsa, inseguro
+ hostKeys = listToAttrs (map
+ (name: {
+ inherit name;
+
+ value = mkOption {
+ type = types.bool;
+ default = false;
+ };
+ }) ["ecdsa" "ed25519" "rsa"]);
+
+ restrictListen = mkOption {
+ default = null;
+
+ type = with types;
+ nullOr (submodule {
+ options = {
+ addresses = mkOption {
+ type = listOf str;
+ };
+
+ interface = mkOption {
+ type = nullOr str;
+ default = null;
+ };
+
+ vsockCid = mkOption {
+ type = nullOr ints.u32;
+ default = null;
+ };
+ };
+ });
+ };
+
+ passwordAuthentication = mkOption {
+ type = types.bool;
+ default = false;
+ };
+
+ shiftPortNumber = mkOption {
+ type = types.bool;
+ default = true;
+ };
+
+ withDeployKeys = mkOption {
+ type = types.bool;
+ default = false;
+ };
+ };
+
+ config = lib.mkIf cfg.enable {
+ assertions = [
+ {
+ assertion = cfg.tunnel.enable -> withOath;
+ message = "SSH tunnel requires oath";
+ }
+ {
+ assertion = restrict != null -> (restrict.vsockCid != null -> (restrict.interface == null && restrict.addresses == []));
+ message = "SSH vsock restrict requires disabling inet";
+ }
+ {
+ assertion = restrict != null -> (restrict.vsockCid != null -> config.services.openssh.startWhenNeeded);
+ message = "SSH vsock restrict requires socket activation";
+ }
+ {
+ assertion = restrict != null -> (restrict.vsockCid != null -> config.local.virt.enable);
+ message = "SSH vsock restrict requires nixvirt";
+ }
+ {
+ assertion = any (key: key) (attrValues cfg.hostKeys);
+ message = "No OpenSSH host keys were enabled";
+ }
+ ];
+
+ local.boot.impermanence.files =
+ flatten (map (key: [key.path "${key.path}.pub"]) config.services.openssh.hostKeys);
+
+ networking.firewall = {
+ interfaces = optionalAttrs (restrict != null && restrict.interface != null) {
+ ${restrict.interface}.allowedTCPPorts = [port];
+ };
+
+ allowedTCPPorts = optional (restrict == null || restrict.interface == null) port;
+ };
+
+ services.openssh = {
+ enable = true;
+
+ ports = optional (restrict != null -> restrict.addresses != []) port;
+ startWhenNeeded = mkDefault (!config.services.fail2ban.enable);
+
+ extraConfig =
+ optionalString (exemptList != []) ''
+ PerSourcePenaltyExemptList ${concatStringsSep "," exemptList}
+ ''
+ + optionalString cfg.tunnel.enable ''
+ # User 'tunnel' has no password. Use PAM OATH
+ # and connect with -N, forward with -R.
+ Match User tunnel
+ AllowTcpForwarding remote
+ AllowStreamLocalForwarding no
+ X11Forwarding no
+ PermitTunnel no
+ GatewayPorts no
+ AllowAgentForwarding no
+ PermitOpen none
+ PermitListen 60220 60221 60222 60223 60224 60225 60226 60227 60228 60229
+
+ Banner ${pkgs.writeText "tunnel-banner" ''
+ This is a reverse tunnel
+ ''}
+ '';
+
+ hostKeys =
+ map
+ (name:
+ {
+ path = "/etc/ssh/ssh_host_${name}_key";
+ type = name;
+ }
+ // optionalAttrs (name == "rsa") {
+ bits = 4096;
+ })
+ (attrNames (filterAttrs (name: enable: enable) cfg.hostKeys));
+
+ settings = {
+ X11Forwarding = config.local.seat.enable && config.local.seat.graphical;
+ PermitRootLogin = "prohibit-password";
+ PasswordAuthentication = withOath || withPassword; # Necesario para oath, no reemplaza a oath
+ };
+
+ listenAddresses =
+ mkIf (restrict != null)
+ (map (addr: {inherit addr;}) restrict.addresses);
+ };
+
+ systemd.sockets = mkIf (restrict != null && restrict.vsockCid != null) {
+ sshd = let
+ kernelMod = "modprobe@${
+ if restrict.vsockCid == 2
+ then "vhost_"
+ else ""
+ }vsock.service";
+ in {
+ after = [kernelMod];
+ wants = [kernelMod];
+
+ #socketConfig.ListenStream = mkForce [ "vsock:${toString restrict.vsockCid}:${toString port}" ];
+ };
+ };
+
+ users.users = {
+ root = mkIf cfg.withDeployKeys {
+ openssh.authorizedKeys.keyFiles = [./ssh-key.pub];
+ };
+
+ tunnel = mkIf cfg.tunnel.enable {
+ uid = 1100;
+ group = "nogroup";
+ isSystemUser = true;
+
+ # Requiere oath
+ password = "tunnel";
+
+ home = "/var/empty";
+ shell = "${pkgs.coreutils}/bin/true";
+ };
+ };
+ };
+}
diff --git a/sys/auth/ssh-key.pub b/sys/auth/ssh-key.pub
new file mode 100644
index 0000000..1bb3788
--- /dev/null
+++ b/sys/auth/ssh-key.pub
@@ -0,0 +1 @@
+# This file has been lustrated.
diff --git a/sys/baseline/default.nix b/sys/baseline/default.nix
new file mode 100644
index 0000000..96654d8
--- /dev/null
+++ b/sys/baseline/default.nix
@@ -0,0 +1,95 @@
+{
+ config,
+ flakes,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; {
+ config = {
+ # This value determines the NixOS release from which the default
+ # settings for stateful data, like file locations and database versions
+ # on your system were taken. It‘s perfectly fine and recommended to leave
+ # this value at the release version of the first install of this system.
+ # Before changing this value read the documentation for this option
+ # (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).
+ system.stateVersion = "21.11"; # Did you read the comment?
+
+ environment = {
+ pathsToLink = ["/share/zsh"];
+
+ systemPackages = with pkgs;
+ [
+ git
+ ]
+ ++ optionals (!config.boot.isContainer) [
+ lm_sensors
+ lshw
+ parted
+ pciutils
+ smartmontools
+ usbutils
+ ];
+ };
+
+ home-manager = {
+ useGlobalPkgs = true;
+ useUserPackages = true;
+
+ extraSpecialArgs = {inherit flakes;};
+ };
+
+ lib.local = pkgs.local.lib;
+
+ local.boot.impermanence.directories = ["/var/lib/dhparams"];
+
+ nix = {
+ package = pkgs.nix;
+
+ channel.enable = false;
+
+ extraOptions = ''
+ experimental-features = nix-command flakes
+ '';
+
+ gc = {
+ dates = "Sat *-*-* 00:00:00";
+ automatic = true;
+ };
+
+ # No me interesa el global registry
+ settings.flake-registry = "";
+ };
+
+ programs = {
+ fuse.userAllowOther = true;
+ zsh.enable = true;
+ };
+
+ security.dhparams = {
+ enable = true;
+ defaultBitSize = 4096;
+ };
+
+ services = {
+ earlyoom = {
+ enable = mkDefault true;
+ enableNotifications = true;
+ };
+
+ journald.extraConfig = ''
+ ForwardToKMsg=no
+ ForwardToWall=no
+ ForwardToConsole=no
+ '';
+ };
+
+ # Coredumps son un riesgo de seguridad y puden usar mucho disco
+ systemd.coredump.extraConfig = ''
+ Storage=none
+ ProcessSizeMax=0
+ '';
+
+ time.timeZone = mkDefault "America/Costa_Rica";
+ };
+}
diff --git a/sys/boot/chain.nix b/sys/boot/chain.nix
new file mode 100644
index 0000000..43edcb4
--- /dev/null
+++ b/sys/boot/chain.nix
@@ -0,0 +1,41 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.boot;
+in {
+ options.local.boot = {
+ loader = mkOption {
+ type = types.enum ["none" "grub" "systemd-boot"];
+ };
+
+ kernel = mkOption {
+ type = types.raw;
+ };
+ };
+
+ config = mkIf (cfg.loader != "none") {
+ boot = {
+ kernelPackages = cfg.kernel;
+
+ loader =
+ if cfg.loader == "grub"
+ then {
+ grub = {
+ enable = true;
+ device = "nodev";
+ efiSupport = true;
+ };
+ }
+ else {
+ systemd-boot = {
+ enable = true;
+ editor = true;
+ };
+ };
+ };
+ };
+}
diff --git a/sys/boot/default.nix b/sys/boot/default.nix
new file mode 100644
index 0000000..4580cba
--- /dev/null
+++ b/sys/boot/default.nix
@@ -0,0 +1,14 @@
+{
+ imports = [
+ ./chain.nix
+ ./detached-luks.nix
+ ./efi.nix
+ ./firmware.nix
+ ./fscrypt.nix
+ ./impermanence.nix
+ ./namespaced.nix
+ ./secure-boot.nix
+ ./stack
+ ./tpm.nix
+ ];
+}
diff --git a/sys/boot/detached-luks.nix b/sys/boot/detached-luks.nix
new file mode 100644
index 0000000..78ae35c
--- /dev/null
+++ b/sys/boot/detached-luks.nix
@@ -0,0 +1,117 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.boot.detachedLuks;
+
+ bootFs = config.fileSystems."/boot";
+ tpmInitrd = config.local.boot.tpm.initrd.enable;
+
+ pcrList = concatStringsSep "," (map toString config.local.boot.tpm.initrd.pcrs);
+in {
+ options.local.boot.detachedLuks = {
+ enable = mkEnableOption "detached LUKS header in initrd";
+
+ headerFromBoot = mkOption {
+ type = types.str;
+ };
+
+ tpmStorageFromBoot = mkOption {
+ type = types.str;
+ default = "tpm-boot";
+ };
+
+ crypt = mkOption {
+ type = types.str;
+ };
+
+ target = mkOption {
+ type = types.str;
+ };
+ };
+
+ config = mkIf cfg.enable {
+ boot.initrd = let
+ headerPath = "/initrd-boot/${cfg.headerFromBoot}";
+ headerPathEscaped = escapeShellArg headerPath;
+
+ tpmPath = escapeShellArg "/initrd-boot/${cfg.tpmStorageFromBoot}";
+ hardwareKeyPath = "/tpm/unsealed.luks-key";
+ in {
+ preDeviceCommands = ''
+ mkdir -p `dirname ${headerPathEscaped}`
+ touch ${headerPathEscaped}
+ '';
+
+ postDeviceCommands = mkIf (!config.boot.initrd.systemd.enable) ''
+ # Set the system time from the hardware clock to work around a
+ # bug in qemu-kvm > 1.5.2 (where the VM clock is initialised
+ # to the *boot time* of the host).
+ hwclock -s
+ '';
+
+ #FIXME: Demasiado vulgar
+ preLVMCommands = optionalString (config.local.boot.efi.enable && config.local.boot.efi.removable) ''
+ sleep 2
+ '';
+
+ luks.devices.${cfg.target} = {
+ device = cfg.crypt;
+ header = headerPath;
+ preLVM = false;
+
+ keyFile = mkIf tpmInitrd hardwareKeyPath;
+ fallbackToPassword = tpmInitrd;
+
+ preOpenCommands =
+ ''
+ mount -o ro -t ${bootFs.fsType} ${bootFs.device} /initrd-boot
+ ''
+ + optionalString tpmInitrd ''
+ mkdir /tpm
+ touch ${escapeShellArg hardwareKeyPath}
+
+ unseal_tpm_key() {
+ tpm2 createprimary -Q -C owner -g sha256 -G ecc -c /tpm/prim.ctx || return
+
+ tpm2 loadexternal -Q -C owner -G rsa -u ${tpmPath}/signing-key.pub -c /tpm/signing-key.ctx -n /tpm/signing-key.name || return
+ tpm2 verifysignature -Q -c /tpm/signing-key.ctx -g sha256 -m ${tpmPath}/auth.policy -s ${tpmPath}/auth.sig -t /tpm/verified.ticket -f rsassa || return
+
+ tpm2 startauthsession -Q -S /tpm/session.ctx --policy-session || return
+
+ tpm_resets=`tpm2 readclock | grep reset_count | sed 's/.*: //g'`
+ tpm2 policycountertimer -Q -S /tpm/session.ctx resets="$tpm_resets" || return
+ tpm2 policypcr -Q -S /tpm/session.ctx -l sha256:${pcrList} || return
+ tpm2 policyauthorize -Q -S /tpm/session.ctx -i ${tpmPath}/auth.policy -n /tpm/signing-key.name -t /tpm/verified.ticket || return
+
+ tpm2 load -Q -C /tpm/prim.ctx -u ${tpmPath}/key.pub -r ${tpmPath}/key.priv -c /tpm/key.ctx || return
+ tpm2 unseal -Q -c /tpm/key.ctx -p session:/tpm/session.ctx -o ${escapeShellArg hardwareKeyPath} || return
+
+ tpm2 flushcontext /tpm/session.ctx
+ }
+
+ unseal_tpm_key
+ '';
+
+ postOpenCommands = mkBefore (''
+ umount /initrd-boot
+ ''
+ + optionalString tpmInitrd ''
+ rm -r /tpm
+ '');
+ };
+ };
+
+ local.boot = {
+ stack = {
+ btrfsToplevelMultidrive.toplevel.device = "/dev/mapper/${cfg.target}";
+ luksExt4FscryptImpermanence = {inherit (cfg) target;};
+ };
+
+ tpm.initrd.enable = mkDefault config.local.boot.tpm.enable;
+ };
+ };
+}
diff --git a/sys/boot/efi.nix b/sys/boot/efi.nix
new file mode 100644
index 0000000..71c42c8
--- /dev/null
+++ b/sys/boot/efi.nix
@@ -0,0 +1,49 @@
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ cfg = config.local.boot.efi;
+in {
+ options.local.boot.efi = {
+ enable = mkEnableOption "EFI with FAT32 system partition";
+
+ esp = {
+ mountpoint = mkOption {
+ type = types.enum ["/boot" "/boot/efi"];
+ default = "/boot";
+ };
+
+ uuid = mkOption {
+ type = types.strMatching "[0-9A-F]{4}-[0-9A-F]{4}";
+ };
+ };
+
+ removable = mkOption {
+ type = types.bool;
+ };
+ };
+
+ config = mkIf cfg.enable {
+ boot = {
+ initrd.supportedFilesystems = ["vfat"];
+
+ loader = {
+ efi = {
+ efiSysMountPoint = cfg.esp.mountpoint;
+ canTouchEfiVariables = !cfg.removable;
+ };
+
+ grub.efiInstallAsRemovable = cfg.removable;
+ };
+ };
+
+ fileSystems.${cfg.esp.mountpoint} = {
+ device = "/dev/disk/by-uuid/${cfg.esp.uuid}";
+ fsType = "vfat";
+ options = ["noatime" "umask=027" "sync"];
+ neededForBoot = true;
+ };
+ };
+}
diff --git a/sys/boot/firmware.nix b/sys/boot/firmware.nix
new file mode 100644
index 0000000..b3598a7
--- /dev/null
+++ b/sys/boot/firmware.nix
@@ -0,0 +1,33 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.boot.firmware;
+in {
+ options.local.boot.firmware = {
+ mode = mkOption {
+ type = types.enum ["none" "redistributable" "all"];
+ };
+
+ cpuVendor = mkOption {
+ type = types.enum ["amd" "intel"];
+ };
+ };
+
+ config = mkIf (cfg.mode != "none") {
+ hardware = {
+ cpu = {
+ amd.updateMicrocode = cfg.cpuVendor == "amd";
+ intel.updateMicrocode = cfg.cpuVendor == "intel";
+ };
+
+ enableAllFirmware = cfg.mode == "all";
+ enableRedistributableFirmware = true;
+ };
+
+ services.fwupd.enable = true;
+ };
+}
diff --git a/sys/boot/fscrypt.nix b/sys/boot/fscrypt.nix
new file mode 100644
index 0000000..459e02b
--- /dev/null
+++ b/sys/boot/fscrypt.nix
@@ -0,0 +1,30 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.boot.fscrypt;
+in {
+ options.local.boot.fscrypt = {
+ enable = mkEnableOption "fscrypt support";
+ };
+
+ config = mkIf cfg.enable {
+ environment.systemPackages = [pkgs.fscrypt-experimental];
+
+ local.boot.impermanence = {
+ directories = [
+ {
+ directory = "/.fscrypt";
+ mode = "u=rwx,g=rx,o=rx";
+ }
+ ];
+
+ files = [
+ "/etc/fscrypt.conf"
+ ];
+ };
+ };
+}
diff --git a/sys/boot/impermanence.nix b/sys/boot/impermanence.nix
new file mode 100644
index 0000000..632094b
--- /dev/null
+++ b/sys/boot/impermanence.nix
@@ -0,0 +1,56 @@
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ cfg = config.local.boot.impermanence;
+in {
+ options.local.boot.impermanence = {
+ enable = mkEnableOption "root fs impermanence";
+
+ #TODO: type correcto de files, directories?
+
+ directories = mkOption {
+ type = with lib.types; listOf (either str attrs);
+ default = [];
+ };
+
+ files = mkOption {
+ type = with lib.types; listOf (either str attrs);
+ default = [];
+ };
+ };
+
+ config = mkMerge [
+ {
+ local.boot.impermanence = {
+ directories = [
+ "/etc/lvm"
+ "/var/lib/nixos"
+ "/var/log"
+ ];
+
+ files = [
+ "/etc/machine-id"
+ "/var/lib/logrotate.status"
+ ];
+ };
+ }
+ (mkIf cfg.enable {
+ assertions = [
+ {
+ assertion = (config.fileSystems ? "/persist") && config.fileSystems."/persist".neededForBoot;
+ message = "Impermanence requires /persist to be a neededForBoot mountpoint";
+ }
+ ];
+
+ environment.persistence."/persist" = {
+ hideMounts = true;
+
+ files = cfg.files;
+ directories = cfg.directories;
+ };
+ })
+ ];
+}
diff --git a/sys/boot/namespaced.nix b/sys/boot/namespaced.nix
new file mode 100644
index 0000000..3f95960
--- /dev/null
+++ b/sys/boot/namespaced.nix
@@ -0,0 +1,33 @@
+{
+ config,
+ lib,
+ options,
+ ...
+}:
+with lib; let
+ cfg = config.local.boot.namespaced;
+in {
+ options.local.boot.namespaced = {
+ enable = mkEnableOption "system containerization";
+ };
+
+ config = mkIf cfg.enable {
+ boot.isContainer = true;
+
+ local.boot = mkMerge ([
+ {
+ loader = mkForce "none";
+
+ efi.enable = mkForce false;
+ firmware.mode = mkForce "none";
+ secureBoot.enable = mkForce false;
+ impermanence.enable = mkForce false;
+ }
+ ]
+ ++ map
+ (name: {
+ stack.${name}.enable = mkForce false;
+ })
+ (attrNames options.local.boot.stack));
+ };
+}
diff --git a/sys/boot/secure-boot.nix b/sys/boot/secure-boot.nix
new file mode 100644
index 0000000..b13ab7c
--- /dev/null
+++ b/sys/boot/secure-boot.nix
@@ -0,0 +1,51 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.boot.secureBoot;
+
+ pkiBundle =
+ if cfg.legacyPath
+ then "/etc/secureboot"
+ else "/var/lib/sbctl";
+in {
+ options.local.boot.secureBoot = {
+ enable = mkEnableOption "secure boot";
+
+ legacyPath = mkOption {
+ type = types.bool;
+ default = false;
+ };
+ };
+
+ config = mkIf cfg.enable {
+ assertions = [
+ {
+ assertion = config.local.boot.efi.enable;
+ message = "secure boot requires EFI";
+ }
+ {
+ assertion = config.local.boot.loader == "systemd-boot";
+ message = "lanzaboote requires systemd-boot";
+ }
+ ];
+
+ boot = {
+ loader.systemd-boot.enable = mkForce false;
+
+ lanzaboote = {
+ enable = true;
+ inherit pkiBundle;
+ };
+ };
+
+ environment.systemPackages = [
+ pkgs.sbctl
+ ];
+
+ local.boot.impermanence.directories = [pkiBundle];
+ };
+}
diff --git a/sys/boot/stack/btrfs-toplevel-multidrive.nix b/sys/boot/stack/btrfs-toplevel-multidrive.nix
new file mode 100644
index 0000000..52db865
--- /dev/null
+++ b/sys/boot/stack/btrfs-toplevel-multidrive.nix
@@ -0,0 +1,99 @@
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ cfg = config.local.boot.stack.btrfsToplevelMultidrive;
+in {
+ options.local.boot.stack.btrfsToplevelMultidrive = {
+ enable = mkEnableOption "filesystem stack: persistent btrfs toplevel with optional hdd drive";
+
+ toplevel = {
+ device = mkOption {
+ type = types.str;
+ };
+
+ ssd = mkOption {
+ type = types.bool;
+ };
+
+ snapshot = mkOption {
+ type = types.bool;
+ default = false;
+ };
+
+ root = mkOption {
+ type = types.str;
+ };
+
+ pivot = mkOption {
+ type = types.str;
+ default = "/";
+ };
+ };
+
+ secondary = {
+ device = mkOption {
+ type = types.str;
+ };
+
+ ssd = mkOption {
+ type = types.bool;
+ };
+
+ snapshot = mkOption {
+ type = types.bool;
+ default = false;
+ };
+
+ home = mkOption {
+ type = types.str;
+ };
+
+ pivot = mkOption {
+ type = types.str;
+ default = "/";
+ };
+ };
+ };
+
+ config = mkIf cfg.enable {
+ local.btrfs = {
+ mounts = {
+ "/" = {
+ inherit (cfg.toplevel) device ssd;
+ subvol = cfg.toplevel.root;
+ };
+
+ "/toplevel" = {
+ inherit (cfg.toplevel) device ssd;
+ subvol = cfg.toplevel.pivot;
+ };
+
+ #FIXME: Este nombre es legacy
+ "/hdd" = {
+ inherit (cfg.secondary) device ssd;
+ subvol = cfg.secondary.pivot;
+ };
+
+ "/home" = {
+ inherit (cfg.secondary) device ssd;
+ subvol = cfg.secondary.home;
+ };
+ };
+
+ snapper =
+ optionalAttrs cfg.toplevel.snapshot
+ {
+ root = "/";
+ }
+ // optionalAttrs cfg.secondary.snapshot {
+ home = "/home";
+ };
+ };
+
+ # Asegura que /hdd sea descifrado antes de intentar montar /home
+ fileSystems."/home".depends = ["/hdd"];
+ };
+}
diff --git a/sys/boot/stack/default.nix b/sys/boot/stack/default.nix
new file mode 100644
index 0000000..ff211e6
--- /dev/null
+++ b/sys/boot/stack/default.nix
@@ -0,0 +1,6 @@
+{
+ imports = [
+ ./btrfs-toplevel-multidrive.nix
+ ./luks-ext4-fscrypt-impermanence.nix
+ ];
+}
diff --git a/sys/boot/stack/luks-ext4-fscrypt-impermanence.nix b/sys/boot/stack/luks-ext4-fscrypt-impermanence.nix
new file mode 100644
index 0000000..81feb60
--- /dev/null
+++ b/sys/boot/stack/luks-ext4-fscrypt-impermanence.nix
@@ -0,0 +1,98 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.boot.stack.luksExt4FscryptImpermanence;
+in {
+ options.local.boot.stack.luksExt4FscryptImpermanence = {
+ enable = mkEnableOption "filesystem stack: whatever LUKS approach+ext4+impermanence with per-boot keys";
+
+ target = mkOption {
+ type = types.str;
+ };
+ };
+
+ # - boot device
+ # - some unknown fs, probably vfat
+ # - detached luks header file
+ #
+ # - toplevel device
+ # - headerless luks
+ # - /toplevel (ext4)
+ # - /toplevel/nix
+ # - /toplevel/persist
+ # - /toplevel/boot-archive.pub
+ # - /toplevel/boot-keys
+ # - /toplevel/boot-keys/2000-01-01T00:00:00-06:00.key.crypt (encrypted for /toplevel/boot-archive.pub)
+ # - /toplevel/boot-keys/...
+ # - /toplevel/boot-keys/last.key.crypt -> 2000-01-01T00:00:00-06:00.key.crypt
+ # - /toplevel/boots
+ # - /toplevel/boots/2000-01-01T00:00:00-06:00 (raw protector in last.key.crypt)
+ # - /toplevel/boots/...
+ # - /toplevel/boots/last -> 2000-01-01T00:00:00-06:00 (mounted as /)
+ config = mkIf cfg.enable {
+ boot.initrd.luks.devices.${cfg.target}.postOpenCommands = let
+ fscryptctl = "${pkgs.fscryptctl}/bin/fscryptctl";
+ in ''
+ # FIXME: posiblemente algunos --make-* son innecesarios a partir de aquí
+ mkdir -p /mnt-root /mnt-toplevel
+ mount -o noatime /dev/mapper/${cfg.target} /mnt-toplevel
+ mount --make-private /mnt-toplevel
+
+ boot_stamp="$(date -Is)"
+ root_from_toplevel="/mnt-toplevel/boots/$boot_stamp"
+
+ mkdir -p "$root_from_toplevel" /mnt-toplevel/boot-keys
+ chmod 700 /mnt-toplevel/boot-keys
+
+ head -c64 /dev/urandom >/boot-key
+ key_id=$(${fscryptctl} add_key /mnt-toplevel </boot-key)
+ ${fscryptctl} set_policy "$key_id" "$root_from_toplevel"
+ (umask 077; test -f /mnt-toplevel/boot-archive.pub && \
+ ${pkgs.openssl}/bin/openssl pkeyutl -encrypt \
+ -in /boot-key -pubin -inkey /mnt-toplevel/boot-archive.pub \
+ -out "/mnt-toplevel/boot-keys/$boot_stamp.key.crypt")
+ rm -f /boot-key
+
+ ln -Tsf "$boot_stamp" /mnt-toplevel/boots/last
+ ln -Tsf "$boot_stamp.key.crypt" /mnt-toplevel/boot-keys/last.key.crypt
+
+ mount --bind "$root_from_toplevel" /mnt-root
+ mount --make-shared /mnt-root
+
+ # mount --move es mala idea, ya que "moving a mount residing under a
+ # shared mount is unsupported"
+ mkdir -p /mnt-root/toplevel
+ mount --bind /mnt-toplevel /mnt-root/toplevel
+ mount --make-private /mnt-root/toplevel
+ umount /mnt-toplevel
+ '';
+
+ fileSystems = {
+ "/" = {
+ device = "none";
+ fsType = "ext4";
+ options = ["remount"];
+ };
+
+ "/nix" = {
+ device = "/persist/nix";
+ options = ["bind"];
+ };
+
+ "/persist" = {
+ device = "/toplevel/persist";
+ options = ["bind"];
+ neededForBoot = true;
+ };
+ };
+
+ local.boot = {
+ fscrypt.enable = true;
+ impermanence.enable = true;
+ };
+ };
+}
diff --git a/sys/boot/tpm.nix b/sys/boot/tpm.nix
new file mode 100644
index 0000000..ecc115b
--- /dev/null
+++ b/sys/boot/tpm.nix
@@ -0,0 +1,128 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.boot.tpm;
+
+ pcrList = concatStringsSep "," (map toString cfg.initrd.pcrs);
+
+ # Crear signing-key con:
+ # $ openssl genrsa -out ~/vtmp/signing-key.priv 2048
+ # $ openssl rsa -in ~/vtmp/signing-key.priv -out ~/vtmp/signing-key.pub -pubout
+ # Y copiar signing-key.pub a /boot/tpm-boot. Guardar signing-key.priv en lugar seguro.
+ #
+ # Crear llave con:
+ # $ tpm2_loadexternal -G rsa -C owner -u signing-key.pub -c signing-key.ctx -n signing-key.name
+ # $ tpm2_startauthsession -S session.ctx
+ # $ tpm2_policyauthorize -S session.ctx -L require-signed.policy -n signing-key.name
+ # $ tpm2_flushcontext session.ctx
+ # $ tpm2_createprimary -C owner -g sha256 -G ecc -c prim.ctx
+ # $ head -c128 /dev/urandom | tpm2_create -C prim.ctx -u key.pub -r key.priv -c key.ctx -L require-signed.policy -i-
+ # Y mover key.priv/key.pub a /boot/tpm-boot
+ #
+ # Usage: tpm2-grant-next-boot < signing-key.priv
+ # Genera auth.policy y auth.sig
+ tpm2-grant-next-boot = pkgs.writeShellApplication {
+ name = "tpm2-grant-next-boot";
+
+ runtimeInputs = [
+ pkgs.jq
+ pkgs.openssl
+ pkgs.sbctl
+ pkgs.tpm2-tools
+ ];
+
+ text = ''
+ if [ -z "''${YES_I_DO_WANT_TO_SIGN_WITH_SECURE_BOOT_DISABLED:=}" ] && [ "$(sbctl status --json | jq .secure_boot)" != "truee" ]; then
+ echo "$0: bad Secure Boot state, check the output of \`sbctl status\`" >&2
+ echo "$0: signing a TPM PCR policy with Secure Boot disabled is dangerous" >&2
+ echo "$0: set 'YES_I_DO_WANT_TO_SIGN_WITH_SECURE_BOOT_DISABLED' to skip this check" >&2
+ exit 1
+ fi
+
+ ctx_dir="$(mktemp -d)"
+ trap 'rm -rf -- "$ctx_dir"' EXIT
+
+ tpm2_createprimary -Q -C owner -g sha256 -G ecc -c "$ctx_dir/prim.ctx"
+
+ tpm2_startauthsession -Q -S "$ctx_dir/session.ctx"
+ tpm_resets=$(tpm2_readclock | grep reset_count | sed 's/.*: //')
+ tpm2_policycountertimer -Q -S "$ctx_dir/session.ctx" resets="$((tpm_resets+1))"
+ tpm2_policypcr -Q -S "$ctx_dir/session.ctx" -L auth.policy -l sha256:${pcrList}
+ tpm2_flushcontext -Q "$ctx_dir/session.ctx"
+
+ openssl dgst -sha256 -sign /dev/stdin -out auth.sig auth.policy
+ '';
+ };
+in {
+ options.local.boot.tpm = {
+ enable = mkEnableOption "Trusted Platform Module 2.0";
+
+ driver = mkOption {
+ type = types.enum ["tis" "crb"];
+ };
+
+ initrd = {
+ enable = mkEnableOption "TPM2 in initrd";
+
+ pcrs = mkOption {
+ type = with types; listOf (ints.between 0 23);
+
+ # From 'systemd-analyze pcrs'
+ default = [
+ 0 # platform-code
+ 1 # platform-config
+ 2 # external-code
+ 3 # external-config
+ 4 # boot-loader-code
+ 5 # boot-loader-config
+ 7 # secure-boot-policy
+ 9 # kernel-initrd
+ 11 # kernel-boot
+ 12 # kernel-config
+ 13 # sysexts
+ 14 # shim-policy
+ ];
+ };
+ };
+ };
+
+ config = mkIf cfg.enable {
+ assertions = [
+ {
+ assertion = config.local.boot.efi.enable;
+ message = "TPM2 requires EFI";
+ }
+ {
+ assertion = cfg.initrd.enable -> cfg.enable;
+ message = "TPM2 in initrd requires TPM2";
+ }
+ ];
+
+ boot.initrd = mkIf cfg.initrd.enable {
+ extraUtilsCommands = ''
+ copy_bin_and_libs ${pkgs.tpm2-tools}/bin/.tpm2-wrapped
+ mv $out/bin/{.tpm2-wrapped,tpm2}
+ cp {${pkgs.tpm2-tss},$out}/lib/libtss2-tcti-device.so.0
+ '';
+
+ kernelModules = [
+ "tpm_${cfg.driver}"
+ ];
+ };
+
+ environment.systemPackages = optionals cfg.initrd.enable [
+ tpm2-grant-next-boot
+ ];
+
+ security.tpm2 = {
+ enable = true;
+
+ pkcs11.enable = true;
+ tctiEnvironment.enable = true;
+ };
+ };
+}
diff --git a/sys/btrfs/default.nix b/sys/btrfs/default.nix
new file mode 100644
index 0000000..ee76537
--- /dev/null
+++ b/sys/btrfs/default.nix
@@ -0,0 +1,6 @@
+{
+ imports = [
+ ./mounts.nix
+ ./snapper.nix
+ ];
+}
diff --git a/sys/btrfs/mounts.nix b/sys/btrfs/mounts.nix
new file mode 100644
index 0000000..3863356
--- /dev/null
+++ b/sys/btrfs/mounts.nix
@@ -0,0 +1,47 @@
+{
+ lib,
+ config,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.btrfs;
+in {
+ options.local.btrfs = {
+ mounts = mkOption {
+ default = {};
+
+ type = with lib.types;
+ attrsOf (submodule {
+ options = {
+ ssd = mkOption {
+ type = bool;
+ };
+
+ device = mkOption {
+ type = str;
+ };
+
+ subvol = mkOption {
+ type = str;
+ };
+ };
+ });
+ };
+ };
+
+ config = mkIf (cfg.mounts != {}) {
+ fileSystems = let
+ btrfsMount = {
+ device,
+ subvol,
+ ssd,
+ }: {
+ inherit device;
+ fsType = "btrfs";
+ options = ["noatime" "compress=zstd" "subvol=${subvol}"] ++ optional ssd "ssd";
+ };
+ in
+ mapAttrs (_: btrfsMount) cfg.mounts;
+ };
+}
diff --git a/sys/btrfs/snapper.nix b/sys/btrfs/snapper.nix
new file mode 100644
index 0000000..2d29aa4
--- /dev/null
+++ b/sys/btrfs/snapper.nix
@@ -0,0 +1,76 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.btrfs;
+in {
+ options.local.btrfs = {
+ snapper = mkOption {
+ type = with lib.types; attrsOf str;
+ default = {};
+ };
+ };
+
+ config = mkIf (cfg.snapper != {}) {
+ environment.systemPackages = [pkgs.local.btclone];
+
+ services.snapper.configs = let
+ snapperConfig = _: subvolume: {
+ SUBVOLUME = subvolume;
+
+ # btrfs qgroup for space aware cleanup algorithms
+ QGROUP = "";
+
+ # fraction of the filesystems space the snapshots may use
+ SPACE_LIMIT = "0.5";
+
+ # fraction of the filesystems space that should be free
+ FREE_LIMIT = "0.2";
+
+ # users and groups allowed to work with config
+ ALLOW_USERS = [];
+ ALLOW_GROUPS = [];
+
+ # sync users and groups from ALLOW_USERS and ALLOW_GROUPS to .snapshots
+ # directory
+ SYNC_ACL = "no";
+
+ # start comparing pre- and post-snapshot in background after creating
+ # post-snapshot
+ BACKGROUND_COMPARISON = "yes";
+
+ # run daily number cleanup
+ NUMBER_CLEANUP = "yes";
+
+ # limit for number cleanup
+ NUMBER_MIN_AGE = "1800";
+ NUMBER_LIMIT = "100";
+ NUMBER_LIMIT_IMPORTANT = "10";
+
+ # create hourly snapshots
+ TIMELINE_CREATE = true;
+
+ # cleanup hourly snapshots after some time
+ TIMELINE_CLEANUP = true;
+
+ # limits for timeline cleanup
+ TIMELINE_MIN_AGE = "1800";
+ TIMELINE_LIMIT_HOURLY = "24";
+ TIMELINE_LIMIT_DAILY = "7";
+ TIMELINE_LIMIT_WEEKLY = "4";
+ TIMELINE_LIMIT_MONTHLY = "12";
+ TIMELINE_LIMIT_YEARLY = "10";
+
+ # cleanup empty pre-post-pairs
+ EMPTY_PRE_POST_CLEANUP = "yes";
+
+ # limits for empty pre-post-pair cleanup
+ EMPTY_PRE_POST_MIN_AGE = "1800";
+ };
+ in
+ mapAttrs snapperConfig cfg.snapper;
+ };
+}
diff --git a/sys/default.nix b/sys/default.nix
new file mode 100644
index 0000000..131ddeb
--- /dev/null
+++ b/sys/default.nix
@@ -0,0 +1,38 @@
+{
+ lib,
+ config,
+ flakes,
+ pkgs,
+ ...
+}:
+with lib; {
+ imports = [
+ flakes.nixpkgs.nixosModules.notDetected
+ flakes.nixvirt.nixosModules.default
+ flakes.lanzaboote.nixosModules.lanzaboote
+ flakes.impermanence.nixosModule
+ flakes.home-manager.nixosModules.home-manager
+ flakes.trivionomicon.nixosModules.default
+ ../pki
+ ./auth
+ ./baseline
+ ./boot
+ ./btrfs
+ ./env
+ ./gitea
+ ./hardware
+ ./home-assistant
+ ./jobs
+ ./kiosk
+ ./mail
+ ./mta
+ ./net
+ ./ns
+ ./nspawn
+ ./preset
+ ./seat
+ ./syncthing
+ ./virt
+ ./web
+ ];
+}
diff --git a/sys/env/default.nix b/sys/env/default.nix
new file mode 100644
index 0000000..5e3cb98
--- /dev/null
+++ b/sys/env/default.nix
@@ -0,0 +1,8 @@
+{
+ imports = [
+ ./maps.nix
+ ./domains.nix
+ ./users.nix
+ ./virtual.nix
+ ];
+}
diff --git a/sys/env/domains.nix b/sys/env/domains.nix
new file mode 100644
index 0000000..1bb3788
--- /dev/null
+++ b/sys/env/domains.nix
@@ -0,0 +1 @@
+# This file has been lustrated.
diff --git a/sys/env/maps.nix b/sys/env/maps.nix
new file mode 100644
index 0000000..1bb3788
--- /dev/null
+++ b/sys/env/maps.nix
@@ -0,0 +1 @@
+# This file has been lustrated.
diff --git a/sys/env/users.nix b/sys/env/users.nix
new file mode 100644
index 0000000..1bb3788
--- /dev/null
+++ b/sys/env/users.nix
@@ -0,0 +1 @@
+# This file has been lustrated.
diff --git a/sys/env/virtual.nix b/sys/env/virtual.nix
new file mode 100644
index 0000000..1bb3788
--- /dev/null
+++ b/sys/env/virtual.nix
@@ -0,0 +1 @@
+# This file has been lustrated.
diff --git a/sys/gitea/default.nix b/sys/gitea/default.nix
new file mode 100644
index 0000000..212b9f1
--- /dev/null
+++ b/sys/gitea/default.nix
@@ -0,0 +1,41 @@
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ cfg = config.local.gitea;
+in {
+ options.local.gitea = {
+ enable = mkEnableOption "gitea";
+ };
+
+ config = mkIf cfg.enable {
+ environment.etc."fail2ban/filter.d/gitea.local".text = ''
+ [Definition]
+ failregex = .*(Failed authentication attempt|invalid credentials|Attempted access of unknown user).* from <HOST>
+ ignoreregex =
+ '';
+
+ services = {
+ fail2ban.jails.gitea.settings = {
+ filter = "gitea";
+ logpath = "${config.services.gitea.stateDir}/log/gitea.log";
+ maxretry = "10";
+ findtime = "3600";
+ bantime = "900";
+ action = "iptables-allports";
+ };
+
+ gitea = {
+ enable = true;
+ useWizard = true;
+ };
+ };
+
+ users = {
+ users.gitea.uid = 962;
+ groups.gitea.gid = 962;
+ };
+ };
+}
diff --git a/sys/hardware/altera.nix b/sys/hardware/altera.nix
new file mode 100644
index 0000000..fddd722
--- /dev/null
+++ b/sys/hardware/altera.nix
@@ -0,0 +1,25 @@
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ cfg = config.local.hardware.altera;
+in {
+ options.local.hardware.altera = {
+ enable = mkEnableOption "Altera USB Blaster";
+ };
+
+ config = mkIf cfg.enable {
+ services.udev.extraRules = ''
+ # USB-Blaster
+ ATTRS{idVendor}=="09fb", ATTRS{idProduct}=="6001", MODE="660", GROUP="users", TAG+="uaccess"
+ ATTRS{idVendor}=="09fb", ATTRS{idProduct}=="6002", MODE="660", GROUP="users", TAG+="uaccess"
+ ATTRS{idVendor}=="09fb", ATTRS{idProduct}=="6003", MODE="660", GROUP="users", TAG+="uaccess"
+
+ # USB-Blaster II
+ ATTRS{idVendor}=="09fb", ATTRS{idProduct}=="6010", MODE="660", GROUP="users", TAG+="uaccess"
+ ATTRS{idVendor}=="09fb", ATTRS{idProduct}=="6810", MODE="660", GROUP="users", TAG+="uaccess"
+ '';
+ };
+}
diff --git a/sys/hardware/apc.nix b/sys/hardware/apc.nix
new file mode 100644
index 0000000..97a5bb0
--- /dev/null
+++ b/sys/hardware/apc.nix
@@ -0,0 +1,33 @@
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ cfg = config.local.hardware.apc;
+in {
+ options.local.hardware.apc = {
+ enable = mkEnableOption "APC UPS support";
+ };
+
+ config = mkIf cfg.enable {
+ services.apcupsd = {
+ enable = true;
+
+ configText = concatStrings (mapAttrsToList (k: v: "${k} ${v}\n") {
+ UPSMODE = "disable";
+ UPSTYPE = "usb";
+ UPSCABLE = "usb";
+ UPSCLASS = "standalone";
+
+ NISIP = "127.0.0.1";
+ NETSERVER = "on";
+
+ MINUTES = "5";
+ BATTERYLEVEL = "10";
+
+ NOLOGON = "disable";
+ });
+ };
+ };
+}
diff --git a/sys/hardware/athena.nix b/sys/hardware/athena.nix
new file mode 100644
index 0000000..755c184
--- /dev/null
+++ b/sys/hardware/athena.nix
@@ -0,0 +1,48 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.hardware.athena;
+
+ athena = pkgs.local.athena-bccr.${cfg.release};
+in {
+ options.local.hardware.athena = {
+ enable = mkEnableOption "Athena ASEDrive III smartcard reader";
+
+ release = mkOption {
+ type = types.str;
+ default = "latest";
+ description = "athena-bccr release tag";
+ };
+ };
+
+ config = mkIf cfg.enable {
+ environment = {
+ etc = {
+ "Athena".source = "${athena.ase-pkcs11}/etc/Athena";
+
+ "pkcs11/modules/asep11".text = ''
+ module: ${athena.libasep11}
+ '';
+ };
+
+ systemPackages = [athena.ase-pkcs11];
+ };
+
+ #FIXME: Extremadamente peligroso si BCCR o MICITT caen, investigar política nacional de root CA
+ security.pki.certificateFiles = ["${athena.bccr-cacerts}/root-ca.pem"];
+
+ services = {
+ pcscd.enable = true;
+
+ #TODO: Sería mejor agregar un grupo separado
+ udev.extraRules = ''
+ # Athena Smartcard Solutions, Inc. ASEDrive V3CR
+ ATTRS{idVendor}=="0dc3", ATTRS{idProduct}=="1004", MODE="660", GROUP="users", TAG+="uaccess"
+ '';
+ };
+ };
+}
diff --git a/sys/hardware/bluetooth.nix b/sys/hardware/bluetooth.nix
new file mode 100644
index 0000000..63e3f0c
--- /dev/null
+++ b/sys/hardware/bluetooth.nix
@@ -0,0 +1,19 @@
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ cfg = config.local.hardware.bluetooth;
+in {
+ options.local.hardware.bluetooth = {
+ enable = mkEnableOption "bluetooth services";
+ };
+
+ config = mkIf cfg.enable {
+ hardware.bluetooth = {
+ enable = true;
+ powerOnBoot = mkDefault false;
+ };
+ };
+}
diff --git a/sys/hardware/default.nix b/sys/hardware/default.nix
new file mode 100644
index 0000000..2ded912
--- /dev/null
+++ b/sys/hardware/default.nix
@@ -0,0 +1,13 @@
+{
+ imports = [
+ ./altera.nix
+ ./athena.nix
+ ./apc.nix
+ ./bluetooth.nix
+ ./epson.nix
+ ./laptop.nix
+ ./printing.nix
+ ./thinkpad.nix
+ ./yubico.nix
+ ];
+}
diff --git a/sys/hardware/epson.nix b/sys/hardware/epson.nix
new file mode 100644
index 0000000..30b1303
--- /dev/null
+++ b/sys/hardware/epson.nix
@@ -0,0 +1,38 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.hardware.epson;
+in {
+ options.local.hardware.epson = {
+ enable = mkEnableOption "Epson printers and scanners";
+ };
+
+ config = mkIf cfg.enable {
+ assertions = [
+ {
+ assertion = config.local.hardware.printing.enable;
+ message = "epson requires printing";
+ }
+ ];
+
+ hardware.sane = {
+ enable = true;
+
+ extraBackends = [
+ pkgs.epkowa
+ ];
+ };
+
+ services.printing = {
+ enable = true;
+
+ drivers = [
+ pkgs.epson_201207w
+ ];
+ };
+ };
+}
diff --git a/sys/hardware/laptop.nix b/sys/hardware/laptop.nix
new file mode 100644
index 0000000..3b5b772
--- /dev/null
+++ b/sys/hardware/laptop.nix
@@ -0,0 +1,19 @@
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ cfg = config.local.hardware.laptop;
+in {
+ options.local.hardware.laptop = {
+ enable = mkEnableOption "laptop stuff";
+ };
+
+ config = mkIf cfg.enable {
+ services = {
+ tlp.enable = true;
+ upower.enable = true;
+ };
+ };
+}
diff --git a/sys/hardware/printing.nix b/sys/hardware/printing.nix
new file mode 100644
index 0000000..e11a016
--- /dev/null
+++ b/sys/hardware/printing.nix
@@ -0,0 +1,50 @@
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ cfg = config.local.hardware.printing;
+ inherit (config.local.net) dhcpInterface;
+in {
+ options.local.hardware.printing = {
+ enable = mkEnableOption "print and scan services";
+
+ users = mkOption {
+ type = with types; listOf str;
+ default = [];
+ };
+ };
+
+ config = mkIf cfg.enable {
+ assertions = [
+ {
+ assertion = config.local.net.enable;
+ message = "Printing requires net";
+ }
+ ];
+
+ services.avahi = {
+ enable = true;
+ nssmdns4 = true;
+
+ # Abre 5353 en todas las interfaces (!!!)
+ openFirewall = false;
+ };
+
+ hardware.sane.enable = true;
+
+ networking.firewall.interfaces = mkIf (dhcpInterface != null) {
+ ${dhcpInterface}.allowedUDPPorts = [5353];
+ };
+
+ services.printing.enable = true;
+
+ users.users = listToAttrs (map
+ (user: {
+ name = user;
+ value.extraGroups = ["scanner" "lp"];
+ })
+ cfg.users);
+ };
+}
diff --git a/sys/hardware/thinkpad.nix b/sys/hardware/thinkpad.nix
new file mode 100644
index 0000000..ab18694
--- /dev/null
+++ b/sys/hardware/thinkpad.nix
@@ -0,0 +1,42 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.hardware.thinkpad;
+in {
+ options.local.hardware.thinkpad = {
+ enable = mkEnableOption "Thinkpad hardware support";
+ };
+
+ config = mkIf cfg.enable {
+ # For suspending to RAM to work, set Config -> Power -> Sleep State to "Linux" in EFI.
+ # See https://wiki.archlinux.org/index.php/Lenovo_ThinkPad_X1_Carbon_(Gen_6)#Suspend_issues
+ # Fingerprint sensor requires a firmware-update to work.
+
+ boot = {
+ extraModulePackages = with config.boot.kernelPackages; [acpi_call];
+ extraModprobeConfig = "options iwlwifi 11n_disable=1 wd_disable=1";
+
+ # acpi_call makes tlp work for newer thinkpads
+ kernelModules = ["acpi_call"];
+
+ # Force use of the thinkpad_acpi driver for backlight control.
+ # This allows the backlight save/load systemd service to work.
+ kernelParams = ["acpi_backlight=native"];
+ };
+
+ hardware.firmware = [pkgs.sof-firmware];
+
+ local.hardware.laptop.enable = true;
+
+ services = {
+ fprintd.enable = true;
+ thinkfan.enable = true;
+ tlp.enable = true;
+ tp-auto-kbbl.enable = true;
+ };
+ };
+}
diff --git a/sys/hardware/yubico.nix b/sys/hardware/yubico.nix
new file mode 100644
index 0000000..0c8478c
--- /dev/null
+++ b/sys/hardware/yubico.nix
@@ -0,0 +1,24 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.hardware.yubico;
+in {
+ options.local.hardware.yubico = {
+ enable = mkEnableOption "Yubico hardware support";
+ };
+
+ config = mkIf cfg.enable {
+ environment.etc."pkcs11/modules/ykcs11".text = ''
+ module: ${pkgs.yubico-piv-tool}/lib/libykcs11.so
+ '';
+
+ services = {
+ pcscd.enable = true;
+ udev.packages = [pkgs.yubikey-personalization];
+ };
+ };
+}
diff --git a/sys/home-assistant/default.nix b/sys/home-assistant/default.nix
new file mode 100644
index 0000000..e997c08
--- /dev/null
+++ b/sys/home-assistant/default.nix
@@ -0,0 +1,6 @@
+{
+ imports = [
+ ./hass.nix
+ ./yaml-extra.nix
+ ];
+}
diff --git a/sys/home-assistant/hass.nix b/sys/home-assistant/hass.nix
new file mode 100644
index 0000000..7fd3251
--- /dev/null
+++ b/sys/home-assistant/hass.nix
@@ -0,0 +1,79 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.home-assistant;
+in {
+ options.local.home-assistant = {
+ enable = mkEnableOption "home-assistant";
+ };
+
+ config = mkIf cfg.enable {
+ # https://nathan.gs/2024/06/22/fail2ban-to-secure-ha-on-nixos/
+ environment.etc."fail2ban/filter.d/home-assistant.local".text = ''
+ [Definition]
+ failregex = ^.* \[homeassistant\.components\.http\.ban\] Login attempt or request with invalid authentication from <HOST>.*$
+
+ ignoreregex =
+
+ journalmatch = _SYSTEMD_UNIT=home-assistant.service + _COMM=home-assistant
+
+ datepattern = {^LN-BEG}
+ '';
+
+ local.boot.impermanence.directories = [
+ {
+ directory = "/var/lib/hass";
+ user = "hass";
+ group = "hass";
+ mode = "u=rwx,g=,o=";
+ }
+ ];
+
+ services = {
+ fail2ban.jails.home-assistant = {};
+
+ home-assistant = {
+ enable = true;
+
+ extraComponents = [
+ "met"
+ "google_translate"
+ "radio_browser"
+ "tuya"
+ "wake_on_lan"
+ "webostv"
+ "xiaomi_miio"
+ ];
+
+ config = {
+ # Includes dependencies for a basic setup
+ # https://www.home-assistant.io/integrations/default_config/
+ default_config = {};
+
+ switch = [
+ # Televisor 192.168.42.205
+ # TODO: No sirve por 192.168.34 vs 192.168.42
+ {
+ platform = "wake_on_lan";
+ mac = "74:40:be:58:5f:da";
+ }
+ ];
+ };
+
+ customComponents = with pkgs.home-assistant-custom-components; [
+ dreame_vacuum
+ smartthinq_sensors
+ xiaomi_miot
+ ];
+
+ customLovelaceModules = with pkgs.home-assistant-custom-lovelace-modules; [
+ xiaomi-vacuum-map-card
+ ];
+ };
+ };
+ };
+}
diff --git a/sys/home-assistant/yaml-extra.nix b/sys/home-assistant/yaml-extra.nix
new file mode 100644
index 0000000..77d1ed2
--- /dev/null
+++ b/sys/home-assistant/yaml-extra.nix
@@ -0,0 +1,23 @@
+{lib, ...}:
+with lib; {
+ options.services.home-assistant = {
+ config = mkOption {
+ type = with lib.types;
+ nullOr (submodule {
+ options = {
+ http = {
+ use_x_forwarded_for = mkOption {
+ type = nullOr bool;
+ default = null;
+ };
+
+ trusted_proxies = mkOption {
+ type = nullOr (either str (listOf str));
+ default = null;
+ };
+ };
+ };
+ });
+ };
+ };
+}
diff --git a/sys/jobs/default.nix b/sys/jobs/default.nix
new file mode 100644
index 0000000..24d6c73
--- /dev/null
+++ b/sys/jobs/default.nix
@@ -0,0 +1,5 @@
+{
+ imports = [
+ ./pki-expiry
+ ];
+}
diff --git a/sys/jobs/pki-expiry/default.nix b/sys/jobs/pki-expiry/default.nix
new file mode 100644
index 0000000..553cdc8
--- /dev/null
+++ b/sys/jobs/pki-expiry/default.nix
@@ -0,0 +1,60 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.jobs.pkiExpiry;
+ inherit (config.local) pki;
+in {
+ options.local.jobs.pkiExpiry = {
+ enable = mkEnableOption "PKI expiration reminder";
+ };
+
+ config = mkIf cfg.enable {
+ systemd = {
+ services.pki-expiry = {
+ after = ["postfix.service"];
+ path = ["/run/wrappers"];
+
+ environment.PKI_PUBLIC = let
+ mkdir = "mkdir -p $out/{ca,cert,crl}";
+
+ cas = mapAttrsToList (_: ca: "ln -s ${ca.cert} $out/ca/${ca.path}") pki.ca;
+ crls = mapAttrsToList (_: ca: "ln -s ${ca.crl} $out/crl/${ca.path}") pki.ca;
+
+ certs =
+ mapAttrsToList
+ (path: leaf: "ln -s ${leaf.cert} $out/cert/${path}")
+ (filterAttrs (_: object: ! object ? leaves) pki.byPath);
+
+ pkiPublic = pkgs.runCommandNoCCLocal "pki-public" {} (concatLines ([mkdir] ++ cas ++ crls ++ certs));
+ in "${pkiPublic}";
+
+ serviceConfig = {
+ Type = "oneshot";
+ StateDirectory = "pki-expiry";
+ WorkingDirectory = "/var/lib/pki-expiry";
+
+ ExecStart = let
+ script = pkgs.writeShellApplication {
+ name = "pki-expiry";
+ text = readFile ./pki-expiry.sh;
+ runtimeInputs = with pkgs; [diffutils openssl];
+ };
+ in "${getExe script}";
+ };
+ };
+
+ timers.pki-expiry = {
+ wantedBy = ["timers.target"];
+
+ timerConfig = {
+ OnStartupSec = "10m";
+ OnUnitInactiveSec = "3d";
+ };
+ };
+ };
+ };
+}
diff --git a/sys/jobs/pki-expiry/pki-expiry.sh b/sys/jobs/pki-expiry/pki-expiry.sh
new file mode 100644
index 0000000..0e95a26
--- /dev/null
+++ b/sys/jobs/pki-expiry/pki-expiry.sh
@@ -0,0 +1,108 @@
+#!/usr/bin/env bash
+#
+function will_expire() {
+ expiry_status=""
+ expiry_vars="$(openssl "$openssl_cmd" -in "$object_path" -noout "${openssl_var_opts[@]}")"
+
+ expiry_date="$(echo "$expiry_vars" | grep "^$openssl_expiry_var=" | sed 's/^.\+=//g')"
+ if [ -z "$expiry_date" ]; then
+ return 1
+ fi
+
+ expiry_secs="$(date +%s -d "$expiry_date")"
+ diff="$((expiry_secs - now))"
+
+ if [ "$diff" -gt "$1" ]; then
+ return 1
+ elif [ "$diff" -lt 0 ]; then
+ remaining=0
+ else
+ remaining="$((diff / 86400))"
+ fi
+
+ total_matches="$((total_matches + 1))"
+
+ if [ -z "$min_expiry" ]; then
+ min_expiry="$remaining"
+ elif [ "$remaining" -lt "$min_expiry" ]; then
+ min_expiry="$remaining"
+ fi
+}
+
+function has_expired() {
+ if ! will_expire 0; then
+ return 1
+ fi
+
+ expiry_status="has expired"
+}
+
+function will_expire_days() {
+ if ! will_expire "$(($1 * 86400))"; then
+ return 1
+ fi
+
+ expiry_status="will expire in $remaining days"
+}
+
+function check_object() {
+ object_id="$(basename "$1")"
+ object_path="$1"
+
+ if has_expired || will_expire_days 3 || will_expire_days 7 || will_expire_days 15 || will_expire_days 30; then
+ {
+ echo
+ echo "$object_repr '$object_id' $expiry_status"
+ echo "$expiry_vars"
+ } >>"$mail_out"
+ fi
+}
+
+function check_dir() {
+ object_repr="$2"
+
+ for path in "$PKI_PUBLIC/$1"/*; do
+ check_object "$path"
+ done
+}
+
+if [ -z "$PKI_PUBLIC" ]; then
+ echo "$0: \$PKI_PUBLIC not set"
+ exit 1
+elif [ ! -d "$PKI_PUBLIC" ]; then
+ echo "$0: invalid \$PKI_PUBLIC: $PKI_PUBLIC"
+ exit 1
+fi
+
+mail_out="$(mktemp)"
+trap 'rm -f -- "$mail_out"' EXIT
+
+now="$(date +%s)"
+min_expiry=""
+total_matches=0
+
+openssl_cmd=x509
+openssl_var_opts=(-startdate -enddate)
+openssl_expiry_var="notAfter"
+
+check_dir ca "CA"
+check_dir cert "Certificate"
+
+openssl_cmd=crl
+openssl_var_opts=(-lastupdate -nextupdate)
+openssl_expiry_var="nextUpdate"
+
+check_dir crl "CRL for CA"
+
+if [ -s "$mail_out" ] && ! cmp -s last-mail "$mail_out"; then
+ sendmail -t <<- EOF
+ From: PKI expiration reminder <pki-expiry>
+ To: sysadmin
+ Subject: $total_matches PKI objects will expire in $min_expiry days
+
+ The following PKI objects are due for renewal:
+ $(<"$mail_out")
+ EOF
+
+ mv -- "$mail_out" last-mail
+fi
diff --git a/sys/kiosk/default.nix b/sys/kiosk/default.nix
new file mode 100644
index 0000000..be20829
--- /dev/null
+++ b/sys/kiosk/default.nix
@@ -0,0 +1,48 @@
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ cfg = config.local.kiosk;
+in {
+ options.local.kiosk = {
+ enable = mkEnableOption "kiosk mode";
+
+ program = mkOption {
+ type = types.str;
+ };
+
+ user = mkOption {
+ type = types.str;
+ };
+
+ allowVTSwitch = mkOption {
+ type = types.bool;
+ default = false;
+ };
+ };
+
+ config = mkIf cfg.enable {
+ services = {
+ cage = {
+ enable = true;
+ inherit (cfg) program user;
+
+ extraArguments = [
+ (
+ if cfg.allowVTSwitch
+ then "-sd"
+ else "-d"
+ )
+ ];
+ };
+
+ physlock = {
+ enable = true;
+ disableSysRq = true;
+ muteKernelMessages = true;
+ };
+ };
+ };
+}
diff --git a/sys/mail/default.nix b/sys/mail/default.nix
new file mode 100644
index 0000000..f87b6fe
--- /dev/null
+++ b/sys/mail/default.nix
@@ -0,0 +1,246 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.mailHost;
+ imapHostname = config.local.domains.imap.main;
+
+ cert = config.security.acme.certs.${imapHostname}.directory;
+
+ inherit (config.local) users virtual;
+in {
+ options.local.mailHost = {
+ enable = mkEnableOption "mailbox host service";
+
+ mdaListen = mkOption {
+ type = types.str;
+ };
+
+ saslPort = mkOption {
+ type = types.port;
+ };
+
+ lmtpPort = mkOption {
+ type = types.port;
+ };
+ };
+
+ config = mkIf cfg.enable {
+ # 25.05: The option definition `services.dovecot2.modules' in
+ # `/nix/store/d3mfmsa6klf9dizidvs9qgfv4bgxqgvz-source/sys/mail' no longer
+ # has any effect; please remove it. Now need to use
+ # `environment.systemPackages` to load additional Dovecot modules
+ environment.systemPackages = [
+ pkgs.dovecot_pigeonhole
+ ];
+
+ services = {
+ dovecot2 = {
+ enable = true;
+ enablePAM = false;
+ enableLmtp = true;
+
+ sslServerKey = "${cert}/key.pem";
+ sslServerCert = "${cert}/fullchain.pem";
+
+ mailUser = "vmail";
+ mailGroup = "vmail";
+ mailLocation = "maildir:~/mail";
+ mailPlugins.perProtocol.lmtp.enable = ["sieve"];
+
+ # https://github.com/NixOS/nixpkgs/issues/286859
+ sieve.extensions = [
+ "fileinto"
+ "mailbox"
+ ];
+
+ extraConfig = let
+ inherit (config.networking) domain;
+
+ # https://dovecot.org/list/dovecot/2019-March/115250.html
+ # Otra solución posible (https://serverfault.com/a/1062274/980378):
+ # auth_username_format = %{if;%d;eq;${domain};%Ln;%Lu}
+ localEntry = canonical: username: ''
+ ${username}:::::::user=${canonical} nopassword userdb_user=${canonical}
+ '';
+
+ localMailboxes =
+ pkgs.writeText "local-mailboxes"
+ (concatStrings
+ (flatten (mapAttrsToList
+ (canonical: user:
+ map (localEntry canonical) ([canonical] ++ user.hardAliases))
+ users)));
+
+ localCerts = flatten (mapAttrsToList
+ (canonical: user: let
+ certNames = {
+ inherit canonical;
+ logins = [canonical] ++ user.hardAliases;
+ };
+ in
+ map (flip nameValuePair certNames) user.mail.certs)
+ users);
+
+ vmailCerts = flatten (flatten (mapAttrsToList
+ (domain: virtual:
+ mapAttrsToList
+ (username: user: let
+ address = "${username}@${domain}";
+
+ certNames = {
+ canonical = address;
+ logins = [address];
+ };
+ in
+ map (flip nameValuePair certNames) user.mail.certs)
+ virtual.users)
+ virtual));
+
+ certLogins =
+ pkgs.writeText "cert-logins"
+ (concatLines (flatten (mapAttrsToList
+ (certPath: names:
+ map
+ (addr: "${config.local.pki.byPath.${certPath}.commonName}@nodomain,${addr}:::::::user=${names.canonical}")
+ names.logins)
+ (listToAttrs (localCerts ++ vmailCerts)))));
+
+ vmailPath = "/var/lib/vmail/%{if;%d;ne;;%Ld;${domain}}";
+ in ''
+ auth_mechanisms = plain login external
+
+ ssl_ca = <${config.local.pki.ca.mail.fullchain}
+ ssl_require_crl = yes
+ ssl_verify_client_cert = yes
+
+ # Esto descarta @domain.tld de locales explícitos, pero lo exige para los demás.
+ # Implicación: locales implícitos sin dominio fallan en autenticar
+ auth_username_format = %{if;%Ld;eq;${domain};%Ln;%{if;%d;ne;;%Lu;%Ln@nodomain}}
+ auth_ssl_username_from_cert = yes
+
+ # TODO: los defaults de nixpkgs dejan los sockets bajo
+ # /run/dovecot2 con demasiados permisos rwx, arreglar
+
+ service auth {
+ inet_listener mta-sasl {
+ port = ${toString cfg.saslPort}
+ address = ${cfg.mdaListen}
+ }
+ }
+
+ service lmtp {
+ inet_listener mta-lmtp {
+ port = ${toString cfg.lmtpPort}
+ address = ${cfg.mdaListen}
+ }
+ }
+
+ # FIXME: Esta cadena de passdbs hace que 'doveadm user lookup'
+ # falle para usuarios locales, pero todo lo demás sirve. Parece
+ # ser debido a que pam no puede enumerar.
+
+ passdb {
+ driver = static
+ args = nopassword
+
+ master = yes
+ mechanisms = external
+
+ result_success = continue-fail
+ result_failure = return-fail
+ result_internalfail = return-fail
+ }
+
+ passdb {
+ driver = passwd-file
+ args = scheme=PLAIN username_format=%{master_user},%Lu ${certLogins}
+
+ mechanisms = external
+ override_fields = nopassword
+
+ result_failure = return-fail
+ result_internalfail = return-fail
+ }
+
+ passdb {
+ driver = passwd-file
+ args = username_format=%Ln ${vmailPath}/passwd
+ }
+
+ passdb {
+ driver = passwd-file
+ args = scheme=PLAIN ${localMailboxes}
+
+ # Esta es una forma de determinar si se encontró el usuario en
+ # el passwd-file por medio de nopassword sin realmente
+ # autenticarlo. Cuidado con result_success, porque si eso se
+ # configura mal se permite inicio de sesión con cualquier
+ # contraseña (!!!).
+ result_success = continue
+ result_failure = return-fail
+ result_internalfail = return-fail
+
+ username_filter = !*@*
+ }
+
+ passdb {
+ driver = pam
+ args = dovecot2
+ username_filter = !*@*
+ #TODO: algo como 'override_fields = allow_nets=...'
+ }
+
+ userdb {
+ driver = passwd-file
+ args = username_format=%Ln ${vmailPath}/passwd
+ override_fields = uid=vmail gid=vmail home=${vmailPath}/home/%Ln
+ }
+
+ userdb {
+ driver = passwd-file
+ args = ${localMailboxes}
+
+ result_success = continue-ok
+ result_internalfail = return-fail
+ skip = found
+ }
+
+ userdb {
+ driver = passwd
+ args = blocking=no
+ skip = notfound
+ }
+ '';
+ };
+
+ fail2ban.jails.dovecot.settings = {
+ filter = "dovecot[mode=aggressive]";
+ maxretry = 3;
+ };
+ };
+
+ security = {
+ # Necesario debido a 'enablePAM = false'
+ pam.services.dovecot2 = {};
+
+ acme.certs.${imapHostname} = {
+ inherit (config.services.dovecot2) group;
+
+ reloadServices = ["dovecot2.service"];
+ };
+ };
+
+ users = {
+ users.${config.services.dovecot2.mailUser}.uid = 995;
+ groups.${config.services.dovecot2.mailGroup}.gid = 993;
+ };
+
+ networking.firewall.allowedTCPPorts = [143 993];
+
+ local.certs.imap.enable = true;
+ };
+}
diff --git a/sys/mta/default.nix b/sys/mta/default.nix
new file mode 100644
index 0000000..57c1c27
--- /dev/null
+++ b/sys/mta/default.nix
@@ -0,0 +1,269 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.mta;
+
+ inherit (config.local) domains virtual users;
+ inherit (config.networking) domain;
+
+ isBackup = cfg.mode == "backup";
+ isPrimary = cfg.mode == "primary";
+
+ allDomains = optional (! virtualDomains ? ${domain}) domain ++ attrNames virtualDomains;
+ virtualDomains = filterAttrs (name: _: name != domain) virtual;
+
+ cert = config.security.acme.certs.${mtaDomain.main}.directory;
+
+ mtaDomain =
+ if isPrimary
+ then domains.smtp
+ else domains.smtp-backup;
+
+ mdaTransport =
+ if isPrimary
+ then "lmtp:inet:${cfg.mdaAddr}:${toString cfg.lmtpPort}"
+ else "error:bad transport";
+in {
+ options.local.mta = {
+ enable = mkEnableOption "mail transfer agent";
+
+ mode = mkOption {
+ type = types.enum ["primary" "backup"];
+ };
+
+ mdaAddr = mkOption {
+ type = types.str;
+ };
+
+ saslPort = mkOption {
+ type = types.port;
+ };
+
+ lmtpPort = mkOption {
+ type = types.port;
+ };
+
+ relayListen = mkOption {
+ type = types.str;
+ };
+ };
+
+ config = mkIf cfg.enable {
+ services = {
+ fail2ban.jails.postfix.settings = {
+ filter = "postfix[mode=aggressive]";
+ };
+
+ opendkim = mkIf isPrimary {
+ enable = true;
+
+ group = "postfix";
+ domains = "csl:" + concatStringsSep "," ([domain] ++ attrNames virtualDomains);
+ selector = "202408";
+
+ configFile = pkgs.writeText "opendkim.conf" ''
+ UMask 007
+ InternalHosts 0.0.0.0/0,::/0
+ '';
+ };
+
+ postfix = {
+ enable = true;
+ enableSmtp = true;
+ enableSubmissions = isPrimary;
+
+ inherit domain;
+ hostname = mtaDomain.main;
+
+ #TODO: check_recipient_access para rechazar localhost desde afuera
+ destination = optionals isPrimary ["localhost" "$mydomain"];
+ origin = "$mydomain";
+
+ networksStyle = "host";
+
+ relayHost = optionalString isBackup domains.smtp.main;
+ lookupMX = false;
+
+ relayDomains =
+ if isBackup
+ then allDomains
+ else null;
+
+ sslKey = "${cert}/key.pem";
+ sslCert = "${cert}/fullchain.pem";
+
+ # También es postmaster
+ rootAlias = config.local.sysadmin;
+
+ extraAliases =
+ optionalString isPrimary
+ (concatLines (flatten (mapAttrsToList
+ (name: user:
+ map
+ (alias: "${alias}: ${name}")
+ user.hardAliases)
+ users)));
+
+ localRecipients =
+ optionals isPrimary
+ (map (user: "${user}@${domain}")
+ (attrNames (users // virtual.${domain}.users)));
+
+ virtual =
+ optionalString isPrimary
+ (concatLines (flatten (mapAttrsToList
+ (name: virtual:
+ mapAttrsToList
+ (alias: targets: "${alias}@${name} ${concatStringsSep ", " targets}")
+ virtual.aliases)
+ virtual)));
+
+ mapFiles = optionalAttrs isPrimary {
+ sender_ccerts =
+ pkgs.writeText "postfix-sender_ccerts"
+ (concatLines (flatten (mapAttrsToList
+ (username: user:
+ map
+ (alias: "${alias}@${domain} CCERTS ${concatStringsSep ","
+ (map (certPath: config.local.pki.byPath.${certPath}.fingerprint.sha256-bytes-upper)
+ user.mail.certs)}")
+ ([username] ++ user.hardAliases))
+ (filterAttrs (_: user: user.mail.certs != []) users))));
+
+ sender_login =
+ pkgs.writeText "postfix-sender_login"
+ (concatLines (flatten (mapAttrsToList
+ (username: user:
+ map
+ (alias: "${alias}@${domain} ${username}")
+ ([username] ++ user.hardAliases))
+ users)));
+
+ virtual_recipients =
+ pkgs.writeText "postfix-virtual_recipients"
+ (concatLines (flatten (mapAttrsToList
+ (virtualDomain: virtual:
+ mapAttrsToList
+ # El lado derecho de esta tabla debe existir pero nunca se usa
+ (username: _: "${username}@${virtualDomain} foo")
+ virtual.users)
+ virtualDomains)));
+
+ virtual_rules =
+ pkgs.writeText "postfix-virtual_rules"
+ (concatLines (flatten (mapAttrsToList
+ (name: virtual:
+ map
+ (rule: "/^${rule.pattern}@${name}$/ ${concatStringsSep ", " rule.targets}")
+ virtual.rules)
+ virtual)));
+ };
+
+ config =
+ {
+ # user+extension@domain.tld
+ recipient_delimiter = optionalString isPrimary "+";
+
+ message_size_limit = toString (50 * 1048576);
+
+ local_transport = mdaTransport;
+ virtual_transport = mdaTransport;
+
+ smtpd_tls_auth_only = true;
+ # Nota: smtpd_tls_dh1024_param_file fue deprecado en 3.9
+
+ tls_append_default_CA = false; # Crítico
+
+ # https://linux-audit.com/postfix-hardening-guide-for-security-and-privacy/
+ smtpd_helo_required = true;
+ disable_vrfy_command = true;
+ }
+ // optionalAttrs isPrimary {
+ virtual_alias_maps = mkAfter ["pcre:/etc/postfix/virtual_rules"];
+ virtual_mailbox_domains = attrNames virtualDomains;
+ virtual_mailbox_maps = ["hash:/etc/postfix/virtual_recipients"];
+
+ smtpd_sasl_type = "dovecot";
+ smtpd_sasl_path = "inet:${cfg.mdaAddr}:${toString cfg.saslPort}";
+ smtpd_sasl_local_domain = "$mydomain";
+ smtpd_sasl_security_options = ["noanonymous"];
+
+ smtpd_tls_CAfile = "${config.local.pki.ca.mail.fullchain}";
+ smtpd_tls_ccert_verifydepth = "1";
+
+ # Inventado, no es parámetro de postfix
+ local_submission_client_restrictions = [
+ "permit_tls_all_clientcerts"
+ "permit_sasl_authenticated"
+ "reject"
+ ];
+
+ smtpd_sender_login_maps = ["hash:/etc/postfix/sender_login"];
+
+ smtpd_relay_restrictions = [
+ "permit_mynetworks"
+ "permit_tls_all_clientcerts"
+ "permit_sasl_authenticated"
+ "reject_unauth_destination"
+ ];
+
+ smtpd_sender_restrictions = [
+ "check_sender_access hash:/etc/postfix/sender_ccerts"
+ "reject_sender_login_mismatch"
+ ];
+
+ smtpd_milters = "unix:/run/opendkim/opendkim.sock";
+ non_smtpd_milters = "$smtpd_milters";
+ milter_default_action = "accept";
+ }
+ // optionalAttrs isBackup {
+ inet_interfaces = [cfg.relayListen];
+
+ smtpd_relay_restrictions = [
+ "reject_unauth_destination"
+ ];
+ };
+
+ # Importante: existe submissionOptions por aparte, no son iguales
+ submissionsOptions = optionalAttrs isPrimary {
+ smtpd_client_restrictions = "$local_submission_client_restrictions";
+ smtpd_sasl_auth_enable = "yes";
+ smtpd_tls_ask_ccert = "yes";
+ smtpd_tls_security_level = "encrypt";
+ };
+ };
+ };
+
+ #TODO: solo para las destination addresses necesarias
+ networking.firewall.allowedTCPPorts = optionals isPrimary [25 465];
+
+ local = {
+ boot.impermanence.directories =
+ [
+ {
+ directory = "/var/lib/postfix";
+ user = "root";
+ group = "root";
+ mode = "u=rwx,g=rx,o=rx";
+ }
+ ]
+ ++ optionals isPrimary [
+ {
+ directory = "/var/lib/opendkim";
+ user = "opendkim";
+ group = "postfix";
+ mode = "u=rwx,g=,o=";
+ }
+ ];
+
+ certs.smtp.enable = isPrimary;
+ certs.smtp-backup.enable = isBackup;
+ };
+
+ security.acme.certs.${mtaDomain.main}.reloadServices = ["postfix.service"];
+ };
+}
diff --git a/sys/net/default.nix b/sys/net/default.nix
new file mode 100644
index 0000000..c3c5740
--- /dev/null
+++ b/sys/net/default.nix
@@ -0,0 +1,9 @@
+{
+ imports = [
+ ./fail2ban.nix
+ ./interfaces.nix
+ ./nets.nix
+ ./options.nix
+ ./vsock.nix
+ ];
+}
diff --git a/sys/net/fail2ban.nix b/sys/net/fail2ban.nix
new file mode 100644
index 0000000..32197b6
--- /dev/null
+++ b/sys/net/fail2ban.nix
@@ -0,0 +1,37 @@
+{
+ lib,
+ config,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.net.fail2ban;
+ inherit (config.local) nets;
+in {
+ options.local.net.fail2ban = {
+ enable = mkEnableOption "fail2ban";
+ };
+
+ config = mkIf cfg.enable {
+ services.fail2ban = {
+ enable = true;
+
+ bantime = "10m";
+
+ bantime-increment = {
+ enable = true;
+
+ maxtime = "48h";
+ rndtime = "10m";
+ overalljails = true;
+ };
+
+ ignoreIP = [
+ nets.static-vpn.v6.cidr
+ nets.gate-srv.v6.cidr
+ nets.gate-public.hosts.gate.v4.address
+ nets.gate-public.hosts.gate.v6.address
+ ];
+ };
+ };
+}
diff --git a/sys/net/interfaces.nix b/sys/net/interfaces.nix
new file mode 100644
index 0000000..3b0abcd
--- /dev/null
+++ b/sys/net/interfaces.nix
@@ -0,0 +1,119 @@
+{
+ lib,
+ config,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.net;
+in {
+ options.local.net = with lib.types; {
+ enable = mkEnableOption "networking stack";
+
+ hostname = mkOption {
+ type = str;
+ };
+
+ dhcpInterface = mkOption {
+ type = nullOr str;
+ default = null;
+ };
+ };
+
+ config = mkIf cfg.enable {
+ boot.kernel.sysctl = {
+ # rp_filter=1 reemplazado por nixos-fw-rpfilter
+ "net.ipv4.conf.all.rp_filter" = mkForce 2;
+ "net.ipv4.conf.default.rp_filter" = mkForce 2;
+
+ "net.ipv4.conf.all.forwarding" = mkForce true;
+ "net.ipv6.conf.all.forwarding" = mkForce true;
+ "net.ipv4.conf.default.forwarding" = mkForce true;
+ "net.ipv6.conf.default.forwarding" = mkForce true;
+
+ "net.ipv4.conf.all.accept_redirects" = mkForce false;
+ "net.ipv6.conf.all.accept_redirects" = mkForce false;
+ "net.ipv4.conf.default.accept_redirects" = mkForce false;
+ "net.ipv6.conf.default.accept_redirects" = mkForce false;
+ };
+
+ environment.systemPackages = with pkgs; [
+ conntrack-tools
+ dhcpcd
+ dnsutils
+ nmap
+ socat
+ tcpdump
+ ];
+
+ networking = {
+ domain = mkDefault config.local.domains.host.main;
+ hostName = cfg.hostname;
+
+ firewall = {
+ logReversePathDrops = true;
+ checkReversePath = "loose";
+
+ extraCommands = mkBefore ''
+ ip46tables -t filter -P INPUT DROP
+ ip46tables -t filter -P FORWARD ACCEPT #TODO: DROP
+
+ ip46tables -t filter -N local-input
+ ip46tables -t filter -N local-forward
+ ip46tables -t nat -N local-prerouting
+ ip46tables -t nat -N local-postrouting
+
+ ip46tables -t filter -I INPUT -j local-input
+ ip46tables -t filter -I FORWARD -j local-forward
+ ip46tables -t nat -I PREROUTING -j local-prerouting
+ ip46tables -t nat -I POSTROUTING -j local-postrouting
+
+ ip46tables -t filter -A local-forward -m conntrack --ctstate RELATED,ESTABLISHED,SNAT,DNAT -j ACCEPT
+ '';
+
+ extraStopCommands = mkAfter ''
+ ip46tables -t filter -D INPUT -j local-input || true
+ ip46tables -t filter -D FORWARD -j local-forward || true
+ ip46tables -t nat -D PREROUTING -j local-prerouting || true
+ ip46tables -t nat -D POSTROUTING -j local-postrouting || true
+
+ ip46tables -t filter -F local-input || true
+ ip46tables -t filter -X local-input || true
+ ip46tables -t filter -F local-forward || true
+ ip46tables -t filter -X local-forward || true
+ ip46tables -t nat -F local-prerouting || true
+ ip46tables -t nat -X local-prerouting || true
+ ip46tables -t nat -F local-postrouting || true
+ ip46tables -t nat -X local-postrouting || true
+
+ ip46tables -t filter -P INPUT ACCEPT
+ ip46tables -t filter -P FORWARD ACCEPT
+ '';
+
+ logRefusedConnections = false;
+ };
+
+ useDHCP = false;
+ enableIPv6 = mkDefault true;
+ useNetworkd = mkDefault true;
+ useHostResolvConf = false;
+
+ wireguard.enable = true;
+ };
+
+ systemd.network.networks = mkIf (cfg.dhcpInterface != null) {
+ "40-${cfg.dhcpInterface}" = {
+ matchConfig.Name = cfg.dhcpInterface;
+
+ networkConfig = {
+ DHCP = "ipv4";
+ IPv6AcceptRA = true;
+ IPv6PrivacyExtensions = "kernel";
+ };
+
+ # make routing on this interface a dependency for network-online.target
+ linkConfig.RequiredForOnline = "routable";
+ };
+ };
+ };
+}
diff --git a/sys/net/nets.nix b/sys/net/nets.nix
new file mode 100644
index 0000000..1bb3788
--- /dev/null
+++ b/sys/net/nets.nix
@@ -0,0 +1 @@
+# This file has been lustrated.
diff --git a/sys/net/options.nix b/sys/net/options.nix
new file mode 100644
index 0000000..0608fb9
--- /dev/null
+++ b/sys/net/options.nix
@@ -0,0 +1,278 @@
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ v4PtrHierarchy = address: bits: reverseList (sublist 0 (bits / 8) (splitString "." address));
+
+ v6PtrHierarchy = address: bits: let
+ separator = lists.findFirstIndex (hextet: hextet == "") null colonSplit;
+ colonSplit = splitString ":" address;
+
+ zeroFill = replicate (8 - length colonSplit + 1) "0000";
+ leftSplit = sublist 0 separator colonSplit;
+ rightSplit = sublist (separator + 1) (length colonSplit - separator - 1) colonSplit;
+
+ fullSplit =
+ if separator != null
+ then leftSplit ++ zeroFill ++ rightSplit
+ else colonSplit;
+
+ padded = map (hextet: strings.replicate (4 - stringLength hextet) "0" + hextet) fullSplit;
+ in
+ reverseList (sublist 0 (bits / 4) (flatten (map stringToCharacters padded)));
+
+ matchPtrRecordName = {
+ splitter,
+ netAddress,
+ netBits,
+ targetAddress,
+ targetBits,
+ }: let
+ netSplit = splitter netAddress netBits;
+ targetSplit = splitter targetAddress targetBits;
+
+ netLength = length netSplit;
+ lengthDelta = length targetSplit - netLength;
+
+ withinNet = lengthDelta >= 0 && sublist lengthDelta netLength targetSplit == netSplit;
+ throwMessage = "${targetAddress}/${toString targetBits} is not a subset of ${netAddress}/${toString netBits}";
+
+ recordHierarchy = sublist 0 lengthDelta targetSplit;
+
+ recordName =
+ if recordHierarchy != []
+ then concatStringsSep "." recordHierarchy
+ else "@";
+ in
+ throwIfNot withinNet throwMessage recordName;
+in {
+ options.local.nets = with lib.types;
+ mkOption {
+ readOnly = true;
+
+ type = attrsOf (submodule ({config, ...}: {
+ options = let
+ v4config = config.v4;
+ v6config = config.v6;
+ in {
+ hosts = mkOption {
+ default = {};
+
+ type = attrsOf (submodule {
+ options = {
+ v4 = mkOption {
+ default = null;
+
+ type = nullOr (submodule ({config, ...}: {
+ options = {
+ suffix = mkOption {
+ type = str;
+ };
+
+ address = mkOption {
+ type = str;
+ readOnly = true;
+ };
+
+ cidr = mkOption {
+ type = str;
+ readOnly = true;
+ };
+
+ single = mkOption {
+ type = str;
+ readOnly = true;
+ };
+ };
+
+ config = {
+ address =
+ if v4config.bits == 0
+ then config.suffix
+ else if v4config.bits == 32
+ then v4config.subnet
+ else "${v4config.prefix}.${config.suffix}";
+
+ cidr = "${config.address}/${toString v4config.bits}";
+ single = "${config.address}/32";
+ };
+ }));
+ };
+
+ v6 = mkOption {
+ default = null;
+
+ type = nullOr (submodule ({config, ...}: {
+ options = {
+ suffix = mkOption {
+ type = str;
+ };
+
+ address = mkOption {
+ type = str;
+ readOnly = true;
+ };
+
+ cidr = mkOption {
+ type = str;
+ readOnly = true;
+ };
+
+ single = mkOption {
+ type = str;
+ readOnly = true;
+ };
+ };
+
+ config = {
+ address = let
+ hextets = fragment: length (splitString ":" fragment);
+ separator =
+ if doubleColon
+ then "::"
+ else ":";
+ doubleColon = hextets v6config.prefix + hextets config.suffix < 8;
+
+ joined =
+ if v6config.bits == 128
+ then v6config.prefix
+ else if v6config.bits == 0
+ then config.suffix
+ else "${v6config.prefix}${separator}${config.suffix}";
+ in
+ joined;
+
+ cidr = "${config.address}/${toString v6config.bits}";
+ single = "${config.address}/128";
+ };
+ }));
+ };
+ };
+ });
+ };
+
+ v4 = mkOption {
+ default = null;
+
+ type = nullOr (submodule ({config, ...}: {
+ options = {
+ bits = mkOption {
+ type = enum [0 8 16 24 32];
+ };
+
+ prefix = mkOption {
+ type = str;
+ };
+
+ subnet = mkOption {
+ type = str;
+ readOnly = true;
+ };
+
+ cidr = mkOption {
+ type = str;
+ readOnly = true;
+ };
+
+ ptrDomain = mkOption {
+ type = str;
+ readOnly = true;
+ };
+
+ ptrRecordName = mkOption {
+ type = functionTo (functionTo str);
+ readOnly = true;
+ };
+ };
+
+ config = {
+ cidr = "${config.subnet}/${toString config.bits}";
+
+ subnet =
+ if config.bits != 0
+ then config.prefix + strings.replicate (4 - config.bits / 8) ".0"
+ else "0.0.0.0";
+
+ ptrDomain = concatStrings (map (x: x + ".") (v4PtrHierarchy config.subnet config.bits)) + "in-addr.arpa";
+
+ ptrRecordName = address: bits:
+ matchPtrRecordName {
+ splitter = v4PtrHierarchy;
+
+ netBits = config.bits;
+ netAddress = config.subnet;
+
+ targetBits = bits;
+ targetAddress = address;
+ };
+ };
+ }));
+ };
+
+ v6 = mkOption {
+ default = null;
+
+ type = nullOr (submodule ({config, ...}: {
+ options = {
+ bits = mkOption {
+ type =
+ addCheck (ints.between 0 128) (b: mod b 4 == 0)
+ // {
+ description = "IPv6 subnet bits at nibble boundary";
+ };
+ };
+
+ prefix = mkOption {
+ type = str;
+ };
+
+ subnet = mkOption {
+ type = str;
+ readOnly = true;
+ };
+
+ cidr = mkOption {
+ type = str;
+ readOnly = true;
+ };
+
+ ptrDomain = mkOption {
+ type = str;
+ readOnly = true;
+ };
+
+ ptrRecordName = mkOption {
+ type = functionTo (functionTo str);
+ readOnly = true;
+ };
+ };
+
+ config = {
+ cidr = "${config.subnet}/${toString config.bits}";
+
+ subnet =
+ if config.bits == 128 || length (splitString "::" config.prefix) > 1
+ then config.prefix
+ else "${config.prefix}::";
+
+ ptrDomain = concatStrings (map (x: x + ".") (v6PtrHierarchy config.subnet config.bits)) + "ip6.arpa";
+
+ ptrRecordName = address: bits:
+ matchPtrRecordName {
+ splitter = v6PtrHierarchy;
+
+ netBits = config.bits;
+ netAddress = config.subnet;
+
+ targetBits = bits;
+ targetAddress = address;
+ };
+ };
+ }));
+ };
+ };
+ }));
+ };
+}
diff --git a/sys/net/vsock.nix b/sys/net/vsock.nix
new file mode 100644
index 0000000..c6b0ad6
--- /dev/null
+++ b/sys/net/vsock.nix
@@ -0,0 +1,63 @@
+{
+ lib,
+ config,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.net.vsock;
+in {
+ options.local.net.vsock = {
+ connect = mkOption {
+ default = {};
+ type = with lib.types;
+ attrsOf (submodule ({name, ...}: {
+ options = {
+ enable = mkEnableOption "vsock connect '${name}'";
+
+ cid = mkOption {
+ type = ints.u32;
+ default = 2;
+ };
+
+ localPort = mkOption {
+ type = port;
+ };
+
+ vsockPort = mkOption {
+ type = port;
+ };
+ };
+ }));
+ };
+ };
+
+ config = {
+ systemd = let
+ connects =
+ mapAttrs
+ (_: connect: {
+ service.serviceConfig = {
+ Type = "simple";
+ ExecStart = "${getExe pkgs.socat} - VSOCK:${toString connect.cid}:${toString connect.vsockPort}";
+ StandardInput = "socket";
+ };
+
+ socket = {
+ wantedBy = ["sockets.target"];
+
+ socketConfig = {
+ Accept = true;
+ ListenStream = "[::1]:${toString connect.localPort}";
+ };
+
+ unitConfig.ConditionVirtualization = "kvm";
+ };
+ })
+ cfg.connect;
+ in {
+ sockets = mapAttrs' (name: connect: nameValuePair "vsock-${name}" connect.socket) connects;
+ services = mapAttrs' (name: connect: nameValuePair "vsock-${name}@" connect.service) connects;
+ };
+ };
+}
diff --git a/sys/ns/default.nix b/sys/ns/default.nix
new file mode 100644
index 0000000..b1a4da3
--- /dev/null
+++ b/sys/ns/default.nix
@@ -0,0 +1,10 @@
+{
+ imports = [
+ ./mx.nix
+ ./ns.nix
+ ./nsd.nix
+ ./ptr
+ ./rr.nix
+ ./zones
+ ];
+}
diff --git a/sys/ns/dkim/README.md b/sys/ns/dkim/README.md
new file mode 100644
index 0000000..37073ba
--- /dev/null
+++ b/sys/ns/dkim/README.md
@@ -0,0 +1 @@
+# This directory has been lustrated.
diff --git a/sys/ns/mx.nix b/sys/ns/mx.nix
new file mode 100644
index 0000000..892b684
--- /dev/null
+++ b/sys/ns/mx.nix
@@ -0,0 +1,60 @@
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ inherit (config.local) domains;
+in {
+ options.local.ns.zones = mkOption {
+ type = with lib.types;
+ attrsOf (submodule ({
+ config,
+ name,
+ ...
+ }: {
+ options.localMX = {
+ enable = mkEnableOption "local MX settings";
+ };
+
+ config = mkIf config.localMX.enable {
+ mx = [
+ {
+ name = "@";
+ priority = 10;
+ host = "${domains.smtp.gated}.";
+ }
+ {
+ name = "@";
+ priority = 20;
+ host = "${domains.smtp-backup.main}.";
+ }
+ # Many thanks to junkemailfilter.com for all their years of service. RIP.
+ #{ name = "@"; priority = 30; host = "mxbackup1.junkemailfilter.com."; }
+ #{ name = "@"; priority = 40; host = "mxbackup2.junkemailfilter.com."; }
+ ];
+
+ txt =
+ [
+ {
+ name = "@";
+ text = "v=spf1 mx a -all";
+ }
+ {
+ name = "_dmarc";
+ text = "v=DMARC1;p=reject;sp=reject;adkim=r;aspf=r;fo=1;rf=afrf;rua=mailto:postmaster@${name}";
+ }
+ {
+ name = "_adsp._domainkey";
+ text = "dkim=all";
+ }
+ ]
+ ++ map
+ (selector: {
+ name = "${toString selector}._domainkey";
+ text = readFile (./dkim + "/${toString selector}.txt");
+ }) [202001 202102 202402 202408];
+ };
+ }));
+ };
+}
diff --git a/sys/ns/ns.nix b/sys/ns/ns.nix
new file mode 100644
index 0000000..e5b30e8
--- /dev/null
+++ b/sys/ns/ns.nix
@@ -0,0 +1,153 @@
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ inherit (config.networking) domain;
+ inherit (config.local.nets) gate-public;
+ inherit (config.local.ns.server) tsigName;
+
+ ptrNets = config.local.ns.ptr;
+in {
+ options.local.ns.zones = mkOption {
+ type = with lib.types;
+ attrsOf
+ (submodule
+ ({
+ config,
+ name,
+ ...
+ }: let
+ inherit (config.soa) primary;
+
+ cfg = config.localNS;
+ ptrDomain = cfg.ptrNet.v4 != null || cfg.ptrNet.v6 != null;
+ in {
+ options.localNS = {
+ enable = mkEnableOption "local NS settings";
+
+ acme = mkOption {
+ default = {};
+ type = attrsOf str;
+ };
+
+ ptrNet = {
+ v4 = mkOption {
+ type = nullOr str;
+ default = null;
+ };
+
+ v6 = mkOption {
+ type = nullOr str;
+ default = null;
+ };
+ };
+ };
+
+ config =
+ mkIf cfg.enable
+ {
+ ptrName = let
+ name =
+ if cfg.ptrNet.v6 != null
+ then "${cfg.ptrNet.v6}-v6"
+ else "${cfg.ptrNet.v4}-v4";
+ in
+ mkIf ptrDomain name;
+
+ # https://docs.gandi.net/en/domain_names/advanced_users/secondary_nameserver.html
+ nsdConfig = let
+ providerSecondary = [
+ "37.205.15.45 ${tsigName}" # ns3.vpsfree.cz
+ "37.205.11.85 ${tsigName}" # ns4.vpsfree.cz
+ "2a03:3b40:fe:2be::1 ${tsigName}" # ns3.vpsfree.cz
+ "2a03:3b40:101:4::1 ${tsigName}" # ns4.vpsfree.cz
+ ];
+ in {
+ notify = providerSecondary;
+ provideXFR = providerSecondary;
+ };
+
+ ns = [
+ {
+ name = "@";
+ host = primary;
+ }
+ {
+ name = "@";
+ host = "ns3.vpsfree.cz.";
+ }
+ {
+ name = "@";
+ host = "ns4.vpsfree.cz.";
+ }
+ ];
+
+ a =
+ optional (!ptrDomain)
+ {
+ name = primary;
+ ipv4 = gate-public.hosts.gate.v4.address;
+ ptr = null;
+ };
+
+ aaaa =
+ optional (!ptrDomain)
+ {
+ name = primary;
+ ipv6 = gate-public.hosts.gate.v6.address;
+ ptr = null;
+ };
+
+ ptr = let
+ ptrsToRecords = mapAttrsToList (suffix: target: {
+ name = suffix;
+ inherit target;
+ });
+
+ v4Net = cfg.ptrNet.v4;
+ v6Net = cfg.ptrNet.v6;
+
+ v4Records = optionals (v4Net != null) (ptrsToRecords ptrNets.${v4Net}.v4.targets);
+ v6Records = optionals (v6Net != null) (ptrsToRecords ptrNets.${v6Net}.v6.targets);
+ in
+ v4Records ++ v6Records;
+
+ soa = mkIf ptrDomain {
+ authorityZone = mkDefault "${domain}.";
+ };
+
+ cname =
+ mapAttrsToList
+ (name: id: {
+ name = "_acme-challenge" + optionalString (name != "@") ".${name}";
+ target = "${id}.acme-challenge.${domain}.";
+ })
+ cfg.acme;
+ };
+ }));
+ };
+
+ config = {
+ assertions =
+ mapAttrsToList
+ (name: zone: {
+ assertion = zone.localNS.ptrNet.v4 != null -> zone.localNS.ptrNet.v6 == null;
+ message = "zone '${name}' defined as both a v4 and v6 PTR zone";
+ })
+ config.local.ns.zones;
+
+ local.ns.ptr = let
+ zonePtrNets = name: zone:
+ optionalAttrs (zone.localNS.ptrNet.v4 != null)
+ {
+ ${zone.localNS.ptrNet.v4}.v4.zone = name;
+ }
+ // optionalAttrs (zone.localNS.ptrNet.v6 != null) {
+ ${zone.localNS.ptrNet.v6}.v6.zone = name;
+ };
+ in
+ mkMerge (flatten (mapAttrsToList zonePtrNets (filterAttrs (_: zone: zone.localNS.enable) config.local.ns.zones)));
+ };
+}
diff --git a/sys/ns/nsd.nix b/sys/ns/nsd.nix
new file mode 100644
index 0000000..d49e464
--- /dev/null
+++ b/sys/ns/nsd.nix
@@ -0,0 +1,87 @@
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ inherit (config.networking) domain;
+
+ cfg = config.local.ns.server;
+
+ acmeChallengeDomain = "acme-challenge.${domain}";
+in {
+ options. local. ns. server = {
+ enable = mkEnableOption "nsd authoritative server";
+
+ tsigName = mkOption {
+ type = types.str;
+ default = "NOKEY";
+ };
+
+ acme = {
+ apiListen.v6 = mkOption {
+ type = types.str;
+ };
+
+ dnsListen.v6 = mkOption {
+ type = types.str;
+ };
+ };
+ };
+
+ config = mkIf cfg.enable {
+ assertions = [
+ {
+ assertion = cfg.tsigName == "NOKEY" || config.services.nsd.keys ? "${cfg.tsigName}";
+ message = "TSIG key '${cfg.tsigName}' not defined";
+ }
+ ];
+
+ networking.firewall = let
+ inherit (config.services.nsd) port;
+ in {
+ allowedTCPPorts = [port];
+ allowedUDPPorts = [port];
+ };
+
+ services = {
+ acme-dns = {
+ enable = true;
+ settings = {
+ api = {
+ ip = "[${cfg.acme.apiListen.v6}]";
+ port = 80;
+ };
+
+ general = {
+ domain = acmeChallengeDomain;
+ nsname = acmeChallengeDomain;
+ nsadmin = "hostmaster.${domain}";
+
+ listen = "[${cfg.acme.dnsListen.v6}]:53";
+
+ records = [
+ "${acmeChallengeDomain}. NS ${acmeChallengeDomain}."
+ "${acmeChallengeDomain}. AAAA ${cfg.acme.dnsListen.v6}"
+ ];
+ };
+ };
+ };
+
+ nsd = {
+ enable = true;
+
+ ipFreebind = true;
+
+ bind8Stats = true;
+ statistics = 3600;
+
+ tcpCount = 128;
+ tcpTimeout = 30;
+ tcpQueryCount = 128;
+
+ zones = mapAttrs' (name: zone: nameValuePair "${name}." zone.nsdConfig) config.local.ns.zones;
+ };
+ };
+ };
+}
diff --git a/sys/ns/ptr/default.nix b/sys/ns/ptr/default.nix
new file mode 100644
index 0000000..b4fba7e
--- /dev/null
+++ b/sys/ns/ptr/default.nix
@@ -0,0 +1,9 @@
+{config, ...}: let
+ inherit (config.local) nets;
+in {
+ config.local.ns.zones = {
+ ${nets.gate-public.v4.ptrDomain} = import ./gate-public-v4;
+ ${nets.gate-public.v6.ptrDomain} = import ./gate-public-v6;
+ ${nets.static-prefix.v6.ptrDomain} = import ./static-prefix-v6;
+ };
+}
diff --git a/sys/ns/ptr/gate-public-v4/default.nix b/sys/ns/ptr/gate-public-v4/default.nix
new file mode 100644
index 0000000..44c7f2e
--- /dev/null
+++ b/sys/ns/ptr/gate-public-v4/default.nix
@@ -0,0 +1,14 @@
+{config, ...}: let
+ inherit (config.local) nets;
+in {
+ imports = [
+ ./serial.nix
+ ];
+
+ config = {
+ localNS = {
+ enable = true;
+ ptrNet.v4 = "gate-public";
+ };
+ };
+}
diff --git a/sys/ns/ptr/gate-public-v4/serial.nix b/sys/ns/ptr/gate-public-v4/serial.nix
new file mode 100644
index 0000000..008e5d8
--- /dev/null
+++ b/sys/ns/ptr/gate-public-v4/serial.nix
@@ -0,0 +1,6 @@
+{
+ config = {
+ soa.serial = 2025042402;
+ nullSerialHash = "sha256-afaedee02017aabd45b944a657ce91515866982c7cb900927edcee6d2b39c731";
+ };
+}
diff --git a/sys/ns/ptr/gate-public-v6/default.nix b/sys/ns/ptr/gate-public-v6/default.nix
new file mode 100644
index 0000000..674421f
--- /dev/null
+++ b/sys/ns/ptr/gate-public-v6/default.nix
@@ -0,0 +1,14 @@
+{config, ...}: let
+ inherit (config.local) nets;
+in {
+ imports = [
+ ./serial.nix
+ ];
+
+ config = {
+ localNS = {
+ enable = true;
+ ptrNet.v6 = "gate-public";
+ };
+ };
+}
diff --git a/sys/ns/ptr/gate-public-v6/serial.nix b/sys/ns/ptr/gate-public-v6/serial.nix
new file mode 100644
index 0000000..126a17e
--- /dev/null
+++ b/sys/ns/ptr/gate-public-v6/serial.nix
@@ -0,0 +1,6 @@
+{
+ config = {
+ soa.serial = 2025042402;
+ nullSerialHash = "sha256-9a8ac8849ea6c8993e44feefe439b96c643e2ccf3a03d0d700558e9a188f57d7";
+ };
+}
diff --git a/sys/ns/ptr/static-prefix-v6/default.nix b/sys/ns/ptr/static-prefix-v6/default.nix
new file mode 100644
index 0000000..7688b97
--- /dev/null
+++ b/sys/ns/ptr/static-prefix-v6/default.nix
@@ -0,0 +1,14 @@
+{config, ...}: let
+ inherit (config.local) nets;
+in {
+ imports = [
+ ./serial.nix
+ ];
+
+ config = {
+ localNS = {
+ enable = true;
+ ptrNet.v6 = "static-prefix";
+ };
+ };
+}
diff --git a/sys/ns/ptr/static-prefix-v6/serial.nix b/sys/ns/ptr/static-prefix-v6/serial.nix
new file mode 100644
index 0000000..a7c214a
--- /dev/null
+++ b/sys/ns/ptr/static-prefix-v6/serial.nix
@@ -0,0 +1,6 @@
+{
+ config = {
+ soa.serial = 2025042600;
+ nullSerialHash = "sha256-a5ce7781b014aa816998410db440dd40278d8b566d1de76e06776a83c9839b35";
+ };
+}
diff --git a/sys/ns/rr.nix b/sys/ns/rr.nix
new file mode 100644
index 0000000..7f089d1
--- /dev/null
+++ b/sys/ns/rr.nix
@@ -0,0 +1,520 @@
+{
+ config,
+ lib,
+ options,
+ pkgs,
+ ...
+}:
+with lib; let
+ inherit (config.local) nets;
+
+ cfg = config.local.ns;
+ globalConfig = config;
+
+ segmentRegex = "[a-z0-9_-]+(\\.[a-z0-9_-]+)*";
+
+ emailType = lib.types.strMatching "[a-z0-9._-]+(@${segmentRegex})?";
+ domainRefType = lib.types.strMatching "@|${segmentRegex}\\.?";
+ domainNameType = lib.types.strMatching "${segmentRegex}\\.";
+
+ zoneHashCheck = name: zone: let
+ zoneHash = algorithm: "${algorithm}-${builtins.hashString algorithm cfg.nullSerialZones.${name}.content}";
+ expected = zoneHash "sha256";
+ in {
+ inherit expected zone;
+ needsUpdate = zone.soa.serial == null || zone.nullSerialHash != expected;
+ };
+
+ rrTypes = [
+ "A"
+ "AAAA"
+ "CNAME"
+ "MX"
+ "NS"
+ "PTR"
+ "SOA"
+ "SRV"
+ "TXT"
+ ];
+in {
+ options.local.ns = {
+ nullSerialZones = mkOption {
+ type = options.local.ns.zones.type;
+ readOnly = true;
+ };
+
+ ptr = mkOption {
+ default = {};
+
+ type = with lib.types;
+ attrsOf (submodule {
+ options = {
+ v4 = {
+ zone = mkOption {
+ type = nullOr str;
+ default = null;
+ };
+
+ targets = mkOption {
+ type = attrsOf str;
+ default = {};
+ };
+ };
+
+ v6 = {
+ zone = mkOption {
+ type = nullOr str;
+ default = null;
+ };
+
+ targets = mkOption {
+ type = attrsOf str;
+ default = {};
+ };
+ };
+ };
+ });
+ };
+
+ zones = mkOption {
+ default = {};
+
+ type = with lib.types;
+ attrsOf (submodule ({
+ config,
+ name,
+ ...
+ }: let
+ nameOption = args @ {
+ defaultZone ? "${name}.",
+ permitRelative ? true,
+ ...
+ }:
+ mkOption (removeAttrs args ["defaultZone" "permitRelative"]
+ // {
+ type = domainRefType;
+
+ apply = value: let
+ zone =
+ throwIfNot
+ (hasSuffix "." defaultZone)
+ "zone expression '${defaultZone}' must be absolute, not relative"
+ defaultZone;
+ in
+ if value == "@"
+ then zone
+ else if hasSuffix "." value
+ then value
+ else if permitRelative
+ then "${value}.${zone}"
+ else throw "zone expression '${value}' in zone '${zone}' must be absolute, not relative";
+ });
+
+ rrType = options:
+ mkOption {
+ default = [];
+ type = listOf (submodule {
+ options =
+ options
+ // {
+ name = nameOption {};
+
+ ttl = mkOption {
+ type = int;
+ default = config.defaultTTL;
+ };
+ };
+ });
+ };
+
+ rrConfig = {
+ rrs,
+ type,
+ format,
+ applyName ? (rr: rr.name),
+ }: (map
+ (rr: {
+ inherit type;
+ inherit (rr) ttl;
+
+ data = format rr;
+ name = applyName rr;
+ })
+ rrs);
+ in {
+ options = {
+ local = mkOption {
+ type = unspecified;
+ default = globalConfig.local;
+ readOnly = true;
+ };
+
+ defaultTTL = mkOption {
+ type = int;
+ default = 3600;
+ };
+
+ ptrName = mkOption {
+ type = nullOr str;
+ default = null;
+ };
+
+ defaultPtr = {
+ v4 = mkOption {
+ type = nullOr str;
+ default = null;
+ };
+
+ v6 = mkOption {
+ type = nullOr str;
+ default = null;
+ };
+ };
+
+ nsdConfig = mkOption {
+ type = attrsOf unspecified;
+ default = {};
+ };
+
+ content = mkOption {
+ type = lines;
+ readOnly = true;
+ };
+
+ nullSerialHash = mkOption {
+ type = nullOr str;
+ default = null;
+ };
+
+ rr = mkOption {
+ default = [];
+ type =
+ listOf
+ (submodule {
+ options = {
+ name = nameOption {};
+
+ ttl = mkOption {
+ type = int;
+ };
+
+ class = mkOption {
+ type = enum ["IN"];
+ default = "IN";
+ };
+
+ type = mkOption {
+ type = enum rrTypes;
+ };
+
+ data = mkOption {
+ type = listOf (either int str);
+ default = [];
+ };
+ };
+ });
+ };
+
+ soa = {
+ authorityZone = nameOption {
+ default = "@";
+ permitRelative = false;
+ };
+
+ ttl = mkOption {
+ type = int;
+ default = config.defaultTTL;
+ };
+
+ primary = nameOption {
+ default = "ns1";
+ defaultZone = config.soa.authorityZone;
+ };
+
+ hostmaster = mkOption {
+ type = emailType;
+ default = "hostmaster";
+
+ apply = address: let
+ split = splitString "@" address;
+
+ user = head split;
+ domain =
+ if length split == 2
+ then head (tail split)
+ else removeSuffix "." config.soa.authorityZone;
+ in
+ if hasSuffix "." address
+ then address
+ else "${replaceStrings ["."] ["\\."] user}.${domain}.";
+ };
+
+ serial = mkOption {
+ type = nullOr int;
+ default = null;
+ };
+
+ refresh = mkOption {
+ type = int;
+ default = 3 * 3600;
+ };
+
+ retry = mkOption {
+ type = int;
+ default = 3600;
+ };
+
+ expire = mkOption {
+ type = int;
+ default = 7 * 24 * 3600;
+ };
+
+ negativeTTL = mkOption {
+ type = int;
+ default = 3600;
+ };
+ };
+
+ a = rrType {
+ ipv4 = mkOption {
+ type = str;
+ };
+
+ ptr = mkOption {
+ type = nullOr str;
+ default = config.defaultPtr.v4;
+ };
+ };
+
+ aaaa = rrType {
+ ipv6 = mkOption {
+ type = str;
+ };
+
+ ptr = mkOption {
+ type = nullOr str;
+ default = config.defaultPtr.v6;
+ };
+ };
+
+ cname = rrType {
+ target = nameOption {};
+ };
+
+ mx = rrType {
+ host = nameOption {};
+
+ priority = mkOption {
+ type = int;
+ };
+ };
+
+ ns = rrType {
+ host = nameOption {};
+ };
+
+ ptr = rrType {
+ target = nameOption {};
+ };
+
+ srv = rrType {
+ host = nameOption {};
+
+ port = mkOption {
+ type = port;
+ };
+
+ priority = mkOption {
+ type = int;
+ };
+
+ proto = mkOption {
+ type = enum ["tcp" "udp"];
+ };
+
+ service = mkOption {
+ type = str;
+ };
+
+ weight = mkOption {
+ type = int;
+ };
+ };
+
+ txt = rrType {
+ text = mkOption {
+ type = strMatching "[^\"\n\\]*\n?";
+ apply = removeSuffix "\n";
+ };
+ };
+ };
+
+ config = {
+ nsdConfig.data = config.content;
+
+ content = let
+ rrLine = rr: concatMapStringsSep " " toString ([rr.name rr.ttl rr.class rr.type] ++ rr.data);
+ in
+ ''
+ $ORIGIN ${name}.
+ $TTL ${toString config.defaultTTL}
+ ''
+ + concatLines (map rrLine config.rr);
+
+ rr = mkMerge [
+ (mkOrder 0 (singleton {
+ inherit (config.soa) ttl;
+
+ name = "${name}.";
+ type = "SOA";
+
+ data = with config.soa; [
+ primary
+ hostmaster
+ (throwIf (serial == null) "No serial defined for zone ${name}" serial)
+ refresh
+ retry
+ expire
+ negativeTTL
+ ];
+ }))
+
+ (mkOrder 1 (rrConfig {
+ rrs = config.ns;
+ type = "NS";
+ format = rr: [rr.host];
+ }))
+
+ (rrConfig {
+ rrs = config.a;
+ type = "A";
+ format = rr: [rr.ipv4];
+ })
+
+ (rrConfig {
+ rrs = config.aaaa;
+ type = "AAAA";
+ format = rr: [rr.ipv6];
+ })
+
+ (rrConfig {
+ rrs = config.cname;
+ type = "CNAME";
+ format = rr: [rr.target];
+ })
+
+ (rrConfig {
+ rrs = config.mx;
+ type = "MX";
+ format = rr: [rr.priority rr.host];
+ })
+
+ (rrConfig {
+ rrs = config.ptr;
+ type = "PTR";
+ format = rr: [rr.target];
+ })
+
+ (rrConfig {
+ rrs = config.srv;
+ type = "SRV";
+
+ format = rr: [rr.priority rr.weight rr.port rr.host];
+ applyName = rr: "_${rr.service}._${rr.proto}.${rr.name}";
+ })
+
+ (rrConfig {
+ rrs = config.txt;
+ type = "TXT";
+
+ format = rr: let
+ # nsd-zonecheck: text string is longer than 255 characters, try splitting it into multiple parts
+ txtFragments = text: let
+ max = 255;
+ length = stringLength text;
+ in
+ singleton (substring 0 max text) ++ optionals (length > max) (txtFragments (substring max length text));
+ in
+ map (fragment: "\"${fragment}\"") (txtFragments rr.text);
+ })
+ ];
+ };
+ }));
+ };
+ };
+
+ config = {
+ assertions =
+ [
+ (
+ let
+ badZones = attrNames (filterAttrs (name: zone: (zoneHashCheck name zone).needsUpdate) cfg.zones);
+ in {
+ assertion = badZones == [];
+ message = "Update serials for these zones (null-serial hash mismatch): ${concatStringsSep ", " badZones}";
+ }
+ )
+ ]
+ ++ flatten (mapAttrsToList
+ (name: ptr: [
+ {
+ assertion = ptr.v4.targets != {} -> ptr.v4.zone != null;
+ message = "undefined v4 PTR net '${name}': ${concatStringsSep ", " (attrValues ptr.v4.targets)}";
+ }
+ {
+ assertion = ptr.v6.targets != {} -> ptr.v6.zone != null;
+ message = "undefined v6 PTR net '${name}': ${concatStringsSep ", " (attrValues ptr.v6.targets)}";
+ }
+ ])
+ cfg.ptr);
+
+ lib.local.zoneSerialUpdates = let
+ ptrChecks = filterAttrs (_: check: check.zone.ptrName != null) allZoneChecks;
+ zoneChecks = filterAttrs (_: check: check.zone.ptrName == null) allZoneChecks;
+ allZoneChecks = filterAttrs (_: check: check.needsUpdate) (mapAttrs zoneHashCheck cfg.zones);
+
+ updateInfo = name: check: {
+ inherit name;
+ inherit (check) expected;
+ inherit (check.zone.soa) serial;
+ };
+ in {
+ ptr = mapAttrs (_: check: updateInfo check.zone.ptrName check) ptrChecks;
+ zones = mapAttrs updateInfo zoneChecks;
+ };
+
+ local.ns = {
+ nullSerialZones = let
+ defaultAttrs = ["defaultTTL" "defaultPtr" "ptrName"];
+ filteredAttrs = defaultAttrs ++ map toLower rrTypes;
+ in
+ mapAttrs
+ (_: zone:
+ mkMerge [
+ (filterAttrs (name: _: elem name filteredAttrs) zone)
+ {soa.serial = mkOverride 0 0;}
+ ])
+ cfg.zones;
+
+ ptr = let
+ zonePtrs = zone: let
+ v4Ptrs =
+ map
+ (a: {
+ ${a.ptr}.v4.targets.${nets.${a.ptr}.v4.ptrRecordName a.ipv4 32} = a.name;
+ })
+ (filter (a: a.ptr != null) zone.a);
+
+ v6Ptrs =
+ map
+ (aaaa: {
+ ${aaaa.ptr}.v6.targets.${nets.${aaaa.ptr}.v6.ptrRecordName aaaa.ipv6 128} = aaaa.name;
+ })
+ (filter (aaaa: aaaa.ptr != null) zone.aaaa);
+ in
+ v4Ptrs ++ v6Ptrs;
+ in
+ mkMerge (flatten (mapAttrsToList (_: zonePtrs) cfg.zones));
+ };
+ };
+}
diff --git a/sys/ns/zones/README.md b/sys/ns/zones/README.md
new file mode 100644
index 0000000..37073ba
--- /dev/null
+++ b/sys/ns/zones/README.md
@@ -0,0 +1 @@
+# This directory has been lustrated.
diff --git a/sys/nspawn/default.nix b/sys/nspawn/default.nix
new file mode 100644
index 0000000..15e60de
--- /dev/null
+++ b/sys/nspawn/default.nix
@@ -0,0 +1,5 @@
+{
+ imports = [
+ ./dmz.nix
+ ];
+}
diff --git a/sys/nspawn/dmz.nix b/sys/nspawn/dmz.nix
new file mode 100644
index 0000000..3263730
--- /dev/null
+++ b/sys/nspawn/dmz.nix
@@ -0,0 +1,229 @@
+{
+ config,
+ lib,
+ pkgs,
+ flakes,
+ doctrine,
+ ...
+}:
+with lib; let
+ cfg = config.local.nspawn.dmz;
+ inherit (config.local) mailHost;
+
+ dmzNet = config.local.nets.${cfg.netName};
+
+ hassPort = config.services.home-assistant.config.http.server_port;
+ hassEnable = config.local.home-assistant.enable;
+in {
+ options.local.nspawn.dmz = {
+ enable = mkEnableOption "DMZ services in a container";
+
+ dns64 = mkOption {
+ type = types.str;
+ };
+
+ netName = mkOption {
+ type = types.str;
+ };
+
+ net6 = mkOption {
+ type = types.str;
+ readOnly = true;
+ };
+
+ hostAddr6 = mkOption {
+ type = types.str;
+ readOnly = true;
+ };
+
+ system = mkOption {
+ type = types.raw;
+ };
+ };
+
+ # Situación con os-release
+ #
+ # La idea aquí es poder hacer 'btrfs subvol create /var/lib/machines/foo' y
+ # dejar que systemd-nspawn y el activation script creen todo lo demás. Esto
+ # no sirve bien debido a la prueba barata que hace systemd para revisar si el
+ # árbol parece contener una imagen de sistema operativo. Esta prueba falla en
+ # dos momentos distintos:
+ #
+ # 1. Inmediatamente tras crear un árbol vacío, puesto que os-release no existe.
+ # La solución naive es 'mkdir rootfs/etc && touch rootfs/etc/os-release'.
+ #
+ # 2. Luego de reiniciar el contenedor una vez que NixOS ha preparado /etc, ya que
+ # systemd espera un archivo regular y no telera el symlink a la store.
+ #
+ # Resulta ser que systemd revisa tanto /etc/os-release como /usr/lib/os-release.
+ # NixOS evidentemente no usa la segunda ruta por ser FHS, así que la duct tape
+ # final es 'mkdir rootfs/usr/lib && touch rootfs/usr/lib/os-release'.
+
+ config = mkIf cfg.enable {
+ local = {
+ mailHost.mdaListen = cfg.hostAddr6;
+
+ nspawn.dmz = {
+ hostAddr6 = dmzNet.hosts.gateway.v6.address;
+
+ system = let
+ containerModule = {...}: {
+ #TODO: urgente: bloquear puertos de dovecot a non-postfix con iptables
+ config = {
+ local = {
+ preset.dmz = {
+ enable = true;
+ container = true;
+ };
+
+ mta = {
+ mdaAddr = "[${mailHost.mdaListen}]";
+ inherit (mailHost) saslPort lmtpPort;
+ };
+
+ web.sites = {
+ home = {
+ enable = hassEnable;
+ proxyUrl = "http://[${cfg.hostAddr6}]:${toString hassPort}";
+ };
+ };
+ };
+
+ nixpkgs = {
+ pkgs = mkDefault pkgs;
+ localSystem = mkDefault pkgs.stdenv.hostPlatform;
+ };
+
+ services.nginx.virtualHosts = {
+ "${config.local.domains.imap.main}".locations."^~ /.well-known/acme-challenge/" = {
+ root = "/var/lib/acme/acme-challenge";
+
+ extraConfig = ''
+ auth_basic off;
+ auth_request off;
+ '';
+ };
+ };
+
+ systemd.network.networks."40-host0" = {
+ name = "host0";
+
+ networkConfig = {
+ DNS = [cfg.dns64];
+
+ DHCP = "no";
+ IPv6AcceptRA = "yes";
+ LinkLocalAddressing = "ipv6";
+ };
+
+ ipv6AcceptRAConfig = {
+ Token = [
+ "static:::${dmzNet.hosts.dmz.v6.suffix}"
+ "eui64"
+ "static:::${dmzNet.hosts.mta.v6.suffix}"
+ "static:::${dmzNet.hosts.web.v6.suffix}"
+ ];
+
+ UseDNS = false;
+ };
+ };
+ };
+ };
+ in
+ flakes.trivionomicon.lib.mkSystem {
+ inherit doctrine flakes pkgs;
+
+ modules = [
+ ../.
+ containerModule
+ ];
+ };
+ };
+ };
+
+ services = {
+ home-assistant.config.http = mkIf hassEnable {
+ server_host = [cfg.hostAddr6];
+ trusted_proxies = [dmzNet.hosts.web.v6.address];
+ use_x_forwarded_for = true;
+ };
+ };
+
+ systemd = {
+ nspawn.dmz = {
+ execConfig.PrivateUsers = "pick";
+
+ filesConfig.BindReadOnly = [
+ # idmap porque algunos hacks en nixpkgs (postfix-setup.service)
+ # asumen que la store es de root
+ "/nix/store:/nix/store:idmap"
+ "${cfg.system.config.system.build.toplevel}/init:/sbin/init"
+ ];
+ };
+
+ network.networks."40-ve-dmz" = {
+ matchConfig = {
+ Name = "ve-dmz";
+ Driver = "veth";
+ };
+
+ addresses = [
+ {
+ Address = dmzNet.hosts.gateway.v6.cidr;
+ AddPrefixRoute = "no";
+ PreferredLifetime = 0;
+ }
+ ];
+
+ networkConfig = {
+ LinkLocalAddressing = "ipv6";
+ DHCPServer = "no";
+ IPMasquerade = "no";
+ LLDP = "no";
+ EmitLLDP = "no";
+ IPv6SendRA = "yes";
+ IPv6AcceptRA = "no";
+ };
+
+ ipv6Prefixes = [
+ {
+ Assign = "no";
+ Prefix = dmzNet.v6.cidr;
+ }
+ ];
+
+ routes = [
+ {
+ Destination = dmzNet.v6.cidr;
+ # Sin esto, siempre se escogerá una ULA como source address debido a "PreferredLifetime = 0" en la GUA
+ PreferredSource = dmzNet.hosts.gateway.v6.address;
+ }
+ ];
+ };
+
+ services = {
+ dovecot2.after = ["systemd-nspawn@dmz.service"];
+
+ "systemd-nspawn@dmz" = {
+ overrideStrategy = "asDropin";
+
+ after = ["network-online.target"];
+ wants = ["network-online.target"];
+ wantedBy = ["machines.target"];
+ };
+ };
+ };
+
+ networking.firewall = {
+ allowedTCPPorts = [25 80 443];
+
+ interfaces.ve-dmz = {
+ allowedTCPPorts =
+ [mailHost.saslPort mailHost.lmtpPort]
+ ++ optional hassEnable hassPort;
+
+ allowedUDPPorts = [67]; # DHCP
+ };
+ };
+ };
+}
diff --git a/sys/platform/README.md b/sys/platform/README.md
new file mode 100644
index 0000000..37073ba
--- /dev/null
+++ b/sys/platform/README.md
@@ -0,0 +1 @@
+# This directory has been lustrated.
diff --git a/sys/preset/default.nix b/sys/preset/default.nix
new file mode 100644
index 0000000..45ae529
--- /dev/null
+++ b/sys/preset/default.nix
@@ -0,0 +1,6 @@
+{
+ imports = [
+ ./dmz.nix
+ ./user.nix
+ ];
+}
diff --git a/sys/preset/dmz.nix b/sys/preset/dmz.nix
new file mode 100644
index 0000000..5a04c1e
--- /dev/null
+++ b/sys/preset/dmz.nix
@@ -0,0 +1,64 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.preset.dmz;
+in {
+ options.local.preset.dmz = {
+ enable = mkEnableOption "dmz preset";
+
+ container = mkOption {
+ type = types.bool;
+ default = false;
+ };
+ };
+
+ config = lib.mkIf cfg.enable {
+ local = {
+ boot = {
+ kernel = mkDefault pkgs.linuxPackages_hardened;
+ loader = mkDefault "grub";
+
+ efi.enable = mkDefault (!cfg.container);
+ firmware.mode = mkDefault "none";
+ namespaced.enable = cfg.container;
+
+ stack.luksExt4FscryptImpermanence = {
+ enable = mkDefault (!cfg.container);
+ };
+ };
+
+ jobs.pkiExpiry.enable = mkDefault config.local.mta.enable;
+
+ mta = {
+ enable = mkDefault true;
+
+ mode = "primary";
+ };
+
+ net = {
+ enable = true;
+ hostname = "dmz";
+
+ fail2ban.enable = true;
+ };
+
+ web.sites.portal.enable = true;
+ };
+
+ services = {
+ resolved = {
+ llmnr = "false";
+ fallbackDns = []; # Disable the default systemd-resolved server list
+ };
+ };
+
+ users = {
+ allowNoPasswordLogin = cfg.container;
+ mutableUsers = false;
+ };
+ };
+}
diff --git a/sys/preset/user.nix b/sys/preset/user.nix
new file mode 100644
index 0000000..fd9c5ff
--- /dev/null
+++ b/sys/preset/user.nix
@@ -0,0 +1,73 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}: let
+ inherit (lib) mkDefault;
+ cfg = config.local.preset.user;
+in {
+ options.local.preset.user = {
+ enable = lib.mkEnableOption "user-like preset";
+ };
+
+ config = lib.mkIf cfg.enable {
+ local = {
+ installUsers = mkDefault "single";
+
+ auth = {
+ oath.enable = mkDefault true;
+
+ openssh = {
+ enable = mkDefault true;
+
+ hostKeys = {
+ rsa = mkDefault true;
+ ecdsa = mkDefault true;
+ ed25519 = mkDefault true;
+ };
+ };
+ };
+
+ boot = {
+ kernel = mkDefault pkgs.linuxPackages_latest;
+ loader = mkDefault "grub";
+
+ efi = {
+ enable = mkDefault true;
+ removable = mkDefault false;
+ };
+
+ firmware.mode = mkDefault "redistributable";
+ detachedLuks.enable = mkDefault true;
+
+ stack.btrfsToplevelMultidrive = {
+ enable = mkDefault true;
+
+ toplevel.root = mkDefault "/root";
+ secondary.home = mkDefault "/home";
+ };
+ };
+
+ hardware = {
+ yubico.enable = mkDefault true;
+ bluetooth.enable = mkDefault true;
+ };
+
+ net.enable = true;
+
+ seat = {
+ enable = true;
+ graphical = mkDefault true;
+ };
+ };
+
+ services.nullmailer = {
+ enable = mkDefault true;
+
+ config = {
+ me = "${config.networking.hostName}@${config.networking.domain}";
+ };
+ };
+ };
+}
diff --git a/sys/seat/default.nix b/sys/seat/default.nix
new file mode 100644
index 0000000..402047f
--- /dev/null
+++ b/sys/seat/default.nix
@@ -0,0 +1,142 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.seat;
+
+ users = filterAttrs (_: user: user.install) config.local.users;
+in {
+ options.local.seat = {
+ enable = mkEnableOption "user seat";
+
+ graphical = mkOption {
+ type = types.bool;
+ default = false;
+ };
+
+ wayland = mkOption {
+ type = types.bool;
+ default = true;
+ };
+
+ videoDrivers = mkOption {
+ type = with types; listOf str;
+ };
+ };
+
+ config =
+ mkIf cfg.enable
+ (mkMerge [
+ {
+ hardware = {
+ acpilight.enable = true;
+ };
+
+ security.rtkit.enable = true;
+
+ services = {
+ pipewire = {
+ enable = true;
+
+ alsa = {
+ enable = true;
+ support32Bit = true;
+ };
+
+ jack.enable = true;
+ pulse.enable = true;
+ wireplumber.enable = true;
+ };
+
+ pulseaudio.enable = false;
+ };
+
+ users = {
+ groups =
+ mapAttrs (_: user: {inherit (user) gid;}) users
+ // {
+ adbusers.gid = 1008;
+ };
+
+ users =
+ mapAttrs
+ (username: user: {
+ isNormalUser = true;
+
+ inherit (user) uid;
+ description = user.gecos;
+
+ group = username;
+ extraGroups = ["users"] ++ user.groups;
+
+ shell =
+ if user.allowLogin
+ then pkgs.zsh
+ else null;
+ })
+ users;
+ };
+ }
+ (mkIf cfg.graphical {
+ environment = {
+ sessionVariables.NIXOS_OZONE_WL = "1";
+
+ systemPackages = with pkgs; [
+ qt5.qtwayland
+ qt6.qtwayland
+ ];
+ };
+
+ hardware.graphics.enable = true;
+
+ programs = {
+ dconf.enable = true;
+
+ gtklock = {
+ enable = true;
+
+ config = {};
+ modules = [];
+ };
+ };
+
+ services = {
+ libinput.enable = true;
+
+ udev.packages = with pkgs; [
+ pkgs.android-udev-rules
+ ];
+
+ xserver = mkIf (!cfg.wayland) {
+ enable = true;
+ videoDrivers = cfg.videoDrivers ++ ["modesetting" "fbdev"];
+ displayManager.startx.enable = mkDefault true;
+ };
+ };
+
+ xdg.portal = {
+ enable = true;
+ wlr.enable = true;
+ extraPortals = [pkgs.xdg-desktop-portal-gtk];
+ xdgOpenUsePortal = true;
+
+ # warning: xdg-desktop-portal 1.17 reworked how portal implementations are loaded, you
+ # should either set `xdg.portal.config` or `xdg.portal.configPackages`
+ # to specify which portal backend to use for the requested interface.
+ #
+ # https://github.com/flatpak/xdg-desktop-portal/blob/1.18.1/doc/portals.conf.rst.in
+ #
+ # If you simply want to keep the behaviour in < 1.17, which uses the first
+ # portal implementation found in lexicographical order, use the following:
+ #
+ # xdg.portal.config.common.default = "*";
+ config.common.default = "*";
+ };
+
+ users.groups.adbusers.gid = 1008;
+ })
+ ]);
+}
diff --git a/sys/syncthing/default.nix b/sys/syncthing/default.nix
new file mode 100644
index 0000000..951ad30
--- /dev/null
+++ b/sys/syncthing/default.nix
@@ -0,0 +1,45 @@
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ cfg = config.local.syncthing;
+in {
+ options.local.syncthing = {
+ enable = mkEnableOption "syncthing server";
+ openFirewall = mkEnableOption "syncthing firewall rules";
+ };
+
+ config = mkMerge [
+ {
+ networking.firewall = {
+ allowedTCPPorts = optional cfg.openFirewall 22000;
+ allowedUDPPorts = optional cfg.openFirewall 22000;
+ };
+ }
+ (mkIf cfg.enable {
+ local.syncthing.openFirewall = true;
+
+ services.syncthing = {
+ enable = true;
+
+ systemService = true;
+ overrideFolders = false;
+ overrideDevices = false;
+ openDefaultPorts = true;
+
+ guiAddress = "127.0.0.1:8384";
+
+ settings.options.urAccepted = -1;
+
+ relay = {
+ enable = true;
+
+ pools = [];
+ providedBy = "${config.networking.hostName}.${config.networking.domain}";
+ };
+ };
+ })
+ ];
+}
diff --git a/sys/virt/default.nix b/sys/virt/default.nix
new file mode 100644
index 0000000..1434bad
--- /dev/null
+++ b/sys/virt/default.nix
@@ -0,0 +1,5 @@
+{
+ imports = [
+ ./libvirt.nix
+ ];
+}
diff --git a/sys/virt/dom/README.md b/sys/virt/dom/README.md
new file mode 100644
index 0000000..37073ba
--- /dev/null
+++ b/sys/virt/dom/README.md
@@ -0,0 +1 @@
+# This directory has been lustrated.
diff --git a/sys/virt/libvirt.nix b/sys/virt/libvirt.nix
new file mode 100644
index 0000000..ebbfbcd
--- /dev/null
+++ b/sys/virt/libvirt.nix
@@ -0,0 +1,64 @@
+{
+ config,
+ flakes,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.virt;
+
+ inherit (config.lib.local) importAll;
+
+ doms = mapAttrs (_: dom: dom {inherit config lib pkgs;}) (importAll {root = ./dom;});
+in {
+ options.local.virt = {
+ enable = mkEnableOption "hypervisor support";
+
+ dom =
+ mapAttrs
+ (name: _: {
+ enable = mkEnableOption "domain ${name}";
+ })
+ doms;
+ };
+
+ config = mkIf cfg.enable {
+ local.boot.impermanence.directories = [
+ {
+ directory = "/var/dom";
+ user = "root";
+ group = "qemu-libvirtd";
+ mode = "u=rwx,g=rx,o=";
+ }
+ ];
+
+ virtualisation = {
+ libvirt = {
+ enable = any (dom: dom.enable) (attrValues cfg.dom);
+
+ connections."qemu:///system".domains = let
+ makeDomain = def: {
+ active = true;
+ restart = false;
+ definition = flakes.nixvirt.lib.domain.writeXML def;
+ };
+ in
+ map makeDomain (attrValues (filterAttrs (name: _: cfg.dom.${name}.enable) doms));
+
+ swtpm.enable = true;
+ };
+
+ libvirtd = {
+ enable = true;
+
+ qemu = {
+ runAsRoot = false;
+
+ ovmf.enable = true;
+ swtpm.enable = true;
+ };
+ };
+ };
+ };
+}
diff --git a/sys/web/default.nix b/sys/web/default.nix
new file mode 100644
index 0000000..2fc769f
--- /dev/null
+++ b/sys/web/default.nix
@@ -0,0 +1,7 @@
+{
+ imports = [
+ ./nginx.nix
+ ./php-fpm.nix
+ ./sites
+ ];
+}
diff --git a/sys/web/nginx.nix b/sys/web/nginx.nix
new file mode 100644
index 0000000..a054289
--- /dev/null
+++ b/sys/web/nginx.nix
@@ -0,0 +1,94 @@
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ cfg = config.local.web;
+ inherit (config.local) domains;
+in {
+ options.local.web = {
+ enable = mkEnableOption "web server";
+
+ defaultACMEHost = mkOption {
+ type = types.str;
+ };
+
+ ownedCerts = mkOption {
+ type = with lib.types; listOf str;
+ default = [];
+ };
+ };
+
+ config = mkIf cfg.enable {
+ services = {
+ fail2ban.jails = {
+ # https://discourse.nixos.org/t/fail2ban-with-nginx-and-authelia/31419
+ nginx-botsearch.settings = {
+ # Usar log en vez de journalctl
+ # TODO: Pasar todo a systemd?
+ backend = "pyinotify";
+ logpath = "/var/log/nginx/*.log";
+ journalmatch = "";
+ };
+
+ nginx-bad-request.settings = {
+ backend = "pyinotify";
+ logpath = "/var/log/nginx/*.log";
+ journalmatch = "";
+
+ maxretry = 10;
+ };
+ };
+
+ nginx = {
+ enable = true;
+
+ recommendedGzipSettings = true;
+ recommendedOptimisation = true;
+ recommendedProxySettings = true;
+ recommendedTlsSettings = true;
+
+ logError = "/var/log/nginx/error.log";
+ sslDhparam = config.security.dhparams.params.nginx.path;
+ clientMaxBodySize = "42M";
+
+ mapHashBucketSize = 128;
+
+ virtualHosts.default = {
+ default = true;
+
+ addSSL = true;
+ useACMEHost = cfg.defaultACMEHost;
+
+ locations."/".extraConfig = ''
+ return 403;
+ '';
+ };
+ };
+ };
+
+ local.certs = listToAttrs (map
+ (name: {
+ inherit name;
+ value.enable = true;
+ })
+ cfg.ownedCerts);
+
+ networking.firewall.allowedTCPPorts = [80 443];
+
+ security = {
+ acme.certs = listToAttrs (map
+ (name: {
+ name = domains.${name}.main;
+ value = {
+ group = mkDefault config.services.nginx.group;
+ reloadServices = ["nginx.service"];
+ };
+ })
+ cfg.ownedCerts);
+
+ dhparams.params.nginx = {};
+ };
+ };
+}
diff --git a/sys/web/php-fpm.nix b/sys/web/php-fpm.nix
new file mode 100644
index 0000000..33efe1a
--- /dev/null
+++ b/sys/web/php-fpm.nix
@@ -0,0 +1,154 @@
+# Based on <https://gist.github.com/aanderse/3344baef2c3b86c8a1e98e63bd9256ea>
+# See also:
+# - <https://albert.cx/20181125-use-separate-systemd-units-for-php-fpm-pools>
+# - <https://freedesktop.org/wiki/Software/systemd/DaemonSocketActivation/>
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.services.php-fpm-isolated;
+
+ configFile = {
+ pool,
+ poolOpts,
+ runtimeDir,
+ sockFile,
+ pidFile,
+ }: let
+ config = {
+ global = {
+ daemonize = false;
+ error_log = "syslog";
+ pid = pidFile;
+ };
+
+ "${pool}" = let
+ enforced = {
+ inherit (poolOpts) user group;
+ listen = sockFile;
+ };
+
+ defaults = {
+ "pm" = "dynamic";
+ "pm.max_children" = 16;
+ "pm.min_spare_servers" = 1;
+ "pm.max_spare_servers" = 4;
+ "pm.start_servers" = 1;
+ "catch_workers_output" = true;
+ "php_admin_flag[log_errors]" = true;
+ "env[PATH]" = makeBinPath [pkgs.php];
+ };
+
+ env =
+ mapAttrs'
+ (name: value: {
+ name = "env[${name}]";
+ value = "\"${escape ["\""] value}\"";
+ })
+ poolOpts.env;
+ in
+ defaults // poolOpts.config // env // enforced;
+ };
+ in
+ (pkgs.formats.ini {}).generate "php-fpm-pool-${pool}.conf" config;
+in {
+ options.services.php-fpm-isolated.pools = mkOption {
+ default = {};
+
+ type = with types;
+ attrsOf (submodule {
+ options = {
+ enable = mkEnableOption "PHP-FPM pool";
+
+ user = mkOption {
+ type = str;
+ };
+
+ group = mkOption {
+ type = str;
+ };
+
+ unveil = mkOption {
+ type = listOf (either package str);
+ };
+
+ env = mkOption {
+ type = attrsOf str;
+ default = {};
+ };
+
+ config = mkOption {
+ type = attrsOf (oneOf [int str bool]);
+ default = {};
+ };
+ };
+ });
+ };
+
+ config.systemd = let
+ php-fpm = "${pkgs.php}/bin/php-fpm";
+
+ unitsFor = pool: poolOpts: let
+ runtimeBase = "php-fpm-isolated/${pool}";
+ runtimeDir = "/run/${runtimeBase}";
+ pidFile = "${runtimeDir}/${pool}.pid";
+ sockFile = "${runtimeDir}/${pool}.sock";
+ in {
+ name = "php-fpm-pool-${pool}";
+
+ value.service = {
+ description = "PHP-FPM process manager for pool '${pool}'";
+ after = ["network.target"];
+
+ confinement.enable = true;
+
+ serviceConfig = {
+ Type = "notify";
+ ExecReload = "${pkgs.coreutils}/bin/kill -USR2 $MAINPID";
+ PIDFile = pidFile;
+
+ Environment = "FPM_SOCKETS=${sockFile}=3";
+
+ ExecStart = let
+ fpmConfig = configFile {
+ inherit pool poolOpts runtimeDir sockFile pidFile;
+ };
+ in "${php-fpm} --nodaemonize --fpm-config ${fpmConfig} --pid ${pidFile}";
+
+ PrivateTmp = true;
+ PrivateNetwork = true;
+ PrivateDevices = true;
+ # XXX: We need AF_NETLINK to make the sendmail SUID binary from postfix work
+ RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6 AF_NETLINK";
+
+ User = poolOpts.user;
+ Group = poolOpts.group;
+ RuntimeDirectory = runtimeBase;
+
+ BindReadOnlyPaths = let
+ unveiled = map builtins.toString poolOpts.unveil;
+ in
+ ["/run/systemd/journal/socket"] ++ unveiled;
+ };
+ };
+
+ value.socket = {
+ description = "PHP-FPM socket for pool '${pool}'";
+ listenStreams = [sockFile];
+
+ socketConfig = {
+ User = poolOpts.user;
+ Group = poolOpts.group;
+ };
+ };
+ };
+
+ units = mapAttrs' unitsFor (filterAttrs (_: pool: pool.enable) cfg.pools);
+ in {
+ sockets = mapAttrs (_: unit: unit.socket) units;
+ services = mapAttrs (_: unit: unit.service) units;
+ };
+}
diff --git a/sys/web/sites/default.nix b/sys/web/sites/default.nix
new file mode 100644
index 0000000..ba2835c
--- /dev/null
+++ b/sys/web/sites/default.nix
@@ -0,0 +1,7 @@
+{
+ imports = [
+ ./home.nix
+ ./host.nix
+ ./portal.nix
+ ];
+}
diff --git a/sys/web/sites/home.nix b/sys/web/sites/home.nix
new file mode 100644
index 0000000..fed9b84
--- /dev/null
+++ b/sys/web/sites/home.nix
@@ -0,0 +1,38 @@
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ cfg = config.local.web.sites.home;
+ inherit (config.local) domains;
+in {
+ options.local.web.sites.home = {
+ enable = mkEnableOption "home site";
+
+ proxyUrl = mkOption {
+ type = types.str;
+ };
+ };
+
+ config = mkIf cfg.enable {
+ local.web = {
+ enable = mkDefault true;
+ ownedCerts = ["home"];
+ };
+
+ services.nginx.virtualHosts.${domains.home.main} = {
+ forceSSL = true;
+ useACMEHost = domains.home.main;
+
+ locations."/".extraConfig = ''
+ proxy_pass ${cfg.proxyUrl};
+ proxy_redirect http:// https://;
+
+ # Necesario debido a websockets
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection $connection_upgrade;
+ '';
+ };
+ };
+}
diff --git a/sys/web/sites/host.nix b/sys/web/sites/host.nix
new file mode 100644
index 0000000..ea6cc23
--- /dev/null
+++ b/sys/web/sites/host.nix
@@ -0,0 +1,106 @@
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ cfg = config.local.web.sites.host;
+
+ inherit (config.local) domains;
+ inherit (config.local.net) hostname;
+
+ users = filterAttrs (_: user: user.install) config.local.users;
+ hostDomain = domains.${hostDomainName};
+ hostDomainName = "host-${hostname}";
+
+ userCerts = flatten (flatten (mapAttrsToList
+ (name: user:
+ map
+ (cert: {
+ fprint = config.local.pki.byPath.${cert}.fingerprint.sha1-lower;
+ inherit name;
+ })
+ user.mail.certs)
+ users));
+in {
+ options.local.web.sites.host = {
+ enable = mkEnableOption "host site, restricted to per-user client certs";
+ };
+
+ config = mkIf cfg.enable {
+ local.web = {
+ enable = mkDefault true;
+ ownedCerts = [hostDomainName];
+ };
+
+ services = {
+ nginx = {
+ appendHttpConfig = ''
+ map $ssl_client_fingerprint $host_user_from_fprint {
+ default "";
+ ${concatMapStringsSep "\n " (pair: "\"${escapeRegex pair.fprint}\" \"${pair.name}\";") userCerts}
+ }
+ '';
+
+ virtualHosts = {
+ ${hostDomain.main} = {
+ forceSSL = true;
+ useACMEHost = hostDomain.main;
+
+ extraConfig = ''
+ ssl_verify_depth 2;
+ ssl_verify_client optional;
+ ssl_client_certificate ${config.local.pki.ca.mail.fullchain};
+
+ #if ($ssl_client_verify != "SUCCESS") {
+ #return 403;
+ #}
+ '';
+
+ locations =
+ {
+ "/".return = 403;
+ }
+ // concatMapAttrs
+ (name: user: let
+ userLocation = config: {
+ extraConfig =
+ ''
+ if ($host_user_from_fprint != "${name}") {
+ return 403;
+ }
+ ''
+ + config;
+ };
+
+ userLocations =
+ {
+ "/${name}" = ''
+ return 404;
+ '';
+ }
+ // optionalAttrs user.mail.dav {
+ "/${name}/dav" = ''
+ proxy_pass http://unix:/run/host-www/${name}/dav.sock;
+ '';
+ };
+ in
+ mapAttrs (_: userLocation) userLocations)
+ (filterAttrs (_: user: user.mail.certs != []) users);
+ };
+ };
+ };
+ };
+
+ systemd.tmpfiles.settings."10-run-host-www" =
+ concatMapAttrs
+ (name: _: {
+ "/run/host-www/${name}".d = {
+ mode = "0750";
+ user = name;
+ group = "nginx";
+ };
+ })
+ users;
+ };
+}
diff --git a/sys/web/sites/portal.nix b/sys/web/sites/portal.nix
new file mode 100644
index 0000000..c4d948e
--- /dev/null
+++ b/sys/web/sites/portal.nix
@@ -0,0 +1,42 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.web.sites.portal;
+ inherit (config.local) domains;
+in {
+ options.local.web.sites.portal = {
+ enable = mkEnableOption "public non-fqdn portal";
+ };
+
+ config = mkIf cfg.enable {
+ local.web = {
+ enable = mkDefault true;
+ ownedCerts = ["host" "sysret"];
+ defaultACMEHost = domains.host.main;
+ };
+
+ services.nginx.virtualHosts = {
+ ${domains.host.www} = {
+ forceSSL = true;
+ useACMEHost = domains.host.main;
+ serverAliases = [domains.host.main];
+ };
+
+ ${domains.sysret.main} = {
+ forceSSL = true;
+ useACMEHost = domains.sysret.main;
+ serverAliases = [domains.sysret.www];
+
+ locations = {
+ "/".alias = "${pkgs.local.sysret-static}/";
+ "/fsociety".return = "301 https://meet.posixlycorrect.com/%C6%92%C6%A8%C5%8F%C4%8B%D3%80%C9%99%CF%AE%D0%A3";
+ "/.well-known/openpgpkey/hu/".alias = "/var/lib/pgp-wkd/";
+ };
+ };
+ };
+ };
+}
diff --git a/sysret.org/.gitignore b/sysret.org/.gitignore
new file mode 100644
index 0000000..46f5006
--- /dev/null
+++ b/sysret.org/.gitignore
@@ -0,0 +1 @@
+public/*
diff --git a/README.updating.txt b/sysret.org/README.updating.txt
index 390d7ba..390d7ba 100644
--- a/README.updating.txt
+++ b/sysret.org/README.updating.txt
diff --git a/config.toml b/sysret.org/config.toml
index 92cb280..92cb280 100644
--- a/config.toml
+++ b/sysret.org/config.toml
diff --git a/themes/tabi-lean/.gitignore b/sysret.org/themes/tabi-lean/.gitignore
index d70ebaa..d70ebaa 100644
--- a/themes/tabi-lean/.gitignore
+++ b/sysret.org/themes/tabi-lean/.gitignore
diff --git a/themes/tabi-lean/LICENSE b/sysret.org/themes/tabi-lean/LICENSE
index b09859c..b09859c 100644
--- a/themes/tabi-lean/LICENSE
+++ b/sysret.org/themes/tabi-lean/LICENSE
diff --git a/themes/tabi-lean/config.toml b/sysret.org/themes/tabi-lean/config.toml
index a54f0f4..a54f0f4 100644
--- a/themes/tabi-lean/config.toml
+++ b/sysret.org/themes/tabi-lean/config.toml
diff --git a/themes/tabi-lean/i18n/ar.toml b/sysret.org/themes/tabi-lean/i18n/ar.toml
index eccaa7c..eccaa7c 100644
--- a/themes/tabi-lean/i18n/ar.toml
+++ b/sysret.org/themes/tabi-lean/i18n/ar.toml
diff --git a/themes/tabi-lean/i18n/ca.toml b/sysret.org/themes/tabi-lean/i18n/ca.toml
index 0191c24..0191c24 100644
--- a/themes/tabi-lean/i18n/ca.toml
+++ b/sysret.org/themes/tabi-lean/i18n/ca.toml
diff --git a/themes/tabi-lean/i18n/de.toml b/sysret.org/themes/tabi-lean/i18n/de.toml
index 7255f9d..7255f9d 100644
--- a/themes/tabi-lean/i18n/de.toml
+++ b/sysret.org/themes/tabi-lean/i18n/de.toml
diff --git a/themes/tabi-lean/i18n/en.toml b/sysret.org/themes/tabi-lean/i18n/en.toml
index 4184298..4184298 100644
--- a/themes/tabi-lean/i18n/en.toml
+++ b/sysret.org/themes/tabi-lean/i18n/en.toml
diff --git a/themes/tabi-lean/i18n/es.toml b/sysret.org/themes/tabi-lean/i18n/es.toml
index a39478b..a39478b 100644
--- a/themes/tabi-lean/i18n/es.toml
+++ b/sysret.org/themes/tabi-lean/i18n/es.toml
diff --git a/themes/tabi-lean/i18n/et.toml b/sysret.org/themes/tabi-lean/i18n/et.toml
index 7f71604..7f71604 100644
--- a/themes/tabi-lean/i18n/et.toml
+++ b/sysret.org/themes/tabi-lean/i18n/et.toml
diff --git a/themes/tabi-lean/i18n/fa.toml b/sysret.org/themes/tabi-lean/i18n/fa.toml
index b609409..b609409 100644
--- a/themes/tabi-lean/i18n/fa.toml
+++ b/sysret.org/themes/tabi-lean/i18n/fa.toml
diff --git a/themes/tabi-lean/i18n/fi.toml b/sysret.org/themes/tabi-lean/i18n/fi.toml
index bf820e9..bf820e9 100644
--- a/themes/tabi-lean/i18n/fi.toml
+++ b/sysret.org/themes/tabi-lean/i18n/fi.toml
diff --git a/themes/tabi-lean/i18n/fr.toml b/sysret.org/themes/tabi-lean/i18n/fr.toml
index 54c8666..54c8666 100644
--- a/themes/tabi-lean/i18n/fr.toml
+++ b/sysret.org/themes/tabi-lean/i18n/fr.toml
diff --git a/themes/tabi-lean/i18n/hi.toml b/sysret.org/themes/tabi-lean/i18n/hi.toml
index 2ac79ba..2ac79ba 100644
--- a/themes/tabi-lean/i18n/hi.toml
+++ b/sysret.org/themes/tabi-lean/i18n/hi.toml
diff --git a/themes/tabi-lean/i18n/it.toml b/sysret.org/themes/tabi-lean/i18n/it.toml
index 4b558c9..4b558c9 100644
--- a/themes/tabi-lean/i18n/it.toml
+++ b/sysret.org/themes/tabi-lean/i18n/it.toml
diff --git a/themes/tabi-lean/i18n/ja.toml b/sysret.org/themes/tabi-lean/i18n/ja.toml
index c1a7533..c1a7533 100644
--- a/themes/tabi-lean/i18n/ja.toml
+++ b/sysret.org/themes/tabi-lean/i18n/ja.toml
diff --git a/themes/tabi-lean/i18n/ko.toml b/sysret.org/themes/tabi-lean/i18n/ko.toml
index f4e177e..f4e177e 100644
--- a/themes/tabi-lean/i18n/ko.toml
+++ b/sysret.org/themes/tabi-lean/i18n/ko.toml
diff --git a/themes/tabi-lean/i18n/nl.toml b/sysret.org/themes/tabi-lean/i18n/nl.toml
index a300339..a300339 100644
--- a/themes/tabi-lean/i18n/nl.toml
+++ b/sysret.org/themes/tabi-lean/i18n/nl.toml
diff --git a/themes/tabi-lean/i18n/or.toml b/sysret.org/themes/tabi-lean/i18n/or.toml
index e431309..e431309 100644
--- a/themes/tabi-lean/i18n/or.toml
+++ b/sysret.org/themes/tabi-lean/i18n/or.toml
diff --git a/themes/tabi-lean/i18n/pt-PT.toml b/sysret.org/themes/tabi-lean/i18n/pt-PT.toml
index fa79380..fa79380 100644
--- a/themes/tabi-lean/i18n/pt-PT.toml
+++ b/sysret.org/themes/tabi-lean/i18n/pt-PT.toml
diff --git a/themes/tabi-lean/i18n/ru.toml b/sysret.org/themes/tabi-lean/i18n/ru.toml
index 16765e3..16765e3 100644
--- a/themes/tabi-lean/i18n/ru.toml
+++ b/sysret.org/themes/tabi-lean/i18n/ru.toml
diff --git a/themes/tabi-lean/i18n/uk.toml b/sysret.org/themes/tabi-lean/i18n/uk.toml
index d20cb8e..d20cb8e 100644
--- a/themes/tabi-lean/i18n/uk.toml
+++ b/sysret.org/themes/tabi-lean/i18n/uk.toml
diff --git a/themes/tabi-lean/i18n/zh-Hans.toml b/sysret.org/themes/tabi-lean/i18n/zh-Hans.toml
index f4f181b..f4f181b 100644
--- a/themes/tabi-lean/i18n/zh-Hans.toml
+++ b/sysret.org/themes/tabi-lean/i18n/zh-Hans.toml
diff --git a/themes/tabi-lean/i18n/zh-Hant.toml b/sysret.org/themes/tabi-lean/i18n/zh-Hant.toml
index 29d6282..29d6282 100644
--- a/themes/tabi-lean/i18n/zh-Hant.toml
+++ b/sysret.org/themes/tabi-lean/i18n/zh-Hant.toml
diff --git a/themes/tabi-lean/sass/main.scss b/sysret.org/themes/tabi-lean/sass/main.scss
index 6433d2c..6433d2c 100644
--- a/themes/tabi-lean/sass/main.scss
+++ b/sysret.org/themes/tabi-lean/sass/main.scss
diff --git a/themes/tabi-lean/sass/parts/_admonitions.scss b/sysret.org/themes/tabi-lean/sass/parts/_admonitions.scss
index 6feec43..6feec43 100644
--- a/themes/tabi-lean/sass/parts/_admonitions.scss
+++ b/sysret.org/themes/tabi-lean/sass/parts/_admonitions.scss
diff --git a/themes/tabi-lean/sass/parts/_archive.scss b/sysret.org/themes/tabi-lean/sass/parts/_archive.scss
index 6df323b..6df323b 100644
--- a/themes/tabi-lean/sass/parts/_archive.scss
+++ b/sysret.org/themes/tabi-lean/sass/parts/_archive.scss
diff --git a/themes/tabi-lean/sass/parts/_aside.scss b/sysret.org/themes/tabi-lean/sass/parts/_aside.scss
index 4757524..4757524 100644
--- a/themes/tabi-lean/sass/parts/_aside.scss
+++ b/sysret.org/themes/tabi-lean/sass/parts/_aside.scss
diff --git a/themes/tabi-lean/sass/parts/_cards.scss b/sysret.org/themes/tabi-lean/sass/parts/_cards.scss
index 0b6c560..0b6c560 100644
--- a/themes/tabi-lean/sass/parts/_cards.scss
+++ b/sysret.org/themes/tabi-lean/sass/parts/_cards.scss
diff --git a/themes/tabi-lean/sass/parts/_code.scss b/sysret.org/themes/tabi-lean/sass/parts/_code.scss
index 2623f50..2623f50 100644
--- a/themes/tabi-lean/sass/parts/_code.scss
+++ b/sysret.org/themes/tabi-lean/sass/parts/_code.scss
diff --git a/themes/tabi-lean/sass/parts/_comments.scss b/sysret.org/themes/tabi-lean/sass/parts/_comments.scss
index aab54d9..aab54d9 100644
--- a/themes/tabi-lean/sass/parts/_comments.scss
+++ b/sysret.org/themes/tabi-lean/sass/parts/_comments.scss
diff --git a/themes/tabi-lean/sass/parts/_footer.scss b/sysret.org/themes/tabi-lean/sass/parts/_footer.scss
index 2b49c3d..2b49c3d 100644
--- a/themes/tabi-lean/sass/parts/_footer.scss
+++ b/sysret.org/themes/tabi-lean/sass/parts/_footer.scss
diff --git a/themes/tabi-lean/sass/parts/_header-anchor.scss b/sysret.org/themes/tabi-lean/sass/parts/_header-anchor.scss
index 8a06200..8a06200 100644
--- a/themes/tabi-lean/sass/parts/_header-anchor.scss
+++ b/sysret.org/themes/tabi-lean/sass/parts/_header-anchor.scss
diff --git a/themes/tabi-lean/sass/parts/_header.scss b/sysret.org/themes/tabi-lean/sass/parts/_header.scss
index 4640d1b..4640d1b 100644
--- a/themes/tabi-lean/sass/parts/_header.scss
+++ b/sysret.org/themes/tabi-lean/sass/parts/_header.scss
diff --git a/themes/tabi-lean/sass/parts/_home-banner.scss b/sysret.org/themes/tabi-lean/sass/parts/_home-banner.scss
index ce6b9c1..ce6b9c1 100644
--- a/themes/tabi-lean/sass/parts/_home-banner.scss
+++ b/sysret.org/themes/tabi-lean/sass/parts/_home-banner.scss
diff --git a/themes/tabi-lean/sass/parts/_iine.scss b/sysret.org/themes/tabi-lean/sass/parts/_iine.scss
index 9ac95c4..9ac95c4 100644
--- a/themes/tabi-lean/sass/parts/_iine.scss
+++ b/sysret.org/themes/tabi-lean/sass/parts/_iine.scss
diff --git a/themes/tabi-lean/sass/parts/_image-hover.scss b/sysret.org/themes/tabi-lean/sass/parts/_image-hover.scss
index 9f36f23..9f36f23 100644
--- a/themes/tabi-lean/sass/parts/_image-hover.scss
+++ b/sysret.org/themes/tabi-lean/sass/parts/_image-hover.scss
diff --git a/themes/tabi-lean/sass/parts/_image-toggler.scss b/sysret.org/themes/tabi-lean/sass/parts/_image-toggler.scss
index e2f420e..e2f420e 100644
--- a/themes/tabi-lean/sass/parts/_image-toggler.scss
+++ b/sysret.org/themes/tabi-lean/sass/parts/_image-toggler.scss
diff --git a/themes/tabi-lean/sass/parts/_image.scss b/sysret.org/themes/tabi-lean/sass/parts/_image.scss
index e8bae01..e8bae01 100644
--- a/themes/tabi-lean/sass/parts/_image.scss
+++ b/sysret.org/themes/tabi-lean/sass/parts/_image.scss
diff --git a/themes/tabi-lean/sass/parts/_misc.scss b/sysret.org/themes/tabi-lean/sass/parts/_misc.scss
index d798ddd..d798ddd 100644
--- a/themes/tabi-lean/sass/parts/_misc.scss
+++ b/sysret.org/themes/tabi-lean/sass/parts/_misc.scss
diff --git a/themes/tabi-lean/sass/parts/_multilingual_quote.scss b/sysret.org/themes/tabi-lean/sass/parts/_multilingual_quote.scss
index ecd5f1c..ecd5f1c 100644
--- a/themes/tabi-lean/sass/parts/_multilingual_quote.scss
+++ b/sysret.org/themes/tabi-lean/sass/parts/_multilingual_quote.scss
diff --git a/themes/tabi-lean/sass/parts/_pagination.scss b/sysret.org/themes/tabi-lean/sass/parts/_pagination.scss
index 5361b1e..5361b1e 100644
--- a/themes/tabi-lean/sass/parts/_pagination.scss
+++ b/sysret.org/themes/tabi-lean/sass/parts/_pagination.scss
diff --git a/themes/tabi-lean/sass/parts/_posts_list.scss b/sysret.org/themes/tabi-lean/sass/parts/_posts_list.scss
index e74f89c..e74f89c 100644
--- a/themes/tabi-lean/sass/parts/_posts_list.scss
+++ b/sysret.org/themes/tabi-lean/sass/parts/_posts_list.scss
diff --git a/themes/tabi-lean/sass/parts/_quick_navigation_buttons.scss b/sysret.org/themes/tabi-lean/sass/parts/_quick_navigation_buttons.scss
index 768592f..768592f 100644
--- a/themes/tabi-lean/sass/parts/_quick_navigation_buttons.scss
+++ b/sysret.org/themes/tabi-lean/sass/parts/_quick_navigation_buttons.scss
diff --git a/themes/tabi-lean/sass/parts/_search.scss b/sysret.org/themes/tabi-lean/sass/parts/_search.scss
index df820e4..df820e4 100644
--- a/themes/tabi-lean/sass/parts/_search.scss
+++ b/sysret.org/themes/tabi-lean/sass/parts/_search.scss
diff --git a/themes/tabi-lean/sass/parts/_spoiler.scss b/sysret.org/themes/tabi-lean/sass/parts/_spoiler.scss
index b43911b..b43911b 100644
--- a/themes/tabi-lean/sass/parts/_spoiler.scss
+++ b/sysret.org/themes/tabi-lean/sass/parts/_spoiler.scss
diff --git a/themes/tabi-lean/sass/parts/_syntax_theme.scss b/sysret.org/themes/tabi-lean/sass/parts/_syntax_theme.scss
index ece3930..ece3930 100644
--- a/themes/tabi-lean/sass/parts/_syntax_theme.scss
+++ b/sysret.org/themes/tabi-lean/sass/parts/_syntax_theme.scss
diff --git a/themes/tabi-lean/sass/parts/_table.scss b/sysret.org/themes/tabi-lean/sass/parts/_table.scss
index d6e5326..d6e5326 100644
--- a/themes/tabi-lean/sass/parts/_table.scss
+++ b/sysret.org/themes/tabi-lean/sass/parts/_table.scss
diff --git a/themes/tabi-lean/sass/parts/_tags.scss b/sysret.org/themes/tabi-lean/sass/parts/_tags.scss
index ae28d0a..ae28d0a 100644
--- a/themes/tabi-lean/sass/parts/_tags.scss
+++ b/sysret.org/themes/tabi-lean/sass/parts/_tags.scss
diff --git a/themes/tabi-lean/sass/parts/_theme-switch.scss b/sysret.org/themes/tabi-lean/sass/parts/_theme-switch.scss
index 9c5bd4f..9c5bd4f 100644
--- a/themes/tabi-lean/sass/parts/_theme-switch.scss
+++ b/sysret.org/themes/tabi-lean/sass/parts/_theme-switch.scss
diff --git a/themes/tabi-lean/sass/parts/_webmention.scss b/sysret.org/themes/tabi-lean/sass/parts/_webmention.scss
index b6d6338..b6d6338 100644
--- a/themes/tabi-lean/sass/parts/_webmention.scss
+++ b/sysret.org/themes/tabi-lean/sass/parts/_webmention.scss
diff --git a/themes/tabi-lean/sass/parts/_zola-error.scss b/sysret.org/themes/tabi-lean/sass/parts/_zola-error.scss
index 3bdbcbc..3bdbcbc 100644
--- a/themes/tabi-lean/sass/parts/_zola-error.scss
+++ b/sysret.org/themes/tabi-lean/sass/parts/_zola-error.scss
diff --git a/themes/tabi-lean/sass/skins/blue.scss b/sysret.org/themes/tabi-lean/sass/skins/blue.scss
index d135219..d135219 100644
--- a/themes/tabi-lean/sass/skins/blue.scss
+++ b/sysret.org/themes/tabi-lean/sass/skins/blue.scss
diff --git a/themes/tabi-lean/sass/skins/evangelion.scss b/sysret.org/themes/tabi-lean/sass/skins/evangelion.scss
index d0350a5..d0350a5 100644
--- a/themes/tabi-lean/sass/skins/evangelion.scss
+++ b/sysret.org/themes/tabi-lean/sass/skins/evangelion.scss
diff --git a/themes/tabi-lean/sass/skins/indigo_ingot.scss b/sysret.org/themes/tabi-lean/sass/skins/indigo_ingot.scss
index 11a6370..11a6370 100644
--- a/themes/tabi-lean/sass/skins/indigo_ingot.scss
+++ b/sysret.org/themes/tabi-lean/sass/skins/indigo_ingot.scss
diff --git a/themes/tabi-lean/sass/skins/lavender.scss b/sysret.org/themes/tabi-lean/sass/skins/lavender.scss
index 97a40df..97a40df 100644
--- a/themes/tabi-lean/sass/skins/lavender.scss
+++ b/sysret.org/themes/tabi-lean/sass/skins/lavender.scss
diff --git a/themes/tabi-lean/sass/skins/lowcontrast_orange.scss b/sysret.org/themes/tabi-lean/sass/skins/lowcontrast_orange.scss
index ad84bf4..ad84bf4 100644
--- a/themes/tabi-lean/sass/skins/lowcontrast_orange.scss
+++ b/sysret.org/themes/tabi-lean/sass/skins/lowcontrast_orange.scss
diff --git a/themes/tabi-lean/sass/skins/lowcontrast_peach.scss b/sysret.org/themes/tabi-lean/sass/skins/lowcontrast_peach.scss
index 328a4da..328a4da 100644
--- a/themes/tabi-lean/sass/skins/lowcontrast_peach.scss
+++ b/sysret.org/themes/tabi-lean/sass/skins/lowcontrast_peach.scss
diff --git a/themes/tabi-lean/sass/skins/lowcontrast_pink.scss b/sysret.org/themes/tabi-lean/sass/skins/lowcontrast_pink.scss
index 3f96d1d..3f96d1d 100644
--- a/themes/tabi-lean/sass/skins/lowcontrast_pink.scss
+++ b/sysret.org/themes/tabi-lean/sass/skins/lowcontrast_pink.scss
diff --git a/themes/tabi-lean/sass/skins/mint.scss b/sysret.org/themes/tabi-lean/sass/skins/mint.scss
index e598c24..e598c24 100644
--- a/themes/tabi-lean/sass/skins/mint.scss
+++ b/sysret.org/themes/tabi-lean/sass/skins/mint.scss
diff --git a/themes/tabi-lean/sass/skins/monochrome.scss b/sysret.org/themes/tabi-lean/sass/skins/monochrome.scss
index 976e12e..976e12e 100644
--- a/themes/tabi-lean/sass/skins/monochrome.scss
+++ b/sysret.org/themes/tabi-lean/sass/skins/monochrome.scss
diff --git a/themes/tabi-lean/sass/skins/posixlycorrect.scss b/sysret.org/themes/tabi-lean/sass/skins/posixlycorrect.scss
index 47b6c2c..47b6c2c 100644
--- a/themes/tabi-lean/sass/skins/posixlycorrect.scss
+++ b/sysret.org/themes/tabi-lean/sass/skins/posixlycorrect.scss
diff --git a/themes/tabi-lean/sass/skins/red.scss b/sysret.org/themes/tabi-lean/sass/skins/red.scss
index 169340f..169340f 100644
--- a/themes/tabi-lean/sass/skins/red.scss
+++ b/sysret.org/themes/tabi-lean/sass/skins/red.scss
diff --git a/themes/tabi-lean/sass/skins/sakura.scss b/sysret.org/themes/tabi-lean/sass/skins/sakura.scss
index 4e418eb..4e418eb 100644
--- a/themes/tabi-lean/sass/skins/sakura.scss
+++ b/sysret.org/themes/tabi-lean/sass/skins/sakura.scss
diff --git a/themes/tabi-lean/sass/skins/teal.scss b/sysret.org/themes/tabi-lean/sass/skins/teal.scss
index 3a1fbcd..3a1fbcd 100644
--- a/themes/tabi-lean/sass/skins/teal.scss
+++ b/sysret.org/themes/tabi-lean/sass/skins/teal.scss
diff --git a/themes/tabi-lean/static/custom_subset.css b/sysret.org/themes/tabi-lean/static/custom_subset.css
index 13ac96e..13ac96e 100644
--- a/themes/tabi-lean/static/custom_subset.css
+++ b/sysret.org/themes/tabi-lean/static/custom_subset.css
diff --git a/themes/tabi-lean/static/feed_style.xsl b/sysret.org/themes/tabi-lean/static/feed_style.xsl
index 1e413bb..1e413bb 100644
--- a/themes/tabi-lean/static/feed_style.xsl
+++ b/sysret.org/themes/tabi-lean/static/feed_style.xsl
diff --git a/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-Bold.ttf b/sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-Bold.ttf
index 41365a8..41365a8 100644
--- a/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-Bold.ttf
+++ b/sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-Bold.ttf
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-BoldItalic.ttf b/sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-BoldItalic.ttf
index ede5867..ede5867 100644
--- a/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-BoldItalic.ttf
+++ b/sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-BoldItalic.ttf
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-ExtraBold.ttf b/sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-ExtraBold.ttf
index 7430b4f..7430b4f 100644
--- a/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-ExtraBold.ttf
+++ b/sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-ExtraBold.ttf
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-ExtraBoldItalic.ttf b/sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-ExtraBoldItalic.ttf
index 53020b9..53020b9 100644
--- a/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-ExtraBoldItalic.ttf
+++ b/sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-ExtraBoldItalic.ttf
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-ExtraLight.ttf b/sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-ExtraLight.ttf
index cc99cdf..cc99cdf 100644
--- a/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-ExtraLight.ttf
+++ b/sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-ExtraLight.ttf
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-ExtraLightItalic.ttf b/sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-ExtraLightItalic.ttf
index 10bcdaa..10bcdaa 100644
--- a/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-ExtraLightItalic.ttf
+++ b/sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-ExtraLightItalic.ttf
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-Italic.ttf b/sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-Italic.ttf
index d3857d6..d3857d6 100644
--- a/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-Italic.ttf
+++ b/sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-Italic.ttf
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-Light.ttf b/sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-Light.ttf
index 56d5f65..56d5f65 100644
--- a/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-Light.ttf
+++ b/sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-Light.ttf
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-LightItalic.ttf b/sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-LightItalic.ttf
index bcb382c..bcb382c 100644
--- a/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-LightItalic.ttf
+++ b/sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-LightItalic.ttf
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-Medium.ttf b/sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-Medium.ttf
index ee8c06c..ee8c06c 100644
--- a/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-Medium.ttf
+++ b/sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-Medium.ttf
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-MediumItalic.ttf b/sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-MediumItalic.ttf
index f836007..f836007 100644
--- a/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-MediumItalic.ttf
+++ b/sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-MediumItalic.ttf
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-Regular.ttf b/sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-Regular.ttf
index 8e9ac86..8e9ac86 100644
--- a/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-Regular.ttf
+++ b/sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-Regular.ttf
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-SemiBold.ttf b/sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-SemiBold.ttf
index 8c33920..8c33920 100644
--- a/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-SemiBold.ttf
+++ b/sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-SemiBold.ttf
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-SemiBoldItalic.ttf b/sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-SemiBoldItalic.ttf
index dcd0a9a..dcd0a9a 100644
--- a/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-SemiBoldItalic.ttf
+++ b/sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-SemiBoldItalic.ttf
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-Thin.ttf b/sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-Thin.ttf
index 5a288f4..5a288f4 100644
--- a/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-Thin.ttf
+++ b/sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-Thin.ttf
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-ThinItalic.ttf b/sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-ThinItalic.ttf
index 8410608..8410608 100644
--- a/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-ThinItalic.ttf
+++ b/sysret.org/themes/tabi-lean/static/fonts/JetBrainsMonoNLNerdFont-ThinItalic.ttf
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_AMS-Regular.ttf b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_AMS-Regular.ttf
index c6f9a5e..c6f9a5e 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_AMS-Regular.ttf
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_AMS-Regular.ttf
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_AMS-Regular.woff b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_AMS-Regular.woff
index b804d7b..b804d7b 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_AMS-Regular.woff
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_AMS-Regular.woff
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_AMS-Regular.woff2 b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_AMS-Regular.woff2
index 0acaaff..0acaaff 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_AMS-Regular.woff2
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_AMS-Regular.woff2
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Caligraphic-Bold.ttf b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Caligraphic-Bold.ttf
index 9ff4a5e..9ff4a5e 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Caligraphic-Bold.ttf
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Caligraphic-Bold.ttf
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Caligraphic-Bold.woff b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Caligraphic-Bold.woff
index 9759710..9759710 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Caligraphic-Bold.woff
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Caligraphic-Bold.woff
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Caligraphic-Bold.woff2 b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Caligraphic-Bold.woff2
index f390922..f390922 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Caligraphic-Bold.woff2
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Caligraphic-Bold.woff2
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Caligraphic-Regular.ttf b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Caligraphic-Regular.ttf
index f522294..f522294 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Caligraphic-Regular.ttf
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Caligraphic-Regular.ttf
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Caligraphic-Regular.woff b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Caligraphic-Regular.woff
index 9bdd534..9bdd534 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Caligraphic-Regular.woff
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Caligraphic-Regular.woff
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Caligraphic-Regular.woff2 b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Caligraphic-Regular.woff2
index 75344a1..75344a1 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Caligraphic-Regular.woff2
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Caligraphic-Regular.woff2
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Fraktur-Bold.ttf b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Fraktur-Bold.ttf
index 4e98259..4e98259 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Fraktur-Bold.ttf
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Fraktur-Bold.ttf
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Fraktur-Bold.woff b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Fraktur-Bold.woff
index e7730f6..e7730f6 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Fraktur-Bold.woff
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Fraktur-Bold.woff
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Fraktur-Bold.woff2 b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Fraktur-Bold.woff2
index 395f28b..395f28b 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Fraktur-Bold.woff2
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Fraktur-Bold.woff2
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Fraktur-Regular.ttf b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Fraktur-Regular.ttf
index b8461b2..b8461b2 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Fraktur-Regular.ttf
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Fraktur-Regular.ttf
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Fraktur-Regular.woff b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Fraktur-Regular.woff
index acab069..acab069 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Fraktur-Regular.woff
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Fraktur-Regular.woff
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Fraktur-Regular.woff2 b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Fraktur-Regular.woff2
index 735f694..735f694 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Fraktur-Regular.woff2
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Fraktur-Regular.woff2
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Bold.ttf b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Bold.ttf
index 4060e62..4060e62 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Bold.ttf
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Bold.ttf
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Bold.woff b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Bold.woff
index f38136a..f38136a 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Bold.woff
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Bold.woff
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Bold.woff2 b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Bold.woff2
index ab2ad21..ab2ad21 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Bold.woff2
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Bold.woff2
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-BoldItalic.ttf b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-BoldItalic.ttf
index dc00797..dc00797 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-BoldItalic.ttf
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-BoldItalic.ttf
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-BoldItalic.woff b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-BoldItalic.woff
index 67807b0..67807b0 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-BoldItalic.woff
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-BoldItalic.woff
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-BoldItalic.woff2 b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-BoldItalic.woff2
index 5931794..5931794 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-BoldItalic.woff2
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-BoldItalic.woff2
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Italic.ttf b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Italic.ttf
index 0e9b0f3..0e9b0f3 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Italic.ttf
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Italic.ttf
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Italic.woff b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Italic.woff
index 6f43b59..6f43b59 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Italic.woff
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Italic.woff
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Italic.woff2 b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Italic.woff2
index b50920e..b50920e 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Italic.woff2
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Italic.woff2
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Regular.ttf b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Regular.ttf
index dd45e1e..dd45e1e 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Regular.ttf
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Regular.ttf
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Regular.woff b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Regular.woff
index 21f5812..21f5812 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Regular.woff
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Regular.woff
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Regular.woff2 b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Regular.woff2
index eb24a7b..eb24a7b 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Regular.woff2
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Main-Regular.woff2
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Math-BoldItalic.ttf b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Math-BoldItalic.ttf
index 728ce7a..728ce7a 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Math-BoldItalic.ttf
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Math-BoldItalic.ttf
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Math-BoldItalic.woff b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Math-BoldItalic.woff
index 0ae390d..0ae390d 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Math-BoldItalic.woff
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Math-BoldItalic.woff
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Math-BoldItalic.woff2 b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Math-BoldItalic.woff2
index 2965702..2965702 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Math-BoldItalic.woff2
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Math-BoldItalic.woff2
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Math-Italic.ttf b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Math-Italic.ttf
index 70d559b..70d559b 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Math-Italic.ttf
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Math-Italic.ttf
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Math-Italic.woff b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Math-Italic.woff
index eb5159d..eb5159d 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Math-Italic.woff
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Math-Italic.woff
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Math-Italic.woff2 b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Math-Italic.woff2
index 215c143..215c143 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Math-Italic.woff2
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Math-Italic.woff2
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Bold.ttf b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Bold.ttf
index 2f65a8a..2f65a8a 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Bold.ttf
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Bold.ttf
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Bold.woff b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Bold.woff
index 8d47c02..8d47c02 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Bold.woff
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Bold.woff
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Bold.woff2 b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Bold.woff2
index cfaa3bd..cfaa3bd 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Bold.woff2
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Bold.woff2
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Italic.ttf b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Italic.ttf
index d5850df..d5850df 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Italic.ttf
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Italic.ttf
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Italic.woff b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Italic.woff
index 7e02df9..7e02df9 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Italic.woff
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Italic.woff
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Italic.woff2 b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Italic.woff2
index 349c06d..349c06d 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Italic.woff2
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Italic.woff2
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Regular.ttf b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Regular.ttf
index 537279f..537279f 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Regular.ttf
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Regular.ttf
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Regular.woff b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Regular.woff
index 31b8482..31b8482 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Regular.woff
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Regular.woff
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Regular.woff2 b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Regular.woff2
index a90eea8..a90eea8 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Regular.woff2
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_SansSerif-Regular.woff2
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Script-Regular.ttf b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Script-Regular.ttf
index fd679bf..fd679bf 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Script-Regular.ttf
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Script-Regular.ttf
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Script-Regular.woff b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Script-Regular.woff
index 0e7da82..0e7da82 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Script-Regular.woff
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Script-Regular.woff
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Script-Regular.woff2 b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Script-Regular.woff2
index b3048fc..b3048fc 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Script-Regular.woff2
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Script-Regular.woff2
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size1-Regular.ttf b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size1-Regular.ttf
index 871fd7d..871fd7d 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size1-Regular.ttf
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size1-Regular.ttf
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size1-Regular.woff b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size1-Regular.woff
index 7f292d9..7f292d9 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size1-Regular.woff
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size1-Regular.woff
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size1-Regular.woff2 b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size1-Regular.woff2
index c5a8462..c5a8462 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size1-Regular.woff2
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size1-Regular.woff2
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size2-Regular.ttf b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size2-Regular.ttf
index 7a212ca..7a212ca 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size2-Regular.ttf
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size2-Regular.ttf
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size2-Regular.woff b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size2-Regular.woff
index d241d9b..d241d9b 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size2-Regular.woff
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size2-Regular.woff
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size2-Regular.woff2 b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size2-Regular.woff2
index e1bccfe..e1bccfe 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size2-Regular.woff2
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size2-Regular.woff2
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size3-Regular.ttf b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size3-Regular.ttf
index 00bff34..00bff34 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size3-Regular.ttf
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size3-Regular.ttf
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size3-Regular.woff b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size3-Regular.woff
index e6e9b65..e6e9b65 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size3-Regular.woff
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size3-Regular.woff
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size3-Regular.woff2 b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size3-Regular.woff2
index 249a286..249a286 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size3-Regular.woff2
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size3-Regular.woff2
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size4-Regular.ttf b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size4-Regular.ttf
index 74f0892..74f0892 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size4-Regular.ttf
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size4-Regular.ttf
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size4-Regular.woff b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size4-Regular.woff
index e1ec545..e1ec545 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size4-Regular.woff
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size4-Regular.woff
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size4-Regular.woff2 b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size4-Regular.woff2
index 680c130..680c130 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size4-Regular.woff2
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Size4-Regular.woff2
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Typewriter-Regular.ttf b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Typewriter-Regular.ttf
index c83252c..c83252c 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Typewriter-Regular.ttf
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Typewriter-Regular.ttf
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Typewriter-Regular.woff b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Typewriter-Regular.woff
index 2432419..2432419 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Typewriter-Regular.woff
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Typewriter-Regular.woff
Binary files differ
diff --git a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Typewriter-Regular.woff2 b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Typewriter-Regular.woff2
index 771f1af..771f1af 100644
--- a/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Typewriter-Regular.woff2
+++ b/sysret.org/themes/tabi-lean/static/fonts/KaTeX/KaTeX_Typewriter-Regular.woff2
Binary files differ
diff --git a/themes/tabi-lean/static/inter_subset_en.css b/sysret.org/themes/tabi-lean/static/inter_subset_en.css
index cafb383..cafb383 100644
--- a/themes/tabi-lean/static/inter_subset_en.css
+++ b/sysret.org/themes/tabi-lean/static/inter_subset_en.css
diff --git a/themes/tabi-lean/static/inter_subset_es.css b/sysret.org/themes/tabi-lean/static/inter_subset_es.css
index fe802b0..fe802b0 100644
--- a/themes/tabi-lean/static/inter_subset_es.css
+++ b/sysret.org/themes/tabi-lean/static/inter_subset_es.css
diff --git a/themes/tabi-lean/static/isso.css b/sysret.org/themes/tabi-lean/static/isso.css
index c5a7329..c5a7329 100644
--- a/themes/tabi-lean/static/isso.css
+++ b/sysret.org/themes/tabi-lean/static/isso.css
diff --git a/themes/tabi-lean/static/isso.min.css b/sysret.org/themes/tabi-lean/static/isso.min.css
index 2d7b16c..2d7b16c 100644
--- a/themes/tabi-lean/static/isso.min.css
+++ b/sysret.org/themes/tabi-lean/static/isso.min.css
diff --git a/themes/tabi-lean/static/js/codeBlockNameLinks.js b/sysret.org/themes/tabi-lean/static/js/codeBlockNameLinks.js
index ea0b678..ea0b678 100644
--- a/themes/tabi-lean/static/js/codeBlockNameLinks.js
+++ b/sysret.org/themes/tabi-lean/static/js/codeBlockNameLinks.js
diff --git a/themes/tabi-lean/static/js/codeBlockNameLinks.min.js b/sysret.org/themes/tabi-lean/static/js/codeBlockNameLinks.min.js
index df1f999..df1f999 100644
--- a/themes/tabi-lean/static/js/codeBlockNameLinks.min.js
+++ b/sysret.org/themes/tabi-lean/static/js/codeBlockNameLinks.min.js
diff --git a/themes/tabi-lean/static/js/copyCodeToClipboard.js b/sysret.org/themes/tabi-lean/static/js/copyCodeToClipboard.js
index 805eb59..805eb59 100644
--- a/themes/tabi-lean/static/js/copyCodeToClipboard.js
+++ b/sysret.org/themes/tabi-lean/static/js/copyCodeToClipboard.js
diff --git a/themes/tabi-lean/static/js/copyCodeToClipboard.min.js b/sysret.org/themes/tabi-lean/static/js/copyCodeToClipboard.min.js
index 240d4ff..240d4ff 100644
--- a/themes/tabi-lean/static/js/copyCodeToClipboard.min.js
+++ b/sysret.org/themes/tabi-lean/static/js/copyCodeToClipboard.min.js
diff --git a/themes/tabi-lean/static/js/decodeMail.js b/sysret.org/themes/tabi-lean/static/js/decodeMail.js
index f26ac68..f26ac68 100644
--- a/themes/tabi-lean/static/js/decodeMail.js
+++ b/sysret.org/themes/tabi-lean/static/js/decodeMail.js
diff --git a/themes/tabi-lean/static/js/decodeMail.min.js b/sysret.org/themes/tabi-lean/static/js/decodeMail.min.js
index 2b766a0..2b766a0 100644
--- a/themes/tabi-lean/static/js/decodeMail.min.js
+++ b/sysret.org/themes/tabi-lean/static/js/decodeMail.min.js
diff --git a/themes/tabi-lean/static/js/filterCards.js b/sysret.org/themes/tabi-lean/static/js/filterCards.js
index a24137f..a24137f 100644
--- a/themes/tabi-lean/static/js/filterCards.js
+++ b/sysret.org/themes/tabi-lean/static/js/filterCards.js
diff --git a/themes/tabi-lean/static/js/filterCards.min.js b/sysret.org/themes/tabi-lean/static/js/filterCards.min.js
index b150e70..b150e70 100644
--- a/themes/tabi-lean/static/js/filterCards.min.js
+++ b/sysret.org/themes/tabi-lean/static/js/filterCards.min.js
diff --git a/themes/tabi-lean/static/js/footnoteBacklinks.js b/sysret.org/themes/tabi-lean/static/js/footnoteBacklinks.js
index 8c20098..8c20098 100644
--- a/themes/tabi-lean/static/js/footnoteBacklinks.js
+++ b/sysret.org/themes/tabi-lean/static/js/footnoteBacklinks.js
diff --git a/themes/tabi-lean/static/js/footnoteBacklinks.min.js b/sysret.org/themes/tabi-lean/static/js/footnoteBacklinks.min.js
index c2175a7..c2175a7 100644
--- a/themes/tabi-lean/static/js/footnoteBacklinks.min.js
+++ b/sysret.org/themes/tabi-lean/static/js/footnoteBacklinks.min.js
diff --git a/themes/tabi-lean/static/js/giscus.js b/sysret.org/themes/tabi-lean/static/js/giscus.js
index 1fbe837..1fbe837 100644
--- a/themes/tabi-lean/static/js/giscus.js
+++ b/sysret.org/themes/tabi-lean/static/js/giscus.js
diff --git a/themes/tabi-lean/static/js/giscus.min.js b/sysret.org/themes/tabi-lean/static/js/giscus.min.js
index 2846f22..2846f22 100644
--- a/themes/tabi-lean/static/js/giscus.min.js
+++ b/sysret.org/themes/tabi-lean/static/js/giscus.min.js
diff --git a/themes/tabi-lean/static/js/hyvortalk.js b/sysret.org/themes/tabi-lean/static/js/hyvortalk.js
index 3f9959d..3f9959d 100644
--- a/themes/tabi-lean/static/js/hyvortalk.js
+++ b/sysret.org/themes/tabi-lean/static/js/hyvortalk.js
diff --git a/themes/tabi-lean/static/js/hyvortalk.min.js b/sysret.org/themes/tabi-lean/static/js/hyvortalk.min.js
index f4ea4f5..f4ea4f5 100644
--- a/themes/tabi-lean/static/js/hyvortalk.min.js
+++ b/sysret.org/themes/tabi-lean/static/js/hyvortalk.min.js
diff --git a/themes/tabi-lean/static/js/initializeTheme.js b/sysret.org/themes/tabi-lean/static/js/initializeTheme.js
index 95e754c..95e754c 100644
--- a/themes/tabi-lean/static/js/initializeTheme.js
+++ b/sysret.org/themes/tabi-lean/static/js/initializeTheme.js
diff --git a/themes/tabi-lean/static/js/initializeTheme.min.js b/sysret.org/themes/tabi-lean/static/js/initializeTheme.min.js
index 3f65952..3f65952 100644
--- a/themes/tabi-lean/static/js/initializeTheme.min.js
+++ b/sysret.org/themes/tabi-lean/static/js/initializeTheme.min.js
diff --git a/themes/tabi-lean/static/js/isso.js b/sysret.org/themes/tabi-lean/static/js/isso.js
index 4666604..4666604 100644
--- a/themes/tabi-lean/static/js/isso.js
+++ b/sysret.org/themes/tabi-lean/static/js/isso.js
diff --git a/themes/tabi-lean/static/js/isso.min.js b/sysret.org/themes/tabi-lean/static/js/isso.min.js
index 833eaff..833eaff 100644
--- a/themes/tabi-lean/static/js/isso.min.js
+++ b/sysret.org/themes/tabi-lean/static/js/isso.min.js
diff --git a/themes/tabi-lean/static/js/katex.min.js b/sysret.org/themes/tabi-lean/static/js/katex.min.js
index f0f08ba..f0f08ba 100644
--- a/themes/tabi-lean/static/js/katex.min.js
+++ b/sysret.org/themes/tabi-lean/static/js/katex.min.js
diff --git a/themes/tabi-lean/static/js/loadComments.js b/sysret.org/themes/tabi-lean/static/js/loadComments.js
index 911f1ca..911f1ca 100644
--- a/themes/tabi-lean/static/js/loadComments.js
+++ b/sysret.org/themes/tabi-lean/static/js/loadComments.js
diff --git a/themes/tabi-lean/static/js/loadComments.min.js b/sysret.org/themes/tabi-lean/static/js/loadComments.min.js
index ef14653..ef14653 100644
--- a/themes/tabi-lean/static/js/loadComments.min.js
+++ b/sysret.org/themes/tabi-lean/static/js/loadComments.min.js
diff --git a/themes/tabi-lean/static/js/lunr/lunr.da.js b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.da.js
index 32c6d01..32c6d01 100644
--- a/themes/tabi-lean/static/js/lunr/lunr.da.js
+++ b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.da.js
diff --git a/themes/tabi-lean/static/js/lunr/lunr.da.min.js b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.da.min.js
index eb41d29..eb41d29 100644
--- a/themes/tabi-lean/static/js/lunr/lunr.da.min.js
+++ b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.da.min.js
diff --git a/themes/tabi-lean/static/js/lunr/lunr.de.js b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.de.js
index 5cd9243..5cd9243 100644
--- a/themes/tabi-lean/static/js/lunr/lunr.de.js
+++ b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.de.js
diff --git a/themes/tabi-lean/static/js/lunr/lunr.de.min.js b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.de.min.js
index 7d099c6..7d099c6 100644
--- a/themes/tabi-lean/static/js/lunr/lunr.de.min.js
+++ b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.de.min.js
diff --git a/themes/tabi-lean/static/js/lunr/lunr.du.js b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.du.js
index cf4eda5..cf4eda5 100644
--- a/themes/tabi-lean/static/js/lunr/lunr.du.js
+++ b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.du.js
diff --git a/themes/tabi-lean/static/js/lunr/lunr.du.min.js b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.du.min.js
index 8ac0d07..8ac0d07 100644
--- a/themes/tabi-lean/static/js/lunr/lunr.du.min.js
+++ b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.du.min.js
diff --git a/themes/tabi-lean/static/js/lunr/lunr.es.js b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.es.js
index aa43b27..aa43b27 100644
--- a/themes/tabi-lean/static/js/lunr/lunr.es.js
+++ b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.es.js
diff --git a/themes/tabi-lean/static/js/lunr/lunr.es.min.js b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.es.min.js
index dc48558..dc48558 100644
--- a/themes/tabi-lean/static/js/lunr/lunr.es.min.js
+++ b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.es.min.js
diff --git a/themes/tabi-lean/static/js/lunr/lunr.fi.js b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.fi.js
index 8f78b5d..8f78b5d 100644
--- a/themes/tabi-lean/static/js/lunr/lunr.fi.js
+++ b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.fi.js
diff --git a/themes/tabi-lean/static/js/lunr/lunr.fi.min.js b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.fi.min.js
index a99beca..a99beca 100644
--- a/themes/tabi-lean/static/js/lunr/lunr.fi.min.js
+++ b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.fi.min.js
diff --git a/themes/tabi-lean/static/js/lunr/lunr.fr.js b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.fr.js
index 13c2420..13c2420 100644
--- a/themes/tabi-lean/static/js/lunr/lunr.fr.js
+++ b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.fr.js
diff --git a/themes/tabi-lean/static/js/lunr/lunr.fr.min.js b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.fr.min.js
index 4382cb7..4382cb7 100644
--- a/themes/tabi-lean/static/js/lunr/lunr.fr.min.js
+++ b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.fr.min.js
diff --git a/themes/tabi-lean/static/js/lunr/lunr.hu.js b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.hu.js
index 986ddb0..986ddb0 100644
--- a/themes/tabi-lean/static/js/lunr/lunr.hu.js
+++ b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.hu.js
diff --git a/themes/tabi-lean/static/js/lunr/lunr.hu.min.js b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.hu.min.js
index 1825c26..1825c26 100644
--- a/themes/tabi-lean/static/js/lunr/lunr.hu.min.js
+++ b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.hu.min.js
diff --git a/themes/tabi-lean/static/js/lunr/lunr.it.js b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.it.js
index 90014d7..90014d7 100644
--- a/themes/tabi-lean/static/js/lunr/lunr.it.js
+++ b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.it.js
diff --git a/themes/tabi-lean/static/js/lunr/lunr.it.min.js b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.it.min.js
index 36b30b5..36b30b5 100644
--- a/themes/tabi-lean/static/js/lunr/lunr.it.min.js
+++ b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.it.min.js
diff --git a/themes/tabi-lean/static/js/lunr/lunr.jp.js b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.jp.js
index 90a7629..90a7629 100644
--- a/themes/tabi-lean/static/js/lunr/lunr.jp.js
+++ b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.jp.js
diff --git a/themes/tabi-lean/static/js/lunr/lunr.jp.min.js b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.jp.min.js
index a978f34..a978f34 100644
--- a/themes/tabi-lean/static/js/lunr/lunr.jp.min.js
+++ b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.jp.min.js
diff --git a/themes/tabi-lean/static/js/lunr/lunr.no.js b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.no.js
index 5917006..5917006 100644
--- a/themes/tabi-lean/static/js/lunr/lunr.no.js
+++ b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.no.js
diff --git a/themes/tabi-lean/static/js/lunr/lunr.no.min.js b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.no.min.js
index f809a60..f809a60 100644
--- a/themes/tabi-lean/static/js/lunr/lunr.no.min.js
+++ b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.no.min.js
diff --git a/themes/tabi-lean/static/js/lunr/lunr.pt.js b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.pt.js
index d960d97..d960d97 100644
--- a/themes/tabi-lean/static/js/lunr/lunr.pt.js
+++ b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.pt.js
diff --git a/themes/tabi-lean/static/js/lunr/lunr.pt.min.js b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.pt.min.js
index 9776adc..9776adc 100644
--- a/themes/tabi-lean/static/js/lunr/lunr.pt.min.js
+++ b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.pt.min.js
diff --git a/themes/tabi-lean/static/js/lunr/lunr.ro.js b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.ro.js
index 9638278..9638278 100644
--- a/themes/tabi-lean/static/js/lunr/lunr.ro.js
+++ b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.ro.js
diff --git a/themes/tabi-lean/static/js/lunr/lunr.ro.min.js b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.ro.min.js
index 4fe0c44..4fe0c44 100644
--- a/themes/tabi-lean/static/js/lunr/lunr.ro.min.js
+++ b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.ro.min.js
diff --git a/themes/tabi-lean/static/js/lunr/lunr.ru.js b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.ru.js
index 4a0c415..4a0c415 100644
--- a/themes/tabi-lean/static/js/lunr/lunr.ru.js
+++ b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.ru.js
diff --git a/themes/tabi-lean/static/js/lunr/lunr.ru.min.js b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.ru.min.js
index f254753..f254753 100644
--- a/themes/tabi-lean/static/js/lunr/lunr.ru.min.js
+++ b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.ru.min.js
diff --git a/themes/tabi-lean/static/js/lunr/lunr.sv.js b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.sv.js
index 2e1c20e..2e1c20e 100644
--- a/themes/tabi-lean/static/js/lunr/lunr.sv.js
+++ b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.sv.js
diff --git a/themes/tabi-lean/static/js/lunr/lunr.sv.min.js b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.sv.min.js
index 1e5c7a3..1e5c7a3 100644
--- a/themes/tabi-lean/static/js/lunr/lunr.sv.min.js
+++ b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.sv.min.js
diff --git a/themes/tabi-lean/static/js/lunr/lunr.tr.js b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.tr.js
index ccecfad..ccecfad 100644
--- a/themes/tabi-lean/static/js/lunr/lunr.tr.js
+++ b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.tr.js
diff --git a/themes/tabi-lean/static/js/lunr/lunr.tr.min.js b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.tr.min.js
index c2d8fb6..c2d8fb6 100644
--- a/themes/tabi-lean/static/js/lunr/lunr.tr.min.js
+++ b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.tr.min.js
diff --git a/themes/tabi-lean/static/js/lunr/lunr.zh.js b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.zh.js
index 8d85823..8d85823 100644
--- a/themes/tabi-lean/static/js/lunr/lunr.zh.js
+++ b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.zh.js
diff --git a/themes/tabi-lean/static/js/lunr/lunr.zh.min.js b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.zh.min.js
index 387e69a..387e69a 100644
--- a/themes/tabi-lean/static/js/lunr/lunr.zh.min.js
+++ b/sysret.org/themes/tabi-lean/static/js/lunr/lunr.zh.min.js
diff --git a/themes/tabi-lean/static/js/lunr/lunrStemmerSupport.js b/sysret.org/themes/tabi-lean/static/js/lunr/lunrStemmerSupport.js
index 32959fb..32959fb 100755
--- a/themes/tabi-lean/static/js/lunr/lunrStemmerSupport.js
+++ b/sysret.org/themes/tabi-lean/static/js/lunr/lunrStemmerSupport.js
diff --git a/themes/tabi-lean/static/js/lunr/lunrStemmerSupport.min.js b/sysret.org/themes/tabi-lean/static/js/lunr/lunrStemmerSupport.min.js
index 3567a8c..3567a8c 100755
--- a/themes/tabi-lean/static/js/lunr/lunrStemmerSupport.min.js
+++ b/sysret.org/themes/tabi-lean/static/js/lunr/lunrStemmerSupport.min.js
diff --git a/themes/tabi-lean/static/js/mermaid.min.js b/sysret.org/themes/tabi-lean/static/js/mermaid.min.js
index 51902c2..51902c2 100644
--- a/themes/tabi-lean/static/js/mermaid.min.js
+++ b/sysret.org/themes/tabi-lean/static/js/mermaid.min.js
diff --git a/themes/tabi-lean/static/js/searchElasticlunr.js b/sysret.org/themes/tabi-lean/static/js/searchElasticlunr.js
index 9ad09e1..9ad09e1 100644
--- a/themes/tabi-lean/static/js/searchElasticlunr.js
+++ b/sysret.org/themes/tabi-lean/static/js/searchElasticlunr.js
diff --git a/themes/tabi-lean/static/js/searchElasticlunr.min.js b/sysret.org/themes/tabi-lean/static/js/searchElasticlunr.min.js
index 291bc7a..291bc7a 100644
--- a/themes/tabi-lean/static/js/searchElasticlunr.min.js
+++ b/sysret.org/themes/tabi-lean/static/js/searchElasticlunr.min.js
diff --git a/themes/tabi-lean/static/js/sortTable.js b/sysret.org/themes/tabi-lean/static/js/sortTable.js
index 16e02e9..16e02e9 100644
--- a/themes/tabi-lean/static/js/sortTable.js
+++ b/sysret.org/themes/tabi-lean/static/js/sortTable.js
diff --git a/themes/tabi-lean/static/js/sortTable.min.js b/sysret.org/themes/tabi-lean/static/js/sortTable.min.js
index de423a8..de423a8 100644
--- a/themes/tabi-lean/static/js/sortTable.min.js
+++ b/sysret.org/themes/tabi-lean/static/js/sortTable.min.js
diff --git a/themes/tabi-lean/static/js/themeSwitcher.js b/sysret.org/themes/tabi-lean/static/js/themeSwitcher.js
index c5ddf95..c5ddf95 100644
--- a/themes/tabi-lean/static/js/themeSwitcher.js
+++ b/sysret.org/themes/tabi-lean/static/js/themeSwitcher.js
diff --git a/themes/tabi-lean/static/js/themeSwitcher.min.js b/sysret.org/themes/tabi-lean/static/js/themeSwitcher.min.js
index e563ad3..e563ad3 100644
--- a/themes/tabi-lean/static/js/themeSwitcher.min.js
+++ b/sysret.org/themes/tabi-lean/static/js/themeSwitcher.min.js
diff --git a/themes/tabi-lean/static/js/utterances.js b/sysret.org/themes/tabi-lean/static/js/utterances.js
index ddfa35a..ddfa35a 100644
--- a/themes/tabi-lean/static/js/utterances.js
+++ b/sysret.org/themes/tabi-lean/static/js/utterances.js
diff --git a/themes/tabi-lean/static/js/utterances.min.js b/sysret.org/themes/tabi-lean/static/js/utterances.min.js
index 992de3b..992de3b 100644
--- a/themes/tabi-lean/static/js/utterances.min.js
+++ b/sysret.org/themes/tabi-lean/static/js/utterances.min.js
diff --git a/themes/tabi-lean/static/js/webmention.js b/sysret.org/themes/tabi-lean/static/js/webmention.js
index 261b238..261b238 100644
--- a/themes/tabi-lean/static/js/webmention.js
+++ b/sysret.org/themes/tabi-lean/static/js/webmention.js
diff --git a/themes/tabi-lean/static/js/webmention.min.js b/sysret.org/themes/tabi-lean/static/js/webmention.min.js
index 5340d7e..5340d7e 100644
--- a/themes/tabi-lean/static/js/webmention.min.js
+++ b/sysret.org/themes/tabi-lean/static/js/webmention.min.js
diff --git a/themes/tabi-lean/static/katex.min.css b/sysret.org/themes/tabi-lean/static/katex.min.css
index 30e6009..30e6009 100644
--- a/themes/tabi-lean/static/katex.min.css
+++ b/sysret.org/themes/tabi-lean/static/katex.min.css
diff --git a/themes/tabi-lean/static/no_js.css b/sysret.org/themes/tabi-lean/static/no_js.css
index 0294a30..0294a30 100644
--- a/themes/tabi-lean/static/no_js.css
+++ b/sysret.org/themes/tabi-lean/static/no_js.css
diff --git a/themes/tabi-lean/static/sitemap_style.xsl b/sysret.org/themes/tabi-lean/static/sitemap_style.xsl
index 70c3bb4..70c3bb4 100644
--- a/themes/tabi-lean/static/sitemap_style.xsl
+++ b/sysret.org/themes/tabi-lean/static/sitemap_style.xsl
diff --git a/themes/tabi-lean/static/social_icons/LICENSE b/sysret.org/themes/tabi-lean/static/social_icons/LICENSE
index 76875fb..76875fb 100644
--- a/themes/tabi-lean/static/social_icons/LICENSE
+++ b/sysret.org/themes/tabi-lean/static/social_icons/LICENSE
diff --git a/themes/tabi-lean/static/social_icons/apple.svg b/sysret.org/themes/tabi-lean/static/social_icons/apple.svg
index d0532d5..d0532d5 100644
--- a/themes/tabi-lean/static/social_icons/apple.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/apple.svg
diff --git a/themes/tabi-lean/static/social_icons/bitcoin.svg b/sysret.org/themes/tabi-lean/static/social_icons/bitcoin.svg
index 941d9b0..941d9b0 100644
--- a/themes/tabi-lean/static/social_icons/bitcoin.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/bitcoin.svg
diff --git a/themes/tabi-lean/static/social_icons/bluesky.svg b/sysret.org/themes/tabi-lean/static/social_icons/bluesky.svg
index 07bbec0..07bbec0 100644
--- a/themes/tabi-lean/static/social_icons/bluesky.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/bluesky.svg
diff --git a/themes/tabi-lean/static/social_icons/calckey.svg b/sysret.org/themes/tabi-lean/static/social_icons/calckey.svg
index 70c9ef1..70c9ef1 100755
--- a/themes/tabi-lean/static/social_icons/calckey.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/calckey.svg
diff --git a/themes/tabi-lean/static/social_icons/castopod.svg b/sysret.org/themes/tabi-lean/static/social_icons/castopod.svg
index 709288a..709288a 100755
--- a/themes/tabi-lean/static/social_icons/castopod.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/castopod.svg
diff --git a/themes/tabi-lean/static/social_icons/codeberg.svg b/sysret.org/themes/tabi-lean/static/social_icons/codeberg.svg
index d5fdd1a..d5fdd1a 100644
--- a/themes/tabi-lean/static/social_icons/codeberg.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/codeberg.svg
diff --git a/themes/tabi-lean/static/social_icons/debian.svg b/sysret.org/themes/tabi-lean/static/social_icons/debian.svg
index cf9d229..cf9d229 100644
--- a/themes/tabi-lean/static/social_icons/debian.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/debian.svg
diff --git a/themes/tabi-lean/static/social_icons/deviantart.svg b/sysret.org/themes/tabi-lean/static/social_icons/deviantart.svg
index 7dbd0b6..7dbd0b6 100644
--- a/themes/tabi-lean/static/social_icons/deviantart.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/deviantart.svg
diff --git a/themes/tabi-lean/static/social_icons/diaspora.svg b/sysret.org/themes/tabi-lean/static/social_icons/diaspora.svg
index 55527b5..55527b5 100644
--- a/themes/tabi-lean/static/social_icons/diaspora.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/diaspora.svg
diff --git a/themes/tabi-lean/static/social_icons/discord.svg b/sysret.org/themes/tabi-lean/static/social_icons/discord.svg
index f0dfeab..f0dfeab 100644
--- a/themes/tabi-lean/static/social_icons/discord.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/discord.svg
diff --git a/themes/tabi-lean/static/social_icons/discourse.svg b/sysret.org/themes/tabi-lean/static/social_icons/discourse.svg
index 343bea6..343bea6 100644
--- a/themes/tabi-lean/static/social_icons/discourse.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/discourse.svg
diff --git a/themes/tabi-lean/static/social_icons/email.svg b/sysret.org/themes/tabi-lean/static/social_icons/email.svg
index 85245e2..85245e2 100644
--- a/themes/tabi-lean/static/social_icons/email.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/email.svg
diff --git a/themes/tabi-lean/static/social_icons/ethereum.svg b/sysret.org/themes/tabi-lean/static/social_icons/ethereum.svg
index af202de..af202de 100644
--- a/themes/tabi-lean/static/social_icons/ethereum.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/ethereum.svg
diff --git a/themes/tabi-lean/static/social_icons/etsy.svg b/sysret.org/themes/tabi-lean/static/social_icons/etsy.svg
index ebc040a..ebc040a 100644
--- a/themes/tabi-lean/static/social_icons/etsy.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/etsy.svg
diff --git a/themes/tabi-lean/static/social_icons/facebook.svg b/sysret.org/themes/tabi-lean/static/social_icons/facebook.svg
index 0afaf7a..0afaf7a 100644
--- a/themes/tabi-lean/static/social_icons/facebook.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/facebook.svg
diff --git a/themes/tabi-lean/static/social_icons/forgejo.svg b/sysret.org/themes/tabi-lean/static/social_icons/forgejo.svg
index 64769ca..64769ca 100755
--- a/themes/tabi-lean/static/social_icons/forgejo.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/forgejo.svg
diff --git a/themes/tabi-lean/static/social_icons/friendica.svg b/sysret.org/themes/tabi-lean/static/social_icons/friendica.svg
index 200aa8b..200aa8b 100755
--- a/themes/tabi-lean/static/social_icons/friendica.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/friendica.svg
diff --git a/themes/tabi-lean/static/social_icons/funkwhale.svg b/sysret.org/themes/tabi-lean/static/social_icons/funkwhale.svg
index a320e0a..a320e0a 100755
--- a/themes/tabi-lean/static/social_icons/funkwhale.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/funkwhale.svg
diff --git a/themes/tabi-lean/static/social_icons/gitea.svg b/sysret.org/themes/tabi-lean/static/social_icons/gitea.svg
index 3022da4..3022da4 100755
--- a/themes/tabi-lean/static/social_icons/gitea.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/gitea.svg
diff --git a/themes/tabi-lean/static/social_icons/github.svg b/sysret.org/themes/tabi-lean/static/social_icons/github.svg
index e32807a..e32807a 100644
--- a/themes/tabi-lean/static/social_icons/github.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/github.svg
diff --git a/themes/tabi-lean/static/social_icons/gitlab.svg b/sysret.org/themes/tabi-lean/static/social_icons/gitlab.svg
index b577d3f..b577d3f 100644
--- a/themes/tabi-lean/static/social_icons/gitlab.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/gitlab.svg
diff --git a/themes/tabi-lean/static/social_icons/google-scholar.svg b/sysret.org/themes/tabi-lean/static/social_icons/google-scholar.svg
index f271dca..f271dca 100644
--- a/themes/tabi-lean/static/social_icons/google-scholar.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/google-scholar.svg
diff --git a/themes/tabi-lean/static/social_icons/google.svg b/sysret.org/themes/tabi-lean/static/social_icons/google.svg
index b3776b0..b3776b0 100644
--- a/themes/tabi-lean/static/social_icons/google.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/google.svg
diff --git a/themes/tabi-lean/static/social_icons/greatape.svg b/sysret.org/themes/tabi-lean/static/social_icons/greatape.svg
index 3a58d86..3a58d86 100755
--- a/themes/tabi-lean/static/social_icons/greatape.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/greatape.svg
diff --git a/themes/tabi-lean/static/social_icons/hacker-news.svg b/sysret.org/themes/tabi-lean/static/social_icons/hacker-news.svg
index 23e3980..23e3980 100644
--- a/themes/tabi-lean/static/social_icons/hacker-news.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/hacker-news.svg
diff --git a/themes/tabi-lean/static/social_icons/hubzilla.svg b/sysret.org/themes/tabi-lean/static/social_icons/hubzilla.svg
index 2d6c740..2d6c740 100755
--- a/themes/tabi-lean/static/social_icons/hubzilla.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/hubzilla.svg
diff --git a/themes/tabi-lean/static/social_icons/instagram.svg b/sysret.org/themes/tabi-lean/static/social_icons/instagram.svg
index 89f63c4..89f63c4 100644
--- a/themes/tabi-lean/static/social_icons/instagram.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/instagram.svg
diff --git a/themes/tabi-lean/static/social_icons/itchio.svg b/sysret.org/themes/tabi-lean/static/social_icons/itchio.svg
index 4a4ac25..4a4ac25 100644
--- a/themes/tabi-lean/static/social_icons/itchio.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/itchio.svg
diff --git a/themes/tabi-lean/static/social_icons/keybase.svg b/sysret.org/themes/tabi-lean/static/social_icons/keybase.svg
index f4c2ebb..f4c2ebb 100644
--- a/themes/tabi-lean/static/social_icons/keybase.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/keybase.svg
diff --git a/themes/tabi-lean/static/social_icons/lemmy.svg b/sysret.org/themes/tabi-lean/static/social_icons/lemmy.svg
index 07eede1..07eede1 100755
--- a/themes/tabi-lean/static/social_icons/lemmy.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/lemmy.svg
diff --git a/themes/tabi-lean/static/social_icons/letterboxd.svg b/sysret.org/themes/tabi-lean/static/social_icons/letterboxd.svg
index d3e1925..d3e1925 100644
--- a/themes/tabi-lean/static/social_icons/letterboxd.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/letterboxd.svg
diff --git a/themes/tabi-lean/static/social_icons/linkedin.svg b/sysret.org/themes/tabi-lean/static/social_icons/linkedin.svg
index d54fcf5..d54fcf5 100644
--- a/themes/tabi-lean/static/social_icons/linkedin.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/linkedin.svg
diff --git a/themes/tabi-lean/static/social_icons/mastodon.svg b/sysret.org/themes/tabi-lean/static/social_icons/mastodon.svg
index 5e12f81..5e12f81 100644
--- a/themes/tabi-lean/static/social_icons/mastodon.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/mastodon.svg
diff --git a/themes/tabi-lean/static/social_icons/matrix.svg b/sysret.org/themes/tabi-lean/static/social_icons/matrix.svg
index 7618c33..7618c33 100644
--- a/themes/tabi-lean/static/social_icons/matrix.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/matrix.svg
diff --git a/themes/tabi-lean/static/social_icons/misskey.svg b/sysret.org/themes/tabi-lean/static/social_icons/misskey.svg
index ab3a381..ab3a381 100755
--- a/themes/tabi-lean/static/social_icons/misskey.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/misskey.svg
diff --git a/themes/tabi-lean/static/social_icons/nostr.svg b/sysret.org/themes/tabi-lean/static/social_icons/nostr.svg
index fd103ae..fd103ae 100755
--- a/themes/tabi-lean/static/social_icons/nostr.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/nostr.svg
diff --git a/themes/tabi-lean/static/social_icons/orcid.svg b/sysret.org/themes/tabi-lean/static/social_icons/orcid.svg
index 2c3e4bd..2c3e4bd 100644
--- a/themes/tabi-lean/static/social_icons/orcid.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/orcid.svg
diff --git a/themes/tabi-lean/static/social_icons/paypal.svg b/sysret.org/themes/tabi-lean/static/social_icons/paypal.svg
index efdc81a..efdc81a 100644
--- a/themes/tabi-lean/static/social_icons/paypal.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/paypal.svg
diff --git a/themes/tabi-lean/static/social_icons/peertube.svg b/sysret.org/themes/tabi-lean/static/social_icons/peertube.svg
index 3986e7f..3986e7f 100755
--- a/themes/tabi-lean/static/social_icons/peertube.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/peertube.svg
diff --git a/themes/tabi-lean/static/social_icons/pinterest.svg b/sysret.org/themes/tabi-lean/static/social_icons/pinterest.svg
index eb977c2..eb977c2 100644
--- a/themes/tabi-lean/static/social_icons/pinterest.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/pinterest.svg
diff --git a/themes/tabi-lean/static/social_icons/pixelfed.svg b/sysret.org/themes/tabi-lean/static/social_icons/pixelfed.svg
index 87b2154..87b2154 100755
--- a/themes/tabi-lean/static/social_icons/pixelfed.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/pixelfed.svg
diff --git a/themes/tabi-lean/static/social_icons/pleroma.svg b/sysret.org/themes/tabi-lean/static/social_icons/pleroma.svg
index b2390cc..b2390cc 100755
--- a/themes/tabi-lean/static/social_icons/pleroma.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/pleroma.svg
diff --git a/themes/tabi-lean/static/social_icons/quora.svg b/sysret.org/themes/tabi-lean/static/social_icons/quora.svg
index 375d302..375d302 100644
--- a/themes/tabi-lean/static/social_icons/quora.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/quora.svg
diff --git a/themes/tabi-lean/static/social_icons/reddit.svg b/sysret.org/themes/tabi-lean/static/social_icons/reddit.svg
index a8a3a96..a8a3a96 100644
--- a/themes/tabi-lean/static/social_icons/reddit.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/reddit.svg
diff --git a/themes/tabi-lean/static/social_icons/rss.svg b/sysret.org/themes/tabi-lean/static/social_icons/rss.svg
index b862886..b862886 100644
--- a/themes/tabi-lean/static/social_icons/rss.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/rss.svg
diff --git a/themes/tabi-lean/static/social_icons/signal.svg b/sysret.org/themes/tabi-lean/static/social_icons/signal.svg
index c6ee14a..c6ee14a 100644
--- a/themes/tabi-lean/static/social_icons/signal.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/signal.svg
diff --git a/themes/tabi-lean/static/social_icons/skype.svg b/sysret.org/themes/tabi-lean/static/social_icons/skype.svg
index 3369aba..3369aba 100644
--- a/themes/tabi-lean/static/social_icons/skype.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/skype.svg
diff --git a/themes/tabi-lean/static/social_icons/slack.svg b/sysret.org/themes/tabi-lean/static/social_icons/slack.svg
index 0dbc26d..0dbc26d 100644
--- a/themes/tabi-lean/static/social_icons/slack.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/slack.svg
diff --git a/themes/tabi-lean/static/social_icons/snapchat.svg b/sysret.org/themes/tabi-lean/static/social_icons/snapchat.svg
index 2cd79dd..2cd79dd 100644
--- a/themes/tabi-lean/static/social_icons/snapchat.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/snapchat.svg
diff --git a/themes/tabi-lean/static/social_icons/soundcloud.svg b/sysret.org/themes/tabi-lean/static/social_icons/soundcloud.svg
index 4724d74..4724d74 100644
--- a/themes/tabi-lean/static/social_icons/soundcloud.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/soundcloud.svg
diff --git a/themes/tabi-lean/static/social_icons/spotify.svg b/sysret.org/themes/tabi-lean/static/social_icons/spotify.svg
index 1d393ba..1d393ba 100644
--- a/themes/tabi-lean/static/social_icons/spotify.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/spotify.svg
diff --git a/themes/tabi-lean/static/social_icons/stack-exchange.svg b/sysret.org/themes/tabi-lean/static/social_icons/stack-exchange.svg
index 0a3177f..0a3177f 100644
--- a/themes/tabi-lean/static/social_icons/stack-exchange.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/stack-exchange.svg
diff --git a/themes/tabi-lean/static/social_icons/stack-overflow.svg b/sysret.org/themes/tabi-lean/static/social_icons/stack-overflow.svg
index 2ca50c7..2ca50c7 100644
--- a/themes/tabi-lean/static/social_icons/stack-overflow.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/stack-overflow.svg
diff --git a/themes/tabi-lean/static/social_icons/steam.svg b/sysret.org/themes/tabi-lean/static/social_icons/steam.svg
index b61f374..b61f374 100644
--- a/themes/tabi-lean/static/social_icons/steam.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/steam.svg
diff --git a/themes/tabi-lean/static/social_icons/telegram.svg b/sysret.org/themes/tabi-lean/static/social_icons/telegram.svg
index 02f48c0..02f48c0 100644
--- a/themes/tabi-lean/static/social_icons/telegram.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/telegram.svg
diff --git a/themes/tabi-lean/static/social_icons/twitter.svg b/sysret.org/themes/tabi-lean/static/social_icons/twitter.svg
index 0778f72..0778f72 100644
--- a/themes/tabi-lean/static/social_icons/twitter.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/twitter.svg
diff --git a/themes/tabi-lean/static/social_icons/vimeo.svg b/sysret.org/themes/tabi-lean/static/social_icons/vimeo.svg
index d98368e..d98368e 100644
--- a/themes/tabi-lean/static/social_icons/vimeo.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/vimeo.svg
diff --git a/themes/tabi-lean/static/social_icons/whatsapp.svg b/sysret.org/themes/tabi-lean/static/social_icons/whatsapp.svg
index d259142..d259142 100644
--- a/themes/tabi-lean/static/social_icons/whatsapp.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/whatsapp.svg
diff --git a/themes/tabi-lean/static/social_icons/wordpress.svg b/sysret.org/themes/tabi-lean/static/social_icons/wordpress.svg
index 807a5ed..807a5ed 100755
--- a/themes/tabi-lean/static/social_icons/wordpress.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/wordpress.svg
diff --git a/themes/tabi-lean/static/social_icons/writefreely.svg b/sysret.org/themes/tabi-lean/static/social_icons/writefreely.svg
index c2bd4fc..c2bd4fc 100755
--- a/themes/tabi-lean/static/social_icons/writefreely.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/writefreely.svg
diff --git a/themes/tabi-lean/static/social_icons/x.svg b/sysret.org/themes/tabi-lean/static/social_icons/x.svg
index f5feed7..f5feed7 100644
--- a/themes/tabi-lean/static/social_icons/x.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/x.svg
diff --git a/themes/tabi-lean/static/social_icons/youtube.svg b/sysret.org/themes/tabi-lean/static/social_icons/youtube.svg
index 287dca2..287dca2 100644
--- a/themes/tabi-lean/static/social_icons/youtube.svg
+++ b/sysret.org/themes/tabi-lean/static/social_icons/youtube.svg
diff --git a/themes/tabi-lean/templates/404.html b/sysret.org/themes/tabi-lean/templates/404.html
index 4c19dac..4c19dac 100644
--- a/themes/tabi-lean/templates/404.html
+++ b/sysret.org/themes/tabi-lean/templates/404.html
diff --git a/themes/tabi-lean/templates/anchor-link.html b/sysret.org/themes/tabi-lean/templates/anchor-link.html
index 254dbe3..254dbe3 100644
--- a/themes/tabi-lean/templates/anchor-link.html
+++ b/sysret.org/themes/tabi-lean/templates/anchor-link.html
diff --git a/themes/tabi-lean/templates/archive.html b/sysret.org/themes/tabi-lean/templates/archive.html
index 637b414..637b414 100644
--- a/themes/tabi-lean/templates/archive.html
+++ b/sysret.org/themes/tabi-lean/templates/archive.html
diff --git a/themes/tabi-lean/templates/atom.xml b/sysret.org/themes/tabi-lean/templates/atom.xml
index 3e5b55c..3e5b55c 100644
--- a/themes/tabi-lean/templates/atom.xml
+++ b/sysret.org/themes/tabi-lean/templates/atom.xml
diff --git a/themes/tabi-lean/templates/base.html b/sysret.org/themes/tabi-lean/templates/base.html
index 56f2a65..56f2a65 100644
--- a/themes/tabi-lean/templates/base.html
+++ b/sysret.org/themes/tabi-lean/templates/base.html
diff --git a/themes/tabi-lean/templates/cards.html b/sysret.org/themes/tabi-lean/templates/cards.html
index 451f6b2..451f6b2 100644
--- a/themes/tabi-lean/templates/cards.html
+++ b/sysret.org/themes/tabi-lean/templates/cards.html
diff --git a/themes/tabi-lean/templates/index.html b/sysret.org/themes/tabi-lean/templates/index.html
index d0dfc01..d0dfc01 100644
--- a/themes/tabi-lean/templates/index.html
+++ b/sysret.org/themes/tabi-lean/templates/index.html
diff --git a/themes/tabi-lean/templates/info-page.html b/sysret.org/themes/tabi-lean/templates/info-page.html
index 077b1a1..077b1a1 100644
--- a/themes/tabi-lean/templates/info-page.html
+++ b/sysret.org/themes/tabi-lean/templates/info-page.html
diff --git a/themes/tabi-lean/templates/internal/alias.html b/sysret.org/themes/tabi-lean/templates/internal/alias.html
index f56f769..f56f769 100644
--- a/themes/tabi-lean/templates/internal/alias.html
+++ b/sysret.org/themes/tabi-lean/templates/internal/alias.html
diff --git a/themes/tabi-lean/templates/macros/feed_utils.html b/sysret.org/themes/tabi-lean/templates/macros/feed_utils.html
index ff35194..ff35194 100644
--- a/themes/tabi-lean/templates/macros/feed_utils.html
+++ b/sysret.org/themes/tabi-lean/templates/macros/feed_utils.html
diff --git a/themes/tabi-lean/templates/macros/format_date.html b/sysret.org/themes/tabi-lean/templates/macros/format_date.html
index f747fd1..f747fd1 100644
--- a/themes/tabi-lean/templates/macros/format_date.html
+++ b/sysret.org/themes/tabi-lean/templates/macros/format_date.html
diff --git a/themes/tabi-lean/templates/macros/list_posts.html b/sysret.org/themes/tabi-lean/templates/macros/list_posts.html
index 2076194..2076194 100644
--- a/themes/tabi-lean/templates/macros/list_posts.html
+++ b/sysret.org/themes/tabi-lean/templates/macros/list_posts.html
diff --git a/themes/tabi-lean/templates/macros/page_header.html b/sysret.org/themes/tabi-lean/templates/macros/page_header.html
index daa8d02..daa8d02 100644
--- a/themes/tabi-lean/templates/macros/page_header.html
+++ b/sysret.org/themes/tabi-lean/templates/macros/page_header.html
diff --git a/themes/tabi-lean/templates/macros/rel_attributes.html b/sysret.org/themes/tabi-lean/templates/macros/rel_attributes.html
index 71672c7..71672c7 100644
--- a/themes/tabi-lean/templates/macros/rel_attributes.html
+++ b/sysret.org/themes/tabi-lean/templates/macros/rel_attributes.html
diff --git a/themes/tabi-lean/templates/macros/series_page.html b/sysret.org/themes/tabi-lean/templates/macros/series_page.html
index d5704a1..d5704a1 100644
--- a/themes/tabi-lean/templates/macros/series_page.html
+++ b/sysret.org/themes/tabi-lean/templates/macros/series_page.html
diff --git a/themes/tabi-lean/templates/macros/settings.html b/sysret.org/themes/tabi-lean/templates/macros/settings.html
index d237d7a..d237d7a 100644
--- a/themes/tabi-lean/templates/macros/settings.html
+++ b/sysret.org/themes/tabi-lean/templates/macros/settings.html
diff --git a/themes/tabi-lean/templates/macros/table_of_contents.html b/sysret.org/themes/tabi-lean/templates/macros/table_of_contents.html
index 18a3ab6..18a3ab6 100644
--- a/themes/tabi-lean/templates/macros/table_of_contents.html
+++ b/sysret.org/themes/tabi-lean/templates/macros/table_of_contents.html
diff --git a/themes/tabi-lean/templates/macros/target_attribute.html b/sysret.org/themes/tabi-lean/templates/macros/target_attribute.html
index 2da5b9d..2da5b9d 100644
--- a/themes/tabi-lean/templates/macros/target_attribute.html
+++ b/sysret.org/themes/tabi-lean/templates/macros/target_attribute.html
diff --git a/themes/tabi-lean/templates/macros/translate.html b/sysret.org/themes/tabi-lean/templates/macros/translate.html
index 1b138dd..1b138dd 100644
--- a/themes/tabi-lean/templates/macros/translate.html
+++ b/sysret.org/themes/tabi-lean/templates/macros/translate.html
diff --git a/themes/tabi-lean/templates/page.html b/sysret.org/themes/tabi-lean/templates/page.html
index 0dff1a7..0dff1a7 100644
--- a/themes/tabi-lean/templates/page.html
+++ b/sysret.org/themes/tabi-lean/templates/page.html
diff --git a/themes/tabi-lean/templates/partials/analytics.html b/sysret.org/themes/tabi-lean/templates/partials/analytics.html
index 6a5d30e..6a5d30e 100644
--- a/themes/tabi-lean/templates/partials/analytics.html
+++ b/sysret.org/themes/tabi-lean/templates/partials/analytics.html
diff --git a/themes/tabi-lean/templates/partials/cards_pages.html b/sysret.org/themes/tabi-lean/templates/partials/cards_pages.html
index 89bdabc..89bdabc 100644
--- a/themes/tabi-lean/templates/partials/cards_pages.html
+++ b/sysret.org/themes/tabi-lean/templates/partials/cards_pages.html
diff --git a/themes/tabi-lean/templates/partials/comments.html b/sysret.org/themes/tabi-lean/templates/partials/comments.html
index 1129055..1129055 100644
--- a/themes/tabi-lean/templates/partials/comments.html
+++ b/sysret.org/themes/tabi-lean/templates/partials/comments.html
diff --git a/themes/tabi-lean/templates/partials/content_security_policy.html b/sysret.org/themes/tabi-lean/templates/partials/content_security_policy.html
index e8fa062..e8fa062 100644
--- a/themes/tabi-lean/templates/partials/content_security_policy.html
+++ b/sysret.org/themes/tabi-lean/templates/partials/content_security_policy.html
diff --git a/themes/tabi-lean/templates/partials/copyright.html b/sysret.org/themes/tabi-lean/templates/partials/copyright.html
index b9cfc01..b9cfc01 100644
--- a/themes/tabi-lean/templates/partials/copyright.html
+++ b/sysret.org/themes/tabi-lean/templates/partials/copyright.html
diff --git a/themes/tabi-lean/templates/partials/extra_features.html b/sysret.org/themes/tabi-lean/templates/partials/extra_features.html
index 50c3337..50c3337 100644
--- a/themes/tabi-lean/templates/partials/extra_features.html
+++ b/sysret.org/themes/tabi-lean/templates/partials/extra_features.html
diff --git a/themes/tabi-lean/templates/partials/filter_card_tags.html b/sysret.org/themes/tabi-lean/templates/partials/filter_card_tags.html
index d40ec2d..d40ec2d 100644
--- a/themes/tabi-lean/templates/partials/filter_card_tags.html
+++ b/sysret.org/themes/tabi-lean/templates/partials/filter_card_tags.html
diff --git a/themes/tabi-lean/templates/partials/footer.html b/sysret.org/themes/tabi-lean/templates/partials/footer.html
index 1a5194f..1a5194f 100644
--- a/themes/tabi-lean/templates/partials/footer.html
+++ b/sysret.org/themes/tabi-lean/templates/partials/footer.html
diff --git a/themes/tabi-lean/templates/partials/hcard.html b/sysret.org/themes/tabi-lean/templates/partials/hcard.html
index 6479da6..6479da6 100644
--- a/themes/tabi-lean/templates/partials/hcard.html
+++ b/sysret.org/themes/tabi-lean/templates/partials/hcard.html
diff --git a/themes/tabi-lean/templates/partials/hcard_small.html b/sysret.org/themes/tabi-lean/templates/partials/hcard_small.html
index f30add5..f30add5 100644
--- a/themes/tabi-lean/templates/partials/hcard_small.html
+++ b/sysret.org/themes/tabi-lean/templates/partials/hcard_small.html
diff --git a/themes/tabi-lean/templates/partials/header.html b/sysret.org/themes/tabi-lean/templates/partials/header.html
index ada1f23..ada1f23 100644
--- a/themes/tabi-lean/templates/partials/header.html
+++ b/sysret.org/themes/tabi-lean/templates/partials/header.html
diff --git a/themes/tabi-lean/templates/partials/history_url.html b/sysret.org/themes/tabi-lean/templates/partials/history_url.html
index 8327ca3..8327ca3 100644
--- a/themes/tabi-lean/templates/partials/history_url.html
+++ b/sysret.org/themes/tabi-lean/templates/partials/history_url.html
diff --git a/themes/tabi-lean/templates/partials/home_banner.html b/sysret.org/themes/tabi-lean/templates/partials/home_banner.html
index 353757b..353757b 100644
--- a/themes/tabi-lean/templates/partials/home_banner.html
+++ b/sysret.org/themes/tabi-lean/templates/partials/home_banner.html
diff --git a/themes/tabi-lean/templates/partials/iine_button.html b/sysret.org/themes/tabi-lean/templates/partials/iine_button.html
index 508fd3a..508fd3a 100644
--- a/themes/tabi-lean/templates/partials/iine_button.html
+++ b/sysret.org/themes/tabi-lean/templates/partials/iine_button.html
diff --git a/themes/tabi-lean/templates/partials/language_switcher.html b/sysret.org/themes/tabi-lean/templates/partials/language_switcher.html
index 83cf61f..83cf61f 100644
--- a/themes/tabi-lean/templates/partials/language_switcher.html
+++ b/sysret.org/themes/tabi-lean/templates/partials/language_switcher.html
diff --git a/themes/tabi-lean/templates/partials/main_page_posts_list.html b/sysret.org/themes/tabi-lean/templates/partials/main_page_posts_list.html
index 067e178..067e178 100644
--- a/themes/tabi-lean/templates/partials/main_page_posts_list.html
+++ b/sysret.org/themes/tabi-lean/templates/partials/main_page_posts_list.html
diff --git a/themes/tabi-lean/templates/partials/main_page_projects_list.html b/sysret.org/themes/tabi-lean/templates/partials/main_page_projects_list.html
index 82f0637..82f0637 100644
--- a/themes/tabi-lean/templates/partials/main_page_projects_list.html
+++ b/sysret.org/themes/tabi-lean/templates/partials/main_page_projects_list.html
diff --git a/themes/tabi-lean/templates/partials/multilingual_tags.html b/sysret.org/themes/tabi-lean/templates/partials/multilingual_tags.html
index fe81e6e..fe81e6e 100644
--- a/themes/tabi-lean/templates/partials/multilingual_tags.html
+++ b/sysret.org/themes/tabi-lean/templates/partials/multilingual_tags.html
diff --git a/themes/tabi-lean/templates/partials/nav.html b/sysret.org/themes/tabi-lean/templates/partials/nav.html
index de55151..de55151 100644
--- a/themes/tabi-lean/templates/partials/nav.html
+++ b/sysret.org/themes/tabi-lean/templates/partials/nav.html
diff --git a/themes/tabi-lean/templates/partials/paginate.html b/sysret.org/themes/tabi-lean/templates/partials/paginate.html
index 6502af7..6502af7 100644
--- a/themes/tabi-lean/templates/partials/paginate.html
+++ b/sysret.org/themes/tabi-lean/templates/partials/paginate.html
diff --git a/themes/tabi-lean/templates/partials/search_modal.html b/sysret.org/themes/tabi-lean/templates/partials/search_modal.html
index a3702d2..a3702d2 100644
--- a/themes/tabi-lean/templates/partials/search_modal.html
+++ b/sysret.org/themes/tabi-lean/templates/partials/search_modal.html
diff --git a/themes/tabi-lean/templates/partials/social_media_images.html b/sysret.org/themes/tabi-lean/templates/partials/social_media_images.html
index d6bbcc7..d6bbcc7 100644
--- a/themes/tabi-lean/templates/partials/social_media_images.html
+++ b/sysret.org/themes/tabi-lean/templates/partials/social_media_images.html
diff --git a/themes/tabi-lean/templates/partials/theme_switcher.html b/sysret.org/themes/tabi-lean/templates/partials/theme_switcher.html
index 2e30f90..2e30f90 100644
--- a/themes/tabi-lean/templates/partials/theme_switcher.html
+++ b/sysret.org/themes/tabi-lean/templates/partials/theme_switcher.html
diff --git a/themes/tabi-lean/templates/partials/title.html b/sysret.org/themes/tabi-lean/templates/partials/title.html
index de77d73..de77d73 100644
--- a/themes/tabi-lean/templates/partials/title.html
+++ b/sysret.org/themes/tabi-lean/templates/partials/title.html
diff --git a/themes/tabi-lean/templates/partials/webmentions.html b/sysret.org/themes/tabi-lean/templates/partials/webmentions.html
index e579a04..e579a04 100644
--- a/themes/tabi-lean/templates/partials/webmentions.html
+++ b/sysret.org/themes/tabi-lean/templates/partials/webmentions.html
diff --git a/themes/tabi-lean/templates/section.html b/sysret.org/themes/tabi-lean/templates/section.html
index 3f2af39..3f2af39 100644
--- a/themes/tabi-lean/templates/section.html
+++ b/sysret.org/themes/tabi-lean/templates/section.html
diff --git a/themes/tabi-lean/templates/series.html b/sysret.org/themes/tabi-lean/templates/series.html
index 5a4cc0c..5a4cc0c 100644
--- a/themes/tabi-lean/templates/series.html
+++ b/sysret.org/themes/tabi-lean/templates/series.html
diff --git a/themes/tabi-lean/templates/shortcodes/add_src_to_code_block.html b/sysret.org/themes/tabi-lean/templates/shortcodes/add_src_to_code_block.html
index 907e092..907e092 100644
--- a/themes/tabi-lean/templates/shortcodes/add_src_to_code_block.html
+++ b/sysret.org/themes/tabi-lean/templates/shortcodes/add_src_to_code_block.html
diff --git a/themes/tabi-lean/templates/shortcodes/admonition.html b/sysret.org/themes/tabi-lean/templates/shortcodes/admonition.html
index 3519527..3519527 100644
--- a/themes/tabi-lean/templates/shortcodes/admonition.html
+++ b/sysret.org/themes/tabi-lean/templates/shortcodes/admonition.html
diff --git a/themes/tabi-lean/templates/shortcodes/aside.html b/sysret.org/themes/tabi-lean/templates/shortcodes/aside.html
index ca337f9..ca337f9 100644
--- a/themes/tabi-lean/templates/shortcodes/aside.html
+++ b/sysret.org/themes/tabi-lean/templates/shortcodes/aside.html
diff --git a/themes/tabi-lean/templates/shortcodes/dimmable_image.html b/sysret.org/themes/tabi-lean/templates/shortcodes/dimmable_image.html
index a72720c..a72720c 100644
--- a/themes/tabi-lean/templates/shortcodes/dimmable_image.html
+++ b/sysret.org/themes/tabi-lean/templates/shortcodes/dimmable_image.html
diff --git a/themes/tabi-lean/templates/shortcodes/dual_theme_image.html b/sysret.org/themes/tabi-lean/templates/shortcodes/dual_theme_image.html
index 5eadc09..5eadc09 100644
--- a/themes/tabi-lean/templates/shortcodes/dual_theme_image.html
+++ b/sysret.org/themes/tabi-lean/templates/shortcodes/dual_theme_image.html
diff --git a/themes/tabi-lean/templates/shortcodes/force_text_direction.html b/sysret.org/themes/tabi-lean/templates/shortcodes/force_text_direction.html
index 79d9697..79d9697 100644
--- a/themes/tabi-lean/templates/shortcodes/force_text_direction.html
+++ b/sysret.org/themes/tabi-lean/templates/shortcodes/force_text_direction.html
diff --git a/themes/tabi-lean/templates/shortcodes/full_width_image.html b/sysret.org/themes/tabi-lean/templates/shortcodes/full_width_image.html
index a50bf10..a50bf10 100644
--- a/themes/tabi-lean/templates/shortcodes/full_width_image.html
+++ b/sysret.org/themes/tabi-lean/templates/shortcodes/full_width_image.html
diff --git a/themes/tabi-lean/templates/shortcodes/iine.html b/sysret.org/themes/tabi-lean/templates/shortcodes/iine.html
index d37211d..d37211d 100644
--- a/themes/tabi-lean/templates/shortcodes/iine.html
+++ b/sysret.org/themes/tabi-lean/templates/shortcodes/iine.html
diff --git a/themes/tabi-lean/templates/shortcodes/image_hover.html b/sysret.org/themes/tabi-lean/templates/shortcodes/image_hover.html
index 443329b..443329b 100644
--- a/themes/tabi-lean/templates/shortcodes/image_hover.html
+++ b/sysret.org/themes/tabi-lean/templates/shortcodes/image_hover.html
diff --git a/themes/tabi-lean/templates/shortcodes/image_toggler.html b/sysret.org/themes/tabi-lean/templates/shortcodes/image_toggler.html
index 991d5f5..991d5f5 100644
--- a/themes/tabi-lean/templates/shortcodes/image_toggler.html
+++ b/sysret.org/themes/tabi-lean/templates/shortcodes/image_toggler.html
diff --git a/themes/tabi-lean/templates/shortcodes/invertible_image.html b/sysret.org/themes/tabi-lean/templates/shortcodes/invertible_image.html
index 0e3c920..0e3c920 100644
--- a/themes/tabi-lean/templates/shortcodes/invertible_image.html
+++ b/sysret.org/themes/tabi-lean/templates/shortcodes/invertible_image.html
diff --git a/themes/tabi-lean/templates/shortcodes/mermaid.html b/sysret.org/themes/tabi-lean/templates/shortcodes/mermaid.html
index 88bbdc4..88bbdc4 100644
--- a/themes/tabi-lean/templates/shortcodes/mermaid.html
+++ b/sysret.org/themes/tabi-lean/templates/shortcodes/mermaid.html
diff --git a/themes/tabi-lean/templates/shortcodes/multilingual_quote.html b/sysret.org/themes/tabi-lean/templates/shortcodes/multilingual_quote.html
index 7ea9849..7ea9849 100644
--- a/themes/tabi-lean/templates/shortcodes/multilingual_quote.html
+++ b/sysret.org/themes/tabi-lean/templates/shortcodes/multilingual_quote.html
diff --git a/themes/tabi-lean/templates/shortcodes/references.html b/sysret.org/themes/tabi-lean/templates/shortcodes/references.html
index 1894479..1894479 100644
--- a/themes/tabi-lean/templates/shortcodes/references.html
+++ b/sysret.org/themes/tabi-lean/templates/shortcodes/references.html
diff --git a/themes/tabi-lean/templates/shortcodes/remote_text.html b/sysret.org/themes/tabi-lean/templates/shortcodes/remote_text.html
index 70fd33a..70fd33a 100644
--- a/themes/tabi-lean/templates/shortcodes/remote_text.html
+++ b/sysret.org/themes/tabi-lean/templates/shortcodes/remote_text.html
diff --git a/themes/tabi-lean/templates/shortcodes/spoiler.html b/sysret.org/themes/tabi-lean/templates/shortcodes/spoiler.html
index ff9e695..ff9e695 100644
--- a/themes/tabi-lean/templates/shortcodes/spoiler.html
+++ b/sysret.org/themes/tabi-lean/templates/shortcodes/spoiler.html
diff --git a/themes/tabi-lean/templates/shortcodes/toc.html b/sysret.org/themes/tabi-lean/templates/shortcodes/toc.html
index 8756586..8756586 100644
--- a/themes/tabi-lean/templates/shortcodes/toc.html
+++ b/sysret.org/themes/tabi-lean/templates/shortcodes/toc.html
diff --git a/themes/tabi-lean/templates/shortcodes/wide_container.html b/sysret.org/themes/tabi-lean/templates/shortcodes/wide_container.html
index 6268e63..6268e63 100644
--- a/themes/tabi-lean/templates/shortcodes/wide_container.html
+++ b/sysret.org/themes/tabi-lean/templates/shortcodes/wide_container.html
diff --git a/themes/tabi-lean/templates/sitemap.xml b/sysret.org/themes/tabi-lean/templates/sitemap.xml
index 480759f..480759f 100644
--- a/themes/tabi-lean/templates/sitemap.xml
+++ b/sysret.org/themes/tabi-lean/templates/sitemap.xml
diff --git a/themes/tabi-lean/templates/tags/list.html b/sysret.org/themes/tabi-lean/templates/tags/list.html
index 7b5e468..7b5e468 100644
--- a/themes/tabi-lean/templates/tags/list.html
+++ b/sysret.org/themes/tabi-lean/templates/tags/list.html
diff --git a/themes/tabi-lean/templates/tags/single.html b/sysret.org/themes/tabi-lean/templates/tags/single.html
index 2f25fd2..2f25fd2 100644
--- a/themes/tabi-lean/templates/tags/single.html
+++ b/sysret.org/themes/tabi-lean/templates/tags/single.html
diff --git a/themes/tabi-lean/templates/taxonomy_list.html b/sysret.org/themes/tabi-lean/templates/taxonomy_list.html
index b13e1b9..b13e1b9 100644
--- a/themes/tabi-lean/templates/taxonomy_list.html
+++ b/sysret.org/themes/tabi-lean/templates/taxonomy_list.html
diff --git a/themes/tabi-lean/templates/taxonomy_single.html b/sysret.org/themes/tabi-lean/templates/taxonomy_single.html
index ff09a3b..ff09a3b 100644
--- a/themes/tabi-lean/templates/taxonomy_single.html
+++ b/sysret.org/themes/tabi-lean/templates/taxonomy_single.html
diff --git a/themes/tabi-lean/theme.toml b/sysret.org/themes/tabi-lean/theme.toml
index a096a83..a096a83 100644
--- a/themes/tabi-lean/theme.toml
+++ b/sysret.org/themes/tabi-lean/theme.toml