#!/bin/sh # Fallar ante cualquier error set -e # Por ahora sólo soportamos x86_64 uname -m | grep -q x86_64 || exit 1 DIR="$(dirname "$(realpath "$0")")" ROOT="$(dirname "$DIR")" SELF="$(basename "$0")" SSH_ADHOC=false # Sólo se puede correr desde el directorio de Sutty if test "$ROOT" != "$(dirname "$PWD")" && test "$ROOT" != "$PWD"; then echo "¡No estás corriendo dentro de una carpeta de Sutty!" >&2 fi # Necesitamos bubblewrap if ! test "$HAIN_ENV" && ! type bwrap >/dev/null 2>&1 ; then echo "Por favor, instala el paquete bubblewrap" >&2 exit 1 fi if test -f /proc/sys/kernel/unprivileged_userns_clone && test "$(cat /proc/sys/kernel/unprivileged_userns_clone)" -ne 1 ; then echo "Necesitamos configurar tu sistema, ingresa tu contraseña para correr el comando" >&2 echo "sudo sysctl -a kernel.unprivileged_userns_clone=1" >&2 sudo sysctl -a kernel.unprivileged_userns_clone=1 fi # Si estamos corriendo el comando desde la raíz de trabajo no hay que # agregar el directorio. if test "$ROOT" = "$PWD"; then WORKDIR="/Sutty" else WORKDIR="/Sutty/${PWD##*/}/" fi # Podemos cambiar el entorno ENTORNO=${ENTORNO:-${ROOT}/hain} correr() { echo "> $1" >&2 if test "$AS_ROOT"; then SET_UID=0 SET_GID=0 else SET_UID="$(id -u)" SET_GID="$(id -g)" fi env -i \ DISPLAY="$DISPLAY" \ TERM="$TERM" \ USER="suttier" \ HOME="/home/suttier" \ HAIN_ENV=true \ RAILS_ENV="${RAILS_ENV:-development}" \ JEKYLL_ENV="${JEKYLL_ENV:-development}" \ $(test -f "$ENV_FILE" && (grep -v '^#' "$ENV_FILE" | xargs -0) || true) \ EDITOR="nano" \ PAGER="less -niSFX" \ SSH_AUTH_SOCK="${SSH_AUTH_SOCK}" \ bwrap \ --die-with-parent \ --unshare-user \ --uid "$SET_UID" \ --gid "$SET_GID" \ --unshare-ipc \ --unshare-uts \ --unshare-cgroup-try \ --bind "$ENTORNO" / \ --bind "$ROOT" /Sutty \ $(test -f ~/.Xauthority && echo "--ro-bind $HOME/.Xauthority /home/suttier/.Xauthority") \ --ro-bind /etc/hosts /etc/hosts \ --ro-bind /etc/resolv.conf /etc/resolv.conf \ --ro-bind /etc/localtime /etc/localtime \ --dev-bind /dev /dev \ --dev-bind /sys /sys \ --dev-bind /proc /proc \ --dev-bind /tmp /tmp \ --chdir "$WORKDIR" \ /bin/sh -l -c "$1" < "${stdin:-/dev/null}" } generar_certificado() { chmod 700 "$ENTORNO/etc/ssl/private" ca_key="/etc/ssl/private/ca-sutty.key" ca_crt="/usr/local/share/ca-certificates/ca-sutty.crt" domain_key="/etc/ssl/private/sutty.local.key" domain_csr="/etc/ssl/private/sutty.local.csr" domain_crt="/etc/ssl/certs/sutty.local.crt" if test -f "$ROOT/sutty.local/domain/sutty.local.crt"; then SUTTY_LOCAL="$ROOT/sutty.local" echo "Migrando certificados de sutty.local..." >&2 cp "$SUTTY_LOCAL/ca/key.key" "$ENTORNO$ca_key" cp "$SUTTY_LOCAL/ca/crt.crt" "$ENTORNO$ca_crt" cp "$SUTTY_LOCAL/domain/sutty.local.key" "$ENTORNO$domain_key" cp "$SUTTY_LOCAL/domain/sutty.local.csr" "$ENTORNO$domain_csr" cp "$SUTTY_LOCAL/domain/sutty.local.crt" "$ENTORNO$domain_crt" return fi echo "Generando certificados..." >&2 correr "openssl req -x509 -nodes -new -sha256 -days 3650 -newkey rsa:2048 \ -keyout $ca_key -out $ca_crt.pem -subj '/C=AR/CN=Sutty-Local-CA'" correr "openssl x509 -outform pem -in $ca_crt.pem -out $ca_crt" correr "update-ca-certificates" correr "openssl req -new -nodes -newkey rsa:2048 \ -keyout $domain_key -out $domain_csr \ -subj '/C=AR/ST=Ninguno/L=Interdimension/O=Sutty-Local/CN=sutty.local'" correr "openssl x509 -req -sha256 -days 3650 \ -in $domain_csr -CA $ca_crt -CAkey $ca_key \ -CAcreateserial -extfile /Sutty/haini.sh/domains.ext -out $domain_crt" rm "$ENTORNO$ca_crt.pem" echo "Instalando certificados..." >&2 if which update-ca-certificates 2>/dev/null; then sudo install -Dm 644 "$ENTORNO$ca_crt" /usr/share/ca-certificates/extra/sutty.crt sudo dpkg-reconfigure ca-certificates sudo update-ca-certificates else sudo trust anchor "$ENTORNO$ca_crt" fi } crear_entorno() { ALPINE="3.13.5" ALPINE_URL="https://dl-cdn.alpinelinux.org/alpine/v${ALPINE%.*}/releases/x86_64/alpine-minirootfs-${ALPINE}-x86_64.tar.gz" # Definir si vamos a usar wget o curl type wget >/dev/null 2>&1 && download="wget -O -" type busybox >/dev/null 2>&1 && download="busybox wget -O -" type curl >/dev/null 2>&1 && download="curl" # Si no hay ninguno de los dos, salir test -z "${download}" && exit 1 # Darle permiso de lectura a otres también umask 022 # Crear el directorio de trabajo mkdir -p "$ENTORNO" # Descargar y extraer Alpine test -f "$ENTORNO/etc/os-release" || ${download} "${ALPINE_URL}" | tar xz --directory "$ENTORNO" # Configurar los repositorios de Sutty grep -q sutty "$ENTORNO/etc/apk/repositories" || echo "https://alpine.sutty.nl/alpine/v${ALPINE%\.*}/sutty" >> "$ENTORNO/etc/apk/repositories" test -f "$ENTORNO/etc/apk/keys/alpine@sutty.nl-5ea884cd.rsa.pub" || wget https://alpine.sutty.nl/alpine/sutty.pub -O "$ENTORNO/etc/apk/keys/alpine@sutty.nl-5ea884cd.rsa.pub" # Instalar las dependencias solo si cambiaron if test "$ENTORNO/etc/apk/world" -ot "$DIR/packages"; then echo "Instalando paquetes..." >&2 packages="$(tr "\n" " " < "$DIR/packages")" correr "apk add --no-cache $packages" fi # Habilitar la instalación de gemas binarias sed -re "s/#(@platforms = )/\1/" -i "$ENTORNO/usr/lib/ruby/2.7.0/rubygems.rb" # Deshabilitar el usuario de nginx sed -re "/user nginx/d" -i "$ENTORNO/etc/nginx/nginx.conf" # Crear el directorio del PID install -dm 755 "$ENTORNO/run/nginx" # Instalar la configuración install -m 640 "$DIR/nginx.conf" "$ENTORNO/etc/nginx/http.d/default.conf" mkdir -p "$ENTORNO/home" # migrar de versiones anteriores de hainish test -d "$ENTORNO$HOME" && test ! -d "$ENTORNO/home/suttier" \ && mv "$ENTORNO$HOME" "$ENTORNO/home/suttier" mkdir -p "$ENTORNO/home/suttier" if ! grep ^suttier: "$ENTORNO/etc/group" >/dev/null 2>&1 ; then AS_ROOT=true correr "addgroup \ -g $(id -g) \ suttier" fi if ! correr "id suttier" >/dev/null 2>&1 ; then AS_ROOT=true correr "adduser \ --disabled-password \ --gecos '' \ --home /home/suttier \ --no-create-home \ --uid $(id -u) \ --ingroup suttier \ suttier" fi # Configurar rubygems para que descargue las gemas desde Sutty install -m 640 "$DIR/.gemrc" "$ENTORNO/home/suttier/.gemrc" # Resaltado de sintaxis en nano grep -q "^include " "$ENTORNO/etc/nanorc" || echo "include \"/usr/share/nano/*.nanorc\"" >> "$ENTORNO/etc/nanorc" # Instalar scripts for script in "$DIR/bin/"*; do install -m 755 "$script" "$ENTORNO/usr/local/bin/${script##*/}" done # Configurar SSH install -m 700 -d "$ENTORNO/home/suttier/.ssh" install -m 644 "$DIR/ssh/known_hosts" "$ENTORNO/home/suttier/.ssh/known_hosts" test -f "$ENTORNO/etc/ssl/certs/sutty.local.crt" || generar_certificado test -f "$ENTORNO/usr/local/share/ca-certificates/ca-sutty.crt" || mv "$ENTORNO/etc/ssl/certs/ca-sutty.crt" "$ENTORNO/usr/local/share/ca-certificates/ca-sutty.crt" } # Auto-actualizar una vez por hora actualizar() { test ! "$TERM" = "dumb" || return last_update="$(find "$DIR/.git/FETCH_HEAD" -mmin +60 | wc -l)" if test ! $last_update -ne 0; then return fi echo -n "Actualizando haini.sh... " >&2 if ping -q -c 1 0xacab.org >/dev/null 2>&1; then git -C "$DIR" pull --ff-only if test "$DIR/.git/FETCH_HEAD" -ot "$DIR/.git/ORIG_HEAD"; then echo "haini.sh se actualizó, por favor volvé a ejecutar el comando" >&2 exit 0 fi else echo "no se pudo conectar 0xacab.org, intentando la próxima vez." >&2 fi } DEFAULT="sh" case $1 in init) echo "Advertencia: haini.sh init está deprecado, usá \`export PATH=$DIR:\$PATH\`." >&2 echo "export PATH=$DIR:\$PATH" exit ;; serve) shift; DEFAULT=nginx ;; *) if ! test "$HAIN_ENV" && ! type "$SELF" >/dev/null 2>&1 ; then echo "Tip: Usá \`export PATH=$DIR:\$PATH\` para poder correr comandos de haini.sh con solo 'haini.sh'" >&2 fi ;; esac if test "$HAIN_ENV"; then ${*:-$DEFAULT} else if test -z "${SSH_AUTH_SOCK}"; then if ! type ssh-agent >/dev/null 2>&1 ; then echo "Instala ssh-agent para poder trabajar con git remoto dentro de haini.sh" >&2 else SSH_ADHOC=true echo "Iniciando un ssh-agent temporal." >&2 eval "$(ssh-agent)" ssh-add fi fi actualizar crear_entorno stdin="$(test "$TERM" = "dumb" || echo "/dev/stdin")" correr "${*:-$DEFAULT}" ; salida=$? ${SSH_ADHOC} && ssh-agent -k exit $salida fi