From c903985bf7e772e2d08275c1a95c8a55ab011577 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 7 Nov 2024 08:57:52 +0100 Subject: [PATCH 1/2] credential_format(): also encode [:] An upcoming change wants to sanitize the credential password prompt where a URL is displayed that may potentially come from a `.gitmodules` file. To this end, the `credential_format()` function is employed. To sanitize the host name (and optional port) part of the URL, we need a new mode of the `strbuf_add_percentencode()` function because the current mode is both too strict and too lenient: too strict because it encodes `:`, `[` and `]` (which should be left unencoded in `:` and in IPv6 addresses), and too lenient because it does not encode invalid host name characters `/`, `_` and `~`. So let's introduce and use a new mode specifically to encode the host name and optional port part of a URI, leaving alpha-numerical characters, periods, colons and brackets alone and encoding all others. This only leads to a change of behavior for URLs that contain invalid host names. Signed-off-by: Johannes Schindelin --- credential.c | 3 ++- strbuf.c | 4 +++- strbuf.h | 1 + t/t0300-credentials.sh | 13 +++++++++++++ 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/credential.c b/credential.c index f32011343f..572f1785da 100644 --- a/credential.c +++ b/credential.c @@ -164,7 +164,8 @@ static void credential_format(struct credential *c, struct strbuf *out) strbuf_addch(out, '@'); } if (c->host) - strbuf_addstr(out, c->host); + strbuf_add_percentencode(out, c->host, + STRBUF_ENCODE_HOST_AND_PORT); if (c->path) { strbuf_addch(out, '/'); strbuf_add_percentencode(out, c->path, 0); diff --git a/strbuf.c b/strbuf.c index c383f41a3c..756b96c561 100644 --- a/strbuf.c +++ b/strbuf.c @@ -492,7 +492,9 @@ void strbuf_add_percentencode(struct strbuf *dst, const char *src, int flags) unsigned char ch = src[i]; if (ch <= 0x1F || ch >= 0x7F || (ch == '/' && (flags & STRBUF_ENCODE_SLASH)) || - strchr(URL_UNSAFE_CHARS, ch)) + ((flags & STRBUF_ENCODE_HOST_AND_PORT) ? + !isalnum(ch) && !strchr("-.:[]", ch) : + !!strchr(URL_UNSAFE_CHARS, ch))) strbuf_addf(dst, "%%%02X", (unsigned char)ch); else strbuf_addch(dst, ch); diff --git a/strbuf.h b/strbuf.h index f6dbb9681e..f9f8bb0381 100644 --- a/strbuf.h +++ b/strbuf.h @@ -380,6 +380,7 @@ size_t strbuf_expand_dict_cb(struct strbuf *sb, void strbuf_addbuf_percentquote(struct strbuf *dst, const struct strbuf *src); #define STRBUF_ENCODE_SLASH 1 +#define STRBUF_ENCODE_HOST_AND_PORT 2 /** * Append the contents of a string to a strbuf, percent-encoding any characters diff --git a/t/t0300-credentials.sh b/t/t0300-credentials.sh index c66d91e82d..cb91be1427 100755 --- a/t/t0300-credentials.sh +++ b/t/t0300-credentials.sh @@ -514,6 +514,19 @@ test_expect_success 'match percent-encoded values in username' ' EOF ' +test_expect_success 'match percent-encoded values in hostname' ' + test_config "credential.https://a%20b%20c/.helper" "$HELPER" && + check fill <<-\EOF + url=https://a b c/ + -- + protocol=https + host=a b c + username=foo + password=bar + -- + EOF +' + test_expect_success 'fetch with multiple path components' ' test_unconfig credential.helper && test_config credential.https://example.com/foo/repo.git.helper "verbatim foo bar" && -- 2.47.1