/*
** Copyright (c) 2002 D. Richard Hipp
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public
** License as published by the Free Software Foundation; either
** version 2 of the License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** General Public License for more details.
**
** You should have received a copy of the GNU General Public
** License along with this library; if not, write to the
** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
** Boston, MA 02111-1307, USA.
**
** Author contact information:
** drh@hwaci.com
** http://www.hwaci.com/drh/
**
*******************************************************************************
**
** This file contains code used to throttle output to misbehaving spiders.
*/
#include Your access to this website has been temporarily suspended because
@ you are using it excessively. You can retry your request later. This page is intended to capture spiders that
@ ignore the "robots.txt" file.
@ If you are not a spider, click on the "I am human" link
@ above. If you click on the "I am a spider" link, your access to this
@ server will be suspended for about an hour.
@ Remove older entries
common_footer();
}
/*
** WEBPAGE: /captcha
**
** Generate the captcha page. This is basically a honeypot with a cookie
** for state. Once the client exceeds the throttle threshold, they risk
** getting locked out unless they (eventually) get this question correct
** or slow down on the hits.
*/
void captcha_page(void){
time_t now = time(NULL);
int q1, q2;
if( atoi(PD("a","0")) == (atoi(PD("q1","-1")) + atoi(PD("q2","-1"))) ){
/* User gave the right answer. Set cookie and continue on.
*/
captcha_set_cookie();
cgi_redirect(PD("nxp","index"));
return;
}
/* Note that we don't do _any_ credential checks in this page... However,
** some flags are needed for sane header generation. For example, we
** want a "Login" in the menu rather than "Logout" so isAnon should be
** set.
*/
g.isAnon = 1;
common_standard_menu(0, 0);
common_add_help_item("CvstracAdminAbuse");
common_header("Abbreviated Turing Test");
/* small numbers */
srand(now);
q1 = (rand()%5)+1;
q2 = (rand()%5)+1;
@ In order to continue, you must show you're a human. Please answer
@ the following mathematical skill testing question (and ensure cookies
@ are enabled):
@
@
@
@
@
az = db_query("SELECT ipaddr, lastaccess, load FROM access_load %s LIMIT %d",
zOrderBy, limit);
for(i=0; az[i]; i+=3){
struct tm *pTm;
time_t atime;
char zTime[200];
atime = atoi(az[i+1]);
pTm = localtime(&atime);
strftime(zTime, sizeof(zTime), "%Y-%m-%d %H:%M:%S", pTm);
@ IP Address
@ Last Access
@ Load
}
@ %h(az[i])
@ %h(zTime)
@ %s(az[i+2])
@ @
@ common_footer(); } static int count_links(const char *zText){ int nLink = 0; if( zText!=0 ){ int i, j; for(i=0;zText[i];i++){ char c = zText[i]; if( (c=='h' || c=='f' || c=='m') && (j=is_url(&zText[i]))>0 ){ nLink ++; i += j; continue; } } } return nLink; } /* If someone blows the limit, tweak the current throttler counter ** for their IP. Each failure increases it by a defined fraction ** of the throttle limit, which mean they'll get locked out after ** triggering the failure too many times. Currently, that's ** twice. ** ** Hopefully this strikes a balance between stopping spammers and ** not annoying legitimate users too much... */ static void increase_load(){ const char *zAddr = getenv("REMOTE_ADDR"); const char *zLimit = db_config("throttle", 0); double rLimit; if( zLimit!=0 && (rLimit = atof(zLimit))>0.0 && zAddr!=0 ){ time_t now = time(0); char *zLastLoad = db_short_query("SELECT load FROM access_load " "WHERE ipaddr='%q'", zAddr); db_execute("REPLACE INTO access_load(ipaddr,load,lastaccess) " "VALUES('%q',%g,%d)", zAddr, (zLastLoad ? atof(zLastLoad) : 0) + rLimit/WIKI_EDIT_LOCKOUT, now); if(zLastLoad) free(zLastLoad); } /* we also need to clear any captcha cookie since having it ** bypasses the throttler. This is also handy since it's not ** IP specific, so users who are behind variable IP's are going ** to still get caught. */ captcha_clear_cookie(); } /* ** Apply any appropriate anti-spam heuristics to the provided wiki edit. ** ** Obviously, we're only going to apply this restriction to anonymous ** users. Currently. ** ** Returns NULL if the change is acceptable. Otherwise, it returns a string ** containing an explanation for the rejection. */ char *is_edit_allowed(const char *zOld, const char *zNew){ if( g.isAnon ){ const char *zKeys = db_config("keywords",""); int nMscore = atoi(db_config("keywords_max_score","0")); int nMax = atoi(db_config("max_links_per_edit","0")); /* ** Check for too many "bad words" in the new text. Checking the "diff" ** might be better? */ if( nMscore && zKeys[0] ) { db_add_functions(); if( db_exists("SELECT 1 WHERE search('%q','%q')>%d",zKeys,zNew,nMscore)){ increase_load(); return "Forbidden keywords!"; } } /* ** Check to see if the threshold of external links was exceeded. */ if( nMax ){ int nOld = count_links(zOld); int nNew = count_links(zNew); /* Note that someone could bypass this by replacing a whole bunch of ** links in an existing page. If that starts to happen it might be ** necessary to compare the list of links or something. ** ** Some keyword filtering would help a bit, too. */ if( nNew - nOld >= nMax ){ increase_load(); return "Too many external links for one edit!"; } } } return 0; }