Commit Diff


commit - b1ebf3b36ff38d95f3c552bcddb2ad4c3e910d06
commit + 050c0b8ca3bc56e34b304d886ed11ec58badadf2
blob - 9c8a90e392c27e03eb1dd32a88414aa62a355012
blob + 4adb82067f778d138e3c0dd4a7cb34decdbf52af
--- gotd/libexec/got-notify-http/got-notify-http.c
+++ gotd/libexec/got-notify-http/got-notify-http.c
@@ -729,18 +729,71 @@ jsonify(FILE *fp, const char *repo)
 
 	return 0;
 }
+
+static char
+sixet2ch(int c)
+{
+	c &= 0x3F;
 
+	if (c < 26)
+		return 'A' + c;
+	c -= 26;
+	if (c < 26)
+		return 'a' + c;
+	c -= 26;
+	if (c < 10)
+		return '0' + c;
+	c -= 10;
+	if (c == 0)
+		return '+';
+	if (c == 1)
+		return '/';
+
+	errx(1, "invalid sixet 0x%x", c);
+}
+
 static char *
 basic_auth(const char *username, const char *password)
 {
-	char	*tmp;
-	int	 len;
+	char	*str, *tmp, *end, *s, *p;
+	char	 buf[3];
+	int	 len, i, r;
 
-	len = asprintf(&tmp, "%s:%s", username, password);
-	if (len == -1)
+	r = asprintf(&str, "%s:%s", username, password);
+	if (r == -1)
 		err(1, "asprintf");
 
-	/* XXX base64-ify */
+	/*
+	 * Will need 4 * r/3 bytes to encode the string, plus a
+	 * rounding to the next multiple of 4 for padding, plus NUL.
+	 */
+	len = 4 * r / 3;
+	len = (len + 3) & ~3;
+	len++;
+
+	tmp = calloc(1, len);
+	if (tmp == NULL)
+		err(1, "malloc");
+
+	s = str;
+	p = tmp;
+	while (*s != '\0') {
+		memset(buf, 0, sizeof(buf));
+		for (i = 0; i < 3 && *s != '\0'; ++i, ++s)
+			buf[i] = *s;
+
+		*p++ = sixet2ch(buf[0] >> 2);
+		*p++ = sixet2ch((buf[1] >> 4) | (buf[0] << 4));
+		if (i > 1)
+			*p++ = sixet2ch((buf[1] << 2) | (buf[2] >> 6));
+		if (i > 2)
+			*p++ = sixet2ch(buf[2]);
+	}
+
+	for (end = tmp + len - 1; p < end; ++p)
+		*p = '=';
+
+	free(str);
 	return tmp;
 }
 
blob - 682368c09afd8f26371f3c0eb5b63f700ac39026
blob + abc10999b714c055c44b01f7d380e97962a222f8
--- gotd/notify.c
+++ gotd/notify.c
@@ -161,7 +161,8 @@ gotd_notify_sighdlr(int sig, short event, void *arg)
 }
 
 static void
