aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--git_hooks_client/git_hooks_client.c29
-rw-r--r--git_hooks_handle.go24
-rw-r--r--ssh_handle_receive_pack.go37
3 files changed, 87 insertions, 3 deletions
diff --git a/git_hooks_client/git_hooks_client.c b/git_hooks_client/git_hooks_client.c
index fa3e04c..541e606 100644
--- a/git_hooks_client/git_hooks_client.c
+++ b/git_hooks_client/git_hooks_client.c
@@ -14,6 +14,16 @@ int main(int argc, char *argv[]) {
dprintf(STDERR_FILENO, "environment variable LINDENII_FORGE_HOOKS_SOCKET_PATH undefined\n");
return EXIT_FAILURE;
}
+ const char *cookie = getenv("LINDENII_FORGE_HOOKS_COOKIE");
+ if (cookie == NULL) {
+ dprintf(STDERR_FILENO, "environment variable LINDENII_FORGE_HOOKS_COOKIE undefined\n");
+ return EXIT_FAILURE;
+ }
+ if (strlen(cookie) != 64) {
+ dprintf(STDERR_FILENO, "environment variable LINDENII_FORGE_HOOKS_COOKIE is not 64 characters long, something has gone wrong\n");
+ dprintf(STDERR_FILENO, "%s\n", cookie);
+ return EXIT_FAILURE;
+ }
/*
* All hooks in git (see builtin/receive-pack.c) use a pipe by setting
@@ -83,7 +93,24 @@ int main(int argc, char *argv[]) {
}
/*
- * First we report argc and argv to the UNIX domain socket.
+ * We first send the 64-byte cookie to the UNIX domain socket
+ */
+ ssize_t cookie_bytes_sent = send(sock, cookie, 64, 0);
+ switch (cookie_bytes_sent) {
+ case -1:
+ perror("send cookie");
+ close(sock);
+ return EXIT_FAILURE;
+ case 64:
+ break;
+ default:
+ dprintf(STDERR_FILENO, "send returned unexpected value on internal socket\n");
+ close(sock);
+ return EXIT_FAILURE;
+ }
+
+ /*
+ * Next we can report argc and argv to the UNIX domain socket.
*/
uint64_t argc64 = (uint64_t)argc;
ssize_t bytes_sent = send(sock, &argc64, sizeof(argc64), 0);
diff --git a/git_hooks_handle.go b/git_hooks_handle.go
index 5cb59ce..4e3d93d 100644
--- a/git_hooks_handle.go
+++ b/git_hooks_handle.go
@@ -31,6 +31,21 @@ func hooks_handle_connection(conn net.Conn) {
return
}
+ cookie := make([]byte, 64)
+ _, err = conn.Read(cookie)
+ if err != nil {
+ conn.Write([]byte{1})
+ fmt.Fprintln(conn, "Failed to read cookie:", err.Error())
+ return
+ }
+
+ deployer_chan, ok := hooks_cookie_deployer.Load(string(cookie))
+ if !ok {
+ conn.Write([]byte{1})
+ fmt.Fprintln(conn, "Invalid cookie")
+ return
+ }
+
var argc64 uint64
err = binary.Read(conn, binary.NativeEndian, &argc64)
if err != nil {
@@ -57,7 +72,14 @@ func hooks_handle_connection(conn net.Conn) {
args = append(args, arg.String())
}
- conn.Write([]byte{0})
+ callback := make(chan struct{})
+
+ deployer_chan <- hooks_cookie_deployer_return{
+ args: args,
+ callback: callback,
+ conn: conn,
+ }
+ <-callback
}
func serve_git_hooks(listener net.Listener) error {
diff --git a/ssh_handle_receive_pack.go b/ssh_handle_receive_pack.go
index 58f99da..214fa2a 100644
--- a/ssh_handle_receive_pack.go
+++ b/ssh_handle_receive_pack.go
@@ -1,16 +1,27 @@
package main
import (
+ "crypto/rand"
"errors"
"fmt"
+ "net"
"os"
"os/exec"
glider_ssh "github.com/gliderlabs/ssh"
+ "go.lindenii.runxiyu.org/lindenii-common/cmap"
)
var err_unauthorized_push = errors.New("You are not authorized to push to this repository")
+type hooks_cookie_deployer_return struct {
+ args []string
+ callback chan struct{}
+ conn net.Conn
+}
+
+var hooks_cookie_deployer = cmap.ComparableMap[string, chan hooks_cookie_deployer_return]{}
+
func ssh_handle_receive_pack(session glider_ssh.Session, pubkey string, repo_identifier string) (err error) {
repo_path, access, err := get_repo_path_perms_from_ssh_path_pubkey(session.Context(), repo_identifier, pubkey)
if err != nil {
@@ -20,8 +31,20 @@ func ssh_handle_receive_pack(session glider_ssh.Session, pubkey string, repo_ide
return err_unauthorized_push
}
+ cookie, err := random_urlsafe_string(16)
+ if err != nil {
+ fmt.Fprintln(session.Stderr(), "Error while generating cookie:", err)
+ }
+
+ c := make(chan hooks_cookie_deployer_return)
+ hooks_cookie_deployer.Store(cookie, c)
+ defer hooks_cookie_deployer.Delete(cookie)
+
proc := exec.CommandContext(session.Context(), "git-receive-pack", repo_path)
- proc.Env = append(os.Environ(), "LINDENII_FORGE_HOOKS_SOCKET_PATH="+config.Hooks.Socket)
+ proc.Env = append(os.Environ(),
+ "LINDENII_FORGE_HOOKS_SOCKET_PATH="+config.Hooks.Socket,
+ "LINDENII_FORGE_HOOKS_COOKIE="+cookie,
+ )
proc.Stdin = session
proc.Stdout = session
proc.Stderr = session.Stderr()
@@ -32,6 +55,12 @@ func ssh_handle_receive_pack(session glider_ssh.Session, pubkey string, repo_ide
return err
}
+ deployer := <-c
+
+ deployer.conn.Write([]byte{1})
+
+ deployer.callback <- struct{}{}
+
err = proc.Wait()
if exitError, ok := err.(*exec.ExitError); ok {
fmt.Fprintln(session.Stderr(), "Process exited with error", exitError.ExitCode())
@@ -41,3 +70,9 @@ func ssh_handle_receive_pack(session glider_ssh.Session, pubkey string, repo_ide
return err
}
+
+func random_string(sz int) (string, error) {
+ r := make([]byte, sz)
+ _, err := rand.Read(r)
+ return string(r), err
+}