From 34aec07482bca46d5fa9069b75d075155197d21e Mon Sep 17 00:00:00 2001
From: Massimiliano Adamo <massimiliano.adamo@geant.org>
Date: Mon, 31 May 2021 18:11:32 +0200
Subject: [PATCH] testing artifacts

---
 .gitlab-ci-psnc.yml |  16 +++
 acme-downloader.sh  | 231 ++++++++++++++++++++++++++++++++++++++++++++
 build.sh            |  56 +++++++----
 go.mod              |  11 +++
 go.sum              |  25 +++++
 5 files changed, 319 insertions(+), 20 deletions(-)
 create mode 100755 acme-downloader.sh
 create mode 100644 go.mod
 create mode 100644 go.sum

diff --git a/.gitlab-ci-psnc.yml b/.gitlab-ci-psnc.yml
index 548677e..25b4acd 100644
--- a/.gitlab-ci-psnc.yml
+++ b/.gitlab-ci-psnc.yml
@@ -1,6 +1,7 @@
 ---
 stages:
   - sonarqube
+  - upload_linux_artifact
 sonarqube:
   image: sonarsource/sonar-scanner-cli:${SONAR_SCANNER_CLI_VERSION}
   stage: sonarqube
@@ -10,3 +11,18 @@ sonarqube:
     - /usr/bin/entrypoint.sh sonar-scanner -Dsonar.projectKey="$CI_PROJECT_NAME"
   tags:
     - sonarqube
