#! /usr/bin/env bash
set -eu -o pipefail

# Early out to prevent blind copy paste:
echo "Please read and adapt before running this script."
exit 1

USAGE="USAGE:
  $0 run <user> <command> [<args>...]
  $0 up
  $0 down"

# Path to config file with PIA credentials and server:
CONFIG=/etc/wireguard/pia-wirebox.conf

# Name of network namespace (can be left as is):
NETNS=pia-wirebox

# Name of network interface (can be left as is)
IFNAME=wg-pia

# Content of file "ca.rsa.4096.crt",
# pasted here to spare you the need of installing yet another file:
CERT='-----BEGIN CERTIFICATE-----
MIIHqzCCBZOgAwIBAgIJAJ0u+vODZJntMA0GCSqGSIb3DQEBDQUAMIHoMQswCQYD
VQQGEwJVUzELMAkGA1UECBMCQ0ExEzARBgNVBAcTCkxvc0FuZ2VsZXMxIDAeBgNV
BAoTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMSAwHgYDVQQLExdQcml2YXRlIElu
dGVybmV0IEFjY2VzczEgMB4GA1UEAxMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3Mx
IDAeBgNVBCkTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMS8wLQYJKoZIhvcNAQkB
FiBzZWN1cmVAcHJpdmF0ZWludGVybmV0YWNjZXNzLmNvbTAeFw0xNDA0MTcxNzQw
MzNaFw0zNDA0MTIxNzQwMzNaMIHoMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0Ex
EzARBgNVBAcTCkxvc0FuZ2VsZXMxIDAeBgNVBAoTF1ByaXZhdGUgSW50ZXJuZXQg
QWNjZXNzMSAwHgYDVQQLExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4GA1UE
AxMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxIDAeBgNVBCkTF1ByaXZhdGUgSW50
ZXJuZXQgQWNjZXNzMS8wLQYJKoZIhvcNAQkBFiBzZWN1cmVAcHJpdmF0ZWludGVy
bmV0YWNjZXNzLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALVk
hjumaqBbL8aSgj6xbX1QPTfTd1qHsAZd2B97m8Vw31c/2yQgZNf5qZY0+jOIHULN
De4R9TIvyBEbvnAg/OkPw8n/+ScgYOeH876VUXzjLDBnDb8DLr/+w9oVsuDeFJ9K
V2UFM1OYX0SnkHnrYAN2QLF98ESK4NCSU01h5zkcgmQ+qKSfA9Ny0/UpsKPBFqsQ
25NvjDWFhCpeqCHKUJ4Be27CDbSl7lAkBuHMPHJs8f8xPgAbHRXZOxVCpayZ2SND
fCwsnGWpWFoMGvdMbygngCn6jA/W1VSFOlRlfLuuGe7QFfDwA0jaLCxuWt/BgZyl
p7tAzYKR8lnWmtUCPm4+BtjyVDYtDCiGBD9Z4P13RFWvJHw5aapx/5W/CuvVyI7p
Kwvc2IT+KPxCUhH1XI8ca5RN3C9NoPJJf6qpg4g0rJH3aaWkoMRrYvQ+5PXXYUzj
tRHImghRGd/ydERYoAZXuGSbPkm9Y/p2X8unLcW+F0xpJD98+ZI+tzSsI99Zs5wi
jSUGYr9/j18KHFTMQ8n+1jauc5bCCegN27dPeKXNSZ5riXFL2XX6BkY68y58UaNz
meGMiUL9BOV1iV+PMb7B7PYs7oFLjAhh0EdyvfHkrh/ZV9BEhtFa7yXp8XR0J6vz
1YV9R6DYJmLjOEbhU8N0gc3tZm4Qz39lIIG6w3FDAgMBAAGjggFUMIIBUDAdBgNV
HQ4EFgQUrsRtyWJftjpdRM0+925Y6Cl08SUwggEfBgNVHSMEggEWMIIBEoAUrsRt
yWJftjpdRM0+925Y6Cl08SWhge6kgeswgegxCzAJBgNVBAYTAlVTMQswCQYDVQQI
EwJDQTETMBEGA1UEBxMKTG9zQW5nZWxlczEgMB4GA1UEChMXUHJpdmF0ZSBJbnRl
cm5ldCBBY2Nlc3MxIDAeBgNVBAsTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMSAw
HgYDVQQDExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4GA1UEKRMXUHJpdmF0
ZSBJbnRlcm5ldCBBY2Nlc3MxLzAtBgkqhkiG9w0BCQEWIHNlY3VyZUBwcml2YXRl
aW50ZXJuZXRhY2Nlc3MuY29tggkAnS7684Nkme0wDAYDVR0TBAUwAwEB/zANBgkq
hkiG9w0BAQ0FAAOCAgEAJsfhsPk3r8kLXLxY+v+vHzbr4ufNtqnL9/1Uuf8NrsCt
pXAoyZ0YqfbkWx3NHTZ7OE9ZRhdMP/RqHQE1p4N4Sa1nZKhTKasV6KhHDqSCt/dv
Em89xWm2MVA7nyzQxVlHa9AkcBaemcXEiyT19XdpiXOP4Vhs+J1R5m8zQOxZlV1G
tF9vsXmJqWZpOVPmZ8f35BCsYPvv4yMewnrtAC8PFEK/bOPeYcKN50bol22QYaZu
LfpkHfNiFTnfMh8sl/ablPyNY7DUNiP5DRcMdIwmfGQxR5WEQoHL3yPJ42LkB5zs
6jIm26DGNXfwura/mi105+ENH1CaROtRYwkiHb08U6qLXXJz80mWJkT90nr8Asj3
5xN2cUppg74nG3YVav/38P48T56hG1NHbYF5uOCske19F6wi9maUoto/3vEr0rnX
JUp2KODmKdvBI7co245lHBABWikk8VfejQSlCtDBXn644ZMtAdoxKNfR2WTFVEwJ
iyd1Fzx0yujuiXDROLhISLQDRjVVAvawrAtLZWYK31bY7KlezPlQnl/D9Asxe85l
8jO5+0LdJ6VyOs/Hd4w52alDW/MFySDZSfQHMTIc30hLBJ8OnCEIvluVQQ2UQvoW
+no177N9L2Y+M9TcTA62ZyMXShHQGeh20rb4kK8f+iFX8NxtdHVSkxMEFSfDDyQ=
-----END CERTIFICATE-----'

