#!/bin/bash

#-----------------------------------------------------------------------------------------------
# Setup

ServerName=""
Subnet=""
Gateway=""
SignedURL=""
# Specify extra subnets with a comma in between
ExtraSubnets="10.50.50.0/24,10.140.0.0/24,10.130.0.0/24,10.150.0.0/24"
ExpireDays=1000

CAname=Edgerouter
CAsubject="/C=NL/ST=UTRECHT/L=UTRECHT/O=CAworld"
CAexpire=$ExpireDays
CAkeyLength=2048
ServerSubject="/C=NL/ST=UTRECHT/L=UTRECHT/O=ServerWorld/CN=${ServerName}"
ServerExpire=$ExpireDays
ServerKeyLength=2048

ClientName=client
ClientSubject="/C=NL/ST=UTRECHT/L=UTRECHT/O=ClientWorld/CN=${ClientName}"
ClientExpire=$ExpireDays
ClientKeyLength=2048

DHkeyLength=1024

#-----------------------------------------------------------------------------------------------
# Cleanup Old Files

rm -rf $CAname*
rm -rf $ServerName.crt
rm -rf $ServerName.key
rm -rf dh.pem
rm -rf $ServerName.ovpn
rm -rf $ClientName*
rm -rf client.ovpn

#-----------------------------------------------------------------------------------------------
# Functions

function makeCA () {
    CAname=$1
    CAexpire=$2
    CAsubject=$3
    CAkeyLength=$4
    printf "Generating Certificate Authority ${CAname}...\n\n"

    openssl genrsa -out ${CAname}.key ${CAkeyLength}
    openssl req -x509 -new -nodes -key ${CAname}.key -sha256 -days ${CAexpire} -out ${CAname}.pem -subj $CAsubject
}

function makeCert () {
    CAname=$1
    CertName=$2
    CertExpire=$3
    CertSubject=$4
    CertKeyLength=$5
    printf "\nGeneration certificate for ${CertName}...\n\n"

    ConfigFile=`mktemp`
    printf 'basicConstraints = CA:FALSE\nsubjectKeyIdentifier=hash\nauthorityKeyIdentifier=keyid' > ${ConfigFile}

    openssl genrsa -out ${CertName}.key ${CertKeyLength}
    openssl req  -new -key ${CertName}.key -out ${CertName}.csr -subj ${CertSubject}
    openssl x509 -req -extfile ${ConfigFile} -in ${CertName}.csr -CA ${CAname}.pem -CAkey ${CAname}.key \
             -CAcreateserial -out ${CertName}.crt -days ${CertExpire} -sha256

    rm ${CertName}.csr
    rm ${ConfigFile}
}

function makeOvpnFile () {
    CAname=$1
    ClientName=$2
    HostName=$3
    printf "\nGenerating .ovpn file ${ServerName}.ovpn...\n\n"

    echo client > ${ServerName}.ovpn
    echo dev tun >> ${ServerName}.ovpn
    echo proto udp >> ${ServerName}.ovpn
    echo remote ${HostName} 1194 >> ${ServerName}.ovpn
    echo cipher AES-256-CBC >> ${ServerName}.ovpn
    echo auth SHA256 >> ${ServerName}.ovpn
    echo resolv-retry infinite >> ${ServerName}.ovpn
    echo redirect-gateway def1 >> ${ServerName}.ovpn
    echo nobind >> ${ServerName}.ovpn
    echo comp-lzo yes >> ${ServerName}.ovpn
    echo persist-key >> ${ServerName}.ovpn
    echo persist-tun >> ${ServerName}.ovpn
    echo user nobody >> ${ServerName}.ovpn
    echo group nogroup >> ${ServerName}.ovpn
    echo verb 3 >> ${ServerName}.ovpn
    echo setenv ALLOW_PASSWORD_SAVE 1 >> ${ServerName}.ovpn
    echo auth-user-pass >> ${ServerName}.ovpn
    echo '<ca>' >> ${ServerName}.ovpn
    cat ${CAname}.pem >> ${ServerName}.ovpn
    echo '</ca>' >> ${ServerName}.ovpn
    echo '<cert>' >> ${ServerName}.ovpn
    cat ${ClientName}.crt >> ${ServerName}.ovpn
    echo '</cert>' >> ${ServerName}.ovpn
    echo '<key>' >> ${ServerName}.ovpn
    cat ${ClientName}.key >> ${ServerName}.ovpn
    echo '</key>' >> ${ServerName}.ovpn
}

