roundabout,
created on Monday, 4 December 2023, 17:41:44 (1701711704),
received on Wednesday, 31 July 2024, 06:54:38 (1722408878)
Author identity: vlad <vlad.muntoiu@gmail.com>
ea7cf8e86b9a30b54e7761eccaf146fe06a5561b
app.py
@@ -24,6 +24,7 @@ import config
app = flask.Flask(__name__) from flask_httpauth import HTTPBasicAuth auth = HTTPBasicAuth() app.config["SQLALCHEMY_DATABASE_URI"] = config.DB_URI
@@ -41,7 +42,8 @@ def gitCommand(repo, data, *args):
command = ["git", *args] proc = subprocess.Popen(" ".join(command), cwd=repo, env=env, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE)proc = subprocess.Popen(" ".join(command), cwd=repo, env=env, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE)print(command) if data:
@@ -106,7 +108,8 @@ with app.app_context():
avatarName = random.choice(os.listdir(config.DEFAULT_AVATARS_PATH)) if os.path.join(config.DEFAULT_AVATARS_PATH, avatarName).endswith(".svg"): cairosvg.svg2png(url=os.path.join(config.DEFAULT_AVATARS_PATH, avatarName), write_to="/tmp/roundabout-avatar.png")cairosvg.svg2png(url=os.path.join(config.DEFAULT_AVATARS_PATH, avatarName), write_to="/tmp/roundabout-avatar.png")avatar = Image.open("/tmp/roundabout-avatar.png") else: avatar = Image.open(os.path.join(config.DEFAULT_AVATARS_PATH, avatarName))
@@ -188,7 +191,8 @@ def getVisibility(username, repository):
import gitHTTP def humanSize(value, decimals=2, scale=1024, units=("B", "kiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB", "RiB", "QiB")):def humanSize(value, decimals=2, scale=1024, units=("B", "kiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB", "RiB", "QiB")):for unit in units: if value < scale: break
@@ -196,7 +200,7 @@ def humanSize(value, decimals=2, scale=1024, units=("B", "kiB", "MiB", "GiB", "T
if int(value) == value: # do not return decimals, if the value is already round return int(value), unit return round(value * 10**decimals) / 10**decimals, unitreturn round(value * 10 ** decimals) / 10 ** decimals, unitdef guessMIME(path):
@@ -269,44 +273,57 @@ def login():
if user and bcrypt.check_password_hash(user.passwordHashed, password): flask.session["username"] = user.username flask.flash(Markup(f"<iconify-icon icon='mdi:account'></iconify-icon>Successfully logged in as {username}"), category="success")flask.flash( Markup(f"<iconify-icon icon='mdi:account'></iconify-icon>Successfully logged in as {username}"), category="success")return flask.redirect("/", code=303) elif not user: flask.flash(Markup("<iconify-icon icon='mdi:account-question'></iconify-icon>User not found"), category="alert")flask.flash(Markup("<iconify-icon icon='mdi:account-question'></iconify-icon>User not found"), category="alert")return flask.render_template("login.html") else: flask.flash(Markup("<iconify-icon icon='mdi:account-question'></iconify-icon>Invalid password"), category="error")flask.flash(Markup("<iconify-icon icon='mdi:account-question'></iconify-icon>Invalid password"), category="error")return flask.render_template("login.html") if "signup" in flask.request.form: username = flask.request.form["username"] password = flask.request.form["password"] password2 = flask.request.form["password2"] email = flask.request.form.get("email") email2 = flask.request.form.get("email2") # repeat email is a honeypotemail2 = flask.request.form.get("email2") # repeat email is a honeypotname = flask.request.form.get("name") if not onlyChars(username, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_"): flask.flash(Markup("<iconify-icon icon='mdi:account-error'></iconify-icon>Usernames may only contain Latin alphabet, numbers, '-' and '_'"), category="error")flask.flash(Markup( "<iconify-icon icon='mdi:account-error'></iconify-icon>Usernames may only contain Latin alphabet, numbers, '-' and '_'"), category="error")return flask.render_template("login.html") if username in config.RESERVED_NAMES: flask.flash(Markup(f"<iconify-icon icon='mdi:account-error'></iconify-icon>Sorry, {username} is a system path"), category="error")flask.flash( Markup(f"<iconify-icon icon='mdi:account-error'></iconify-icon>Sorry, {username} is a system path"), category="error")return flask.render_template("login.html") userCheck = User.query.filter_by(username=username).first() if userCheck: flask.flash(Markup(f"<iconify-icon icon='mdi:account-error'></iconify-icon>The username {username} is taken"), category="error")flask.flash( Markup(f"<iconify-icon icon='mdi:account-error'></iconify-icon>The username {username} is taken"), category="error")return flask.render_template("login.html") if password2 != password: flask.flash(Markup("<iconify-icon icon='mdi:key-alert'></iconify-icon>Make sure the passwords match"), category="error")flask.flash(Markup("<iconify-icon icon='mdi:key-alert'></iconify-icon>Make sure the passwords match"), category="error")return flask.render_template("login.html") user = User(username, password, email, name) db.session.add(user) db.session.commit() flask.session["username"] = user.username flask.flash(Markup(f"<iconify-icon icon='mdi:account'></iconify-icon>Successfully created and logged in as {username}"), category="success")flask.flash(Markup( f"<iconify-icon icon='mdi:account'></iconify-icon>Successfully created and logged in as {username}"), category="success")return flask.redirect("/", code=303)
@@ -320,8 +337,8 @@ def newRepo():
if not onlyChars(name, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_"): flask.flash(Markup( "<iconify-icon icon='mdi:error'></iconify-icon>Repository names may only contain Latin alphabet, numbers, '-' and '_'"),category="error")"<iconify-icon icon='mdi:error'></iconify-icon>Repository names may only contain Latin alphabet, numbers, '-' and '_'"), category="error")return flask.render_template("new-repo.html") user = User.query.filter_by(username=flask.session.get("username")).first()
@@ -331,9 +348,11 @@ def newRepo():
db.session.commit() if not os.path.exists(os.path.join(config.REPOS_PATH, repo.route)): subprocess.run(["git", "init", repo.name], cwd=os.path.join(config.REPOS_PATH, flask.session.get("username")))subprocess.run(["git", "init", repo.name], cwd=os.path.join(config.REPOS_PATH, flask.session.get("username")))flask.flash(Markup(f"<iconify-icon icon='mdi:folder'></iconify-icon>Successfully created repository {name}"), category="success")flask.flash(Markup(f"<iconify-icon icon='mdi:folder'></iconify-icon>Successfully created repository {name}"), category="success")return flask.redirect(repo.route, code=303)
@@ -358,7 +377,8 @@ def repositoryIndex(username, repository):
@app.route("/<username>/<repository>/raw/<branch>/<path:subpath>") def repositoryRaw(username, repository, branch, subpath): if not (getVisibility(username, repository) or getPermissionLevel(flask.session.get("user"), username, repository) is not None):if not (getVisibility(username, repository) or getPermissionLevel(flask.session.get("user"), username, repository) is not None):flask.abort(403) serverRepoLocation = os.path.join(config.REPOS_PATH, os.path.join(username, repository))
@@ -392,7 +412,8 @@ def userAvatar(username):
@app.route("/<username>/<repository>/tree/<branch>/", defaults={"subpath": ""}) @app.route("/<username>/<repository>/tree/<branch>/<path:subpath>") def repositoryTree(username, repository, branch, subpath): if not (getVisibility(username, repository) or getPermissionLevel(flask.session.get("username"), username, repository) is not None):if not (getVisibility(username, repository) or getPermissionLevel(flask.session.get("username"), username, repository) is not None):flask.abort(403) serverRepoLocation = os.path.join(config.REPOS_PATH, os.path.join(username, repository))
@@ -409,15 +430,23 @@ def repositoryTree(username, repository, branch, subpath):
if repo.heads: repoData.defaultBranch = repo.heads[0].name else: return flask.render_template("empty.html", remote=f"http://{config.BASE_DOMAIN}/git/{username}/{repository}"), 200return flask.render_template("empty.html", remote=f"http://{config.BASE_DOMAIN}/git/{username}/{repository}"), 200if not branch: branch = repoData.defaultBranch return flask.redirect(f"./{branch}", code=302) if branch.startswith("tag:"): ref = f"tags/{branch[4:]}" if branch.startswith("~"): ref = branch[1:]else: try:repo.git.checkout("-f", branch)except git.exc.GitCommandError:return flask.render_template("not-found.html"), 404ref = f"refs/{branch}" try: repo.git.checkout("-f", branch) except git.exc.GitCommandError: return flask.render_template("not-found.html"), 404branches = repo.heads
@@ -520,7 +549,8 @@ def repositoryTree(username, repository, branch, subpath):
@app.route("/<username>/<repository>/forum/") def repositoryForum(username, repository): if not (getVisibility(username, repository) or getPermissionLevel(flask.session.get("username"), username, repository) is not None):if not (getVisibility(username, repository) or getPermissionLevel(flask.session.get("username"), username, repository) is not None):flask.abort(403) return flask.render_template("repo-forum.html", username=username, repository=repository)
@@ -528,7 +558,8 @@ def repositoryForum(username, repository):
@app.route("/<username>/<repository>/branches/") def repositoryBranches(username, repository): if not (getVisibility(username, repository) or getPermissionLevel(flask.session.get("username"), username, repository) is not None):if not (getVisibility(username, repository) or getPermissionLevel(flask.session.get("username"), username, repository) is not None):flask.abort(403) return flask.render_template("repo-branches.html", username=username, repository=repository)
@@ -536,7 +567,8 @@ def repositoryBranches(username, repository):
@app.route("/<username>/<repository>/log/") def repositoryLog(username, repository): if not (getVisibility(username, repository) or getPermissionLevel(flask.session.get("username"), username, repository) is not None):if not (getVisibility(username, repository) or getPermissionLevel(flask.session.get("username"), username, repository) is not None):flask.abort(403) return flask.render_template("repo-log.html", username=username, repository=repository)
@@ -569,3 +601,6 @@ def e403(error):
def e418(error): return flask.render_template("teapot.html"), 418 if __name__ == "__main__": app.run(debug=True, port=8080, host="0.0.0.0")
gitHTTP.py
@@ -29,6 +29,7 @@ def verifyPassword(username, password):
return False @app.route("/<username>/<repository>/git-upload-pack", methods=["POST"]) @app.route("/git/<username>/<repository>/git-upload-pack", methods=["POST"]) @auth.login_required(optional=True) def gitUploadPack(username, repository):
@@ -43,6 +44,7 @@ def gitUploadPack(username, repository):
return flask.Response(text, content_type="application/x-git-upload-pack-result") @app.route("/<username>/<repository>/git-receive-pack", methods=["POST"]) @app.route("/git/<username>/<repository>/git-receive-pack", methods=["POST"]) @auth.login_required def gitReceivePack(username, repository):
@@ -70,7 +72,8 @@ def gitReceivePack(username, repository):
return flask.Response(text, content_type="application/x-git-receive-pack-result") @app.route("/git/<username>/<repository>/info/refs", methods=["GET"])@app.route("/<username>/<repository>/info/refs", methods=["GET", "POST"]) @app.route("/git/<username>/<repository>/info/refs", methods=["GET", "POST"])@auth.login_required(optional=True) def gitInfoRefs(username, repository): serverRepoLocation = os.path.join(config.REPOS_PATH, username, repository, ".git")