From 4660f5a7ca51bb198ad4a5ff3a233252627dba5b Mon Sep 17 00:00:00 2001 From: Kumi Date: Wed, 19 Jun 2024 11:49:34 +0200 Subject: [PATCH] feat: add proxy for Git client requests to GitHub Introduced a new route to handle Git client requests, proxying them to GitHub. This includes support for methods like GET, POST, PUT, DELETE, and PATCH. Added the `requests` library to manage the HTTP requests and updated imports accordingly. This enhancement allows Git client interactions with the app to be seamlessly redirected to corresponding GitHub repositories, improving integration and user experience. --- pyproject.toml | 2 +- src/gitcloak/app.py | 79 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 79 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index c5b1920..a5160bf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,7 +15,7 @@ classifiers = [ "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", ] -dependencies = ["dulwich", "flask", "markdown2[all]"] +dependencies = ["dulwich", "flask", "markdown2[all]", "requests"] [project.scripts] gitcloak = "gitcloak.app:main" diff --git a/src/gitcloak/app.py b/src/gitcloak/app.py index 0d0de66..8956ff0 100644 --- a/src/gitcloak/app.py +++ b/src/gitcloak/app.py @@ -1,4 +1,13 @@ -from flask import Flask, render_template, abort, send_from_directory, Response +from flask import ( + Flask, + render_template, + abort, + send_from_directory, + Response, + request, + redirect, +) +import requests from .classes.git import Git from .classes.markdown import RelativeURLRewriter import logging @@ -206,6 +215,74 @@ def preview_file(owner: str, repo: str, file_path: str): abort(404, description=str(e)) +@app.route("/.git", methods=["GET", "POST", "PUT", "DELETE", "PATCH"]) +@app.route( + "/.git/", + methods=["GET", "POST", "PUT", "DELETE", "PATCH"], +) +def proxy_git(subpath, extra=None): + """Route for proxying Git client requests to GitHub. + + Args: + subpath (str): The subpath of the request. + extra (str): An optional extra path after .git. + + Returns: + Response: A response from the repository on GitHub. + """ + path = f"{subpath}.git" + if extra: + path += f"/{extra}" + github_url = f"https://github.com/{path}" + + logger.debug(f"Proxying Git request to {github_url}") + + resp = requests.request( + method=request.method, + url=github_url, + headers={ + key: value + for (key, value) in request.headers.items() + if key.lower() != "host" + and not key.lower().startswith("x-forwarded") + and not key.lower().startswith("forwarded") + }, + data=request.get_data(), + cookies=request.cookies, + params=request.args, + allow_redirects=False, + stream=True, + ) + + # Those headers shouldn't be passed directly to the client + excluded_headers = [ + "content-length", + "content-encoding", + "transfer-encoding", + "connection", + ] + + headers = [ + (name, value) + for (name, value) in resp.raw.headers.items() + if name.lower() not in excluded_headers + ] + + return Response(resp.raw, status=resp.status_code, headers=dict(headers)) + + +@app.before_request +def catch_git_requests(): + if "git/" in request.headers.get("User-Agent", ""): + try: + path = request.path.lstrip("/") + path = path.split("/") + return proxy_git("/".join(path[:2]), "/".join(path[2:]) or None) + except Exception as e: + logger.error(f"Error proxying Git request: {e}") + abort(404, description=str(e)) + + def main(): """Main function to run the Flask app.""" port = os.environ.get("PORT", 8107)