80f55de280d3cc483b772c1d02dd88b6bc1cf173
max
  Thu Oct 16 03:01:55 2025 -0700
adding an apache logfile line when apiKey is recognized, refs #36428

diff --git src/hg/lib/cart.c src/hg/lib/cart.c
index 14cd37aee1b..f53e0c2c84f 100644
--- src/hg/lib/cart.c
+++ src/hg/lib/cart.c
@@ -1470,30 +1470,31 @@
 {
     char *url = "https://challenges.cloudflare.com/turnstile/v0/siteverify";
     char *secret = cfgVal("cloudFlareSecretKey");
     if (!secret)
         errAbort("'cloudFlareSecretKey' must be set in hg.conf if cloudflare is activated in hg.conf");
 
     char data[3000]; // cloudflare token is at most 2000 bytes
     safef(data, sizeof(data), "secret=%s&response=%s", secret, token);
     char *reply = curlPostUrl(url, data);
 
     boolean res = strstr(reply, "\"success\":true") != NULL;
     freez(&reply);
     return res;
 }
 
+// hg.conf key with the cloud flare secret key, used twice here, so a global macro
 #define CLOUDFLARESITEKEY "cloudFlareSiteKey"
 
 void printCaptcha() 
 /* print an html page that shows the captcha and on success, reloads the page with the token added as token=x */
 {
     char *cfSiteKey = cfgVal(CLOUDFLARESITEKEY);
     if (!cfSiteKey)
         return;
 
     puts("Content-Type:text/html\n"); // puts outputs one newline. Header requires two newlines.
     puts("<html><head>");
     puts("<script>");
     printf("function showWidget() { \n"
        "turnstile.render('#myWidget', {\n"
          "sitekey: '%s',\n"
@@ -1553,45 +1554,45 @@
     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
+char *cgi = cgiScriptName();
+
+// An 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, so the check if the apiKey is valid is assumed 
-// to have been done at the bottleneck step
+// to have been done at the bottleneck step, which in all our CGIs is called before the cart is initialized.
 char *apiKey = cgiOptionalString("apiKey");
 if (apiKey) 
 {
-        // This assumes that we've checked the API key already in botdelay.c. All our CGIs 
-        // call botDelay, we assume that botDelay has been called.
+    fprintf(stderr, "CAPTCHAPASS_APIKEY %s %s\n", apiKey, cgi);
     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
 char *token = cgiOptionalString("token");
 if (token)
 { 
     if (isValidToken(token))