import os, shutil, html, urllib.parse, subprocess from flask import Flask, request, redirect, send_file, Response from werkzeug.middleware.dispatcher import DispatcherMiddleware from werkzeug.serving import run_simple app = Flask(__name__) app.config["APPLICATION_ROOT"] = "/fm" SECRET_HINTS = ("TOKEN", "KEY", "SECRET", "PASSWORD", "AUTH", "COOKIE") def is_sensitive(name): up = name.upper() return any(h in up for h in SECRET_HINTS) def mask_secrets(text): # Guide rule 10: never surface real credential values in output. out = [] for line in text.splitlines(): if any(h in line.upper() for h in SECRET_HINTS) and ("=" in line or ":" in line): out.append("*** line masked (possible secret) ***") else: out.append(line) return "\n".join(out) PAGE = """
{html.escape(output)}
"""
return Response(PAGE.format(body=body))
# ---------------- FILE MANAGER ----------------
@app.route("/")
def browse():
path = os.path.abspath(request.args.get("path", "/"))
if not os.path.exists(path):
return Response(PAGE.format(body=f"Not found: {html.escape(path)}
"), status=404) if os.path.isfile(path): return redirect(f"/fm/view?path={urllib.parse.quote(path)}") parent = os.path.dirname(path.rstrip("/")) or "/" rows = f'Permission denied: {html.escape(path)}
"), status=403) for name in entries: full = os.path.join(path, name); q = urllib.parse.quote(full) try: size = os.path.getsize(full) if os.path.isfile(full) else "" except OSError: size = "?" if os.path.isdir(full): link = f'📁 {html.escape(name)}/' actions = f'delete' else: link = f'📄 {html.escape(name)}' actions = (f'download | ' f'edit | ' f'delete') rows += f"| Name | Size | Actions |
|---|
{html.escape(content)}")
return Response(PAGE.format(body=body))
@app.route("/edit")
def edit():
path = os.path.abspath(request.args.get("path", ""))
try:
with open(path, "r", errors="replace") as f:
content = f.read()
except Exception as e:
content = f"[cannot open: {e}]"
body = f"""
"""
return Response(PAGE.format(body=body))
@app.route("/save", methods=["POST"])
def save():
path = os.path.abspath(request.form["path"])
with open(path, "w") as f:
f.write(request.form["content"])
return redirect(f"/fm/view?path={urllib.parse.quote(path)}")
@app.route("/download")
def download():
path = os.path.abspath(request.args.get("path", ""))
if is_sensitive(os.path.basename(path)):
return Response("masked (sensitive filename)", status=403)
return send_file(path, as_attachment=True)
@app.route("/mkdir", methods=["POST"])
def mkdir():
base = os.path.abspath(request.form["path"])
os.makedirs(os.path.join(base, request.form["name"]), exist_ok=True)
return redirect(f"/fm/?path={urllib.parse.quote(base)}")
@app.route("/upload", methods=["POST"])
def upload():
base = os.path.abspath(request.form["path"])
f = request.files.get("file")
if f and f.filename:
f.save(os.path.join(base, f.filename))
return redirect(f"/fm/?path={urllib.parse.quote(base)}")
@app.route("/delete")
def delete():
path = os.path.abspath(request.args.get("path", ""))
parent = os.path.dirname(path)
try:
shutil.rmtree(path) if os.path.isdir(path) else os.remove(path)
except Exception as e:
return Response(PAGE.format(body=f"Delete failed: {e}
"), status=500) return redirect(f"/fm/?path={urllib.parse.quote(parent)}") if __name__ == "__main__": wrapped = DispatcherMiddleware(Flask("empty"), {"/fm": app}) run_simple("0.0.0.0", 9001, wrapped)