#!/usr/bin/env bash

set -euo pipefail

# Global configuration
KEY_RING="gitlab-ci-runners-signing"
KEY_NAME="gitlab-runner-ssl-com"
KEY_LOCATION="us-east1"
CERT_PATH="$GITLAB_SIGNING_CERT_PATH"
P11_ENGINE="/usr/lib64/engines-1.1/pkcs11.so"
# You'll need to download this from: https://github.com/GoogleCloudPlatform/kms-integrations/releases
GOOGLE_CLOUD_PKCS11_PROVIDER="${GOOGLE_CLOUD_PKCS11_PROVIDER:-/usr/local/lib/libkmsp11.so}"

# Global temp directory for artifacts
TEMP_DIR=$(mktemp -d)
# Ensure temp directory gets cleaned up when script exits
trap 'rm -rf "$TEMP_DIR"' EXIT

# Function to set up the PKCS#11 environment
setup_signing_environment() {
  # Check for required files
  if [ ! -f "$P11_ENGINE" ]; then
      echo "$P11_ENGINE not found."
      echo "On RedHat systems: dnf install openssl-pkcs11"
      echo "On Debian/Ubuntu systems: apt install libengine-pkcs11-openssl"
    return 1
  fi

  if [ ! -f "$GOOGLE_CLOUD_PKCS11_PROVIDER" ]; then
    echo "Error: Google Cloud PKCS#11 provider not found at $GOOGLE_CLOUD_PKCS11_PROVIDER"
    echo "Please install it according to: https://cloud.google.com/kms/docs/reference/pkcs11-openssl"
    echo "Or set GOOGLE_CLOUD_PKCS11_PROVIDER environment variable to its location"
    return 1
  fi

  if [ ! -f "$CERT_PATH" ]; then
    echo "Error: Certificate file not found at $CERT_PATH"
    echo "Please set the GITLAB_SIGNING_CERT_PATH environment variable to your certificate location"
    return 1
  fi

  # Create a YAML configuration file for the Google Cloud KMS PKCS#11 provider
  local kms_p11_config_file="$TEMP_DIR/kms_pkcs11.yaml"
  cat >"$kms_p11_config_file" <<EOF
---
tokens:
  - key_ring: "projects/$GCLOUD_PROJECT/locations/$KEY_LOCATION/keyRings/$KEY_RING"
EOF
  export KMS_PKCS11_CONFIG="$kms_p11_config_file"
  echo "Signing environment setup completed."
}

# Function to sign a binary file using Google Cloud HSM
sign_binary() {
  local input_file="$1"
  local output_file="${2:-$input_file}"

  # Validate input
  if [ -z "$input_file" ]; then
    echo "Error: Input filename is required"
    echo "Usage: sign_binary input_file [output_file]"
    return 1
  fi

  if [ ! -f "$input_file" ]; then
    echo "Error: Input file '$input_file' not found"
    return 1
  fi

  echo "Signing file: $input_file"

  # Check if we're overwriting the input file
  if [ "$input_file" = "$output_file" ]; then
    echo "Signed binary will replace the input file"
    # Create temporary output file path
    local final_output="$output_file"
    output_file="$TEMP_DIR/$(basename "$input_file").signed"
  else
    echo "Output will be saved to: $output_file"
  fi

  echo "Signing binary with Google Cloud HSM via PKCS#11..."

  # Create output directory if it doesn't exist
  mkdir -p "$(dirname "$output_file")"

  local key_uri="pkcs11:object=$KEY_NAME"

  # Sign the binary using osslsigncode with PKCS#11
  osslsigncode sign \
    -h sha256 \
    -pkcs11engine "$P11_ENGINE" \
    -pkcs11module "$GOOGLE_CLOUD_PKCS11_PROVIDER" \
    -key "$key_uri" \
    -certs "$CERT_PATH" \
    -in "$input_file" \
    -out "$output_file" \
    -ts "http://ts.ssl.com"

  # If we're replacing the input file, move the temporary output file to the final destination
  # and back up the unsigned binary.
  if [ -n "${final_output:-}" ]; then
    echo "Renaming $input_file to $input_file.unsigned"
    mv "$input_file" "$input_file.unsigned"
    mv "$output_file" "$final_output"
    output_file="$final_output"
  fi

  echo "Signing completed successfully!"
  echo "Signed file: $output_file"
}

# Sign multiple binaries
sign_binaries() {
  # Setup the environment once
  setup_signing_environment || return 1

  # Sign each binary in the arguments
  local binary
  for binary in "$@"; do
    sign_binary "$binary"
  done

  echo "All binaries signed successfully!"
}

sign_binaries out/binaries/gitlab-runner-windows*.exe out/binaries/gitlab-runner-helper/gitlab-runner-helper.windows*.exe
