#!/bin/sh
# Pixeleto Tracker — the installer for your own server (a fresh Ubuntu 24.04, 4 GB RAM or more).
#
#   curl -fsSL https://get.pixeleto.io | sudo sh -s -- --key PXT-XXXXX-XXXXX-XXXXX-XXXXX-XXXXX
#
# It asks for your dashboard's domain and your admin login (or: --domain trk.example.com --email you@example.com,
# and ADMIN_PASSWORD in the environment), then installs everything — Postgres, ClickHouse, Redis, Caddy (HTTPS), the
# tracker — checks your license with Pixeleto, and keeps the tracker up to date every night.
# Your license key and account: https://cp.pixeleto.io/account
set -eu
export DEBIAN_FRONTEND=noninteractive

SERVER=${PIXELETO_SERVER:-https://cp.pixeleto.io}
KEY=${LICENSE_KEY:-}
DOMAIN=${DOMAIN:-}
ADMIN_EMAIL=${ADMIN_EMAIL:-}
ADMIN_NAME=${ADMIN_NAME:-}
ADMIN_PASSWORD=${ADMIN_PASSWORD:-}
TIMEZONE=${TIMEZONE:-America/New_York}
while [ $# -gt 0 ]; do
  case "$1" in
    --key) KEY=$2; shift 2 ;;
    --domain) DOMAIN=$2; shift 2 ;;
    --email) ADMIN_EMAIL=$2; shift 2 ;;
    --name) ADMIN_NAME=$2; shift 2 ;;
    --timezone) TIMEZONE=$2; shift 2 ;;
    --server) SERVER=$2; shift 2 ;;
    *) echo "install: unknown option $1" >&2; exit 1 ;;
  esac
done

