credential_format(): also encode <host>[:<port>]

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
`<host>:<port>` 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 <johannes.schindelin@gmx.de>
main
Johannes Schindelin 2024-11-07 08:57:52 +01:00
parent 83b08eb19f
commit c903985bf7
4 changed files with 19 additions and 2 deletions

View File

@ -164,7 +164,8 @@ static void credential_format(struct credential *c, struct strbuf *out)
strbuf_addch(out, '@'); strbuf_addch(out, '@');
} }
if (c->host) if (c->host)
strbuf_addstr(out, c->host); strbuf_add_percentencode(out, c->host,
STRBUF_ENCODE_HOST_AND_PORT);
if (c->path) { if (c->path) {
strbuf_addch(out, '/'); strbuf_addch(out, '/');
strbuf_add_percentencode(out, c->path, 0); strbuf_add_percentencode(out, c->path, 0);

View File

@ -492,7 +492,9 @@ void strbuf_add_percentencode(struct strbuf *dst, const char *src, int flags)
unsigned char ch = src[i]; unsigned char ch = src[i];
if (ch <= 0x1F || ch >= 0x7F || if (ch <= 0x1F || ch >= 0x7F ||
(ch == '/' && (flags & STRBUF_ENCODE_SLASH)) || (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); strbuf_addf(dst, "%%%02X", (unsigned char)ch);
else else
strbuf_addch(dst, ch); strbuf_addch(dst, ch);

View File

@ -380,6 +380,7 @@ size_t strbuf_expand_dict_cb(struct strbuf *sb,
void strbuf_addbuf_percentquote(struct strbuf *dst, const struct strbuf *src); void strbuf_addbuf_percentquote(struct strbuf *dst, const struct strbuf *src);


#define STRBUF_ENCODE_SLASH 1 #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 * Append the contents of a string to a strbuf, percent-encoding any characters

View File

@ -514,6 +514,19 @@ test_expect_success 'match percent-encoded values in username' '
EOF 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_expect_success 'fetch with multiple path components' '
test_unconfig credential.helper && test_unconfig credential.helper &&
test_config credential.https://example.com/foo/repo.git.helper "verbatim foo bar" && test_config credential.https://example.com/foo/repo.git.helper "verbatim foo bar" &&