#!/usr/bin/python3
# -*- coding: UTF-8 -*-
"""
Handle OpenVPN client connection event.
"""
# © 2012, Multapplied Networks, Inc.
import os
import re
import requests
import sys
from systemd import journal
import traceback

CONFIG_FILE_UMASK = 0o77 # Mask all group, other bits
URI = "/openvpn/client-connected"
CLIENT_CONNECT_KEY_FILE = "/etc/bondingadmin/local-www-key"
DEFAULT_SERVER = "localhost"
TIMEOUT = 10.0
MSG_PREFIX = "openvpn-client-connect"


def download_client_config(server, connect_key, node_id, client_addr):
    """Download the client configuration."""
    return requests.post(
        "https://%s%s" % (server, URI),
        data={
            "key": connect_key,
            "id": node_id,
            "client_addr": client_addr,
        },
        timeout=TIMEOUT,
        verify=False,
    )

def save_client_config(filename, client_config):
    """Save the client configuration."""
    original_umask = os.umask(CONFIG_FILE_UMASK)
    with open(filename, "w") as config:
        config.write(client_config)
    os.umask(original_umask)

if __name__ == "__main__":
    node_id = None
    try:
        with open(CLIENT_CONNECT_KEY_FILE, "r") as connect_key_file:
            connect_key = connect_key_file.read().strip()

        node_id_match = re.match("node-([0-9]+)-", os.environ["common_name"])
        node_id = int(node_id_match.group(1))
        journal.send("%s: Starting connect for node %s." % (MSG_PREFIX, node_id))

        if 'trusted_ip' in os.environ:
            client_addr = "%s:%s" % (
                os.environ["trusted_ip"],
                os.environ["trusted_port"]
            )
        elif 'trusted_ip6' in os.environ:
            client_addr = "%s:%s" % (
                os.environ["trusted_ip6"],
                os.environ["trusted_port"]
            )
        else:
            journal.send("%s: No trusted IP" % MSG_PREFIX)
            sys.exit(1)

        response = download_client_config(DEFAULT_SERVER, connect_key, node_id, client_addr)
        if response.status_code == requests.codes.ok:
            save_client_config(sys.argv[1], response.text)
        else:
            journal.send("%s: Unexpected response to node %s config request: %s" % (MSG_PREFIX, node_id, response.status_code))
            sys.exit(1) # This disconnects the client.
    except requests.exceptions.RequestException as e:
        journal.send("%s: Failed to fetch configuration for node %s: %s" % (MSG_PREFIX, node_id, e))
        sys.exit(1) # This disconnects the client.
    except Exception as e:
        tb = traceback.format_exc()
        journal.send("%s: Encountered an exception while connecting node %s: %s" % (MSG_PREFIX, node_id, tb))
        sys.exit(1) # This disconnects the client.
    journal.send("%s: Finished connect for node %s." % (MSG_PREFIX, node_id))
