#!/usr/bin/env bash
#
# Copyright (c) 2024, Cloudera, Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

SCRIPT_PATH="$(
  cd "$(dirname "$0")" >/dev/null 2>&1 || exit
  pwd -P
)"

CMA_INSTANCE_NAME=${CMA_INSTANCE_NAME:-cma-server}
CMA_APP_DATA_DIR=${CMA_APP_DATA_DIR:-${HOME}/.cma}

CMA_KEYSTORE_TYPE=${CMA_KEYSTORE_TYPE:-pkcs12}
CMA_TRUSTSTORE_TYPE=${CMA_TRUSTSTORE_TYPE:-pkcs12}
CMA_KEY_ALIAS=${CMA_KEY_ALIAS:-cma}

DEFAULT_CMA_SERVICE_TYPE=${CMA_SERVICE_TYPE:-server}
CMA_SSL_CONF_FILE_NAME="cma-ssl.properties"

write_ssl_server_conf() {
  CMA_SERVER_SSL_CONF_FILE=${CMA_SERVER_SSL_CONF_FILE:-"ssl-server.properties"}

  # create dir
  local dir=$(dirname "${CMA_SERVER_SSL_CONF_FILE}")
  mkdir -p ${dir}

  cat >"${CMA_SERVER_SSL_CONF_FILE}" <<EOF
# Keystore file
cma.server.ssl.key-store=file:${CMA_KEYSTORE_FILE_PATH}

# Keystore type
cma.server.ssl.key-store-type=${CMA_KEYSTORE_TYPE}

# Keystore password
cma.server.ssl.key-store-password=${CMA_KEYSTORE_PASSWORD}

# Key alias
cma.server.ssl.key-alias=${CMA_KEY_ALIAS}

# Private key password
cma.server.ssl.key-password=${CMA_KEY_PASSWORD:-${CMA_KEYSTORE_PASSWORD}}

# Public cert
cma.server.ssl.cert.pem=${CMA_CERT_PEM_PATH}

# Private key
cma.server.ssl.key.pem=${CMA_KEY_PEM_PATH}
EOF

  echo "Saved server ssl configs into ${CMA_SERVER_SSL_CONF_FILE} ..." | tee -a "$LOG_FILE"

  # secure config file
  chmod 600 ${CMA_SERVER_SSL_CONF_FILE}

}

write_ssl_client_conf() {
  CMA_CLIENT_SSL_CONF_FILE=${CMA_CLIENT_SSL_CONF_FILE:-"ssl-client.properties"}

  # create dir
  local dir=$(dirname "${CMA_CLIENT_SSL_CONF_FILE}")
  mkdir -p ${dir}

  cat >"${CMA_CLIENT_SSL_CONF_FILE}" <<EOF
# Truststore file
cma.client.ssl.trust-store=file:${CMA_TRUSTSTORE_FILE_PATH}

# Truststore type
cma.client.ssl.trust-store-type=${CMA_TRUSTSTORE_TYPE}

# Truststore password
cma.client.ssl.trust-store-password=${CMA_TRUSTSTORE_PASSWORD}
EOF

  echo "Saved client ssl configs into ${CMA_CLIENT_SSL_CONF_FILE}" | tee -a "$LOG_FILE"

  # secure config file
  chmod 600 ${CMA_CLIENT_SSL_CONF_FILE}

}

backup_server_ssl_file() {
  mv "${CMA_SERVER_SSL_CONF_FILE}" "${CMA_SERVER_SSL_CONF_FILE_BAK}"
}

backup_client_ssl_file() {
  mv "${CMA_CLIENT_SSL_CONF_FILE}" "${CMA_CLIENT_SSL_CONF_FILE_BAK}"
}

update_active_profiles() {
  local profile_property="${1}"
  local profile="ssl"
  if [ -f "${CMA_SERVER_CONF_FILE}" ]; then
    if [ "${CMA_SERVER_SSL}" = true ]; then
      add_to_active_profiles "${profile}" "${profile_property}" | tee -a "$LOG_FILE"
    else
      remove_from_active_profiles "${profile}" "${profile_property}" | tee -a "$LOG_FILE"
    fi
  else
    # create cma-ssl.properties file with active profiles and ssl configs
    CMA_SSL_PROPERTIES_FILE="${CMA_SERVER_CONF_DIR}/${CMA_SSL_CONF_FILE_NAME}"
    if [ "${CMA_SERVER_SSL}" = true ]; then
      echo "Creating ${CMA_SSL_PROPERTIES_FILE} with active profiles and ssl configs..." | tee -a "$LOG_FILE"
      cat >"${CMA_SSL_PROPERTIES_FILE}" <<EOF
cma.profile=${profile}
cma.server.ssl.conf.file=${CMA_SERVER_SSL_CONF_FILE_PATH}
cma.client.ssl.conf.file=${CMA_CLIENT_SSL_CONF_FILE_PATH}
EOF
    else
      if [ -f "${CMA_SSL_PROPERTIES_FILE}" ]; then
        echo "Removing ${CMA_SSL_PROPERTIES_FILE}..." | tee -a "$LOG_FILE"
        rm -f "${CMA_SSL_PROPERTIES_FILE}"
      fi
    fi
  fi
}

