From cea6896788a42c0ea40f99deb4b5987d6741e360 Mon Sep 17 00:00:00 2001 From: Emile Date: Fri, 16 Aug 2024 23:33:53 +0200 Subject: big dump, forgot to commit... --- flake.lock | 32 +- flake.nix | 1 + nix/hosts/caladan/darwin-configuration.nix | 4 +- nix/hosts/caladan/home_emile.nix | 6 + nix/hosts/corrino/configuration.nix | 14 +- ...dicated-wipe-and-install-nixos-luks-raid-lvm.sh | 347 ++++++++ nix/hosts/corrino/ports.nix | 10 +- nix/hosts/corrino/www/ctf.emile.space.nix | 2 +- nix/hosts/corrino/www/emile.space.nix | 4 + nix/hosts/corrino/www/git/cgit.nix | 8 +- nix/hosts/corrino/www/md.emile.space.nix | 8 - nix/hosts/corrino/www/photo.emile.space.nix | 33 - nix/hosts/corrino/www/photo/default.nix | 8 + nix/hosts/corrino/www/photo/photoprism.nix | 33 + nix/hosts/corrino/www/r2wa.rs.nix | 29 +- nix/hosts/corrino/www/social.emile.space.nix | 7 + nix/hosts/corrino/www/sso.emile.space.nix | 2 +- nix/hosts/gamont/README.md | 3 + nix/hosts/gamont/configuration.nix | 127 +++ nix/hosts/lampadas/configuration.nix | 5 + nix/hosts/lernaeus/configuration.nix | 4 + nix/hosts/pi1/result | 1 + nix/hosts/pi2/default.nix | 47 ++ nix/hosts/pi2/result | 1 + nix/modules/default.nix | 1 + nix/modules/r2wars-web/default.nix | 73 ++ nix/pkgs/overlay.nix | 3 +- nix/pkgs/r2wars-web/default.nix | 31 + nix/pkgs/vokobe/.gitignore | 7 + nix/pkgs/vokobe/Cargo.lock | 270 ++++++ nix/pkgs/vokobe/Cargo.toml | 10 + nix/pkgs/vokobe/LICENSE | 21 + nix/pkgs/vokobe/README.md | 101 +++ nix/pkgs/vokobe/default.nix | 16 + nix/pkgs/vokobe/flaaaaake.nix | 44 + nix/pkgs/vokobe/src/main.rs | 922 +++++++++++++++++++++ web/vokobe/.gitignore | 7 - web/vokobe/Cargo.lock | 270 ------ web/vokobe/Cargo.toml | 10 - web/vokobe/LICENSE | 21 - web/vokobe/README.md | 101 --- web/vokobe/default.nix | 16 - web/vokobe/flaaaaake.nix | 44 - web/vokobe/src/main.rs | 922 --------------------- 44 files changed, 2166 insertions(+), 1460 deletions(-) create mode 100755 nix/hosts/corrino/hetzner-dedicated-wipe-and-install-nixos-luks-raid-lvm.sh delete mode 100644 nix/hosts/corrino/www/photo.emile.space.nix create mode 100644 nix/hosts/corrino/www/photo/default.nix create mode 100644 nix/hosts/corrino/www/photo/photoprism.nix create mode 100644 nix/hosts/gamont/README.md create mode 100644 nix/hosts/gamont/configuration.nix create mode 120000 nix/hosts/pi1/result create mode 100644 nix/hosts/pi2/default.nix create mode 120000 nix/hosts/pi2/result create mode 100644 nix/modules/r2wars-web/default.nix create mode 100644 nix/pkgs/r2wars-web/default.nix create mode 100644 nix/pkgs/vokobe/.gitignore create mode 100644 nix/pkgs/vokobe/Cargo.lock create mode 100644 nix/pkgs/vokobe/Cargo.toml create mode 100644 nix/pkgs/vokobe/LICENSE create mode 100644 nix/pkgs/vokobe/README.md create mode 100644 nix/pkgs/vokobe/default.nix create mode 100644 nix/pkgs/vokobe/flaaaaake.nix create mode 100644 nix/pkgs/vokobe/src/main.rs delete mode 100644 web/vokobe/.gitignore delete mode 100644 web/vokobe/Cargo.lock delete mode 100644 web/vokobe/Cargo.toml delete mode 100644 web/vokobe/LICENSE delete mode 100644 web/vokobe/README.md delete mode 100644 web/vokobe/default.nix delete mode 100644 web/vokobe/flaaaaake.nix delete mode 100644 web/vokobe/src/main.rs diff --git a/flake.lock b/flake.lock index baead9f..3893592 100644 --- a/flake.lock +++ b/flake.lock @@ -10,11 +10,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1722339003, - "narHash": "sha256-ZeS51uJI30ehNkcZ4uKqT4ZDARPyqrHADSKAwv5vVCU=", + "lastModified": 1723293904, + "narHash": "sha256-b+uqzj+Wa6xgMS9aNbX4I+sXeb5biPDi39VgvSFqFvU=", "ref": "refs/heads/main", - "rev": "3f1dae074a12feb7327b4bf43cbac0d124488bb7", - "revCount": 312, + "rev": "f6291c5935fdc4e0bef208cfc0dcab7e3f7a1c41", + "revCount": 314, "type": "git", "url": "https://github.com/ryantm/agenix" }, @@ -52,11 +52,11 @@ ] }, "locked": { - "lastModified": 1722609272, - "narHash": "sha256-Kkb+ULEHVmk07AX+OhwyofFxBDpw+2WvsXguUS2m6e4=", + "lastModified": 1722924007, + "narHash": "sha256-+CQDamNwqO33REJLft8c26NbUi2Td083hq6SvAm2xkU=", "ref": "refs/heads/master", - "rev": "f7142b8024d6b70c66fd646e1d099d3aa5bfec49", - "revCount": 1663, + "rev": "91010a5613ffd7ee23ee9263213157a1c422b705", + "revCount": 1665, "type": "git", "url": "https://github.com/lnl7/nix-darwin" }, @@ -183,11 +183,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1722621932, - "narHash": "sha256-Uz5xeHsH7+qZVncZwfzGd+CTjxd0mwaP7Q/pbs7OB5c=", + "lastModified": 1723449574, + "narHash": "sha256-9c/blnpryB8JYUZDt8ePD9HxWfJgVKyd8gZX80H8DnI=", "ref": "release-24.05", - "rev": "15ed5d4537fd46399513bb040bf98415c825281b", - "revCount": 633688, + "rev": "1e6169f8966165bf2320fb5d1df605558902e4cf", + "revCount": 634030, "type": "git", "url": "https://github.com/nixos/nixpkgs" }, @@ -199,11 +199,11 @@ }, "nixpkgs-unstable": { "locked": { - "lastModified": 1722415718, - "narHash": "sha256-5US0/pgxbMksF92k1+eOa8arJTJiPvsdZj9Dl+vJkM4=", + "lastModified": 1723221148, + "narHash": "sha256-7pjpeQlZUNQ4eeVntytU3jkw9dFK3k1Htgk2iuXjaD8=", "ref": "nixpkgs-unstable", - "rev": "c3392ad349a5227f4a3464dce87bcc5046692fce", - "revCount": 660607, + "rev": "154bcb95ad51bc257c2ce4043a725de6ca700ef6", + "revCount": 664329, "type": "git", "url": "https://github.com/nixos/nixpkgs" }, diff --git a/flake.nix b/flake.nix index b17cb78..411bf42 100644 --- a/flake.nix +++ b/flake.nix @@ -157,6 +157,7 @@ in { inherit (pkgs) vokobe + r2wars-web # emu-riscv # emu-mips # emu-x86_64 diff --git a/nix/hosts/caladan/darwin-configuration.nix b/nix/hosts/caladan/darwin-configuration.nix index c681b35..a181b35 100644 --- a/nix/hosts/caladan/darwin-configuration.nix +++ b/nix/hosts/caladan/darwin-configuration.nix @@ -42,12 +42,14 @@ trusted-users = [ "root" "hydra" "emile" ]; trusted-public-keys = [ - "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=" + "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" + "cache.garnix.io:CTFPyKSLcx5RMJKfLo5EEPUObbA78b0YQ2DTCJXqr9g=" ]; substituters = [ "https://cache.nixos.org" "https://nix-community.cachix.org" + "https://cache.garnix.io" ]; experimental-features = [ "nix-command" "flakes" ]; diff --git a/nix/hosts/caladan/home_emile.nix b/nix/hosts/caladan/home_emile.nix index a7009ab..f57daaf 100644 --- a/nix/hosts/caladan/home_emile.nix +++ b/nix/hosts/caladan/home_emile.nix @@ -165,6 +165,7 @@ # c foo cmake + pkg-config # iot hack foo minicom @@ -180,13 +181,18 @@ virt-manager # lisp foo + #unstable.sbcl # sbcl + #clasp-common-lisp + clisp # infrastructure as code foo terraform ansible portmidi + tiny # irc + # blender # ] ++ lib.optionals stdenv.isDarwin [ diff --git a/nix/hosts/corrino/configuration.nix b/nix/hosts/corrino/configuration.nix index d23b6bf..1f054ff 100644 --- a/nix/hosts/corrino/configuration.nix +++ b/nix/hosts/corrino/configuration.nix @@ -25,7 +25,10 @@ in { ./www/hydra.emile.space.nix ./www/netbox.emile.space.nix ./www/grafana.emile.space.nix - ./www/photo.emile.space.nix + + # ./www/photo.emile.space.nix + # ./www/photo + ./www/tickets.emile.space.nix ./www/talks.emile.space.nix ./www/stream.emile.space.nix @@ -34,6 +37,9 @@ in { ./www/sso.emile.space.nix ./www/s3.emile.space.nix + # ./www/irc.emile.space.nix + # ./www/irc + ./www/ctf.emile.space.nix # ./www/magic-hash.emile.space.nix @@ -450,8 +456,12 @@ in { }; }; + virtualisation.podman = { + enable = true; + autoPrune.enable = true; + }; virtualisation = { - docker.enable = true; + # docker.enable = true; libvirtd = { enable = true; qemu = { diff --git a/nix/hosts/corrino/hetzner-dedicated-wipe-and-install-nixos-luks-raid-lvm.sh b/nix/hosts/corrino/hetzner-dedicated-wipe-and-install-nixos-luks-raid-lvm.sh new file mode 100755 index 0000000..de42261 --- /dev/null +++ b/nix/hosts/corrino/hetzner-dedicated-wipe-and-install-nixos-luks-raid-lvm.sh @@ -0,0 +1,347 @@ +#!/usr/bin/env bash + +# Installs NixOS on a Hetzner server, wiping the server. +# +# This is for a specific server configuration; adjust where needed. +# +# Prerequisites: +# * Update the script wherever FIXME is present +# +# Usage: +# ssh root@YOUR_SERVERS_IP bash -s < hetzner-dedicated-wipe-and-install-nixos.sh +# +# When the script is done, make sure to boot the server from HD, not rescue mode again. + +# Explanations: +# +# * Adapted from https://gist.github.com/nh2/78d1c65e33806e7728622dbe748c2b6a +# * Following largely https://nixos.org/nixos/manual/index.html#sec-installing-from-other-distro. +# * **Important:** We boot in legacy-BIOS mode, not UEFI, because that's what Hetzner uses. +# * NVMe devices aren't supported for booting (those require EFI boot) +# * We set a custom `configuration.nix` so that we can connect to the machine afterwards, +# inspired by https://nixos.wiki/wiki/Install_NixOS_on_Hetzner_Online +# * This server has 2 HDDs. +# We put everything on RAID1. +# Storage scheme: `partitions -> RAID -> LVM -> ext4`. +# * A root user with empty password is created, so that you can just login +# as root and press enter when using the Hetzner spider KVM. +# Of course that empty-password login isn't exposed to the Internet. +# Change the password afterwards to avoid anyone with physical access +# being able to login without any authentication. +# * The script reboots at the end. + +NIXOS_VERSION="22.11" + +echo "Enter New Hostname" +HOSTNAME="corrino" + +echo "Enter LUKS Password" +LUKS_PASSWORD="FIXME" + +set -eu +set -o pipefail + +set -x + +# Inspect existing disks +lsblk + +# Undo existing setups to allow running the script multiple times to iterate on it. +# We allow these operations to fail for the case the script runs the first time. +set +e +umount /mnt/boot /mnt/dev /mnt/proc /mnt/run /mnt/sys /mnt +vgchange -an +cryptsetup close luks0 +rm initrd_ssh_host_ecdsa_key +set -e + +# Stop all mdadm arrays that the boot may have activated. +mdadm --stop --scan + +# Prevent mdadm from auto-assembling arrays. +# Otherwise, as soon as we create the partition tables below, it will try to +# re-assemple a previous RAID if any remaining RAID signatures are present, +# before we even get the chance to wipe them. +# From: +# https://unix.stackexchange.com/questions/166688/prevent-debian-from-auto-assembling-raid-at-boot/504035#504035 +# We use `>` because the file may already contain some detected RAID arrays, +# which would take precedence over our ``. +echo 'AUTO -all +ARRAY UUID=00000000:00000000:00000000:00000000' > /etc/mdadm/mdadm.conf + +# Create partition tables (--script to not ask) +parted --script /dev/nvme0n1 mklabel gpt +parted --script /dev/nvme1n1 mklabel gpt + +# Create partitions (--script to not ask) +# +# We create the 1MB BIOS boot partition at the front. +# +# Note we use "MB" instead of "MiB" because otherwise `--align optimal` has no effect; +# as per documentation https://www.gnu.org/software/parted/manual/html_node/unit.html#unit: +# > Note that as of parted-2.4, when you specify start and/or end values using IEC +# > binary units like "MiB", "GiB", "TiB", etc., parted treats those values as exact +# +# Note: When using `mkpart` on GPT, as per +# https://www.gnu.org/software/parted/manual/html_node/mkpart.html#mkpart +# the first argument to `mkpart` is not a `part-type`, but the GPT partition name: +# ... part-type is one of 'primary', 'extended' or 'logical', and may be specified only with 'msdos' or 'dvh' partition tables. +# A name must be specified for a 'gpt' partition table. +# GPT partition names are limited to 36 UTF-16 chars, see https://en.wikipedia.org/wiki/GUID_Partition_Table#Partition_entries_(LBA_2-33). +parted --script --align optimal /dev/nvme0n1 -- mklabel gpt mkpart 'bios' 1MB 2MB set 1 bios_grub on mkpart 'boot' 2MB 1000MB mkpart 'root' 1000MB '100%' +parted --script --align optimal /dev/nvme1n1 -- mklabel gpt mkpart 'bios' 1MB 2MB set 1 bios_grub on mkpart 'boot' 2MB 1000MB mkpart 'root' 1000MB '100%' + +# Relaod partitions +partprobe + +# Wait for all devices to exist +udevadm settle --timeout=5 --exit-if-exists=/dev/nvme0n1p1 +udevadm settle --timeout=5 --exit-if-exists=/dev/nvme0n1p2 +udevadm settle --timeout=5 --exit-if-exists=/dev/nvme0n1p3 + +udevadm settle --timeout=5 --exit-if-exists=/dev/nvme1n1p1 +udevadm settle --timeout=5 --exit-if-exists=/dev/nvme1n1p2 +udevadm settle --timeout=5 --exit-if-exists=/dev/nvme1n1p3 + +# Wipe any previous RAID signatures +mdadm --zero-superblock --force /dev/nvme0n1p2 +mdadm --zero-superblock --force /dev/nvme0n1p3 +mdadm --zero-superblock --force /dev/nvme1n1p2 +mdadm --zero-superblock --force /dev/nvme1n1p3 + +# Create RAIDs +# Note that during creating and boot-time assembly, mdadm cares about the +# host name, and the existence and contents of `mdadm.conf`! +# This also affects the names appearing in /dev/md/ being different +# before and after reboot in general (but we take extra care here +# to pass explicit names, and set HOMEHOST for the rebooting system further +# down, so that the names appear the same). +# Almost all details of this are explained in +# https://bugzilla.redhat.com/show_bug.cgi?id=606481#c14 +# and the followup comments by Doug Ledford. +#mdadm --create --run --verbose /dev/md0 --level=1 --raid-devices=2 --homehost=lxc11 --name=root0 /dev/nvme0n1p2 /dev/nvme1n1p2 +mdadm --create --run --verbose /dev/md0 --level=1 --raid-devices=2 --homehost=$HOSTNAME --name=md0 /dev/nvme0n1p2 /dev/nvme1n1p2 +mdadm --create --run --verbose /dev/md1 --level=1 --raid-devices=2 --homehost=$HOSTNAME --name=md1 /dev/nvme0n1p3 /dev/nvme1n1p3 + +# Assembling the RAID can result in auto-activation of previously-existing LVM +# groups, preventing the RAID block device wiping below with +# `Device or resource busy`. So disable all VGs first. +vgchange -an + +# Wipe filesystem signatures that might be on the RAID from some +# possibly existing older use of the disks (RAID creation does not do that). +# See https://serverfault.com/questions/911370/why-does-mdadm-zero-superblock-preserve-file-system-information +wipefs -a /dev/md0 +wipefs -a /dev/md1 + +# Disable RAID recovery. We don't want this to slow down machine provisioning +# in the rescue mode. It can run in normal operation after reboot. +echo 0 > /proc/sys/dev/raid/speed_limit_max + +# LUKS +echo "$LUKS_PASSWORD" | cryptsetup luksFormat --type luks2 -h sha512 /dev/md1 +echo "$LUKS_PASSWORD" | cryptsetup luksOpen /dev/md1 luks0 + +# LVM +# PVs +pvcreate /dev/mapper/luks0 +#pvcreate /dev/md0 + +# VGs +#vgcreate vg0 /dev/md0 +vgcreate vg0 /dev/mapper/luks0 + +# LVs (--yes to automatically wipe detected file system signatures) +lvcreate --yes --extents 95%FREE -n root vg0 # 5% slack space + +# Filesystems (-F to not ask on preexisting FS) +mkfs.ext4 -F -L boot /dev/md0 +mkfs.ext4 -F -L root /dev/vg0/root + +# Creating file systems changes their UUIDs. +# Trigger udev so that the entries in /dev/disk/by-uuid get refreshed. +# `nixos-generate-config` depends on those being up-to-date. +# See https://github.com/NixOS/nixpkgs/issues/62444 +udevadm trigger + +# Wait for FS labels to appear +udevadm settle --timeout=5 --exit-if-exists=/dev/disk/by-label/boot +udevadm settle --timeout=5 --exit-if-exists=/dev/disk/by-label/root + +# NixOS pre-installation mounts + +# Mount target root partition +mount /dev/disk/by-label/root /mnt +mkdir /mnt/boot +mount /dev/disk/by-label/boot /mnt/boot + +# Installing nix + +# Installing nix requires `sudo`; the Hetzner rescue mode doesn't have it. +apt-get install -y sudo + +# Allow installing nix as root, see +# https://github.com/NixOS/nix/issues/936#issuecomment-475795730 +mkdir -p /etc/nix +echo "build-users-group =" > /etc/nix/nix.conf + +curl -L https://nixos.org/nix/install | sh +set +u +x # sourcing this may refer to unset variables that we have no control over +. $HOME/.nix-profile/etc/profile.d/nix.sh +set -u -x + +# FIXME Keep in sync with `system.stateVersion` set below! +nix-channel --add https://nixos.org/channels/nixos-$NIXOS_VERSION nixpkgs +nix-channel --update + +# Getting NixOS installation tools +nix-env -iE "_: with import { configuration = {}; }; with config.system.build; [ nixos-generate-config nixos-install nixos-enter manual.manpages ]" + +nixos-generate-config --root /mnt + +# Find the name of the network interface that connects us to the Internet. +# Inspired by https://unix.stackexchange.com/questions/14961/how-to-find-out-which-interface-am-i-using-for-connecting-to-the-internet/302613#302613 +RESCUE_INTERFACE=$(ip route get 8.8.8.8 | grep -Po '(?<=dev )(\S+)') + +# Find what its name will be under NixOS, which uses stable interface names. +# See https://major.io/2015/08/21/understanding-systemds-predictable-network-device-names/#comment-545626 +# NICs for most Hetzner servers are not onboard, which is why we use +# `ID_NET_NAME_PATH`otherwise it would be `ID_NET_NAME_ONBOARD`. +INTERFACE_DEVICE_PATH=$(udevadm info -e | grep -Po "(?<=^P: )(.*${RESCUE_INTERFACE})") +UDEVADM_PROPERTIES_FOR_INTERFACE=$(udevadm info --query=property "--path=$INTERFACE_DEVICE_PATH") +NIXOS_INTERFACE=$(echo "$UDEVADM_PROPERTIES_FOR_INTERFACE" | grep -o -E 'ID_NET_NAME_PATH=\w+' | cut -d= -f2) +echo "Determined NIXOS_INTERFACE as '$NIXOS_INTERFACE'" +# DOESNT WORK on PX server there it was eno1 + +IP_V4=$(ip route get 8.8.8.8 | grep -Po '(?<=src )(\S+)') +echo "Determined IP_V4 as $IP_V4" + +# Determine Internet IPv6 by checking route, and using ::1 +# (because Hetzner rescue mode uses ::2 by default). +# The `ip -6 route get` output on Hetzner looks like: +# # ip -6 route get 2001:4860:4860:0:0:0:0:8888 +# 2001:4860:4860::8888 via fe80::1 dev eth0 src 2a01:4f8:151:62aa::2 metric 1024 pref medium +IP_V6="$(ip route get 2001:4860:4860:0:0:0:0:8888 | head -1 | cut -d' ' -f7 | cut -d: -f1-4)::1" +echo "Determined IP_V6 as $IP_V6" + + +# From https://stackoverflow.com/questions/1204629/how-do-i-get-the-default-gateway-in-linux-given-the-destination/15973156#15973156 +read _ _ DEFAULT_GATEWAY _ < <(ip route list match 0/0); echo "$DEFAULT_GATEWAY" +echo "Determined DEFAULT_GATEWAY as $DEFAULT_GATEWAY" + +# Generate `configuration.nix`. Note that we splice in shell variables. +cat > /mnt/etc/nixos/configuration.nix <> /root/.profile + ''; + }; + boot.kernelParams = [ "ip=$IP_V4::$DEFAULT_GATEWAY:255.255.255.192:$HOSTNAME:$NIXOS_INTERFACE:off:8.8.8.8:8.8.4.4:" ]; + boot.loader.supportsInitrdSecrets = true; + boot.initrd.luks.forceLuksSupportInInitrd = true; + boot.initrd.luks.devices = { + root = { + preLVM = true; + device = "/dev/md1"; + allowDiscards = true; + }; + }; + + boot.initrd.secrets = { + "/initrd_ssh_host_ecdsa_key" = "/initrd_ssh_host_ecdsa_key"; + }; + # The mdadm RAID1s were created with 'mdadm --create ... --homehost=hetzner', + # but the hostname for each machine may be different, and mdadm's HOMEHOST + # setting defaults to '' (using the system hostname). + # This results mdadm considering such disks as "foreign" as opposed to + # "local", and showing them as e.g. '/dev/md/hetzner:root0' + # instead of '/dev/md/root0'. + # This is mdadm's protection against accidentally putting a RAID disk + # into the wrong machine and corrupting data by accidental sync, see + # https://bugzilla.redhat.com/show_bug.cgi?id=606481#c14 and onward. + # We do not worry about plugging disks into the wrong machine because + # we will never exchange disks between machines, so we tell mdadm to + # ignore the homehost entirely. + environment.etc."mdadm.conf".text = '' + HOMEHOST + ''; + # The RAIDs are assembled in stage1, so we need to make the config + # available there. + boot.initrd.services.swraid.mdadmConf = config.environment.etc."mdadm.conf".text; + # Network (Hetzner uses static IP assignments, and we don't use DHCP here) + networking.useDHCP = false; + networking.interfaces."$NIXOS_INTERFACE".ipv4.addresses = [ + { + address = "$IP_V4"; + + # FIXME Lookup for right netmask prefix length within rescu system + prefixLength = 26; + } + ]; + networking.interfaces."$NIXOS_INTERFACE".ipv6.addresses = [ + { + address = "$IP_V6"; + prefixLength = 64; + } + ]; + networking.defaultGateway = "$DEFAULT_GATEWAY"; + networking.defaultGateway6 = { address = "fe80::1"; interface = "$NIXOS_INTERFACE"; }; + networking.nameservers = [ "8.8.8.8" "8.8.4.4" ]; + # Initial empty root password for easy login: + users.users.root.initialHashedPassword = ""; + services.openssh.permitRootLogin = "prohibit-password"; + users.users.root.openssh.authorizedKeys.keys = [ + # FIXME Replace this by your SSH pubkey! + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPZi43zHEsoWaQomLGaftPE5k0RqVrZyiTtGqZlpWsew" + ]; + services.openssh.enable = true; + + # FIXME + # This value determines the NixOS release with which your system is to be + # compatible, in order to avoid breaking some software such as database + # servers. You should change this only after NixOS release notes say you + # should. + system.stateVersion = "$NIXOS_VERSION"; # Did you read the comment? +} +EOF + +ssh-keygen -t ecdsa -N "" -f initrd_ssh_host_ecdsa_key; +cp initrd_ssh_host_ecdsa_key /mnt/initrd_ssh_host_ecdsa_key; + +# Install NixOS +PATH="$PATH" `which nixos-install` --no-root-passwd --root /mnt --max-jobs 40 + +umount /mnt/boot +umount /mnt + +echo "DONE" diff --git a/nix/hosts/corrino/ports.nix b/nix/hosts/corrino/ports.nix index 6be514d..2d7ba06 100644 --- a/nix/hosts/corrino/ports.nix +++ b/nix/hosts/corrino/ports.nix @@ -2,15 +2,23 @@ emile.ports = { stream_rtmp = 1935; initrd_ssh = 2222; - photo = 2342; + photo = { + photoprism = 2342; + immich = 2343; + }; git = 3000; hydra = 3001; grafana = 3002; md = 3003; gotosocial = 3004; + irc = { + clear = 6667; + ssl = 6697; + }; stream = 8080; netbox = 8001; restic = 8002; + r2wars-web = 8089; ctf = 8338; magic-hash = 8339; tickets = 8349; diff --git a/nix/hosts/corrino/www/ctf.emile.space.nix b/nix/hosts/corrino/www/ctf.emile.space.nix index 1d8b382..6eee75f 100644 --- a/nix/hosts/corrino/www/ctf.emile.space.nix +++ b/nix/hosts/corrino/www/ctf.emile.space.nix @@ -13,7 +13,7 @@ }; virtualisation.oci-containers = { - backend = "docker"; + # backend = "docker"; containers = { "ctfd" = { image = "ctfd/ctfd"; diff --git a/nix/hosts/corrino/www/emile.space.nix b/nix/hosts/corrino/www/emile.space.nix index 9cca880..c39ca31 100644 --- a/nix/hosts/corrino/www/emile.space.nix +++ b/nix/hosts/corrino/www/emile.space.nix @@ -13,6 +13,10 @@ ''; }; + "/@hanemile".extraConfig = '' + return 301 https://social.emile.space/@hanemile; + ''; + #"/.well-known" = { # root = "/var/www/emile.space"; # extraConfig = '' diff --git a/nix/hosts/corrino/www/git/cgit.nix b/nix/hosts/corrino/www/git/cgit.nix index e6983e5..1e63dfc 100644 --- a/nix/hosts/corrino/www/git/cgit.nix +++ b/nix/hosts/corrino/www/git/cgit.nix @@ -72,6 +72,12 @@ section = "Radare2"; owner = "emile"; }; + r2wars-web = { + desc = "The software behind https://r2wa.rs"; + path = "/var/lib/git/repositories/r2wars-web.git"; + section = "Radare2"; + owner = "emile"; + }; r2wars-rs = { desc = "A rust implementation of radare2"; path = "/var/lib/git/repositories/r2wars-rs.git"; @@ -538,7 +544,7 @@ # exposing stuff gitDaemon = { - enable = false; + enable = true; user = "git"; group = "git"; diff --git a/nix/hosts/corrino/www/md.emile.space.nix b/nix/hosts/corrino/www/md.emile.space.nix index 7ad7a94..52b4a53 100644 --- a/nix/hosts/corrino/www/md.emile.space.nix +++ b/nix/hosts/corrino/www/md.emile.space.nix @@ -4,17 +4,9 @@ services.nginx.virtualHosts."md.emile.space" = { forceSSL = true; enableACME = true; - - # TODO(emile): figure out why this doesn't work when enabled, has to do with authelia - # extraConfig = authelia-location; - locations = { "/" = { - # proxyPass = "http://127.0.0.1:3003"; proxyPass = "http://127.0.0.1:${toString config.services.hedgedoc.settings.port}"; - - # TODO(emile): figure out why this doesn't work when enabled, has to do with authelia - # extraConfig = authelia-authrequest; }; }; }; diff --git a/nix/hosts/corrino/www/photo.emile.space.nix b/nix/hosts/corrino/www/photo.emile.space.nix deleted file mode 100644 index 9c1e97a..0000000 --- a/nix/hosts/corrino/www/photo.emile.space.nix +++ /dev/null @@ -1,33 +0,0 @@ -{ config, ... }: - -{ - services.nginx.virtualHosts."photo.emile.space" = { - forceSSL = true; - enableACME = true; - - locations = { - "/" = { - proxyPass = "http://127.0.0.1:${toString config.services.photoprism.port}"; - proxyWebsockets = true; - }; - }; - }; - - services.photoprism = { - enable = true; - - address = "127.0.0.1"; - port = config.emile.ports.photo; - - passwordFile = config.age.secrets.photoprism_password.path; - - # originalsPath = "/data/photos"; - originalsPath = "/mnt/storagebox-bx11/photos"; - - settings = { - PHOTOPRISM_ADMIN_USER = "root"; - PHOTOPRISM_DEFAULT_LOCALE = "en"; - PHOTOPRISM_SITE_URL = "https://photo.emile.space"; - }; - }; -} diff --git a/nix/hosts/corrino/www/photo/default.nix b/nix/hosts/corrino/www/photo/default.nix new file mode 100644 index 0000000..dd555e4 --- /dev/null +++ b/nix/hosts/corrino/www/photo/default.nix @@ -0,0 +1,8 @@ +{ ... }: + +{ + imports = [ + ./photoprism.nix + # ./immich.nix + ]; +} diff --git a/nix/hosts/corrino/www/photo/photoprism.nix b/nix/hosts/corrino/www/photo/photoprism.nix new file mode 100644 index 0000000..c1cbbf8 --- /dev/null +++ b/nix/hosts/corrino/www/photo/photoprism.nix @@ -0,0 +1,33 @@ +{ config, ... }: + +{ + services.nginx.virtualHosts."photo.emile.space" = { + forceSSL = true; + enableACME = true; + + locations = { + "/" = { + proxyPass = "http://127.0.0.1:${toString config.services.photoprism.port}"; + proxyWebsockets = true; + }; + }; + }; + + services.photoprism = { + enable = true; + + address = "127.0.0.1"; + port = config.emile.ports.photo.photoprism; + + passwordFile = config.age.secrets.photoprism_password.path; + + # originalsPath = "/data/photos"; + originalsPath = "/mnt/storagebox-bx11/photos"; + + settings = { + PHOTOPRISM_ADMIN_USER = "root"; + PHOTOPRISM_DEFAULT_LOCALE = "en"; + PHOTOPRISM_SITE_URL = "https://photo.emile.space"; + }; + }; +} diff --git a/nix/hosts/corrino/www/r2wa.rs.nix b/nix/hosts/corrino/www/r2wa.rs.nix index f7a0a7e..7da11e1 100644 --- a/nix/hosts/corrino/www/r2wa.rs.nix +++ b/nix/hosts/corrino/www/r2wa.rs.nix @@ -1,16 +1,37 @@ -{ ... }: +{ config, pkgs, ... }: { services.nginx.virtualHosts."r2wa.rs" = { forceSSL = true; enableACME = true; - # kTLS = true; - locations = { "/" = { - return = "301 http://emile.space/blog/2020/r2wars/"; + proxyPass = "http://127.0.0.1:${toString config.emile.ports.r2wars-web}"; }; }; }; + + environment.systemPackages = with pkgs; [ radare2 ]; + + # deploy: + # - push code + # - build in order to get the new hash (nix build .#r2war-sweb) + # - update hash in the package (//nix/pkgs/r2wars-web/default.nix) + # - deploy + + services.emile.r2wars-web = { + enable = true; + + host = "127.0.0.1"; + port = config.emile.ports.r2wars-web; + + # TODO(emile): change these when going live + sessionKey = "insecuretmpkey"; + salt = "insecuresalt"; + + logfilePath = "/var/lib/r2wars/r2wars.log"; + databasePath = "/var/lib/r2wars/main.db"; + sessiondbPath = "/var/lib/r2wars/session.db"; + }; } diff --git a/nix/hosts/corrino/www/social.emile.space.nix b/nix/hosts/corrino/www/social.emile.space.nix index 62e1933..9f9a6f1 100644 --- a/nix/hosts/corrino/www/social.emile.space.nix +++ b/nix/hosts/corrino/www/social.emile.space.nix @@ -91,4 +91,11 @@ }; environmentFile = config.age.secrets.gotosocial_environment_file.path; }; + + systemd.services.gotosocial = { + after = [ "authelia-main.service" ]; + serviceConfig = { + Restart = "on-failure"; + }; + }; } diff --git a/nix/hosts/corrino/www/sso.emile.space.nix b/nix/hosts/corrino/www/sso.emile.space.nix index 0f77197..27988fa 100644 --- a/nix/hosts/corrino/www/sso.emile.space.nix +++ b/nix/hosts/corrino/www/sso.emile.space.nix @@ -192,7 +192,7 @@ in { }; totp = { - disable = false; + disable = true; issuer = "sso.emile.space"; algorithm = "sha1"; digits = 6; diff --git a/nix/hosts/gamont/README.md b/nix/hosts/gamont/README.md new file mode 100644 index 0000000..dc77dc0 --- /dev/null +++ b/nix/hosts/gamont/README.md @@ -0,0 +1,3 @@ +# gamont + +The WIFI Cableā„¢ diff --git a/nix/hosts/gamont/configuration.nix b/nix/hosts/gamont/configuration.nix new file mode 100644 index 0000000..4ea1678 --- /dev/null +++ b/nix/hosts/gamont/configuration.nix @@ -0,0 +1,127 @@ +{ config, pkgs, lib, ... }: + +let + user = "nixos"; + password = ""; + SSID = "%p%p%p"; + SSIDpassword = ""; + interface = "wlan0"; + hostname = "gamont"; + keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPZi43zHEsoWaQomLGaftPE5k0RqVrZyiTtGqZlpWsew emile@caladan" + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEzLZ56SEgwZZ0OusTdSDDhpMlxSg1zPNdRLuxKOfrR5 emile@chusuk" + ]; +in { + + boot = { + kernelPackages = pkgs.linuxKernel.packages.linux_rpi4; + kernel.sysctl = { + "net.ipv4.conf.all.forwarding" = true; + }; + initrd.availableKernelModules = [ "xhci_pci" "usbhid" "usb_storage" ]; + loader = { + grub.enable = false; + generic-extlinux-compatible.enable = true; + }; + }; + + fileSystems = { + "/" = { + device = "/dev/disk/by-label/NIXOS_SD"; + fsType = "ext4"; + options = [ "noatime" ]; + }; + }; + + networking = { + hostName = hostname; + wireless = { + enable = true; + networks."${SSID}".psk = SSIDpassword; + interfaces = [ interface ]; + }; + + firewall = { + allowedTCPPorts = [ 53 ]; + allowedUDPPorts = [ 53 ]; + }; + + interfaces.end0 = { + ipv4.addresses = [ { address = "192.168.1.1"; prefixLength = 24; } ]; + }; + + nftables = { + enable = true; + ruleset = '' + table inet filter { + chain input { + type filter hook input priority 0; + accept + } + + chain output { + type filter hook output priority 0; + accept + } + + chain forward { + type filter hook forward priority 0; + accept + } + } + + table ip nat { + chain postrouting { + type nat hook postrouting priority srcnat; policy accept; + masquerade + } + } + ''; + }; + }; + + environment.systemPackages = with pkgs; [ + helix + vim + dnsmasq + tcpdump + curl + iptables nftables + ]; + + services = { + openssh.enable = true; + dnsmasq = { + enable = true; + settings = { + server = [ + "8.8.8.8" + "8.8.4.4" + ]; + dhcp-authoritative = true; + domain-needed = true; + dhcp-range = [ "192.168.1.10,192.168.1.254" ]; + + interface = [ "end0" ]; + + }; + }; + }; + + users = { + mutableUsers = false; + users."${user}" = { + isNormalUser = true; + password = password; + extraGroups = [ "wheel" ]; + openssh.authorizedKeys.keys = keys; + }; + + users.root = { + openssh.authorizedKeys.keys = keys; + }; + }; + + hardware.enableRedistributableFirmware = true; + system.stateVersion = "23.11"; +} diff --git a/nix/hosts/lampadas/configuration.nix b/nix/hosts/lampadas/configuration.nix index ae3af87..2453a88 100644 --- a/nix/hosts/lampadas/configuration.nix +++ b/nix/hosts/lampadas/configuration.nix @@ -54,6 +54,11 @@ in { networking = { hostName = "lampadas"; firewall.enable = true; + + # iperf + firewall.allowedTCPPorts = [ 5201 ]; + firewall.allowedUDPPorts = [ 5201 ]; + nameservers = [ "8.8.8.8" "8.8.4.4" "1.1.1.1"]; }; diff --git a/nix/hosts/lernaeus/configuration.nix b/nix/hosts/lernaeus/configuration.nix index 9522b76..cfbc35f 100644 --- a/nix/hosts/lernaeus/configuration.nix +++ b/nix/hosts/lernaeus/configuration.nix @@ -44,6 +44,10 @@ in { networking = { hostName = "lernaeus"; firewall.enable = true; + + # iperf + firewall.allowedTCPPorts = [ 5201 ]; + firewall.allowedUDPPorts = [ 5201 ]; }; time.timeZone = "Europe/Berlin"; diff --git a/nix/hosts/pi1/result b/nix/hosts/pi1/result new file mode 120000 index 0000000..8da9c2f --- /dev/null +++ b/nix/hosts/pi1/result @@ -0,0 +1 @@ +/nix/store/k4i56ilirmnfdg0izgpq40hwz45x2lmw-nixos-sd-image-23.05pre482756.12ba1a5f90b-armv6l-linux.img-armv6l-unknown-linux-gnueabihf \ No newline at end of file diff --git a/nix/hosts/pi2/default.nix b/nix/hosts/pi2/default.nix new file mode 100644 index 0000000..939027f --- /dev/null +++ b/nix/hosts/pi2/default.nix @@ -0,0 +1,47 @@ +# build the sd image for the pi using +# ; nix-build '' -A config.system.build.sdImage -I nixos-config='./default.nix' + +# after booting +# ; nix-channel --list +# ; nix-channel --remove nixos +# ; nix-channel --add https://channels.nixos.org/nixos-unstable nixos +# ; nix-channel --update nixos +# (this takes quite some time) +# ; nixos-rebuild switch + +{ lib, pkgs, ... }: + +{ + imports = [ + + # + # + + # For nixpkgs cache + # + ]; + + users.users = { + emile = { + isNormalUser = true; + hashedPassword = "$y$j9T$gKt6Iovrn.SAkMxnTCqqV1$55.sKRrjWTbe7Z6Xi17G0e3G7GbAGc65YXtX9zD5AR3"; + extraGroups = [ "wheel" ]; + }; + }; + + nixpkgs = { + # crossSystem = lib.systems.examples.raspberryPi; + crossSystem = lib.systems.examples.armv7l-hf-multiplatform; + # localSystem = { system = "x86_64-linux"; }; + localSystem = { system = "aarch64-darwin"; }; + overlays = [ + (final: super: { + # Due to https://github.com/NixOS/nixpkgs/issues/154163#issuecomment-1350599022 + makeModulesClosure = x: + super.makeModulesClosure (x // { allowMissing = true; }); + }) + ]; + }; + system.stateVersion = "24.05"; +} + diff --git a/nix/hosts/pi2/result b/nix/hosts/pi2/result new file mode 120000 index 0000000..8da9c2f --- /dev/null +++ b/nix/hosts/pi2/result @@ -0,0 +1 @@ +/nix/store/k4i56ilirmnfdg0izgpq40hwz45x2lmw-nixos-sd-image-23.05pre482756.12ba1a5f90b-armv6l-linux.img-armv6l-unknown-linux-gnueabihf \ No newline at end of file diff --git a/nix/modules/default.nix b/nix/modules/default.nix index 767e466..6e6faae 100644 --- a/nix/modules/default.nix +++ b/nix/modules/default.nix @@ -3,5 +3,6 @@ { imports = [ ./ports + ./r2wars-web ]; } diff --git a/nix/modules/r2wars-web/default.nix b/nix/modules/r2wars-web/default.nix new file mode 100644 index 0000000..7e37b26 --- /dev/null +++ b/nix/modules/r2wars-web/default.nix @@ -0,0 +1,73 @@ +{ config, lib, pkgs, ... }: + +let + cfg = config.services.emile.r2wars-web; +in with lib; { + + options.services.emile.r2wars-web = { + enable = mkEnableOption "Enable r2wars-web"; + + # ip and port to listen on + host = mkOption { + type = types.str; + default = "127.0.0.1"; + example = "0.0.0.0"; + description = "The host the service listens on"; + }; + + port = mkOption { + type = types.int; + default = 8080; + example = 8080; + description = "The port the service listens on"; + }; + + # env vars with secrets to set + sessionKey = mkOption { + type = types.str; + default = ""; + example = "abc1Itheich4aeQu9Ouz7ahcaiVoogh9"; + description = "The sessionKey passed to the bin as an env var"; + }; + + salt = mkOption { + type = types.str; + default = ""; + example = "OhD0ki5aLieMoowah8Eemaim2beaf2Na"; + description = "The salt passed to the bin as an env var"; + }; + + # paths to files + logfilePath = mkOption { + type = types.str; + default = "/var/lib/r2wars.log"; + example = "/var/lib/r2wars.log"; + description = "The path to the logfile"; + }; + + databasePath = mkOption { + type = types.str; + default = "/var/lib/main.db"; + example = "/var/lib/main.db"; + description = "The path to the main database"; + }; + + sessiondbPath = mkOption { + type = types.str; + default = "/var/lib/sessions.db"; + example = "/var/lib/sessions.db"; + description = "The path to the sessions database"; + }; + }; + + config = mkIf cfg.enable { + systemd.services.r2wars-web = { + wantedBy = [ "multi-user.target" ]; + environment = { + SESSION_KEY = cfg.sessionKey; + SALT = cfg.salt; + }; + serviceConfig.ExecStart = "${pkgs.r2wars-web}/bin/r2wars-web -h ${cfg.host} -p ${toString cfg.port} --logfilepath ${cfg.logfilePath} --databasepath ${cfg.databasePath} --sessiondbpath ${cfg.sessiondbPath} --templates ${pkgs.r2wars-web}/templates"; + }; + }; +} diff --git a/nix/pkgs/overlay.nix b/nix/pkgs/overlay.nix index 11531f2..d9e3999 100644 --- a/nix/pkgs/overlay.nix +++ b/nix/pkgs/overlay.nix @@ -1,4 +1,5 @@ final: prev: { - vokobe = final.callPackage ../../web/vokobe { inherit (final) naersk; }; + vokobe = final.callPackage ./vokobe { inherit (final) naersk; }; + r2wars-web = final.callPackage ./r2wars-web { }; } diff --git a/nix/pkgs/r2wars-web/default.nix b/nix/pkgs/r2wars-web/default.nix new file mode 100644 index 0000000..2e46665 --- /dev/null +++ b/nix/pkgs/r2wars-web/default.nix @@ -0,0 +1,31 @@ +{ pkgs, lib, fetchgit }: + +pkgs.buildGoModule rec { + name = "r2wars-web-${version}"; + version = "0.1.0"; + + src = fetchgit { + url = "git://git.emile.space/r2wars-web.git"; + hash = "sha256-n+La+C1diNCkxlGIxLu9nGQ//tJ5eDUjvXvdGP4Mdnk="; + }; + + vendorHash = null; + CGO_ENABLED=0; + subPackages = [ "src" ]; + + postInstall = '' + mkdir -p $out + cp -r templates $out + + mv $out/bin/src $out/bin/r2wars-web + ''; + + doCheck = false; + + meta = { + description = "A golang implementation of r2wars"; + homepage = "https://r2wa.rs"; + license = lib.licenses.mit; + maintainers = with lib.maintainers; [ hanemile ]; + }; +} diff --git a/nix/pkgs/vokobe/.gitignore b/nix/pkgs/vokobe/.gitignore new file mode 100644 index 0000000..b774d54 --- /dev/null +++ b/nix/pkgs/vokobe/.gitignore @@ -0,0 +1,7 @@ +# the cargo build artefacts +debug/ +target/ + +# the nix result symlink +result + diff --git a/nix/pkgs/vokobe/Cargo.lock b/nix/pkgs/vokobe/Cargo.lock new file mode 100644 index 0000000..cdf64e1 --- /dev/null +++ b/nix/pkgs/vokobe/Cargo.lock @@ -0,0 +1,270 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "clap" +version = "2.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +dependencies = [ + "ansi_term", + "atty", + "bitflags", + "strsim", + "textwrap", + "unicode-width", + "vec_map", +] + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4" + +[[package]] +name = "memchr" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + +[[package]] +name = "structopt" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c6b5c64445ba8094a6ab0c3cd2ad323e07171012d9c98b0b15651daf1787a10" +dependencies = [ + "clap", + "lazy_static", + "structopt-derive", +] + +[[package]] +name = "structopt-derive" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "unicode-segmentation" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" + +[[package]] +name = "unicode-width" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "vokobe" +version = "0.1.3" +dependencies = [ + "regex", + "structopt", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/nix/pkgs/vokobe/Cargo.toml b/nix/pkgs/vokobe/Cargo.toml new file mode 100644 index 0000000..9c01d4e --- /dev/null +++ b/nix/pkgs/vokobe/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "vokobe" +version = "0.1.3" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +regex = "1.10.3" +structopt = "0.3" diff --git a/nix/pkgs/vokobe/LICENSE b/nix/pkgs/vokobe/LICENSE new file mode 100644 index 0000000..cb5d6ff --- /dev/null +++ b/nix/pkgs/vokobe/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Emile Hansmaennel + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/nix/pkgs/vokobe/README.md b/nix/pkgs/vokobe/README.md new file mode 100644 index 0000000..c2c54a9 --- /dev/null +++ b/nix/pkgs/vokobe/README.md @@ -0,0 +1,101 @@ +# Vokobe + +A minimal static site generator tailored to my needs. + +CI: [https://hydra.emile.space/project/vokobe](https://hydra.emile.space/project/vokobe) + +## Build + +```bash +; cargo build --release +``` + +## Usage/Examples + +```bash +; ./target/release/vokobe --help +vokobe 0.1.0 +A static site generator + +USAGE: + vokobe [FLAGS] + +FLAGS: + -a, --analytics Activate sending analytics to stats.emile.space + -h, --help Prints help information + -V, --version Prints version information + +ARGS: + Input path + Output path + Site name (e.g. emile.space) +``` + + +## Deployment + +The following subsections contain some example for small shell scripts that might be useful for Deployment. + +### build.sh + +Remove the output dir, build it from scratch and update the perms. + +I'm actually considering rebuilding vokobe with incremental builds in mind, as it can take a bit to create some really large projects. + +```bash +rm -rf out/ +vokobe -a ./in ./out emile.space +chmod -R +r out/ +``` + +### sync.sh + +Syncronize the generated output to the remote host for hosting it. + +```bash +rsync -avz --delete /* @: +``` + +### publish.sh + +Build and Syncronize. + +```bash +./build.sh +./sync.sh +``` + +### host.sh + +Host the local version + +```bash +python3 -m http.server 8081 -d / -b 0.0.0.0 +``` + +### watchbuild.sh + +rebuild on changes + +```bash +#! /usr/bin/env nix-shell +#! nix-shell -i bash -p fd entr + +while sleep 0.5; do + fd . in | entr -d ./build.sh +done +``` + +### local.sh + +run a script updating it on changes and one hosting the output. + +```bash +sh ./watchbuild.sh & +sh ./host.sh +``` + + +## Contributing + +Send patches! diff --git a/nix/pkgs/vokobe/default.nix b/nix/pkgs/vokobe/default.nix new file mode 100644 index 0000000..7257962 --- /dev/null +++ b/nix/pkgs/vokobe/default.nix @@ -0,0 +1,16 @@ +{ pkgs, naersk, ... }: + +let + naersk' = pkgs.callPackage naersk {}; +in naersk'.buildPackage { + src = ./.; + + meta = with pkgs.lib; { + description = "A minimal static site generator tailored to my needs."; + homepage = "https://git.emile.space/hanemile/vokobe"; + license = licenses.mit; + platforms = platforms.all; + maintainers = with maintainers; [ hanemile ]; + }; +} + diff --git a/nix/pkgs/vokobe/flaaaaake.nix b/nix/pkgs/vokobe/flaaaaake.nix new file mode 100644 index 0000000..7cf2f03 --- /dev/null +++ b/nix/pkgs/vokobe/flaaaaake.nix @@ -0,0 +1,44 @@ +{ + inputs = { + flake-utils.url = "github:numtide/flake-utils"; + naersk.url = "github:nix-community/naersk"; + nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; + }; + + outputs = { self, flake-utils, naersk, nixpkgs }: + let + pkgs = (import nixpkgs) { + system = "x86_64-linux"; + }; + + naersk' = pkgs.callPackage naersk {}; + + in rec { + packages."x86_64-linux".vokobe = naersk'.buildPackage { + src = ./.; + + meta = with pkgs.lib; { + description = "A minimal static site generator tailored to my needs."; + homepage = "https://git.emile.space/hanemile/vokobe"; + license = licenses.mit; + platforms = platforms.all; + maintainers = with maintainers; [ + hanemile + ]; + }; + }; + + # For `nix build` & `nix run`: + defaultPackage = packages."x86_64-linux".vokobe; + + # For `nix develop` (optional, can be skipped): + devShell = pkgs.mkShell { + nativeBuildInputs = with pkgs; [ rustc cargo ]; + }; + + # hydraJobs.""."" = derivation; + hydraJobs = { + build."x86_64-linux" = packages."x86_64-linux".vokobe; + }; + }; +} \ No newline at end of file diff --git a/nix/pkgs/vokobe/src/main.rs b/nix/pkgs/vokobe/src/main.rs new file mode 100644 index 0000000..ab26457 --- /dev/null +++ b/nix/pkgs/vokobe/src/main.rs @@ -0,0 +1,922 @@ +/* +pull the std into scope and inline it so that we get documentation for it, +even when running offline +*/ +#[doc(inline)] +pub use std; + +use std::path::{Path, PathBuf}; +use std::io::{self, Read, Write, BufRead, BufReader}; +use std::fs::{self, File}; +use std::time; +use std::collections::HashMap; + +use structopt::StructOpt; +use regex::Regex; + +#[derive(Debug, StructOpt)] +#[structopt(name = "vokobe", about = "A static site generator")] +struct Opt { + /// Input path + #[structopt(parse(from_os_str))] + input_path: PathBuf, + + /// Output path + #[structopt(parse(from_os_str))] + output_path: PathBuf, + + /// Site name (e.g. emile.space) + site_name: String, + + /// Activate sending analytics to stats.emile.space + // -a and --analytics will be generated + // analytics are sent to stats.emile.space + #[structopt(short, long)] + analytics: bool, +} + +fn main() -> std::io::Result<()> { + + let mut internal_links: HashMap> = HashMap::new(); + + let opt = Opt::from_args(); + + let in_path = opt.input_path; + let output_path = opt.output_path; + + // read the style + let style_path = Path::new(&in_path).join("style.css"); + let mut style_file = File::open(style_path) + .expect("could not open style file"); + let mut style = String::new(); + style_file.read_to_string(&mut style) + .expect("could not read style file to string"); + + // read all dirs in the input path + let pathes = recursive_read_dir(&in_path, false)?; + + // pass 1: store the backlinks + + for path in &pathes { + if path.ends_with("README.md") { + // open the file and read it as a string + let mut readme_file = File::open(path)?; + let mut readme = String::new(); + readme_file.read_to_string(&mut readme)?; + + let internal_links_in_file + = parse_internal_links(readme.as_str()); + + for link in internal_links_in_file { + + internal_links.entry(link).or_insert_with(Vec::new).push(path.to_string_lossy().into_owned()) + } + } + } + + + // for each markdown_file in markdown_files { + // let internal_links_in_file = parse_internal_links(markdown_file); + // internal_links.insert(markdown_file, internal_links_in_file); + // } + + // pass 2: create the html + + println!("Got {} files", pathes.len()); + let mut readme_counter = 0; + + for path in pathes { + let stripped_path = path.strip_prefix(&in_path) + .expect(format!( + "could not strip the in_path prefix: {:?}", in_path).as_str()); + + // copy images and other files to the output folder + if path.is_file() { + + // define the source and destination + let src = Path::new(&in_path).join(stripped_path); + let dst = Path::new(&output_path).join(stripped_path); + + // define the destination folder (the dst path without the file) and create it + let mut dst_folder = dst.clone(); + dst_folder.pop(); // remove the file itself from the path + fs::create_dir_all(dst_folder)?; + + // copy the file to the destination + std::fs::copy(src, dst.as_path())?; + } + + if stripped_path.ends_with("README.md") { + readme_counter += 1; + + // define the "raw" path (no infile prefix, no file) + let mut ancestors = stripped_path.ancestors(); + ancestors.next(); + + let raw_path = ancestors.next() + .expect("could not extract next ancestor"); + + // out + rawpath + let index_path = output_path.join(raw_path); + + // (out + rawpath) + "index.html" + let index_file = index_path.join("index.html"); + + // - create the dir for the index.html as well as the index.html + // itself + fs::create_dir_all(index_path)?; + let mut file = File::create(&index_file)?; + + // this is the main block calling all other smaller functions. The + // whole output is compsed here + write_header(&mut file, &opt.site_name, &style)?; + write_body_start(&mut file, &opt.site_name)?; + write_nav(&mut file, in_path.as_path(), raw_path, opt.analytics)?; + write_same_level(&mut file, in_path.as_path(), raw_path)?; + write_readme_content(&mut file, in_path.as_path(), raw_path)?; + write_footer(&mut file, raw_path, &internal_links)?; + + file.write_all("".as_bytes())?; + } + } + + println!("Got {readme_counter} README.md files"); + + Ok(()) +} + +fn parse_internal_links(markdown_file: &str) -> Vec { + // Define a regular expression to match markdown-style links + let link_regex = Regex::new(r"\[([^\]]+)\]\(([^)]+)\)").unwrap(); + + // Initialize a vector to store internal links found in the markdown file + let mut internal_links = Vec::new(); + + // Iterate over each match of the regular expression in the markdown content + for capture in link_regex.captures_iter(&markdown_file) { + // Extract the link text and URL from the capture groups + // let link_text = &capture[1]; + let mut link_url = &capture[2]; + + // Check if the link is an internal link (e.g., relative URL) + // You can customize this condition based on your site's URL structure + if link_url.starts_with('/') || link_url.starts_with("../") { + if link_url.ends_with('/') { + link_url = link_url.trim_end_matches('/'); + } + internal_links.push(link_url.to_string()); + } + } + + internal_links +} + +/// Write the html header including the style file +/// TODO: Don't add the style file into each compiled html output, as the +/// style can be included allowing the user to cache the style file in their +/// browser. +fn write_header(file: &mut File, site_name: &String, style: &String) -> std::io::Result<()>{ + + // write the header including the style file + file.write_all(format!(r#" + + + + + + {} + + + + "#, site_name, style).as_bytes())?; + + Ok(()) +} + +/// write the start of the html body tag and the header linking back to the +/// site itself. +fn write_body_start(file: &mut File, site_name: &String) -> std::io::Result<()>{ + file.write_all(format!(r#" + +
+ {} +
"#, site_name).as_bytes())?; + + Ok(()) +} + +/// Write the navigation section to the given file +fn write_nav(file: &mut File, in_path: &Path, raw_path: &Path, analytics: bool) + -> std::io::Result<()> { + + if analytics == true { + /* + file.write_all(format!(r#" + +