#!/usr/bin/env bash

# Prowler - the handy cloud security tool (copyright 2018) by Toni de la Fuente
#
# 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.

DATE_CMD="date"
BASE64_CMD="base64"

gnu_how_older_from_today() {
  DATE_TO_COMPARE=$1
  TODAY_IN_DAYS=$("$DATE_CMD" -d "$("$DATE_CMD" +%Y-%m-%d)" +%s)
  DATE_FROM_IN_DAYS=$("$DATE_CMD" -d $DATE_TO_COMPARE +%s)
  DAYS_SINCE=$((($TODAY_IN_DAYS - $DATE_FROM_IN_DAYS )/60/60/24))
  echo $DAYS_SINCE
}
bsd_how_older_from_today() {
  DATE_TO_COMPARE=$1
  TODAY_IN_DAYS=$("$DATE_CMD" +%s)
  DATE_FROM_IN_DAYS=$("$DATE_CMD" -jf %Y-%m-%d $DATE_TO_COMPARE +%s)
  DAYS_SINCE=$((($TODAY_IN_DAYS - $DATE_FROM_IN_DAYS )/60/60/24))
  echo $DAYS_SINCE
}

# function to convert from timestamp to date
# output date format %Y-%m-%d
gnu_timestamp_to_date() {
  # if date comes from cli v2 in format like 2020-04-29T10:13:09.191000-04:00, which is ISO8601

  # remove fractions of a second
  TIMESTAMP_TO_CONVERT=$(cut -f1 -d"." <<<  "${1}")
  if ! "${DATE_CMD}" -d "${TIMESTAMP_TO_CONVERT}" +%s > /dev/null  2>&1;
  then
    # If input is epoch use the @
    OUTPUT_DATE=$("${DATE_CMD}" -d @"${TIMESTAMP_TO_CONVERT}" +'%Y-%m-%d')
  else
    # If input is not epoch dont use @
    OUTPUT_DATE=$("${DATE_CMD}" -d "${TIMESTAMP_TO_CONVERT}" +'%Y-%m-%d')
  fi
  echo "${OUTPUT_DATE}"
}
bsd_timestamp_to_date() {
  # if date comes from cli v2 in format like 2020-04-29T10:13:09.191000-04:00, which is ISO8601

  # remove fractions of a second
  TIMESTAMP_TO_CONVERT=$(cut -f1 -d"." <<<  "${1}")
  OUTPUT_DATE=$("${DATE_CMD}" -jf %Y-%m-%d "${TIMESTAMP_TO_CONVERT}" +%F 2>/dev/null)
  echo "${OUTPUT_DATE}"
}

gnu_decode_report() {
  "$BASE64_CMD" -d
}
bsd_decode_report() {
  "$BASE64_CMD" -D
}

gnu_how_many_days_from_today() {
  DATE_TO_COMPARE=$1
  TODAY_IN_DAYS=$("$DATE_CMD" -d "$("$DATE_CMD" +%Y-%m-%d)" +%s)
  DATE_IN_DAYS=$("$DATE_CMD" -d $DATE_TO_COMPARE +%s)
  DAYS_TO=$((( $DATE_IN_DAYS - $TODAY_IN_DAYS )/60/60/24))
  echo $DAYS_TO
}
bsd_how_many_days_from_today() {
  DATE_TO_COMPARE=$1
  TODAY_IN_DAYS=$("$DATE_CMD" +%s)
  DATE_IN_DAYS=$("$DATE_CMD" -jf %Y-%m-%d $DATE_TO_COMPARE +%s)
  DAYS_TO=$((( $DATE_IN_DAYS - $TODAY_IN_DAYS )/60/60/24))
  echo $DAYS_TO
}