function showConfGuide () {
    CAname=$1
    ServerName=$2
    printf "\nAdd these configuration lines to your edgerouter...\n\n"

    CurrentPath=`pwd`
    echo set interfaces openvpn vtun0 tls ca-cert-file ${CurrentPath}/${CAname}.pem
    echo set interfaces openvpn vtun0 tls cert-file ${CurrentPath}/${ServerName}.crt
    echo set interfaces openvpn vtun0 tls key-file ${CurrentPath}/${ServerName}.key
    echo set interfaces openvpn vtun0 tls dh-file ${CurrentPath}/dh.pem
    echo set interfaces openvpn vtun0 mode server
    echo set interfaces openvpn vtun0 hash sha256
    echo set interfaces openvpn vtun0 openvpn-option --duplicate-cn
    echo set interfaces openvpn vtun0 openvpn-option "'--user nobody'"
    echo set interfaces openvpn vtun0 openvpn-option "'--group nogroup'"
    echo set interfaces openvpn vtun0 openvpn-option --persist-key
    echo set interfaces openvpn vtun0 openvpn-option --persist-tun
    echo set interfaces openvpn vtun0 openvpn-option "'--dev vtun0'"
    echo set interfaces openvpn vtun0 openvpn-option --client-to-client
    echo set interfaces openvpn vtun0 openvpn-option "'--proto udp'"
    echo set interfaces openvpn vtun0 openvpn-option "'--keepalive 10 120'"
    echo set interfaces openvpn vtun0 openvpn-option "'--comp-lzo yes'"
    echo set interfaces openvpn vtun0 openvpn-option "'--verb 4'"
    echo set interfaces openvpn vtun0 openvpn-option "'--plugin /usr/lib/openvpn/openvpn-auth-pam.so common-auth'"
    echo set interfaces openvpn vtun0 server subnet 10.99.99.0/24
    echo set interfaces openvpn vtun0 hash sha256
    echo set interfaces openvpn vtun0 encryption aes256
    echo
    echo
    echo !!!! READ AND ADJUST !!!!
    echo set interfaces openvpn vtun0 server push-route $Subnet
    echo set interfaces openvpn vtun0 server name-server $Gateway
    IFS=','
    # Read the input string into an array
    read -ra items <<< "$ExtraSubnets"

    # Loop through the array
    for item in "${items[@]}"; do
        echo "set interfaces openvpn vtun0 server push-route $item"
    done
    # echo set interfaces openvpn vtun0 server push-route 10.50.50.0/24
    # echo set interfaces openvpn vtun0 server push-route 10.140.0.0/24
    # echo set interfaces openvpn vtun0 server push-route 10.130.0.0/24
    # echo set interfaces openvpn vtun0 server push-route 10.150.0.0/24
    echo
}

function makeDH () {
    DHkeyLength=$1
    printf "\nMaking diffie-hellman keypair for perfect forward secrecy...\n\n"

    openssl dhparam -out dh.pem -2 ${DHkeyLength}
}

#-----------------------------------------------------------------------------------------------
# Make everything

makeCA ${CAname} ${CAexpire} ${CAsubject} ${CAkeyLength}
makeCert ${CAname} ${ServerName} ${ServerExpire} ${ServerSubject} ${ServerKeyLength}
makeCert ${CAname} ${ClientName} ${ClientExpire} ${ClientSubject} ${ClientKeyLength}
makeDH ${DHkeyLength}
makeOvpnFile ${CAname} ${ClientName} ${ServerName}
showConfGuide ${CAname} ${ServerName}

#-----------------------------------------------------------------------------------------------
# Send the VPN File to our Systems

curl -fsS -m 10 --retry 5 -F "file=@/config/openvpn/$ServerName.ovpn" $SignedURL
