diff --git a/README.md b/README.md index 07a6835..df68e69 100644 --- a/README.md +++ b/README.md @@ -16,9 +16,9 @@ installation `sudo nixos-rebuild --flake .#your-flake-name-here switch` -if you're trying to install `virtbox`, then use the `--impure` flag: +if you're trying to install `netbox`, then use the `--impure` flag: -`sudo nixos-rebuild --flake .#virtbox switch --impure` +`sudo nixos-rebuild --flake .#netbox switch --impure` for alternate installations on non-NixOS hosts, a Makefile will be made available @@ -28,6 +28,8 @@ things to do - integrate `disko` and `sops-nix` into the setup - switch from gitea to cgit - establish backup infrastructure for `netbox` +- move gmail-mail-bridge into mail-sync repo + * (perhaps figure out how to produce a flake for it) license ------- diff --git a/boxes/mainsail/default.nix b/boxes/mainsail/default.nix index e492f9b..d17b946 100644 --- a/boxes/mainsail/default.nix +++ b/boxes/mainsail/default.nix @@ -2,11 +2,8 @@ { imports = [ ./hardware-configuration.nix - ./server.nix ../../modules/bootstrap.nix ../../modules/common.nix - ../../modules/x11.nix - ../../modules/discord.nix ]; boot.loader.grub.enable = true; @@ -26,20 +23,40 @@ "; environment.systemPackages = with pkgs; [ - vscodium-fhs - libreoffice + neovim + git + curl + ]; - anki-bin - ytfzf - kdenlive - libreoffice - i3 - gcc - gnumake + services.home-assistant = { + enable = true; + extraComponents = [ + # Components required to complete the onboarding + "netgear" + "hue" + "nest" + "esphome" + "met" + "radio_browser" + ]; + config = { + # Includes dependencies for a basic setup + # https://www.home-assistant.io/integrations/default_config/ + default_config = {}; + }; + openFirewall = true; + }; - scrcpy - thunderbird - mepo + services.openssh = { + enable = true; + settings = { + PermitRootLogin = "no"; + PasswordAuthentication = false; + }; + }; + + users.users.usr.openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKbhM3wj0oqjR3pUaZgpfX4Xo4dlzvBTbQ48zHyg7Pwx usr" ]; system.stateVersion = "23.11"; diff --git a/boxes/mainsail/hardware-configuration.nix b/boxes/mainsail/hardware-configuration.nix index c2a86c1..9bc31a8 100644 --- a/boxes/mainsail/hardware-configuration.nix +++ b/boxes/mainsail/hardware-configuration.nix @@ -5,27 +5,28 @@ { imports = - [ (modulesPath + "/profiles/qemu-guest.nix") + [ (modulesPath + "/installer/scan/not-detected.nix") ]; - boot.initrd.availableKernelModules = [ "ahci" "xhci_pci" "virtio_pci" "sr_mod" "virtio_blk" ]; + boot.initrd.availableKernelModules = [ "xhci_pci" "ehci_pci" "ahci" "usbhid" "usb_storage" "ums_realtek" "sd_mod" ]; boot.initrd.kernelModules = [ ]; boot.kernelModules = [ "kvm-intel" ]; boot.extraModulePackages = [ ]; fileSystems."/" = - { device = "/dev/disk/by-uuid/7b70ab88-296c-4737-90b2-267cb2432dc1"; + { device = "/dev/disk/by-uuid/948aeaf8-cb7e-4f85-ae3e-1bc6a25ec156"; fsType = "ext4"; }; - swapDevices = [ ]; + fileSystems."/boot" = + { device = "/dev/disk/by-uuid/617cb1ae-a788-429a-b0d4-63d46d8a4e1b"; + fsType = "ext4"; + }; - # Enables DHCP on each ethernet and wireless interface. In case of scripted networking - # (the default) this is the recommended approach. When using systemd-networkd it's - # still possible to use this option, but it's recommended to use it in conjunction - # with explicit per-interface declarations with `networking.interfaces..useDHCP`. - networking.useDHCP = lib.mkDefault true; - # networking.interfaces.enp1s0.useDHCP = lib.mkDefault true; + swapDevices = + [ { device = "/dev/disk/by-uuid/d82ae76c-68f4-4e70-9162-5dab5f84375b"; } + ]; nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; } diff --git a/boxes/mainsail/home.nix b/boxes/mainsail/home.nix deleted file mode 100644 index 144dd0e..0000000 --- a/boxes/mainsail/home.nix +++ /dev/null @@ -1,9 +0,0 @@ -{ lib, inputs, config, pkgs, home, ... }: - -{ - imports = [ - ../../home/x11.nix - ]; - - home.stateVersion = "23.11"; -} diff --git a/boxes/mainsail/server.nix b/boxes/mainsail/server.nix deleted file mode 100644 index 7503d58..0000000 --- a/boxes/mainsail/server.nix +++ /dev/null @@ -1,70 +0,0 @@ -{ lib, config, pkgs, ...}: -{ - services.paperless = { - enable = true; - passwordFile = "/etc/paperless-password"; - port = 3004; - address = "localhost"; - extraConfig = { - PAPERLESS_URL = "https://paperless.beepboop.systems"; - }; - }; - - services.calibre-web.enable = true; - services.calibre-web.listen.port = 8080; - - powerManagement.enable = false; - - programs.adb.enable = true; - users.users.usr.extraGroups = ["adbusers"]; - - services.openssh = { - enable = true; - ports = [2222]; - }; - -<<<<<<< Updated upstream - services.radicale = { - enable = true; - settings = { - auth = { - type = "htpasswd"; - htpasswd_filename = "radicale-passwd"; - htpasswd_encryption = "plain"; - }; - }; - }; - -======= ->>>>>>> Stashed changes - systemd.targets.sleep.enable = false; - systemd.targets.suspend.enable = false; - systemd.targets.hibernate.enable = false; - systemd.targets.hybrid-sleep.enable = false; - - systemd.services.paperless-web-bridge = { - script = '' - ${pkgs.openssh}/bin/ssh -v -NR 3004:localhost:3004 -oExitOnForwardFailure=yes -p 55555 useracc@beepboop.systems - ''; - wantedBy = [ "multi-user.target" ]; - after = [ "network.target" "ankisyncd.service" ]; - serviceConfig = { - Restart = "on-failure"; - StartLimitBurst = 10000; - RestartSec = "0s"; - }; - }; - - systemd.services.internal-ssh-bridge = { - script = '' - ${pkgs.openssh}/bin/ssh -v -NR 2222:localhost:2222 -oExitOnForwardFailure=yes -p 55555 useracc@beepboop.systems - ''; - wantedBy = [ "multi-user.target" ]; - after = [ "network.target" "ankisyncd.service" ]; - serviceConfig = { - Restart = "on-failure"; - StartLimitBurst = 10000; - RestartSec = "0s"; - }; - }; -} diff --git a/boxes/mlg/default.nix b/boxes/mlg/default.nix index 61992fd..fd22d23 100644 --- a/boxes/mlg/default.nix +++ b/boxes/mlg/default.nix @@ -2,8 +2,9 @@ { imports = [ -# ./hardware-configuration.nix + ./hardware-configuration.nix ./nvidia.nix + ../../modules/ssh-phone-home.nix ../../modules/bootstrap.nix ../../modules/common.nix ../../modules/x11.nix @@ -28,6 +29,16 @@ minetest ]; + services.openssh.enable = true; + services.ssh-phone-home = { + enable = true; + localUser = "usr"; + remoteHostname = "192.168.1.100"; + remotePort = 22; + remoteUser = "usr"; + bindPort = 2222; + }; + boot.loader = { efi = { canTouchEfiVariables = true; diff --git a/boxes/netbox/default.nix b/boxes/netbox/default.nix index ce56bad..e21f423 100644 --- a/boxes/netbox/default.nix +++ b/boxes/netbox/default.nix @@ -113,6 +113,7 @@ in { [ ./hardware-configuration.nix ../../modules/bootstrap.nix + ../../builds/gmail_mail_bridge.nix ]; networking.networkmanager.enable = true; @@ -136,11 +137,30 @@ in { neovim ]; + services.gmail_mail_bridge.enable = true; + system.copySystemConfiguration = true; system.stateVersion = "23.05"; # don't change this, lol boot.loader.grub.enable = true; boot.loader.grub.device = "/dev/vda"; + services.sslh = { + enable = true; + settings.protocols = [ + { + host = "localhost"; + name = "ssh"; + port = "55555"; + service = "ssh"; + } + { + host = "localhost"; + name = "tls"; + port = "442"; + } + ]; + }; + # cgit users = { groups.git = { }; @@ -226,12 +246,10 @@ in { ''; }; - users.users.useracc = { - isNormalUser = true; - extraGroups = [ "wheel" "docker" ]; - }; - users.users.ryan = { + openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKbhM3wj0oqjR3pUaZgpfX4Xo4dlzvBTbQ48zHyg7Pwx usr" + ]; isNormalUser = true; extraGroups = [ "wheel" "docker" ]; }; @@ -278,6 +296,7 @@ in { services.nginx.enable = true; services.nginx.clientMaxBodySize = "100m"; + services.nginx.defaultSSLListenPort = 442; services.nginx.virtualHosts."beepboop.systems" = { forceSSL = true; @@ -319,6 +338,21 @@ in { return 301 https://mail.beepboop.systems; ''; }; + locations."~ \\.git" = { + extraConfig = '' + client_max_body_size 0; + + include ${pkgs.nginx}/conf/fastcgi_params; + fastcgi_param SCRIPT_FILENAME ${pkgs.git}/bin/git-http-backend; + fastcgi_param GIT_HTTP_EXPORT_ALL ""; + fastcgi_param GIT_PROJECT_ROOT /var/lib/git; + fastcgi_param PATH_INFO $uri; + + # Forward REMOTE_USER as we want to know when we are authenticated + fastcgi_param REMOTE_USER $remote_user; + fastcgi_pass unix:${config.services.fcgiwrap.socketAddress}; + ''; + }; locations."/" = { extraConfig = '' include ${pkgs.nginx}/conf/fastcgi_params; @@ -412,11 +446,20 @@ in { services.nginx.virtualHosts."mail.beepboop.systems" = { forceSSL = true; enableACME = true; - globalRedirect = "cube.beepboop.systems"; + locations."/bridge-submit" = { + extraConfig = '' + proxy_pass http://localhost:8041; + ''; + }; + locations."/" = { + extraConfig = '' + return 301 https://cube.beepboop.systems; + ''; + }; }; networking.firewall = { enable = true; - allowedTCPPorts = [ 5232 55555 22 80 443 ]; + allowedTCPPorts = [ 80 443 ]; }; } diff --git a/builds/gmail_mail_bridge.nix b/builds/gmail_mail_bridge.nix new file mode 100644 index 0000000..a81985c --- /dev/null +++ b/builds/gmail_mail_bridge.nix @@ -0,0 +1,19 @@ +{ lib, pkgs, config, ... }: +let + cfg = config.services.gmail_mail_bridge; + appEnv = pkgs.python3.withPackages (p: with p; [ waitress (callPackage ./gmail_mail_bridge/default.nix {}) ]); +in { + options.services.gmail_mail_bridge = { + enable = lib.mkEnableOption "Enable the gmail_mail_bridge"; + }; + + config = lib.mkIf cfg.enable { + systemd.services.gmail_mail_bridge = { + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + ExecStart = "${appEnv}/bin/waitress-serve --port=8041 gmail_mail_bridge:app"; + StandardOutput = "journal"; + }; + }; + }; +} diff --git a/builds/gmail_mail_bridge/.gitignore b/builds/gmail_mail_bridge/.gitignore new file mode 100644 index 0000000..aaca2e2 --- /dev/null +++ b/builds/gmail_mail_bridge/.gitignore @@ -0,0 +1 @@ +__pycache_/ diff --git a/builds/gmail_mail_bridge/README b/builds/gmail_mail_bridge/README new file mode 100644 index 0000000..eae7b1c --- /dev/null +++ b/builds/gmail_mail_bridge/README @@ -0,0 +1,10 @@ +synchronize email from gmail accounts whose OAuth access is heavily restricted + +background +---------- + +my school district disabled external OAuth access to email, which is not cool. this script gets around this and creates a bridge so you can recieve emails from your school email. + +do note that this is heavily unpolished and most definately insecure. there are some hardcoded credentials (which you can change, it just takes a little technical know-how) + +have fun! diff --git a/builds/gmail_mail_bridge/default.nix b/builds/gmail_mail_bridge/default.nix new file mode 100644 index 0000000..bde908a --- /dev/null +++ b/builds/gmail_mail_bridge/default.nix @@ -0,0 +1,20 @@ +{ pkgs, pythonPackages ? (import {}).python3Packages }: +pythonPackages.buildPythonPackage { + name = "gmail_mail_bridge"; + src = ./gmail_mail_bridge; + + propagatedBuildInputs = [ pythonPackages.flask pkgs.system-sendmail ]; + + installPhase = '' + runHook preInstall + + mkdir -p $out/${pythonPackages.python.sitePackages} + cp -r . $out/${pythonPackages.python.sitePackages}/gmail_mail_bridge + + runHook postInstall + ''; + + shellHook = "export FLASK_APP=gmail_mail_bridge"; + + format = "other"; +} diff --git a/builds/gmail_mail_bridge/gmail_mail_bridge/__init__.py b/builds/gmail_mail_bridge/gmail_mail_bridge/__init__.py new file mode 100644 index 0000000..e6a7241 --- /dev/null +++ b/builds/gmail_mail_bridge/gmail_mail_bridge/__init__.py @@ -0,0 +1,37 @@ +from flask import Flask +from flask import request +from flask import redirect +from flask import abort + +import logging + +import smtplib +import email + +from subprocess import Popen, PIPE, STDOUT + +pre_shared_secret = "amongus sussy imposter" +to = "ryan@beepboop.systems" + +app = Flask(__name__) + +def handle_post(request): + msg = email.message_from_string(request.form["payload"]) + del msg["To"] + msg["To"] = to + if not msg["From"]: + msg["From"] = "unknown-sender@mail.beepboop.systems" + + s = smtplib.SMTP('localhost') + s.send_message(msg) + s.quit() + +@app.route("/bridge-submit", methods = ["GET", "POST"]) +def testing(): + if request.method == 'POST': + data = request.form + if data['auth'] == pre_shared_secret: + handle_post(request) + else: + return 'you didn\'t use post' + return "default answer" diff --git a/builds/gmail_mail_bridge/shell.nix b/builds/gmail_mail_bridge/shell.nix new file mode 100644 index 0000000..abd9f69 --- /dev/null +++ b/builds/gmail_mail_bridge/shell.nix @@ -0,0 +1,12 @@ +{ pkgs ? import (fetchTarball "https://github.com/NixOS/nixpkgs/tarball/nixos-23.11") {} }: + +pkgs.mkShell { + packages = [ + (pkgs.python3.withPackages (ps: [ + ps.flask + ])) + + pkgs.curl + pkgs.jq + ]; +} diff --git a/builds/gmail_mail_bridge/sync.gas b/builds/gmail_mail_bridge/sync.gas new file mode 100644 index 0000000..0df9d17 --- /dev/null +++ b/builds/gmail_mail_bridge/sync.gas @@ -0,0 +1,23 @@ +// google-side synchronization +// add a minute-wise trigger for mail synchronization +// go to the sidebar, select triggers, add a new one, configure it +// to run syncMail every minute + +function syncMail() { + var threads = GmailApp.search("label:need_processing"); + var label = GmailApp.getUserLabelByName("need_processing"); + for (var thread of threads) { + for (var message of GmailApp.getMessagesForThread(thread)) { + var formData = { + auth: 'amongus sussy imposter', + payload: message.getRawContent(), + }; + var options = { + 'method' : 'POST', + 'payload' : formData + }; + var resp = UrlFetchApp.fetch('https://mail.beepboop.systems/bridge-submit', options); + } + thread.removeLabel(label); + } +} diff --git a/flake.lock b/flake.lock index 56996e5..430a6ad 100644 --- a/flake.lock +++ b/flake.lock @@ -209,12 +209,12 @@ }, "locked": { "lastModified": 1, - "narHash": "sha256-Q/utpukYR3ZDNlXzUFtDrlmLDfusxdseH6THPh9JrQc=", - "path": "/nix/store/6c7g2njv4c637rnhc7vxqvk9xcbq9ghf-source/builds", + "narHash": "sha256-3icKqIEjS068WDJ+05sEvFDL6DsPB0GpKTc8Bm4F9Po=", + "path": "/nix/store/9797g0387xqz764w22ascnvn3bvm90kd-source/builds", "type": "path" }, "original": { - "path": "/nix/store/6c7g2njv4c637rnhc7vxqvk9xcbq9ghf-source/builds", + "path": "/nix/store/9797g0387xqz764w22ascnvn3bvm90kd-source/builds", "type": "path" } }, diff --git a/flake.nix b/flake.nix index 06e0817..2a1dfcb 100644 --- a/flake.nix +++ b/flake.nix @@ -82,13 +82,6 @@ specialArgs = { inherit inputs; }; modules = [ ./boxes/mainsail - - home-manager.nixosModules.home-manager { - home-manager.useGlobalPkgs = true; - home-manager.useUserPackages = true; - home-manager.extraSpecialArgs = { inherit inputs; }; - home-manager.users.usr = import ./boxes/mainsail/home.nix; - } ]; }; }; diff --git a/modules/ssh-phone-home.nix b/modules/ssh-phone-home.nix new file mode 100644 index 0000000..d1e74b9 --- /dev/null +++ b/modules/ssh-phone-home.nix @@ -0,0 +1,105 @@ +{ config, lib, pkgs, ... }: + +# with thanks to +# https://www.auntieneo.net/2014/12/14/reverse-ssh-tunnel-on-nixos-with-systemd/ + +with lib; + +let + inherit (pkgs) openssh; + cfg = config.services.ssh-phone-home; +in + +{ + + ###### interface + + options = { + services.ssh-phone-home = { + enable = mkOption { + type = types.bool; + default = false; + description = '' + Whether to enable a "phone home" reverse SSH proxy. + ''; + }; + + persist = mkOption { + type = types.bool; + default = true; + description = '' + When this is set to true, the service will persistently attempt to + reconnect at intervals whenever the port forwarding operation fails. + This is the recommended behavior for reliable operation. If one finds + oneself in an environment where this kind of behavior might draw the + suspicion of a network administrator, it might be a good idea to + set this option to false (or not use ssh-phone-home + at all). + ''; + }; + + localUser = mkOption { + description = '' + Local user to connect as (i.e. the user with password-less SSH keys). + ''; + }; + + remoteHostname = mkOption { + description = '' + The remote host to connect to. This should be the host outside of the + firewall or NAT. + ''; + }; + + remotePort = mkOption { + default = 22; + description = '' + The port on which to connect to the remote host via SSH protocol. + ''; + }; + + remoteUser = mkOption { + description = '' + The username to connect to the remote host as. + ''; + }; + + bindPort = mkOption { + default = 2222; + description = '' + The port to bind and listen to on the remote host. + ''; + }; + }; + }; + + + ###### implementation + + config = mkIf cfg.enable { + systemd.services.ssh-phone-home = + { + description = '' + Reverse SSH tunnel as a service + ''; + + # FIXME: This isn't triggered until a reboot, and probably won't work between suspends. + wantedBy = [ "multi-user.target" ]; + + serviceConfig = with cfg; { + User = cfg.localUser; + } // (if cfg.persist then + { + # Restart every 10 seconds on failure + RestartSec = 10; + Restart = "on-failure"; + } + else {} + ); + + script = with cfg; '' + ${openssh}/bin/ssh -NTC -o ServerAliveInterval=30 -o ExitOnForwardFailure=yes -R ${toString bindPort}:localhost:22 -l ${remoteUser} -p ${toString remotePort} ${remoteHostname} + ''; + }; + }; +}