# Creates a keystore and a truststore from the specified public cert & private key
# If the public cert is not specified, a self-signed cert and private key are also created.
generate_keystores() {

  if [ -z "${CMA_CERT_PEM}" ]; then
    mkdir -p "${CMA_SSL_DIR}"
    CMA_CERT_PEM="${DEFAULT_CERT_PEM}"
  fi

  if [ -z "${CMA_KEY_PEM}" ]; then
    mkdir -p "${CMA_SSL_DIR}"
    CMA_KEY_PEM="${DEFAULT_KEY_PEM}"
  fi

  CMA_KEYSTORE_TYPE=$(to_lower "${CMA_KEYSTORE_TYPE}")
  if [ -z "${CMA_KEYSTORE_FILE}" ]; then
    mkdir -p "${CMA_SSL_DIR}"
    CMA_KEYSTORE_FILE="${CMA_SSL_DIR}/cma_keystore"
    if [ "${CMA_KEYSTORE_TYPE}" = "jks" ]; then
      CMA_KEYSTORE_FILE+=".jks"
    elif [ "${CMA_KEYSTORE_TYPE}" = "pkcs12" ]; then
      CMA_KEYSTORE_FILE+=".p12"
    else
      echo "Unsupported keystore type '${CMA_KEYSTORE_TYPE}'"
      exit 1
    fi
  fi

  if [ -z "${CMA_SAN}" ] && [ "${DEPLOYMENT_TYPE}" = "docker" ]; then
    CMA_SAN="DNS:localhost,IP:127.0.0.1,DNS:cma-auth-server,DNS:cma-gateway-server,DNS:cma-server,DNS:*.cma.local"
  fi

  if [ -f "${CMA_KEYSTORE_FILE}" ]; then
    rm -f "${CMA_KEYSTORE_FILE}"
    echo "Deleted keystore ${CMA_KEYSTORE_FILE}"
  fi

  if [ -n "${CMA_KEY_PASSWORD}" ]; then
    if [ -n "${CMA_KEYSTORE_PASSWORD}" ]; then
      echo "Warning: Different store and key passwords not supported. The key password is used as store password!"
    fi
    CMA_KEYSTORE_PASSWORD="${CMA_KEY_PASSWORD}"

    KEYPASS_OPTS="-keypass ${CMA_KEY_PASSWORD}"
    SRC_KEYPASS_OPTS="-srckeypass ${CMA_KEY_PASSWORD}"
    OPENSSL_KEYPASS_OPTS="-passin pass:${CMA_KEY_PASSWORD}"
    CMA_SSL_KEYPASS_OPTS="--keypass ${CMA_KEY_PASSWORD}"
  fi

  if [ -z "${CMA_KEYSTORE_PASSWORD}" ]; then
    CMA_KEYSTORE_PASSWORD=cmaP4ss@123
  fi

  if [ -z "${JAVA_HOME}" ]; then
    if [ -f "${CMA_SERVER_ENV_FILE}" ]; then
      echo "Loading JAVA_HOME from ${CMA_SERVER_ENV_FILE}"
      export JAVA_HOME=$(get_cma_environment_variable_value "JAVA_HOME")
    fi
  fi
  echo "JAVA_HOME: $JAVA_HOME" | tee -a "$LOG_FILE"

  KEYTOOL_BIN="${JAVA_HOME}/bin/keytool"

  if [  ! -x "${KEYTOOL_BIN}" ]; then
     echo "[ERROR] No keytool in PATH/JAVA_HOME!"
     exit 1
  fi

  if [ "${SSL_TOOL}" != "cma-ssl" ]; then
    if [ ! -x "$(which openssl)" ]; then
       echo "[ERROR] No openssl in PATH!"
       exit 1
    fi
  fi

  local cert_exists=$([ -n "${CMA_CERT_PEM}" -a -f "${CMA_CERT_PEM}" ] && echo 'true' || echo 'false')
  local key_exists=$([ -n "${CMA_KEY_PEM}" -a -f "${CMA_KEY_PEM}" ] && echo 'true' || echo 'false')


  # generate keystore
  if [ "${cert_exists}" = "true" ]; then
    if [ "${key_exists}" != "true" ]; then
      echo "[ERROR] Missing private key!"
      exit 1
    fi

    echo "Creating keystore using certificate ${CMA_CERT_PEM} and private key ${CMA_KEY_PEM}"

    if [ "${CMA_KEYSTORE_TYPE}" = "pkcs12" ]; then
      if [ "${SSL_TOOL}" = "cma-ssl" ]; then
        ${CMA_SSL_BIN} pkcs12 create --cert "${CMA_CERT_PEM}" --key "${CMA_KEY_PEM}" --keystore "${CMA_KEYSTORE_FILE}" --name "${CMA_KEY_ALIAS}" --password "${CMA_KEYSTORE_PASSWORD}" ${CMA_SSL_KEYPASS_OPTS}
      else
        openssl pkcs12 -export -in "${CMA_CERT_PEM}" -inkey "${CMA_KEY_PEM}" -out "${CMA_KEYSTORE_FILE}" -name "${CMA_KEY_ALIAS}" -password pass:"${CMA_KEYSTORE_PASSWORD}" ${OPENSSL_KEYPASS_OPTS}
      fi

    else
      p12_keystore_file="${CMA_SSL_DIR}/cma_keystore_temp.p12"
      if [ "${SSL_TOOL}" = "cma-ssl" ]; then
        ${CMA_SSL_BIN} pkcs12 create --cert "${CMA_CERT_PEM}" --key "${CMA_KEY_PEM}" --keystore "${p12_keystore_file}" --name "${CMA_KEY_ALIAS}" --password "${CMA_KEYSTORE_PASSWORD}" ${CMA_SSL_KEYPASS_OPTS}
      else
        openssl pkcs12 -export -in "${CMA_CERT_PEM}" -inkey "${CMA_KEY_PEM}" -out "${p12_keystore_file}" -name "${CMA_KEY_ALIAS}" -password pass:"${CMA_KEYSTORE_PASSWORD}" ${OPENSSL_KEYPASS_OPTS}
      fi
      ${KEYTOOL_BIN} -importkeystore -srckeystore "${p12_keystore_file}" -srcstoretype pkcs12 -srcstorepass "${CMA_KEYSTORE_PASSWORD}" \
        -destkeystore "${CMA_KEYSTORE_PASSWORD}" -deststoretype ${CMA_KEYSTORE_TYPE} -deststorepass "${CMA_KEYSTORE_PASSWORD}"
      rm -f "${p12_keystore_file}"
    fi
  else
    local hostname=$(hostname -f)
    local ip=$(get_current_ip_addr)

    ${KEYTOOL_BIN} -genkeypair -alias "${CMA_KEY_ALIAS}" -keyalg RSA -keysize 4096 \
    -validity "${CMA_KEYSTORE_VALIDITY:-90}" \
    -storetype "${CMA_KEYSTORE_TYPE}" -keystore "${CMA_KEYSTORE_FILE}" -storepass "${CMA_KEYSTORE_PASSWORD}" \
    -dname "CN=${hostname}" -ext SAN=${CMA_SAN:-"DNS:localhost,IP:127.0.0.1,DNS:${hostname},IP:${ip}"} ${KEYPASS_OPTS}
  fi

  if [ -f "${CMA_KEYSTORE_FILE}" ]; then
    echo "Keystore (${CMA_KEYSTORE_FILE}) successfully generated!"
  else
    echo "Failed to create keystore (${CMA_KEYSTORE_FILE})!"
    exit 1
  fi

  if [ "${CMA_SKIP_TRUSTSTORE}" = "true" ]; then
    return
  fi

  CMA_TRUSTSTORE_TYPE=$(to_lower "${CMA_TRUSTSTORE_TYPE}")
  if [ -z "${CMA_TRUSTSTORE_FILE}" ]; then
    mkdir -p "${CMA_SSL_DIR}"
    CMA_TRUSTSTORE_FILE="${CMA_SSL_DIR}/cma_truststore"
    if [ "${CMA_TRUSTSTORE_TYPE}" = "jks" ]; then
      CMA_TRUSTSTORE_FILE+=".jks"
    elif [ "${CMA_TRUSTSTORE_TYPE}" = "pkcs12" ]; then
      CMA_TRUSTSTORE_FILE+=".p12"
    else
      echo "Unsupported keystore type '${CMA_TRUSTSTORE_TYPE}'"
      exit 1
    fi
  fi

  if [ -f "${CMA_TRUSTSTORE_FILE}" ]; then
    rm -f "${CMA_TRUSTSTORE_FILE}"
    echo "Deleted truststore ${CMA_TRUSTSTORE_FILE}"
  fi


  if [ -z "${CMA_TRUSTSTORE_PASSWORD}" ]; then
    CMA_TRUSTSTORE_PASSWORD=${CMA_KEYSTORE_PASSWORD}
  fi

  # generate truststore - import only the public certificate (no private key) so
  # that Java's PKIX TrustManagerFactory treats it as a TrustedCertificateEntry.
  # A truststore built with openssl pkcs12 or keytool -importkeystore produces a
  # PrivateKeyEntry which PKIX ignores, causing silent TLS failures on the client.
  local truststore_cert_pem="${CMA_CERT_PEM}"
  if [ "${cert_exists}" != "true" ]; then
    # No PEM cert available; export the public cert from the source keystore
    truststore_cert_pem="${CMA_SSL_DIR}/cma_cert_exported.pem"
    ${KEYTOOL_BIN} -exportcert -keystore "${CMA_KEYSTORE_FILE}" -storepass "${CMA_KEYSTORE_PASSWORD}" \
      -storetype "${CMA_KEYSTORE_TYPE}" -alias "${CMA_KEY_ALIAS}" -rfc -file "${truststore_cert_pem}"
  fi
  ${KEYTOOL_BIN} -importcert -alias "${CMA_KEY_ALIAS}" -file "${truststore_cert_pem}" \
    -keystore "${CMA_TRUSTSTORE_FILE}" -storepass "${CMA_TRUSTSTORE_PASSWORD}" \
    -storetype "${CMA_TRUSTSTORE_TYPE}" -noprompt

  if [ "${cert_exists}" != "true" ]; then
    rm -f "${truststore_cert_pem}"
  fi

  if [ -f "${CMA_TRUSTSTORE_FILE}" ]; then
    echo "Truststore (${CMA_TRUSTSTORE_FILE}) successfully generated!"
  else
    echo "Failed to create truststore (${CMA_TRUSTSTORE_FILE})!"
    exit 1
  fi

  if [ "${cert_exists}" != "true" ]; then

    local p12_keystore_file=${CMA_KEYSTORE_FILE}
    if [ "${CMA_KEYSTORE_TYPE}" = "jks" ]; then
      p12_keystore_file="${CMA_SSL_DIR}/cma_keystore_temp.p12"

      ${KEYTOOL_BIN} -importkeystore -srckeystore "${CMA_KEYSTORE_FILE}" -srcstorepass "${CMA_KEYSTORE_TYPE}" \
      -srcalias "${CMA_KEY_ALIAS}" -srcstorepass "${CMA_KEYSTORE_PASSWORD}" "${SRC_KEYPASS_OPTS}" \
      -destkeystore "${p12_keystore_file}" -deststoretype PKCS12 -deststorepass "${CMA_KEYSTORE_PASSWORD}"

      rm -f "${p12_keystore_file}"
    fi

    if [ "${SSL_TOOL}" = "cma-ssl" ]; then
      ${CMA_SSL_BIN} pkcs12 export-cert --keystore "${p12_keystore_file}" --password "${CMA_KEYSTORE_PASSWORD}" --name "${CMA_KEY_ALIAS}" --out "${CMA_CERT_PEM}"
    else
      openssl pkcs12 -in "${p12_keystore_file}" -out "${CMA_CERT_PEM}" -clcerts -nokeys -password pass:"${CMA_KEYSTORE_PASSWORD}"
    fi

    if [ -f "${CMA_CERT_PEM}" ]; then
      echo "Certificate successfully exported into ${CMA_CERT_PEM}!"
    else
      echo "Failed to export certificate ${CMA_CERT_PEM}!"
    fi

    if [ -f "${CMA_KEY_PEM}" ]; then
      rm -f "${CMA_KEY_PEM}"
      echo "Deleted private key ${CMA_KEY_PEM}"
    fi

    # generate private key
    if [ "${SSL_TOOL}" = "cma-ssl" ]; then
      ${CMA_SSL_BIN} pkcs12 export-key --keystore "${p12_keystore_file}" --password "${CMA_KEYSTORE_PASSWORD}" --name "${CMA_KEY_ALIAS}" --out "${CMA_KEY_PEM}"
    else
      openssl pkcs12 -in "${p12_keystore_file}" -out "${CMA_KEY_PEM}" -nodes -nocerts -password pass:"${CMA_KEYSTORE_PASSWORD}"
    fi
    echo "Private key successfully exported into "${CMA_KEY_PEM}"!"
  fi

  local openssl_major_version=$(get_openssl_version |  awk -F '.' {'print $1'})
  if [ "${openssl_major_version}" -ge 3 ]; then
    OPENSSL_OPTS=-traditional
  fi
  local cma_key_rsa_pem="${CMA_SSL_DIR}/cma_key_rsa.pem"
  if [ "${cert_exists}" != "true" -a -n "${CMA_KEY_PASSWORD}" ]; then
    echo "Encrypt the self-signed private key ${CMA_KEY_PEM}.."
    if [ "${SSL_TOOL}" = "cma-ssl" ]; then
      ${CMA_SSL_BIN} rsa --key "${CMA_KEY_PEM}" --out "${cma_key_rsa_pem}" --passout "${CMA_KEY_PASSWORD}" --traditional
    else
      openssl rsa -in "${CMA_KEY_PEM}" -out "${cma_key_rsa_pem}" -passout pass:"${CMA_KEY_PASSWORD}" -aes256 ${OPENSSL_OPTS}
    fi
    CMA_KEY_PEM="${cma_key_rsa_pem}"

  elif $(grep -q  "ENCRYPTED PRIVATE KEY" "${CMA_KEY_PEM}"); then
    echo "The private key ${CMA_KEY_PEM} is encrypted pkcs8, so it's going to be converted to encrypted pkcs1 format."
    if [ "${SSL_TOOL}" = "cma-ssl" ]; then
      ${CMA_SSL_BIN} rsa --key "${CMA_KEY_PEM}" --passin "${CMA_KEY_PASSWORD}" --out "${cma_key_rsa_pem}" --passout "${CMA_KEY_PASSWORD}" --traditional
    else
      openssl rsa -in "${CMA_KEY_PEM}" -passin pass:"${CMA_KEY_PASSWORD}" -out "${cma_key_rsa_pem}" -passout pass:"${CMA_KEY_PASSWORD}" -aes256 ${OPENSSL_OPTS}
    fi
    CMA_KEY_PEM="${cma_key_rsa_pem}"
  fi
}