-run_notification_helper(const char *prog, const char **argv, int fd)
+run_notification_helper(const char *prog, const char **argv, int fd,
+    const char *user, const char *pass)
 {
 	const struct got_error *err = NULL;
 	pid_t pid;
@@ -184,6 +185,11 @@ run_notification_helper(const char *prog, const char *
 		}
 
 		closefrom(STDERR_FILENO + 1);
+
+		if (user != NULL && pass != NULL) {
+			setenv("GOT_NOTIFY_HTTP_USER", user, 1);
+			setenv("GOT_NOTIFY_HTTP_PASS", pass, 1);
+		}
 
 		if (execv(prog, (char *const *)argv) == -1) {
 			fprintf(stderr, "%s: exec %s: %s\n", getprogname(),
@@ -249,7 +255,8 @@ notify_email(struct gotd_notification_target *target, 
 
 	argv[i] = NULL;
 
-	run_notification_helper(GOTD_PATH_PROG_NOTIFY_EMAIL, argv, fd);
+	run_notification_helper(GOTD_PATH_PROG_NOTIFY_EMAIL, argv, fd,
+	    NULL, NULL);
 }
 
 static void
@@ -273,7 +280,8 @@ notify_http(struct gotd_notification_target *target, c
 
 	argv[argc] = NULL;
 
-	run_notification_helper(GOTD_PATH_PROG_NOTIFY_HTTP, argv, fd);
+	run_notification_helper(GOTD_PATH_PROG_NOTIFY_HTTP, argv, fd,
+	    target->conf.http.user, target->conf.http.password);
 }
 
 static const struct got_error *
blob - 0dee7475233829d5d5fc2cc3f028cfc7789ce428
blob + c00bf5c27253d88367260cc43d44b187d066276e
--- regress/gotd/Makefile
+++ regress/gotd/Makefile
@@ -188,7 +188,7 @@ start_gotd_http_notification: ensure_root
 	@echo '    path "$(GOTD_TEST_REPO)"' >> $(PWD)/gotd.conf
 	@echo '    permit rw $(GOTD_DEVUSER)' >> $(PWD)/gotd.conf
 	@echo '    notify {' >> $(PWD)/gotd.conf
-	@echo '         url "http://localhost:${GOTD_TEST_HTTP_PORT}/"' >> $(PWD)/gotd.conf
+	@echo '         url "http://localhost:${GOTD_TEST_HTTP_PORT}/" user flan password "password"' >> $(PWD)/gotd.conf
 	@echo "    }" >> $(PWD)/gotd.conf
 	@echo "}" >> $(PWD)/gotd.conf
 	@$(GOTD_TRAP); $(GOTD_START_CMD)
blob - 5cbff3264bfe341856058856515d41c34ed996bf
blob + a9297fb4c098dec8fe8f0e0da89a4516a4ddaecc
--- regress/gotd/http-server
+++ regress/gotd/http-server
@@ -18,10 +18,11 @@ use v5.36;
 use IPC::Open2;
 use Getopt::Long qw(:config bundling);
 
+my $auth;
 my $port = 8000;
 
-GetOptions("p:i" => \$port)
-    or die("usage: $0 [-p port]\n");
+GetOptions("a:s" => \$auth, "p:i" => \$port)
+    or die("usage: $0 [-a auth] [-p port]\n");
 
 my $pid = open2(my $out, my $in, 'nc', '-l', 'localhost', $port);
 
@@ -61,6 +62,15 @@ while (<$out>) {
 		    unless m/Connection: close$/;
 		next;
 	}
+
+	if (m/Authorization/) {
+		die "bad authorization header"
+		    unless m/Authorization: basic (.*)$/;
+		my $t = $1;
+		die "wrong authorization; got $t want $auth"
+		    if not defined($auth) or $auth ne $t;
+		next;
+	}
 }
 
 die "no Content-Length header" unless defined $clen;
blob - 38661743a189d324f50db59d65ebfb278ed84eff
blob + 18726da0df985a0e71d65fb2408032c6677ffe00
--- regress/gotd/http_notification.sh
+++ regress/gotd/http_notification.sh
@@ -17,6 +17,9 @@
 . ../cmdline/common.sh
 . ./common.sh
 
+# flan:password encoded in base64
+AUTH="ZmxhbjpwYXNzd29yZA=="
+
 test_file_changed() {
 	local testroot=`test_init file_changed 1`
 
@@ -41,7 +44,7 @@ test_file_changed() {
 	local commit_id=`git_show_head $testroot/repo-clone`
 	local author_time=`git_show_author_time $testroot/repo-clone`
 
-	timeout 5 ./http-server -p $GOTD_TEST_HTTP_PORT \
+	timeout 5 ./http-server -a $AUTH -p $GOTD_TEST_HTTP_PORT \
 	    > $testroot/stdout &
 
 	got send -b main -q -r $testroot/repo-clone
@@ -134,7 +137,7 @@ test_bad_utf8() {
 	local commit_id=`git_show_head $testroot/repo-clone`
 	local author_time=`git_show_author_time $testroot/repo-clone`
 
-	timeout 5 ./http-server -p $GOTD_TEST_HTTP_PORT \
+	timeout 5 ./http-server -a $AUTH -p $GOTD_TEST_HTTP_PORT \
 	    > $testroot/stdout &
 
 	got send -b main -q -r $testroot/repo-clone
@@ -229,7 +232,7 @@ test_many_commits_not_summarized() {
 		set -- "$@" "$commit_id $d"
 	done
 
-	timeout 5 ./http-server -p "$GOTD_TEST_HTTP_PORT" \
+	timeout 5 ./http-server -a $AUTH -p "$GOTD_TEST_HTTP_PORT" \
 	    > $testroot/stdout &
 
 	got send -b main -q -r $testroot/repo-clone
@@ -334,7 +337,7 @@ test_many_commits_summarized() {
 		set -- "$@" "$short_commit_id $d"
 	done
 
-	timeout 5 ./http-server -p "$GOTD_TEST_HTTP_PORT" \
+	timeout 5 ./http-server -a $AUTH -p "$GOTD_TEST_HTTP_PORT" \
 	    > $testroot/stdout &
 
 	got send -b main -q -r $testroot/repo-clone
@@ -414,7 +417,7 @@ test_branch_created() {
 	local commit_id=`git_show_branch_head $testroot/repo-clone newbranch`
 	local author_time=`git_show_author_time $testroot/repo-clone $commit_id`
 
-	timeout 5 ./http-server -p "$GOTD_TEST_HTTP_PORT" \
+	timeout 5 ./http-server -a $AUTH -p "$GOTD_TEST_HTTP_PORT" \
 	    > $testroot/stdout &
 
 	got send -b newbranch -q -r $testroot/repo-clone
@@ -501,7 +504,7 @@ test_branch_removed() {
 		return 1
 	fi
 
-	timeout 5 ./http-server -p "$GOTD_TEST_HTTP_PORT" \
+	timeout 5 ./http-server -a $AUTH -p "$GOTD_TEST_HTTP_PORT" \
 	    > $testroot/stdout &
 
 	local commit_id=`git_show_branch_head $testroot/repo-clone newbranch`
@@ -556,7 +559,7 @@ test_tag_created() {
 	local commit_id=`git_show_head $testroot/repo-clone`
 	local tagger_time=`git_show_tagger_time $testroot/repo-clone 1.0`
 
-	timeout 5 ./http-server -p "$GOTD_TEST_HTTP_PORT" \
+	timeout 5 ./http-server -a $AUTH -p "$GOTD_TEST_HTTP_PORT" \
 	    >$testroot/stdout &
 
 	got send -t 1.0 -q -r $testroot/repo-clone
@@ -634,7 +637,7 @@ test_tag_changed() {
 	got tag -r $testroot/repo-clone -m "new tag" 1.0 > /dev/null
 	local tagger_time=`git_show_tagger_time $testroot/repo-clone 1.0`
 
-	timeout 5 ./http-server -p "$GOTD_TEST_HTTP_PORT" \
+	timeout 5 ./http-server -a $AUTH -p "$GOTD_TEST_HTTP_PORT" \
 	    > $testroot/stdout &
 
 	got send -f -t 1.0 -q -r $testroot/repo-clone