~codelongandpros/tilde-hack

849668bfd9a1adadfdc9786e79b5abf897f3fe3e — Scott Little 8 months ago
first
A  => about/about.py +41 -0
@@ 1,41 @@
#!/usr/bin/env python3
import json
import os
import argparse
import getpass

parser = argparse.ArgumentParser(description="Get bio information about other users")
parser.add_argument("--edit", type=str)
parser.add_argument("user", default="", nargs="?")
args = parser.parse_args()

def load_user_json(username):
    with open(os.path.join("/opt/pub/about", username + ".json")) as f:
        return json.load(f)
def save_user_json(username, info):
    with open(os.path.join("/opt/pub/about", username + ".json"), "w") as f:
        json.dump(info, f)

if args.edit:
    data = load_user_json(getpass.getuser())
    with open(0) as stdin:
        new_data = stdin.read().rstrip()
    if args.edit not in data.keys():
        print(f"{args.edit}: not a vaild field")
        exit(2)
    data[args.edit] = new_data
    save_user_json(getpass.getuser(), data)
elif args.user:
    data = load_user_json(args.user)
    print(f"username: \033[31m{data['username']}\033[0m")
    print(f"full name: \033[32m{data['full_name']}\033[0m")
    print(f"nickname: \033[32m{data['nick']}\033[0m")
    print(f"pronouns: \033[33m{data['pronouns']}\033[0m")
    print(f"working on: \033[34m{data['working_on']}\033[0m")
    print(f"bio: \033[35m{data['bio']}\033[0m")
    print(f"irc: \033[36m{data['irc']}\033[0m")
    print(f"email: \033[36m{data['username']}@tilde.hackclub.com\033[0m")
else:
    print("Exactly one of --edit or USER must be given")
    parser.print_usage()
    exit(1)

A  => about/default.nix +12 -0
@@ 1,12 @@
{ pkgs ? import <nixpkgs> {}, ...}:
with pkgs;
stdenv.mkDerivation {
  pname = "about";
  version = "0.0.0";
  src = ./.;
  buildInputs = [ python39 ];
  dontBuild = true;
  installPhase = ''
    install -Dm755 $src/about.py $out/bin/about
  '';
}
\ No newline at end of file

A  => about/result +1 -0
@@ 1,1 @@
/nix/store/pisnll14s9prmrvkw4a4w7dfgrv79pyy-about-0.0.0
\ No newline at end of file

A  => about/test.json +1 -0
@@ 1,1 @@
{"username": "test", "full_name": "Test McTestyface", "pronouns": "she/her", "bio": "I'm dead, F", "working_on": "becoming alive", "irc":"test101", "email": "test@tilde.hackclub.com", "nick": "arst"}

A  => about/test/.me +7 -0
@@ 1,7 @@
{
  "username": "test",
  "full_name": "Test McTestyface",
  "pronouns": "all of them",
  "bio": "I'm dead, F",
  "working_on": "becoming alive"
}

A  => addusr/addusr.nix +13 -0
@@ 1,13 @@
{ pkgs ? import <nixpkgs> {}, ...}:
with pkgs;
stdenv.mkDerivation {
  pname = "addusr";
  version = "0.0.1";
  src = ./addusr.py;
  buildInputs = [ python39 ];
  dontUnpack = true;
  dontBuild = true;
  installPhase = ''
    install -Dm755 $src $out/bin/addusr
  '';
}

A  => addusr/addusr.py +30 -0
@@ 1,30 @@
#!/usr/bin/env python3
import sys
import os
if len(sys.argv) != 4:
    print(f"Usage: {sys.argv[0]} username real_name ssh_token")
    exit(1)
with open(f"users/{sys.argv[1]}.nix", "w") as f:
    contents = """
{ pkgs, ... }:
{
users.users."%s" = {
  description = "%s";
  isNormalUser = true;
  shell = pkgs.fish;
  openssh.authorizedKeys.keys = [ "%s" ];
};
}
""" % (sys.argv[1], sys.argv[2], sys.argv[3])
    f.write(contents)
with open("users/default.nix", "w") as f:
    files = [' ' * 4 + './' + file for file in os.listdir("users") if file != "default.nix"]
    contents = """
{ ... }:
{
  imports = [
%s
  ];
}
""" % ('\n'.join(files))
    f.write(contents)

A  => configuration.nix +119 -0
@@ 1,119 @@
# Edit this configuration file to define what should be installed on
# your system.  Help is available in the configuration.nix(5) man page
# and in the NixOS manual (accessible by running ‘nixos-help’).

{ config, pkgs, ... }:
let
  addusr = (import ./setupusr/addusr.nix {});
  newusersetup = (import ./newusersetup.nix {});
  about = (import ./about {});
