#!/bin/bash
#---------------------------------------------------------------------
##
## @Synopsis Functions that verify gpg signatures
##
## @Copyright Copyright 2005 by the Source Mage Team
##
#---------------------------------------------------------------------



#---------------------------------------------------------------------
## Low level routine for verifying a file given a signature and keyring.
## The keyring must contain the public key for the signature.
## @param signature of the file
## @param file to verify
## @param public keyring
##
## @return 0 on success, non-zero on failure:
##    1: verification failure
##    3: no signature file
##    4: no file to verify
##    5: no keyring
##  200: gpg isnt installed
##
## @stdout annoying message instructing user to install gnupg if its
##         not installed
#---------------------------------------------------------------------
function gpg_verify_signature() { # $1 sig $2 file $3 pubring

  local signature=$1
  local file=$2
  local keyring=$3

  test -f $signature || return 3
  test -f $file || return 4
  test -f $keyring || return 5

  # always trust and supply our own keyring.
  # We provide our own trust for the pubkey validity.

  local GPGPROG
  smgl_which gpg GPGPROG 2> /dev/null

  if test -z "$GPGPROG" ; then
    message "It appears you do not have gpg (gnupg) in your PATH."
    message "${QUERY_COLOR}For full source verification, it is highly" \
            "suggested that you cast gnupg\nas soon as possible. This" \
            "should be done for you on a system update.${DEFAULT_COLOR}"
    return 200
  else
    gpg --no-default-keyring  \
        --always-trust        \
        --keyring $keyring    \
        --batch               \
        --verify              \
        $signature            \
        $file 2> /dev/null ||
    return 1      # error out if verification fails.
  fi
  return 0
}


#---------------------------------------------------------------------
## Get the sorcery gpg key file associated with a branch
## @param (optional) sorcery branch, if empty use $SORCERY_BRANCH
## @return 0 on success, 1 on failure
## @stdout full path to sorcery key (if successful)
#---------------------------------------------------------------------
function gpg_get_sorcery_key() {
  local branch=${1:-$SORCERY_BRANCH}
  local key=$GPG_KEY_DIR/sorcery-$branch.gpg
  test -f $key || return 1
  echo $key
  return 0
}

#---------------------------------------------------------------------
## Get the grimmoire gpg key file associated with a branch
## @param grimoire branch (test, stable, games etc.)
## @return 0 on success, 1 on failure
## @stdout full path to grimoire key (if successful)
#---------------------------------------------------------------------
function gpg_get_grimoire_key() {
  local branch=$1
  local key=$GPG_KEY_DIR/grimoire-$branch.gpg
  test -f $key || return 1
  echo $key
  return 0
}

#---------------------------------------------------------------------
## Verify a grimoire tarball's gpg signature
## @param file on local disk to verify
## @param url from which to get the signature
## @param (optional) grimoire branch, if derive it from the filename with
##                   ${SOURCE%%*.}
## @param (optional) signature file, if empty download $SOURCE.$GPG_SIG_EXT
##                   from $2
## @return 0 on success, non-zero on failure:
##   1: verification failed
##   2: verification is disabled
## 254: no keyring found
## 255: could not download signature
## anything else see gpg_verify_signature
##
## @stdout possibly a failure message depending on what happens (nothing
##         is output on success)
#---------------------------------------------------------------------
function gpg_verify_grimoire() {
  if [[ "$GPG_VERIFY_GRIMOIRE" != on ]] ; then
    return 2
  fi

  local FILENAME=$1
  local SOURCE_URL=$2


  # optional args
  local BRANCH=$3
  local SIGNATURE=$4

  local SOURCE=$(basename $FILENAME)

  test -z $BRANCH && BRANCH=${SOURCE%%.*}

  local gpg_pub_key=$(gpg_get_grimoire_key $BRANCH)
  if test -z $gpg_pub_key && test -f $gpg_pub_key ; then
    message "No keyring found! (maybe you need to cast sorcery-pubkeys?)"
    return 254
  fi
  gpg_verify_common $FILENAME $SOURCE_URL $gpg_pub_key grimoire $SIGNATURE
}