+upload_linux_artifact:
+  script: ./build.sh --os=linux --arch=amd64 --upx
+  artifacts:
+    paths:
+      - /home/maxadamo/go/bin/acme-downloader
+upload_windows_artifact:
+  script: ./build.sh --os=windows --arch=amd64 --upx
+  artifacts:
+    paths:
+      - /home/maxadamo/go/bin/windows_amd64/acme-downloader.exe
+upload_shell_script:
+  artifacts:
+    paths:
+      - acme-downloader.sh
+
diff --git a/acme-downloader.sh b/acme-downloader.sh
new file mode 100755
index 0000000..6d1e4d2
--- /dev/null
+++ b/acme-downloader.sh
@@ -0,0 +1,231 @@
+#!/bin/bash
+#
+# exit 0: the certificate still looks good and it won't be replaced
+# exit 1: a new certificate was installed and we need to reload our service
+# exit 2: uh, oh something went wrong
+#
+# the certificate will be checked, if it is valid, if the key matches
+# and if it contains at least the cert-name
+#
+LOCAL_MD5=$(md5sum $0 | awk '{print $1}')
+REMOTE_MD5=$(curl -s https://repositories.geant.org/pub/acme/acme-downloader.sh | md5sum | awk '{print $1}')
+if [[ $LOCAL_MD5 != $REMOTE_MD5 ]]; then
+    echo "$0 differs from https://repositories.geant.org/pub/acme/acme-downloader.sh"
+    echo "suggesting that you are running an older version"
+    echo ""
+fi
+
+REDIS_URL="https://redis.geant.org/GET"
+VAULT_URL="https://vault.geant.org/v1"
+TMP_CERT=$(mktemp)
+TMP_FULLCHAIN=$(mktemp)
+TMP_CA=$(mktemp)
+TMP_KEY=$(mktemp)
+
+stty -echoctl # hide ^C
+
+# function called by trap
+clean_up() {
+    rm -f $TMP_CERT $TMP_FULLCHAIN $TMP_CA $TMP_KEY
+    exit 2
+}
+trap 'clean_up' SIGINT
+
+if [ $(id -u) -ne 0 ]; then
+    echo -e "plase run this script as root\ngiving up..."
+    clean_up
+elif ! which curl jq &>/dev/null; then
+    echo -e "please install curl and jq\ngiving up..."
+    clean_up
+fi
+
+# lsb_release is not always installed
+if ! source /etc/os-release &>/dev/null; then
+    echo "no idea what to do with this OS: I was not able to access /etc/os-release"
+    echo ""
+    clean_up
+elif [[ "$ID" == "ubuntu" ]] || [[ "$ID" == "debian" ]]; then
+    CERT_BASE="/etc/ssl/certs"
+    KEY_BASE="/etc/ssl/private"
+    GROUPNAME="ssl-cert"
+elif [[ "$ID" == "centos" ]] || [[ "$ID" == "rhel" ]]; then
+    CERT_BASE="/etc/pki/tls/certs"
+    KEY_BASE="/etc/pki/tls/private"
+    GROUPNAME="root"
+else
+    echo "no idea what to do with OS: $ID"
+    echo "please amend the script accordingly"
+    echo ""
+    clean_up
+fi
+
+usage() {
+    echo "Usage: $(basename $0)"
+    echo "    -h | --help [Print this help and exit]"
+    echo "    --redis-token (Redis access token)"
+    echo "    --vault-token (Vault access token)"
+    echo "    --cert-name (Certificate name)"
+    echo "    --team-name (Team name: swd, dream_team, it, ne, ti...)"
+    echo "    --days [OPTIONAL check days before expiration. Default: 30)"
+    echo "    --type [OPTIONAL. OV or EV. Default: EV]"
+    echo "    --cert-destination [OPTIONAL Default: ${CERT_BASE}/<cert-name>.crt]"
+    echo "    --fullchain-destination [OPTIONAL Default: ${CERT_BASE}/<cert-name>_fullchain.crt]"
+    echo "    --key-destination [OPTIONAL Default: ${KEY_BASE}/<cert-name>.key]"
+    echo "    --ca-destination [OPTIONAL Default: ${CERT_BASE}/COMODO_<type>.crt]"
+    echo "    --wildcard [OPTIONAL if the certificate is wildcard]"
+    echo ""
+    clean_up
+}
+
+OPTS=$(getopt -o "h" --longoptions "help,redis-token:,vault-token:,cert-name:,team-name:,days:,type:,cert-destination:,fullchain-destination:,key-destination:,ca-destination:,wildcard" -- "$@")
+eval set -- "$OPTS"
+
+while true; do
+    case "$1" in
+    -h | --help)
+        usage
+        clean_up
+        ;;
+    --redis-token)
+        shift
+        REDIS_TOKEN="${1}"
+        ;;
+    --vault-token)
+        shift
+        VAULT_TOKEN="${1}"
+        ;;
+    --cert-name)
+        shift
+        CERT_NAME="${1}"
+        ;;
+    --team-name)
+        shift
+        TEAM_NAME="${1}"
+        ;;
+    --days)
+        shift
+        DAYS="${1}"
+        ;;
+    --type)
+        shift
+        TYPE="${1}"
+        ;;
+    --cert-destination)
+        shift
+        CERT_DESTINATION="${1}"
+        ;;
+    --fullchain-destination)
+        shift
+        FULLCHAIN_DESTINATION="${1}"
+        ;;
+    --key-destination)
+        shift
+        KEY_DESTINATION="${1}"
+        ;;
+    --ca-destination)
+        shift
+        CA_DESTINATION="${1}"
+        ;;
+    --wildcard)
+        WILDCARD='WILDCARD'
+        ;;
+    --)
+        shift
+        break
+        ;;
+    esac
+    shift
+done
+
+TYPE=$(echo $TYPE | tr '[:lower:]' '[:upper:]')
+
+if [[ -z $REDIS_TOKEN ]] || [[ -z $VAULT_TOKEN ]] || [[ -z $CERT_NAME ]] || [[ -z $TEAM_NAME ]]; then
+    echo -e "\n--redis-token, --vault-token, --cert-name and --team-name are mandatory\n"
+    usage
+fi
+
+[[ -z $TYPE ]] && TYPE="EV" # let's default to EV type
+if [[ $TYPE != "EV" ]] && [[ $TYPE != "OV" ]]; then
+    echo "type must be either EV, ev, OV, ov"
+    usage
+fi
+[[ -z $DAYS ]] && DAYS=30
+[[ -z $CERT_DESTINATION ]] && CERT_DESTINATION="${CERT_BASE}/${CERT_NAME}.crt"
+[[ -z $FULLCHAIN_DESTINATION ]] && FULLCHAIN_DESTINATION="${CERT_BASE}/${CERT_NAME}_fullchain.crt"
+[[ -z $KEY_DESTINATION ]] && KEY_DESTINATION="${KEY_BASE}/${CERT_NAME}.key"
+[[ -z $CA_DESTINATION ]] && CA_DESTINATION="${CERT_BASE}/COMODO_${TYPE}.crt"
+
+UNDERSCORED_CERT_NAME=$(echo $CERT_NAME | sed -e 's,\.,_,g')
+MINUTES=$((${DAYS} * 86400))
+
+# give up if the certificate expiration is still within a proper range
+if openssl x509 -checkend $MINUTES -noout -in $FULLCHAIN_DESTINATION &>/dev/null; then
+    rm -f $TMP_CERT $TMP_FULLCHAIN $TMP_CA $TMP_KEY
+    exit 0
+fi
+
+# download certificates and delete the last empty line if it exists and remove the first line from Webdis
+if [[ -z $WILDCARD ]]; then
+    curl -s -u redis:$REDIS_TOKEN ${REDIS_URL}/${TEAM_NAME}:${CERT_NAME}:redis_${UNDERSCORED_CERT_NAME}_pem.txt >$TMP_CERT
+    curl -s -u redis:$REDIS_TOKEN ${REDIS_URL}/${TEAM_NAME}:${CERT_NAME}:redis_${UNDERSCORED_CERT_NAME}_fullchain_pem.txt >$TMP_FULLCHAIN
+    curl -s -u redis:$REDIS_TOKEN ${REDIS_URL}/${TEAM_NAME}:${CERT_NAME}:redis_${UNDERSCORED_CERT_NAME}_chain_pem.txt >$TMP_CA
+    curl -s -H "X-Vault-Token: ${VAULT_TOKEN}" ${VAULT_URL}/${TEAM_NAME}/${CERT_NAME}/vault_${UNDERSCORED_CERT_NAME}_key | jq -j .data.value >$TMP_KEY
+else
+    curl -s -u redis:$REDIS_TOKEN ${REDIS_URL}/${TEAM_NAME}:common:redis_sectigo_ov_${UNDERSCORED_CERT_NAME}_pem.txt >$TMP_CERT
+    curl -s -u redis:$REDIS_TOKEN ${REDIS_URL}/${TEAM_NAME}:common:redis_sectigo_ov_${UNDERSCORED_CERT_NAME}_fullchain_pem.txt >$TMP_FULLCHAIN
+    curl -s -u redis:$REDIS_TOKEN ${REDIS_URL}/${TEAM_NAME}:common:redis_sectigo_ov_${UNDERSCORED_CERT_NAME}_chain_pem.txt >$TMP_CA
+    curl -s -H "X-Vault-Token: ${VAULT_TOKEN}" ${VAULT_URL}/${TEAM_NAME}/common/vault_sectigo_ov_wildcard_${UNDERSCORED_CERT_NAME}_key | jq -j .data.value >$TMP_KEY
+fi
+
+# Before installing any certificate we need to check the validity of
+# Certificate, Full Chain, CA and Key that we downloaded
+
+# checking if certificates are valid
+if ! openssl x509 -checkend $MINUTES -noout -in $TMP_CERT &>/dev/null; then
+    echo "the Certificate is malformed or is expiring. Giving up"
+    clean_up
+fi
+if ! openssl x509 -checkend $MINUTES -noout -in $TMP_FULLCHAIN &>/dev/null; then
+    echo "the Full Chain is malformed or is expiring. Giving up"
+    clean_up
+fi
+if ! openssl x509 -in $TMP_CA -text -noout &>/dev/null; then
+    echo "the CA is malformed. Giving up"
+    clean_up
+fi
+
+# checking if key matches the certificate and the full-chain
+KEY_MD5=$(openssl rsa -noout -modulus -in $TMP_KEY | openssl md5 | awk '{print $NF}')
+FULLCHAIN_MD5=$(openssl x509 -noout -modulus -in $TMP_FULLCHAIN | openssl md5 | awk '{print $NF}')
+CRT_MD5=$(openssl x509 -noout -modulus -in $TMP_CERT | openssl md5 | awk '{print $NF}')
+if [[ $KEY_MD5 != $CRT_MD5 ]] || [[ $KEY_MD5 != $FULLCHAIN_MD5 ]]; then
+    echo "the Key $TMP_KEY is either malformed or it does not match the certificate. Giving up"
+    clean_up
+fi
+
+# checking if the certificate contains at least our cert_name
+if ! openssl x509 -noout -text -in $TMP_CERT | grep -qw $CERT_NAME; then
+    echo "the certificate does not match your CN $CERT_NAME"
+    clean_up
+fi
+if ! openssl x509 -noout -text -in $TMP_FULLCHAIN | grep -qw $CERT_NAME; then
+    echo "the full chain certificate does not match your CN $CERT_NAME"
+    clean_up
+fi
+
+# let's install the certificates
+install --owner=root --group=root --mode=0755 --directory $CERT_BASE
+install --owner=root --group=$GROUPNAME --mode=0750 --directory $KEY_BASE
+install --owner=root --group=root --mode=0644 -T ${TMP_CERT} ${CERT_DESTINATION}
+install --owner=root --group=root --mode=0644 -T ${TMP_FULLCHAIN} ${FULLCHAIN_DESTINATION}
+install --owner=root --group=root --mode=0644 -T ${TMP_CA} ${CA_DESTINATION}
+install --owner=root --group=$GROUPNAME --mode=0640 -T ${TMP_KEY} ${KEY_DESTINATION}
+rm -f $TMP_CERT $TMP_FULLCHAIN $TMP_CA $TMP_KEY
+
+echo "installed: ${CERT_DESTINATION}"
+echo "installed: ${FULLCHAIN_DESTINATION}"
+echo "installed: ${CA_DESTINATION}"
+echo "installed: ${KEY_DESTINATION}"
+
+# exiting 1: if we are here we need to reload our service
+exit 1
diff --git a/build.sh b/build.sh
index ade9464..2c155e3 100755
--- a/build.sh
+++ b/build.sh
@@ -7,6 +7,7 @@ if ! which go &>/dev/null; then
     echo "giving up..."
     exit
 fi