in
{
  imports =
    [ # Include the results of the hardware scan.
      ./hardware-configuration.nix
      ./nginx.nix
      ./users
      ./mollybrown.nix
      ./irc.nix
      ./email.nix
      ./packages
    ];

  # Use the GRUB 2 boot loader.
  boot.loader.grub.enable = true;
  boot.loader.grub.version = 2;
  # boot.loader.grub.efiSupport = true;
  # boot.loader.grub.efiInstallAsRemovable = true;
  # boot.loader.efi.efiSysMountPoint = "/boot/efi";
  # Define on which hard drive you want to install Grub.
  boot.loader.grub.device = "/dev/sda"; # or "nodev" for efi only

  networking.hostName = "hacktilde"; # Define your hostname.
  # networking.wireless.enable = true;  # Enables wireless support via wpa_supplicant.

  # Set your time zone.
  time.timeZone = "America/Chicago";

  # The global useDHCP flag is deprecated, therefore explicitly set to false here.
  # Per-interface useDHCP will be mandatory in the future, so this generated config
  # replicates the default behaviour.
  networking.useDHCP = false;
  #networking.defaultGateway.address = "10.101.8.1";
  #networking.interfaces.ens3.useDHCP = true;
  networking.interfaces.ens18.useDHCP = true;
  #networking.interfaces.enr18.ipv4.addresses = [ { address = "10.101.13.164"; prefixLength = 16; } ];

  # Configure network proxy if necessary
  # networking.proxy.default = "http://user:password@proxy:port/";
  # networking.proxy.noProxy = "127.0.0.1,localhost,internal.domain";

  # Select internationalisation properties.
  # i18n.defaultLocale = "en_US.UTF-8";
  # console = {
  #   font = "Lat2-Terminus16";
  #   keyMap = "us";
  # };

  # Enable the X11 windowing system.
  # services.xserver.enable = true;


  

  # Configure keymap in X11
  # services.xserver.layout = "us";
  # services.xserver.xkbOptions = "eurosign:e";

  # Enable CUPS to print documents.
  # services.printing.enable = true;

  # Enable sound.
  # sound.enable = true;
  # hardware.pulseaudio.enable = true;

  # Enable touchpad support (enabled default in most desktopManager).
  # services.xserver.libinput.enable = true;

  # Define a user account. Don't forget to set a password with ‘passwd’.

  # List packages installed in system profile. To search, run:
  # $ nix search wget
  environment.systemPackages = with pkgs; [
    wget
    addusr
    newusersetup    
    about
  ];

  # Some programs need SUID wrappers, can be configured further or are
  # started in user sessions.
  # programs.mtr.enable = true;
  # programs.gnupg.agent = {
  #   enable = true;
  #   enableSSHSupport = true;
  # };

  nix.allowedUsers = [ "root" ];
  # List services that you want to enable:
  
  # Enable the OpenSSH daemon.
  services.openssh.enable = true;
  services.openssh.passwordAuthentication = false;
  
  # Open ports in the firewall.
  networking.firewall.allowedTCPPorts = [ 22 80 443 6697 ];
  # networking.firewall.allowedUDPPorts = [ ... ];
  # Or disable the firewall altogether.
  # networking.firewall.enable = false;

  # 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.05"; # Did you read the comment?

}


A  => configuration.nix~ +119 -0
@@ 1,119 @@
# Edit this configuration file to define what should be installed on
# your system.  Help is available in the configuration.nix(5) man page
# and in the NixOS manual (accessible by running ‘nixos-help’).

{ config, pkgs, ... }:
let
  addusr = (import ./setupusr/addusr.nix {});
  newusersetup = (import ./newusersetup.nix {});
  about = (import ./about {});
in
{
  imports =
    [ # Include the results of the hardware scan.
      ./hardware-configuration.nix
      ./nginx.nix
      ./users
      ./mollybrown.nix
      ./irc.nix
      ./email.nix
      ./packages
    ];

  # Use the GRUB 2 boot loader.
  boot.loader.grub.enable = true;
  boot.loader.grub.version = 2;
  # boot.loader.grub.efiSupport = true;
  # boot.loader.grub.efiInstallAsRemovable = true;
  # boot.loader.efi.efiSysMountPoint = "/boot/efi";
  # Define on which hard drive you want to install Grub.
  boot.loader.grub.device = "/dev/sda"; # or "nodev" for efi only

  networking.hostName = "hacktilde"; # Define your hostname.
  # networking.wireless.enable = true;  # Enables wireless support via wpa_supplicant.

  # Set your time zone.
  time.timeZone = "America/Chicago";

  # The global useDHCP flag is deprecated, therefore explicitly set to false here.
  # Per-interface useDHCP will be mandatory in the future, so this generated config
  # replicates the default behaviour.
  networking.useDHCP = false;
  #networking.defaultGateway.address = "10.101.8.1";
  #networking.interfaces.ens3.useDHCP = true;
  networking.interfaces.ens18.useDHCP = true;
  #networking.interfaces.enr18.ipv4.addresses = [ { address = "10.101.13.164"; prefixLength = 16; } ];

  # Configure network proxy if necessary
  # networking.proxy.default = "http://user:password@proxy:port/";
  # networking.proxy.noProxy = "127.0.0.1,localhost,internal.domain";

  # Select internationalisation properties.
  # i18n.defaultLocale = "en_US.UTF-8";
  # console = {
  #   font = "Lat2-Terminus16";
  #   keyMap = "us";
  # };

  # Enable the X11 windowing system.
  # services.xserver.enable = true;


  

  # Configure keymap in X11
  # services.xserver.layout = "us";
  # services.xserver.xkbOptions = "eurosign:e";

  # Enable CUPS to print documents.
  # services.printing.enable = true;

  # Enable sound.
  # sound.enable = true;
  # hardware.pulseaudio.enable = true;

  # Enable touchpad support (enabled default in most desktopManager).
  # services.xserver.libinput.enable = true;

  # Define a user account. Don't forget to set a password with ‘passwd’.

  # List packages installed in system profile. To search, run:
  # $ nix search wget
  environment.systemPackages = with pkgs; [
    wget
    addusr
    newusersetup
    about
  ];

  # Some programs need SUID wrappers, can be configured further or are
  # started in user sessions.
  # programs.mtr.enable = true;
  # programs.gnupg.agent = {
  #   enable = true;
  #   enableSSHSupport = true;
  # };

  nix.allowedUsers = [ "root" ];
  # List services that you want to enable:
  
  # Enable the OpenSSH daemon.
  services.openssh.enable = true;
  services.openssh.passwordAuthentication = false;
  
  # Open ports in the firewall.
  networking.firewall.allowedTCPPorts = [ 22 80 443 6697 ];
  # networking.firewall.allowedUDPPorts = [ ... ];
  # Or disable the firewall altogether.
  # networking.firewall.enable = false;

  # 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.05"; # Did you read the comment?

}


