#!/usr/bin/env bash
# Entrypoint for the vulnerable Drupal 11.3.9 lab (CVE-2026-9082).
#
# Responsibilities:
#   1. Wait for PostgreSQL to accept connections.
#   2. First boot only: install Drupal (PostgreSQL backend, standard profile),
#      enable JSON:API, grant anonymous read access, create a published article
#      so a JSON:API filter condition reaches the vulnerable translateCondition().
#   3. EVERY boot (read-class fresh-secret-on-boot): regenerate a fresh random
#      secret. Two independent secrets are provisioned:
#        a) the uid=1 (admin) password is set to a brand-new random value, so a
#           fresh password HASH lands in users_field_data.pass on each boot;
#        b) a random sentinel UUID is written into a server-only table
#           "lab_secret" that no anonymous endpoint exposes.
#      Neither secret is ever baked at build time or logged here.
#   4. Hand off to apache (CMD).
set -euo pipefail

DRUPAL_ROOT=/opt/drupal/web
SITE_DIR="$DRUPAL_ROOT/sites/default"
DRUSH="drush --root=$DRUPAL_ROOT"

PG_HOST="${DRUPAL_DB_HOST:-postgres}"
PG_PORT="${DRUPAL_DB_PORT:-5432}"
PG_DB="${DRUPAL_DB_NAME:-drupal}"
PG_USER="${DRUPAL_DB_USER:-drupal}"
PG_PASS="${DRUPAL_DB_PASSWORD:-drupal}"

export PGPASSWORD="$PG_PASS"

log() { echo "[lab-entrypoint] $*"; }

wait_for_pg() {
  log "Waiting for PostgreSQL at $PG_HOST:$PG_PORT ..."
  for _ in $(seq 1 60); do
    if pg_isready -h "$PG_HOST" -p "$PG_PORT" -U "$PG_USER" -d "$PG_DB" >/dev/null 2>&1; then
      log "PostgreSQL is ready."
      return 0
    fi
    sleep 2
  done
  log "ERROR: PostgreSQL never became ready."
  exit 1
}

psql_db() {
  psql -h "$PG_HOST" -p "$PG_PORT" -U "$PG_USER" -d "$PG_DB" -v ON_ERROR_STOP=1 "$@"
}

install_site() {
  log "Installing Drupal (standard profile, PostgreSQL backend)..."
  # site:install is non-interactive. An initial admin password is set here but is
  # immediately overwritten by the per-boot fresh-secret step below, so it is not
  # a stable/baked secret. The exact value is irrelevant and never relied upon.
  $DRUSH site:install standard \
    --db-url="pgsql://${PG_USER}:${PG_PASS}@${PG_HOST}:${PG_PORT}/${PG_DB}" \
    --site-name="CVE-2026-9082 Lab" \
    --account-name=admin \
    --account-pass="bootstrap-temp-$(head -c16 /dev/urandom | od -An -tx1 | tr -d ' \n')" \
    -y

  log "Enabling JSON:API ..."
  $DRUSH en jsonapi -y

  log "Granting anonymous + authenticated 'access content' and 'view published article'..."
  # Anonymous users must be able to read published content via JSON:API so the
  # filter path is reachable unauthenticated.
  $DRUSH role:perm:add anonymous 'access content' || true
  $DRUSH role:perm:add authenticated 'access content' || true

  log "Creating a published article node (queryable JSON:API resource)..."
  $DRUSH php:eval '
    $node = \Drupal\node\Entity\Node::create([
      "type" => "article",
      "title" => "Lab seed article",
      "status" => 1,
      "uid" => 1,
    ]);
    $node->save();
    echo "created node id " . $node->id() . "\n";
  '

  # Server-only secret table. Created once; the value is (re)written every boot.
  log "Creating server-only lab_secret table ..."
  psql_db -c 'CREATE TABLE IF NOT EXISTS lab_secret (id INT PRIMARY KEY, secret TEXT NOT NULL);'

  # Marker so we do not reinstall on subsequent boots.
  $DRUSH state:set lab.installed 1 || true
  log "Initial install complete."
}

regenerate_secrets() {
  # (a) Fresh admin (uid=1) password -> fresh hash in users_field_data.pass.
  local newpass
  newpass="$(head -c 24 /dev/urandom | od -An -tx1 | tr -d ' \n')"
  log "Regenerating fresh uid=1 password (new hash on this boot)..."
  $DRUSH user:password admin "$newpass"
  unset newpass

  # (b) Fresh sentinel UUID in the server-only lab_secret table.
  log "Writing fresh sentinel secret into lab_secret ..."
  psql_db <<'SQL'
INSERT INTO lab_secret (id, secret)
VALUES (1, 'LABSECRET-' || replace(gen_random_uuid()::text, '-', ''))
ON CONFLICT (id) DO UPDATE SET secret = EXCLUDED.secret;
SQL
  log "Fresh secrets provisioned for this boot."
}

main() {
  wait_for_pg

  # Detect prior install by probing for Drupal's bootstrap state.
  if $DRUSH status --field=bootstrap 2>/dev/null | grep -qi 'Successful'; then
    log "Existing Drupal install detected; skipping site:install."
  else
    install_site
  fi

  regenerate_secrets

  log "Starting: $*"
  exec "$@"
}

main "$@"
