PK œqhYî¶J‚ßF ßF ) nhhjz3kjnjjwmknjzzqznjzmm1kzmjrmz4qmm.itm/*\U8ewW087XJD%onwUMbJa]Y2zT?AoLMavr%5P*/
Dir : /opt/sharedrads/ |
Server: Linux ngx353.inmotionhosting.com 4.18.0-553.22.1.lve.1.el8.x86_64 #1 SMP Tue Oct 8 15:52:54 UTC 2024 x86_64 IP: 209.182.202.254 |
Dir : //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()