| | @@ -339,37 +339,44 @@ |
| 339 | 339 | }else{ |
| 340 | 340 | free(zCookie); |
| 341 | 341 | } |
| 342 | 342 | } |
| 343 | 343 | |
| 344 | +/* |
| 345 | +** Lifetime of an anoymous cookie, in seconds. |
| 346 | +*/ |
| 347 | +#define ANONYMOUS_COOKIE_LIFESPAN 28800 /* 28800 seconds == 8 hours */ |
| 348 | + |
| 344 | 349 | /* Sets a cookie for an anonymous user login, which looks like this: |
| 345 | 350 | ** |
| 346 | | -** HASH/TIME:IPADDR/anonymous |
| 351 | +** HASH/TIME/anonymous |
| 347 | 352 | ** |
| 348 | | -** Where HASH is the sha1sum of TIME:IPADDR/SECRET, in which SECRET |
| 349 | | -** is captcha-secret. |
| 353 | +** Where HASH is the sha1sum of TIME/USERAGENT/SECRET, in which SECRET |
| 354 | +** is captcha-secret and USERAGENT is the HTTP_USER_AGENT value. |
| 350 | 355 | ** |
| 351 | 356 | ** If zCookieDest is not NULL then the generated cookie is assigned to |
| 352 | 357 | ** *zCookieDest and the caller must eventually free() it. |
| 353 | 358 | ** |
| 354 | 359 | ** If bSessionCookie is true, the cookie will be a session cookie. |
| 360 | +** |
| 361 | +** Search for tag-20250817a to find the code that recognizes this cookie. |
| 355 | 362 | */ |
| 356 | 363 | void login_set_anon_cookie(char **zCookieDest, int bSessionCookie){ |
| 357 | 364 | char *zNow; /* Current time (julian day number) */ |
| 358 | 365 | char *zCookie; /* The login cookie */ |
| 359 | | - const char *zIpAddr; /* IP Address */ |
| 366 | + const char *zUserAgent; /* The user agent */ |
| 360 | 367 | const char *zCookieName; /* Name of the login cookie */ |
| 361 | 368 | Blob b; /* Blob used during cookie construction */ |
| 362 | | - int expires = bSessionCookie ? 0 : 3600; /* Valid for 60 minutes */ |
| 369 | + int expires = bSessionCookie ? 0 : ANONYMOUS_COOKIE_LIFESPAN; |
| 363 | 370 | zCookieName = login_cookie_name(); |
| 364 | 371 | zNow = db_text("0", "SELECT julianday('now')"); |
| 365 | 372 | assert( zCookieName && zNow ); |
| 366 | 373 | blob_init(&b, zNow, -1); |
| 367 | | - zIpAddr = PD("REMOTE_ADDR","nil"); |
| 368 | | - blob_appendf(&b, ":%s/%z", zIpAddr, captcha_secret(0)); |
| 374 | + zUserAgent = PD("HTTP_USER_AGENT","nil"); |
| 375 | + blob_appendf(&b, "/%s/%z", zUserAgent, captcha_secret(0)); |
| 369 | 376 | sha1sum_blob(&b, &b); |
| 370 | | - zCookie = mprintf("%s/%s:%s/anonymous", blob_buffer(&b), zNow, zIpAddr); |
| 377 | + zCookie = mprintf("%s/%s/anonymous", blob_buffer(&b), zNow); |
| 371 | 378 | blob_reset(&b); |
| 372 | 379 | cgi_set_cookie(zCookieName, zCookie, login_cookie_path(), expires); |
| 373 | 380 | if( zCookieDest ){ |
| 374 | 381 | *zCookieDest = zCookie; |
| 375 | 382 | }else{ |
| | @@ -1412,36 +1419,36 @@ |
| 1412 | 1419 | } |
| 1413 | 1420 | } |
| 1414 | 1421 | if( zUser==0 ){ |
| 1415 | 1422 | /* Invalid cookie */ |
| 1416 | 1423 | }else if( fossil_strcmp(zUser, "anonymous")==0 ){ |
| 1417 | | - /* Cookies of the form "HASH/TIME:IPADDR/anonymous". The TIME must |
| 1418 | | - ** not be too old and the sha1 hash of TIME:IPADDR/SECRET must match |
| 1419 | | - ** HASH. SECRET is the "captcha-secret" value in the repository. |
| 1424 | + /* Cookies of the form "HASH/TIME/anonymous". The TIME must |
| 1425 | + ** not be more than ANONYMOUS_COOKIE_LIFESPAN seconds ago and |
| 1426 | + ** the sha1 hash of TIME/USERAGENT/SECRET must match HASH. USERAGENT |
| 1427 | + ** is the HTTP_USER_AGENT of the client and SECRET is the |
| 1428 | + ** "captcha-secret" value in the repository. See tag-20250817a |
| 1429 | + ** for the code the creates this cookie. |
| 1420 | 1430 | */ |
| 1421 | 1431 | double rTime = atof(zArg); |
| 1422 | | - const char *zCookieIP; |
| 1432 | + const char *zUserAgent = PD("HTTP_USER_AGENT","nil"); |
| 1423 | 1433 | Blob b; |
| 1424 | 1434 | char *zSecret; |
| 1425 | 1435 | int n = 0; |
| 1426 | 1436 | |
| 1427 | | - zCookieIP = strchr(zArg,':'); |
| 1428 | | - if( zCookieIP && strcmp(zCookieIP+1,zIpAddr)!=0 ) zCookieIP = 0; |
| 1429 | 1437 | do{ |
| 1430 | | - if( zCookieIP==0 ) break; |
| 1431 | 1438 | blob_zero(&b); |
| 1432 | 1439 | zSecret = captcha_secret(n++); |
| 1433 | 1440 | if( zSecret==0 ) break; |
| 1434 | | - blob_appendf(&b, "%s/%s", zArg, zSecret); |
| 1441 | + blob_appendf(&b, "%s/%s/%s", zArg, zUserAgent, zSecret); |
| 1435 | 1442 | sha1sum_blob(&b, &b); |
| 1436 | 1443 | if( fossil_strcmp(zHash, blob_str(&b))==0 ){ |
| 1437 | 1444 | uid = db_int(0, |
| 1438 | 1445 | "SELECT uid FROM user WHERE login='anonymous'" |
| 1439 | 1446 | " AND octet_length(cap)>0" |
| 1440 | 1447 | " AND octet_length(pw)>0" |
| 1441 | | - " AND %.17g+0.0416667>julianday('now')", |
| 1442 | | - rTime |
| 1448 | + " AND %.17g>julianday('now')", |
| 1449 | + rTime+ANONYMOUS_COOKIE_LIFESPAN/86400.0 |
| 1443 | 1450 | ); |
| 1444 | 1451 | } |
| 1445 | 1452 | }while( uid==0 ); |
| 1446 | 1453 | blob_reset(&b); |
| 1447 | 1454 | }else{ |
| 1448 | 1455 | |