Ensure trailing slashes are handled correctly

This commit is contained in:
Scott Wallace 2025-02-12 09:29:23 +00:00
parent 97512598f5
commit 5e0cb48906
Signed by: scott
SSH key fingerprint: SHA256:+LJug6Dj01Jdg86CILGng9r0lJseUrpI0xfRqdW9Uws
2 changed files with 30 additions and 36 deletions

View file

@ -1,6 +1,4 @@
"""
Main Flask-based app for Slinky
"""
"""Main Flask-based app for Slinky."""
from flask import Flask, Response, render_template
from werkzeug.middleware.proxy_fix import ProxyFix
@ -15,10 +13,10 @@ app.register_blueprint(slinky_webapp)
@app.route("/")
@protect
def index() -> Response:
"""
Index/Landing page
"""Index/Landing page.
Returns:
str: string of page content
"""
return Response(render_template("index.html"), 200)

View file

@ -1,12 +1,11 @@
"""
Web component
"""
"""Web component."""
import logging
import os
from datetime import datetime
import pathlib
from datetime import UTC, datetime
from functools import wraps
from typing import Any, Callable
from typing import Callable
import yaml
from flask import Blueprint, Response, render_template, request
@ -18,22 +17,18 @@ from slinky import Slinky, random_string
slinky_webapp = Blueprint("webapp", __name__, template_folder="templates")
with open("config.yaml", encoding="utf-8-sig") as conffile:
with pathlib.Path("config.yaml").open(encoding="utf-8-sig") as conffile:
cfg = yaml.safe_load(conffile)
class DelForm(FlaskForm):
"""
Delete form definition
"""
"""Delete form definition."""
delete = HiddenField("delete")
class AddForm(FlaskForm):
"""
Add form definition
"""
"""Add form definition."""
shortcode = StringField(
"Shortcode",
@ -79,18 +74,18 @@ class AddForm(FlaskForm):
def protect(func: Callable[..., Response]) -> Callable[..., Response]:
"""
Decorator that will protect the admin interface
"""Protect the admin interface.
Args:
func (Callable): Wrapped function
Returns:
Callable: Function wrapper
"""
@wraps(func)
def check_ip(*args: Any, **kwargs: Any) -> Response:
def check_ip(*args: ..., **kwargs: ...) -> Response:
remote_addr = request.remote_addr
if "x-forwarded-for" in request.headers:
@ -99,10 +94,7 @@ def protect(func: Callable[..., Response]) -> Callable[..., Response]:
if "x-real-ip" in request.headers:
remote_addr = request.headers["x-real-ip"]
if (
os.environ.get("FLASK_ENV", "") != "development"
and remote_addr not in cfg["allowed_ips"]
):
if os.environ.get("FLASK_ENV", "") != "development" and remote_addr not in cfg["allowed_ips"]:
logging.warning("Protected URL access attempt from %s", remote_addr)
return Response("Not found", 404)
return func(*args, **kwargs)
@ -112,28 +104,32 @@ def protect(func: Callable[..., Response]) -> Callable[..., Response]:
@slinky_webapp.route("/<path:path>", strict_slashes=False)
def try_path_as_shortcode(path: str) -> Response:
"""
Try the initial path as a shortcode, redirect if found
"""Try the initial path as a shortcode, redirect if found.
Returns:
Response: redirect if found, otherwise 404
"""
path = path.strip("/")
should_redirect = True
slinky = Slinky(cfg["db"])
shortcode = slinky.get_by_shortcode(path)
if shortcode.url:
if shortcode.fixed_views == 0:
logging.warning("Shortcode out of views")
should_redirect = False
elif shortcode.fixed_views > 0:
slinky.remove_view(shortcode.id)
if datetime.fromisoformat(shortcode.expiry) < datetime.now():
if datetime.fromisoformat(shortcode.expiry).astimezone(UTC) < datetime.now(UTC):
logging.warning("Shortcode expired")
should_redirect = False
if should_redirect:
return Response(
"Redirecting...", status=302, headers={"location": shortcode.url}
"Redirecting...",
status=302,
headers={"location": shortcode.url},
)
return Response("Not found", 404)
@ -142,11 +138,11 @@ def try_path_as_shortcode(path: str) -> Response:
@slinky_webapp.route("/_/add", methods=["GET", "POST"])
@protect
def add() -> Response:
"""
Create and add a new shorturl
"""Create and add a new shorturl.
Returns:
Response: HTTP response
"""
slinky = Slinky(cfg["db"])
@ -207,11 +203,11 @@ def add() -> Response:
@slinky_webapp.route("/_/list", methods=["GET", "POST"])
@protect
def lister() -> Response:
"""
List the shortcodes, URLs, etc.
"""List the shortcodes, URLs, etc.
Returns:
Response: HTTP response
"""
form = DelForm(meta={"csrf": False})
slinky = Slinky(cfg["db"])
@ -227,17 +223,17 @@ def lister() -> Response:
@slinky_webapp.route("/_/edit/<int:id>", methods=["GET", "POST"])
@protect
def edit(id: int) -> Response: # pylint: disable=invalid-name,redefined-builtin
"""
Edit the shortcode.
def edit(shortcut_id: int) -> Response: # pylint: disable=invalid-name,redefined-builtin
"""Edit the shortcode.
Returns:
Response: HTTP response
"""
form = DelForm(meta={"csrf": False})
slinky = Slinky(cfg["db"])
logging.debug("Editing: %d", id)
logging.debug("Editing: %d", shortcut_id)
if form.is_submitted():
slinky.delete_by_shortcode(form.delete.data.strip())