#!/usr/bin/env bash
# Real demos for P056 "How OAuth Login Works". Made on the Mac with Docker Desktop.
# Three containers on their own network, with names from the reserved .test domain (RFC 6761):
#   kettle   id.test, "Kettle ID": the sign-in service playing Google's part (Keycloak, one realm, one user, one app)
#   shop     shop.test, Ana's Tea Shop: a "Sign in with Kettle ID" button (lab/shop.py: OAuth 2.0 code flow + PKCE,
#            OpenID Connect ID token)
#   laptop   Ana's laptop: a real Chromium (Playwright's build) driven by lab/browser
# Defensive only (owner rule): nothing in the lab steals, captures or relays anything; the refusals shown are the
# sign-in service and the shop protecting themselves. The lab's certificate authority is made fresh on every run.
# Every command shown is typed into a real interactive bash in a pty (demo_driver.py).
set -euo pipefail
cd "$(dirname "$0")"
P=ce-p056
SECRET=lab-only-shop-secret     # the shop's client secret, registered in lab/kettle-realm.json (lab only)
cleanup() { docker rm -f $P-kettle $P-shop $P-laptop >/dev/null 2>&1 || true; docker network rm $P-net >/dev/null 2>&1 || true; }
cleanup
[ -n "${KEEP:-}" ] || trap cleanup EXIT
T=$(mktemp -d)
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:P-256 -nodes -days 2 -subj "/CN=Lab CA" \
  -keyout "$T/ca.key" -out "$T/ca.crt" 2>/dev/null
for s in id.test shop.test; do
  mkdir -p "$T/$s"
  openssl req -newkey ec -pkeyopt ec_paramgen_curve:P-256 -nodes -subj "/CN=$s" \
    -keyout "$T/$s/site.key" -out "$T/$s/site.csr" 2>/dev/null
  printf "subjectAltName=DNS:%s\n" "$s" > "$T/$s/ext"
  openssl x509 -req -in "$T/$s/site.csr" -CA "$T/ca.crt" -CAkey "$T/ca.key" -CAcreateserial -days 2 \
    -extfile "$T/$s/ext" -out "$T/$s/site.crt" 2>/dev/null
  chmod 644 "$T/$s/site.key"     # read by the service's own user inside the container
done
docker build -q -t $P-kettle -f lab/Dockerfile.kettle lab >/dev/null
docker build -q -t $P-shop -f lab/Dockerfile.shop lab >/dev/null
docker build -q -t $P-laptop -f lab/Dockerfile.laptop lab >/dev/null
docker network create $P-net >/dev/null
docker create --name $P-kettle --hostname kettle --network $P-net --network-alias id.test \
  --sysctl net.ipv4.ip_unprivileged_port_start=0 $P-kettle start-dev --import-realm \
  --https-port=443 --http-enabled=false --hostname=https://id.test \
  --https-certificate-file=/opt/keycloak/conf/tls/site.crt \
  --https-certificate-key-file=/opt/keycloak/conf/tls/site.key >/dev/null
docker create --name $P-shop --hostname shop --network $P-net --network-alias shop.test \
  -e CLIENT_SECRET=$SECRET $P-shop >/dev/null
docker cp "$T/id.test" $P-kettle:/opt/keycloak/conf/tls
docker cp "$T/shop.test" $P-shop:/srv/tls
docker cp "$T/ca.crt" $P-shop:/usr/local/share/ca-certificates/lab-ca.crt
docker start $P-kettle >/dev/null
docker run -d --name $P-laptop --hostname laptop --network $P-net --ipc=host $P-laptop sleep infinity >/dev/null
docker cp "$T/ca.crt" $P-laptop:/tmp/lab-ca.crt
rm -rf "$T"
docker exec -u ana $P-laptop sh -c 'mkdir -p ~/.pki/nssdb && certutil -d sql:$HOME/.pki/nssdb -N --empty-password \
  && certutil -d sql:$HOME/.pki/nssdb -A -t "C,," -n "Lab CA" -i /tmp/lab-ca.crt \
  && printf "green-tea-42\n" > ~/.kettle-password && chmod 600 ~/.kettle-password'
docker exec $P-laptop sh -c 'cp /tmp/lab-ca.crt /usr/local/share/ca-certificates/lab-ca.crt && update-ca-certificates >/dev/null 2>&1'
# the shop trusts the lab CA (system store), and starts once Kettle ID answers (its key list is read at start)
docker start $P-shop >/dev/null
docker exec $P-shop sh -c 'update-ca-certificates >/dev/null 2>&1'
for i in $(seq 120); do
  docker exec $P-laptop curl -sf https://id.test/realms/kettle/.well-known/openid-configuration >/dev/null 2>&1 && break
  sleep 2
done
for i in $(seq 30); do docker logs $P-shop 2>&1 | grep -q listening && break; sleep 1; done
# the shop's server shell sees the shop's secret, as its own config would give it
docker exec $P-shop sh -c "echo 'export CLIENT_SECRET=$SECRET' >> /home/ana/.bashrc"
[ -n "${SETUP_ONLY:-}" ] && { echo "lab up"; trap - EXIT; exit 0; }
python3 - "$P" < demo_driver.py
