import flask import jinja2 import os import mimetypes import bleach from markdown_it import MarkdownIt from config import * app = flask.Flask(__name__) md = MarkdownIt("commonmark", {"typographer": True}).enable( ["replacements", "smartquotes"] ) def split_url(url): segments = [""] for character in url: segments[-1] += character if character == "/": segments.append("") if not segments[-1]: del segments[-1] paths = [ [segment, "".join(segments[: i + 1])] for i, segment in enumerate(segments) ] paths[0][0] = f"{title}: {paths[0][0]}" return paths def render(path, main, show_print=True, status_code=200): path = jinja2.filters.escape(path) path_segments = split_url(path) path_html = ( "".join( [ f'
  • {name}
  • \n' for name, path in path_segments[:-1] ] ) + f"
  • {path_segments[-1][0]}
  • " ) actions = ( """
    """ if show_print else "" ) body = ( f""" {path} - {title}
    {actions}
    {main}
    """, ) return flask.Response( body, headers={"Content-Type": "text/html"}, status=status_code, ) def render_txt(text, path): text = jinja2.filters.escape(text.decode("utf-8")) return render(path, f"
    {bleach.clean(text)}
    ") def render_md(text, path): text = bleach.clean( md.render(text.decode("utf-8")), tags=[ "a", "abbr", "acronym", "b", "blockquote", "code", "em", "i", "li", "ol", "strong", "ul", "p", "pre", "img", "h1", "h2", "h3", "h4", "h5", "h6", "hr", ], attributes={ "a": ["href", "title"], "abbr": ["title"], "acronym": ["title"], "ol": ["start"], "li": ["value"], }, ) return render(path, text) def render_directory(contents, path): # TODO: strikethrough forbidden files if path.endswith("/"): contents.sort() listing = "".join( [ f'
  • {i}{"/" if os.path.isdir(os.path.join(root, path[1:], i)) else ""}
  • ' for i in contents ] ) return render( path, f"", show_print=False ) else: return flask.redirect(path + "/") renderers = {"txt": render_txt, "md": render_md} @app.route("/") @app.route("/") def main(path=""): # TODO: remove // and fix .. full_path = os.path.join(root, path) path = "/" + path file_type = path.split(".")[-1] try: return render_directory(os.listdir(full_path), path) except NotADirectoryError: if not file_type in allowed_file_types: return render( path, f"

    403 Forbidden

    {path}

    Disallowed file type: {file_type}", show_print=False, status_code=403, ) elif file_type in renderers: with open(full_path, "rb") as f: return renderers[file_type](f.read(), path) else: if path.endswith("/"): return flask.redirect(path[:-1]) else: with open(full_path, "rb") as f: return flask.Response( f.read(), headers={ "Content-Type": mimetypes.guess_type(full_path)[0] }, ) except FileNotFoundError: return render( path, f"

    404 Not Found

    {path}

    ", show_print=False, status_code=404, )