# if called as source code then return
[[ $_ != $0 ]] && return 2>/dev/null

args=("${@}")

while [[ $# -gt 0 ]]; do
  case $1 in
  enable)
    CMA_SERVER_SSL=true
    shift # past argument with no value
    ;;
  disable)
    CMA_SERVER_SSL=false
    shift # past argument with no value
    ;;
  generate)
    CMA_GENERATE_SSL=true
    shift # past argument with no value
    ;;
  generate-grpc)
    CMA_GENERATE_GRPC=true
    CMA_KEY_ALIAS=cma-grpc
    CMA_SKIP_TRUSTSTORE=true
    shift # past argument with no value
    ;;
  -d | --deployment-type)
    DEPLOYMENT_TYPE=$2
    if [[ ! "${DEPLOYMENT_TYPE}" =~ ^(local|docker)$ ]]; then
      echo "Invalid deployment type: ${DEPLOYMENT_TYPE}. Valid types are: local, docker."
      HELP=true
    fi
    shift # past argument
    shift # past value
    ;;
  -ad=* | --app-data-dir=*)
    CMA_APP_DATA_DIR=${1#*=}
    shift # past argument=value
    ;;
  -ad | --app-data-dir)
    CMA_APP_DATA_DIR=$2
    shift # past argument
    shift # past value
    ;;
  -n=* | --instance-name=* | --container-name=*)
    CMA_INSTANCE_NAME=${1#*=}
    shift # past argument=value
    ;;
  -n | --instance-name | --container-name)
    CMA_INSTANCE_NAME=$2
    shift # past argument
    shift # past value
    ;;
  -s | --service-type)
    CMA_SERVICE_TYPE=$2
    if [[ ! "${CMA_SERVICE_TYPE}" =~ ^(master|server|agent)$ ]]; then
      echo "Invalid service type: ${CMA_SERVICE_TYPE}. Valid types are: master, server, agent."
      HELP=true
    fi
    shift # past argument
    shift # past value
    ;;
  -k=* | --keystore-file=*)
    CMA_KEYSTORE_FILE=${1#*=}
    shift # past argument=value
    ;;
  -k | --keystore-file)
    CMA_KEYSTORE_FILE=$2
    shift # past argument
    shift # past value
    ;;
  -st=* | --store-type=*)
    CMA_KEYSTORE_TYPE=${1#*=}
    shift # past argument=value
    ;;
  -st | --store-type)
    CMA_KEYSTORE_TYPE=$2
    shift # past argument
    shift # past value
    ;;
  -sp=* | --store-pass=*)
    CMA_KEYSTORE_PASSWORD=${1#*=}
    shift # past argument=value
    ;;
  -sp | --store-pass)
    CMA_KEYSTORE_PASSWORD=$2
    shift # past argument
    shift # past value
    ;;
  -ka=* | --key-alias=*)
    CMA_KEY_ALIAS=${1#*=}
    shift # past argument=value
    ;;
  -ka | --key-alias)
    CMA_KEY_ALIAS=$2
    shift # past argument
    shift # past value
    ;;
  -kp=* | --key-pass=*)
    CMA_KEY_PASSWORD=${1#*=}
    shift # past argument=value
    ;;
  -kp | --key-pass)
    CMA_KEY_PASSWORD=$2
    shift # past argument
    shift # past value
    ;;
  --skip-ssl-check)
    SKIP_SSL_CHECK=true
    shift # past argument with no value
    ;;
  -t=* | --truststore-file=*)
    CMA_TRUSTSTORE_FILE=${1#*=}
    shift # past argument=value
    ;;
  -t | --truststore-file)
    CMA_TRUSTSTORE_FILE=$2
    shift # past argument
    shift # past value
    ;;
  -tt=* | --truststore-type=*)
    CMA_TRUSTSTORE_TYPE=${1#*=}
    shift # past argument=value
    ;;
  -tt | --truststore-type)
    CMA_TRUSTSTORE_TYPE=$2
    shift # past argument
    shift # past value
    ;;
  -tp=* | --truststore-pass=*)
    CMA_TRUSTSTORE_PASSWORD=${1#*=}
    shift # past argument=value
    ;;
  -tp | --truststore-pass)
    CMA_TRUSTSTORE_PASSWORD=$2
    shift # past argument
    shift # past value
    ;;
  -cp=* | --cert-pem=*)
    CMA_CERT_PEM=${1#*=}
    shift # past argument=value
    ;;
  -cp | --cert-pem)
    CMA_CERT_PEM=$2
    shift # past argument
    shift # past value
    ;;
  -ck=* | --key-pem=*)
    CMA_KEY_PEM=${1#*=}
    shift # past argument=value
    ;;
  -ck | --key-pem)
    CMA_KEY_PEM=$2
    shift # past argument
    shift # past value
    ;;
  -san=* | --subject-alternative-name=*)
    CMA_SAN=${1#*=}
    shift # past argument=value
    ;;
  -san | --subject-alternative-name)
    CMA_SAN=$2
    shift # past argument
    shift # past value
    ;;
  --generate-only)
    CMA_GENERATE_ONLY=true
    shift # past argument with no value
    ;;
  -y | --assumeyes)
    CMA_YES=true
    shift # past argument with no value
    ;;
  -h | --help)
    HELP=true
    shift # past argument with no value
    ;;
  *)
    echo "Unknown option: $1"
    HELP=true
    shift # past argument with no value
    ;;
  esac
