From cb22c6b6ba10b6672f50ff966afb12817b01a517 Mon Sep 17 00:00:00 2001 From: Uthman Fatih Date: Sun, 12 Oct 2025 19:50:33 +0100 Subject: [PATCH] Added apt support and began work on mail support. --- README.md | 1 - main.py | 6 ++++ requirements.txt | 2 ++ services/apt.py | 76 ++++++++++++++++++++++++++++++++++++++++++++++++ services/mail.py | 40 +++++++++++++++++++++++++ 5 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 main.py create mode 100644 requirements.txt create mode 100644 services/apt.py create mode 100644 services/mail.py diff --git a/README.md b/README.md index 064e85c..7c77b3e 100644 --- a/README.md +++ b/README.md @@ -1,2 +1 @@ # vigil - diff --git a/main.py b/main.py new file mode 100644 index 0000000..a5b1634 --- /dev/null +++ b/main.py @@ -0,0 +1,6 @@ +# _ __________________ +# | | / / _/ ____/ _/ / +# | | / // // / __ / // / +# | |/ // // /_/ // // /___ +# |___/___/\____/___/_____/ +# © Uthmn 2025 under MIT license \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e95d364 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +dotenv==0.9.9 +python-dotenv==1.1.1 diff --git a/services/apt.py b/services/apt.py new file mode 100644 index 0000000..775c6db --- /dev/null +++ b/services/apt.py @@ -0,0 +1,76 @@ +# _ __________________ +# | | / / _/ ____/ _/ / +# | | / // // / __ / // / +# | |/ // // /_/ // // /___ +# |___/___/\____/___/_____/ +# © Uthmn 2025 under MIT license + +import subprocess +import os +import sys +import re + +def require_root(): + if os.geteuid() != 0: + print("This script requires root privileges. Please run with sudo.") + sys.exit(1) + +def detect_apt(): + try: + subprocess.run(["apt", "--version"], capture_output=True, text=True, check=True) + return True + except FileNotFoundError: + return False + except subprocess.CalledProcessError as e: + raise RuntimeError(f"Error running apt: {e.stderr or e}") + +def check_updates(): + # Update package list + try: + subprocess.run(["apt", "update"], capture_output=True, text=True, check=True) + except FileNotFoundError: + raise FileNotFoundError("apt not found on this system.") + except subprocess.CalledProcessError as e: + raise RuntimeError(f"Error running 'apt update': {e.stderr or e.stdout or e}") + + # List upgradable packages + try: + result = subprocess.run( + ["apt", "list", "--upgradable"], + capture_output=True, + text=True, + check=True + ) + upgrades = result.stdout.strip() + lines = [line for line in upgrades.splitlines() if line.strip()] + + if len(lines) <= 1: # Only the header + return {} # No upgrades + + package_dict = {} + for line in lines[1:]: # skip header + # Example line format: + # docker-ce/focal-security 5:24.0.1~3-0~ubuntu-focal amd64 [upgradable from: 5:23.0.0~3-0~ubuntu-focal] + match = re.match( + r"([^/]+)/([^\s]+)\s+([^\s]+)\s+[^\s]+\s+\[upgradable from: ([^\]]+)\]", line + ) + if match: + name, repo, latest_version, installed_version = match.groups() + # Detect security update based on repo name containing "security" + is_security = "security" in repo.lower() + package_dict[name] = { + "installed_version": installed_version, + "latest_version": latest_version, + "repo": repo, + "security": is_security + } + return package_dict + + except subprocess.CalledProcessError as e: + raise RuntimeError(f"Error running 'apt list --upgradable': {e.stderr or e.stdout or e}") + +if __name__ == "__main__": + require_root() + if detect_apt(): + updates = check_updates() + print(updates) diff --git a/services/mail.py b/services/mail.py new file mode 100644 index 0000000..1285303 --- /dev/null +++ b/services/mail.py @@ -0,0 +1,40 @@ +# _ __________________ +# | | / / _/ ____/ _/ / +# | | / // // / __ / // / +# | |/ // // /_/ // // /___ +# |___/___/\____/___/_____/ +# © Uthmn 2025 under MIT license + +import smtplib +from email.mime.text import MIMEText +from dotenv import load_dotenv +from os import getenv +from os.path import dirname, join + +# Load environment variables from .env file +dotenv_path = join(dirname(__file__), "../.env") +load_dotenv(dotenv_path) + +# SMTP server settings +SMTP_SERVER = getenv("SMTP_SERVER") +SMTP_PORT = int(getenv("SMTP_PORT")) +SMTP_USERNAME = getenv("SMTP_USERNAME") +SMTP_PASSWORD = getenv("SMTP_PASSWORD") + +def send_email(receiver_email, subject, body): + sender_email = SMTP_USERNAME + + # Create the email + message = MIMEText(body, "html") + message["Subject"] = subject + message["From"] = sender_email + message["To"] = receiver_email + + # Connect using SSL + try: + with smtplib.SMTP_SSL(SMTP_SERVER, SMTP_PORT) as server: + server.login(SMTP_USERNAME, SMTP_PASSWORD) + server.sendmail(sender_email, receiver_email, message.as_string()) + print("HTML email sent successfully!") + except Exception as e: + print(f"Failed to send email: {e}")