;; Copyright (C) 2023 Denis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org>
;;
;; This file is free software; you can redistribute it and/or modify it
;; under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3 of the License, or (at
;; your option) any later version.
;;
;; You should have received a copy of the GNU General Public License
;; along with this file.  If not, see <http://www.gnu.org/licenses/>.

(define-module (mumble-vm-system)
  #:use-module (gnu)
  #:use-module (gnu packages admin)
  #:use-module (gnu packages certs)
  #:use-module (gnu packages dns)
  #:use-module (gnu packages linux)
  #:use-module (gnu packages ssh)
  #:use-module (gnu packages tls)
  #:use-module (gnu services admin)
  #:use-module (gnu services certbot)
  #:use-module (gnu services ssh)
  #:use-module (gnu services telephony)
  #:use-module (gnu services vpn)
  #:use-module (gnu services web)
  #:use-module (guix build-system copy)
  #:use-module (guix build-system gnu)
  #:use-module ((guix licenses) #:prefix license:)
  #:use-module (guix packages)
  #:use-module (guix utils)
  #:export (mumble-vm-operating-system))

(define enable-wireguard? (string=? "yes" "ENABLE_WIREGUARD"))

(define mumble-vm-config
  (package
    (name "mumble-vm-config")
    (version "0.1")
    ;; TODO: Make that tarball reproducible
    (source (local-file "mumble-vm.tar.xz"))
    (build-system copy-build-system)
    (arguments
     (list
     #:install-plan
     #~(list
        '("first-boot.sh" "share/mumble-vm/configs/")
        '("guix-commit.txt" "share/mumble-vm/configs/")
        '("index.html" "share/mumble-vm/configs/")
        '("mumble-vm-machine.scm" "share/mumble-vm/configs/")
        '("mumble-vm-system.scm" "share/mumble-vm/configs/")
        '("id_ed25519.pub" "share/mumble-vm/configs/")
        '("Makefile" "share/mumble-vm/configs/")
        '("signing-key.pub" "share/mumble-vm/configs/")
        '(#$source
          "share/mumble-vm/configs/mumble-vm.tar.xz")
        '("wireguard-post-up.sh" "share/mumble-vm/configs/"))))
    (synopsis "Full machine configuration.")
    (description
     "This contains all the configuration files of this machine. This is
needed for unattended upgrades to work.")
    (home-page "DOMAIN")
    (license license:gpl3+)))

(define website
  (package
    (name "website")
    (version "0.1")
    ;; TODO: Make that tarball reproducible
    (source (local-file "mumble-vm.tar.xz"))
    (build-system copy-build-system)
    (arguments
     (list
     #:install-plan
     #~(list '("first-boot.sh" "var/www/DOMAIN/")
             '(#$source "var/www/DOMAIN/mumble-vm.tar.xz"))))
    (synopsis "The DOMAIN website.")
    (description
     "The website contains how to use the service, and how to
replicate or contribute to it.")
    (home-page "DOMAIN")
    (license license:gpl3+)))

(define first-boot-script
  (package
    (name "first-boot-script")
    (version "0.1")
    (source (local-file "first-boot.sh" ))
    (build-system gnu-build-system)
    (arguments
     (list #:tests? #f ;no tests
           #:phases
           #~(modify-phases
              %standard-phases
              (delete 'build)
              (delete 'configure)
              (replace 'install
                       (lambda _
                         (chmod "first-boot.sh" #o755)
                         (install-file
                          "first-boot.sh"
                          (string-append (string-append #$output "/bin"))))))))
    (synopsis "Script to run on first boot.")
    (description
     "The first-boot.sh script generates the TLS certificate and restart
the services after that.")
    (home-page #f)
    (license license:gpl3+)))

(define wireguard-post-up-fixups
  (package
    (name "wireguard-post-up-fixups")
    (version "0.1")
    (source (local-file "wireguard-post-up.sh" ))
    (build-system gnu-build-system)
    (arguments
     (list #:tests? #f ;no tests
           #:phases
           #~(modify-phases
              %standard-phases
              (delete 'build)
              (delete 'configure)
              (replace 'install
                       (lambda _
                         (chmod "wireguard-post-up.sh" #o755)
                         (install-file
                          "wireguard-post-up.sh"
                          (string-append (string-append #$output "/bin"))))))))
    (synopsis "Script to fixup the Wireguard interface(s).")
    (description
     "Currently, the wireguard-post-up.sh script sets up the interface
     MTU.")
    (home-page #f)
    (license license:gpl3+)))

(define-public %nginx-deploy-hook
  (program-file
   "nginx-deploy-hook"
   #~(let
         ((nginx-pid (call-with-input-file "/var/run/nginx/pid" read))
          (mumble-server-pid
           (call-with-input-file
               "/var/run/mumble-server/mumble-server.pid" read)))
       ((lambda _
          (kill nginx-pid SIGHUP)
          (kill mumble-server-pid SIGUSR1))))))

(define-public %wireguard-post-up
    (list "/run/current-system/profile/bin/wireguard-post-up.sh"))

(define mumble-vm-operating-system
  (operating-system
   (bootloader (bootloader-configuration
                (bootloader grub-minimal-bootloader)
                (targets '("/dev/vda"))
                (terminal-outputs '(serial_0))))
   (kernel-arguments (append '("console=ttyS0")))
   ;; TODO: Does Mumble have some data? Is BTRFS safer than using ext4
   ;; without doing many fsck?
   (file-systems (cons (file-system
                        (device (file-system-label "Guix_image"))
                        (mount-point "/")
                        (type "ext4")) %base-file-systems))
   (host-name "mumble-vm")
   (timezone "Europe/Paris")
   (packages
    (append
     (list certbot
           first-boot-script
           htop
           iftop
           `(,isc-bind "utils")
           mumble-vm-config
           net-tools
           nmon
           nss-certs
           openssh-sans-x
           website)
     (if enable-wireguard?
         (list wireguard-post-up-fixups)
         (list ))
     %base-packages))
   (services
    (append
     (list
      ;; Agetty

      ;; ttyS0 is already setup automatically due to the console=ttyS0
      ;; kernel argument
      (service agetty-service-type
               (agetty-configuration (term "xterm-256color")
                                     (tty "ttyS1")))
      (service agetty-service-type
               (agetty-configuration (term "xterm-256color")
                                     (tty "ttyS2")))
      (service agetty-service-type
               (agetty-configuration (term "xterm-256color")
                                     (tty "ttyS3")))
      ;; Certbot
      (service
       certbot-service-type
       (certbot-configuration
        (email "LETSENCRYPT_EMAIL")
        (certificates
         (list
          (certificate-configuration
           (domains '("DOMAIN"))
           (deploy-hook %nginx-deploy-hook))))))
      ;; Mumble
      (service mumble-server-service-type
         (mumble-server-configuration
          (welcome-text
           "<br />
Bienvenue sur le service d'audio-conférence de <b>Libre en communs</b>.<br />
https://DOMAIN/
<br />")
          (cert-required? #t) ;; Disallow text password logins
          (max-user-bandwidth 100000)
          (ssl-cert
           "/etc/letsencrypt/live/DOMAIN/fullchain.pem")
          (ssl-key
           "/etc/letsencrypt/live/DOMAIN/privkey.pem")))
      ;; Networking
      (service
       static-networking-service-type
       (list
        (static-networking
         (addresses (list (network-address
                           (device "eth0")
                           (value "VM_IPV4_ADDRESS"))
                          (network-address
                           (device "eth0")
                           (value "VM_IPV6_ADDRESS"))))
         (routes (list (network-route
                        (destination "default")
                        (gateway "VM_IPV4_GATEWAY"))
                       (network-route
                        (destination "default")
                        (gateway "VM_IPV6_GATEWAY"))))
         (name-servers (list "VM_IPV4_DNS" "VM_IPV6_DNS")))))
      ;; Nginx
      (service
       nginx-service-type
       (nginx-configuration
        (log-directory "/var/log")
        (server-blocks
         (list
          (nginx-server-configuration
           (listen '("80" "443 ssl"))
           (server-name '("DOMAIN"))
           (ssl-certificate
            (string-append
             "/etc/letsencrypt/live/"
             "DOMAIN/fullchain.pem"))
           (ssl-certificate-key
            (string-append
             "/etc/letsencrypt/live/"
             "DOMAIN/privkey.pem"))
           (root (string-append
                  "/run/current-system/profile/"
                  "var/www/DOMAIN")))))))
      ;; OpenSSH
      (service openssh-service-type
               (openssh-configuration
                (openssh openssh-sans-x)
                (use-pam? #f)
                (port-number 222)
                (permit-root-login #t)
                (password-authentication? #f)
                (challenge-response-authentication? #f)
                (authorized-keys
                 `(("root" , (local-file "id_ed25519.pub"))
                   ("gnutoo" ,(local-file "id_ed25519.pub"))))))
      ;; Unattended Upgrades
      (service
       unattended-upgrade-service-type
       (unattended-upgrade-configuration
        (operating-system-file (string-append "/run/current-system/profile"
                                              "/share/mumble-vm/configs/"
                                              "mumble-vm-system.scm"))
        (schedule "30 * * * * ")
        (services-to-restart (list 'guix-daemon 'mcron 'ssh-daemon)))))
     (if enable-wireguard?
         (list
          (service wireguard-service-type
                   (wireguard-configuration
                    (addresses '("79.143.250.36/32" "2001:678:938:3ff::36/128"))
                    (dns '("79.143.250.1" "79.143.250.2"
                           "2001:678:938::53:1" "2001:678:938::53:2"))
                    (port 0)
                    (post-up %wireguard-post-up)
                    (private-key (local-file "id_wireguard"))
                    (peers
                     (list
                      (wireguard-peer
                       (name "stephanie.franciliens.net")
                       (endpoint "stephanie.franciliens.net:51820")
                       (public-key
                        "Ybfh3twyBpj7wx/lo9AVBsBKNAUMSQqAWWV0LfywSDI=")
                       (allowed-ips '("0.0.0.0/0" "::/0"))))))))
         (list ))
     (modify-services
      %base-services
      (guix-service-type config => (guix-configuration
                                    (authorized-keys
                                     (append
                                      (list
                                       (local-file
                                        "signing-key.pub"))
                                      %default-authorized-guix-keys)))))))))
mumble-vm-operating-system