A  => email.nix +19 -0
@@ 1,19 @@
{ pkgs, ...}:
{
  environment.systemPackages = with pkgs; [
    aerc
    mailutils
    neomutt
    mutt
  ];
  services.postfix = {
    enable = true;
    config = {
      myhostname = "localhost";
      mydomain = "localhost";
      mynetworks = "127.0.0.1";
      home_mailbox = "mail/";
      mailbox_command = "";
    };
  };
}

A  => hardware-configuration.nix +29 -0
@@ 1,29 @@
# Do not modify this file!  It was generated by ‘nixos-generate-config’
# and may be overwritten by future invocations.  Please make changes
# to /etc/nixos/configuration.nix instead.
{ config, lib, pkgs, modulesPath, ... }:

{
  imports =
    [ (modulesPath + "/profiles/qemu-guest.nix")
    ];

  boot.initrd.availableKernelModules = [ "ata_piix" "floppy" "sd_mod" "sr_mod" ];
  boot.initrd.kernelModules = [ ];
  boot.kernelModules = [ ];
  boot.extraModulePackages = [ ];

  fileSystems."/" =
    { device = "/dev/disk/by-uuid/ea63ef85-3e1b-4ec4-b733-f74219737c65";
      fsType = "ext4";
      autoResize = true;
    };

  fileSystems."/boot" =
    { device = "/dev/disk/by-uuid/31fe09f6-d8fc-4367-97ff-b17c8f6af1e0";
      fsType = "ext2";
    };

  swapDevices = [ ];

}

A  => irc.nix +27 -0
@@ 1,27 @@
{ pkgs, ... }:
{
  environment.systemPackages = with pkgs; [
    irssi
  ];
  services.inspircd = {
    enable = true;
    config = ''
    <server
      name="localhost"
      description="Hack Club local IRC server"
      network="~Hack">
    <admin
      name="Madeline"
      nick="maddie"
      email="hack@club">
    <bind
      address="0.0.0.0"
      port="6697"
      type="clients">
    <connect
      name="main"
      allow="*"
      maxchans="1">
 '';
  };
}

A  => mollybrown.nix +14 -0
@@ 1,14 @@
{ ... }:
{
  systemd.services.molly-brown.serviceConfig.SupplementaryGroups = [ "root" ];
  services.molly-brown = {
    enable = true;
    certPath = "/srv/gmi/cert.crt";
    keyPath = "/srv/gmi/key.key";
    docBase = "/srv/gmi";
    hostName = "localhost";
    settings = {
      homeDocBase = "/srv/pub/gmi";
    };
  };
}

A  => newusersetup.nix +2 -0
@@ 1,2 @@
{ pkgs ? import <nixpkgs> {}, ...}:
pkgs.writeShellScriptBin "newusersetup" (builtins.readFile ./newusersetup.sh)

A  => newusersetup.sh +231 -0
@@ 1,231 @@
#!/usr/bin/env bash
set -e
RED="$(tput setaf 1)"
GREEN="$(tput setaf 2)"
YELLOW="$(tput setaf 3)"
BLUE="$(tput setaf 4)"

