4966fb4582e90c758a94961a9df521434b66d941 gperez2 Fri Sep 18 15:08:08 2026 -0700 Updating hgLogin's CILogon-unverified-email wording (choose a username page, address-collision message, and new-account confirmation) for clarity and consistency, refs #38339 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> diff --git src/hg/hgLogin/hgLogin.c src/hg/hgLogin/hgLogin.c index 3811c7338f9..723bed41d8a 100644 --- src/hg/hgLogin/hgLogin.c +++ src/hg/hgLogin/hgLogin.c @@ -421,33 +421,32 @@ * have sent you a mail" paragraph can be printed above it. Below the form it read as if a * confirmation had already gone to whatever was about to be typed into it. The form is only * for an existing account whose address was never confirmed, and only for the person who just * came back from the provider -- pendingIdentityValid() is that check. */ boolean offerNewAddress = fromProvider && isNotEmpty(existingUser) && pendingIdentityValid(); char *encProvider = htmlEncode(provider); char *encAddress = htmlEncode(address); if (fromProvider) { if (isEmpty(existingUser)) { /* An address the provider released and we would not take is not the same as no address * at all, and CILogon is the first case of it (#38339). */ if (isNotEmpty(unverified)) hPrintf("<p>You signed in with %s, and %s does not tell us whether the email " - "address it gave us really belongs to you, so we asked you for one. No %s " - "account uses <b>%s</b> yet, so we are making a new account for it. Confirming " - "the address is the last step.</p>", + "address it gave us belongs to you. A new %s account has been created because " + "no account uses <b>%s</b>.</p>", encProvider, encProvider, brwName, encAddress); else hPrintf("<p>You signed in with %s, and %s did not tell us an email address, so we " "asked you for one. No %s account uses <b>%s</b> yet, so we are making a new " "account for it. Confirming the address is the last step.</p>", encProvider, encProvider, brwName, encAddress); } else { char *encUser = htmlEncode(existingUser); /* Say that the address was changed. Without this the page comes back looking exactly * as it did before the change, the new address being the only sign anything happened. */ if (justChanged) hPrintf("<p>The email address on the %s account <b>%s</b> is now <b>%s</b>.</p>", brwName, encUser, encAddress); @@ -2522,34 +2521,34 @@ * 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). * 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. * Same for a provider that did release an address which we then dropped because it would not * say the address is verified: CILogon does exactly this, and "does not share your email * address with us" was plainly wrong for it (#38339). */ char *unverified = oauthUnverifiedEmail(); if (isEmpty(email) && unverified != NULL) { char *encUnverified = htmlEncode(unverified); hPrintf("<p>%s gave us the email address <b>%s</b>, but does not tell us whether that " - "address really belongs to you, so we cannot use it to sign you in to an account that " - "already has it. Enter an address below and confirm it once; after that this sign-in " - "will work on its own. If you already have an account, use another sign-in option " - "instead.</p>", label, encUnverified); + "address belongs to you. So we cannot use it to sign you in, even if an account " + "already has this address. Enter your email address below. Once it is confirmed, %s " + "will sign you in directly. If you already have an account, use another sign-in " + "option instead.</p>", label, encUnverified, label); freeMem(encUnverified); } else if (isEmpty(email)) hPrintf("<p>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.</p>", brwName, label, label); else if (providerEmail == NULL) hPrintf("<p>We cannot use the email address %s gave us, so please enter one below.</p>", label); printUsernameNote(); hPrintf("<span style='color:red;'>%s</span>", errMsg ? errMsg : ""); hPrintf("<form method=\"post\" action=\"%s\" name=\"completeAccountForm\">", hgLoginUrl); hPrintf("<div class=\"inputGroup\">" "<label for=\"userName\">Username</label>" @@ -2674,42 +2673,40 @@ char query[1024]; char *addrMatch = sqlAddressMatch(email); sqlSafef(query, sizeof(query), "SELECT count(*) FROM gbMembers WHERE %-s AND accountActivated='Y'", addrMatch); freeMem(addrMatch); if (sqlQuickNum(conn, query) > 0) { char buf[1024]; /* The provider may well have handed us this very address and we dropped it for want of * a verified flag (CILogon, #38339). Saying it never gave us the address would be * wrong there, and the way out is a different one: what is missing is the provider's * word that the address is the user's, not the address itself. */ char *unverified = oauthUnverifiedEmail(); if ((unverified != NULL) && sameWord(unverified, email)) safef(buf, sizeof(buf), - "An account with this email address already exists. %s gave us that address but " - "does not tell us that it is yours, so we cannot sign you in to that account. To " - "reach it, sign in with a provider that does confirm your email address, or with " - "your username and password. To create a new account instead, enter a different " - "email address.", oauthProviderLabel(provider)); + "An account with this email address already exists. To sign in to that account, " + "use a sign-in option that verifies your email address, or use your username and " + "password. To create a new account instead, enter a different email address."); else safef(buf, sizeof(buf), "An account with this email address already exists. %s did not give us that " - "address, so we cannot tell that it is yours and cannot sign you in to that " - "account. To reach it, sign in with a provider that does give us your email " - "address, or with your username and password. To create a new account instead, " - "enter a different email address.", oauthProviderLabel(provider)); + "address, so we cannot tell that it belongs to you. To sign in to that account, " + "use a sign-in option that verifies your email address, or use your username and " + "password. To create a new account instead, enter a different email address.", + oauthProviderLabel(provider)); freez(&errMsg); errMsg = cloneString(buf); completeAccountPage(conn); return; } } char *name = cartUsualString(cart, "oauth_pending_name", ""); char *realName = isNotEmpty(name) ? name : user; /* The new account is created "activated" -- its address trusted for future auto-linking (see * resolveIdentity) -- when the address came from the provider. An address the user typed gets * an inactive account and the usual confirmation mail, so a typed address can never be planted * as a trusted one. An install that sends no mail has no way to confirm anything, so there it * is activated on the spot, the same compromise signup() makes. */