done

__usage="
Usage: ${CMA_CLI_COMMAND:-$(basename "$0")} [command] [options]
Available commands:
  enable: Enable ssl for the CMA server
  disable: Disable ssl for the CMA server
  generate: Creates the keystore and truststore with a self-signed certificate and private key if either is missing
  generate-grpc: Creates only the keystore with a self-signed certificate for gRPC TLS (no ssl-server/client.properties written)
Options:
  -ad,  --app-data-dir: Sets the folder where configs, logs and data are placed for instances (Default: ${CMA_APP_DATA_DIR}})
  -n,   --instance-name <name>: Set the name of the instance (Default: ${CMA_INSTANCE_NAME}) (**NOTE --container-name is also supported)
  -s,   --service-type <type>: Set the service type (server, master, agent) (Default: ${DEFAULT_CMA_SERVICE_TYPE})
  -d,   --deployment-type <type>: Set the deployment type (local, docker) (Default: local)
  -k,   --keystore-file <keystore>: Set the location of the keystore file
  -st,  --store-type <type>: Set keystore type (jks,pkcs12) (Default: ${CMA_KEYSTORE_TYPE})
  -sp,  --store-pass <arg>: Set keystore password
  -ka,  --key-alias <name>: alias name of the key (Default: cma)
  -kp,  --key-pass <arg>: Set private key password
  -t,   --truststore-file <truststore>: Set the location of the truststore file
  -tt,  --truststore-type <type>: Set truststore type (jks,pkcs12) (Default: ${CMA_KEYSTORE_TYPE})
  -tp,  --truststore-pass <arg>: Set truststore password
  -cp,  --cert-pem: Set the location of the public cert (cert.pem)
  -ck,  --key-pem: Set the location of the private key (key.pem)
  -san, --subject-alternative-name: Set the SAN for the self-signed cert (Default: DNS:localhost,IP:127.0.0.1,DNS:<FQDN>,IP:<IP>)
        --skip-ssl-check: Skip ssl config check. This is not recommended unless the check fails even though the ssl config is correct.
        --generate-only: generate keystores and write ssl-server/client.properties without activating the ssl profile or modifying vault config
  -y,   --assumeyes: automatically answer yes for all questions
  -h,   --help: Print this help
