#!/usr/bin/python3
"""Write a candidate vpn-router.conf to the path given on the command line.

Called from postinst, which hands the result to ucf(1). ucf compares it with
/etc/vpn-router/vpn-router.conf and decides what to do about local changes, so
this script never writes to /etc and never has to worry about destroying an
administrator's edits.

The candidate is built in three layers, each overriding the one before:

  1. the shipped defaults
  2. the current contents of /etc/vpn-router/vpn-router.conf, if it exists
  3. any debconf answer that was actually given

Layer 2 is what makes reconfiguration safe: a setting the administrator edited
by hand, and that debconf has nothing to say about, is carried through
unchanged, so ucf only sees a diff where something really changed. An empty
answer means "leave alone", which is why clearing the pre-shared key from the
debconf database after installation does not blank it on the next
dpkg-reconfigure.

Answers arrive as VPN_ROUTER_* environment variables. The pre-shared key is
stored base64-encoded so that arbitrary characters cannot collide with INI
syntax.
"""

import base64
import os
import sys

sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)))

import vpnrouter

# environment variable -> (section, option)
ANSWERS = {
    'VPN_ROUTER_PLATFORM':        ('general', 'platform'),
    'VPN_ROUTER_MODE':            ('general', 'mode'),
    'VPN_ROUTER_INT_ADDR':        ('local', 'int_addr'),
    'VPN_ROUTER_EXTERNAL_INTERFACE': ('interfaces', 'external'),
    'VPN_ROUTER_INTERNAL_INTERFACE': ('interfaces', 'internal'),
    'VPN_ROUTER_LOCAL_FQDN':      ('wan', 'local_fqdn'),
    'VPN_ROUTER_LOCAL_ID_MODE':   ('wan', 'local_id_mode'),
    'VPN_ROUTER_LOCAL_CIDRS':     ('local', 'cidrs'),
    'VPN_ROUTER_INT_GATEWAY_IP':  ('local', 'int_gateway_ip'),
    'VPN_ROUTER_REMOTE_ADDRS':    ('remote', 'addrs'),
    'VPN_ROUTER_REMOTE_ID':       ('remote', 'id'),
    'VPN_ROUTER_REMOTE_CIDRS':    ('remote', 'cidrs'),
    'VPN_ROUTER_P2S_ENABLED':     ('p2s', 'enabled'),
    'VPN_ROUTER_P2S_ADDRESS_POOL': ('p2s', 'address_pool'),
    'VPN_ROUTER_P2S_CA_NAME':     ('p2s', 'ca_name'),
    'VPN_ROUTER_WG_ENABLED':      ('wireguard', 'enabled'),
    'VPN_ROUTER_WG_ADDRESS':      ('wireguard', 'address'),
    'VPN_ROUTER_WG_LISTEN_PORT':  ('wireguard', 'listen_port'),
}


def main():
    if len(sys.argv) != 2:
        print('usage: generate-config OUTPUT', file=sys.stderr)
        return 2
    output = sys.argv[1]

    parser = vpnrouter.default_parser()

    current = vpnrouter.load_config()
    for section in parser.sections():
        for option in parser[section]:
            if current.has_option(section, option):
                parser[section][option] = current.get(section, option)

    for variable, (section, option) in ANSWERS.items():
        if os.environ.get(variable):
            parser[section][option] = os.environ[variable]

    psk = os.environ.get('VPN_ROUTER_PSK', '')
    if psk:
        parser['remote']['psk_b64'] = base64.b64encode(
            psk.encode('utf-8')).decode('ascii')

    with open(output, 'w', encoding='utf-8') as handle:
        parser.write(handle)
    os.chmod(output, 0o600)
    return 0


if __name__ == '__main__':
    sys.exit(main())
