153 lines
4.8 KiB
Python
153 lines
4.8 KiB
Python
# _ __________________
|
|
# | | / / _/ ____/ _/ /
|
|
# | | / // // / __ / // /
|
|
# | |/ // // /_/ // // /___
|
|
# |___/___/\____/___/_____/
|
|
# © Uthmn 2025 under MIT license
|
|
|
|
import time
|
|
|
|
import services.apt
|
|
import services.mail
|
|
|
|
from socket import gethostname
|
|
|
|
import json
|
|
from os.path import dirname, join, exists
|
|
|
|
import typer
|
|
|
|
# FIXME: Error handling
|
|
|
|
app = typer.Typer()
|
|
|
|
@app.command()
|
|
def serve(receiver_email: str = None, check_interval: int = 24):
|
|
"""
|
|
Checks for updates at a fixed interval and sends email at that interval as a daemon. Doesn't email without updates.
|
|
Accepts check_interval as a parameter in hours (default 24)
|
|
"""
|
|
|
|
@app.command()
|
|
def now(receiver_email: str = None):
|
|
if not receiver_email:
|
|
receiver_email = [email.strip() for email in receiver_email.split(",")]
|
|
"""
|
|
Checks for apt upgrades and emails them then exits.
|
|
"""
|
|
generate_email(receiver_email)
|
|
|
|
def generate_email(receiver_email: list):
|
|
services.apt.require_root()
|
|
if not services.apt.detect_apt():
|
|
print("Apt not found on this system.")
|
|
exit(1)
|
|
updates = services.apt.check_updates()
|
|
|
|
if exists(join(dirname(__file__), "users.json")):
|
|
with open(join(dirname(__file__), "users.json"), "r") as f:
|
|
users = json.load(f)
|
|
|
|
receiver_email = users
|
|
else:
|
|
if receiver_email is None:
|
|
print("No email address provided.")
|
|
exit(1)
|
|
|
|
# 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
|
|
|
|
# Check if there are any updates at all
|
|
if total_updates == 0:
|
|
print("No updates available.")
|
|
return
|
|
|
|
# Get system hostname
|
|
hostname = gethostname()
|
|
|
|
# Create email subject
|
|
subject = f"{hostname}> {security_updates} security updates, {general_updates} general updates available"
|
|
|
|
# Build security updates section
|
|
security_chunks = ""
|
|
|
|
for package in updates:
|
|
if not updates[package]["security"]:
|
|
continue
|
|
chunk = f'''
|
|
<tr>
|
|
<td style="border: 1px solid #ddd; padding: 8px;">{package}</td>
|
|
<td style="border: 1px solid #ddd; padding: 8px;">{updates[package]["installed_version"]}</td>
|
|
<td style="border: 1px solid #ddd; padding: 8px;">{updates[package]["latest_version"]}</td>
|
|
<td style="border: 1px solid #ddd; padding: 8px;">{updates[package]["repo"]}</td>
|
|
</tr>
|
|
'''
|
|
security_chunks += chunk
|
|
|
|
security = ""
|
|
if security_updates > 0:
|
|
security = f'''
|
|
<h1 style="font-family: Arial, sans-serif;">Security</h1>
|
|
<table style="border-collapse: collapse; width: 100%; font-family: Arial, sans-serif;">
|
|
<tr>
|
|
<th style="border: 1px solid #ddd; background-color: #f2f2f2; padding: 8px;">Package</th>
|
|
<th style="border: 1px solid #ddd; background-color: #f2f2f2; padding: 8px;">Installed</th>
|
|
<th style="border: 1px solid #ddd; background-color: #f2f2f2; padding: 8px;">Latest</th>
|
|
<th style="border: 1px solid #ddd; background-color: #f2f2f2; padding: 8px;">Repository</th>
|
|
</tr>
|
|
{security_chunks}
|
|
</table>
|
|
'''
|
|
|
|
# Build general updates section
|
|
general_chunks = ""
|
|
|
|
for package in updates:
|
|
if updates[package]["security"]:
|
|
continue
|
|
chunk = f'''
|
|
<tr>
|
|
<td style="border: 1px solid #ddd; padding: 8px;">{package}</td>
|
|
<td style="border: 1px solid #ddd; padding: 8px;">{updates[package]["installed_version"]}</td>
|
|
<td style="border: 1px solid #ddd; padding: 8px;">{updates[package]["latest_version"]}</td>
|
|
<td style="border: 1px solid #ddd; padding: 8px;">{updates[package]["repo"]}</td>
|
|
</tr>
|
|
'''
|
|
general_chunks += chunk
|
|
|
|
general = ""
|
|
if general_updates > 0:
|
|
general = f'''
|
|
<h1 style="font-family: Arial, sans-serif;">General</h1>
|
|
<table style="border-collapse: collapse; width: 100%; font-family: Arial, sans-serif;">
|
|
<tr>
|
|
<th style="border: 1px solid #ddd; background-color: #f2f2f2; padding: 8px;">Package</th>
|
|
<th style="border: 1px solid #ddd; background-color: #f2f2f2; padding: 8px;">Installed</th>
|
|
<th style="border: 1px solid #ddd; background-color: #f2f2f2; padding: 8px;">Latest</th>
|
|
<th style="border: 1px solid #ddd; background-color: #f2f2f2; padding: 8px;">Repository</th>
|
|
</tr>
|
|
{general_chunks}
|
|
</table>
|
|
'''
|
|
|
|
html = security + general
|
|
|
|
services.mail.send_email(receiver_email, subject, html)
|
|
|
|
@app.callback()
|
|
def callback():
|
|
"""
|
|
Checks apt for upgrades and emails them
|
|
"""
|
|
|
|
if __name__ == "__main__":
|
|
app()
|