#!/usr/bin/env python3
#
# Copyright (C) 2021-2023 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

# - remove primary/secondary identifier from nameserver
# - TODO: remove radius server req-limit

import os

from sys import argv
from sys import exit
from vyos.configtree import ConfigTree
from vyos.pki import load_certificate
from vyos.pki import load_crl
from vyos.pki import load_private_key
from vyos.pki import encode_certificate
from vyos.pki import encode_private_key
from vyos.utils.process import run

if len(argv) < 2:
    print("Must specify file name!")
    exit(1)

file_name = argv[1]

with open(file_name, 'r') as f:
    config_file = f.read()

config = ConfigTree(config_file)
base = ['vpn', 'l2tp', 'remote-access', 'ipsec-settings']
pki_base = ['pki']

if not config.exists(base):
    exit(0)

AUTH_DIR = '/config/auth'

def wrapped_pem_to_config_value(pem):
    return "".join(pem.strip().split("\n")[1:-1])

if not config.exists(base + ['authentication', 'x509']):
    exit(0)

x509_base = base + ['authentication', 'x509']
pki_name = 'l2tp_remote_access'

if not config.exists(pki_base + ['ca']):
    config.set(pki_base + ['ca'])
    config.set_tag(pki_base + ['ca'])

if not config.exists(pki_base + ['certificate']):
    config.set(pki_base + ['certificate'])
    config.set_tag(pki_base + ['certificate'])

if config.exists(x509_base + ['ca-cert-file']):
    cert_file = config.return_value(x509_base + ['ca-cert-file'])
    cert_path = os.path.join(AUTH_DIR, cert_file)
    cert = None

    if os.path.isfile(cert_path):
        if not os.access(cert_path, os.R_OK):
            run(f'sudo chmod 644 {cert_path}')

        with open(cert_path, 'r') as f:
            cert_data = f.read()
            cert = load_certificate(cert_data, wrap_tags=False)

    if cert:
        cert_pem = encode_certificate(cert)
        config.set(pki_base + ['ca', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
        config.set(x509_base + ['ca-certificate'], value=pki_name)
    else:
        print(f'Failed to migrate CA certificate on l2tp remote-access config')

    config.delete(x509_base + ['ca-cert-file'])

if config.exists(x509_base + ['crl-file']):
    crl_file = config.return_value(x509_base + ['crl-file'])
    crl_path = os.path.join(AUTH_DIR, crl_file)
    crl = None

    if os.path.isfile(crl_path):
        if not os.access(crl_path, os.R_OK):
            run(f'sudo chmod 644 {crl_path}')

        with open(crl_path, 'r') as f:
            crl_data = f.read()
            crl = load_certificate(crl_data, wrap_tags=False)

    if crl:
        crl_pem = encode_certificate(crl)
        config.set(pki_base + ['ca', pki_name, 'crl'], value=wrapped_pem_to_config_value(crl_pem))
    else:
        print(f'Failed to migrate CRL on l2tp remote-access config')

    config.delete(x509_base + ['crl-file'])

if config.exists(x509_base + ['server-cert-file']):
    cert_file = config.return_value(x509_base + ['server-cert-file'])
    cert_path = os.path.join(AUTH_DIR, cert_file)
    cert = None

    if os.path.isfile(cert_path):
        if not os.access(cert_path, os.R_OK):
            run(f'sudo chmod 644 {cert_path}')

        with open(cert_path, 'r') as f:
            cert_data = f.read()
            cert = load_certificate(cert_data, wrap_tags=False)

    if cert:
        cert_pem = encode_certificate(cert)
        config.set(pki_base + ['certificate', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
        config.set(x509_base + ['certificate'], value=pki_name)
    else:
        print(f'Failed to migrate certificate on l2tp remote-access config')

    config.delete(x509_base + ['server-cert-file'])

if config.exists(x509_base + ['server-key-file']):
    key_file = config.return_value(x509_base + ['server-key-file'])
    key_passphrase = None

    if config.exists(x509_base + ['server-key-password']):
        key_passphrase = config.return_value(x509_base + ['server-key-password'])

    key_path = os.path.join(AUTH_DIR, key_file)
    key = None

    if os.path.isfile(key_path):
        if not os.access(key_path, os.R_OK):
            run(f'sudo chmod 644 {key_path}')

        with open(key_path, 'r') as f:
            key_data = f.read()
            key = load_private_key(key_data, passphrase=key_passphrase, wrap_tags=False)

    if key:
        key_pem = encode_private_key(key, passphrase=key_passphrase)
        config.set(pki_base + ['certificate', pki_name, 'private', 'key'], value=wrapped_pem_to_config_value(key_pem))

        if key_passphrase:
            config.set(pki_base + ['certificate', pki_name, 'private', 'password-protected'])
            config.set(x509_base + ['private-key-passphrase'], value=key_passphrase)
    else:
        print(f'Failed to migrate private key on l2tp remote-access config')

    config.delete(x509_base + ['server-key-file'])
    if config.exists(x509_base + ['server-key-password']):
        config.delete(x509_base + ['server-key-password'])

try:
    with open(file_name, 'w') as f:
        f.write(config.to_string())
except OSError as e:
    print("Failed to save the modified config: {}".format(e))
    exit(1)