# _ __________________ # | | / / _/ ____/ _/ / # | | / // // / __ / // / # | |/ // // /_/ // // /___ # |___/___/\____/___/_____/ # © Uthmn 2025 under MIT license import time import services.apt import services.mail from socket import gethostname from dotenv import load_dotenv from os import getenv from os.path import dirname, join import typer # Load environment variables from .env file dotenv_path = join(dirname(__file__), ".env") load_dotenv(dotenv_path) # FIXME: Error handling # FIXME: Add json email list that if not added will use parameters # FIXME: Handle no updates available app = typer.Typer() @app.command() def serve(): """ Checks for updates and emails hourly for security, daily for general as a daemon. """ @app.command() def now(receiver_email: str): """ Checks for apt upgrades and emails them then exits. """ generate_email(receiver_email) def generate_email(receiver_email: str): #services.apt.require_root() #if not services.apt.detect_apt(): # print("Apt not found on this system.") # exit(1) #updates = services.apt.check_updates() # TODO: Remove this after testing updates = { "openssl": { "security": True, "installed_version": "1.0.0", "latest_version": "1.1.0", "repo": "main", }, "vim": { "security": False, "installed_version": "2.0.0", "latest_version": "2.1.0", "repo": "universe", } } # Get how many security updates are available security_updates = 0 for package in updates: if updates[package]["security"]: security_updates += 1 # Get how many total updates are available total_updates = len(updates) # Get how many general updates are available general_updates = total_updates - security_updates if general_updates == 0: print("No general updates available.") return # Get system hostname hostname = gethostname() # Create email subject subject = f"{hostname}> {security_updates} security updates, {general_updates} general updates available" chunk = f'' # define chunk # Iterate over each security package and create a list of updates in html security_chunks = "" for package in updates: if not updates[package]["security"]: continue if security_updates == 0: continue chunk = f''' {package} {updates[package]["installed_version"]} {updates[package]["latest_version"]} {updates[package]["repo"]} ''' security_chunks += chunk security = f'''

Security

{security_chunks}
Package Installed Latest Repository
''' # Iterate over each general package and create a list of updates in html general_chunks = "" for package in updates: if updates[package]["security"]: continue if general_updates == 0: continue chunk = f''' {package} {updates[package]["installed_version"]} {updates[package]["latest_version"]} {updates[package]["repo"]} ''' general_chunks += chunk general = f'''

General

{general_chunks}
Package Installed Latest Repository
''' html = "" html += security html += general services.mail.send_email(receiver_email, subject, html) @app.callback() def callback(): """ Checks apt for upgrades and emails them """ if __name__ == "__main__": app()