gnu_get_date_previous_than_months() {
  MONTHS_TO_COMPARE=$1
  MONTHS_TO_COMPARE_IN_SECONDS=$(( 60 * 60 * 24 * 31 * $MONTHS_TO_COMPARE ))
  CURRENTSECS=$("$DATE_CMD" +%s)
  STARTDATEINSECS=$(( $CURRENTSECS - $MONTHS_TO_COMPARE_IN_SECONDS ))
  DATE_BEFORE_MONTHS_TO_COMPARE=$("$DATE_CMD" -d @$STARTDATEINSECS '+%Y-%m-%d')
  echo $DATE_BEFORE_MONTHS_TO_COMPARE
}
bsd_get_date_previous_than_months() {
  MONTHS_TO_COMPARE=$1
  DATE_BEFORE_MONTHS_TO_COMPARE=$("$DATE_CMD" -v -$(echo $MONTHS_TO_COMPARE)m '+%Y-%m-%d')
  echo $DATE_BEFORE_MONTHS_TO_COMPARE
}

gnu_get_time_in_milliseconds() {
  "$DATE_CMD" +%s%3N
}
bsd_get_time_in_milliseconds() {
  # BSD date does not support outputting milliseconds, so pad with zeros
  "$DATE_CMD" +%s000
}

gnu_get_iso8601_timestamp() {
  "$DATE_CMD" -u +"%Y-%m-%dT%H:%M:%SZ"
}

bsd_get_iso8601_timestamp() {
  "$DATE_CMD" -u +"%Y-%m-%dT%H:%M:%SZ"
}

gnu_convert_date_to_timestamp() {
  # if [ "$OSTYPE" == "linux-musl" ]; then
  #   date -D "%Y-%m-%dT%H:%M:%SZ" -d "$1" +%s
  # else
    "$DATE_CMD" -u -d "$1" +%s
  # fi
}

bsd_convert_date_to_timestamp() {
  "$DATE_CMD" -u -j -f %Y-%m-%dT%H:%M:%S "$1" +%s
  #date -j -f "%Y-%m-%dT%H:%M:%S" "$1" "+%s"
}

gnu_test_tcp_connectivity() {
  HOST=$1
  PORT=$2
  TIMEOUT=$3
  # This is initially for ES port 9300, not not HTTP but I add HTTP error
  # codes for better handling, so 200 is open and 000 is not responding
  timeout $TIMEOUT bash -c '(echo > /dev/tcp/'$HOST'/'$PORT') >/dev/null 2>&1 && echo "200" || echo "000"'
}
bsd_test_tcp_connectivity() {
  HOST=$1
  PORT=$2
  TIMEOUT=$3
  # This is initially for ES port 9300, not not HTTP but I add HTTP error
  # codes for better handling, so 200 is open and 000 is not responding
  nc -z -G $TIMEOUT $HOST $PORT >/dev/null 2>&1 && echo "200" || echo "000"
}

gnu_replace_sed(){
  sed -i $1 $2
}

bsd_replace_sed(){
  sed -i '' $1 $2
}

