gitHTTP.py
Python script, ASCII text executable
1import uuid 2 3from app import app, User, Repo, Commit, 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 29def gitCommand(repo, data, *args): 30if not os.path.isdir(repo): 31raise FileNotFoundError("Repo not found") 32env = os.environ.copy() 33 34command = ["git", *args] 35 36proc = subprocess.Popen(" ".join(command), cwd=repo, env=env, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE) 37print(command) 38 39if data: 40proc.stdin.write(data) 41 42out, err = proc.communicate() 43return out 44 45 46@app.route("/git/<username>/<repository>/git-upload-pack", methods=["POST"]) 47@auth.login_required 48def gitUploadPack(username, repository): 49serverRepoLocation = os.path.join(config.REPOS_PATH, username, repository, ".git") 50text = gitCommand(serverRepoLocation, flask.request.data, "upload-pack", "--stateless-rpc", ".") 51 52return flask.Response(text, content_type="application/x-git-upload-pack-result") 53 54 55@app.route("/git/<username>/<repository>/git-receive-pack", methods=["POST"]) 56@auth.login_required 57def gitReceivePack(username, repository): 58serverRepoLocation = os.path.join(config.REPOS_PATH, username, repository, ".git") 59text = gitCommand(serverRepoLocation, flask.request.data, "receive-pack", "--stateless-rpc", ".") 60 61sha = flask.request.data.split(b" ", 2)[1].decode() 62info = gitCommand(serverRepoLocation, None, "show", "-s", "--format='%H%n%at%n%cn <%ce>%n%B'").decode() 63 64if re.match("[0-9a-fA-F]", info[:40]): 65print(info.split("\n", 4)) 66sha, time, identity, *body = info.split("\n", 4) 67body = "\n".join("body") 68login = flask.g.user 69 70user = User.query.filter_by(username=login).first() 71repo = Repo.query.filter_by(route=f"/{username}/{repository}").first() 72commit = Commit(sha, user, repo, time, body, identity) 73 74db.session.add(commit) 75db.session.commit() 76 77return flask.Response(text, content_type="application/x-git-receive-pack-result") 78 79 80@app.route("/git/<username>/<repository>/info/refs", methods=["GET"]) 81@auth.login_required 82def gitInfoRefs(username, repository): 83serverRepoLocation = os.path.join(config.REPOS_PATH, username, repository, ".git") 84service = flask.request.args.get("service") 85 86if service.startswith("git"): 87service = service[4:] 88 89print(service) 90 91serviceLine = f"# service=git-{service}\n" 92serviceLine = (f"{len(serviceLine) + 4:04x}" + serviceLine).encode() 93 94if service == "upload-pack": 95text = serviceLine + b"0000" + gitCommand(serverRepoLocation, None, "upload-pack", "--stateless-rpc", "--advertise-refs", "--http-backend-info-refs", ".") 96elif service == "receive-pack": 97text = serviceLine + b"0000" + gitCommand(serverRepoLocation, None, "receive-pack", "--http-backend-info-refs", ".") 98else: 99flask.abort(403) 100 101response = flask.Response(text, content_type=f"application/x-git-{service}-advertisement") 102response.headers["Cache-Control"] = "no-cache" 103 104return response 105 106