#!/usr/bin/bash

##############################################################################
# This file is part of the CRYPTO BONE
# File     : safewebdropsave  (server)
# Version  : 1.6 (ALL-IN-ONE)
# License  : BSD
# Date     : 12 April 2023
# Contact  : Please send enquiries and bug-reports to innovation@senderek.ie
#
# Copyright (c) 2015-2023
#	Ralf Senderek, Ireland.  All rights reserved. (https://senderek.ie)
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
# 3. All advertising materials mentioning features or use of this software
#    must display the following acknowledgement:
#	   This product includes software developed by Ralf Senderek.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND  ANY EXPRESS OR 
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE  IMPLIED WARRANTIES 
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
# POSSIBILITY OF SUCH DAMAGE.
##############################################################################

#----------------------------------------------------#
# load functions and global variables
. ./safewebdrop-functions

function new_name
{
     # $1 : directory
     # $2 : extension that is appended, if $2 exists
     # $3 : PREFIX without number extension
     NAME=""
     LAST=""
     typeset -i NUM=1
     if [[ x$1 != "x" ]]
     then
          if [[ x$2 != "x" ]]
	  then
               LAST=$(/bin/ls $1/$3*.$2 2>/dev/null | /usr/bin/sort | /usr/bin/tail -1)
	       LAST=${LAST%.$2}
	  else
               LAST=$(/bin/ls $1/$3* 2> /dev/null | /usr/bin/sort | /usr/bin/tail -1)
	  fi
          LAST=${LAST##*.}
          LAST=${LAST#0}
          LAST=${LAST#0}
          LAST=${LAST#0}
	  NUM=${LAST}
	  NUM=${NUM}+1
	  PRE="mail"
	  if [[ x$3 != "x" ]]; then
               PRE=$3
	  fi
          if [[ ${NUM} -lt 10 ]]
          then
               NAME="${PRE}.000"${NUM}
          else
               if [[ ${NUM} -lt 100 ]]
               then
                    NAME="${PRE}.00"${NUM}
               else
                    if [[ ${NUM} -lt 1000 ]]
                    then
                         NAME="${PRE}.0"${NUM}
                    else
                         NAME="${PRE}."${NUM}
                    fi
               fi
          fi
     fi
     if [[ ${NUM} -eq 0 ]]
     then
          NAME="${PRE}.0001" 
     fi
     if [[ x$2 != "x" ]]
     then
          NAME=${NAME}.$2
     fi
     /usr/bin/echo ${NAME}
}


function clean {
     /usr/bin/rm -f $SIGNED $VERIFIED
     rm -f ${DEST}/${RECIPIENT}/recoveredmessage 2>/dev/null
}

#----------------------------------------------------#

# import config file
if [[ -s /home/safewebdrop/safewebdrop.config ]] ; then
     . /home/safewebdrop/safewebdrop.config
fi

/usr/bin/echo Content-type: text/html
/usr/bin/echo

# find our HOST name
HOST=${SERVER_NAME}

RECIPIENT=""
SENDER=""
REQ=""
# extract RECIPIENT, SENDER, base64(message) and base64(signed(hash(message)))
OLDIFS="${IFS}"
IFS=\&
set -- $QUERY_STRING 
RECIPIENT=$1
SENDER=$2
REQ=$3
HASHSIG=$4
ATTACHMENT=$5

# split SENDER
IFS=\%
set -- $SENDER 
SENDERID=${1}
SENDERHOST=${2}
IFS=${OLDIFS}

# get the IP
IP=$REMOTE_ADDR

# check if the recipient exists here.
if [[ ${RECIPIENT}  ]]; then
    if [[ -d $DEST/${RECIPIENT} ]]; then
         LOG=${DEST}/${RECIPIENT}/log
         log "-------"
    else
         LOG=${DEST}/admin/log
         log "${RECIPIENT} is not registered here" 
         exit 5
    fi 
fi

if [[ ${REQ} ]] ; then
     # check if the request is in AES encrypted OpenPGP message format
     CLEAR=$(/usr/bin/echo -n "${REQ}" | /usr/bin/base64 -d )
     /usr/bin/echo -n "${CLEAR}" > ${DEST}/tmp/pgpmessage
     # check the existence of gpg on the server, should not be necessary
     if [[ -x /usr/bin/gpg ]] ; then
          CHECK=$(/usr/bin/echo | /usr/bin/gpg --homedir ${DEST}/tmp ${DEST}/tmp/pgpmessage 2>&1)
          /usr/bin/echo -n "${CHECK}" | /usr/bin/grep "encrypted data" 2>/dev/null | /usr/bin/grep "AES" 2>/dev/null >/dev/null
          if (( $? != 0 )) ; then
               /usr/bin/rm -f ${DEST}/tmp/pgpmessage 2>/dev/null
               log "the message is not AES encrypted data"
               exit 6
          fi
          /usr/bin/rm -f ${DEST}/tmp/pgpmessage 2>/dev/null
     else	  
          log "/usr/bin/gpg  does not exist, so the OpenPGP message cannot be checked."
     fi
else
     log "message is empty."
     exit 1
fi 

log "found: AES encrypted data"
log "sender is ${SENDER}"

# generate a file name
FILE=$(new_name  "${DEST}/${RECIPIENT}" "" "drop-${SENDER}")
FILE=${DEST}/${RECIPIENT}/${FILE}

# check if SENDER's public key exists
# first try local authenticated senders
PUBKEY=""

if [[ ${HASHSIG} ]] ; then
     # get the sender's PUBKEY
     if [[ ${SENDER} = *%* ]] ; then
          # full safewebrop name with %
          # check SENDERHOST against HOST
	  if [[ ${SENDERHOST} = ${HOST} ]] ; then
               # we have a local user
               if [[ ${SENDERID} ]]; then
                    if [[ -d ${DEST}/${SENDERID} ]]; then
	                 PUBKEY=${DEST}/${SENDERID}/pubkey.pem
                         if [[ ! -r ${PUBKEY} ]]; then
                              # The pubkey for SENDER is missing.
                              log "no pubkey for registered ${SENDERID} found. EXITING"
	                      exit 5
	                 fi
                    else
	                 # SENDERID is not registered  
	                 log "${SENDERID} is not registered here."
		         PUBKEY=""
                    fi
               fi
          else
               # SENDER has a cross server ID
               log "${SENDER} has a cross server ID"
          fi
     else
          # SENDER maybe a registered local user without %
          if [[ ${SENDER} ]]; then
               if [[ -d $DEST/${SENDER} ]]; then
	            PUBKEY=${DEST}/${SENDER}/pubkey.pem
	            if [[ ! -r ${PUBKEY} ]]; then
                          # The pubkey for SENDER is missing.
		          log "no pubkey for registered ${SENDER} found."
	                  exit 5
	            fi
               else
	            # SENDER is not registered  
	            log "${SENDER} is not registered here."
		    PUBKEY=""
               fi
          fi
     fi 	  
else 
    # no HASHSIG 
    exit 3
fi

log "local pubkey : $PUBKEY ${#PUBKEY}"


# check if cross server messaging is allowed and a valid PUBKEY is still not found

if [[ ${ACCEPT_CROSS_SERVER} = "yes" ]] && [[ ! ${PUBKEY} ]]; then
    log "trying ${SENDER} cross server"
    if [[ -r ${DEST}/${RECIPIENT}/contacts/${SENDER}.pubkey.pem ]]; then
         PUBKEY="$DEST/${RECIPIENT}/contacts/${SENDER}.pubkey.pem"
	 log "pubkey found here: ${PUBKEY}"
    else
	 # now check if an allowance is already stored
         if [[ -s ${DEST}/${RECIPIENT}/contacts/${SENDER}.allow ]] ; then
              /usr/bin/diff ${DEST}/${RECIPIENT}/contacts/${SENDER}.allow ${DEST}/${RECIPIENT}/contacts/${SENDER}.request 2>/dev/null >/dev/null
              if (( $? == 0 )) ; then
                   log "checking the allow file ${SENDER}.allow"
                   log "request and allow matches for ${SENDER}. PUBKEY registered!"
                   /usr/bin/mv ${DEST}/${RECIPIENT}/contacts/${SENDER}.pubkey.pending ${DEST}/${RECIPIENT}/contacts/${SENDER}.pubkey.pem
              else
                  log "request and allow DO NOT MATCH for ${SENDER}."
              fi
         else
              log "no allowance for ${SENDER} yet"
              log "pubkey for ${SENDER} not found in ${RECIPIENT}/contacts"
	 fi
    fi
fi


if [[ ${PUBKEY} ]] ; then
     # the SENDER's pubkey can be used for verification

     SIGNED=${DEST}/${RECIPIENT}/signedhash
     VERIFIED=${DEST}/${RECIPIENT}/verifiedhash
     /usr/bin/rm -f $SIGNED $VERIFIED
     
     # verify the signature
     /usr/bin/echo -n "${HASHSIG}" | base64 -d > ${SIGNED}
     /usr/bin/openssl pkeyutl  -verifyrecover -in ${SIGNED} -keyform PEM -inkey ${PUBKEY} -pubin -out ${VERIFIED}
     if [[ ! -s ${VERIFIED} ]] ; then
         log "${SENDER} : corrupt signature or RSA public key" 
	 clean
	 exit 3
     fi
     MESSAGEHASH=$(/usr/bin/cat ${VERIFIED})
     # check if the signed hash matches the message

     if [[ ${REQ} ]]; then
          # decode the message
          MESSAGE=$(/usr/bin/echo -n "${REQ}" | /usr/bin/base64 -d)
	  /usr/bin/echo -n "${MESSAGE}" > ${DEST}/${RECIPIENT}/recoveredmessage
	  # add  \n\n
	  /usr/bin/echo >> ${DEST}/${RECIPIENT}/recoveredmessage
	  /usr/bin/echo >> ${DEST}/${RECIPIENT}/recoveredmessage
	  HASH=$(/usr/bin/cat ${DEST}/${RECIPIENT}/recoveredmessage | /usr/bin/sha256sum | /usr/bin/cut -c-64) 
          if [[ "${HASH}x" = "${MESSAGEHASH}x" ]] ; then
               /usr/bin/echo -n "${MESSAGE}" > ${FILE}
	       /usr/bin/echo >> ${FILE}
               log "${FILE} saved sucessfully"
	       if [[ ${ATTACHMENT} ]] && [[ ${ATTACHMENT} != "none" ]]; then
	            NUM=${FILE##*.}
		    # return the Number of the stored message
		    /usr/bin/echo -n "${NUM}"
		    clean
                    log "--END--"
		    exit 0
	       else
                    /usr/bin/echo -n "WEBDROP MESSAGE SAVED"
	            clean
                    log "--END ! --"
	            exit 0
	       fi 
	  else
               log "signature verification failed."
	       clean
	       exit 3
	  fi
     fi
fi
clean

# no local user or valid contact has been found.



########################################################final
# finally try all other senders
if [[ ${ACCEPT_UNAUTHORIZED} = "yes" ]] ; then
     # save a message from unauthenticated users
     if [[ ${REQ} ]]; then
          /usr/bin/echo -n "${REQ}" | /usr/bin/base64 -d > ${FILE}
          log "SAVED ${FILE}"
          /usr/bin/echo -n "SAFEWEBDROP MESSAGE SAVED"
     fi
else
     LOG=${DEST}/admin/log 
     log "forbidden unauthorized message ${#REQ} bytes from ${SENDER} for ${RECIPIENT} at $(/usr/bin/date +'%X %x')"
     /usr/bin/echo "forbidden"
     exit 2
fi

log "--END--"
exit 0
