From: Stefan Sperling Subject: gotwebd login status and logout link To: gameoftrees@openbsd.org Date: Sat, 7 Feb 2026 15:39:46 +0100 Make gotwebd display the name of the logged in user, and add a link which can be clicked to log out (asking the browser to delete the auth cookie). ok? M gotwebd/auth.c | 65+ 0- M gotwebd/fcgi.c | 6+ 0- M gotwebd/files/htdocs/gotwebd/gotweb.css | 9+ 0- M gotwebd/gotweb.c | 6+ 0- M gotwebd/gotwebd.h | 3+ 0- M gotwebd/pages.tmpl | 12+ 1- M gotwebd/sockets.c | 3+ 0- M include/got_error.h | 1+ 0- M lib/error.c | 1+ 0- M regress/gotsysd/test_gotwebd.sh | 6+ 0- M regress/gotsysd/test_gotwebd_repos_www.sh | 1+ 0- 11 files changed, 113 insertions(+), 1 deletion(-) commit - cc8eaf00fec74bd43bc96a5daedef4c8540964bf commit + 0b654469a1c4fc80c19dd929a6ff463be03c24ea blob - 3e9cee3c275c4af7cd66b09401c857dac8177c95 blob + e2dbe8fa26b762709ae7cfc950d4c8fe3dab6c38 --- gotwebd/auth.c +++ gotwebd/auth.c @@ -420,6 +420,69 @@ err: } } +static void +do_logout(struct request *c) +{ + const struct got_error *error = NULL; + struct gotwebd *env = gotwebd_env; + uid_t uid; + char *hostname = NULL; + const char *identifier = NULL; + struct gotweb_url url; + + int r; + + if (login_check_token(&uid, &hostname, c->fcgi_params.auth_cookie, + auth_token_secret, sizeof(auth_token_secret), + "authentication") == -1) { + error = got_error(GOT_ERR_LOGOUT_FAILED); + goto err; + } + + /* + * The www user ID represents the case where no authentication + * occurred. This user must not be allowed to log in. + */ + if (uid == env->www_uid) { + error = got_error(GOT_ERR_LOGOUT_FAILED); + goto err; + } + + c->client_uid = uid; + if (strcmp(hostname, c->fcgi_params.server_name) != 0) { + error = got_error_msg(GOT_ERR_LOGOUT_FAILED, + "wrong server name in authentication cookie"); + goto err; + } + + if (gotwebd_env->gotwebd_verbose > 0) { + log_info("logging out uid %u as %s for server \"%s\"", + uid, identifier, hostname); + } + + /* Ask the browser to delete the authentication cookie. */ + r = tp_writef(c->tp, "Clear-Site-Data: \"cookies\"\r\n"); + if (r == -1) { + error = got_error_from_errno("tp_writef"); + goto err; + } + + memset(&url, 0, sizeof(url)); + url.action = INDEX; + gotweb_reply(c, 307, "text/html", &url); + return; + +err: + free(hostname); + hostname = NULL; + + log_warnx("%s: %s", __func__, error->msg); + c->t->error = error; + if (gotweb_reply(c, 400, "text/html", NULL) == -1) + return; + gotweb_render_page(c->tp, gotweb_render_error); +} + static const struct got_error * login_error_hint(struct request *c) { @@ -760,6 +823,8 @@ auth_dispatch_sockets(int fd, short event, void *arg) if (c->fcgi_params.qs.login[0] != '\0') do_login(c); + else if (c->fcgi_params.qs.logout) + do_logout(c); else process_request(c); blob - 2a81e7f5e7e6523aa37d8d9e15a0ab325483eb37 blob + 3aa0806a14d767bd4f2ead5eea1fec881a7c5e9c --- gotwebd/fcgi.c +++ gotwebd/fcgi.c @@ -192,6 +192,7 @@ static const struct querystring_keys querystring_keys[ { "index_page", GOTWEBD_QS_INDEX_PAGE }, { "path", GOTWEBD_QS_PATH }, { "login", GOTWEBD_QS_LOGIN }, + { "logout", GOTWEBD_QS_LOGOUT }, }; static const struct action_keys action_keys[] = { @@ -380,6 +381,11 @@ assign_querystring(struct querystring *qs, char *key, goto done; } break; + case GOTWEBD_QS_LOGOUT: + if (strcmp(value, "1") != 0) + break; + qs->logout = 1; + break; } /* entry found */ blob - ea4cdedb51cb3f930bbc483b0f82bc9590a180b6 blob + 15e6ffef2c615352d5e23d6ef94fe1e37fb9dff1 --- gotwebd/files/htdocs/gotwebd/gotweb.css +++ gotwebd/files/htdocs/gotwebd/gotweb.css @@ -101,6 +101,15 @@ hr { padding-bottom: 10px; padding-top: 10px; } +#login_status { + color: lightgrey; + text-align: right; + padding-right: 10px; + padding-left: 10px; + padding-top: 5px; + padding-bottom: 5px; + font-weight: monospace; +} #np_wrapper { width: 100%; border-bottom: 1px dotted #444444; blob - 2dcdf486c002a5a2a948db88611b6912fc1de984 blob + 21603a5b4142f0537aca3e2741d0930cb22ef6b8 --- gotwebd/gotweb.c +++ gotwebd/gotweb.c @@ -1469,6 +1469,12 @@ gotweb_render_url(struct request *c, struct gotweb_url sep = "&"; } + if (url->logout == 1) { + if (tp_writef(c->tp, "%slogout=1", sep) == -1) + return -1; + sep = "&"; + } + return 0; } blob - 69c2896f72735357062dc4f09af598567a4aa339 blob + e308c7906f34668208667e5f2742f917d90a6df7 --- gotwebd/gotwebd.h +++ gotwebd/gotwebd.h @@ -311,6 +311,7 @@ struct querystring { int index_page; char path[PATH_MAX]; char login[MAX_AUTH_COOKIE]; + int logout; }; struct gotwebd_fcgi_params { @@ -556,6 +557,7 @@ struct gotweb_url { const char *folder; const char *headref; const char *path; + int logout; }; struct querystring_keys { @@ -577,6 +579,7 @@ enum querystring_elements { GOTWEBD_QS_INDEX_PAGE, GOTWEBD_QS_PATH, GOTWEBD_QS_LOGIN, + GOTWEBD_QS_LOGOUT, }; extern struct gotwebd *gotwebd_env; blob - 4fb768f84e038e9bdfc9ee78a9e9c615084cb757 blob + 620eae4ecfde34d2e50eb56fa4eb94374d73fe0d --- gotwebd/pages.tmpl +++ gotwebd/pages.tmpl @@ -169,7 +169,7 @@ nextsep(char *s, char **t) struct request *c = tp->tp_arg; struct server *srv = c->srv; const struct querystring *qs = c->t->qs; - struct gotweb_url u_path; + struct gotweb_url u_path, u_logout; char prefix[MAX_DOCUMENT_URI * 2]; const char *css = srv->custom_css; const char *url_root, *url_path; @@ -198,6 +198,11 @@ nextsep(char *s, char **t) memset(&u_path, 0, sizeof(u_path)); u_path.index_page = -1; u_path.action = SUMMARY; + + memset(&u_logout, 0, sizeof(u_logout)); + u_logout.index_page = -1; + u_logout.action = INDEX; + u_logout.logout = 1; !} @@ -221,6 +226,12 @@ nextsep(char *s, char **t) + {{ if (c->access_identifier[0]) }} +
+ Logged in as: {{ c->access_identifier }}   + (Logout) +
+ {{ end }}