USERNAME="$(id -nu)"
ID="$(grep "^$USERNAME:" /etc/passwd)"
REAL_NAME="$(cut -d: -f5 <<< $ID)"
BOLD=$(tput bold)
NORMAL=$(tput sgr0)
cat << EOF
${BOLD}     ___                              __
    / / |                            / /
   / /| |__   ___  _ __ ___   ___   / / 
  / / | '_ \ / _ \| '_ \` _ \ / _ \ / /  
 / /  | | | | (_) | | | | | |  __// /   
/_/   |_| |_|\___/|_| |_| |_|\___/_/${NORMAL}
Welcome to the Hack Club Tilde!
This is the 'first-time' setup program, which will setup your ~ for you.
First things first:
EOF

BAD_ERR="Oh no!
This means that Madeline probably messed something up along the way...
Contact them on slack (@swlittle7) to fix this."

while :; do
read -p "Is this your username? $USERNAME [Y/n] " USERNAME_VAILD
if [[ "$USERNAME_VAILD" = "n" ]]; then
   echo "$BAD_ERR"
   exit 1
fi
if [[ "$USERNAME_VAILD" = "y" ]]; then
   break
fi
echo "That's not a vaild answer, you need to type 'y' or 'n'"
done

while :; do
read -p "Is this correct? $REAL_NAME [Y/n] " NAME
if [[ "$NAME" = "n" ]]; then
   echo "$BAD_ERR"
   exit 1
fi

if [[ "$NAME" = "y" ]]; then
	break
fi
echo "That's not a valid answer, you need to type 'y' or 'n'"
done

cat <<EOF
Now, we have a system to give some basic info about a user (like Slack profiles).
Don't worry, you can always change these later with \`$ about --edit\`
To get another user's info, run \`$ about USERNAME\`
EOF

cat > "/opt/pub/about/${USER}.json"<<EOF
{"username": "", "full_name": "", "pronouns": "", "bio": "", "working_on": "", "irc":"", "nick": ""}
EOF
read -p "What are your preffered pronouns? " PRONOUNS
read -p "What's your full name? " FULLNAME
read -p "What do you go by? " NICK
read -p "Are you working on any projects? (Press enter for none) " PROJ
read -p "What's your IRC nick? (If you don't know, put your username) " IRC
about --edit username <<< "$USER"
about --edit full_name <<< "$FULLNAME"
about --edit pronouns <<< "$PRONOUNS"
about --edit nick <<< "$NICK"
about --edit working_on <<< "$PROJ"
about --edit irc <<< "$IRC"

BIOFILE="$(mktemp)"
cat <<EOF
The 'nano' editor will now open so that you can edit your bio.
Feel free to make this as short or long as you wish.
Press 'Ctrl+x', then 'y' to exit
EOF
read -p "[Press enter]" NOTHING
nano "$BIOFILE"
about --edit bio < "$BIOFILE"
rm "$BIOFILE"
AST="${BOLD}*${NORMAL}"
cat << EOF

Now that we know that your username and real name is correct, let's choose your shell.
There are three shells:
$AST ${RED}Bash${NORMAL}
$AST ${GREEN}ZSH${NORMAL}
$AST ${YELLOW}Fish${NORMAL}

${RED}Bash${NORMAL} is a simple shell, without lots of features set up out of the box. Its syntax looks like:
${BLUE}\$ while :; do; foo; done${NORMAL}
${GREEN}ZSH${NORMAL} is pretty similar to Bash, except it has more features set up and frameworks to help you manange it. It looks like bash:
${BLUE}\$ while :; do; foo; done${NORMAL}
${YELLOW}Fish${NORMAL} has lots of features and is easy to set up, but it differs from bash in several ways. Fish looks like:
${BLUE}\$ while true
>       foo
> end${NORMAL}
(You'll need to enter your password to change your shell)
EOF

while :
do
   read -p "What shell do you want? [fish/zsh/bash] " NEWSHELL;
   if [[ "$NEWSHELL" = "fish" ]]; then
      echo "exec $(which fish)" >> ~/.bashrc
      break;
   elif [[ "$NEWSHELL" = "zsh" ]]; then
      echo "exec $(which zsh)" >> ~/.bashrc
      break;
   elif [[ "$NEWSHELL" = "bash" ]]; then
      break;
   else
      echo "Sorry, that's not a shell, please enter 'bash', 'zsh' or 'fish'";
   fi; done
cat << EOF
${BOLD}                                  __
                                 / /
__      ____      ____      __  / / 
\ \ /\ / /\ \ /\ / /\ \ /\ / / / /  
 \ V  V /  \ V  V /  \ V  V / / /   
  \_/\_/    \_/\_/    \_/\_(_)_/
${NORMAL}
It's time to set up your (free) web hosting now!
(Note, it only supports static HTML/CSS/JS)
EOF
while :; do
read -p "Do you want to setup web hosting? [Y/n] " WEB
if [[ "$WEB" = "y" ]]; then
cat << EOF
There are a few rules:
- The CORS disallows loading from CDN's  external scrips
- Only static HTML/CSS/JS
- Don't be evil
To add files, drop them into \~/public/www
EOF
   while :; do
     read -p "Got it? [Y/n] " GOTIT
     if [[ "$GOTIT" = "y" ]]; then
         break
     fi
     echo "Please say 'y'"
   done
   if [[ ! -d ~/public ]]; then
      echo mkdir ~/public
   fi
   echo ln -s /srv/pub/$USER/www ~/public/www
   break
elif [[ "$WEB" = "n" ]]; then
   break
fi
echo "$WEB isn't a 'y' or an 'n'"
done

cat << EOF
${BOLD}                 _       __
                (_)     / /
  __ _ _ __ ___  _     / / 
 / _\` | '_ \` _ \| |   / /  
| (_| | | | | | | |_ / /   
 \__, |_| |_| |_|_(_)_/    
  __/ |                    
 |___/${NORMAL}
There's also Gemini hosting (also free)!
If you haven't heard of Gemini, check it out at https://gemini.circumlunar.space 
EOF

while :; do
   read -p "Do you want to setup your gemini hosting? [Y/n] " GEMINI
   if [[ "$GEMINI" = "y" ]]; then
cat << EOF
To put files into geminispace, drop them into ~/public/gmi
The only rule is 'Don't be evil'
EOF
   while :; do
     read -p "Got it? [Y/n] " GOTIT
     if [[ "$GOTIT" = "y" ]]; then
         break
     fi
     echo "Please say 'y'"
   done
      if [[ ! -d ~/public ]]; then
         echo mkdir ~/public
      fi
      echo ln -s /srv/pub/$USER/gmi ~/public/gmi
      break
   elif [[ "$GEMINI" = "n" ]]; then
      break
   fi
done
cat <<EOF
To check your local mail, use neomutt.
Mail is stored in ~/mail.
More info is under \`hcwiki tilde/email\`.
EOF

cat > ~/.muttrc <<EOF
set mbox_type=Maildir
set folder="~/mail"
set spoolfile="~/mail"
set mbox="~/mail"
set mask="!^\\.[^.]"
set sendmail="/run/wrappers/bin/sendmail"
EOF

cat << EOF

You're cleared for liftoff! To find out more, try doing \`wiki tilde/intro\`
If you need to contact an admin, they are:
Madeline: maddie on IRC, madeline@tilde.hackclub.com

${BOLD}
  /\\
  ||
  ||
 /||\\
/:||:\\
|:||:|
|/||\|
${RED}  **
  **
${NORMAL}
(You'll need to log out to have these changes take effect)
Hit enter to log out...
EOF
read NOTHING
sed -e 's/exec newusersetup//' -i ~/.bash_profile
exit

A  => newusersetup.sh~ +231 -0
@@ 1,231 @@
#!/usr/bin/env bash
set -e
RED="$(tput setaf 1)"
GREEN="$(tput setaf 2)"
YELLOW="$(tput setaf 3)"
BLUE="$(tput setaf 4)"

USERNAME="$(id -nu)"
ID="$(grep "^$USERNAME:" /etc/passwd)"
REAL_NAME="$(cut -d: -f5 <<< $ID)"
BOLD=$(tput bold)
NORMAL=$(tput sgr0)
cat << EOF
${BOLD}     ___                              __
    / / |                            / /
   / /| |__   ___  _ __ ___   ___   / / 
  / / | '_ \ / _ \| '_ \` _ \ / _ \ / /  
 / /  | | | | (_) | | | | | |  __// /   
/_/   |_| |_|\___/|_| |_| |_|\___/_/${NORMAL}
Welcome to the Hack Club Tilde!
This is the 'first-time' setup program, which will setup your ~ for you.
First things first:
EOF

BAD_ERR="Oh no!
This means that Madeline probably messed something up along the way...
Contact them on slack (@swlittle7) to fix this."

while :; do
read -p "Is this your username? $USERNAME [Y/n] " USERNAME_VAILD
if [[ "$USERNAME_VAILD" = "n" ]]; then
   echo "$BAD_ERR"
   exit 1
fi
if [[ "$USERNAME_VAILD" = "y" ]]; then
   break
fi
echo "That's not a vaild answer, you need to type 'y' or 'n'"
done

while :; do
read -p "Is this correct? $REAL_NAME [Y/n] " NAME
if [[ "$NAME" = "n" ]]; then
   echo "$BAD_ERR"
   exit 1
fi

if [[ "$NAME" = "y" ]]; then
	break
fi
echo "That's not a valid answer, you need to type 'y' or 'n'"
done

cat <<EOF
Now, we have a system to give some basic info about a user (like Slack profiles).
Don't worry, you can always change these later with \`$ about --edit\`
To get another user's info, run \`$ about USERNAME\`
EOF

cat > "/opt/pub/about/${USER}.json"<<EOF
{"username": "", "full_name": "", "pronouns": "", "bio": "", "working_on": "", "irc":"", "nick": ""}
EOF
read -p "What are your preffered pronouns? " PRONOUNS
read -p "What's your full name? " FULLNAME
read -p "What do you go by? " NICK
read -p "Are you working on any projects? (Press enter for none) " PROJ
read -p "What's your IRC nick? (If you don't know, put your username) " IRC
about --edit username <<< "$USER"
about --edit full_name <<< "$FULLNAME"
about --edit pronouns <<< "$PRONOUNS"
about --edit nick <<< "$NICK"
about --edit working_on <<< "$PROJ"
about --edit irc <<< "$IRC"

BIOFILE="$(mktemp)"
cat <<EOF
The 'nano' editor will now open so that you can edit your bio.
Feel free to make this as short or long as you wish.
Press 'Ctrl+x', then 'y' to exit
EOF
read -p "[Press enter]" NOTHING
nano "$BIOFILE"
about --edit bio < "$BIOFILE"
rm "$BIOFILE"
AST="${BOLD}*${NORMAL}"
cat << EOF

Now that we know that your username and real name is correct, let's choose your shell.
There are three shells:
$AST ${RED}Bash${NORMAL}
$AST ${GREEN}ZSH${NORMAL}
$AST ${YELLOW}Fish${NORMAL}

${RED}Bash${NORMAL} is a simple shell, without lots of features set up out of the box. Its syntax looks like:
${BLUE}\$ while :; do; foo; done${NORMAL}
${GREEN}ZSH${NORMAL} is pretty similar to Bash, except it has more features set up and frameworks to help you manange it. It looks like bash:
${BLUE}\$ while :; do; foo; done${NORMAL}
${YELLOW}Fish${NORMAL} has lots of features and is easy to set up, but it differs from bash in several ways. Fish looks like:
${BLUE}\$ while true
>       foo
> end${NORMAL}
(You'll need to enter your password to change your shell)
EOF

while :
do
   read -p "What shell do you want? [fish/zsh/bash] " NEWSHELL;
   if [[ "$NEWSHELL" = "fish" ]]; then
      echo "exec $(which fish)" >> ~/.bashrc
      break;
   elif [[ "$NEWSHELL" = "zsh" ]]; then
      echo "exec $(which zsh)" >> ~/.bashrc
      break;
   elif [[ "$NEWSHELL" = "bash" ]]; then
      break;
   else
      echo "Sorry, that's not a shell, please enter 'bash', 'zsh' or 'fish'";
   fi; done
cat << EOF
${BOLD}                                  __
                                 / /
__      ____      ____      __  / / 
\ \ /\ / /\ \ /\ / /\ \ /\ / / / /  
 \ V  V /  \ V  V /  \ V  V / / /   
  \_/\_/    \_/\_/    \_/\_(_)_/
${NORMAL}
It's time to set up your (free) web hosting now!
(Note, it only supports static HTML/CSS/JS)
EOF
while :; do
read -p "Do you want to setup web hosting? [Y/n] " WEB
if [[ "$WEB" = "y" ]]; then
cat << EOF
There are a few rules:
- The CORS disallows loading from CDN's  external scrips
- Only static HTML/CSS/JS
- Don't be evil
To add files, drop them into \~/public/www
EOF
   while :; do
     read -p "Got it? [Y/n] " GOTIT
     if [[ "$GOTIT" = "y" ]]; then
         break
     fi
     echo "Please say 'y'"
   done
   if [[ ! -d ~/public ]]; then
      echo mkdir ~/public
   fi
   echo ln -s /srv/pub/$USER/www ~/public/www
   break
elif [[ "$WEB" = "n" ]]; then
   break
fi
echo "$WEB isn't a 'y' or an 'n'"
done

cat << EOF
${BOLD}                 _       __
                (_)     / /
  __ _ _ __ ___  _     / / 
 / _\` | '_ \` _ \| |   / /  
| (_| | | | | | | |_ / /   
 \__, |_| |_| |_|_(_)_/    
  __/ |                    
 |___/${NORMAL}
There's also Gemini hosting (also free)!
If you haven't heard of Gemini, check it out at https://gemini.circumlunar.space 
EOF

while :; do
   read -p "Do you want to setup your gemini hosting? [Y/n] " GEMINI
   if [[ "$GEMINI" = "y" ]]; then
cat << EOF
To put files into geminispace, drop them into ~/public/gmi
The only rule is 'Don't be evil'
EOF
   while :; do
     read -p "Got it? [Y/n] " GOTIT
     if [[ "$GOTIT" = "y" ]]; then
         break
     fi
     echo "Please say 'y'"
   done
      if [[ ! -d ~/public ]]; then
         echo mkdir ~/public
      fi
      echo ln -s /srv/pub/$USER/gmi ~/public/gmi
      break
   elif [[ "$GEMINI" = "n" ]]; then
      break
   fi
done
cat <<EOF
To check your local mail, use neomutt.
Mail is stored in ~/mail.
More info is under \`hcwiki tilde/email\`.
EOF

cat > ~/.muttrc <<EOF
set mbox_type=Maildir
set folder="~/mail"
set spoolfile="~/mail"
set mbox="~/mail"
set mask="!^\\.[^.]"
set sendmail="/run/wrappers/bin/sendmail"
EOF

cat << EOF

You're cleared for liftoff! To find out more, try doing \`wiki tilde/intro\`
If you need to contact an admin, they are:
Madeline: maddie on IRC, madeline@tilde.hackclub.com

${BOLD}
  /\\
  ||
  ||
 /||\\
/:||:\\
|:||:|
|/||\|
${RED}  **
  **
${NORMAL}
(You'll need to log out to have these changes take effect)
Hit enter to log out...
EOF
read NOTHING
sed -e 's/exec newusersetup//' -i ~/.bashrc
exit

A  => nginx.nix +22 -0
@@ 1,22 @@
{ pkgs, ... }:
{
  services.nginx = {
    enable = true;
    virtualHosts = {
      "localhost" = {
        locations = {
          "/" = {
            root = "/srv/www";
          };
          "~ ^/~(.+?)(/.*)?$" = {
            alias = "/srv/pub/$1/www$2";
            extraConfig = ''
             autoindex on;
	     add_header Content-Security-Policy "default-src 'self' 'unsafe-eval' 'unsafe-inline'; sandbox allow-forms allow-orientation-lock allow-pointer-lock allow-presentation allow-scripts allow-same-origin";
            '';
          };
        };
      };
    };
  };
}

A  => packages/cli/editors.pkgs +5 -0
@@ 1,5 @@
emacs
vim
neovim
nano
micro

A  => packages/cli/multiplexers.pkgs +3 -0
@@ 1,3 @@
screen
tmux
zellij

A  => packages/cli/shells.pkgs +4 -0
@@ 1,4 @@
bashInteractive
fish
zsh
starship

A  => packages/cli/vcs.pkgs +2 -0
@@ 1,2 @@
mercurial
gitFull

A  => packages/default.nix +30 -0
@@ 1,30 @@
{ pkgs, ... }:
{
  environment.systemPackages = with pkgs; [
aerc
amfora
bashInteractive
deno
dmd
dub
emacs
fish
gitFull
gnumake
ldc
mercurial
micro
mutt
nano
neomutt
neovim
rdmd
screen
ssmtp
starship
tmux
vim
zellij
zsh
  ];
}

A  => packages/generate.sh +15 -0
@@ 1,15 @@
#!/usr/bin/env bash
set -e
PKGS="$(find . -type f -name '*.pkgs' -exec cat {} +)"
echo "$PKGS"
echo "==="
ALLPKGS="$(uniq <<< "$PKGS" | sort)"
echo "$ALLPKGS"
cat > default.nix <<EOF
{ pkgs, ... }:
{
  environment.systemPackages = with pkgs; [
${ALLPKGS}
  ];
}
EOF

A  => packages/networking/gemini.pkgs +1 -0
@@ 1,1 @@
amfora

A  => packages/networking/mail.pkgs +4 -0
@@ 1,4 @@
mutt
neomutt
aerc
ssmtp

A  => packages/progs/c.pkgs +1 -0
@@ 1,1 @@
gnumake

A  => packages/progs/d.pkgs +4 -0
@@ 1,4 @@
dub
dmd
rdmd
ldc

A  => packages/progs/js.pkgs +1 -0
@@ 1,1 @@
deno

A  => setupusr/addusr.nix +13 -0
@@ 1,13 @@
{ pkgs ? import <nixpkgs> {}, ...}:
with pkgs;
stdenv.mkDerivation {
  pname = "addusr";
  version = "0.0.2";
  src = ./addusr.py;
  buildInputs = [ python39 ];
  dontUnpack = true;
  dontBuild = true;
  installPhase = ''
    install -Dm755 $src $out/bin/addusr
  '';
}

A  => setupusr/addusr.nix~ +13 -0
@@ 1,13 @@
{ pkgs ? import <nixpkgs> {}, ...}:
with pkgs;
stdenv.mkDerivation {
  pname = "addusr";
  version = "0.0.1";
  src = ./addusr.py;
  buildInputs = [ python39 ];
  dontUnpack = true;
  dontBuild = true;
  installPhase = ''
    install -Dm755 $src $out/bin/addusr
  '';
}

A  => setupusr/addusr.py +57 -0
@@ 1,57 @@
#!/Usr/bin/env python3
import sys
import os
import pwd

if len(sys.argv) != 4:
    print(f"Usage: {sys.argv[0]} username real_name ssh_token")
    exit(1)
with open(f"/etc/nixos/users/{sys.argv[1]}.nix", "w") as f:
    print(f"info: creating /etc/nixos/users/{sys.argv[1]}.nix")
    contents = """
{ pkgs, ... }:
{
users.users."%s" = {
  description = "%s";
  isNormalUser = true;
  shell = pkgs.bashInteractive;
  openssh.authorizedKeys.keys = [ "%s" ];
};
}
""" % (sys.argv[1], sys.argv[2], sys.argv[3])
    f.write(contents)
os.chdir("/etc/nixos")
with open("users/default.nix", "w") as f:
    files = [os.path.abspath(os.path.join("users", file)) for file in os.listdir("users") if file != "default.nix"]
    files = [file for file in files if not file.endswith("/.nix") or not file.endswith("~")]
    print("info: creating /etc/nixos/default.nix with these users:")
    print(files)
    contents = """
{ ... }:
{
  imports = [
%s
  ];
}
""" % ('\n'.join(files))
    f.write(contents)

print("info: rebuilding NixOS")
os.system("nixos-rebuild switch")

print("info: setting up hosting under /srv/pub/{sys.argv[1]}")
pub_path = f"/srv/pub/{sys.argv[1]}"
if not os.path.exists(pub_path):
    os.mkdir(pub_path)
    
for srv in ("www", "gmi"):
    path = os.path.join(pub_path, srv)
    if not os.path.exists(path):
        os.mkdir(path)
bash_rc = os.path.join("/home", sys.argv[1], ".bash_profile")
with open(bash_rc, "a") as bashrc:
    bashrc.write("exec newusersetup")
userinfo = pwd.getpwnam(sys.argv[1])
os.chown(bash_rc, userinfo[2], userinfo[3])
os.chown(pub_path, userinfo[2], userinfo[3])
os.chmod(pub_path, 0o644)

A  => setupusr/addusr.py~ +55 -0
@@ 1,55 @@
#!/Usr/bin/env python3
import sys
import os
import pwd

if len(sys.argv) != 4:
    print(f"Usage: {sys.argv[0]} username real_name ssh_token")
    exit(1)
with open(f"/etc/nixos/users/{sys.argv[1]}.nix", "w") as f:
    print(f"info: creating /etc/nixos/users/{sys.argv[1]}.nix")
    contents = """
{ pkgs, ... }:
{
users.users."%s" = {
  description = "%s";
  isNormalUser = true;
  shell = pkgs.bashInteractive;
  openssh.authorizedKeys.keys = [ "%s" ];
};
}
""" % (sys.argv[1], sys.argv[2], sys.argv[3])
    f.write(contents)
os.chdir("/etc/nixos")
with open("users/default.nix", "w") as f:
    files = [os.path.abspath(os.path.join("users", file)) for file in os.listdir("users") if file != "default.nix"]
    files = [file for file in files if not file.endswith("/.nix")]
    print("info: creating /etc/nixos/default.nix with these users:")
    print(files)
    contents = """
{ ... }:
{
  imports = [
%s
  ];
}
""" % ('\n'.join(files))
    f.write(contents)

print("info: rebuilding NixOS")
os.system("nixos-rebuild switch")

print("info: setting up hosting under /srv/pub/{sys.argv[1]}")
pub_path = f"/srv/pub/{sys.argv[1]}"
if not os.path.exists(pub_path):
    os.mkdir(pub_path)
    
for srv in ("www", "gmi"):
    path = os.path.join(pub_path, srv)
    if not os.path.exists(path):
        os.mkdir(path)
bash_rc = os.path.join("/home", sys.argv[1], ".bashrc")
with open(bash_rc, "a") as bashrc:
    bashrc.write("exec newusersetup")
userinfo = pwd.getpwnam(sys.argv[1])
os.chown(bash_rc, userinfo[2], userinfo[3])

A  => setupusr/result +1 -0
@@ 1,1 @@
/nix/store/4npd2rkl26slw6r4c7dqcnc5imaan0in-addusr-0.0.2
\ No newline at end of file

A  => setupusr/setupusr.nix +13 -0
@@ 1,13 @@
{ pkgs ? import <nixpkgs> {}, ... }:
with pkgs;
stdenv.mkDerivation {
  pname = "setupusr";
  version = "0.0.1";
  src = ./setupusr.sh;
  buildInputs = [ (import ./addusr.nix {}) ];
  dontUnpack = true;
  dontBuild = true;
  installPhase = ''
    install -Dm755 $src $out/bin/setupusr.sh
  '';
}
\ No newline at end of file

A  => setupusr/setupusr.nix~ +13 -0
@@ 1,13 @@
{ pkgs ? import <nixpkgs> {}, ... }:
with pkgs;
stdenv.mkDerivation {
  pname = "setupusr";
  version = "0.0.1";
  src = ./setupusr.sh;
  buildInputs = (import ./addusr.nix {});
  dontUnpack = true;
  dontBuild = true;
  installPhase = ''
    install -Dm755 $src $out/bin/setupusr.sh
  '';
}
\ No newline at end of file

A  => setupusr/setupusr.sh +14 -0
@@ 1,14 @@
#!/usr/bin/env bash
set -e
if [[ "$#" -ne 3 ]]; then
    echo "Usage: $0 username real_name ssh_key"
    exit 1
fi
addusr "$1" "$2" "$3"
if [[ -z "$(cut -d: -f1 < /etc/passwd | grep $1)" ]]; then
    echo "$1: no such user"
    exit 1
fi
mkdir -p "/srv/pub/$1"/{www,gmi}
echo exec newusersetup >> /home/$1/.bashrc


A  => setupusr/setupusr.sh~ +14 -0
@@ 1,14 @@
#!/usr/bin/env bash
set -e
if [[ "$#" -ne 3 ]]; then
    echo "Usage: $0 username real_name ssh_key"
    exit 1
fi
if [[ -z "$(cut -d: -f1 < /etc/passwd | grep $1)" ]]; then
    echo "$1: no such user"
    exit 1
fi
addusr "$1" "$2" "$3"
mkdir -p "/srv/pub/$1"/{www,gmi}
echo exec newusersetup >> /home/$1/.bashrc


A  => users/arc.nix +10 -0
@@ 1,10 @@

{ pkgs, ... }:
{
users.users."arc" = {
  description = "Arcade Wise";
  isNormalUser = true;
  shell = pkgs.bashInteractive;
  openssh.authorizedKeys.keys = [ "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDNW1Db7HZy2cD2KN4R7psIRtFrQEdFIpMhZU5Xfw0hjm1rNf7l4tl7kmxSHTvwwayHda8ybQDDlkTd4z1OQUvCCARYjLIyN32PPp4wER4VUPb7FfdTFh/mhUb53k3lcojcb3BmY21Z98kQqNSkIDtQ1jsKVf0Hq10aertpdMEc3Mp/fnq+IsGpHdE0PD44ARp79dijz55Ym8FrVe/duO++HreYcV1oI2e4fyte2N5iBsM3KWrDdVLiTOGyjMSyfEA7BV4W4aDMweUwVZWw4PeHMzJGWwwLON7BuoCG5fNesp/vjnmH9hIQNFkquSSf6GaekBammr3kPzcghFM32F25U2kNdrQKG9CKIskoWKr3KTukEBurK6WFLwdPqRoj8hRpar5WbRmVhwyWvyqt8uqwLdU4FcKJCO85FgjAKVlo8g5KWEpkBCWOUcVzTdX8OYETHOyeHUCVPbNOMW8WL4f1pFaLdhAs8ru2M1W44wYvA6vP190zEknvePx3cOPFFZc= arc@nixGalaxy" ];
};
}

A  => users/default.nix +9 -0
@@ 1,9 @@

{ ... }:
{
  imports = [
/etc/nixos/users/maddie.nix
/etc/nixos/users/me.nix
/etc/nixos/users/arc.nix
  ];
}

A  => users/maddie.nix +11 -0
@@ 1,11 @@

{ pkgs, ... }:
{
users.users."maddie" = {
  description = "Madeline";
  isNormalUser = true;
  shell = pkgs.fish;
  openssh.authorizedKeys.keys = [ "sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBHPDuIYymodbRyNLyBj2lhyzkmoZDgQRmEdmAItCWa5+jMis5tw1c5wmZaFARr/RouHn12WkybbMSWlCOnRwLRcAAAAEc3NoOg== Solokey" "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGB3X4E2F2+o5VA1pdTuMDOXPF8YNGPXUOFaXXOjy9US Generated By Termius" ];
  extraGroups = [ "wheel" ];
};
}

A  => users/me.nix +10 -0
@@ 1,10 @@

{ pkgs, ... }:
{
users.users."me" = {
  description = "foo";
  isNormalUser = true;
  shell = pkgs.bashInteractive;
  openssh.authorizedKeys.keys = [ "bar" ];
};
}