diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index bb45b66..0000000 Binary files a/.DS_Store and /dev/null differ diff --git a/app/main/utils.py b/app/main/utils.py index 81813ff..934e635 100644 --- a/app/main/utils.py +++ b/app/main/utils.py @@ -1,14 +1,18 @@ +import socket +import ssl import subprocess import os import traceback import requests -from flask import current_app, render_template +from flask import app, current_app, render_template from app.models import Posts, MeetingNotes, Monitor, News, EventPosts, Events, Users, Documents from app import db, mail from datetime import datetime from sqlalchemy.exc import SQLAlchemyError from app.constants import file_types from flask_mail import Message +import datetime + class VirusDetectedException(Exception): @@ -462,6 +466,31 @@ def send_website_down_email(id, msg.html = email mail.send(msg) +def get_certificate_expiry_date_time(url): + # Use requests to get the certificate + with requests.get(url, stream=True) as response: + cert = response.raw.connection.sock.getpeercert() + exp_date_text = cert['notAfter'] + # Parse the date with timezone information + expiry_date = datetime.datetime.strptime(exp_date_text, '%b %d %H:%M:%S %Y %Z') + # Assuming the certificate's time zone is UTC + expiry_date = expiry_date.replace(tzinfo=datetime.timezone.utc) + return expiry_date + +def is_certificate_expired(url): + try: + expiry_date = get_certificate_expiry_date_time(url) + # Get the current time in UTC + current_date = datetime.datetime.now(datetime.timezone.utc) + time_remaining = expiry_date - current_date + if time_remaining.days < 0: + return True, "Certificate has expired." + elif time_remaining.days < 7: + return False, f"Certificate is expiring soon: {time_remaining.days} days remaining." + else: + return False, f"Certificate is valid: {time_remaining.days} days remaining." + except Exception as e: + return True, f"Error checking certificate: {e}" def ping_website(monitor_info): """ diff --git a/app/main/views.py b/app/main/views.py index f1ed657..b020fa8 100644 --- a/app/main/views.py +++ b/app/main/views.py @@ -1,4 +1,6 @@ -from flask import render_template, redirect, url_for, session, request as flask_request, jsonify, current_app, flash, send_file, send_from_directory +import socket +import ssl +from flask import app, render_template, redirect, url_for, session, request as flask_request, jsonify, current_app, flash, send_file, send_from_directory from flask_login import login_required, current_user from app.models import Users, Posts, EventPosts, Documents, Monitor from . import main @@ -10,7 +12,7 @@ get_rooms_by_division, create_document, allowed_file, - VirusDetectedException, + VirusDetectedException, is_certificate_expired, scan_file, process_documents_search, process_posts_search, @@ -37,6 +39,7 @@ def index(): Queries for the next 4 events from today forward to display in the Calendar section :return: HTML template for home page """ + posts = Posts.query.filter_by(deleted=False).order_by(Posts.date_created.desc()).limit(20).all() events = EventPosts.query.filter(Posts.deleted == False, EventPosts.event_date >= datetime.utcnow()).order_by( EventPosts.event_date.asc()).limit(4).all() @@ -856,4 +859,4 @@ def monitor(): websites = Monitor.query.order_by(Monitor.id.asc()).all() return render_template('monitor.html', websites=websites, - site_refresh_rate=current_app.config['FRONTEND_REFRESH_RATE']) + site_refresh_rate=current_app.config['FRONTEND_REFRESH_RATE']) diff --git a/app/models.py b/app/models.py index f5a3218..e26c356 100644 --- a/app/models.py +++ b/app/models.py @@ -667,3 +667,4 @@ class Monitor(db.Model): last_success_timestamp = db.Column(db.DateTime) response_header = db.Column(db.String) use_ssl = db.Column(db.Boolean) + expiration_date = db.Column(db.Date) diff --git a/app/static/js/monitor.js b/app/static/js/monitor.js index d97e428..a7f33f3 100644 --- a/app/static/js/monitor.js +++ b/app/static/js/monitor.js @@ -20,6 +20,8 @@ function WebsiteMonitorFunction () { $('#website-' + websiteID + '-check').show(); $('#website-' + websiteID + '-warning').hide(); $('#website-' + websiteID + '-x').hide(); + + } else { tableRow.removeClass('warning'); tableRow.removeClass('success'); @@ -35,7 +37,14 @@ function WebsiteMonitorFunction () { $('#website-' + websiteID + '-time-2').html(data['most_recent_success']); $('#website-' + websiteID + '-status-code').html(data['status_code']); $('#modalBody-' + websiteID).html(data['reason']); + + if (data['is_expired']) { + $('#website-' + websiteID + '-expiration-status').html('Expired'); + } else { + $('#website-' + websiteID + '-expiration-status').html('Valid'); + } }, + error: function (data) { tableRow.removeClass('danger'); tableRow.removeClass('success'); diff --git a/app/templates/email/monitor_email_alert.html b/app/templates/email/monitor_email_alert.html index 2657128..b002626 100644 --- a/app/templates/email/monitor_email_alert.html +++ b/app/templates/email/monitor_email_alert.html @@ -34,5 +34,13 @@ Use SSL? {{ use_ssl }} + + Expiration Date + {{ expiration_date }} + + + Certificate Expired? + {{ 'Yes' if is_expired else 'No' }} + {% endblock %} \ No newline at end of file diff --git a/app/templates/monitor.html b/app/templates/monitor.html index 6489164..64c92a0 100644 --- a/app/templates/monitor.html +++ b/app/templates/monitor.html @@ -28,6 +28,7 @@

Website Monitor

Current Timestamp Most Recent Success Status Code + Certificate Expired @@ -66,6 +67,10 @@

+ + +

+ {% endfor %} diff --git a/intranet.py b/intranet.py index 1d533af..5002bd1 100755 --- a/intranet.py +++ b/intranet.py @@ -1,7 +1,9 @@ #!/usr/bin/env python +from datetime import datetime import os from flask_migrate import Migrate from flask.cli import main +import requests from app import create_app, db from app.models import Documents, EventPosts, Events, MeetingNotes, Monitor, News, Posts, Roles, Users @@ -81,13 +83,53 @@ def ping(): ping_website(monitor) -@app.cli.command() -def test(): - """Run the unit tests.""" - import unittest - tests = unittest.TestLoader().discover('tests') - unittest.TextTestRunner(verbosity=2).run(tests) - -if __name__ == '__main__': - main() +@app.cli.command('check_certificate') +def check_certificate(): + monitors = Monitor.query.all() + + for monitor in monitors: + print(f"Checking URL: {monitor.url}") + print() + + try: + with requests.get(monitor.url, stream=True) as response: + # Check if the response was successful + if response.status_code == 200: + cert = response.raw.connection.sock.getpeercert() + + if cert: # Ensure cert is not None + expiration_date_str = cert['notAfter'] + print(f"Certificate found. Expiration Date: {expiration_date_str}") + print() + + # Convert expiration date string into a datetime object + expiration_date = datetime.strptime(expiration_date_str, "%b %d %H:%M:%S %Y %Z") + monitor.expiration_date = expiration_date.date() + print(f"Parsed expiration date: {expiration_date}") + print() + + # Determine if the certificate is expired + today = datetime.now() + is_expired = expiration_date <= today + monitor.is_expired = is_expired + print(f"Set is_expired to: {is_expired} for {monitor.url}") + else: + print("No certificate found.") + monitor.expiration_date = None + print() + else: + print(f"Failed to retrieve {monitor.url}. Status code: {response.status_code}") + monitor.expiration_date = None + print() + except Exception as e: + print(f"Error while checking {monitor.url}: {e}") + monitor.is_expired = False + monitor.expiration_date = None + print("Set is_expired to False and expiration_date to None due to exception.") + print() + + # Commit changes to the database + db.session.commit() + print(f"Committed: is_expired={monitor.is_expired}, expiration_date={monitor.expiration_date} for {monitor.url}") + print() \ No newline at end of file diff --git a/migrations/versions/044e18572cbe_added_monitor_table.py b/migrations/versions/044e18572cbe_added_monitor_table.py index 53118e8..defda35 100644 --- a/migrations/versions/044e18572cbe_added_monitor_table.py +++ b/migrations/versions/044e18572cbe_added_monitor_table.py @@ -27,6 +27,7 @@ def upgrade(): sa.Column('last_success_timestamp', sa.DateTime(), nullable=True), sa.Column('response_header', sa.String(), nullable=True), sa.Column('use_ssl', sa.Boolean(), nullable=False), + sa.Column('expiration_date', sa.Date(), nullable=True), sa.PrimaryKeyConstraint('id') ) # ### end Alembic commands ###