summaryrefslogtreecommitdiffstats
path: root/gitsrht-shell
blob: b75117f2e412a08be86a2c8444f8b925e4d1f429 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#!/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)