#---------------------------------------------------------------------
## Verify a sorcery tarball's gpg signature
## @param file on local disk to verify
## @param url from which to get the signature
## @param (optional) signature file, if empty download $SOURCE.$GPG_SIG_EXT
## from $2
##
## @return 0 on success, non-zero on failure:
##   1: verification failed
##   2: verification is disabled
## 254: no keyring found
## 255: could not download signature
## anything else see gpg_verify_signature
##
## @stdout possibly a failure message depending on what happens (nothing
##         is output on success)
#---------------------------------------------------------------------
function gpg_verify_sorcery() {
  if [[ "$GPG_VERIFY_SORCERY" != on ]] ; then
    return 2
  fi

  local FILENAME=$1
  local SOURCE_URL=$2

  # optional args
  local SIGNATURE=$3

  local gpg_pub_key=$(gpg_get_sorcery_key)
  if test -z $gpg_pub_key && test -f $gpg_pub_key ; then
    message "No keyring found! (maybe you need to cast sorcery-pubkeys?)"
    return 254
  fi
  gpg_verify_common $FILENAME $SOURCE_URL $gpg_pub_key sorcery $SIGNATURE
}

#---------------------------------------------------------------------
## Common code for verifying sorcery/grimoire tarballs
## @param file on local disk to verify
## @param url from which to get the signature
## @param keyring to verify with
## @param grimoire or sorcery, whatever it is thats being verified (used in
##        an output message
## @param (optional) signature file, if empty download $SOURCE.$GPG_SIG_EXT
##                   from $2
##
## @return 0 on success, non-zero on failure:
##   1: verification failed
## 255: could not download signature
## anything else see gpg_verify_signature
##
## @stdout possibly a failure message depending on what happens (nothing
##         is output on success)
#---------------------------------------------------------------------
function gpg_verify_common() {
  # download the signature
  local FILENAME=$1
  local SOURCE_URL=$2
  local KEYRING=$3
  local REASON=$4
  local SIGNATURE=$5
  local SOURCE=$(basename $FILENAME)

  local SIG_FILE=${SOURCE}.${GPG_SIG_EXT}
  if test -z "$SIGNATURE" ; then
    local SIG_URL=$SOURCE_URL/$SIG_FILE
    echo "$SIG_FILE $SIG_URL" |
    download_files "for $REASON verification" "$TMP_DIR" "no" "neither" || {
      message "Failed to get gpg signature! verification is impossible"
      return 255
    }
  else
    cp $SIGNATURE $TMP_DIR/$SIG_FILE
  fi

  gpg_verify_signature $TMP_DIR/$SIG_FILE $FILENAME $gpg_pub_key
  rc=$?
  rm $TMP_DIR/$SIG_FILE

  return $rc
}

#---------------------------------------------------------------------
## Handles interpriting the output of gpg_verify_sorcery or
## gpg_verify_grimoire.
##
## @param return code of gpg_verify_sorcery or gpg_verify_grimoire
## @return 0 if the program should continue, 1 if not
##
## @stdout Some message thats supposed to inform the user of whats
##         going on, or possibly a query asking the user if they want
##         to continue even though gpg verification failed.
#---------------------------------------------------------------------
function gpg_user_query() {
  local rc=$1
  if [[ $rc == 0 ]] ; then
    message "${MESSAGE_COLOR}gpg signature verified!${DEFAULT_COLOR}"
  elif [[ $rc == 2 ]] ; then
    message "${MESSAGE_COLOR}gpg verification is disabled${DEFAULT_COLOR}"
  else
    message "${PROBLEM_COLOR}Failure to verify gpg signature${DEFAULT_COLOR}"

    if [[ "$3" == "grimoire" ]] ; then
      if [[ "$2" == devel ]] || [[ "$2" == test ]] || [[ "$2" == stable ]] ||
         [[ "$2" == z-rejected ]] || [[ "$2" == games ]] ; then
        query "Continue anyway?" n || return 1
      else
        # if its not one of our grimoires may want the default to be y
        query "Continue anyway?" y || return 1
      fi
    else
      query "Continue anyway?" n || return 1
    fi
  fi
  return 0
}

#---------------------------------------------------------------------
## This software is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.
##
## This software is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this software; if not, write to the Free Software
## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#---------------------------------------------------------------------
