summaryrefslogtreecommitdiff
path: root/EndoForge/src/AnonymousAccessCommand
blob: 082f185e8d26d9d3825aebfe08d07a42b5e765af (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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#!/bin/sh
default_msg()
{
    sshfpline="$(get_sshfp_authline ${SSH_CLIENT%% *})"
    cat <<EOF >&2

    You are:

        $authline
        $sshfpline

EOF
}

not_self_forge_message()
{
    cat <<EOF >&2
Error: access denied.  The specified directory is not a self-forge.

    To enable anonymous access, use the following commands:

        ssh $(id -un)@$(hostname)
        cd "$1"
        git config core.self-forge true

EOF
}

get_sshfp_authline()
{
    (
        r=${1:-.}
        key=$(mktemp) || exit
        trap 'rm -rf "$key"' EXIT
        echo "$authline" > "$key"
        get_sshfp "$key" "$r"
    )
}

get_sshfp()
{
    (
        key="$1"
        r="${2:-.}"
        dns=$(mktemp) || exit
        trap 'rm -rf "$dns"' EXIT

        ssh-keygen -r "$r" -f "$key" > "$dns"
        exec < "$dns"
        while read line
        do
            set -- $line
            if [ "$3 $5" = "SSHFP 2" ]
            then
                echo "$line"
                break
            fi
        done
    )
}

ssh_client_fingerprint_base16()
{
    set -- $(get_sshfp_authline)
    [ "$6" ]
    echo $6
}

is_self_forge()
{
    local dir="$1" confval
    [ -d "$dir" ] || return
    confval=$(GIT_DIR=$dir git config core.self-forge) || return
    [ "$confval" = true ]
}

with_soul_bare()
{
    (
        set -eC
        lockfile=$GIT_DIR/index.lock
        echo $$ > "$lockfile"
        trap 'rm -f "$lockfile"' EXIT

        git config core.bare true
        "$@"
        git config core.bare false
    )
}

unsupported()
{
    echo "$0: Error: unsupported" >&2
}

read authtype authline < "$SSH_USER_AUTH" || exit
[ "$authtype" = publickey ] || exit

cmd=${SSH_ORIGINAL_COMMAND%% *}
case "$cmd" in
    git-send-pack | git-upload-pack | git-receive-pack ) ;;
    * )
        default_msg
        exit
        ;;
esac

arg=${SSH_ORIGINAL_COMMAND#* }
arg=${arg%\'}
arg=${arg#\'}
case "$arg" in
    *\'* )
        unsupported
        exit
        ;;
esac

if ! dir=$(readlink -e "$arg")
then exit
elif [ -d "$dir"/.git ]
then dir=$dir/.git
fi

if ! is_self_forge "$dir"
then
    not_self_forge_message "$arg"
    exit
fi

case "$cmd" in
    git-send-pack | git-upload-pack )
        GIT_NAMESPACE=
        "$cmd" "$dir"
        ;;
    git-receive-pack )
        export GIT_NAMESPACE="$(ssh_client_fingerprint_base16)"
        [ "$GIT_NAMESPACE" ]
        GIT_DIR=$dir with_soul_bare "$cmd" "$dir"
        ;;
esac