Files
platform/scripts/provision-existing-users.sh
T
pastilhasandClaude Opus 4.6 daf5580c39 vnc sidecar: per-user desktop sessions via sidecar architecture
replaces the single hardcoded systemd VNC service with a dynamic
sidecar that manages per-user VNC sessions on demand. any authenticated
user can now access their own desktop, not just Super Admin.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 10:49:53 +00:00

206 lines
6.5 KiB
Bash
Executable File

#!/bin/bash
# One-time migration: provision Linux users for existing database members.
# Reads users from PostgreSQL, skips Super Admins (they use the service account),
# and creates Linux users + seeds shell configs for everyone else.
#
# Usage: bash scripts/provision-existing-users.sh
# Requires: sudoers entry from setup.sh, POSTGRES_URL in .env
set -euo pipefail
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m'
ok() { echo -e " ${GREEN}${NC} $1"; }
warn() { echo -e " ${YELLOW}!${NC} $1"; }
fail() { echo -e " ${RED}${NC} $1"; }
skip() { echo -e " - $1 (skipped)"; }
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
ENV_FILE="$PROJECT_DIR/.env"
TEMPLATE_DIR="$PROJECT_DIR/src/servers/api/terminal/templates"
# Load .env
if [ ! -f "$ENV_FILE" ]; then
fail ".env not found at $ENV_FILE"
exit 1
fi
source <(grep -E '^[A-Z_]+=.*' "$ENV_FILE" | sed 's/^/export /')
# Resolve DATA_PATH
DATA_PATH="${DATA_PATH:-$PROJECT_DIR/data}"
# Parse POSTGRES_URL for psql
if [ -z "${POSTGRES_URL:-}" ]; then
fail "POSTGRES_URL not set in .env"
exit 1
fi
# Extract components from postgresql://user:pass@host:port/dbname
PG_USER=$(echo "$POSTGRES_URL" | sed -n 's|.*://\([^:]*\):.*|\1|p')
PG_PASS=$(echo "$POSTGRES_URL" | sed -n 's|.*://[^:]*:\([^@]*\)@.*|\1|p')
PG_HOST=$(echo "$POSTGRES_URL" | sed -n 's|.*@\([^:]*\):.*|\1|p')
PG_PORT=$(echo "$POSTGRES_URL" | sed -n 's|.*:\([0-9]*\)/.*|\1|p')
PG_DB=$(echo "$POSTGRES_URL" | sed -n 's|.*/\([^?]*\).*|\1|p')
echo ""
echo "═══════════════════════════════════════════"
echo " Provision existing users"
echo "═══════════════════════════════════════════"
echo ""
echo "DATA_PATH: $DATA_PATH"
echo "Database: $PG_DB @ $PG_HOST:$PG_PORT"
echo ""
# Query non-Super Admin active users
USERS=$(PGPASSWORD="$PG_PASS" psql -h "$PG_HOST" -p "$PG_PORT" -U "$PG_USER" -d "$PG_DB" -t -A -F '|' \
-c "SELECT email, COALESCE(username, '') FROM users WHERE role != 'Super Admin' AND status = 'Active';" 2>&1)
if [ $? -ne 0 ]; then
fail "Failed to query database: $USERS"
exit 1
fi
if [ -z "$USERS" ]; then
echo "No non-admin active users found. Nothing to do."
exit 0
fi
echo "── Found users ──"
echo "$USERS" | while IFS='|' read -r email username; do
echo " $email (username: ${username:-<from email>})"
done
echo ""
echo "── Provisioning ──"
while IFS='|' read -r email username; do
# Derive shell username (same logic as toShellUsername in data-path.ts)
if [ -n "$username" ]; then
shell_user=$(echo "$username" | sed 's/@.*$//' | sed 's/[^a-zA-Z0-9._-]/_/g' | tr '[:upper:]' '[:lower:]' | cut -c1-32)
else
shell_user=$(echo "$email" | sed 's/@.*$//' | sed 's/[^a-zA-Z0-9._-]/_/g' | tr '[:upper:]' '[:lower:]' | cut -c1-32)
fi
USER_ROOT="$DATA_PATH/$email"
HOME_DIR="$USER_ROOT/home"
echo ""
echo " [$email$shell_user]"
# Ensure data dirs exist (sudo in case dir is owned by a previous provisioning run)
sudo mkdir -p "$USER_ROOT" "$HOME_DIR"
# Create Linux user if needed
if id "$shell_user" &>/dev/null; then
skip "Linux user $shell_user already exists"
else
if sudo useradd -d "$HOME_DIR" -s /bin/zsh -M "$shell_user"; then
ok "Created Linux user $shell_user"
else
fail "Failed to create Linux user $shell_user"
continue
fi
fi
# Seed shell configs (only if not already present)
if [ ! -f "$HOME_DIR/.zshenv" ] && [ -f "$TEMPLATE_DIR/.zshenv" ]; then
sudo cp "$TEMPLATE_DIR/.zshenv" "$HOME_DIR/.zshenv"
ok "Seeded .zshenv"
else
skip ".zshenv"
fi
if [ ! -f "$HOME_DIR/.zshrc" ] && [ -f "$TEMPLATE_DIR/.zshrc" ]; then
sudo cp "$TEMPLATE_DIR/.zshrc" "$HOME_DIR/.zshrc"
ok "Seeded .zshrc"
else
skip ".zshrc"
fi
if [ ! -f "$HOME_DIR/.tmux.conf" ] && [ -f "$TEMPLATE_DIR/.tmux.conf" ]; then
sudo cp "$TEMPLATE_DIR/.tmux.conf" "$HOME_DIR/.tmux.conf"
ok "Seeded .tmux.conf"
else
skip ".tmux.conf"
fi
sudo mkdir -p "$HOME_DIR/.config"
if [ ! -f "$HOME_DIR/.config/starship-officer.toml" ] && [ -f "$TEMPLATE_DIR/starship-officer.toml" ]; then
sudo cp "$TEMPLATE_DIR/starship-officer.toml" "$HOME_DIR/.config/starship-officer.toml"
ok "Seeded starship config"
else
skip "starship config"
fi
# Oh My Zsh
if [ ! -d "$HOME_DIR/.oh-my-zsh" ]; then
if [ -d "$HOME/.oh-my-zsh" ]; then
sudo cp -r "$HOME/.oh-my-zsh" "$HOME_DIR/.oh-my-zsh"
ok "Copied oh-my-zsh from host"
fi
else
skip "oh-my-zsh"
fi
# LazyVim
sudo mkdir -p "$HOME_DIR/.config"
if [ ! -d "$HOME_DIR/.config/nvim" ]; then
if [ -d "$HOME/.config/nvim" ]; then
sudo cp -r "$HOME/.config/nvim" "$HOME_DIR/.config/nvim"
ok "Copied nvim config from host"
fi
else
skip "nvim config"
fi
# Ensure dirs
sudo mkdir -p "$HOME_DIR/.local/bin"
sudo mkdir -p "$HOME_DIR/.pi/agent/sessions"
# VNC environment
VNC_DIR="$HOME_DIR/.vnc"
sudo mkdir -p "$VNC_DIR"
if [ ! -f "$VNC_DIR/passwd" ]; then
VNC_PASS=$(head -c 32 /dev/urandom | base64 | tr -dc 'a-zA-Z0-9' | head -c 8)
echo -n "$VNC_PASS" | sudo tee "$VNC_DIR/password" > /dev/null
echo -n "$VNC_PASS" | vncpasswd -f | sudo tee "$VNC_DIR/passwd" > /dev/null
sudo tee "$VNC_DIR/xstartup" > /dev/null << 'XSTARTUP'
#!/bin/sh
unset SESSION_MANAGER
unset DBUS_SESSION_BUS_ADDRESS
eval $(dbus-launch --sh-syntax)
export DBUS_SESSION_BUS_ADDRESS
exec startxfce4
XSTARTUP
sudo chmod +x "$VNC_DIR/xstartup"
sudo chmod 600 "$VNC_DIR/passwd"
sudo chmod 600 "$VNC_DIR/password"
ok "Provisioned VNC environment"
else
skip "VNC environment"
fi
# Set ownership and permissions last
# chmod 770 so only owner and group can access (service user is added to group above)
sudo chown -R "$shell_user:$shell_user" "$USER_ROOT"
sudo chmod -R 770 "$USER_ROOT"
# Add service user to this user's group so server jobs can access user data
SERVICE_USER="${SUDO_USER:-$(whoami)}"
if [ "$SERVICE_USER" != "$shell_user" ]; then
sudo usermod -aG "$shell_user" "$SERVICE_USER"
ok "Added $SERVICE_USER to group $shell_user"
fi
ok "Provisioning complete"
done <<< "$USERS"
echo ""
echo "═══════════════════════════════════════════"
echo " Done!"
echo "═══════════════════════════════════════════"
echo ""