"

print_help() {
  echo "$__usage"
  exit 0
}

if [ "${HELP}" = true ]; then
  print_help
fi

if [ -z "${CMA_SERVER_SSL}" -a -z "${CMA_GENERATE_SSL}" -a -z "${CMA_GENERATE_GRPC}" ]; then
  echo "The command is missing!"
  print_help
fi

CMA_DIST_TYPE=${CMA_DIST_TYPE:-distributed}
export CMA_DIST_TYPE

CMA_INSTANCE_DIR=${CMA_APP_DATA_DIR}/${CMA_INSTANCE_NAME}
export CMA_CONF_DIR=${CMA_CONF_DIR:-${CMA_INSTANCE_DIR}/conf}
export CMA_LOG_DIR=${CMA_LOG_DIR:-${CMA_INSTANCE_DIR}/logs}
CMA_DATA_DIR=${CMA_DATA_DIR:-${CMA_INSTANCE_DIR}/data}

CMA_SSL_DIR=${CMA_SSL_DIR:-${CMA_INSTANCE_DIR}/ssl}

DEFAULT_CERT_PEM="${CMA_SSL_DIR}/cma_cert.pem"
DEFAULT_KEY_PEM="${CMA_SSL_DIR}/cma_key.pem"

source "$SCRIPT_PATH"/common.sh # load commons
create_logs_dir
LOG_FILE="$LOGS_DIR"/$(basename "$0" .sh).log