main() {
    if [[ $EUID -ne 0 ]]; then
        exec sudo "${@:0}"
    fi

    case "$1" in
        run|up|down)
            "$@"
            ;;
        *)
            echo "$USAGE"
            exit 1
            ;;
    esac
}

# Run command as user:
# Usage: run <command> [<args...>]
run() {
    up
    ip netns exec $NETNS sudo -u "${SUDO_USER:-$(id -urn)}" -- "$@"
}

# Check if connection is up:
is_up() {
    ip -n $NETNS route 2>&1 | grep default | grep $IFNAME >/dev/null
}

# Bring up wireguard connection:
up() {
    if is_up; then
        return 0
    fi

    read_config "$CONFIG"

    PIA_TOKEN=$(
        curl -s --location --request POST \
            'https://www.privateinternetaccess.com/api/client/v2/token' \
            --form "username=$PIA_USER" \
            --form "password=$PIA_PASS" |
            jq -r '.token'
    )

    OUR_PRIVKEY=$(wg genkey)
    OUR_PUBKEY=$(wg pubkey <<<"$OUR_PRIVKEY")

    SERVER_RESPONSE=$(
        curl -s -G \
            --connect-to "$WG_HOSTNAME::$WG_SERVER_IP:" \
            --cacert <(echo "$CERT") \
            --data-urlencode "pt=${PIA_TOKEN}" \
            --data-urlencode "pubkey=$OUR_PUBKEY" \
            "https://${WG_HOSTNAME}:1337/addKey"
    )

    REQUEST_STATUS=$(jq -r '.status' <<<"$SERVER_RESPONSE")
    if [[ "$REQUEST_STATUS" != "OK" ]]; then
        >&2 echo -e "${red}Server did not return OK. Stopping now.${nc}"
        exit 1
    fi

    SERVER_KEY=$( jq -r '.server_key'  <<<"$SERVER_RESPONSE")
    SERVER_PORT=$(jq -r '.server_port' <<<"$SERVER_RESPONSE")
    SERVER_IP=$(  jq -r '.server_ip'   <<<"$SERVER_RESPONSE") # WG_SERVER_IP
    # SERVER_VIP=$( jq -r '.server_vip'  <<<"$SERVER_RESPONSE") # ?
    PEER_IP=$(    jq -r '.peer_ip'     <<<"$SERVER_RESPONSE")
    # PEER_PUBKEY=$(jq -r '.peer_pubkey' <<<"$SERVER_RESPONSE") # OUR_PUBKEY?
    DNS_SERVERS=$(jq -r '.dns_servers | join(" ")' <<<$SERVER_RESPONSE)

    ip netns add $NETNS || true
    ip -n $NETNS link set dev lo up || true

    # Make "ping" work in namespace:
    ip netns exec $NETNS sysctl -q net.ipv4.ping_group_range="0 2147483647"

    # create network interface, move into namespace:
    ip link add $IFNAME type wireguard
    ip link set $IFNAME netns $NETNS

    ip netns exec $NETNS wg setconf $IFNAME <(echo "
[Interface]
# Address = $PEER_IP
PrivateKey = $OUR_PRIVKEY

[Peer]
PersistentKeepalive = 25
PublicKey = $SERVER_KEY
AllowedIPs = 0.0.0.0/0
Endpoint = $SERVER_IP:$SERVER_PORT
")

    ip -n $NETNS address add "$PEER_IP"/32 dev $IFNAME
    ip -n $NETNS link set up dev $IFNAME mtu 1420
    ip -n $NETNS route add default dev $IFNAME

    mkdir -p /etc/netns/$NETNS
    rm -f /etc/netns/$NETNS/resolv.conf
    printf 'nameserver %s\n' $DNS_SERVERS >/etc/netns/$NETNS/resolv.conf
    chmod -R o+rX /etc/netns
}

# Read config file "safely" without simply sourcing it:
read_config() {
    while IFS='=' read -r lhs rhs; do
        case "$lhs" in
            PIA_USER|PIA_PASS|WG_SERVER_IP|WG_HOSTNAME)
                printf -v "$lhs" "%s" "$rhs"
                ;;
        esac
    done <"$1"
}

# Take down wireguard interface:
down() {
    ip -n $NETNS link delete dev $IFNAME
    ip netns delete $NETNS
}

main "$@"
