Fossil SCM

Improvements to the robot-detection captcha.

drh 2024-08-22 22:48 trunk
Commit 66b111aa42ee9db7546e973cddc7a06dd5888a96d190c7d77860615f8797005a
3 files changed +3 +17 -4 +30 -1
+3
--- src/blob.c
+++ src/blob.c
@@ -125,10 +125,13 @@
125125
*/
126126
int fossil_islower(char c){ return c>='a' && c<='z'; }
127127
int fossil_isupper(char c){ return c>='A' && c<='Z'; }
128128
int fossil_isdigit(char c){ return c>='0' && c<='9'; }
129129
int fossil_isxdigit(char c){ return (c>='0' && c<='9') || (c>='a' && c<='f'); }
130
+int fossil_isXdigit(char c){
131
+ return (c>='0' && c<='9') || (c>='A' && c<='F') || (c>='a' && c<='f');
132
+}
130133
int fossil_tolower(char c){
131134
return fossil_isupper(c) ? c - 'A' + 'a' : c;
132135
}
133136
int fossil_toupper(char c){
134137
return fossil_islower(c) ? c - 'a' + 'A' : c;
135138
--- src/blob.c
+++ src/blob.c
@@ -125,10 +125,13 @@
125 */
126 int fossil_islower(char c){ return c>='a' && c<='z'; }
127 int fossil_isupper(char c){ return c>='A' && c<='Z'; }
128 int fossil_isdigit(char c){ return c>='0' && c<='9'; }
129 int fossil_isxdigit(char c){ return (c>='0' && c<='9') || (c>='a' && c<='f'); }
 
 
 
130 int fossil_tolower(char c){
131 return fossil_isupper(c) ? c - 'A' + 'a' : c;
132 }
133 int fossil_toupper(char c){
134 return fossil_islower(c) ? c - 'a' + 'A' : c;
135
--- src/blob.c
+++ src/blob.c
@@ -125,10 +125,13 @@
125 */
126 int fossil_islower(char c){ return c>='a' && c<='z'; }
127 int fossil_isupper(char c){ return c>='A' && c<='Z'; }
128 int fossil_isdigit(char c){ return c>='0' && c<='9'; }
129 int fossil_isxdigit(char c){ return (c>='0' && c<='9') || (c>='a' && c<='f'); }
130 int fossil_isXdigit(char c){
131 return (c>='0' && c<='9') || (c>='A' && c<='F') || (c>='a' && c<='f');
132 }
133 int fossil_tolower(char c){
134 return fossil_isupper(c) ? c - 'A' + 'a' : c;
135 }
136 int fossil_toupper(char c){
137 return fossil_islower(c) ? c - 'a' + 'A' : c;
138
+17 -4
--- src/captcha.c
+++ src/captcha.c
@@ -656,11 +656,17 @@
656656
const char *zPw = P("name");
657657
if( zPw==0 || zPw[0]==0 ){
658658
(void)exclude_spiders(1);
659659
@ <hr><p>The captcha is shown above. Add a name=HEX query parameter
660660
@ to see how HEX would be rendered in the current captcha font.
661
- @ <p>captcha_is_correct(1) returns %d(captcha_is_correct(1)).
661
+ @ <h2>Debug/Testing Values:</h2>
662
+ @ <ul>
663
+ @ <li> g.isHuman = %d(g.isHuman)
664
+ @ <li> g.zLogin = %h(g.zLogin)
665
+ @ <li> login_cookie_welformed() = %d(login_cookie_wellformed())
666
+ @ <li> captcha_is_correct(1) = %d(captcha_is_correct(1)).
667
+ @ </ul>
662668
style_finish_page();
663669
}else{
664670
style_set_current_feature("test");
665671
style_header("Captcha Test");
666672
@ <pre class="captcha">
@@ -683,11 +689,18 @@
683689
**
684690
** If the bTest argument is non-zero, then show the captcha regardless of
685691
** how the agent identifies. This is used for testing only.
686692
*/
687693
int exclude_spiders(int bTest){
688
- if( !bTest && (g.isHuman || g.zLogin!=0) ) return 0;
694
+ if( !bTest ){
695
+ if( g.isHuman ) return 0; /* This user has already proven human */
696
+ if( g.zLogin!=0 ) return 0; /* Logged in. Consider them human */
697
+ if( login_cookie_wellformed() ){
698
+ /* Logged into another member of the login group */
699
+ return 0;
700
+ }
701
+ }
689702
690703
/* This appears to be a spider. Offer the captcha */
691704
style_set_current_feature("captcha");
692705
style_header("I think you are a robot");
693706
style_submenu_enable(0);
@@ -723,12 +736,12 @@
723736
*/
724737
void captcha_callback(void){
725738
int bTest = atoi(PD("istest","0"));
726739
if( captcha_is_correct(1) ){
727740
if( bTest==0 ){
728
- login_check_credentials();
729
- if( g.zLogin==0 ){
741
+ if( !login_cookie_wellformed() ){
742
+ /* ^^^^--- Don't overwrite a valid login on another repo! */
730743
login_set_anon_cookie(0, 0);
731744
}
732745
cgi_append_header("X-Robot: 0\r\n");
733746
}
734747
login_redirect_to_g();
735748
--- src/captcha.c
+++ src/captcha.c
@@ -656,11 +656,17 @@
656 const char *zPw = P("name");
657 if( zPw==0 || zPw[0]==0 ){
658 (void)exclude_spiders(1);
659 @ <hr><p>The captcha is shown above. Add a name=HEX query parameter
660 @ to see how HEX would be rendered in the current captcha font.
661 @ <p>captcha_is_correct(1) returns %d(captcha_is_correct(1)).
 
 
 
 
 
 
662 style_finish_page();
663 }else{
664 style_set_current_feature("test");
665 style_header("Captcha Test");
666 @ <pre class="captcha">
@@ -683,11 +689,18 @@
683 **
684 ** If the bTest argument is non-zero, then show the captcha regardless of
685 ** how the agent identifies. This is used for testing only.
686 */
687 int exclude_spiders(int bTest){
688 if( !bTest && (g.isHuman || g.zLogin!=0) ) return 0;
 
 
 
 
 
 
 
689
690 /* This appears to be a spider. Offer the captcha */
691 style_set_current_feature("captcha");
692 style_header("I think you are a robot");
693 style_submenu_enable(0);
@@ -723,12 +736,12 @@
723 */
724 void captcha_callback(void){
725 int bTest = atoi(PD("istest","0"));
726 if( captcha_is_correct(1) ){
727 if( bTest==0 ){
728 login_check_credentials();
729 if( g.zLogin==0 ){
730 login_set_anon_cookie(0, 0);
731 }
732 cgi_append_header("X-Robot: 0\r\n");
733 }
734 login_redirect_to_g();
735
--- src/captcha.c
+++ src/captcha.c
@@ -656,11 +656,17 @@
656 const char *zPw = P("name");
657 if( zPw==0 || zPw[0]==0 ){
658 (void)exclude_spiders(1);
659 @ <hr><p>The captcha is shown above. Add a name=HEX query parameter
660 @ to see how HEX would be rendered in the current captcha font.
661 @ <h2>Debug/Testing Values:</h2>
662 @ <ul>
663 @ <li> g.isHuman = %d(g.isHuman)
664 @ <li> g.zLogin = %h(g.zLogin)
665 @ <li> login_cookie_welformed() = %d(login_cookie_wellformed())
666 @ <li> captcha_is_correct(1) = %d(captcha_is_correct(1)).
667 @ </ul>
668 style_finish_page();
669 }else{
670 style_set_current_feature("test");
671 style_header("Captcha Test");
672 @ <pre class="captcha">
@@ -683,11 +689,18 @@
689 **
690 ** If the bTest argument is non-zero, then show the captcha regardless of
691 ** how the agent identifies. This is used for testing only.
692 */
693 int exclude_spiders(int bTest){
694 if( !bTest ){
695 if( g.isHuman ) return 0; /* This user has already proven human */
696 if( g.zLogin!=0 ) return 0; /* Logged in. Consider them human */
697 if( login_cookie_wellformed() ){
698 /* Logged into another member of the login group */
699 return 0;
700 }
701 }
702
703 /* This appears to be a spider. Offer the captcha */
704 style_set_current_feature("captcha");
705 style_header("I think you are a robot");
706 style_submenu_enable(0);
@@ -723,12 +736,12 @@
736 */
737 void captcha_callback(void){
738 int bTest = atoi(PD("istest","0"));
739 if( captcha_is_correct(1) ){
740 if( bTest==0 ){
741 if( !login_cookie_wellformed() ){
742 /* ^^^^--- Don't overwrite a valid login on another repo! */
743 login_set_anon_cookie(0, 0);
744 }
745 cgi_append_header("X-Robot: 0\r\n");
746 }
747 login_redirect_to_g();
748
+30 -1
--- src/login.c
+++ src/login.c
@@ -1312,11 +1312,40 @@
13121312
*/
13131313
g.isHuman = 0;
13141314
(void)exclude_spiders(0);
13151315
cgi_reply();
13161316
fossil_exit(0);
1317
-}
1317
+}
1318
+
1319
+/*
1320
+** When this routine is called, we know that the request does not
1321
+** have a login on the present repository. This routine checks to
1322
+** see if their login cookie might be for another member of the
1323
+** login-group.
1324
+**
1325
+** If this repository is not a part of any login group, then this
1326
+** routine always returns false.
1327
+**
1328
+** If this repository is part of a login group, and the login cookie
1329
+** appears to be well-formed, then return true. That might be a
1330
+** false-positive, as we don't actually check to see if the login
1331
+** cookie is valid for some other repository. But false-positives
1332
+** are ok. This routine is used for robot defense only.
1333
+*/
1334
+int login_cookie_wellformed(void){
1335
+ const char *zCookie;
1336
+ int n;
1337
+ zCookie = P(login_cookie_name());
1338
+ if( zCookie==0 ){
1339
+ return 0;
1340
+ }
1341
+ if( !db_exists("SELECT 1 FROM config WHERE name='login-group-code'") ){
1342
+ return 0;
1343
+ }
1344
+ for(n=0; fossil_isXdigit(zCookie[n]); n++){}
1345
+ return n>48 && zCookie[n]=='/' && zCookie[n+1]!=0;
1346
+}
13181347
13191348
/*
13201349
** This routine examines the login cookie to see if it exists and
13211350
** is valid. If the login cookie checks out, it then sets global
13221351
** variables appropriately.
13231352
--- src/login.c
+++ src/login.c
@@ -1312,11 +1312,40 @@
1312 */
1313 g.isHuman = 0;
1314 (void)exclude_spiders(0);
1315 cgi_reply();
1316 fossil_exit(0);
1317 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1318
1319 /*
1320 ** This routine examines the login cookie to see if it exists and
1321 ** is valid. If the login cookie checks out, it then sets global
1322 ** variables appropriately.
1323
--- src/login.c
+++ src/login.c
@@ -1312,11 +1312,40 @@
1312 */
1313 g.isHuman = 0;
1314 (void)exclude_spiders(0);
1315 cgi_reply();
1316 fossil_exit(0);
1317 }
1318
1319 /*
1320 ** When this routine is called, we know that the request does not
1321 ** have a login on the present repository. This routine checks to
1322 ** see if their login cookie might be for another member of the
1323 ** login-group.
1324 **
1325 ** If this repository is not a part of any login group, then this
1326 ** routine always returns false.
1327 **
1328 ** If this repository is part of a login group, and the login cookie
1329 ** appears to be well-formed, then return true. That might be a
1330 ** false-positive, as we don't actually check to see if the login
1331 ** cookie is valid for some other repository. But false-positives
1332 ** are ok. This routine is used for robot defense only.
1333 */
1334 int login_cookie_wellformed(void){
1335 const char *zCookie;
1336 int n;
1337 zCookie = P(login_cookie_name());
1338 if( zCookie==0 ){
1339 return 0;
1340 }
1341 if( !db_exists("SELECT 1 FROM config WHERE name='login-group-code'") ){
1342 return 0;
1343 }
1344 for(n=0; fossil_isXdigit(zCookie[n]); n++){}
1345 return n>48 && zCookie[n]=='/' && zCookie[n+1]!=0;
1346 }
1347
1348 /*
1349 ** This routine examines the login cookie to see if it exists and
1350 ** is valid. If the login cookie checks out, it then sets global
1351 ** variables appropriately.
1352

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button