echo "#################################################################################################################" >>"$LOG_FILE"

if [ "${CMA_SERVER_SSL}" != false ] && [ -f "${CMA_CONF_DIR}/cma-docker.env" ] && [ "${DOCKER_MODE}" != true ]; then

  CONTAINER_ID=$(get_cma_environment_variable_value "LAST_DOCKER_CONTAINER_ID" "${CMA_CONF_DIR}/cma-docker.env")
  CONTAINER_ID=$(remove_opening_and_closing_quotes "$CONTAINER_ID")
  DEPLOYMENT_TYPE="docker"
fi

# find which cma.env file exists
# master should be first in the list, because currently it uses cma-server.properties in local mode and cma-master.properties in docker mode
for cma_env_type in master server agent; do
  if [ -f "${CMA_SERVER_CONF_DIR}/cma-${cma_env_type}.properties" ]; then
    CMA_CONF_FILE_NAME="cma-${cma_env_type}.properties"
    CMA_EXISTING_SERVICE_TYPE="${cma_env_type}"
    break
  fi
done

# if CMA_CONF_FILE_NAME exists, and CMA_SERVICE_TYPE is set to different value, then notify user
if [ -n "${CMA_SERVICE_TYPE}" ] && [ -n "${CMA_EXISTING_SERVICE_TYPE}" ]; then
  if [[ ! "${CMA_EXISTING_SERVICE_TYPE}" =~ ^${CMA_SERVICE_TYPE} ]]; then
    echo "Actual CMA service type (${CMA_CONF_FILE_NAME}) does not match the requested (${CMA_SERVICE_TYPE})!" | tee -a "$LOG_FILE"
  fi
