gitHTTP.py
Python script, ASCII text executable
1import uuid 2 3from app import app, gitCommand, User, Repo, Commit, RepoAccess, getPermissionLevel, getVisibility, db, bcrypt 4import os 5import shutil 6import config 7import flask 8import git 9import subprocess 10from flask_httpauth import HTTPBasicAuth 11import zlib 12import re 13import datetime 14 15auth = HTTPBasicAuth(realm=config.AUTH_REALM) 16 17 18@auth.verify_password 19def verifyPassword(username, password): 20user = User.query.filter_by(username=username).first() 21 22if user and bcrypt.check_password_hash(user.passwordHashed, password): 23flask.g.user = username 24return True 25 26return False 27 28 29@app.route("/git/<username>/<repository>/git-upload-pack", methods=["POST"]) 30@auth.login_required 31def gitUploadPack(username, repository): 32if not (getVisibility(username, repository) or getPermissionLevel(flask.g.user, username, repository) is not None): 33flask.abort(403) 34 35serverRepoLocation = os.path.join(config.REPOS_PATH, username, repository, ".git") 36text = gitCommand(serverRepoLocation, flask.request.data, "upload-pack", "--stateless-rpc", ".") 37 38return flask.Response(text, content_type="application/x-git-upload-pack-result") 39 40 41@app.route("/git/<username>/<repository>/git-receive-pack", methods=["POST"]) 42@auth.login_required 43def gitReceivePack(username, repository): 44if not getPermissionLevel(flask.g.user, username, repository): 45flask.abort(403) 46 47serverRepoLocation = os.path.join(config.REPOS_PATH, username, repository, ".git") 48text = gitCommand(serverRepoLocation, flask.request.data, "receive-pack", "--stateless-rpc", ".") 49 50sha = flask.request.data.split(b" ", 2)[1].decode() 51info = gitCommand(serverRepoLocation, None, "show", "-s", "--format='%H%n%at%n%cn <%ce>%n%B'", sha).decode() 52 53if re.match("^[0-9a-fA-F]{40}$", info[:40]): 54print(info.split("\n", 3)) 55sha, time, identity, body = info.split("\n", 3) 56login = flask.g.user 57 58user = User.query.filter_by(username=login).first() 59repo = Repo.query.filter_by(route=f"/{username}/{repository}").first() 60commit = Commit(sha, user, repo, time, body, identity) 61 62db.session.add(commit) 63db.session.commit() 64 65return flask.Response(text, content_type="application/x-git-receive-pack-result") 66 67 68@app.route("/git/<username>/<repository>/info/refs", methods=["GET"]) 69@auth.login_required 70def gitInfoRefs(username, repository): 71if not (getVisibility(username, repository) or getPermissionLevel(flask.g.user, username, repository) is not None): 72flask.abort(403) 73 74serverRepoLocation = os.path.join(config.REPOS_PATH, username, repository, ".git") 75service = flask.request.args.get("service") 76 77if service.startswith("git"): 78service = service[4:] 79 80if service == "receive-pack": 81print(getPermissionLevel(flask.g.user, username, repository)) 82if not getPermissionLevel(flask.g.user, username, repository): 83flask.abort(403) 84 85serviceLine = f"# service=git-{service}\n" 86serviceLine = (f"{len(serviceLine) + 4:04x}" + serviceLine).encode() 87 88if service == "upload-pack": 89text = serviceLine + b"0000" + gitCommand(serverRepoLocation, None, "upload-pack", "--stateless-rpc", "--advertise-refs", "--http-backend-info-refs", ".") 90elif service == "receive-pack": 91text = serviceLine + b"0000" + gitCommand(serverRepoLocation, None, "receive-pack", "--http-backend-info-refs", ".") 92else: 93flask.abort(403) 94 95response = flask.Response(text, content_type=f"application/x-git-{service}-advertisement") 96response.headers["Cache-Control"] = "no-cache" 97 98return response 99 100