Fully Working
parent
431bde4e44
commit
58496200ca
33
app.py
33
app.py
|
|
@ -1,33 +0,0 @@
|
|||
from flask import Flask, render_template, request, redirect, url_for
|
||||
import whois
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
# In-memory list to store domain info. In production, you’d use a database.
|
||||
domains = []
|
||||
|
||||
@app.route('/')
|
||||
def home():
|
||||
return render_template('home.html', domains=domains)
|
||||
|
||||
@app.route('/add', methods=['GET', 'POST'])
|
||||
def add_domain():
|
||||
if request.method == 'POST':
|
||||
# Get a list of domains from the form (one or multiple)
|
||||
domain_list = request.form.getlist('domain')
|
||||
for domain in domain_list:
|
||||
if domain.strip(): # ignore empty strings
|
||||
try:
|
||||
w = whois.whois(domain)
|
||||
# Some WHOIS responses return a list of dates.
|
||||
exp_date = w.expiration_date
|
||||
if isinstance(exp_date, list):
|
||||
exp_date = exp_date[0]
|
||||
except Exception as e:
|
||||
exp_date = f"Error: {e}"
|
||||
domains.append({'domain': domain, 'expiration_date': exp_date})
|
||||
return redirect(url_for('home'))
|
||||
return render_template('add_domain.html')
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(host='0.0.0.0', port=5050, debug=True)
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
import os
|
||||
from flask import Flask
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
|
||||
db = SQLAlchemy()
|
||||
|
||||
def create_app():
|
||||
# Create the Flask app and set the template folder (located in app/templates)
|
||||
app = Flask(__name__, template_folder='templates')
|
||||
|
||||
# Configure the SQLite database
|
||||
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(os.path.abspath(os.path.dirname(__file__)), 'domains.db')
|
||||
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
|
||||
|
||||
# Initialize SQLAlchemy with the app
|
||||
db.init_app(app)
|
||||
|
||||
with app.app_context():
|
||||
# Import models so that they are registered with SQLAlchemy before creating tables
|
||||
from app import models
|
||||
db.create_all()
|
||||
|
||||
# Register blueprints
|
||||
from app.routes.domain import domain_bp
|
||||
app.register_blueprint(domain_bp)
|
||||
|
||||
from app.routes.ssl import ssl_bp
|
||||
app.register_blueprint(ssl_bp)
|
||||
|
||||
return app
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
from app import db
|
||||
|
||||
class Domain(db.Model):
|
||||
__tablename__ = 'domain'
|
||||
__table_args__ = {'extend_existing': True}
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
domain = db.Column(db.String(255), unique=True, nullable=False)
|
||||
expiration_date = db.Column(db.String(255)) # WHOIS expiration date
|
||||
ssl_expiration_date = db.Column(db.String(255)) # SSL certificate expiration date
|
||||
ssl_only = db.Column(db.Boolean, default=False) # True if added via the SSL-only form
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Domain {self.domain} | Whois: {self.expiration_date} | SSL: {self.ssl_expiration_date} | ssl_only: {self.ssl_only}>"
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
from flask import Blueprint, render_template, request, redirect, url_for
|
||||
import whois
|
||||
from app.models import Domain
|
||||
from app import db
|
||||
from app.utils import get_ssl_expiration
|
||||
|
||||
domain_bp = Blueprint('domain', __name__)
|
||||
|
||||
@domain_bp.route('/')
|
||||
def home():
|
||||
return render_template('home.html')
|
||||
|
||||
@domain_bp.route('/domains')
|
||||
def domains():
|
||||
# Show only non-ssl_only domains on the normal Domains page.
|
||||
domains_list = Domain.query.filter_by(ssl_only=False).all()
|
||||
return render_template('domains.html', domains=domains_list)
|
||||
|
||||
@domain_bp.route('/add', methods=['GET', 'POST'])
|
||||
def add_domain():
|
||||
if request.method == 'POST':
|
||||
domain_list = request.form.getlist('domain')
|
||||
for domain_name in domain_list:
|
||||
if domain_name.strip():
|
||||
# Perform WHOIS lookup
|
||||
try:
|
||||
w = whois.whois(domain_name)
|
||||
exp_date = w.expiration_date
|
||||
if isinstance(exp_date, list):
|
||||
exp_date = exp_date[0]
|
||||
if exp_date and hasattr(exp_date, "strftime"):
|
||||
whois_exp_date_str = exp_date.strftime("%m/%d/%Y")
|
||||
else:
|
||||
whois_exp_date_str = str(exp_date)
|
||||
except Exception as e:
|
||||
whois_exp_date_str = f"Error: {e}"
|
||||
|
||||
# Perform SSL lookup using our utility function
|
||||
ssl_exp_date_str = get_ssl_expiration(domain_name)
|
||||
|
||||
# Only add if not already present.
|
||||
if not Domain.query.filter_by(domain=domain_name).first():
|
||||
new_domain = Domain(
|
||||
domain=domain_name,
|
||||
expiration_date=whois_exp_date_str,
|
||||
ssl_expiration_date=ssl_exp_date_str,
|
||||
ssl_only=False
|
||||
)
|
||||
db.session.add(new_domain)
|
||||
db.session.commit()
|
||||
return redirect(url_for('domain.domains'))
|
||||
return render_template('add_domain.html')
|
||||
|
||||
@domain_bp.route('/delete/<int:domain_id>', methods=['GET'])
|
||||
def delete_domain(domain_id):
|
||||
domain_to_delete = Domain.query.get_or_404(domain_id)
|
||||
db.session.delete(domain_to_delete)
|
||||
db.session.commit()
|
||||
# Redirect back to the Domains page (or SSL page if needed)
|
||||
return redirect(url_for('domain.domains'))
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
from flask import Blueprint, render_template, request, redirect, url_for
|
||||
from app.models import Domain
|
||||
from app import db
|
||||
from app.utils import get_ssl_expiration
|
||||
|
||||
ssl_bp = Blueprint('ssl', __name__)
|
||||
|
||||
@ssl_bp.route('/ssl')
|
||||
def ssl_page():
|
||||
# Get all domains (both normal and ssl_only)
|
||||
domains = Domain.query.all()
|
||||
# Update each domain's SSL expiration (optional, to refresh if needed)
|
||||
for d in domains:
|
||||
current_ssl_exp = get_ssl_expiration(d.domain)
|
||||
if d.ssl_expiration_date != current_ssl_exp:
|
||||
d.ssl_expiration_date = current_ssl_exp
|
||||
db.session.commit()
|
||||
return render_template('ssl.html', domains=domains)
|
||||
|
||||
@ssl_bp.route('/ssl/add', methods=['GET', 'POST'])
|
||||
def add_ssl_domain():
|
||||
if request.method == 'POST':
|
||||
domain_list = request.form.getlist('domain')
|
||||
for domain_name in domain_list:
|
||||
if domain_name.strip():
|
||||
# Both lookups are performed when adding an SSL-only domain.
|
||||
try:
|
||||
w = whois.whois(domain_name)
|
||||
exp_date = w.expiration_date
|
||||
if isinstance(exp_date, list):
|
||||
exp_date = exp_date[0]
|
||||
if exp_date and hasattr(exp_date, "strftime"):
|
||||
whois_exp_date_str = exp_date.strftime("%m/%d/%Y")
|
||||
else:
|
||||
whois_exp_date_str = str(exp_date)
|
||||
except Exception as e:
|
||||
whois_exp_date_str = f"Error: {e}"
|
||||
|
||||
ssl_exp_date_str = get_ssl_expiration(domain_name)
|
||||
|
||||
if not Domain.query.filter_by(domain=domain_name).first():
|
||||
new_domain = Domain(
|
||||
domain=domain_name,
|
||||
expiration_date=whois_exp_date_str,
|
||||
ssl_expiration_date=ssl_exp_date_str,
|
||||
ssl_only=True
|
||||
)
|
||||
db.session.add(new_domain)
|
||||
db.session.commit()
|
||||
return redirect(url_for('ssl.ssl_page'))
|
||||
return render_template('add_ssl_domain.html')
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
{% extends "base.html" %}
|
||||
{% block title %}Add Domain{% endblock %}
|
||||
{% block content %}
|
||||
<h1>Add Domain(s)</h1>
|
||||
<form method="post">
|
||||
<div id="domainFields">
|
||||
<input type="text" name="domain" placeholder="Enter domain name">
|
||||
</div>
|
||||
<br>
|
||||
<button type="button" onclick="addField()">Add Another</button>
|
||||
<br><br>
|
||||
<input type="submit" value="Save">
|
||||
</form>
|
||||
<br>
|
||||
<a href="{{ url_for('domain.domains') }}">Back to Domains</a>
|
||||
<script>
|
||||
function addField() {
|
||||
var container = document.getElementById("domainFields");
|
||||
var input = document.createElement("input");
|
||||
input.type = "text";
|
||||
input.name = "domain";
|
||||
input.placeholder = "Enter domain name";
|
||||
container.appendChild(document.createElement("br"));
|
||||
container.appendChild(input);
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
{% extends "base.html" %}
|
||||
{% block title %}Add SSL Domain{% endblock %}
|
||||
{% block content %}
|
||||
<h1>Add SSL Domain(s)</h1>
|
||||
<form method="post">
|
||||
<div id="domainFields">
|
||||
<input type="text" name="domain" placeholder="Enter domain name">
|
||||
</div>
|
||||
<br>
|
||||
<button type="button" onclick="addField()">Add Another</button>
|
||||
<br><br>
|
||||
<input type="submit" value="Save">
|
||||
</form>
|
||||
<br>
|
||||
<a href="{{ url_for('ssl.ssl_page') }}">Back to SSL Page</a>
|
||||
<script>
|
||||
function addField() {
|
||||
var container = document.getElementById("domainFields");
|
||||
var input = document.createElement("input");
|
||||
input.type = "text";
|
||||
input.name = "domain";
|
||||
input.placeholder = "Enter domain name";
|
||||
container.appendChild(document.createElement("br"));
|
||||
container.appendChild(input);
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>{% block title %}My Domain App{% endblock %}</title>
|
||||
<style>
|
||||
nav {
|
||||
background-color: #eee;
|
||||
padding: 10px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
nav a {
|
||||
margin-right: 15px;
|
||||
text-decoration: none;
|
||||
color: #333;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<nav>
|
||||
<a href="{{ url_for('domain.home') }}">Home</a>
|
||||
<a href="{{ url_for('domain.domains') }}">Domains</a>
|
||||
<a href="{{ url_for('ssl.ssl_page') }}">SSL</a>
|
||||
</nav>
|
||||
{% block content %}{% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
{% extends "base.html" %}
|
||||
{% block title %}Domains{% endblock %}
|
||||
{% block content %}
|
||||
<h1>Domains List</h1>
|
||||
<table border="1" cellpadding="5" cellspacing="0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Domain</th>
|
||||
<th>Expiration Date</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for domain in domains %}
|
||||
<tr>
|
||||
<td>{{ domain.domain }}</td>
|
||||
<td>{{ domain.expiration_date }}</td>
|
||||
<td>
|
||||
<a href="{{ url_for('domain.delete_domain', domain_id=domain.id) }}" onclick="return confirm('Are you sure you want to delete this domain?');">X</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<br>
|
||||
<button onclick="window.location.href='{{ url_for('domain.add_domain') }}'">Add Domain</button>
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
{% extends "base.html" %}
|
||||
{% block title %}Home{% endblock %}
|
||||
{% block content %}
|
||||
<h1>Welcome to the Domain App</h1>
|
||||
<p>Use the navigation bar to view your domains or add new ones.</p>
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
{% extends "base.html" %}
|
||||
{% block title %}SSL Certificates{% endblock %}
|
||||
{% block content %}
|
||||
<h1>SSL Certificates</h1>
|
||||
<table border="1" cellpadding="5" cellspacing="0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Domain</th>
|
||||
<th>SSL Expiration</th>
|
||||
<th>Type</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for d in domains %}
|
||||
<tr>
|
||||
<td>{{ d.domain }}</td>
|
||||
<td>{{ d.ssl_expiration_date }}</td>
|
||||
<td>
|
||||
{% if d.ssl_only %}
|
||||
Email
|
||||
{% else %}
|
||||
Domain
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{ url_for('domain.delete_domain', domain_id=d.id) }}" onclick="return confirm('Are you sure you want to delete this domain?');">X</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<br>
|
||||
<button onclick="window.location.href='{{ url_for('ssl.add_ssl_domain') }}'">Add SSL Domain</button>
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
import socket, ssl, datetime
|
||||
|
||||
def get_ssl_expiration(domain, port=443):
|
||||
try:
|
||||
ctx = ssl.create_default_context()
|
||||
with socket.create_connection((domain, port), timeout=5) as sock:
|
||||
with ctx.wrap_socket(sock, server_hostname=domain) as ssock:
|
||||
cert = ssock.getpeercert()
|
||||
notAfter = cert.get('notAfter')
|
||||
if notAfter:
|
||||
# Example certificate expiry format: "Jun 1 12:00:00 2025 GMT"
|
||||
exp_date = datetime.datetime.strptime(notAfter, '%b %d %H:%M:%S %Y %Z')
|
||||
return exp_date.strftime("%m/%d/%Y")
|
||||
return "NO SSL"
|
||||
except Exception:
|
||||
return "NO SSL"
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
from app import create_app
|
||||
|
||||
app = create_app()
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(host='0.0.0.0', port=5050, debug=True)
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Add Domain</title>
|
||||
<script>
|
||||
function addField() {
|
||||
var container = document.getElementById("domainFields");
|
||||
var input = document.createElement("input");
|
||||
input.type = "text";
|
||||
input.name = "domain";
|
||||
input.placeholder = "Enter domain name";
|
||||
// Create a line break for spacing
|
||||
container.appendChild(document.createElement("br"));
|
||||
container.appendChild(input);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Add Domain(s)</h1>
|
||||
<form method="post">
|
||||
<div id="domainFields">
|
||||
<input type="text" name="domain" placeholder="Enter domain name">
|
||||
</div>
|
||||
<br>
|
||||
<button type="button" onclick="addField()">Add Another</button>
|
||||
<br><br>
|
||||
<input type="submit" value="Save">
|
||||
</form>
|
||||
<br>
|
||||
<a href="{{ url_for('home') }}">Back to Home</a>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Domain List</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Domain List</h1>
|
||||
<table border="1" cellpadding="5" cellspacing="0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Domain</th>
|
||||
<th>Expiration Date</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for domain in domains %}
|
||||
<tr>
|
||||
<td>{{ domain.domain }}</td>
|
||||
<td>{{ domain.expiration_date }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<br>
|
||||
<a href="{{ url_for('add_domain') }}">Add Domain</a>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Reference in New Issue