fi

if [ -z "${CMA_EXISTING_SERVICE_TYPE}" ]; then
  if [ -n "${CMA_SERVICE_TYPE}" ]; then
    CMA_EXISTING_SERVICE_TYPE="${CMA_SERVICE_TYPE}"
  else
    CMA_EXISTING_SERVICE_TYPE="${DEFAULT_CMA_SERVICE_TYPE}"
  fi
  CMA_CONF_FILE_NAME="cma-${CMA_EXISTING_SERVICE_TYPE}.properties"
fi

CMA_SERVER_PID_DIR=${CMA_SERVER_PID_DIR:-${CMA_INSTANCE_DIR}}
CMA_SERVER_PID_FILE="${CMA_SERVER_PID_DIR}/cma-server.pid"
CMA_SERVER_LOG_FILE=${CMA_LOG_DIR}/cma-server.log

if [ "${CMA_GENERATE_SSL}" = true ]; then
  generate_keystores 2>&1 > >(tee -a "$LOG_FILE")
  if [ $? -ne 0 ]; then
    exit 1
  fi
  SKIP_GENERATE=true

  if [ "${CMA_GENERATE_ONLY}" = true ]; then
    # Only generate keystores and write ssl-server/client.properties.
    # Do not activate the ssl Spring profile or modify vault config.
    CMA_SERVER_SSL=true
    SKIP_SSL_CHECK=true
  else
    while true; do
      if [ "${CMA_YES}" != true ]; then
        read -p 'Do you want to enable ssl with the generated certificates and keystores? (yes|no) [yes]: ' yn
      fi
      yn=${yn:-"yes"}
      case $yn in
        [Yy]* ) CMA_SERVER_SSL=true; break;;
        [Nn]* ) exit;;
        * ) echo "Please answer yes or no.";;
      esac
    done
  fi
fi

if [ "${CMA_GENERATE_GRPC}" = true ]; then
  generate_keystores 2>&1 > >(tee -a "$LOG_FILE")
  if [ $? -ne 0 ]; then
    exit 1
  fi
  exit 0
fi

