dccbd05b94e1a9323a61a14df17ac93b25aee9d3 gperez2 Thu Sep 17 09:48:20 2026 -0700 Updating hgLogin's recovery-email wording (heading, menu link, description, and confirmation mail) for clarity and to match Change password/Change email, refs #38197 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> diff --git src/hg/hgLogin/hgLogin.c src/hg/hgLogin/hgLogin.c index a51106c0598..0fdc857f89f 100644 --- src/hg/hgLogin/hgLogin.c +++ src/hg/hgLogin/hgLogin.c @@ -1257,31 +1257,32 @@ char expStr[32]; safef(expStr, sizeof(expStr), "%ld", clock1() + 7*24*3600); // link good for a week char *sig = recovEmailSig(user, recovEmail, curRecov, curVerified, expStr); char url[1024]; safef(url, sizeof(url), "%s?hgLogin.do.confirmRecovEmail=1&user=%s&recovEmail=%s&exp=%s&sig=%s", hgLoginUrl, cgiEncode(user), cgiEncode(recovEmail), expStr, sig); char subject[256]; safef(subject, sizeof(subject), "Confirm your %s recovery email address", brwName); char *remoteAddr = getenv("REMOTE_ADDR"); char message[4096]; safef(message, sizeof(message), "Someone (probably you, from IP address %s) gave this address as the recovery email address " "for the %s account \"%s\".\nTo confirm that this mailbox is yours, open this link in your " "browser:\n\n%s\n\nThe link works once and expires in seven days. Until it is opened, this " - "address cannot be used to sign in to that account and will not receive a password reset.\n\n" + "email address cannot be used to sign in to that account and will not receive a " + "password-reset email.\n\n" "If this is *not* you, do not open the link: someone typed your address by mistake, and " "ignoring this message is all it takes to keep them from using it.\n\n%s\n%s", emptyForNull(remoteAddr), brwName, user, url, signature, returnAddr); /* Not sendActMailOut(): that exits the CGI when the address will not take mail, which would * end the signup response after the account has already been created and its activation mail * sent. A recovery address is optional and easy to mistype, so a bad one must not derail * signing up -- the address simply stays unconfirmed, which is the safe state. */ if (mailViaPipeBounce(recovEmail, subject, message, returnAddr) == -1) fprintf(stderr, "hgLogin: could not mail recovery-address confirmation to %s for account " "%s\n", recovEmail, user); freeMem(sig); } static void sendRecovEmailChangeAlertMail(char *email, char *user, char *newRecov) /* Tell the account's main address that its recovery address just changed, so its owner finds @@ -1516,31 +1517,31 @@ sqlFreeResult(&sr); char *expected = recovEmailSig(user, recovEmail, emptyForNull(curRecov), emptyForNull(curVerified), expStr); boolean sigOk = isNotEmpty(sig) && sameString(sig, expected); freeMem(expected); if (!sigOk || isEmpty(user) || spc_email_isvalid(recovEmail) == 0) { freez(&errMsg); errMsg = cloneString("This confirmation link is not valid or has already been used."); displayLoginPage(conn); return; } if (clock1() > atol(expStr)) { freez(&errMsg); - errMsg = cloneString("This confirmation link has expired."); + errMsg = cloneString("This confirmation link has expired. Please request a new one."); displayLoginPage(conn); return; } /* Set the address as well as the flag: for a signup this rewrites the same value, and for a * change this is the point at which the new address takes effect. */ sqlSafef(query, sizeof(query), "UPDATE gbMembers SET recovEmail='%s', recovEmailVerified='Y', lastUse=NOW() " "WHERE userName='%s'", recovEmail, user); sqlUpdate(conn, query); /* A change, not a signup confirmation: tell the main address, so a hijack gets noticed. */ if (isNotEmpty(curRecov) && differentWord(curRecov, recovEmail)) { sqlSafef(query, sizeof(query), "SELECT email FROM gbMembers WHERE userName='%s'", user); char *email = sqlQuickString(conn, query); if (isNotEmpty(email)) @@ -1578,40 +1579,43 @@ char query[512]; sqlSafef(query, sizeof(query), "SELECT recovEmail, recovEmailVerified FROM gbMembers WHERE userName='%s'", user); struct sqlResult *sr = sqlGetResult(conn, query); char **row = sqlNextRow(sr); char *curRecov = (row != NULL) ? cloneString(emptyForNull(row[0])) : cloneString(""); boolean curConfirmed = (row != NULL) && sameWord(emptyForNull(row[1]), "Y"); sqlFreeResult(&sr); sqlSafef(query, sizeof(query), "SELECT password FROM gbMembers WHERE userName='%s'", user); boolean hasPassword = isNotEmpty(sqlQuickString(conn, query)); char *encUser = htmlEncode(user); char *encCurRecov = htmlEncode(isNotEmpty(curRecov) ? curRecov : "(none)"); hPrintf("<div id=\"changeRecovEmailBox\" class=\"centeredContainer formBox\">" "<h2>%s</h2>", brwName); -hPrintf("<h3>Recovery Email</h3>"); +hPrintf("<h3>Change recovery email</h3>"); hPrintf("<p><span style='color:red;'>%s</span></p>", errMsg ? errMsg : ""); hPrintf("<form method=\"post\" action=\"%s\" name=\"changeRecovEmailForm\">", hgLoginUrl); hPrintf("<p>Signed in as <b>%s</b>.<br>Current recovery email address: <b>%s</b>%s</p>", encUser, encCurRecov, (isNotEmpty(curRecov) && !curConfirmed) ? " (waiting to be confirmed)" : ""); -hPrintf("<p style=\"font-size:0.9em\">A second address you can use to get back into your " - "account: it can sign you in, including with the Google and ORCID buttons, and it receives " - "a copy of a password reset. We email it a link to confirm it, and it does nothing until " - "you open that link. Your current address keeps working until then.</p>"); +hPrintf("<p style=\"font-size:0.9em\">You can add a second email address to get back into " + "your account. Once confirmed, it can sign you in, including through the Google and " + "ORCID buttons, and it will get a copy of the password-reset email whenever one is sent " + "for this account. We will email a confirmation link to the new address. Until that " + "link is opened, the email address cannot be used to sign in and will not receive a " + "password-reset email.%s</p>", + isNotEmpty(curRecov) ? " Your current recovery email address keeps working until then." : ""); freeMem(encUser); freeMem(encCurRecov); if (hasPassword) hPrintf("<div class=\"inputGroup\">" "<label for=\"curPassword\">Current password</label>" "<input type=\"password\" name=\"hgLogin_curPassword\" value=\"\" size=\"30\" " "id=\"curPassword\">" "</div>"); hPrintf("<div class=\"inputGroup\">" "<label for=\"newRecovEmail1\">New recovery email address</label>" "<input type=\"text\" name=\"hgLogin_newRecovEmail1\" value=\"\" size=\"30\" " "id=\"newRecovEmail1\">" "</div>"); hPrintf("<div class=\"inputGroup\">" "<label for=\"newRecovEmail2\">Re-enter new recovery email address</label>" @@ -1696,31 +1700,31 @@ changeRecovEmailPage(conn); return; } /* Do not store the address yet: mail a one-time confirmation link and put it on the account * only when that link is opened (see confirmRecovEmail). Until then the address the user has * now keeps working, so a typo here costs them nothing. */ sendRecovEmailConfirmMail(recov1, user, curRecov, curVerified); cartRemove(cart, "hgLogin_newRecovEmail1"); cartRemove(cart, "hgLogin_newRecovEmail2"); cartRemove(cart, "hgLogin_curPassword"); char *encRecov = htmlEncode(recov1); hPrintf("<div class=\"centeredContainer formBox\"><h2>%s</h2>", brwName); hPrintf("<h3>Almost done. Please check your email</h3>"); hPrintf("<p>We sent a confirmation link to <b>%s</b>. Open the link in that message to finish " "setting your recovery email address. The link works once and expires in seven days. Until " - "then nothing about your account changes.</p></div>", encRecov); + "that link is opened, nothing about your account changes.</p></div>", encRecov); freeMem(encRecov); returnToURL(3000); } void signupPage(struct sqlConnection *conn) /* draw the signup page */ { hPrintf("<div id=\"signUpBox\" class=\"centeredContainer formBox\">" "<h2>%s</h2>", brwName); hPrintf( "<p>Signing up enables you to save multiple sessions, share your sessions with others via short and stable session links and manage previously uploaded custom tracks and track hubs.</p>" "\n"); hPrintf("<p>Already have an account? " "<a href=\"%s?hgLogin.do.displayLoginPage=1\">Go to the login page</a>.</p>", hgLoginUrl); printSocialButtons(FALSE, TRUE, "Sign up");