# SPDX-FileCopyrightText: 2020 Luke Granger-Brown <depot@lukegb.com>
#
# SPDX-License-Identifier: Apache-2.0

{ config, depot, pkgs, lib, ... }:
let
  inherit (depot.ops) secrets;
  machineSecrets = secrets.machineSpecific.bvm-matrix;
in {
  imports = [
    ../lib/bvm.nix
  ];

  # Networking!
  networking = {
    hostName = "bvm-matrix";
    hostId = "1c2786ad";

    interfaces.enp1s0 = {
      ipv4.addresses = [{ address = "10.100.0.205"; prefixLength = 23; }];
    };
    interfaces.enp2s0 = {
      ipv4.addresses = [{ address = "92.118.28.6"; prefixLength = 24; }];
      ipv6.addresses = [{ address = "2a09:a441::6"; prefixLength = 32; }];
    };
    defaultGateway = { address = "92.118.28.1"; interface = "enp2s0"; };
    defaultGateway6 = { address = "2a09:a441::1"; interface = "enp2s0"; };

    firewall.allowedUDPPorts = [
      3478  # TURN
    ];
    firewall.allowedTCPPorts = [
      80 443  # HTTP/S
      3478  # TURN
    ];
  };
  my.ip.tailscale = "100.74.197.67";

  services.postfix = {
    enable = true;
    hostname = "matrix.zxcvbnm.ninja";
    origin = "zxcvbnm.ninja";
    domain = "zxcvbnm.ninja";
    enableSubmission = true;
  };
  services.postgresql = {
    enable = true;
    ensureDatabases = [ "matrix-synapse" ];
    ensureUsers = [{
      name = "matrix-synapse";
      ensurePermissions = {
        "DATABASE \"matrix-synapse\"" = "ALL PRIVILEGES";
      };
    }];
  };
  services.coturn = {
    enable = true;
    use-auth-secret = true;
    realm = "matrix.zxcvbnm.ninja";
    static-auth-secret = machineSecrets.turnSecret;
    cert = "/var/lib/acme/matrix.zxcvbnm.ninja/fullchain.pem";
    pkey = "/var/lib/acme/matrix.zxcvbnm.ninja/privkey.pem";
  };
  services.nginx = {
    enable = true;
    recommendedTlsSettings = true;
    recommendedOptimisation = true;
    recommendedGzipSettings = true;
    recommendedProxySettings = true;

    virtualHosts = {
      "zxcvbnm.ninja" = {
        forceSSL = true;
        locations = let
          inherit (lib) mapAttrs' nameValuePair;
          wellKnown = {
            "matrix/server" = { "m.server" = "matrix.zxcvbnm.ninja:443"; };
            "matrix/client" = {
              "m.homeserver" = { "base_url" = "https://matrix.zxcvbnm.ninja"; };
              "m.identity_server" = { "base_url" = "https://vector.im"; };
            };
          };
        in
          mapAttrs' (name: value: nameValuePair "= /.well-known/${name}" { extraConfig = ''
            add_header Content-Type application/json;
            add_header Access-Control-Allow-Origin *;
            return 200 '${builtins.toJSON value}';
          ''; }) wellKnown;
      };
      "matrix.zxcvbnm.ninja" = {
        forceSSL = true;
        locations."/".return = "301 https://element.zxcvbnm.ninja$request_uri";
        locations."/_matrix".proxyPass = "http://[::1]:8008";
      };
      "element.zxcvbnm.ninja" = {
        forceSSL = true;
        extraConfig = ''
          add_header X-Frame-Options SAMEORIGIN;
          add_header X-Content-Type-Options nosniff;
          add_header X-XSS-Protection "1; mode=block";
          add_header Content-Security-Policy "frame-ancestors 'none'";
        '';

        root = pkgs.element-web.override {
          conf = {
            default_server_config."m.homeserver" = {
              base_url = "https://matrix.zxcvbnm.ninja";
              server_name = "matrix.zxcvbnm.ninja";
            };
            disable_guests = true;
            disable_custom_urls = true;
            settingDefaults = {
              "UIFeature.registration" = false;
            };
          };
        };
      };
    };
  };
  services.matrix-synapse = {
    enable = true;
    settings = {
      server_name = "zxcvbnm.ninja";
      url_preview_enabled = true;
      url_preview_ip_range_blacklist = [
        "127.0.0.0/8"
        "10.0.0.0/8"
        "172.16.0.0/12"
        "192.168.0.0/16"
        "100.64.0.0/10"
        "169.254.0.0/16"
        "::1/128"
        "fe80::/64"
        "fc00::/7"
      ];
      listeners = [{
        port = 8008;
        bind_addresses = [ "::1" ];
        type = "http";
        tls = false;
        x_forwarded = true;
        resources = [{
          names = [ "client" "federation" ];
          compress = false;
        }];
      }];
      turn_uris = [
        "turns:matrix.zxcvbnm.ninja:3478?transport=udp"
        "turns:matrix.zxcvbnm.ninja:3478?transport=tcp"
        "turn:matrix.zxcvbnm.ninja:3478?transport=udp"
        "turn:matrix.zxcvbnm.ninja:3478?transport=tcp"
      ];
      experimental_features.spaces_enabled = true;
      public_baseurl = "https://matrix.zxcvbnm.ninja/";

      macaroon_secret_key = machineSecrets.matrix.macaroonSecretKey;
      registration_shared_secret = machineSecrets.matrix.registrationSecret;
      turn_shared_secret = machineSecrets.turnSecret;
      form_secret = machineSecrets.matrix.formSecret;
    };
  };

  # Users allowed to use SSL certificate for matrix.zxcvbnm.ninja.
  users.groups.matrixcert = {
    members = [ "turnserver" "nginx" ];
  };

  my.vault.acmeCertificates."matrix.zxcvbnm.ninja" = {
    group = "matrixcert";
    hostnames = [ "matrix.zxcvbnm.ninja" "element.zxcvbnm.ninja" "zxcvbnm.ninja" ];
    nginxVirtualHosts = [ "zxcvbnm.ninja" "element.zxcvbnm.ninja" "matrix.zxcvbnm.ninja" ];
  };

  system.stateVersion = "21.05";
}