+unset GOBIN
 BIN_NAME=acme-downloader
 PATH=$PATH:$(go env GOPATH)/bin
 GOPATH=$(go env GOPATH)
@@ -14,9 +15,9 @@ PROG_VERSION="1.0"
 BUILDTIME=$(date -u '+%Y-%m-%d_%H:%M:%S')
 REPO_DIR=$(dirname $0)
 if [ "$REPO_DIR" = '.' ]; then
-    REPO_DIR=`pwd`
+    REPO_DIR=$(pwd)
 fi
-ln -sf "$REPO_DIR" "${GOPATH}/src/"
+test -L "${GOPATH}/src/${REPO_DIR}" || ln -sf "$REPO_DIR" "${GOPATH}/src/"
 REPO_NAME=$(basename "$REPO_DIR")
 cd "${GOPATH}/src/$REPO_NAME"
 
@@ -27,13 +28,16 @@ usage() {
     echo "    -h | --help [Print this help and exit]"
     echo "    --os=OS     (Compile binary for this OS)"
     echo "    --arch=ARCH (Compile binary for this Architecture)"
+    echo "    --upx       (Enable UPX compression)"
+    echo "    --no-upx    (Disable UPX compression)"
     echo ""
     echo "    Below is a list of supported OS/Arch combinations:"
-    echo "OS         ARCH"; go tool dist list | column -t -s '/' --table-columns =======,=======
+    echo "OS         ARCH"
+    go tool dist list | column -t -s '/' --table-columns =======,=======
     exit
 }
 
