214e76748ab09f24db9e390c633482be7901e8ab max Tue Jun 30 16:58:26 2026 -0700 adding captcha tracing to cart.c, no redmine diff --git src/hg/lib/cart.c src/hg/lib/cart.c index 0bd6dd90b68..19181c4a8a7 100644 --- src/hg/lib/cart.c +++ src/hg/lib/cart.c @@ -1502,37 +1502,44 @@ 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" +static char *getSessionId() +/* Get session id if any from CGI. */ +{ +return cgiOptionalString("hgsid"); +} + 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; + fprintf(stderr, "CAPTCHA_PRINT %s\n", getSessionId()); 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" "theme: 'light',\n" "callback: function (token) {\n" " const parser = new URL(window.location);\n" " parser.searchParams.set('token', token);\n" " window.location = parser.href;\n" " },\n" "});\n" "}\n", cfSiteKey); puts("</script>"); @@ -1596,59 +1603,61 @@ 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)) { + fprintf(stderr, "CAPTCHA_VALID %s\n", getSessionId()); cgiVarExclude("token"); // Drop any IP-tracking rows for this hguid so a legitimate user // who roams networks isn't repeatedly captcha-gated. if (cfgOptionBooleanDefault("hguidIpTracking.enabled", FALSE) && isNotEmpty(userId)) { unsigned long userIdNum = cartDbParseId(userId, NULL); if (userIdNum != 0) { struct sqlConnection *conn = hConnectCentralNoCache(); char *table = cfgOptionDefault("hguidIpTracking.table", "hguidIpAccess"); char query[256]; sqlSafef(query, sizeof(query), "DELETE FROM %s WHERE userId=%lu", table, userIdNum); sqlUpdate(conn, query); sqlDisconnect(&conn); } } return; } else { puts("Content-Type: text/html\n"); puts("<html><body>Internal captcha error: Cloudflare rejected the captcha token. " "Something is not working internally, we are very sorry. You can try reloading the page. " "If this problem persists, send an email to genome-www@soe.ucsc.edu and we will " "look into it as quickly as we can in the PST timezone. You can use any internet browser " "where you have used the genome browser before, but not from this internet browser. " "You can try our mirror sites, " "genome-euro.ucsc.edu or genome-asia.ucsc.edu, while we are working on a solution.</body></html>"); + fprintf(stderr, "CAPTCHA_REJECT %s\n", getSessionId()); exit(0); } } printCaptcha(); } void cartRemove(struct cart *cart, char *var); static void genericCgiSetup() /* Run steps that all CGIs must do that unrelated to the cart: timeout, logging setup, UDC. */ { static boolean genericSetupDone = FALSE; @@ -2538,36 +2547,30 @@ static char *cookieDate() /* Return date string for cookie format. We'll have to * revisit this in 35 years.... */ { return "Thu, 31-Dec-2037 23:59:59 GMT"; } static char *getCookieId(char *cookieName) /* Get id value from cookie. */ { return findCookieData(cookieName); } -static char *getSessionId() -/* Get session id if any from CGI. */ -{ -return cgiOptionalString("hgsid"); -} - static void clearDbContents(struct sqlConnection *conn, char *table, char * secureId) /* Clear out contents field of row in table that matches id. */ { if (!secureId) return; struct dyString *query = dyStringNew(256); char *sessionKey = NULL; unsigned long id = cartDbParseId(secureId, &sessionKey); char *defaultCartContents = getDefaultCart(conn); sqlDyStringPrintf(query, "update %s set contents='%s' where id=%lu", table, defaultCartContents, id); if (cartDbUseSessionKey()) { if (!sessionKey) sessionKey = ""; sqlDyStringPrintf(query, " and sessionKey='%s'", sessionKey);