say() { printf '\n== %s\n' "$*"; }
die() { printf '\ninstall: %s\n' "$*" >&2; exit 1; }
ask() {
  eval "cur=\${$1:-}"
  [ -n "$cur" ] && return 0
  [ -r /dev/tty ] || die "$1 is not set (no terminal to ask on)"
  printf '%s' "$2" > /dev/tty
  IFS= read -r ans < /dev/tty
  [ -n "$ans" ] || ans="${3:-}"
  eval "$1=\$ans"
}
ask_secret() {
  eval "cur=\${$1:-}"
  [ -n "$cur" ] && return 0
  [ -r /dev/tty ] || die "$1 is not set (no terminal to ask on)"
  while :; do
    printf '%s' "$2" > /dev/tty; stty -echo < /dev/tty; IFS= read -r a < /dev/tty; stty echo < /dev/tty; echo > /dev/tty
    printf 'Again: ' > /dev/tty; stty -echo < /dev/tty; IFS= read -r b < /dev/tty; stty echo < /dev/tty; echo > /dev/tty
    if [ "$a" != "$b" ]; then echo "They don't match — again." > /dev/tty; continue; fi
    if [ ${#a} -lt 10 ]; then echo "At least 10 characters — again." > /dev/tty; continue; fi
    eval "$1=\$a"
    return 0
  done
}
json() { sed -n "s/.*\"$1\": *\"\\([^\"]*\\)\".*/\\1/p" "$2" | head -n 1; }

# ---- this server ----
[ "$(id -u)" = 0 ] || die "run it as root:  curl -fsSL https://get.pixeleto.io | sudo sh -s -- --key YOUR-KEY"
. /etc/os-release
[ "${ID:-}" = ubuntu ] || die "this installer is for Ubuntu 24.04 (this server runs ${PRETTY_NAME:-something else})"
[ "${VERSION_ID:-}" = 24.04 ] || echo "install: made for Ubuntu 24.04 — this is ${VERSION_ID:-?}; carrying on" >&2
mem_mb=$(awk '/^MemTotal:/ {print int($2/1024)}' /proc/meminfo)
[ "$mem_mb" -ge 3500 ] || echo "install: this server has $mem_mb MB of memory; 4 GB or more is recommended" >&2
if [ -L /opt/tracker-current ]; then
  echo "install: the tracker is already installed here — updating it instead"
  exec sh /opt/tracker/deploy/release/update.sh
fi

APP=/opt/tracker
ask KEY "Your license key (cp.pixeleto.io › Account): "
KEY=$(printf %s "$KEY" | tr -d ' ' | tr 'a-z' 'A-Z')
ask DOMAIN "Your dashboard's domain (e.g. trk.example.com): "
DOMAIN=$(printf %s "$DOMAIN" | tr 'A-Z' 'a-z' | sed -e 's#^[a-z]*://##' -e 's#/.*$##')
printf %s "$DOMAIN" | grep -Eq '^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)+$' || die "\"$DOMAIN\" isn't a domain name"
ask ADMIN_EMAIL "Your admin login (email): "
printf %s "$ADMIN_EMAIL" | grep -Eq '^[^@ ]+@[^@ ]+\.[^@ ]+$' || die "\"$ADMIN_EMAIL\" isn't an email address"
ask ADMIN_NAME "Your name [$(printf %s "$ADMIN_EMAIL" | cut -d@ -f1)]: " "$(printf %s "$ADMIN_EMAIL" | cut -d@ -f1)"
ask_secret ADMIN_PASSWORD "Your admin password (at least 10 characters): "
[ -f "/usr/share/zoneinfo/$TIMEZONE" ] || die "unknown --timezone \"$TIMEZONE\" (e.g. America/New_York, Europe/London)"

say "checking your license"
apt-get update -q >/dev/null
apt-get -y -q install ca-certificates curl openssl dnsutils rsync >/dev/null
tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT
umask 077
printf 'Authorization: Bearer %s\n' "$KEY" > "$tmp/auth"
umask 022
code=$(curl -sS -o "$tmp/latest.json" -w '%{http_code}' -H @"$tmp/auth" "$SERVER/api/v1/releases/latest" || echo 000)
[ "$code" = 200 ] || die "$(json message "$tmp/latest.json" || true) (license check: $code)"
VERSION=$(json version "$tmp/latest.json")
SHA=$(json sha256 "$tmp/latest.json")
# this server's place on the license (the same server installing again keeps its place)
fingerprint=$(printf 'tracker:%s' "$(cat /etc/machine-id 2>/dev/null || hostname)" | sha256sum | cut -c1-40)
printf '{"key":"%s","domain":"%s","fingerprint":"%s","version":"%s"}' "$KEY" "$DOMAIN" "$fingerprint" "$VERSION" > "$tmp/activate.json"
code=$(curl -sS -o "$tmp/activated.json" -w '%{http_code}' -H 'content-type: application/json' --data-binary @"$tmp/activate.json" "$SERVER/api/v1/activate" || echo 000)
[ "$code" = 200 ] || die "$(json message "$tmp/activated.json" || true) (activation: $code)"
echo "license OK — installing $VERSION"

say "checking $DOMAIN"
my_ip=$(curl -fs4 -m 10 https://api.ipify.org || true)
dns_ip=$(dig +short A "$DOMAIN" | tail -n 1 || true)
if [ -n "$my_ip" ] && [ "$dns_ip" = "$my_ip" ]; then
  echo "$DOMAIN points at this server ($my_ip)"
else
  echo "NOTE: $DOMAIN points at ${dns_ip:-nothing yet}; this server is ${my_ip:-?}."
  echo "      Add an A record $DOMAIN → ${my_ip:-<this server's IP>}. The install carries on; HTTPS starts once it's there."
fi

say "downloading $VERSION"
curl -fsS -H @"$tmp/auth" -o "$tmp/release.tar.gz" "$SERVER/api/v1/releases/$VERSION/download" || die "the download failed — try again"
echo "$SHA  $tmp/release.tar.gz" | sha256sum -c --quiet - || die "the download doesn't match its checksum — try again"
rel=/opt/tracker-releases/$VERSION-$(date -u +%Y%m%d%H%M%S)
mkdir -p "$rel"
tar -xzf "$tmp/release.tar.gz" -C "$rel"

say "server setup (packages, firewall, swap — a few minutes)"
NO_DEPLOY_REPO=1 sh "$rel/deploy/server-setup.sh"
mkdir -p "$APP/deploy"
rsync -a --exclude /data/ "$rel/deploy/" "$APP/deploy/"

say "settings"
if [ ! -f "$APP/.env" ]; then
  umask 077
  {
    echo "# $DOMAIN — made by the Pixeleto installer on $(date -u +%F). Secrets: never share this file."
    echo "APP_HOST=$DOMAIN"
    echo "APP_URL=https://$DOMAIN"
    echo "APP_TIMEZONE=$TIMEZONE"
    echo "POSTGRES_PASSWORD=$(openssl rand -hex 24)"
    echo "CLICKHOUSE_PASSWORD=$(openssl rand -hex 24)"
    echo "BETTER_AUTH_SECRET=$(openssl rand -hex 32)"
    echo "SECRETS_KEY=$(openssl rand -base64 32)"
    echo "# your Pixeleto license (cp.pixeleto.io › Account)"
    echo "LICENSE_KEY=$KEY"
    [ "$SERVER" = https://cp.pixeleto.io ] || echo "LICENSE_SERVER_URL=$SERVER"
    echo "# Telegram alerts (optional): TELEGRAM_BOT_TOKEN= and TELEGRAM_CHAT_ID="
  } > "$APP/.env"
  umask 022
fi
chmod 600 "$APP/.env"
PG_PW=$(grep -E '^POSTGRES_PASSWORD=' "$APP/.env" | tail -n 1 | cut -d= -f2-)

say "databases"
systemctl enable --now -q postgresql@17-main
sudo -u postgres psql -q -v ON_ERROR_STOP=1 -v pw="$PG_PW" <<'SQL'
SELECT 'CREATE ROLE tracker LOGIN' WHERE NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'tracker')\gexec
ALTER ROLE tracker WITH LOGIN PASSWORD :'pw';
SELECT 'CREATE DATABASE tracker OWNER tracker' WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'tracker')\gexec
SQL

say "location data"
sh "$APP/deploy/geo-update.sh" || echo "install: location data didn't download — it's retried every month" >&2

say "starting the tracker"
sh "$rel/deploy/release/install-release.sh" "$rel"

say "your admin login"
( set -a; . /etc/tracker/app.env; set +a
  ADMIN_EMAIL="$ADMIN_EMAIL" ADMIN_NAME="$ADMIN_NAME" ADMIN_PASSWORD="$ADMIN_PASSWORD" node /opt/tracker-current/apps/worker/dist/create-admin.js )

# (the nightly backup and update, and the monthly location data, were scheduled by install-release.sh)

cat <<DONE

== done — Pixeleto Tracker $VERSION is running
Dashboard:  https://$DOMAIN   (sign in as $ADMIN_EMAIL)
            HTTPS starts once $DOMAIN's A record points at ${my_ip:-this server}.
Next:       add your traffic sources, affiliate networks, offers and campaigns in the dashboard.
            Tracking domains: Tracker › Domains, then point them at this server — HTTPS is automatic.
Updates:    every night by themselves (or now: sh $APP/deploy/release/update.sh)
Backups:    every night, the last 7 kept in /var/backups/pixeleto-tracker (restore: sh $APP/deploy/release/restore.sh)
Account:    https://cp.pixeleto.io/account — your plan, license and servers
DONE
