#!/usr/bin/env bash

set -euo pipefail

usage() {
  cat <<'EOF'
Import a root CA from Linux OS truststore into all installed Java truststores.

Usage:
  import-linux-root-ca-into-java.sh --name "<certificate common name>" [--alias "<java alias>"] [--storepass "<password>"]
  import-linux-root-ca-into-java.sh --sha256 "<sha256 fingerprint>" [--alias "<java alias>"] [--storepass "<password>"]

Examples:
  import-linux-root-ca-into-java.sh --name "savignano Root CA G4"
  import-linux-root-ca-into-java.sh --sha256 "99:CC:3C:A2:FD:EA:9B:58:F3:9F:C3:18:39:23:B0:A2:E1:50:31:84:94:89:8B:14:13:1F:28:CF:E2:27:C2:B0" --alias sss_root_g4

Notes:
  - Requires: openssl, keytool, sudo
  - Default keystore password is "changeit"
EOF
}

CERT_NAME=""
CERT_SHA256=""
CERT_ALIAS=""
STOREPASS="${STOREPASS:-changeit}"

while [[ $# -gt 0 ]]; do
  case "$1" in
    -n|--name)
      CERT_NAME="${2:-}"
      shift 2
      ;;
    -s|--sha256)
      CERT_SHA256="${2:-}"
      shift 2
      ;;
    -a|--alias)
      CERT_ALIAS="${2:-}"
      shift 2
      ;;
    --storepass)
      STOREPASS="${2:-}"
      shift 2
      ;;
    -h|--help)
      usage
      exit 0
      ;;
    *)
      echo "Unknown argument: $1" >&2
      usage
      exit 2
      ;;
  esac
done

if [[ -z "$CERT_NAME" && -z "$CERT_SHA256" ]]; then
  echo "Provide either --name or --sha256." >&2
  usage
  exit 2
fi

for cmd in openssl keytool sudo; do
  if ! command -v "$cmd" >/dev/null 2>&1; then
    echo "Missing required command: $cmd" >&2
    exit 1
  fi
done

normalize_fp() {
  tr -d '[:space:]:.-' | tr '[:lower:]' '[:upper:]'
}

make_alias() {
  printf '%s' "$1" \
    | tr '[:upper:]' '[:lower:]' \
    | sed -E 's/[^a-z0-9._-]+/_/g; s/^_+//; s/_+$//; s/_{2,}/_/g'
}

TARGET_FP=""
if [[ -n "$CERT_SHA256" ]]; then
  TARGET_FP="$(printf '%s' "$CERT_SHA256" | normalize_fp)"
fi

WORKDIR="$(mktemp -d /tmp/linux-ca-import.XXXXXX)"
trap 'rm -rf "$WORKDIR"' EXIT

SELECTED_CERT="$WORKDIR/selected.pem"
MATCHES=0

# Common trust locations across Debian/Ubuntu/RHEL/Fedora/SUSE.
TRUST_DIRS=(
  /usr/local/share/ca-certificates
  /usr/share/ca-certificates
  /etc/ssl/certs
  /etc/pki/ca-trust/source/anchors
  /etc/pki/tls/certs
)

FOUND_CERT_FILES=()
for dir in "${TRUST_DIRS[@]}"; do
  [[ -d "$dir" ]] || continue
  while IFS= read -r f; do
    FOUND_CERT_FILES+=("$f")
  done < <(find -L "$dir" -maxdepth 3 -type f \( -name '*.crt' -o -name '*.pem' -o -name '*.cer' \) 2>/dev/null || true)
done

if [[ ${#FOUND_CERT_FILES[@]} -eq 0 ]]; then
  echo "No certificate files found in known trust directories." >&2
  exit 1
fi

for cert_file in "${FOUND_CERT_FILES[@]}"; do
  CERT_FP="$(openssl x509 -in "$cert_file" -noout -fingerprint -sha256 2>/dev/null | awk -F= '{print $2}' | normalize_fp || true)"
  [[ -n "$CERT_FP" ]] || continue

  if [[ -n "$TARGET_FP" && "$CERT_FP" != "$TARGET_FP" ]]; then
    continue
  fi

  if [[ -n "$CERT_NAME" ]]; then
    SUBJECT="$(openssl x509 -in "$cert_file" -noout -subject -nameopt RFC2253 2>/dev/null || true)"
    if ! printf '%s' "$SUBJECT" | grep -qiF "$CERT_NAME"; then
      continue
    fi
  fi

  cp "$cert_file" "$SELECTED_CERT"
  MATCHES=$((MATCHES + 1))
done

if [[ $MATCHES -eq 0 ]]; then
  echo "No matching certificate found in OS trust directories." >&2
  exit 1
fi

if [[ $MATCHES -gt 1 ]]; then
  echo "Warning: multiple matching certificates found; using the last match." >&2
fi

if [[ -z "$CERT_ALIAS" ]]; then
  if [[ -n "$CERT_NAME" ]]; then
    CERT_ALIAS="$(make_alias "$CERT_NAME")"
  else
    SUBJECT="$(openssl x509 -in "$SELECTED_CERT" -noout -subject -nameopt RFC2253)"
    CN="$(printf '%s' "$SUBJECT" | sed -E 's/.*CN=([^,]+).*/\1/')"
    CERT_ALIAS="$(make_alias "$CN")"
  fi
fi

if [[ -z "$CERT_ALIAS" ]]; then
  CERT_ALIAS="imported_root_ca"
fi

echo "Selected certificate:"
openssl x509 -in "$SELECTED_CERT" -noout -subject -issuer -fingerprint -sha256
echo "Java alias: $CERT_ALIAS"
echo

# Detect JDK/JRE homes by searching common roots for cacerts files.
JAVA_SEARCH_ROOTS=(
  /usr/lib/jvm
  /usr/java
  /opt/java
  /opt/jdk
  /usr/lib64/jvm
)

KEYSTORES=()
for root in "${JAVA_SEARCH_ROOTS[@]}"; do
  [[ -d "$root" ]] || continue
  while IFS= read -r ks; do
    KEYSTORES+=("$ks")
  done < <(find -L "$root" -type f -path '*/lib/security/cacerts' -o -type f -path '*/jre/lib/security/cacerts' 2>/dev/null || true)
done

if [[ ${#KEYSTORES[@]} -eq 0 ]]; then
  echo "No Java truststores found under common JVM directories." >&2
  exit 1
fi

# De-duplicate keystore paths.
UNIQ_KEYSTORES=()
for ks in "${KEYSTORES[@]}"; do
  seen=0
  for existing in "${UNIQ_KEYSTORES[@]}"; do
    if [[ "$existing" == "$ks" ]]; then
      seen=1
      break
    fi
  done
  if [[ $seen -eq 0 ]]; then
    UNIQ_KEYSTORES+=("$ks")
  fi
done

IMPORTED=0
for ks in "${UNIQ_KEYSTORES[@]}"; do
  echo "==> Importing into: $ks"
  sudo keytool -delete -alias "$CERT_ALIAS" -keystore "$ks" -storepass "$STOREPASS" >/dev/null 2>&1 || true
  sudo keytool -importcert -noprompt -trustcacerts -alias "$CERT_ALIAS" -file "$SELECTED_CERT" -keystore "$ks" -storepass "$STOREPASS"
  IMPORTED=$((IMPORTED + 1))
done

echo
echo "Imported into $IMPORTED Java truststore(s)."
