#!/usr/bin/env python3 import sys import os try: f = open("/var/log/git-srht-shell", "a") os.close(sys.stderr.fileno()) os.dup2(f.fileno(), sys.stderr.fileno()) except Exception as ex: sys.stderr.write("Unable to open log for writing\n") sys.stderr.write(str(ex) + "\n") import requests import shlex from datetime import datetime from srht.config import cfg from srht.validation import Validation from srht.database import DbSession db = DbSession(cfg("git.sr.ht", "connection-string")) from scmsrht.access import has_access, UserAccess from gitsrht.types import User, Repository, RepoVisibility, Redirect from gitsrht.repos import GitRepoApi db.init() def log(s, *args): sys.stderr.write("{} {}\n".format(datetime.now().isoformat(), s.format(*args) if isinstance(s, str) else str(s))) origin = cfg("git.sr.ht", "origin") repos = cfg("git.sr.ht", "repos") _cmd = os.environ.get("SSH_ORIGINAL_COMMAND") if not _cmd: _cmd = "" if len(sys.argv) < 2: log("Error: expected 2 arguments from SSH") sys.exit(1) user_id = sys.argv[1] ssh_key = sys.argv[2] user = User.query.filter(User.id == user_id).first() if not user: log("Unknown user ID {}", user_id) sys.exit(1) log("User: {}", user.username) cmd = shlex.split(_cmd) valid_commands = ["git-receive-pack", "git-upload-pack", "git-upload-archive"] if len(cmd) < 1 or not cmd[0] in valid_commands: log("Not permitting unacceptable command") print("Hi {}! You've successfully authenticated, ".format(user.username) + "but I do not provide an interactive shell. Bye!") sys.exit(128) os.chdir(repos) path = os.path.abspath(cmd[-1]) if not path.startswith(repos): path = os.path.join(repos, path) cmd[-1] = path repo = Repository.query.filter(Repository.path == path).first() if not repo: repo = Redirect.query.filter(Redirect.path == path).first() if repo: repo = repo.new_repo sys.stderr.write("\n\t\033[93mNOTICE\033[0m\n") sys.stderr.write("\tThis repository has moved:\n") # TODO: orgs sys.stderr.write("\t{}/~{}/{}\n".format( origin, repo.owner.username, repo.name)) sys.stderr.write("\tPlease update your remote.\n\n") sys.exit(128) _path, repo_name = os.path.split(path) owner = os.path.basename(_path) if "~" + user.username != owner: sys.exit(128) valid = Validation({ "name": repo_name }) repo_api = GitRepoApi() repo = repo_api.create_repo(valid, user) if not valid.ok: sys.exit(128) repo.visibility = RepoVisibility.autocreated db.session.commit() import gitsrht.types as tables if cmd[0] == "git-receive-pack": if not has_access(repo, UserAccess.write, user, tables=tables): sys.exit(128) else: if not has_access(repo, UserAccess.read, user, tables=tables): sys.exit(128) log("Executing {}", " ".join(cmd)) sys.stderr.close() os.execvp(cmd[0], cmd)