-OPTS=$(getopt -o "h" --longoptions "help,os:,arch:" -- "$@")
+OPTS=$(getopt -o "h" --longoptions "help,os:,arch:,upx,no-upx" -- "$@")
 eval set -- "$OPTS"
 
 while true; do
@@ -49,6 +53,12 @@ while true; do
         shift
         ARCH="$1"
         ;;
+    --upx)
+        UPX='UPX'
+        ;;
+    --no-upx)
+        NOUPX='NOUPX'
+        ;;
     --)
         shift
         break
@@ -85,21 +95,27 @@ run_upx() {
     upx --brute "$EXECUTABLE_PATH"
 }
 
-while true; do
-    echo -e "\nUPX degrades performances but in the case of acme-downloader it is not noticeable"
-    echo -e "UPX does not work on some OS/Arch combination (I haven't tried them all)\n"
-    read -p "Do you wish to run upx against ${BIN_NAME}? (y/n) " yn
-    case $yn in
-    [Yy]*)
-        echo ""
-        run_upx
-        break
-        ;;
-    [Nn]*) break ;;
-    *)
-        echo "Please answer Y|y or N|n."
-        ;;
-    esac
-done
+if [ -n $UPX ]; then
+    run_upx
+elif [ -n $NOUPX ]; then
+    true
+else
+    while true; do
+        echo -e "\nUPX degrades performances but in the case of acme-downloader it is not noticeable"
+        echo -e "UPX does not work on some OS/Arch combination (I haven't tried them all)\n"
+        read -p "Do you wish to run upx against ${BIN_NAME}? (y/n) " yn
+        case $yn in
+        [Yy]*)
+            echo ""
+            run_upx
+            break
+            ;;
+        [Nn]*) break ;;
+        *)
+            echo "Please answer Y|y or N|n."
+            ;;
+        esac
+    done
+fi
 
 echo -e "\nthe binary was compiled and it is avilable as:\n - \"$EXECUTABLE_PATH\"\n"
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..099344e
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,11 @@
+module acme-downloader
+
+go 1.16
+
+require (
+	github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815
+	github.com/go-ini/ini v1.62.0
+	github.com/smartystreets/goconvey v1.6.4 // indirect
+	github.com/tidwall/gjson v1.8.0
+	gopkg.in/ini.v1 v1.62.0 // indirect
+)
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..5209733
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,25 @@
+github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815 h1:bWDMxwH3px2JBh6AyO7hdCn/PkvCZXii8TGj7sbtEbQ=
+github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
+github.com/go-ini/ini v1.62.0 h1:7VJT/ZXjzqSrvtraFp4ONq80hTcRQth1c9ZnQ3uNQvU=
+github.com/go-ini/ini v1.62.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
+github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
+github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
+github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
+github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
+github.com/tidwall/gjson v1.8.0 h1:Qt+orfosKn0rbNTZqHYDqBrmm3UDA4KRkv70fDzG+PQ=
+github.com/tidwall/gjson v1.8.0/go.mod h1:5/xDoumyyDNerp2U36lyolv46b3uF/9Bu6OfyQ9GImk=
+github.com/tidwall/match v1.0.3 h1:FQUVvBImDutD8wJLN6c5eMzWtjgONK9MwIBCOrUJKeE=
+github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
+github.com/tidwall/pretty v1.1.0 h1:K3hMW5epkdAVwibsQEfR/7Zj0Qgt4DxtNumTq/VloO8=
+github.com/tidwall/pretty v1.1.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=
+gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
-- 
GitLab