b74aa56e4115f371dbe818e98412f0c9e738e142
max
  Tue Sep 30 07:45:16 2025 -0700
allow apiKey=xxx to get around captcha and also bottleneck on the apiKey then, not on the cookie userId or hgsid, refs #36428

diff --git src/hg/lib/cart.c src/hg/lib/cart.c
index 7ee8473fa98..a989b3ef1ad 100644
--- src/hg/lib/cart.c
+++ src/hg/lib/cart.c
@@ -27,30 +27,31 @@
 #include "hgMaf.h"
 #include "hui.h"
 #include "geoMirror.h"
 #include "hubConnect.h"
 #include "trackHub.h"
 #include "cgiApoptosis.h"
 #include "customComposite.h"
 #include "regexHelper.h"
 #include "windowsToAscii.h"
 #include "jsonWrite.h"
 #include "verbose.h"
 #include "genark.h"
 #include "quickLift.h"
 #include "botDelay.h"
 #include "curlWrap.h"
+#include "hubSpaceKeys.h"
 
 static char *sessionVar = "hgsid";	/* Name of cgi variable session is stored in. */
 static char *positionCgiName = "position";
 
 DbConnector cartDefaultConnector = hConnectCart;
 DbDisconnect cartDefaultDisconnector = hDisconnectCart;
 static boolean cartDidContentType = FALSE;
 
 struct slPair *httpHeaders = NULL; // A list of headers to output before the content-type
 
 static void hashUpdateDynamicVal(struct hash *hash, char *name, void *val)
 /* Val is a dynamically allocated (freeMem-able) entity to put
  * in hash.  Override existing hash item with that name if any.
  * Otherwise make new hash item. */
 {
@@ -1551,30 +1552,36 @@
     return;
 
 captchaCheckDone = TRUE;
 
 if (fromCommandLine || isEmpty(cfgOption(CLOUDFLARESITEKEY)))
     return;
 
 // no captcha for our own QA scripts running on a server with our IP address
 if (botException())
     return;
 
 // certain user agents are allowed to use the website without a captcha
 if (isUserAgentException())
     return;
 
+// a valid apiKey can always be used to get around the captcha. Note that bottlenecking is then done on the level
+// of the apiKey, if a valid apiKey has been supplied, see botDelay.c
+char *apiKey = cgiOptionalString("apiKey");
+if (apiKey && userNameForApiKey(apiKey))
+    return;
+
 // hgRenderTracks should not show the captcha - it was made to be used from other websites
 // For hgSession, we redirect from euro and asia to the RR - avoid showing the captcha there
 // hgLogin is the redirect target for hgSession, so avoid it there as well
 char *cgi = cgiScriptName();
 if ( sameWord(cgi, "/cgi-bin/hgRenderTracks") || sameWord(cgi, "/cgi-bin/hgSession") || sameWord(cgi, "/cgi-bin/hgLogin") )
     return;
 
 // Do not show a captcha if we have a valid cookie 
 // but for debugging, it's nice to be able to force the captcha
 if (userId && userIdFound && !cgiOptionalString("captcha"))
     return;
 
 // when the captcha is solved, our JS code does a full page-reload, no AJAX. That saves us one round-trip.
 // After the reload, the new page URL has the captcha token in the URL argument list, so now we need to validate it
 // and remove it from the cart