if [ "${CMA_SERVER_SSL}" = true ]; then

  if [ "${SKIP_GENERATE}" != true ]; then
    while [ -z "${CMA_CERT_PEM}" ]; do
      if [ "${CMA_YES}" != true ]; then
        read -p "Enter the location of the cert file (PEM format required) [${DEFAULT_CERT_PEM}]:" CMA_CERT_PEM
      fi
      CMA_CERT_PEM=${CMA_CERT_PEM:-${DEFAULT_CERT_PEM}}
    done

    while [ -z "${CMA_KEY_PEM}" ]; do
      if [ "${CMA_YES}" != true ]; then
        read -p "Enter the location of the key file (PEM format required) [${DEFAULT_KEY_PEM}]:" CMA_KEY_PEM
      fi
      CMA_KEY_PEM=${CMA_KEY_PEM:-${DEFAULT_KEY_PEM}}
    done

    generate_keystores 2>&1 > >(tee -a "$LOG_FILE")
    if [ $? -ne 0 ]; then
      exit 1
    fi
  fi

  if [ "$SKIP_SSL_CHECK" = true ]; then
    echo "SSL verification skipped!" | tee -a "$LOG_FILE"
  else
    if [ -z ${JAVA_HOME} ]; then
      locate_and_verify_cma_java_home
    fi

    # check ssl
    verify_ssl_config | tee -a "$LOG_FILE"
    if [ ${PIPESTATUS[0]} -ne 0 ]; then
      echo "Exiting..." | tee -a "$LOG_FILE"
      exit 1
    fi

    echo "Server SSL verification done!" | tee -a "$LOG_FILE"
  fi

  # define files paths
  CMA_KEYSTORE_FILE_PATH="${CMA_KEYSTORE_FILE}"
  CMA_CERT_PEM_PATH="${CMA_CERT_PEM}"
  CMA_KEY_PEM_PATH="${CMA_KEY_PEM}"
  CMA_TRUSTSTORE_FILE_PATH="${CMA_TRUSTSTORE_FILE}"
  CMA_SERVER_SSL_CONF_FILE_PATH="${CMA_SERVER_SSL_CONF_FILE}"
  CMA_CLIENT_SSL_CONF_FILE_PATH="${CMA_CLIENT_SSL_CONF_FILE}"

  if [ "${DEPLOYMENT_TYPE}" = "docker" ]; then
    if [ -n "${CONTAINER_ID}" ]; then
      container_ssl_path=$(docker inspect --format '{{range .Mounts}}{{if eq .Name "cma_app-ssl"}}{{.Destination}}{{end}}{{end}}' "${CONTAINER_ID}")
      container_conf_path=$(docker inspect --format '{{range .Mounts}}{{if eq .Name "cma_app-conf"}}{{.Destination}}{{end}}{{end}}' "${CONTAINER_ID}")
      echo "Container SSL path: ${container_ssl_path}" | tee -a "$LOG_FILE"
      echo "Container conf path: ${container_conf_path}" | tee -a "$LOG_FILE"
    fi

    if [ -z "${container_ssl_path}" ]; then
      case "${CMA_EXISTING_SERVICE_TYPE}" in
        server | master)
          container_ssl_path="/home/cma/cma-server/ssl"
          ;;
        agent)
          container_ssl_path="/home/cma/cma-agent/ssl"
          ;;
        *)
          echo "Unknown CMA deployment type: ${CMA_EXISTING_SERVICE_TYPE}!" | tee -a "$LOG_FILE"
          exit 1
          ;;
      esac
    fi

    if [ -z "${container_conf_path}" ]; then
      case "${CMA_EXISTING_SERVICE_TYPE}" in
        server | master)
          container_conf_path="/home/cma/cma-server/conf"
          ;;
        agent)
          container_conf_path="/home/cma/cma-agent/conf"
          ;;
        *)
          echo "Unknown CMA deployment type: ${CMA_EXISTING_SERVICE_TYPE}!" | tee -a "$LOG_FILE"
          exit 1
          ;;
      esac
    fi

    CMA_KEYSTORE_FILE_PATH="${container_ssl_path}/$(basename "${CMA_KEYSTORE_FILE}")"
    CMA_CERT_PEM_PATH="${container_ssl_path}/$(basename "${CMA_CERT_PEM}")"
    CMA_KEY_PEM_PATH="${container_ssl_path}/$(basename "${CMA_KEY_PEM}")"
    CMA_TRUSTSTORE_FILE_PATH="${container_ssl_path}/$(basename "${CMA_TRUSTSTORE_FILE}")"
    CMA_SERVER_SSL_CONF_FILE_PATH="${container_conf_path}/$(basename "${CMA_SERVER_SSL_CONF_FILE}")"
    CMA_CLIENT_SSL_CONF_FILE_PATH="${container_conf_path}/$(basename "${CMA_CLIENT_SSL_CONF_FILE}")"
  fi

  # create ssl server conf file
  write_ssl_server_conf

  # create ssl client conf file
  write_ssl_client_conf

  if [ "${CMA_GENERATE_ONLY}" != true ]; then
    # create cma-vault-server.properties
    if [ ! -f ${CMA_VAULT_SERVER_CONF_FILE} ]; then
      create_cma_vault_server_conf
    else
      backup_cma_vault_server_conf
    fi
    set_cma_conf_value "vault.server.scheme" "https" ${CMA_VAULT_SERVER_CONF_FILE}

    CMA_SERVER_SSL_CERT_PEM=$(get_cma_conf_value "cma.server.ssl.cert.pem" "${CMA_SERVER_SSL_CONF_FILE}")
    CMA_SERVER_SSL_KEY_PEM=$(get_cma_conf_value "cma.server.ssl.key.pem" "${CMA_SERVER_SSL_CONF_FILE}")
    CMA_SERVER_SSL_KEY_PASSWORD=$(get_cma_conf_value "cma.server.ssl.key-password" "${CMA_SERVER_SSL_CONF_FILE}")

    create_cma_vault_server_ssl_conf
  fi
else
  backup_server_ssl_file
  backup_client_ssl_file

  # update vault protocol if property file exists
  if [ -f ${CMA_VAULT_SERVER_CONF_FILE} ]; then
    set_cma_conf_value "vault.server.scheme" "http" ${CMA_VAULT_SERVER_CONF_FILE}
  fi
fi

# get profiles property name
case "${CMA_EXISTING_SERVICE_TYPE}" in
  server | master)
    CMA_PROFILES_PROPERTY="cma.server.profiles"
    ;;
  agent)
    CMA_PROFILES_PROPERTY="cma.agent.profiles"
    ;;
  *)
    echo "Unknown CMA deployment type: ${CMA_EXISTING_SERVICE_TYPE}!" | tee -a "$LOG_FILE"
    exit 1
    ;;
esac

if [ "${CMA_GENERATE_ONLY}" != true ]; then
  # refresh active profiles
  CMA_SERVER_CONF_FILE="${CMA_SERVER_CONF_DIR}/${CMA_CONF_FILE_NAME}"
  update_active_profiles "${CMA_PROFILES_PROPERTY}"

  # TODO: workaround for master which uses cma-server.properties in local mode and cma-master.properties in docker mode
  if [ "${CMA_EXISTING_SERVICE_TYPE}" = "master" ]; then
    CMA_SERVER_CONF_FILE="${CMA_SERVER_CONF_DIR}/cma-server.properties"
    if [ -f "${CMA_SERVER_CONF_FILE}" ]; then
      update_active_profiles "${CMA_PROFILES_PROPERTY}"
    fi
  fi

  if is_vault_active; then
    echo "The change will take effect after both CMA and Vault Server are restarted!" | tee -a "$LOG_FILE"
  else
    echo "The change will take effect after the CMA Server is restarted!" | tee -a "$LOG_FILE"
  fi
fi
