#!/bin/bash

# HARICA-Serverzertifikate

# (C) 2025 Rainer Perske, Universitaet Muenster
# Lizenz: CC BY SA <https://creativecommons.org/licenses/by-sa/4.0/>

{ set -e

  # Liste aller FQDNs, fuer die jeweils ein eigenes Zertifikat beantragt werden soll  
  # Fuer mehrere FQDNs in einem Zertifikat muss unten das Skript erweitert werden
  # Siehe den unten dick markierten Kommentar
  fqdnlist='
    perfidix.uni-muenster.de
    perfix.uni-muenster.de
  '

  # Vorausgesetzt werden zwei bei HARICA registrierte Kennungen
  # - normaler Nutzer, ohne 2FA
  # - SSL Enterprise Approver, mit 2FA
  # Die Kennungen, Passwoerter und der OTP-Schluessel sind hier einzutragen
  # Ebenso ein nur temporaer benoetigtes Passwort fuer den privaten Schluessel

  ##### Logindaten

  user1=.....
  pass1=.....
  user2=.....
  pass2=.....
  totp2=.....
  keypass=.....

  proxy='-x http://wwwproxy.uni-muenster.de:3128' # falls noetig

  ##### Login als normaler Nutzer

  # Keine alten Cookies
  /bin/rm -rf "harica.$user1.cookies"

  # Anmeldeseite aufrufen
  page="$(
    curl -sS $proxy \
      -c "harica.$user1.cookies" -b "harica.$user1.cookies" \
      -X GET -L \
      "https://cm.harica.gr/"
  )"
  # RequestVerificationToken extrahieren
  RVT1="${page#*'name="__RequestVerificationToken"'}"
  RVT1="${RVT1#*'value="'}"
  RVT1="${RVT1%%'"'*}"

  # JavaWebToken abrufen
  JWT1="$(
    curl -sS $proxy \
      -c "harica.$user1.cookies" -b "harica.$user1.cookies" \
      -H "RequestVerificationToken: $RVT1" \
      -X POST -H 'Content-Type: application/json' \
      -d '{ "email":"'"$user1"'", "password":"'"$pass1"'" }' \
      "https://cm.harica.gr/api/User/Login"
  )"
  # ohne OTP

  # Anmeldeseite mit JavaWebToken aufrufen
  page="$(
    curl -sS $proxy \
      -c "harica.$user1.cookies" -b "harica.$user1.cookies" \
      -H "Authorization: $JWT1" \
      -X GET \
      "https://cm.harica.gr/"
  )"
  # Neues RequestVerificationToken extrahieren
  RVT1="${page#*'name="__RequestVerificationToken"'}"
  RVT1="${RVT1#*'value="'}"
  RVT1="${RVT1%%'"'*}"

  ##### Login als Enterprise Approver

  # Keine alten Cookies
  /bin/rm -rf "harica.$user2.cookies"

  # Anmeldeseite aufrufen
  page="$(
    curl -sS $proxy \
      -c "harica.$user2.cookies" -b "harica.$user2.cookies" \
      -X GET -L \
      "https://cm.harica.gr/"
  )"
  # RequestVerificationToken extrahieren
  RVT2="${page#*'name="__RequestVerificationToken"'}"
  RVT2="${RVT2#*'value="'}"
  RVT2="${RVT2%%'"'*}"

  # JavaWebToken abrufen
  JWT2="$(
    curl -sS $proxy \
      -c "harica.$user2.cookies" -b "harica.$user2.cookies" \
      -H "RequestVerificationToken: $RVT2" \
      -X POST -H 'Content-Type: application/json' \
      -d '{ "email":"'"$user2"'", "password":"'"$pass2"'" }' \
      "https://cm.harica.gr/api/User/Login"
  )"
  if test -z "$JWT2"
  then JWT2="$(
    curl -sS $proxy \
      -c "harica.$user2.cookies" -b "harica.$user2.cookies" \
      -H "RequestVerificationToken: $RVT2" \
      -X POST -H 'Content-Type: application/json' \
      -d '{ "email":"'"$user2"'", "password":"'"$pass2"'", "token":"'"$( oathtool --totp --base32 "$totp2" )"'" }' \
      "https://cm.harica.gr/api/User/Login2FA"
  )"
  fi

  # Anmeldeseite mit JavaWebToken aufrufen
  page="$(
    curl -sS $proxy \
      -c "harica.$user2.cookies" -b "harica.$user2.cookies" \
      -H "Authorization: $JWT2" \
      -X GET \
      "https://cm.harica.gr/"
  )"
  # Neues RequestVerificationToken extrahieren
  RVT2="${page#*'name="__RequestVerificationToken"'}"
  RVT2="${RVT2#*'value="'}"
  RVT2="${RVT2%%'"'*}"

  for fqdn in $fqdnlist
  do
    set -e

    ##### Request als normaler Nutzer

    ORGDATA="$(
      curl -sS $proxy \
        -c "harica.$user2.cookies" -b "harica.$user2.cookies" \
        -H "RequestVerificationToken: $RVT2" \
        -H "Authorization: $JWT2" \
        -X POST -H 'Content-Type: application/json' \
        -H 'Accept: application/json' \
        -d '[{"domain":"'"$fqdn"'"}]' \
        'https://cm.harica.gr/api/ServerCertificate/CheckMachingOrganization'
    )"
    ORGDN="${ORGDATA##*'"id":"'}"
    ORGDN="OrganizationId:${ORGDN%%'"'*}"
    C="${ORGDATA##*'"country":"'}"
    C="${C%%'"'*}"
    ST="${ORGDATA##*'"state":"'}"
    ST="${ST%%'"'*}"
    L="${ORGDATA##*'"locality":"'}"
    L="${L%%'"'*}"
    O="${ORGDATA##*'"organizationName":"'}"
    O="${O%%'"'*}"
    OU="${ORGDATA##*'"organizationUnitName":"'}"
    OU="${OU%%'"'*}"
    test "$C"  && ORGDN="$ORGDN&C:$C"   || true
    test "$ST" && ORGDN="$ORGDN&ST:$ST" || true
    test "$L"  && ORGDN="$ORGDN&L:$L"   || true
    test "$O"  && ORGDN="$ORGDN&O:$O"   || true
    test "$OU" && ORGDN="$ORGDN&OU:$OU" || true

    openssl req -new \
      -newkey rsa:4096 -sha256 -utf8 -batch \
      -keyout "$fqdn.key.pem" -passout fd:3 3<<<"$keypass" \
      -outform pem -out "$fqdn.csr.pem" \
      -subj "/CN=$fqdn"
    ########## Das folgende JSON-Array ist fuer weitere FQDNs im Zertifikat
    ########## mit zusaetzlichen Elementen zu versehen, bei denen sich
    ########## nur der FQDN unterscheidet, alles andere bleibt gleich.
    domains='[
      { "domain":"'"$fqdn"'",
        "isValid":true,
        "includeWWW":false,
        "errorMessage":"",
        "warningMessage":"",
        "isPrevalidated":true,
        "isWildcard":false,
        "isFreeDomain":true,
        "isFreeDomainDV":true,
        "isFreeDomainEV":false,
        "canRequestOV":true,
        "canRequestEV":false
      }
    ]'
    REQID="$(
      curl -sS $proxy \
        -c "harica.$user1.cookies" -b "harica.$user1.cookies" \
        -H "RequestVerificationToken: $RVT1" \
        -H "Authorization: $JWT1" \
        -X POST \
        -H 'Accept: application/json' \
        -F domains="$domains" \
        -F domainsString="$domains" \
        -F csr="<$fqdn.csr.pem" \
        -F duration=1 \
        -F transactionType=OV \
        -F friendlyName="$fqdn" \
        -F isManualCSR=true \
        -F consentSameKey=true \
        -F organizationDN="$ORGDN" \
        https://cm.harica.gr/api/ServerCertificate/RequestServerCertificate
    )"
    REQID="${REQID##*'"id":"'}"
    REQID="${REQID%%'"'*}"

    ##### Aktionen als Enterprise Approver

    curl -sS $proxy \
      -c "harica.$user2.cookies" -b "harica.$user2.cookies" \
      -H "RequestVerificationToken: $RVT2" \
      -H "Authorization: $JWT2" \
      -X POST -H 'Content-Type: application/json' \
      -H 'Accept: application/json' \
      -d '{"startIndex":0,"status":"Pending","filterPostDTOs":[]}' \
      'https://cm.harica.gr/api/OrganizationValidatorSSL/GetSSLReviewableTransactions' |
    php -r '
      $r="'"$REQID"'";
      $a=json_decode(stream_get_contents(STDIN),true);
      foreach($a as $b)if($b["transactionId"]==$r)foreach($b["reviewGetDTOs"] as $c)if(!$c["isReviewed"])echo $c["reviewId"]." ".$c["reviewValue"]."\n";
    ' |
    while read -r i v
    do
      curl -sS $proxy \
        -c "harica.$user2.cookies" -b "harica.$user2.cookies" \
        -H "RequestVerificationToken: $RVT2" \
        -H "Authorization: $JWT2" \
        -X POST \
        -H 'Accept: application/json' \
        -F reviewId="$i" \
        -F isValid=true \
        -F informApplicant=false \
        -F reviewMessage="Approved by $user2" \
        -F reviewValue="$v" \
        'https://cm.harica.gr/api/OrganizationValidatorSSL/UpdateReviews' | jq .
    done

    ##### Zertifikat abholen als normaler Nutzer

    CERTS="$(
      curl -sS $proxy \
        -c "harica.$user1.cookies" -b "harica.$user1.cookies" \
        -H "RequestVerificationToken: $RVT1" \
        -H "Authorization: $JWT1" \
        -X POST -H 'Content-Type: application/json' \
        -H 'Accept: application/json' \
        -d '{"id":"'"$REQID"'"}' \
        'https://cm.harica.gr/api/Certificate/GetCertificate'
    )"
    CERTS="${CERTS##*'"pemBundle":"'}"
    CERTS="${CERTS%%'"'*}"
    CERTS="${CERTS//\\n/
}"

    openssl rsa -in "$fqdn.key.pem" -passin fd:3 3<<<"$keypass"    >"$fqdn.pem"
    echo "$CERTS"                                                 >>"$fqdn.pem"
    echo "Private key and all certificates for $fqdn can be found in $fqdn.pem"
    /bin/rm "$fqdn.key.pem" "$fqdn.csr.pem"

  done

  exit
}