5a249cd50f592a3b7598110eec792cfc942fab3f
max
  Wed Sep 9 08:52:06 2026 -0700
Address the v504 code review

hgSession: an anonymous share name that arrives with the request is saved only
when it is not already in the table.  Every anonymous link sits under the one
reserved user "l", so a name already there stays as it is and the caller is told
so.  The top-right Share dialog is unaffected, since it passes a name it has
just reserved and such a name does not exist yet.  Snapshot names are now left
out of both My Sessions listings, which is what their "__" prefix has claimed
all along.

Share dialog: "Create link & copy" reports the copy instead of promising it.
copyToClipboard says whether the text reached the clipboard, the dialog passes
that on when a browser refuses, and it tries the asynchronous clipboard API
before giving up.  The preview is built with the same encoding the server uses,
so a name holding a hyphen or a slash previews as the link that really gets
made.  Cancelling out of the name editor no longer copies a second time, and a
reply with no link in it says so rather than showing "undefined".

hgBlat: a second click on the share button while the first request is still out
no longer mints a second snapshot session, and a box dismissed during the wait
stays closed.

Also: a snapshot moves a cart value into durable storage only when it is a
trash path, the way sessionData's own callers check; sqlAddressMatch keeps to
its own documented precondition when handed an empty address; alphaGenomeToWig
compares its output with its input rather than with itself, rejects a position
that is not all digits and skips an empty score; and hgc's default iframe width
reaches the browser as one percent sign.

refs #38294

diff --git src/hg/hgLogin/hgLogin.c src/hg/hgLogin/hgLogin.c
index 50db23eebf0..62daed5ebcc 100644
--- src/hg/hgLogin/hgLogin.c
+++ src/hg/hgLogin/hgLogin.c
@@ -518,33 +518,39 @@
 char *remoteAddr=getenv("REMOTE_ADDR");
 
 safef(subject, sizeof(subject),"Your username at the %s", brwName);
 safef(msg, sizeof(msg), 
     "  Someone (probably you, from IP address %s) has requested username(s) associated with this email address at the %s: \n\n  %s\n\n%s\n%s", 
    remoteAddr, brwName, users, signature, returnAddr);
 sendMailOut(email, subject, msg);
 }
 
 static char *sqlAddressMatch(char *email)
 /* Return a SQL fragment matching the gbMembers rows that belong to whoever controls email: the
  * accounts carrying it as their primary address, plus the accounts carrying it as a *confirmed*
  * recovery address.  An unconfirmed recovEmail is only a string that a signup form typed in --
  * nobody ever proved they can read mail there -- so matching it would let someone who registered
  * with a victim's address as their recovery address capture that victim's login (see
- * confirmRecovEmail).  Callers must pass a non-empty email, or rows with a blank recovEmail
- * match.  Result is allocd and carries the sqlSafef prefix; embed it with %-s. */
+ * confirmRecovEmail).  An empty email matches nothing: rows with a blank recovEmail would
+ * otherwise all match, which is every account on a mirror that has just added the column.
+ * Result is allocd and carries the sqlSafef prefix; embed it with %-s. */
 {
+if (isEmpty(email))
+    {
+    struct dyString *dyNone = sqlDyStringCreate("(0)");
+    return dyStringCannibalize(&dyNone);
+    }
 struct dyString *dy = sqlDyStringCreate("(email='%s'", email);
 if (recovEmailVerifyOk)
     sqlDyStringPrintf(dy, " OR (recovEmail='%s' AND recovEmailVerified='Y')", email);
 else
     /* A mirror whose gbMembers predates the column: we cannot tell confirmed from unconfirmed,
      * so keep the old behavior rather than locking those users out of their own accounts. */
     sqlDyStringPrintf(dy, " OR recovEmail='%s'", email);
 sqlDyStringPrintf(dy, ")");
 return dyStringCannibalize(&dy);
 }
 
 void sendUsername(struct sqlConnection *conn, char *email)
 /* email user username(s)  */
 {
 struct sqlResult *sr;
@@ -1121,33 +1127,35 @@
     "%s).\n\nIf you made this change, nothing more is needed.  If you did NOT, please reply to "
     "this message right away so we can help you secure the account.\n\n%s\n%s",
     brwName, user, newEmail, emptyForNull(remoteAddr), signature, returnAddr);
 sendActMailOut(oldEmail, subject, message);
 }
 
 static char *recovEmailSig(char *user, char *newRecov, char *curRecov, char *curVerified,
                            char *expStr)
 /* HMAC-MD5 over a pending recovery address, keyed by the secret login.cookieSalt.  It goes in
  * the link mailed to that address, so that opening the link -- and only opening it -- puts the
  * address on the account and marks it confirmed, proving the mailbox really does reach the
  * person who claimed it.  One signature serves both cases: the address given at signup (where
  * newRecov is already stored, unconfirmed) and a later change (where it is not stored at all
  * until the link is opened, so a typo cannot cost the user a working recovery address).
  * curRecov and curVerified are the account's stored address and flag when the link was minted;
- * because confirmRecovEmail recomputes the signature from what is on the account now, a link
- * stops validating once it has been used, so each link works exactly once and a stale link
- * cannot quietly undo a newer change.  Result is allocd. */
+ * because confirmRecovEmail recomputes the signature from what is on the account now, applying a
+ * link stops it validating, so a stale link cannot quietly undo a newer change.  Note this is a
+ * check on the account's state, not a one-time token: put the account back the way it was when the
+ * link was minted and, within the week, the same link applies again.  That only ever moves the
+ * owner between addresses they have already confirmed for themselves.  Result is allocd. */
 {
 char *salt = cfgOption(CFG_LOGIN_COOKIE_SALT);
 if (isEmpty(salt))
     errAbort("Confirming a recovery email address requires %s in hg.conf, set to a secret random "
         "string.  Without a secret we cannot sign the confirmation link.", CFG_LOGIN_COOKIE_SALT);
 char buf[1024];
 safef(buf, sizeof(buf), "recovEmail|%s|%s|%s|%s|%s",
     emptyForNull(user), emptyForNull(newRecov), emptyForNull(curRecov),
     emptyForNull(curVerified), emptyForNull(expStr));
 return hmacMd5(salt, buf);
 }
 
 static void sendRecovEmailConfirmMail(char *recovEmail, char *user, char *curRecov,
                                       char *curVerified)
 /* Email a one-time link to recovEmail that, when opened, puts it on account user as a confirmed