added better url fixes

This commit is contained in:
2025-02-17 15:41:48 -05:00
parent f988ddc489
commit 8b53ceb12d
2 changed files with 264 additions and 242 deletions
+47 -24
View File
@@ -8,7 +8,7 @@ from flask import (
flash, flash,
abort, abort,
jsonify, jsonify,
session session,
) )
from flask_sqlalchemy import SQLAlchemy from flask_sqlalchemy import SQLAlchemy
from flask_login import ( from flask_login import (
@@ -47,7 +47,7 @@ PORT = 5121
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:////app/instance/db.sqlite" app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:////app/instance/db.sqlite"
app.config["UPLOAD_FOLDER"] = "sites" app.config["UPLOAD_FOLDER"] = "sites"
app.config["SERVER_NAME"] = "tinysite.cloud" app.config["SERVER_NAME"] = "tinysite.cloud"
# app.config["SESSION_COOKIE_DOMAIN"] = ".tinysite.cloud" app.config["SESSION_COOKIE_DOMAIN"] = ".tinysite.cloud"
db = SQLAlchemy(app) db = SQLAlchemy(app)
@@ -72,11 +72,26 @@ RESERVED_SUBDOMAINS = {
# TODO: add specific page redirects here as they're added # TODO: add specific page redirects here as they're added
def isDefaultRoute(hostname: str): def isDefaultRoute(hostname: str):
if hostname.count(".") < 2: # exactly the main domain
if hostname == app.config["SERVER_NAME"]:
return True return True
subdomain = hostname.split(".")[0] # a reserved subdomain
return not subdomain or subdomain in RESERVED_SUBDOMAINS parts = hostname.split(".")
server_parts = app.config["SERVER_NAME"].split(".")
# the host ends with the server domain
if parts[-len(server_parts) :] != server_parts:
return False
# subdomain portion
subdomain = ".".join(parts[: -len(server_parts)])
# any part of the subdomain is reserved
return (
any(part in RESERVED_SUBDOMAINS for part in subdomain.split("."))
or subdomain in RESERVED_SUBDOMAINS
)
# Models # Models
@@ -101,16 +116,29 @@ class Site(db.Model):
created_at = db.Column(db.DateTime, default=datetime.utcnow) created_at = db.Column(db.DateTime, default=datetime.utcnow)
@app.context_processor
def inject_subdomain():
host = request.host
server_parts = app.config["SERVER_NAME"].split(".")
host_parts = host.split(".")
subdomain = None
if host_parts[-len(server_parts) :] == server_parts:
subdomain_parts = host_parts[: -len(server_parts)]
if subdomain_parts:
subdomain = ".".join(subdomain_parts)
return {
"SUBDOMAIN": subdomain,
"FULL_DOMAIN": host,
"SERVERNAME": app.config["SERVER_NAME"],
}
@app.errorhandler(404) @app.errorhandler(404)
def page_not_found(_): def page_not_found(_):
return render_template("404.html", domain=request.host), 404 return render_template("404.html", domain=request.host), 404
@app.context_processor
def inject_global_variable():
return {
"SERVERNAME": app.config["SERVER_NAME"],
}
# Auth setup # Auth setup
login_manager = LoginManager() login_manager = LoginManager()
@@ -327,11 +355,11 @@ def delete_file(site_id, filename):
return redirect(url_for("dashboard")) return redirect(url_for("dashboard"))
# use subdomains
@app.route("/", subdomain="<subdomain>", defaults={"filename": "index.html"}) @app.route("/", subdomain="<subdomain>", defaults={"filename": "index.html"})
@app.route("/<path:filename>") @app.route("/<path:filename>", subdomain="<subdomain>")
def serve_site_content(filename): def serve_site_content(subdomain, filename):
subdomain = request.host.split(".")[0] if isDefaultRoute(request.host):
abort(404) # Reserve default routes for main app
site = Site.query.filter_by(subdomain=subdomain).first_or_404() site = Site.query.filter_by(subdomain=subdomain).first_or_404()
site.last_accessed = datetime.utcnow() site.last_accessed = datetime.utcnow()
@@ -341,12 +369,9 @@ def serve_site_content(filename):
app.config["UPLOAD_FOLDER"], str(site.user_id), str(site.id) app.config["UPLOAD_FOLDER"], str(site.user_id), str(site.id)
) )
if isDefaultRoute(request.host): # Security checks
return send_from_directory("index.html")
# Security check
if ".." in filename or filename.startswith("/") or not os.path.exists(site_dir): if ".." in filename or filename.startswith("/") or not os.path.exists(site_dir):
return render_template("404.html"), 404 abort(404)
try: try:
return send_from_directory(site_dir, filename) return send_from_directory(site_dir, filename)
@@ -355,7 +380,6 @@ def serve_site_content(filename):
try: try:
return send_from_directory(site_dir, f"{filename}.html") return send_from_directory(site_dir, f"{filename}.html")
except NotFound: except NotFound:
redirect(app.config["SERVER_NAME"])
return send_from_directory(site_dir, "index.html") return send_from_directory(site_dir, "index.html")
abort(404) abort(404)
@@ -374,10 +398,9 @@ def inject_utilities():
@app.route("/") @app.route("/")
def home(): def home():
if isDefaultRoute(request.host): if not isDefaultRoute(request.host):
abort(404)
return render_template("home.html") return render_template("home.html")
else:
return serve_site_content("index.html")
if __name__ == "__main__": if __name__ == "__main__":
+6 -7
View File
@@ -13,14 +13,13 @@
<meta property="og:description" <meta property="og:description"
content="Host and share your static sites effortlessly with ION Static Site Hosting. Enjoy instant deployment, a sleek dark mode interface, and secure, private data handling!"> content="Host and share your static sites effortlessly with ION Static Site Hosting. Enjoy instant deployment, a sleek dark mode interface, and secure, private data handling!">
<meta property="og:image" content="{{ url_for('static', filename='hosting.png') }}"> <meta property="og:image" content="{{ url_for('static', filename='hosting.png') }}">
<meta property="og:url" content="https://{{session['servername']}}/"> <meta property="og:url" content="https://{{ SERVERNAME }}/">
<meta name="twitter:card" content="{{ url_for('static', filename='hosting.png') }}"> <meta name="twitter:card" content="{{ url_for('static', filename='hosting.png') }}">
<meta name="twitter:title" content="ION Static Site Hosting"> <meta name="twitter:title" content="ION Static Site Hosting">
<meta name="twitter:description" <meta name="twitter:description"
content="Host and share your static sites effortlessly with ION Static Site Hosting. Enjoy instant deployment, a sleek dark mode interface, and secure, private data handling!"> content="Host and share your static sites effortlessly with ION Static Site Hosting. Enjoy instant deployment, a sleek dark mode interface, and secure, private data handling!">
<meta name="twitter:image" content="{{ url_for('static', filename='hosting.png') }}"> <meta name="twitter:image" content="{{ url_for('static', filename='hosting.png') }}">
<title>ION Static Site Hosting - {% block title %}{% endblock %}</title> <title>ION Static Site Hosting - {% block title %}{% endblock %}</title>
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}" id="theme-style"> <link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}" id="theme-style">
<link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}"> <link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}">
@@ -53,13 +52,13 @@
<body> <body>
<nav class="navbar"> <nav class="navbar">
<div class="container"> <div class="container">
<a href="https://{{ SERVERNAME }}">Home</a> <a href="{{ url_for('home', _external=True) }}">Home</a>
{% if current_user.is_authenticated %} {% if current_user.is_authenticated %}
<a href="https://{{ SERVERNAME }}/dashboard">Dashboard</a> <a href="{{ url_for('dashboard', _external=True) }}">Dashboard</a>
<a href="https://{{ SERVERNAME }}/logout">Logout</a> <a href="{{ url_for('logout', _external=True) }}">Logout</a>
{% else %} {% else %}
<a href="{{ url_for('login') }}">Login</a> <a href="{{ url_for('login', _external=True) }}">Login</a>
<a href="{{ url_for('register') }}">Register</a> <a href="{{ url_for('register', _external=True) }}">Register</a>
{% endif %} {% endif %}
<button id="theme-toggle" class="btn">Toggle Dark Mode</button> <button id="theme-toggle" class="btn">Toggle Dark Mode</button>
</div> </div>