#!/usr/bin/env python3
#
# Copyright (C) 2019 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/>.
#
#

import sys
import os
import subprocess

import vyos.defaults
from vyos.config import Config
from vyos import ConfigError

vyos_conf_scripts_dir = vyos.defaults.directories['conf_mode']

dependencies = [
    'https.py',
]

def request_certbot(cert):
    email = cert.get('email')
    if email is not None:
        email_flag = '-m {0}'.format(email)
    else:
        email_flag = ''

    domains = cert.get('domains')
    if domains is not None:
        domain_flag = '-d ' + ' -d '.join(domains)
    else:
        domain_flag = ''

    certbot_cmd = 'certbot certonly -n --nginx --agree-tos --no-eff-email --expand {0} {1}'.format(email_flag, domain_flag)

    completed = subprocess.run(certbot_cmd, shell=True)

    return completed.returncode

def get_config():
    conf = Config()
    if not conf.exists('service https certificates certbot'):
        return None
    else:
        conf.set_level('service https certificates certbot')

    cert = {}

    if conf.exists('domain-name'):
        cert['domains'] = conf.return_values('domain-name')

    if conf.exists('email'):
        cert['email'] = conf.return_value('email')

    return cert

def verify(cert):
    if cert is None:
        return None

    if 'domains' not in cert:
        raise ConfigError("At least one domain name is required to"
                          " request a letsencrypt certificate.")

    if 'email' not in cert:
        raise ConfigError("An email address is required to request"
                          " a letsencrypt certificate.")

def generate(cert):
    if cert is None:
        return None

    # certbot will attempt to reload nginx, even with 'certonly';
    # start nginx if not active
    ret = os.system('systemctl is-active --quiet nginx.ervice')
    if ret:
        os.system('sudo systemctl start nginx.service')

    ret = request_certbot(cert)
    if ret:
        raise ConfigError("The certbot request failed for the"
                          " specified domains.")

def apply(cert):
    if cert is not None:
        os.system('sudo systemctl restart certbot.timer')
    else:
        os.system('sudo systemctl stop certbot.timer')
        return None

    for dep in dependencies:
        cmd = '{0}/{1}'.format(vyos_conf_scripts_dir, dep)
        try:
            subprocess.check_call(cmd, shell=True)
        except subprocess.CalledProcessError as err:
            raise ConfigError(str(err))

if __name__ == '__main__':
    try:
        c = get_config()
        verify(c)
        generate(c)
        apply(c)
    except ConfigError as e:
        print(e)
        sys.exit(1)