b1a27c93758e1f12cd212f1293d9f3ec9bbfb0af max Mon Sep 14 14:53:21 2026 -0700 hgLogin: do not blame the provider when it sent an address we cannot use The "choose a username" page decided what to say by asking whether oauthProviderEmail() had returned an address, but that returns NULL both when the provider released nothing and when it released something spc_email_isvalid rejects, which is every address containing a byte >= 127. A user arriving with a non-ASCII address was therefore told that their provider "does not share your email address with us", which is untrue, and then asked to type one. Key the explanation on whether an address arrived at all, and say plainly that we could not use the one we were sent in the case where one did. refs #38341 diff --git src/hg/hgLogin/hgLogin.c src/hg/hgLogin/hgLogin.c index 541e90f019f..a7d1aa73d01 100644 --- src/hg/hgLogin/hgLogin.c +++ src/hg/hgLogin/hgLogin.c @@ -2377,36 +2377,43 @@ if (isEmpty(suggested)) suggested = suggestUsername(conn, email, name); char *encSuggested = htmlEncode(suggested); // both go into value="" attributes; escape (XSS) char *label = oauthProviderLabel(provider); hPrintf("
" "

%s

", brwName); hPrintf("

Choose a username

"); hPrintf("

You signed in with %s. Pick a username for your new %s account. " "You can change the suggested name below.

", label, brwName); /* Explain why this is always a new account when the provider released no address (ORCID does * this by design: its OpenID Connect offers only the "openid" scope, so the ORCID iD is all we * ever get). Without an address we cannot tell a returning user from a new one, so every first * sign-in lands here, which surprised real users (#38341). Keyed on whether an address arrived, * not on the provider's name: a mirror can call a provider anything it likes in hg.conf, so a - * name test would silently miss it (#38213). */ -if (providerEmail == NULL) + * name test would silently miss it (#38213). + * Test whether anything arrived, not whether oauthProviderEmail() accepted it. A provider that + * sends an address we cannot use -- spc_email_isvalid rejects every byte >= 127, so any + * non-ASCII address -- also leaves us asking for one, but telling that user the provider shares + * no address would be simply untrue. */ +if (isEmpty(email)) hPrintf("

A new %s account is created for any %s sign-in we have not seen before, because " "%s does not share your email address with us. So you cannot sign in to an existing " "account this way. Use another sign-in option if you do not want to create a new " "account.

", brwName, label, label); +else if (providerEmail == NULL) + hPrintf("

We cannot use the email address %s gave us, so please enter one below.

", + label); printUsernameNote(); hPrintf("%s", errMsg ? errMsg : ""); hPrintf("
", hgLoginUrl); hPrintf("
" "" "" "
", encSuggested); if (providerEmail == NULL) { /* No address from the provider, so we have to ask -- and because anyone can type anything * here, the account is not usable until the mailed link is opened. Say that next to the box * rather than springing the confirmation page on the user after they submit. Show back what * they typed so an error does not wipe the address they are being asked to correct. */ char *encTyped = htmlEncode(cartUsualString(cart, "hgLogin_email", "")); hPrintf("
"