Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Improvements and simplifications to anti-robot defenses. |
|---|---|
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA3-256: |
16b33097fe60eac71f84a7ca28362d36 |
| User & Date: | drh 2025-08-16 13:59:51.025 |
Context
|
2025-08-16
| ||
| 14:20 | Open up access to /test-robotck to all users. Clear the "Press OK to continue" from the screen when the Ok button is pressed, so that it does not linger for zip and tarball downloads. check-in: 508d3cd98a user: drh tags: trunk | |
| 13:59 | Improvements and simplifications to anti-robot defenses. check-in: 16b33097fe user: drh tags: trunk | |
| 13:57 | Improved anti-robot captcha. Closed-Leaf check-in: 206089acd1 user: drh tags: robot-restrict-simplified | |
| 10:10 | Correct the signature of an extern decl of fossil_strndup(), as reported in [forum:21ac5f59a0 | forum post 21ac5f59a0]. check-in: d546932976 user: stephan tags: trunk | |
Changes
Changes to src/browse.c.
| ︙ | ︙ | |||
1160 1161 1162 1163 1164 1165 1166 |
const char *zNow; /* Time of check-in */
int isBranchCI; /* name= is a branch name */
int showId = PB("showid");
Stmt q1, q2;
double baseTime;
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
| < | 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 |
const char *zNow; /* Time of check-in */
int isBranchCI; /* name= is a branch name */
int showId = PB("showid");
Stmt q1, q2;
double baseTime;
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
zName = P("name");
if( zName==0 ) zName = "tip";
rid = symbolic_name_to_rid(zName, "ci");
if( rid==0 ){
fossil_fatal("not a valid check-in: %s", zName);
}
zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
|
| ︙ | ︙ |
Changes to src/captcha.c.
| ︙ | ︙ | |||
742 743 744 745 746 747 748 |
const char *zPw = P("name");
if( zPw==0 || zPw[0]==0 ){
(void)exclude_spiders(1);
@ <hr><p>The captcha is shown above. Add a name=HEX query parameter
@ to see how HEX would be rendered in the current captcha font.
@ <h2>Debug/Testing Values:</h2>
@ <ul>
| | > > > > > > > > < | < < | < | 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 |
const char *zPw = P("name");
if( zPw==0 || zPw[0]==0 ){
(void)exclude_spiders(1);
@ <hr><p>The captcha is shown above. Add a name=HEX query parameter
@ to see how HEX would be rendered in the current captcha font.
@ <h2>Debug/Testing Values:</h2>
@ <ul>
@ <li> g.isRobot = %d(g.isRobot)
@ <li> g.zLogin = %h(g.zLogin)
@ <li> login_cookie_welformed() = %d(login_cookie_wellformed())
@ <li> captcha_is_correct(1) = %d(captcha_is_correct(1)).
@ </ul>
style_finish_page();
}else{
style_set_current_feature("test");
style_header("Captcha Test");
@ <pre class="captcha">
@ %s(captcha_render(zPw))
@ </pre>
style_finish_page();
}
}
/*
** WEBPAGE: honeypot
** This page is a honeypot for spiders and bots.
*/
void honeypot_page(void){
(void)exclude_spiders(0);
}
/*
** Check to see if the current request is coming from an agent that
** self-identifies as a spider.
**
** If the agent does not claim to be a spider or if the user has logged
** in (even as anonymous), then return 0 without doing anything.
**
** But if the user agent does self-identify as a spider and there is
** no login, offer a captcha challenge to allow the user agent to prove
** that he is human and return non-zero.
**
** If the bTest argument is non-zero, then show the captcha regardless of
** how the agent identifies. This is used for testing only.
*/
int exclude_spiders(int bTest){
if( !bTest ){
if( g.zLogin!=0 ) return 0; /* Logged in. Consider them human */
if( login_cookie_wellformed() ){
/* Logged into another member of the login group */
return 0;
}
}
/* This appears to be a spider. Offer the captcha */
style_set_current_feature("captcha");
style_header("Captcha");
style_submenu_enable(0);
@ <form method='POST' action='%R/ityaar'>
@ <h2>Prove that you are human:
if( bTest ){
@ <input type="hidden" name="istest" value="1">
}
captcha_generate(3);
@ </form>
if( !bTest ){
if( P("fossil-goto")==0 ){
|
| ︙ | ︙ | |||
828 829 830 831 832 833 834 |
/* ^^^^--- Don't overwrite a valid login on another repo! */
login_set_anon_cookie(0, 0);
}
cgi_append_header("X-Robot: 0\r\n");
}
login_redirect_to_g();
}else{
| | | 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 |
/* ^^^^--- Don't overwrite a valid login on another repo! */
login_set_anon_cookie(0, 0);
}
cgi_append_header("X-Robot: 0\r\n");
}
login_redirect_to_g();
}else{
g.isRobot = 1;
(void)exclude_spiders(bTest);
if( bTest ){
@ <hr><p>Wrong code. Try again
style_finish_page();
}
}
}
|
| ︙ | ︙ |
Changes to src/diff.c.
| ︙ | ︙ | |||
3786 3787 3788 3789 3790 3791 3792 |
struct AnnVers *p;
unsigned clr1, clr2, clr;
int bBlame = g.zPath[0]!='a';/* True for BLAME output. False for ANNOTATE. */
/* Gather query parameters */
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
| | < | 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 |
struct AnnVers *p;
unsigned clr1, clr2, clr;
int bBlame = g.zPath[0]!='a';/* True for BLAME output. False for ANNOTATE. */
/* Gather query parameters */
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
if( robot_restrict("annotate") ) return;
fossil_nice_default();
zFilename = P("filename");
zRevision = PD("checkin",0);
zOrigin = P("origin");
zLimit = P("limit");
showLog = PB("log");
fileVers = PB("filevers");
|
| ︙ | ︙ |
Changes to src/diffcmd.c.
| ︙ | ︙ | |||
1520 1521 1522 1523 1524 1525 1526 |
const char *zFrom = P("from");
const char *zTo = P("to");
DiffConfig DCfg;
cgi_check_for_malice();
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
if( zFrom==0 || zTo==0 ) fossil_redirect_home();
| | | 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 |
const char *zFrom = P("from");
const char *zTo = P("to");
DiffConfig DCfg;
cgi_check_for_malice();
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
if( zFrom==0 || zTo==0 ) fossil_redirect_home();
if( robot_restrict("diff") ) return;
fossil_nice_default();
cgi_set_content_type("text/plain");
diff_config_init(&DCfg, DIFF_VERBOSE);
diff_two_versions(zFrom, zTo, &DCfg, 0);
}
|
Changes to src/info.c.
| ︙ | ︙ | |||
1419 1420 1421 1422 1423 1424 1425 |
int graphFlags = 0;
Blob qp; /* non-glob= query parameters for generated links */
Blob qpGlob; /* glob= query parameter for generated links */
int bInvert = PB("inv");
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
| | | 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 |
int graphFlags = 0;
Blob qp; /* non-glob= query parameters for generated links */
Blob qpGlob; /* glob= query parameter for generated links */
int bInvert = PB("inv");
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
if( robot_restrict("diff") ) return;
login_anonymous_available();
fossil_nice_default();
blob_init(&qp, 0, 0);
blob_init(&qpGlob, 0, 0);
diffType = preferred_diff_type();
zRe = P("regex");
if( zRe ) re_compile(&pRe, zRe, 0);
|
| ︙ | ︙ | |||
1973 1974 1975 1976 1977 1978 1979 |
ReCompiled *pRe = 0;
u32 objdescFlags = 0;
int verbose = PB("verbose");
DiffConfig DCfg;
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
| | | 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 |
ReCompiled *pRe = 0;
u32 objdescFlags = 0;
int verbose = PB("verbose");
DiffConfig DCfg;
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
if( robot_restrict("diff") ) return;
diff_config_init(&DCfg, 0);
diffType = preferred_diff_type();
if( P("from") && P("to") ){
v1 = artifact_from_ci_and_filename("from");
v2 = artifact_from_ci_and_filename("to");
if( v1==0 || v2==0 ) fossil_redirect_home();
}else{
|
| ︙ | ︙ | |||
2414 2415 2416 2417 2418 2419 2420 |
blob_zero(&downloadName);
if( P("verbose")!=0 ) objdescFlags |= OBJDESC_DETAIL;
object_description(rid, objdescFlags, 0, &downloadName);
style_submenu_element("Download", "%R/raw/%s?at=%T",
zUuid, file_tail(blob_str(&downloadName)));
@ <hr>
content_get(rid, &content);
| | | | 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 |
blob_zero(&downloadName);
if( P("verbose")!=0 ) objdescFlags |= OBJDESC_DETAIL;
object_description(rid, objdescFlags, 0, &downloadName);
style_submenu_element("Download", "%R/raw/%s?at=%T",
zUuid, file_tail(blob_str(&downloadName)));
@ <hr>
content_get(rid, &content);
if( blob_size(&content)>100000 ){
/* Prevent robots from running hexdump on megabyte-sized source files
** and there by eating up lots of CPU time and bandwidth. There is
** no good reason for a robot to need a hexdump. */
@ <p>A hex dump of this file is not available because it is too large.
@ Please download the raw binary file and generate a hex dump yourself.</p>
}else{
@ <blockquote><pre>
hexdump(&content);
@ </pre></blockquote>
}
style_finish_page();
|
| ︙ | ︙ | |||
2700 2701 2702 2703 2704 2705 2706 |
const char *zName = P("name");
const char *zCI = P("ci");
HQuery url;
char *zCIUuid = 0;
int isSymbolicCI = 0; /* ci= exists and is a symbolic name, not a hash */
int isBranchCI = 0; /* ci= refers to a branch name */
char *zHeader = 0;
| < < < < < | 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 |
const char *zName = P("name");
const char *zCI = P("ci");
HQuery url;
char *zCIUuid = 0;
int isSymbolicCI = 0; /* ci= exists and is a symbolic name, not a hash */
int isBranchCI = 0; /* ci= refers to a branch name */
char *zHeader = 0;
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
cgi_check_for_malice();
style_set_current_feature("artifact");
if( fossil_strcmp(g.zPath, "docfile")==0 ){
isFile = 1;
docOnly = 1;
}
/* Capture and normalize the name= and ci= query parameters */
if( zName==0 ){
zName = P("filename");
if( zName==0 ){
zName = P("fn");
}
|
| ︙ | ︙ |
Changes to src/login.c.
| ︙ | ︙ | |||
1301 1302 1303 1304 1305 1306 1307 |
fossil_exit(0);
}
}
fossil_free(zDecode);
return uid;
}
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 |
fossil_exit(0);
}
}
fossil_free(zDecode);
return uid;
}
/*
** When this routine is called, we know that the request does not
** have a login on the present repository. This routine checks to
** see if their login cookie might be for another member of the
** login-group.
**
** If this repository is not a part of any login group, then this
|
| ︙ | ︙ | |||
1427 1428 1429 1430 1431 1432 1433 | ** is valid. If the login cookie checks out, it then sets global ** variables appropriately. ** ** g.userUid Database USER.UID value. Might be -1 for "nobody" ** g.zLogin Database USER.LOGIN value. NULL for user "nobody" ** g.perm Permissions granted to this user ** g.anon Permissions that would be available to anonymous | | | 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 |
** is valid. If the login cookie checks out, it then sets global
** variables appropriately.
**
** g.userUid Database USER.UID value. Might be -1 for "nobody"
** g.zLogin Database USER.LOGIN value. NULL for user "nobody"
** g.perm Permissions granted to this user
** g.anon Permissions that would be available to anonymous
** g.isRobot True if the client is known to be a spider or robot
** g.perm Populated based on user account's capabilities
**
*/
void login_check_credentials(void){
int uid = 0; /* User id */
const char *zCookie; /* Text of the login cookie */
const char *zIpAddr; /* Raw IP address of the requestor */
|
| ︙ | ︙ | |||
1468 1469 1470 1471 1472 1473 1474 |
uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", zLogin);
}else{
uid = db_int(0, "SELECT uid FROM user WHERE cap LIKE '%%s%%'");
}
g.zLogin = db_text("?", "SELECT login FROM user WHERE uid=%d", uid);
zCap = "sxy";
g.noPswd = 1;
| | | 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 |
uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", zLogin);
}else{
uid = db_int(0, "SELECT uid FROM user WHERE cap LIKE '%%s%%'");
}
g.zLogin = db_text("?", "SELECT login FROM user WHERE uid=%d", uid);
zCap = "sxy";
g.noPswd = 1;
g.isRobot = 0;
zSeed = db_text("??", "SELECT uid||quote(login)||quote(pw)||quote(cookie)"
" FROM user WHERE uid=%d", uid);
login_create_csrf_secret(zSeed);
fossil_free(zSeed);
}
/* Check the login cookie to see if it matches a known valid user.
|
| ︙ | ︙ | |||
1602 1603 1604 1605 1606 1607 1608 |
zCap = "";
}
login_create_csrf_secret("none");
}
login_set_uid(uid, zCap);
| | | > > > | 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 |
zCap = "";
}
login_create_csrf_secret("none");
}
login_set_uid(uid, zCap);
/* Maybe restrict access by robots */
if( g.zLogin==0 && robot_restrict(g.zPath) ){
cgi_reply();
fossil_exit(0);
}
}
/*
** Set the current logged in user to be uid. zCap is precomputed
** (override) capabilities. If zCap==0, then look up the capabilities
** in the USER table.
*/
|
| ︙ | ︙ | |||
1642 1643 1644 1645 1646 1647 1648 |
** "nobody" user is a special case in that g.zLogin==0.
*/
g.userUid = uid;
if( fossil_strcmp(g.zLogin,"nobody")==0 ){
g.zLogin = 0;
}
if( PB("isrobot") ){
| | | | | | 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 |
** "nobody" user is a special case in that g.zLogin==0.
*/
g.userUid = uid;
if( fossil_strcmp(g.zLogin,"nobody")==0 ){
g.zLogin = 0;
}
if( PB("isrobot") ){
g.isRobot = 1;
}else if( g.zLogin==0 ){
g.isRobot = !isHuman(P("HTTP_USER_AGENT"));
}else{
g.isRobot = 0;
}
/* Set the capabilities */
login_replace_capabilities(zCap, 0);
/* The auto-hyperlink setting allows hyperlinks to be displayed for users
** who do not have the "h" permission as long as their UserAgent string
** makes it appear that they are human. Check to see if auto-hyperlink is
** enabled for this repository and make appropriate adjustments to the
** permission flags if it is. This should be done before the permissions
** are (potentially) copied to the anonymous permission set; otherwise,
** those will be out-of-sync.
*/
if( zCap[0] && !g.perm.Hyperlink && !g.isRobot ){
int autoLink = db_get_int("auto-hyperlink",1);
if( autoLink==1 ){
g.jsHref = 1;
g.perm.Hyperlink = 1;
}else if( autoLink==2 ){
g.perm.Hyperlink = 1;
}
|
| ︙ | ︙ |
Changes to src/main.c.
| ︙ | ︙ | |||
231 232 233 234 235 236 237 |
#if USE_SEE
const char *zPidKey; /* Saved value of the --usepidkey option. Only
* applicable when using SEE on Windows or Linux. */
#endif
int useLocalauth; /* No login required if from 127.0.0.1 */
int noPswd; /* Logged in without password (on 127.0.0.1) */
int userUid; /* Integer user id */
| | > | 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 |
#if USE_SEE
const char *zPidKey; /* Saved value of the --usepidkey option. Only
* applicable when using SEE on Windows or Linux. */
#endif
int useLocalauth; /* No login required if from 127.0.0.1 */
int noPswd; /* Logged in without password (on 127.0.0.1) */
int userUid; /* Integer user id */
int isRobot; /* True if the client is definitely a robot. False
** negatives are common for this flag */
int comFmtFlags; /* Zero or more "COMMENT_PRINT_*" bit flags, should be
** accessed through get_comment_format(). */
const char *zSockName; /* Name of the unix-domain socket file */
const char *zSockMode; /* File permissions for unix-domain socket */
const char *zSockOwner; /* Owner, or owner:group for unix-domain socket */
/* Information used to populate the RCVFROM table */
|
| ︙ | ︙ |
Changes to src/robot.c.
| ︙ | ︙ | |||
20 21 22 23 24 25 26 | ** Fossil is run as a service. */ #include "config.h" #include "robot.h" #include <assert.h> #include <time.h> | < < < < < < < < < > | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | ** Fossil is run as a service. */ #include "config.h" #include "robot.h" #include <assert.h> #include <time.h> #define POW_COOKIE "fossil-proofofwork" /* ** Rewrite the current page with a robot squelch captcha and return 1. ** ** Or, if valid proof-of-work is present as either a query parameter or ** as a cookie, then return 0. */ |
| ︙ | ︙ | |||
69 70 71 72 73 74 75 | } h1 = (h1 % 900000000) + 100000000; h2 = (h2 % 900000000) + 100000000; /* If there is already a proof-of-work cookie with this value ** that means that the user agent has already authenticated. */ | | | | | | | > | < | | | | | | | | > > > > > > | | | > > > > > > > > > > > > > > > > > | > > > > > | < < < | > | < < | | < | < < < < < < < < | > < < > | > < < | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 |
}
h1 = (h1 % 900000000) + 100000000;
h2 = (h2 % 900000000) + 100000000;
/* If there is already a proof-of-work cookie with this value
** that means that the user agent has already authenticated.
*/
z = P(POW_COOKIE);
if( z
&& (atoi(z)==h1 || atoi(z)==h2)
&& !cgi_is_qp(POW_COOKIE) ){
return 0;
}
/* Check for a proof query parameter. If found, that means that
** the captcha has just now passed, so set the proof-of-work cookie
** in addition to letting the request through.
*/
z = P("proof");
if( z
&& (atoi(z)==h1 || atoi(z)==h2)
){
cgi_set_cookie(POW_COOKIE,z,"/",900);
return 0;
}
cgi_tag_query_parameter("proof");
/* Ask the client to present proof-of-work */
cgi_reset_content();
cgi_set_content_type("text/html");
style_header("Browser Verification");
@ <h1 id="x1">Checking to see if you are a robot<span id="x2"></span></h1>
@ <form method="GET">
@ <p id="x3" style="visibility:hidden;">\
@ Press <input type="submit" id="x5" value="Ok" focus> to continue</p>
cgi_query_parameters_to_hidden();
@ <input id="x4" type="hidden" name="proof" value="0">
@ </form>
@ <script nonce='%s(style_nonce())'>
@ function aaa(x){return document.getElementById(x);}
@ function bbb(h,a){
@ aaa("x4").value=h
@ if((a%%75)==0){
@ aaa("x2").textContent=aaa("x2").textContent+".";
@ }
@ if(a>0){
@ setTimeout(bbb,1,h+a,a-1);
@ }else{
@ aaa("x3").style.visibility="visible";
@ aaa("x2").textContent="";
@ aaa("x1").textContent="All clear";
@ aaa("x5").focus();
@ }
@ }
k = 800 + h2%99;
h2 = (k*k + k)/2;
@ setTimeout(function(){bbb(%u(h1-h2),%u(k));},10);
@ </script>
style_finish_page();
return 1;
}
/*
** SETTING: robot-restrict width=40 block-text
** The VALUE of this setting is a list of GLOB patterns that match
** pages for which complex HTTP requests from unauthenicated clients
** should be disallowed. "Unauthenticated" means the user is "nobody".
** The recommended value for this setting is:
**
** timelineX,diff,annotate,zip,fileage,file
**
** The "diff" tag covers all diffing pages such as /vdiff, /fdiff, and
** /vpatch. The "annotate" tag also covers /blame and /praise. "zip"
** also covers /tarball and /sqlar. If a tag has an "X" character appended,
** then it only applies if query parameters are such that the page is
** particularly difficult to compute.
**
** In all other case, the tag should exactly match the page name.
*/
/*
** Return the default restriction GLOB
*/
const char *robot_restrict_default(void){
return "timelineX,diff,annotate,zip,fileage,file";
}
/*
** Check to see if the page named in the argument is on the
** robot-restrict list. If it is on the list and if the user
** is "nobody" then bring up a captcha to test to make sure that
** client is not a robot.
**
** This routine returns true if a captcha was rendered and if subsequent
** page generation should be aborted. It returns false if the page
** should not be restricted and should be rendered normally.
*/
int robot_restrict(const char *zPage){
const char *zGlob;
const char *zToken;
if( g.zLogin ) return 0; /* Logged in users always get through */
zGlob = db_get("robot-restrict",robot_restrict_default());
if( zGlob==0 || zGlob[0]==0 ) return 0;
if( !glob_multi_match(zGlob, zPage) ) return 0;
zToken = P("token");
if( zToken!=0
&& db_exists("SELECT 1 FROM config WHERE name='token-%q'", zToken)
){
return 0; /* There is a valid token= query parameter */
}
if( robot_proofofwork() ){
return 1;
}
return 0;
}
/*
** WEBPAGE: test-robotck
**
** Run the robot_restrict() function using the value of the "name="
** query parameter as an argument. Used for testing the robot_restrict()
** logic.
**
** Whenever this page is successfully rendered (when it doesn't go to
** the captcha) it deletes the proof-of-work cookie. So reloading the
** page will reset the cookie and restart the verification.
*/
void robot_restrict_test_page(void){
const char *zName = P("name");
const char *zP1 = P("proof");
const char *zP2 = P(POW_COOKIE);
const char *z;
if( zName==0 || zName[0]==0 ) zName = g.zPath;
login_check_credentials();
if( !g.perm.Admin ){ login_needed(0); return; }
g.zLogin = 0;
if( robot_restrict(zName) ) return;
style_set_current_feature("test");
style_header("robot_restrict() test");
@ <h1>Captcha passed</h1>
@
@ <p>
if( zP1 && zP1[0] ){
@ proof=%h(zP1)<br>
}
if( zP2 && zP2[0] ){
@ fossil_proofofwork=%h(zP2)<br>
cgi_set_cookie(POW_COOKIE,"",0,-1);
}
z = db_get("robot-restrict",robot_restrict_default());
if( z && z[0] ){
@ robot-restrict=%h(z)</br>
}
@ </p>
@ <p><a href="%R/test-robotck/%h(zName)">Retry</a>
style_finish_page();
}
|
Changes to src/setup.c.
| ︙ | ︙ | |||
493 494 495 496 497 498 499 | @ <p>The settings on this page are intended to help site administrators @ defend the site against robots. @ @ <form action="%R/setup_robot" method="post"><div> login_insert_csrf_secret(); @ <input type="submit" name="submit" value="Apply Changes"></p> @ <hr> | | | < | > | | | | | > > > > > > | > > > | < < < < < < < < < < < < < < < < < < < < < < < < < < | 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 |
@ <p>The settings on this page are intended to help site administrators
@ defend the site against robots.
@
@ <form action="%R/setup_robot" method="post"><div>
login_insert_csrf_secret();
@ <input type="submit" name="submit" value="Apply Changes"></p>
@ <hr>
@ <p><b>Do not allow robots access to these pages.</b>
@ <p> If the page name matches the GLOB pattern of this setting, and the
@ users is "nobody", and the client has not previously passed a captcha
@ test to show that it is not a robot, then the page is not displayed.
@ A captcha test is is rendered instead.
@ The recommended value for this setting is:
@ <p>
@    <tt>%h(robot_restrict_default())</tt>
@ <p>
@ The "diff" tag covers all diffing pages such as /vdiff, /fdiff, and
@ /vpatch. The "annotate" tag covers /annotate and also /blame and
@ /praise. The "zip" covers itself and also /tarball and /sqlar. If a
@ tag has an "X" character appended, then it only applies if query
@ parameters are such that the page is particularly difficult to compute.
@ In all other case, the tag should exactly match the page name.
@ (Property: robot-restrict)
@ <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.
@ This limit is only enforced on Unix servers. On Linux systems,
@ access to the /proc virtual filesystem is required, which means this limit
@ might not work inside a chroot() jail.
@ (Property: "max-loadavg")</p>
@
@ <hr>
@ <p><input type="submit" name="submit" value="Apply Changes"></p>
@ </div></form>
db_end_transaction(0);
style_finish_page();
}
|
| ︙ | ︙ |
Changes to src/style.c.
| ︙ | ︙ | |||
1388 1389 1390 1391 1392 1393 1394 |
** Display CGI-variables and other aspects of the run-time
** environment, for debugging and trouble-shooting purposes.
*/
void page_test_env(void){
webpage_error("");
}
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 |
** Display CGI-variables and other aspects of the run-time
** environment, for debugging and trouble-shooting purposes.
*/
void page_test_env(void){
webpage_error("");
}
/*
** Webpages that encounter an error due to missing or incorrect
** query parameters can jump to this routine to render an error
** message screen.
**
** For administators, or if the test_env_enable setting is true, then
** details of the request environment are displayed. Otherwise, just
|
| ︙ | ︙ | |||
1485 1486 1487 1488 1489 1490 1491 |
#endif
@ g.zBaseURL = %h(g.zBaseURL)<br>
@ g.zHttpsURL = %h(g.zHttpsURL)<br>
@ g.zTop = %h(g.zTop)<br>
@ g.zPath = %h(g.zPath)<br>
@ g.userUid = %d(g.userUid)<br>
@ g.zLogin = %h(g.zLogin)<br>
| | | 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 |
#endif
@ g.zBaseURL = %h(g.zBaseURL)<br>
@ g.zHttpsURL = %h(g.zHttpsURL)<br>
@ g.zTop = %h(g.zTop)<br>
@ g.zPath = %h(g.zPath)<br>
@ g.userUid = %d(g.userUid)<br>
@ g.zLogin = %h(g.zLogin)<br>
@ g.isRobot = %d(g.isRobot)<br>
@ g.jsHref = %d(g.jsHref)<br>
if( g.zLocalRoot ){
@ g.zLocalRoot = %h(g.zLocalRoot)<br>
}else{
@ g.zLocalRoot = <i>none</i><br>
}
if( g.nRequest ){
|
| ︙ | ︙ |
Changes to src/tar.c.
| ︙ | ︙ | |||
758 759 760 761 762 763 764 |
Glob *pInclude = 0; /* The compiled in= glob pattern */
Glob *pExclude = 0; /* The compiled ex= glob pattern */
Blob tarball; /* Tarball accumulated here */
const char *z;
login_check_credentials();
if( !g.perm.Zip ){ login_needed(g.anon.Zip); return; }
| | | 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 |
Glob *pInclude = 0; /* The compiled in= glob pattern */
Glob *pExclude = 0; /* The compiled ex= glob pattern */
Blob tarball; /* Tarball accumulated here */
const char *z;
login_check_credentials();
if( !g.perm.Zip ){ login_needed(g.anon.Zip); return; }
if( robot_restrict("zip") ) return;
fossil_nice_default();
zName = fossil_strdup(PD("name",""));
z = P("r");
if( z==0 ) z = P("uuid");
if( z==0 ) z = tar_uuid_from_name(&zName);
if( z==0 ) z = "trunk";
g.zOpenRevision = zRid = fossil_strdup(z);
|
| ︙ | ︙ |
Changes to src/timeline.c.
| ︙ | ︙ | |||
1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 |
}
if( (!g.perm.Read && !g.perm.RdTkt && !g.perm.RdWiki && !g.perm.RdForum)
|| (bisectLocal && !g.perm.Setup)
){
login_needed(g.anon.Read && g.anon.RdTkt && g.anon.RdWiki);
return;
}
if( !bisectLocal ){
etag_check(ETAG_QUERY|ETAG_COOKIE|ETAG_DATA|ETAG_CONFIG, 0);
}
cookie_read_parameter("y","y");
zType = P("y");
if( zType==0 ){
zType = g.perm.Read ? "ci" : "all";
| > | 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 |
}
if( (!g.perm.Read && !g.perm.RdTkt && !g.perm.RdWiki && !g.perm.RdForum)
|| (bisectLocal && !g.perm.Setup)
){
login_needed(g.anon.Read && g.anon.RdTkt && g.anon.RdWiki);
return;
}
if( zBefore && robot_restrict("timelineX") ) return;
if( !bisectLocal ){
etag_check(ETAG_QUERY|ETAG_COOKIE|ETAG_DATA|ETAG_CONFIG, 0);
}
cookie_read_parameter("y","y");
zType = P("y");
if( zType==0 ){
zType = g.perm.Read ? "ci" : "all";
|
| ︙ | ︙ |
Changes to src/zip.c.
| ︙ | ︙ | |||
1010 1011 1012 1013 1014 1015 1016 |
Glob *pExclude = 0; /* The compiled ex= glob pattern */
Blob zip; /* ZIP archive accumulated here */
int eType = ARCHIVE_ZIP; /* Type of archive to generate */
char *zType; /* Human-readable archive type */
login_check_credentials();
if( !g.perm.Zip ){ login_needed(g.anon.Zip); return; }
| | | 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 |
Glob *pExclude = 0; /* The compiled ex= glob pattern */
Blob zip; /* ZIP archive accumulated here */
int eType = ARCHIVE_ZIP; /* Type of archive to generate */
char *zType; /* Human-readable archive type */
login_check_credentials();
if( !g.perm.Zip ){ login_needed(g.anon.Zip); return; }
if( robot_restrict("zip") ) return;
if( fossil_strcmp(g.zPath, "sqlar")==0 ){
eType = ARCHIVE_SQLAR;
zType = "SQL";
/* For some reason, SQL-archives are like catnip for robots. So
** don't allow them to be downloaded by user "nobody" */
if( g.zLogin==0 ){ login_needed(g.anon.Zip); return; }
}else{
|
| ︙ | ︙ |