Mini Shell

Direktori : /opt/sharedrads/
Upload File :
Current File : //opt/sharedrads/check_autossl

#!/opt/imh-python/bin/python3
# pylint: disable=F0401
"""Checks for failed AutoSSL renewals"""
import sys
import datetime
import time
import argparse
import socket
import logging
import os
from pathlib import Path
import json
import pp_api
from cpapis import whmapi1, CpAPIError


class NotificationFile:
    """Provides simple interface for updating users notification file"""

    def __init__(self, user):
        """NotificationFile constructor"""
        self.user = user
        self.filepath = Path('/home', user, '.imh/autossl_notified')
        self.filepath.parent.mkdir(mode=0o755, parents=True, exist_ok=True)
        if not self.filepath.is_file():
            self.filepath.write_bytes(b'{}')

    def read(self) -> dict:
        """Read notification file and return JSON representation"""
        try:
            with open(self.filepath, encoding='ascii') as handle:
                return json.load(handle)
        except ValueError:  # did not read valid json, start fresh
            return {}

    def write(self, domains: dict):
        """Write dict domains to notification file"""
        with open(self.filepath, 'w', encoding='ascii') as handle:
            json.dump(domains, handle)


def email_cx(user, domains):
    """Email user the list of domains using PP API
    domains (dict): [expiration_status][domain] = expiration timestamp"""

    loguser = {'current_user': user}

    pp_connect = pp_api.PowerPanel()
    if 'webhostinghub' in socket.gethostname():
        template_id = 710
    else:
        template_id = 709

    for expstatus in domains:
        variable_text = ""
        if len(domains[expstatus]) == 0:
            logger.debug(
                "No %s notifications, skipping", expstatus, extra=loguser
            )
            continue
        for domain in domains[expstatus]:
            human_expiration = datetime.datetime.fromtimestamp(
                domains[expstatus][domain]
            ).strftime('%m-%d-%Y')
            variable_text += "Domain: {} - Expiration: {}, ".format(
                domain, human_expiration
            )

        # verbiage by CE
        if expstatus == 'expiring':
            exp_verbiage = 'expire'
        else:
            exp_verbiage = 'remain expired'
        results = pp_connect.call(
            "notification.send",
            template=template_id,
            cpanelUser=user,
            variable_1=variable_text,
            variable_2=exp_verbiage,
        )

        if results.status != 0:
            logger.warning(
                "Failed to send notification: %s",
                results.message,
                extra=loguser,
            )
        else:
            logger.info("Notification for %s sent", expstatus, extra=loguser)

    try:
        notification_file = NotificationFile(user)
        user_notifications = notification_file.read()

        for expstatus in domains:
            for domain in domains[expstatus]:
                user_notifications[domain] = domains[expstatus][domain]
        notification_file.write(user_notifications)
    except Exception:
        logger.warning("Unable to record notification!", extra=loguser)


def main():
    """Main logic"""
    parser = argparse.ArgumentParser(description='AutoSSL monitor')
    parser.add_argument('--noop', action='store_true', default=False)
    args = parser.parse_args()

    loguser = {'current_user': 'MAIN'}

    try:
        result = whmapi1('fetch_ssl_vhosts', check=True)
    except CpAPIError as exc:
        logger.debug(exc)
        logger.error("Unable to fetch installed SSLs!")
        sys.exit(1)

    notifications = {}

    for vhost in result['data']['vhosts']:
        is_autossl = False
        if vhost['crt']['issuer.organizationName'] == "cPanel, Inc.":
            is_autossl = True
        # if vhost['crt']['issuer.organizationName'] == "Let's Encrypt":
        #    is_autossl = True

        if not is_autossl:
            continue  # skip vhost if its not autossl issued

        owner = vhost['user']
        domain = vhost['crt']['subject.commonName']['commonName']
        expire = int(vhost['crt']['not_after'])

        # DEBUG
        # owner = 'josephmteer333'
        # expire = 1499988912  #expired
        # expire = 1501113600 #will expire

        loguser = {'current_user': owner}

        if (expire - int(time.time())) > 432000:  # not expiring in 5 days
            continue

        if (expire - int(time.time())) < 0:
            expiration_status = 'expired'
        else:
            expiration_status = 'expiring'

        notification_file = NotificationFile(owner)
        notified_list = notification_file.read()

        # check autossl feature status
        try:
            whmapi1(
                'get_users_features_settings',
                {'user': owner, 'feature': 'autossl'},
                check=True,
            )
        except CpAPIError as exc:
            logger.debug(exc)
            logger.warning(
                "Unable to fetch AutoSSL status! Ignoring...", extra=loguser
            )
            continue
        feature_settings = result['data']['users_features_settings'][0]

        if feature_settings['cpuser_setting']:  # returned None = no override
            if int(feature_settings['cpuser_setting']) == 1:
                # AutoSSL enabled via override
                logger.debug("AutoSSL enabled via override", extra=loguser)
            else:
                logger.info("AutoSSL disabled via override", extra=loguser)
                continue
        elif int(feature_settings['feature_list_setting']) == 1:
            # AutoSSL enabled via featurelist
            logger.debug("AutoSSL enabled via featurelist", extra=loguser)
        else:
            logger.info("AutoSSL not enabled! Skipping...", extra=loguser)
            continue

        human_expiration = datetime.datetime.fromtimestamp(expire).strftime(
            '%m-%d-%Y'
        )

        logger.info(
            "Expiring - Domain: %s Expiration: %s",
            domain,
            human_expiration,
            extra=loguser,
        )

        # domain is expired or expiring at this point, notify accordingly

        if owner not in notifications:
            # create user in dict if not already there
            notifications[owner] = {}
            notifications[owner]['expiring'] = {}
            notifications[owner]['expired'] = {}

        if (domain in notified_list) and (expire == notified_list[domain]):
            # already notified
            logger.debug("Already notified about %s", domain, extra=loguser)
            continue
        notifications[owner][expiration_status][domain] = expire

    if not args.noop:
        for user, domains in notifications.items():
            email_cx(user, domains)


if __name__ == "__main__":

    if os.getuid() != 0:
        sys.exit("This tool must be run as root. Exiting...")

    logformat = logging.Formatter('%(asctime)s [%(current_user)s]: %(message)s')

    logger = logging.getLogger('autossl_check')
    logger.setLevel(logging.DEBUG)

    console = logging.StreamHandler()
    console.setLevel(logging.INFO)
    console.setFormatter(logformat)
    logger.addHandler(console)

    mainlog = logging.FileHandler('/var/log/autossl_check.log')
    mainlog.setLevel(logging.DEBUG)
    mainlog.setFormatter(logformat)
    logger.addHandler(mainlog)

    main()

Zerion Mini Shell 1.0