commit 050c0b8ca3bc56e34b304d886ed11ec58badadf2 from: Omar Polo date: Tue Apr 16 12:13:42 2024 UTC got-notify-http: implement basic authentication ok stsp 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