Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | New setting "anon-cookie-lifespan" sets the life span of an anonymous login cookie. The default is 8 hours. Set to zero to disable anonymous login. |
|---|---|
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA3-256: |
7d2b47a7c3f068ebf948e2545c996897 |
| User & Date: | drh 2025-08-18 15:49:32.450 |
Context
|
2025-08-19
| ||
| 10:28 | Documentation update: Make the robot-restrict setting "none" or "off" to disable all restrictions. check-in: 26a9b03336 user: drh tags: trunk | |
|
2025-08-18
| ||
| 15:49 | New setting "anon-cookie-lifespan" sets the life span of an anonymous login cookie. The default is 8 hours. Set to zero to disable anonymous login. check-in: 7d2b47a7c3 user: drh tags: trunk | |
| 11:45 | Additional obfuscation of the javascript that runs to implement the anti-robot defense. check-in: 4c4bce351d user: drh tags: trunk | |
Changes
Changes to src/login.c.
| ︙ | ︙ | |||
158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
int uid; /* The user ID of anonymous */
int n = 0; /* Counter of captcha-secrets */
if( zUsername==0 ) return 0;
else if( zPassword==0 ) return 0;
else if( zCS==0 ) return 0;
else if( fossil_strcmp(zUsername,"anonymous")!=0 ) return 0;
while( 1/*exit-by-break*/ ){
zPw = captcha_decode((unsigned int)atoi(zCS), n);
if( zPw==0 ) return 0;
if( fossil_stricmp(zPw, zPassword)==0 ) break;
n++;
}
uid = db_int(0, "SELECT uid FROM user WHERE login='anonymous'"
| > | 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
int uid; /* The user ID of anonymous */
int n = 0; /* Counter of captcha-secrets */
if( zUsername==0 ) return 0;
else if( zPassword==0 ) return 0;
else if( zCS==0 ) return 0;
else if( fossil_strcmp(zUsername,"anonymous")!=0 ) return 0;
else if( anon_cookie_lifespan()==0 ) return 0;
while( 1/*exit-by-break*/ ){
zPw = captcha_decode((unsigned int)atoi(zCS), n);
if( zPw==0 ) return 0;
if( fossil_stricmp(zPw, zPassword)==0 ) break;
n++;
}
uid = db_int(0, "SELECT uid FROM user WHERE login='anonymous'"
|
| ︙ | ︙ | |||
338 339 340 341 342 343 344 |
*zDest = zCookie;
}else{
free(zCookie);
}
}
/*
| > > > > > > > | | > > > > > > > > > > > > | 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 |
*zDest = zCookie;
}else{
free(zCookie);
}
}
/*
** SETTING: anon-cookie-lifespan width=10 default=480
** The number of minutes for which an anonymous login cookie is
** valid. Anonymous logins are prohibited if this value is zero.
*/
/*
** The default lifetime of an anoymous cookie, in minutes.
*/
#define ANONYMOUS_COOKIE_LIFESPAN (8*60)
/*
** Return the lifetime of an anonymous cookie, in minutes.
*/
int anon_cookie_lifespan(void){
static int lifespan = -1;
if( lifespan<0 ){
lifespan = db_get_int("anon-cookie-lifespan", ANONYMOUS_COOKIE_LIFESPAN);
if( lifespan<0 ) lifespan = 0;
}
return lifespan;
}
/* Sets a cookie for an anonymous user login, which looks like this:
**
** HASH/TIME/anonymous
**
** Where HASH is the sha1sum of TIME/USERAGENT/SECRET, in which SECRET
** is captcha-secret and USERAGENT is the HTTP_USER_AGENT value.
|
| ︙ | ︙ | |||
362 363 364 365 366 367 368 |
*/
void login_set_anon_cookie(char **zCookieDest, int bSessionCookie){
char *zNow; /* Current time (julian day number) */
char *zCookie; /* The login cookie */
const char *zUserAgent; /* The user agent */
const char *zCookieName; /* Name of the login cookie */
Blob b; /* Blob used during cookie construction */
| | | 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 |
*/
void login_set_anon_cookie(char **zCookieDest, int bSessionCookie){
char *zNow; /* Current time (julian day number) */
char *zCookie; /* The login cookie */
const char *zUserAgent; /* The user agent */
const char *zCookieName; /* Name of the login cookie */
Blob b; /* Blob used during cookie construction */
int expires = bSessionCookie ? 0 : anon_cookie_lifespan();
zCookieName = login_cookie_name();
zNow = db_text("0", "SELECT julianday('now')");
assert( zCookieName && zNow );
blob_init(&b, zNow, -1);
zUserAgent = PD("HTTP_USER_AGENT","nil");
blob_appendf(&b, "/%s/%z", zUserAgent, captcha_secret(0));
sha1sum_blob(&b, &b);
|
| ︙ | ︙ | |||
600 601 602 603 604 605 606 | ** and a "Verify" button. Underneath is the same login page for user ** "anonymous", just displayed in an easier to digest format for one-time ** visitors. ** ** anon=1 is advisory and only has effect if there is not some other login ** cookie. anon=2 means always show the captcha. */ | | | 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 |
** and a "Verify" button. Underneath is the same login page for user
** "anonymous", just displayed in an easier to digest format for one-time
** visitors.
**
** anon=1 is advisory and only has effect if there is not some other login
** cookie. anon=2 means always show the captcha.
*/
anonFlag = anon_cookie_lifespan()>0 ? atoi(PD("anon","0")) : 0;
if( anonFlag==2 ){
g.zLogin = 0;
}else{
login_check_credentials();
if( g.zLogin!=0 ) anonFlag = 0;
}
|
| ︙ | ︙ | |||
783 784 785 786 787 788 789 |
}
if( g.zLogin ){
@ <p>Currently logged in as <b>%h(g.zLogin)</b>.
@ <input type="submit" name="out" value="Logout" autofocus></p>
@ </form>
}else{
unsigned int uSeed = captcha_seed();
| | | 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 |
}
if( g.zLogin ){
@ <p>Currently logged in as <b>%h(g.zLogin)</b>.
@ <input type="submit" name="out" value="Logout" autofocus></p>
@ </form>
}else{
unsigned int uSeed = captcha_seed();
if( g.zLogin==0 && (anonFlag || zGoto==0) && anon_cookie_lifespan()>0 ){
zAnonPw = db_text(0, "SELECT pw FROM user"
" WHERE login='anonymous'"
" AND cap!=''");
}else{
zAnonPw = 0;
}
@ <table class="login_out">
|
| ︙ | ︙ | |||
1416 1417 1418 1419 1420 1421 1422 |
zUser = &zHash[i];
break;
}
}
}
if( zUser==0 ){
/* Invalid cookie */
| | > | 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 |
zUser = &zHash[i];
break;
}
}
}
if( zUser==0 ){
/* Invalid cookie */
}else if( fossil_strcmp(zUser, "anonymous")==0
&& anon_cookie_lifespan()>0 ){
/* Cookies of the form "HASH/TIME/anonymous". The TIME must
** not be more than ANONYMOUS_COOKIE_LIFESPAN seconds ago and
** the sha1 hash of TIME/USERAGENT/SECRET must match HASH. USERAGENT
** is the HTTP_USER_AGENT of the client and SECRET is the
** "captcha-secret" value in the repository. See tag-20250817a
** for the code the creates this cookie.
*/
|
| ︙ | ︙ | |||
1442 1443 1444 1445 1446 1447 1448 |
sha1sum_blob(&b, &b);
if( fossil_strcmp(zHash, blob_str(&b))==0 ){
uid = db_int(0,
"SELECT uid FROM user WHERE login='anonymous'"
" AND octet_length(cap)>0"
" AND octet_length(pw)>0"
" AND %.17g>julianday('now')",
| | | 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 |
sha1sum_blob(&b, &b);
if( fossil_strcmp(zHash, blob_str(&b))==0 ){
uid = db_int(0,
"SELECT uid FROM user WHERE login='anonymous'"
" AND octet_length(cap)>0"
" AND octet_length(pw)>0"
" AND %.17g>julianday('now')",
rTime+anon_cookie_lifespan()/1440.0
);
}
}while( uid==0 );
blob_reset(&b);
}else{
/* Cookies of the form "HASH/CODE/USER". Search first in the
** local user table, then the user table for project CODE if we
|
| ︙ | ︙ | |||
1907 1908 1909 1910 1911 1912 1913 |
/*
** Call this routine if the user lacks g.perm.Hyperlink permission. If
** the anonymous user has Hyperlink permission, then paint a mesage
** to inform the user that much more information is available by
** logging in as anonymous.
*/
void login_anonymous_available(void){
| | | 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 |
/*
** Call this routine if the user lacks g.perm.Hyperlink permission. If
** the anonymous user has Hyperlink permission, then paint a mesage
** to inform the user that much more information is available by
** logging in as anonymous.
*/
void login_anonymous_available(void){
if( !g.perm.Hyperlink && g.anon.Hyperlink && anon_cookie_lifespan()>0 ){
const char *zUrl = PD("PATH_INFO", "");
@ <p>Many <span class="disabled">hyperlinks are disabled.</span><br>
@ Use <a href="%R/login?anon=1&g=%T(zUrl)">anonymous login</a>
@ to enable hyperlinks.</p>
}
}
|
| ︙ | ︙ |
Changes to src/setup.c.
| ︙ | ︙ | |||
516 517 518 519 520 521 522 523 524 525 526 527 528 529 |
@ <br>
textarea_attribute("", 2, 80,
"robot-restrict", "rbrestrict", robot_restrict_default(), 0);
@ <hr>
addAutoHyperlinkSettings();
@ <hr>
entry_attribute("Server Load Average Limit", 11, "max-loadavg", "mxldavg",
"0.0", 0);
@ <p>Some expensive operations (such as computing tarballs, zip archives,
@ or annotation/blame pages) are prohibited if the load average on the host
@ computer is too large. Set the threshold for disallowing expensive
@ computations here. Set this to 0.0 to disable the load average limit.
| > > > > > > > | 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 |
@ <br>
textarea_attribute("", 2, 80,
"robot-restrict", "rbrestrict", robot_restrict_default(), 0);
@ <hr>
addAutoHyperlinkSettings();
@ <hr>
entry_attribute("Anonymous Login Validity", 11, "anon-cookie-lifespan",
"anoncookls", "840", 0);
@ <p>The number of minutes for which an anonymous login cookie is valid.
@ Set to zero to disable anonymous login.
@ (property: anon-cookie-lifespan)
@ <hr>
entry_attribute("Server Load Average Limit", 11, "max-loadavg", "mxldavg",
"0.0", 0);
@ <p>Some expensive operations (such as computing tarballs, zip archives,
@ or annotation/blame pages) are prohibited if the load average on the host
@ computer is too large. Set the threshold for disallowing expensive
@ computations here. Set this to 0.0 to disable the load average limit.
|
| ︙ | ︙ | |||
767 768 769 770 771 772 773 774 775 776 777 778 779 780 |
"auto-captcha", "autocaptcha", 0, 0);
@ <p>When enabled, a button appears on the login screen for user
@ "anonymous" that will automatically fill in the CAPTCHA password.
@ This is less secure than forcing the user to do it manually, but is
@ probably secure enough and it is certainly more convenient for
@ anonymous users. (Property: "auto-captcha")</p>
@ <hr>
@ <p><input type="submit" name="submit" value="Apply Changes"></p>
@ </div></form>
db_end_transaction(0);
style_finish_page();
}
| > > > > > > > | 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 |
"auto-captcha", "autocaptcha", 0, 0);
@ <p>When enabled, a button appears on the login screen for user
@ "anonymous" that will automatically fill in the CAPTCHA password.
@ This is less secure than forcing the user to do it manually, but is
@ probably secure enough and it is certainly more convenient for
@ anonymous users. (Property: "auto-captcha")</p>
@ <hr>
entry_attribute("Anonymous Login Validity", 11, "anon-cookie-lifespan",
"anoncookls", "840", 0);
@ <p>The number of minutes for which an anonymous login cookie is valid.
@ Set to zero to disable anonymous logins.
@ (property: anon-cookie-lifespan)
@ <hr>
@ <p><input type="submit" name="submit" value="Apply Changes"></p>
@ </div></form>
db_end_transaction(0);
style_finish_page();
}
|
| ︙ | ︙ |