#!/bin/bash

##############################################################################
# Copyright (c) 2005-2016 Eclipse Foundation and others.
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Eclipse Public License v1.0
# which accompanies this distribution, and is available at
# http://www.eclipse.org/legal/epl-v10.html
#
# Contributors:
#    Denis Roy (Eclipse Foundation)
#    Matt Ward (Eclipse Foundation)
#    Mikaël Barbero (Eclipse Foundation)
##############################################################################

# sign - adds files to a queue for signing
# Files may be .zip or .jar files
# Queue is processed by genie via a cronjob

# switch to strict mode
set -o nounset
set -o errexit
set -o pipefail

shopt -s nullglob
shopt -s extglob
shopt -s expand_aliases

SCRIPT_NAME="$(basename ${0})"
SCRIPT_PATH="$(dirname "${0}")"
SCRIPT_READLINK="$(readlink -e -n "${0}")"
SCRIPT_REALNAME="$(basename "${SCRIPT_READLINK}")"
SCRIPT_REALPATH="$(dirname "${SCRIPT_READLINK}")"

CONFIG="${CONFIG:-${SCRIPT_REALPATH}/config}"
source "${CONFIG}"
source "${SCRIPT_REALPATH}/sign-lib.shs"

function print_usage() {
  local scriptname="${0}"
  printf "Usage: %s <file> <mail|nomail|now> [outputDir] [skiprepack]\n" ${scriptname}
  printf "    Signs JAR or ZIP file <file>, placing the resulting file in optional [outputDir] and mails notification that signing is complete, if requested.\n"
  printf "    Default is 'now'\n"
}

# handle mandatory argument
if [[ ${#} < 1 ]]; then
  print_usage "${SCRIPT_NAME}"
  exit 255
fi

FILE="${1:-}"; shift # for/case would interpret $1 as output dir otherwise

# handle optional arguments
if [[ ${#} > 0 ]]; then
  for i in "${@}"; do
    case "${i}" in
      mail)
        QUEUE_OPTION="${i}"
      ;;
      nomail)
        QUEUE_OPTION="${i}"
      ;;
      now)
        QUEUE_OPTION="${i}"
      ;;
      skiprepack)
        SKIPREPACK="skiprepack"
      ;;
      notsa)
        NOTSA=""
        warning "Argument 'notsa' is deprecated and not used anymore."
      ;;
      *)
        OUTPUT_DIR="${i}"
      ;;
    esac
    shift
  done
fi

# Checks that the file is valid existing file
if [[ -z "${FILE}" || ! -f "${FILE}" || ("${FILE}" != *.jar && "${FILE}" != *.zip) ]]; then
  error "File '${FILE}' not found, or not a valid file."
  error "Signing aborted."
  exit 2
else 
  FILE="$(absolute_path "${FILE}")"
fi

# checks that the file is a jar and is not already signed
if [[ "${FILE}" == *.jar ]] && jar_is_signed "${FILE}"; then
  info "${FILE} already signed, skipping."
  exit 0
elif [[ "${FILE}" == *.zip ]]; then
  cat >"${FILE}.ant.xml" <<EOL
<project name="addPackProperties" default="doIt">
  <target name="doIt">
    <taskdef name="addPackProperties"
             classname="org.eclipse.cbi.releng.tools.UpdatePackPropertiesFile">
      <classpath>
        <pathelement location="${SCRIPT_REALPATH}/ant-tasks/cbi-ant-tasks.jar"/>
      </classpath>
    </taskdef>
    <addPackProperties archiveFilename="$(absolute_path ${FILE})" verbose="true"/>
  </target>
</project>
EOL
  ${ANT_HOME}/bin/ant -Dverbose="false" -f "${FILE}.ant.xml"
  rm -f "${FILE}.ant.xml"
fi

QUEUE_OPTION="${QUEUE_OPTION:-now}"
if [[ "${QUEUE_OPTION}" != "mail"  &&  "${QUEUE_OPTION}" != "nomail"  &&  "${QUEUE_OPTION}" != "now" ]] ; then
  print_usage "${SCRIPT_NAME}"
  exit 128
fi

# if output dir is not specified, write the output in the folder as the input
OUTPUT_DIR="${OUTPUT_DIR:-$(dirname "${FILE}")}"

if ! has_effective_acl "${SIGNER_USERNAME}" "rw" "${FILE}"; then
  warning "File '${FILE}' not writable by user '${SIGNER_USERNAME}'. Changing permissions to make input file group-writable."
  chmod g+w "${FILE}"
fi;

# Get the parent folder from file to ensure it is in the staging area
if ! is_sub_folder "$(dirname "${FILE}")" "${SAFE_WD[@]}"; then
  error "File '${FILE}' is not in the downloads staging area, or the hudson directory. Not signing from unknown location."
  error "Valid folders are "${SAFE_WD[@]}""
  error "Signing aborted."
  exit 1
fi

# Checks output directory
if [[ ! -d "${OUTPUT_DIR}" ]]; then
  warning "'${OUTPUT_DIR}' is not a valid directory. Creating."
  mkdir -p "${OUTPUT_DIR}" || {
    error "Cannot create '${OUTPUT_DIR}'. May be outside the downloads staging area."
    error "Signing aborted."
    exit 4
  }
else 
  OUTPUT_DIR=$(absolute_path "${OUTPUT_DIR}")
fi

if ! is_sub_folder "${OUTPUT_DIR}" "${SAFE_WD[@]}"; then
  error "Output folder '${OUTPUT_DIR}' is not in the downloads staging area, or the hudson directory. Cannot work in an unknown location."
  error "Valid folders are "${SAFE_WD[@]}""
  error "Signing aborted."
  exit 3
fi

# outputDir must be group writable
if ! has_effective_acl "${SIGNER_USERNAME}" "rw" "${OUTPUT_DIR}"; then
  warning "Output folder '${OUTPUT_DIR}' not writable by user '${SIGNER_USERNAME}'. Changing permissions to make output dir group-writable."
  chmod g+w "${OUTPUT_DIR}"
fi

JAVA_VERSION="$(batch_signer_java_version "$(dirname ${FILE})" "${JAR_PROCESSOR_JAVA:-}")"
JAVA_VERSION="${JAVA_VERSION:-${DEFAULT_JAVA_VERSION}}"

QUEUE_LINE="$(printf "%s:%s:%s:%s:%s:%s:%s" "$(date +%s)" "${USER}" "${FILE}" "${QUEUE_OPTION}" "${OUTPUT_DIR}" "${SKIPREPACK:-}" "${JAVA_VERSION}")"
if [[ "${QUEUE_OPTION}" == "now" ]]; then
  info "Signing '${FILE}' now"
  printf "%s" "${QUEUE_LINE}" | netcat "${SIGN_SERVER_HOSTNAME}" "${SIGN_SERVER_PORT}"
else
  printf "%s\n" "${QUEUE_LINE}" >> "${QUEUE}"
  info "File '${FILE}' added to queue."
  info "You will receive notification when the file is signed, if you used the mail parameter."
  info "You can check signing status by tailing '${LOGFILE}'"
fi
exit 0