os_detector() {
  # Functions to manage dates depending on OS
  if [ "$OSTYPE" == "linux-gnu" ] || [ "$OSTYPE" == "linux-musl" ]; then
    TEMP_REPORT_FILE=$(mktemp -t -p /tmp prowler.cred_report-XXXXXX)
    # function to compare in days, usage how_older_from_today date
    # date format %Y-%m-%d
    how_older_from_today() {
      gnu_how_older_from_today "$1"
    }
    timestamp_to_date() {
      gnu_timestamp_to_date "$1"
    }
    decode_report() {
      gnu_decode_report
    }
    how_many_days_from_today() {
      gnu_how_many_days_from_today "$1"
    }
    get_date_previous_than_months() {
      gnu_get_date_previous_than_months "$1"
    }
    get_time_in_milliseconds() {
      gnu_get_time_in_milliseconds
    }
    get_iso8601_timestamp() {
      gnu_get_iso8601_timestamp
    }
    test_tcp_connectivity() {
      gnu_test_tcp_connectivity "$1" "$2" "$3"
    }
    convert_date_to_timestamp() {
      gnu_convert_date_to_timestamp "$1"
    }
    replace_sed() {
      gnu_replace_sed $1 $2
    }

  elif [[ "$OSTYPE" == "darwin"* ]] || [[ "$OSTYPE" == "freebsd"* ]]; then
    # BSD/OSX commands compatibility
    TEMP_REPORT_FILE=$(mktemp -t prowler.cred_report-XXXXXX)
    # It is possible that the user has installed GNU coreutils on OS X. By default, this will make GNU commands
    # available with a 'g' prefix, e.g. 'gdate'. Test if this is present, and use it if so, as it supports more features.
    # The user also may have replaced the default Mac OS X BSD tools with the GNU coreutils equivalents.
    # Only GNU date/base64 allows --version as a valid argument, so use the validity of this argument
    # as a means to detect that coreutils is installed and is overriding the default tools
    GDATE=$(which gdate)
    if [ -n "${GDATE}" ]; then
      DATE_CMD="gdate"
    fi
    GBASE64=$(which gbase64)
    if [ -n "${GBASE64}" ]; then
      BASE64_CMD="gbase64"
    fi
    if "$DATE_CMD" --version >/dev/null 2>&1 ; then
      how_older_from_today() {
        gnu_how_older_from_today "$1"
      }
      timestamp_to_date() {
        gnu_timestamp_to_date "$1"
      }
      how_many_days_from_today() {
        gnu_how_many_days_from_today "$1"
      }
      get_date_previous_than_months() {
        gnu_get_date_previous_than_months "$1"
      }
      get_time_in_milliseconds() {
        gnu_get_time_in_milliseconds
      }
      get_iso8601_timestamp() {
        gnu_get_iso8601_timestamp
      }
      convert_date_to_timestamp() {
        gnu_convert_date_to_timestamp "$1"
      }
    else
      how_older_from_today() {
        bsd_how_older_from_today "$1"
      }
      timestamp_to_date() {
        bsd_timestamp_to_date "$1"
      }
      how_many_days_from_today() {
        bsd_how_many_days_from_today "$1"
      }
      get_date_previous_than_months() {
        bsd_get_date_previous_than_months "$1"
      }
      get_time_in_milliseconds() {
        bsd_get_time_in_milliseconds
      }
      get_iso8601_timestamp() {
        bsd_get_iso8601_timestamp
      }
      convert_date_to_timestamp() {
        bsd_convert_date_to_timestamp "$1"
      }
    fi
    if "$BASE64_CMD" --version >/dev/null 2>&1 ; then
      decode_report() {
        gnu_decode_report
      }
    else
      decode_report() {
        bsd_decode_report
      }
    fi
    test_tcp_connectivity() {
      bsd_test_tcp_connectivity "$1" "$2" "$3"
    }
    replace_sed() {
      bsd_replace_sed $1 $2
    }
  elif [[ "$OSTYPE" == "cygwin" ]]; then
    # POSIX compatibility layer and Linux environment emulation for Windows
    TEMP_REPORT_FILE=$(mktemp -t -p /tmp prowler.cred_report-XXXXXX)
    how_older_from_today() {
      gnu_how_older_from_today "$1"
    }
    timestamp_to_date() {
      gnu_timestamp_to_date "$1"
    }
    decode_report() {
      gnu_decode_report
    }
    how_many_days_from_today() {
      gnu_how_many_days_from_today "$1"
    }
    get_date_previous_than_months() {
      gnu_get_date_previous_than_months "$1"
    }
    get_time_in_milliseconds() {
      gnu_get_time_in_milliseconds
    }
    get_iso8601_timestamp() {
      gnu_get_iso8601_timestamp
    }
    test_tcp_connectivity() {
      gnu_test_tcp_connectivity "$1" "$2" "$3"
    }
    convert_date_to_timestamp() {
      gnu_convert_date_to_timestamp "$1"
    }
    replace_sed() {
      gnu_replace_sed $1 $2
    }
  else
    echo "Unknown Operating System! Valid \$OSTYPE: linux-gnu, linux-musl, darwin* or cygwin"
    echo "Found: $OSTYPE"
    EXITCODE=1
    exit $EXITCODE
  fi
}