690cc018255362c9d1af6ed5f4fa15ae7a0fc81d
max
  Wed Aug 5 11:26:22 2026 -0700
changes after automated code review

hgLogin: sign the pending social identity with hmacMd5() instead of a hand-built
cookieSalt-prefix + MD5. The salt now keys the HMAC rather than being prepended to
the hashed message. This is the signature that closes the account-takeover hole in
the OAuth account chooser, so it should use a real MAC. It also now fails closed:
with login.cookieSalt unset the old code hashed an empty salt, so anyone could
compute a valid signature and the protection was silently absent - hgLogin refuses
to run a social login without the salt. Ordinary login pages never reach this check.
Pending identities in flight across the upgrade no longer validate; those users are
asked to sign in again.

lib/hmac.c: hmacSha1() and hmacMd5() sized their hex buffers at exactly 40 and 32
chars, so the last sprintf wrote its terminating zero one byte past the array and
the following strlen read out of bounds. Grow both by one and use cloneString().
Output is unchanged, verified against openssl dgst -hmac.

userAccounts.css: drop the #helpBox rule, unused since the last id="helpBox" was
removed from hgLogin.c.

mirrorManual, ex.hg.conf: the login section claimed "three" extra ways to sign in
when there are two (external provider, one-time email link). Also document that
login.cookieSalt is required for social sign-in, now that the check fails closed.
Edited mirrorManual.txt and regenerated the html with mirrorDocs/make, since the
html is pandoc output and hand edits there do not survive.

refs #37984

diff --git src/hg/htdocs/style/userAccounts.css src/hg/htdocs/style/userAccounts.css
index a86f9db3747..b6c5bbac7c7 100644
--- src/hg/htdocs/style/userAccounts.css
+++ src/hg/htdocs/style/userAccounts.css
@@ -1,153 +1,147 @@
 /* Styles for the login, signup, etc pages */
 
 body.accountScreen {background-color: #fffee8;}
 
 /* Use the same sans-serif font as the rest of the site (the page would otherwise fall back
  * to the browser default, Times New Roman). */
 body {font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;}
 
 .formBox a {text-decoration: none}
 
 .formBox a:hover {text-decoration: underline;}
 
 .centeredContainer {margin: 0 auto;}
 
 .formBox {
     width: 400px;
     border: 2px solid #eed5b7;
     margin-top: 2.5em;
     padding: 0 30px;
     -webkit-border-radius: 4px;
     -moz-border-radius: 4px;
     border-radius: 4px;
     background-color: #fff9d2;
 }
 
 /* The signup and login pages have more content (form + social buttons), so give them a
  * little more room than the default 400px formBox. */
 #signUpBox, #loginBox {width: 480px;}
 
 .formBox input {font-size: 1.04em;}
 
 .formBox label {display: block; margin-top: 10px;}
 
 .formBox label.radioLabel {display: inline; margin: 0;}
 
 .formControls {
 	margin: 1em 0;
 }
 
 /* The form submit buttons ("Login", "Sign Up", ...) and the "Cancel" link share one
  * consistent button style, so Cancel looks like the other buttons rather than a plain link. */
 input.largeButton,
 a.cancelButton {
     display: inline-block;
     padding: 4px 8px;
     font-family: inherit;
     font-size: 14px;
     font-weight: 700;
     line-height: 1.2;
     border: 1px solid #999;
     border-radius: 3px;
     background: #f0f0f0;
     color: #222 !important;
     text-decoration: none !important;
     cursor: pointer;
     vertical-align: middle;
 }
 
 input.largeButton:hover,
 a.cancelButton:hover {
     background: #e6e6e6;
     border-color: #666;
 }
 
 /* Small "Forgot username / password" links under the login form fields. */
 a.forgotLink {
     display: block;
     margin-top: 3px;
     font-size: 0.8em;
     text-align: left;
 }
 
-#helpBox {
-    margin-top: 20px;
-    padding: 20px 0 10px 0; 
-    border-top: 1px solid #eed5b7;
-}
-
 label small {
     font-style: italic;
     font-size: 0.9em;
 }
 
 .topBarContainer { /* only needed for login screens */
     padding: 6px 0;    
 }
 
 .highlightBox { /* combine with classes error, alert, or highlight */
 	border: 2px solid;
     padding: 10px;
 }
 
 .error { /* for use with highlightBox, when used for error msgs */
     border-color: #f00;
     background-color: #ffeded;
     color: #f00;
 }
 
 .confirmationTxt {
     font-size: 1.2em;
     font-weight: normal;
 }
 
 .error {color: #bb2525;}
 label.error {
     margin: 0;
     background-color: #FFF9D2;
     padding: 2px 5px;
     width: 321px;
 }
 
 input.error {
     border: 1px solid #bb2525;
     -moz-box-shadow:    inset 0 1px 1px #b0b0b0;
     -webkit-box-shadow: inset 0 1px 1px #b0b0b0;
     box-shadow:         inset 0 1px 1px #b0b0b0;
     padding: 3px 2px;
 }
 
 /* Social login (Google/ORCID) buttons and the "or" divider. */
 .socialLogin {margin: 0.5em 0;}
 
 .orDivider {
     text-align: center;
     border-top: 1px solid #eed5b7;
     line-height: 0.1em;
     margin: 1.2em 0;
 }
 
 .orDivider span {
     background: #fff9d2;
     padding: 0 10px;
 }
 
 a.socialButton {
     display: block;
     box-sizing: border-box;
     width: 100%;
     margin: 8px 0;
     padding: 9px 12px;
     text-align: center;
     font-weight: 700;
     color: #222 !important;
     background: #e0e0e0;
     border: 1px solid #999;
     border-radius: 3px;
     text-decoration: none !important;
 }
 
 a.socialButton:hover {
     background: #d5d5d5;
     border-color: #666;
 }
\ No newline at end of file