Fossil SCM
Improvements and simplifications to anti-robot defenses.
Commit
16b33097fe60eac71f84a7ca28362d36da76a1ff5748bb132fc1bcdf73ca4476
Parent
d546932976888ae…
13 files changed
-1
+12
-8
+1
-2
+1
-1
+4
-9
+11
-96
+2
-1
+109
-60
+20
-37
+1
-46
+1
-1
+1
+1
-1
-1
| --- src/browse.c | ||
| +++ src/browse.c | ||
| @@ -1162,11 +1162,10 @@ | ||
| 1162 | 1162 | int showId = PB("showid"); |
| 1163 | 1163 | Stmt q1, q2; |
| 1164 | 1164 | double baseTime; |
| 1165 | 1165 | login_check_credentials(); |
| 1166 | 1166 | if( !g.perm.Read ){ login_needed(g.anon.Read); return; } |
| 1167 | - if( exclude_spiders(0) ) return; | |
| 1168 | 1167 | zName = P("name"); |
| 1169 | 1168 | if( zName==0 ) zName = "tip"; |
| 1170 | 1169 | rid = symbolic_name_to_rid(zName, "ci"); |
| 1171 | 1170 | if( rid==0 ){ |
| 1172 | 1171 | fossil_fatal("not a valid check-in: %s", zName); |
| 1173 | 1172 |
| --- src/browse.c | |
| +++ src/browse.c | |
| @@ -1162,11 +1162,10 @@ | |
| 1162 | int showId = PB("showid"); |
| 1163 | Stmt q1, q2; |
| 1164 | double baseTime; |
| 1165 | login_check_credentials(); |
| 1166 | if( !g.perm.Read ){ login_needed(g.anon.Read); return; } |
| 1167 | if( exclude_spiders(0) ) return; |
| 1168 | zName = P("name"); |
| 1169 | if( zName==0 ) zName = "tip"; |
| 1170 | rid = symbolic_name_to_rid(zName, "ci"); |
| 1171 | if( rid==0 ){ |
| 1172 | fossil_fatal("not a valid check-in: %s", zName); |
| 1173 |
| --- src/browse.c | |
| +++ src/browse.c | |
| @@ -1162,11 +1162,10 @@ | |
| 1162 | int showId = PB("showid"); |
| 1163 | Stmt q1, q2; |
| 1164 | double baseTime; |
| 1165 | login_check_credentials(); |
| 1166 | if( !g.perm.Read ){ login_needed(g.anon.Read); return; } |
| 1167 | zName = P("name"); |
| 1168 | if( zName==0 ) zName = "tip"; |
| 1169 | rid = symbolic_name_to_rid(zName, "ci"); |
| 1170 | if( rid==0 ){ |
| 1171 | fossil_fatal("not a valid check-in: %s", zName); |
| 1172 |
+12
-8
| --- src/captcha.c | ||
| +++ src/captcha.c | ||
| @@ -744,11 +744,11 @@ | ||
| 744 | 744 | (void)exclude_spiders(1); |
| 745 | 745 | @ <hr><p>The captcha is shown above. Add a name=HEX query parameter |
| 746 | 746 | @ to see how HEX would be rendered in the current captcha font. |
| 747 | 747 | @ <h2>Debug/Testing Values:</h2> |
| 748 | 748 | @ <ul> |
| 749 | - @ <li> g.isHuman = %d(g.isHuman) | |
| 749 | + @ <li> g.isRobot = %d(g.isRobot) | |
| 750 | 750 | @ <li> g.zLogin = %h(g.zLogin) |
| 751 | 751 | @ <li> login_cookie_welformed() = %d(login_cookie_wellformed()) |
| 752 | 752 | @ <li> captcha_is_correct(1) = %d(captcha_is_correct(1)). |
| 753 | 753 | @ </ul> |
| 754 | 754 | style_finish_page(); |
| @@ -759,10 +759,18 @@ | ||
| 759 | 759 | @ %s(captcha_render(zPw)) |
| 760 | 760 | @ </pre> |
| 761 | 761 | style_finish_page(); |
| 762 | 762 | } |
| 763 | 763 | } |
| 764 | + | |
| 765 | +/* | |
| 766 | +** WEBPAGE: honeypot | |
| 767 | +** This page is a honeypot for spiders and bots. | |
| 768 | +*/ | |
| 769 | +void honeypot_page(void){ | |
| 770 | + (void)exclude_spiders(0); | |
| 771 | +} | |
| 764 | 772 | |
| 765 | 773 | /* |
| 766 | 774 | ** Check to see if the current request is coming from an agent that |
| 767 | 775 | ** self-identifies as a spider. |
| 768 | 776 | ** |
| @@ -776,27 +784,23 @@ | ||
| 776 | 784 | ** If the bTest argument is non-zero, then show the captcha regardless of |
| 777 | 785 | ** how the agent identifies. This is used for testing only. |
| 778 | 786 | */ |
| 779 | 787 | int exclude_spiders(int bTest){ |
| 780 | 788 | if( !bTest ){ |
| 781 | - if( g.isHuman ) return 0; /* This user has already proven human */ | |
| 782 | 789 | if( g.zLogin!=0 ) return 0; /* Logged in. Consider them human */ |
| 783 | 790 | if( login_cookie_wellformed() ){ |
| 784 | 791 | /* Logged into another member of the login group */ |
| 785 | 792 | return 0; |
| 786 | 793 | } |
| 787 | 794 | } |
| 788 | 795 | |
| 789 | 796 | /* This appears to be a spider. Offer the captcha */ |
| 790 | 797 | style_set_current_feature("captcha"); |
| 791 | - style_header("I think you are a robot"); | |
| 798 | + style_header("Captcha"); | |
| 792 | 799 | style_submenu_enable(0); |
| 793 | 800 | @ <form method='POST' action='%R/ityaar'> |
| 794 | - @ <p>You seem like a robot. | |
| 795 | - @ | |
| 796 | - @ <p>If you are human, you can prove that by solving the captcha below, | |
| 797 | - @ after which you will be allowed to proceed. | |
| 801 | + @ <h2>Prove that you are human: | |
| 798 | 802 | if( bTest ){ |
| 799 | 803 | @ <input type="hidden" name="istest" value="1"> |
| 800 | 804 | } |
| 801 | 805 | captcha_generate(3); |
| 802 | 806 | @ </form> |
| @@ -830,11 +834,11 @@ | ||
| 830 | 834 | } |
| 831 | 835 | cgi_append_header("X-Robot: 0\r\n"); |
| 832 | 836 | } |
| 833 | 837 | login_redirect_to_g(); |
| 834 | 838 | }else{ |
| 835 | - g.isHuman = 0; | |
| 839 | + g.isRobot = 1; | |
| 836 | 840 | (void)exclude_spiders(bTest); |
| 837 | 841 | if( bTest ){ |
| 838 | 842 | @ <hr><p>Wrong code. Try again |
| 839 | 843 | style_finish_page(); |
| 840 | 844 | } |
| 841 | 845 |
| --- src/captcha.c | |
| +++ src/captcha.c | |
| @@ -744,11 +744,11 @@ | |
| 744 | (void)exclude_spiders(1); |
| 745 | @ <hr><p>The captcha is shown above. Add a name=HEX query parameter |
| 746 | @ to see how HEX would be rendered in the current captcha font. |
| 747 | @ <h2>Debug/Testing Values:</h2> |
| 748 | @ <ul> |
| 749 | @ <li> g.isHuman = %d(g.isHuman) |
| 750 | @ <li> g.zLogin = %h(g.zLogin) |
| 751 | @ <li> login_cookie_welformed() = %d(login_cookie_wellformed()) |
| 752 | @ <li> captcha_is_correct(1) = %d(captcha_is_correct(1)). |
| 753 | @ </ul> |
| 754 | style_finish_page(); |
| @@ -759,10 +759,18 @@ | |
| 759 | @ %s(captcha_render(zPw)) |
| 760 | @ </pre> |
| 761 | style_finish_page(); |
| 762 | } |
| 763 | } |
| 764 | |
| 765 | /* |
| 766 | ** Check to see if the current request is coming from an agent that |
| 767 | ** self-identifies as a spider. |
| 768 | ** |
| @@ -776,27 +784,23 @@ | |
| 776 | ** If the bTest argument is non-zero, then show the captcha regardless of |
| 777 | ** how the agent identifies. This is used for testing only. |
| 778 | */ |
| 779 | int exclude_spiders(int bTest){ |
| 780 | if( !bTest ){ |
| 781 | if( g.isHuman ) return 0; /* This user has already proven human */ |
| 782 | if( g.zLogin!=0 ) return 0; /* Logged in. Consider them human */ |
| 783 | if( login_cookie_wellformed() ){ |
| 784 | /* Logged into another member of the login group */ |
| 785 | return 0; |
| 786 | } |
| 787 | } |
| 788 | |
| 789 | /* This appears to be a spider. Offer the captcha */ |
| 790 | style_set_current_feature("captcha"); |
| 791 | style_header("I think you are a robot"); |
| 792 | style_submenu_enable(0); |
| 793 | @ <form method='POST' action='%R/ityaar'> |
| 794 | @ <p>You seem like a robot. |
| 795 | @ |
| 796 | @ <p>If you are human, you can prove that by solving the captcha below, |
| 797 | @ after which you will be allowed to proceed. |
| 798 | if( bTest ){ |
| 799 | @ <input type="hidden" name="istest" value="1"> |
| 800 | } |
| 801 | captcha_generate(3); |
| 802 | @ </form> |
| @@ -830,11 +834,11 @@ | |
| 830 | } |
| 831 | cgi_append_header("X-Robot: 0\r\n"); |
| 832 | } |
| 833 | login_redirect_to_g(); |
| 834 | }else{ |
| 835 | g.isHuman = 0; |
| 836 | (void)exclude_spiders(bTest); |
| 837 | if( bTest ){ |
| 838 | @ <hr><p>Wrong code. Try again |
| 839 | style_finish_page(); |
| 840 | } |
| 841 |
| --- src/captcha.c | |
| +++ src/captcha.c | |
| @@ -744,11 +744,11 @@ | |
| 744 | (void)exclude_spiders(1); |
| 745 | @ <hr><p>The captcha is shown above. Add a name=HEX query parameter |
| 746 | @ to see how HEX would be rendered in the current captcha font. |
| 747 | @ <h2>Debug/Testing Values:</h2> |
| 748 | @ <ul> |
| 749 | @ <li> g.isRobot = %d(g.isRobot) |
| 750 | @ <li> g.zLogin = %h(g.zLogin) |
| 751 | @ <li> login_cookie_welformed() = %d(login_cookie_wellformed()) |
| 752 | @ <li> captcha_is_correct(1) = %d(captcha_is_correct(1)). |
| 753 | @ </ul> |
| 754 | style_finish_page(); |
| @@ -759,10 +759,18 @@ | |
| 759 | @ %s(captcha_render(zPw)) |
| 760 | @ </pre> |
| 761 | style_finish_page(); |
| 762 | } |
| 763 | } |
| 764 | |
| 765 | /* |
| 766 | ** WEBPAGE: honeypot |
| 767 | ** This page is a honeypot for spiders and bots. |
| 768 | */ |
| 769 | void honeypot_page(void){ |
| 770 | (void)exclude_spiders(0); |
| 771 | } |
| 772 | |
| 773 | /* |
| 774 | ** Check to see if the current request is coming from an agent that |
| 775 | ** self-identifies as a spider. |
| 776 | ** |
| @@ -776,27 +784,23 @@ | |
| 784 | ** If the bTest argument is non-zero, then show the captcha regardless of |
| 785 | ** how the agent identifies. This is used for testing only. |
| 786 | */ |
| 787 | int exclude_spiders(int bTest){ |
| 788 | if( !bTest ){ |
| 789 | if( g.zLogin!=0 ) return 0; /* Logged in. Consider them human */ |
| 790 | if( login_cookie_wellformed() ){ |
| 791 | /* Logged into another member of the login group */ |
| 792 | return 0; |
| 793 | } |
| 794 | } |
| 795 | |
| 796 | /* This appears to be a spider. Offer the captcha */ |
| 797 | style_set_current_feature("captcha"); |
| 798 | style_header("Captcha"); |
| 799 | style_submenu_enable(0); |
| 800 | @ <form method='POST' action='%R/ityaar'> |
| 801 | @ <h2>Prove that you are human: |
| 802 | if( bTest ){ |
| 803 | @ <input type="hidden" name="istest" value="1"> |
| 804 | } |
| 805 | captcha_generate(3); |
| 806 | @ </form> |
| @@ -830,11 +834,11 @@ | |
| 834 | } |
| 835 | cgi_append_header("X-Robot: 0\r\n"); |
| 836 | } |
| 837 | login_redirect_to_g(); |
| 838 | }else{ |
| 839 | g.isRobot = 1; |
| 840 | (void)exclude_spiders(bTest); |
| 841 | if( bTest ){ |
| 842 | @ <hr><p>Wrong code. Try again |
| 843 | style_finish_page(); |
| 844 | } |
| 845 |
+1
-2
| --- src/diff.c | ||
| +++ src/diff.c | ||
| @@ -3788,12 +3788,11 @@ | ||
| 3788 | 3788 | int bBlame = g.zPath[0]!='a';/* True for BLAME output. False for ANNOTATE. */ |
| 3789 | 3789 | |
| 3790 | 3790 | /* Gather query parameters */ |
| 3791 | 3791 | login_check_credentials(); |
| 3792 | 3792 | if( !g.perm.Read ){ login_needed(g.anon.Read); return; } |
| 3793 | - if( exclude_spiders(0) ) return; | |
| 3794 | - if( robot_squelch(990) ) return; | |
| 3793 | + if( robot_restrict("annotate") ) return; | |
| 3795 | 3794 | fossil_nice_default(); |
| 3796 | 3795 | zFilename = P("filename"); |
| 3797 | 3796 | zRevision = PD("checkin",0); |
| 3798 | 3797 | zOrigin = P("origin"); |
| 3799 | 3798 | zLimit = P("limit"); |
| 3800 | 3799 |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -3788,12 +3788,11 @@ | |
| 3788 | int bBlame = g.zPath[0]!='a';/* True for BLAME output. False for ANNOTATE. */ |
| 3789 | |
| 3790 | /* Gather query parameters */ |
| 3791 | login_check_credentials(); |
| 3792 | if( !g.perm.Read ){ login_needed(g.anon.Read); return; } |
| 3793 | if( exclude_spiders(0) ) return; |
| 3794 | if( robot_squelch(990) ) return; |
| 3795 | fossil_nice_default(); |
| 3796 | zFilename = P("filename"); |
| 3797 | zRevision = PD("checkin",0); |
| 3798 | zOrigin = P("origin"); |
| 3799 | zLimit = P("limit"); |
| 3800 |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -3788,12 +3788,11 @@ | |
| 3788 | int bBlame = g.zPath[0]!='a';/* True for BLAME output. False for ANNOTATE. */ |
| 3789 | |
| 3790 | /* Gather query parameters */ |
| 3791 | login_check_credentials(); |
| 3792 | if( !g.perm.Read ){ login_needed(g.anon.Read); return; } |
| 3793 | if( robot_restrict("annotate") ) return; |
| 3794 | fossil_nice_default(); |
| 3795 | zFilename = P("filename"); |
| 3796 | zRevision = PD("checkin",0); |
| 3797 | zOrigin = P("origin"); |
| 3798 | zLimit = P("limit"); |
| 3799 |
+1
-1
| --- src/diffcmd.c | ||
| +++ src/diffcmd.c | ||
| @@ -1522,11 +1522,11 @@ | ||
| 1522 | 1522 | DiffConfig DCfg; |
| 1523 | 1523 | cgi_check_for_malice(); |
| 1524 | 1524 | login_check_credentials(); |
| 1525 | 1525 | if( !g.perm.Read ){ login_needed(g.anon.Read); return; } |
| 1526 | 1526 | if( zFrom==0 || zTo==0 ) fossil_redirect_home(); |
| 1527 | - if( robot_squelch(800) ) return; | |
| 1527 | + if( robot_restrict("diff") ) return; | |
| 1528 | 1528 | |
| 1529 | 1529 | fossil_nice_default(); |
| 1530 | 1530 | cgi_set_content_type("text/plain"); |
| 1531 | 1531 | diff_config_init(&DCfg, DIFF_VERBOSE); |
| 1532 | 1532 | diff_two_versions(zFrom, zTo, &DCfg, 0); |
| 1533 | 1533 |
| --- src/diffcmd.c | |
| +++ src/diffcmd.c | |
| @@ -1522,11 +1522,11 @@ | |
| 1522 | DiffConfig DCfg; |
| 1523 | cgi_check_for_malice(); |
| 1524 | login_check_credentials(); |
| 1525 | if( !g.perm.Read ){ login_needed(g.anon.Read); return; } |
| 1526 | if( zFrom==0 || zTo==0 ) fossil_redirect_home(); |
| 1527 | if( robot_squelch(800) ) return; |
| 1528 | |
| 1529 | fossil_nice_default(); |
| 1530 | cgi_set_content_type("text/plain"); |
| 1531 | diff_config_init(&DCfg, DIFF_VERBOSE); |
| 1532 | diff_two_versions(zFrom, zTo, &DCfg, 0); |
| 1533 |
| --- src/diffcmd.c | |
| +++ src/diffcmd.c | |
| @@ -1522,11 +1522,11 @@ | |
| 1522 | DiffConfig DCfg; |
| 1523 | cgi_check_for_malice(); |
| 1524 | login_check_credentials(); |
| 1525 | if( !g.perm.Read ){ login_needed(g.anon.Read); return; } |
| 1526 | if( zFrom==0 || zTo==0 ) fossil_redirect_home(); |
| 1527 | if( robot_restrict("diff") ) return; |
| 1528 | |
| 1529 | fossil_nice_default(); |
| 1530 | cgi_set_content_type("text/plain"); |
| 1531 | diff_config_init(&DCfg, DIFF_VERBOSE); |
| 1532 | diff_two_versions(zFrom, zTo, &DCfg, 0); |
| 1533 |
+4
-9
| --- src/info.c | ||
| +++ src/info.c | ||
| @@ -1421,11 +1421,11 @@ | ||
| 1421 | 1421 | Blob qpGlob; /* glob= query parameter for generated links */ |
| 1422 | 1422 | int bInvert = PB("inv"); |
| 1423 | 1423 | |
| 1424 | 1424 | login_check_credentials(); |
| 1425 | 1425 | if( !g.perm.Read ){ login_needed(g.anon.Read); return; } |
| 1426 | - if( robot_squelch(950) ) return; | |
| 1426 | + if( robot_restrict("diff") ) return; | |
| 1427 | 1427 | login_anonymous_available(); |
| 1428 | 1428 | fossil_nice_default(); |
| 1429 | 1429 | blob_init(&qp, 0, 0); |
| 1430 | 1430 | blob_init(&qpGlob, 0, 0); |
| 1431 | 1431 | diffType = preferred_diff_type(); |
| @@ -1975,11 +1975,11 @@ | ||
| 1975 | 1975 | int verbose = PB("verbose"); |
| 1976 | 1976 | DiffConfig DCfg; |
| 1977 | 1977 | |
| 1978 | 1978 | login_check_credentials(); |
| 1979 | 1979 | if( !g.perm.Read ){ login_needed(g.anon.Read); return; } |
| 1980 | - if( robot_squelch(800) ) return; | |
| 1980 | + if( robot_restrict("diff") ) return; | |
| 1981 | 1981 | diff_config_init(&DCfg, 0); |
| 1982 | 1982 | diffType = preferred_diff_type(); |
| 1983 | 1983 | if( P("from") && P("to") ){ |
| 1984 | 1984 | v1 = artifact_from_ci_and_filename("from"); |
| 1985 | 1985 | v2 = artifact_from_ci_and_filename("to"); |
| @@ -2416,15 +2416,15 @@ | ||
| 2416 | 2416 | object_description(rid, objdescFlags, 0, &downloadName); |
| 2417 | 2417 | style_submenu_element("Download", "%R/raw/%s?at=%T", |
| 2418 | 2418 | zUuid, file_tail(blob_str(&downloadName))); |
| 2419 | 2419 | @ <hr> |
| 2420 | 2420 | content_get(rid, &content); |
| 2421 | - if( !g.isHuman ){ | |
| 2421 | + if( blob_size(&content)>100000 ){ | |
| 2422 | 2422 | /* Prevent robots from running hexdump on megabyte-sized source files |
| 2423 | 2423 | ** and there by eating up lots of CPU time and bandwidth. There is |
| 2424 | 2424 | ** no good reason for a robot to need a hexdump. */ |
| 2425 | - @ <p>A hex dump of this file is not available. | |
| 2425 | + @ <p>A hex dump of this file is not available because it is too large. | |
| 2426 | 2426 | @ Please download the raw binary file and generate a hex dump yourself.</p> |
| 2427 | 2427 | }else{ |
| 2428 | 2428 | @ <blockquote><pre> |
| 2429 | 2429 | hexdump(&content); |
| 2430 | 2430 | @ </pre></blockquote> |
| @@ -2702,24 +2702,19 @@ | ||
| 2702 | 2702 | HQuery url; |
| 2703 | 2703 | char *zCIUuid = 0; |
| 2704 | 2704 | int isSymbolicCI = 0; /* ci= exists and is a symbolic name, not a hash */ |
| 2705 | 2705 | int isBranchCI = 0; /* ci= refers to a branch name */ |
| 2706 | 2706 | char *zHeader = 0; |
| 2707 | - int iCost; | |
| 2708 | 2707 | |
| 2709 | 2708 | login_check_credentials(); |
| 2710 | 2709 | if( !g.perm.Read ){ login_needed(g.anon.Read); return; } |
| 2711 | 2710 | cgi_check_for_malice(); |
| 2712 | 2711 | style_set_current_feature("artifact"); |
| 2713 | 2712 | if( fossil_strcmp(g.zPath, "docfile")==0 ){ |
| 2714 | 2713 | isFile = 1; |
| 2715 | 2714 | docOnly = 1; |
| 2716 | 2715 | } |
| 2717 | - iCost = 200; | |
| 2718 | - if( isFile ) iCost += 100; | |
| 2719 | - if( zCI ) iCost += 100; | |
| 2720 | - if( robot_squelch(iCost) ) return; | |
| 2721 | 2716 | |
| 2722 | 2717 | /* Capture and normalize the name= and ci= query parameters */ |
| 2723 | 2718 | if( zName==0 ){ |
| 2724 | 2719 | zName = P("filename"); |
| 2725 | 2720 | if( zName==0 ){ |
| 2726 | 2721 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -1421,11 +1421,11 @@ | |
| 1421 | Blob qpGlob; /* glob= query parameter for generated links */ |
| 1422 | int bInvert = PB("inv"); |
| 1423 | |
| 1424 | login_check_credentials(); |
| 1425 | if( !g.perm.Read ){ login_needed(g.anon.Read); return; } |
| 1426 | if( robot_squelch(950) ) return; |
| 1427 | login_anonymous_available(); |
| 1428 | fossil_nice_default(); |
| 1429 | blob_init(&qp, 0, 0); |
| 1430 | blob_init(&qpGlob, 0, 0); |
| 1431 | diffType = preferred_diff_type(); |
| @@ -1975,11 +1975,11 @@ | |
| 1975 | int verbose = PB("verbose"); |
| 1976 | DiffConfig DCfg; |
| 1977 | |
| 1978 | login_check_credentials(); |
| 1979 | if( !g.perm.Read ){ login_needed(g.anon.Read); return; } |
| 1980 | if( robot_squelch(800) ) return; |
| 1981 | diff_config_init(&DCfg, 0); |
| 1982 | diffType = preferred_diff_type(); |
| 1983 | if( P("from") && P("to") ){ |
| 1984 | v1 = artifact_from_ci_and_filename("from"); |
| 1985 | v2 = artifact_from_ci_and_filename("to"); |
| @@ -2416,15 +2416,15 @@ | |
| 2416 | object_description(rid, objdescFlags, 0, &downloadName); |
| 2417 | style_submenu_element("Download", "%R/raw/%s?at=%T", |
| 2418 | zUuid, file_tail(blob_str(&downloadName))); |
| 2419 | @ <hr> |
| 2420 | content_get(rid, &content); |
| 2421 | if( !g.isHuman ){ |
| 2422 | /* Prevent robots from running hexdump on megabyte-sized source files |
| 2423 | ** and there by eating up lots of CPU time and bandwidth. There is |
| 2424 | ** no good reason for a robot to need a hexdump. */ |
| 2425 | @ <p>A hex dump of this file is not available. |
| 2426 | @ Please download the raw binary file and generate a hex dump yourself.</p> |
| 2427 | }else{ |
| 2428 | @ <blockquote><pre> |
| 2429 | hexdump(&content); |
| 2430 | @ </pre></blockquote> |
| @@ -2702,24 +2702,19 @@ | |
| 2702 | HQuery url; |
| 2703 | char *zCIUuid = 0; |
| 2704 | int isSymbolicCI = 0; /* ci= exists and is a symbolic name, not a hash */ |
| 2705 | int isBranchCI = 0; /* ci= refers to a branch name */ |
| 2706 | char *zHeader = 0; |
| 2707 | int iCost; |
| 2708 | |
| 2709 | login_check_credentials(); |
| 2710 | if( !g.perm.Read ){ login_needed(g.anon.Read); return; } |
| 2711 | cgi_check_for_malice(); |
| 2712 | style_set_current_feature("artifact"); |
| 2713 | if( fossil_strcmp(g.zPath, "docfile")==0 ){ |
| 2714 | isFile = 1; |
| 2715 | docOnly = 1; |
| 2716 | } |
| 2717 | iCost = 200; |
| 2718 | if( isFile ) iCost += 100; |
| 2719 | if( zCI ) iCost += 100; |
| 2720 | if( robot_squelch(iCost) ) return; |
| 2721 | |
| 2722 | /* Capture and normalize the name= and ci= query parameters */ |
| 2723 | if( zName==0 ){ |
| 2724 | zName = P("filename"); |
| 2725 | if( zName==0 ){ |
| 2726 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -1421,11 +1421,11 @@ | |
| 1421 | Blob qpGlob; /* glob= query parameter for generated links */ |
| 1422 | int bInvert = PB("inv"); |
| 1423 | |
| 1424 | login_check_credentials(); |
| 1425 | if( !g.perm.Read ){ login_needed(g.anon.Read); return; } |
| 1426 | if( robot_restrict("diff") ) return; |
| 1427 | login_anonymous_available(); |
| 1428 | fossil_nice_default(); |
| 1429 | blob_init(&qp, 0, 0); |
| 1430 | blob_init(&qpGlob, 0, 0); |
| 1431 | diffType = preferred_diff_type(); |
| @@ -1975,11 +1975,11 @@ | |
| 1975 | int verbose = PB("verbose"); |
| 1976 | DiffConfig DCfg; |
| 1977 | |
| 1978 | login_check_credentials(); |
| 1979 | if( !g.perm.Read ){ login_needed(g.anon.Read); return; } |
| 1980 | if( robot_restrict("diff") ) return; |
| 1981 | diff_config_init(&DCfg, 0); |
| 1982 | diffType = preferred_diff_type(); |
| 1983 | if( P("from") && P("to") ){ |
| 1984 | v1 = artifact_from_ci_and_filename("from"); |
| 1985 | v2 = artifact_from_ci_and_filename("to"); |
| @@ -2416,15 +2416,15 @@ | |
| 2416 | object_description(rid, objdescFlags, 0, &downloadName); |
| 2417 | style_submenu_element("Download", "%R/raw/%s?at=%T", |
| 2418 | zUuid, file_tail(blob_str(&downloadName))); |
| 2419 | @ <hr> |
| 2420 | content_get(rid, &content); |
| 2421 | if( blob_size(&content)>100000 ){ |
| 2422 | /* Prevent robots from running hexdump on megabyte-sized source files |
| 2423 | ** and there by eating up lots of CPU time and bandwidth. There is |
| 2424 | ** no good reason for a robot to need a hexdump. */ |
| 2425 | @ <p>A hex dump of this file is not available because it is too large. |
| 2426 | @ Please download the raw binary file and generate a hex dump yourself.</p> |
| 2427 | }else{ |
| 2428 | @ <blockquote><pre> |
| 2429 | hexdump(&content); |
| 2430 | @ </pre></blockquote> |
| @@ -2702,24 +2702,19 @@ | |
| 2702 | HQuery url; |
| 2703 | char *zCIUuid = 0; |
| 2704 | int isSymbolicCI = 0; /* ci= exists and is a symbolic name, not a hash */ |
| 2705 | int isBranchCI = 0; /* ci= refers to a branch name */ |
| 2706 | char *zHeader = 0; |
| 2707 | |
| 2708 | login_check_credentials(); |
| 2709 | if( !g.perm.Read ){ login_needed(g.anon.Read); return; } |
| 2710 | cgi_check_for_malice(); |
| 2711 | style_set_current_feature("artifact"); |
| 2712 | if( fossil_strcmp(g.zPath, "docfile")==0 ){ |
| 2713 | isFile = 1; |
| 2714 | docOnly = 1; |
| 2715 | } |
| 2716 | |
| 2717 | /* Capture and normalize the name= and ci= query parameters */ |
| 2718 | if( zName==0 ){ |
| 2719 | zName = P("filename"); |
| 2720 | if( zName==0 ){ |
| 2721 |
+11
-96
| --- src/login.c | ||
| +++ src/login.c | ||
| @@ -1303,98 +1303,10 @@ | ||
| 1303 | 1303 | } |
| 1304 | 1304 | fossil_free(zDecode); |
| 1305 | 1305 | return uid; |
| 1306 | 1306 | } |
| 1307 | 1307 | |
| 1308 | -/* | |
| 1309 | -** SETTING: robot-restrict width=40 block-text | |
| 1310 | -** The VALUE of this setting is a list of GLOB patterns that match | |
| 1311 | -** pages for which complex HTTP requests from robots should be disallowed. | |
| 1312 | -** The recommended value for this setting is: | |
| 1313 | -** | |
| 1314 | -** timeline,vdiff,fdiff,annotate,blame | |
| 1315 | -** | |
| 1316 | -*/ | |
| 1317 | - | |
| 1318 | -/* | |
| 1319 | -** Check to see if the current HTTP request is a complex request that | |
| 1320 | -** is coming from a robot and if access should restricted for such robots. | |
| 1321 | -** For the purposes of this module, a "complex request" is an HTTP | |
| 1322 | -** request with one or more query parameters other than "name". | |
| 1323 | -** | |
| 1324 | -** If this routine determines that robots should be restricted, then | |
| 1325 | -** this routine publishes a redirect to the honeypot and exits without | |
| 1326 | -** returning to the caller. | |
| 1327 | -** | |
| 1328 | -** This routine believes that this is a complex request is coming from | |
| 1329 | -** a robot if all of the following are true: | |
| 1330 | -** | |
| 1331 | -** * The user is "nobody". | |
| 1332 | -** * Either the REFERER field of the HTTP header is missing or empty, | |
| 1333 | -** or the USERAGENT field of the HTTP header suggests that | |
| 1334 | -** the request as coming from a robot. | |
| 1335 | -** * There are one or more query parameters other than "name". | |
| 1336 | -** | |
| 1337 | -** Robot restrictions are governed by settings. | |
| 1338 | -** | |
| 1339 | -** robot-restrict The value is a list of GLOB patterns for pages | |
| 1340 | -** that should restrict robot access. No restrictions | |
| 1341 | -** are applied if this setting is undefined or is | |
| 1342 | -** an empty string. | |
| 1343 | -*/ | |
| 1344 | -void login_restrict_robot_access(void){ | |
| 1345 | - const char *zGlob; | |
| 1346 | - int isMatch = 1; | |
| 1347 | - int nQP; /* Number of query parameters other than name= */ | |
| 1348 | - if( g.zLogin!=0 ) return; | |
| 1349 | - zGlob = db_get("robot-restrict",0); | |
| 1350 | - if( zGlob==0 || zGlob[0]==0 ) return; | |
| 1351 | - if( g.isHuman ){ | |
| 1352 | - const char *zReferer; | |
| 1353 | - const char *zAccept; | |
| 1354 | - const char *zBr; | |
| 1355 | - zReferer = P("HTTP_REFERER"); | |
| 1356 | - if( zReferer && zReferer[0]!=0 ) return; | |
| 1357 | - | |
| 1358 | - /* Robots typically do not accept the brotli encoding, at least not | |
| 1359 | - ** at the time of this writing (2025-04-01), but standard web-browser | |
| 1360 | - ** all generally do accept brotli. So if brotli is accepted, | |
| 1361 | - ** assume we are not talking to a robot. We might want to revisit this | |
| 1362 | - ** heuristic in the future... | |
| 1363 | - */ | |
| 1364 | - if( (zAccept = P("HTTP_ACCEPT_ENCODING"))!=0 | |
| 1365 | - && (zBr = strstr(zAccept,"br"))!=0 | |
| 1366 | - && !fossil_isalnum(zBr[2]) | |
| 1367 | - && (zBr==zAccept || !fossil_isalnum(zBr[-1])) | |
| 1368 | - ){ | |
| 1369 | - return; | |
| 1370 | - } | |
| 1371 | - } | |
| 1372 | - nQP = cgi_qp_count(); | |
| 1373 | - if( nQP<1 ) return; | |
| 1374 | - isMatch = glob_multi_match(zGlob, g.zPath); | |
| 1375 | - if( !isMatch ) return; | |
| 1376 | - | |
| 1377 | - /* Check for exceptions to the restriction on the number of query | |
| 1378 | - ** parameters. */ | |
| 1379 | - zGlob = db_get("robot-restrict-qp",0); | |
| 1380 | - if( zGlob && zGlob[0] ){ | |
| 1381 | - char *zPath = mprintf("%s/%d", g.zPath, nQP); | |
| 1382 | - isMatch = glob_multi_match(zGlob, zPath); | |
| 1383 | - fossil_free(zPath); | |
| 1384 | - if( isMatch ) return; | |
| 1385 | - } | |
| 1386 | - | |
| 1387 | - /* If we reach this point, it means we have a situation where we | |
| 1388 | - ** want to restrict the activity of a robot. | |
| 1389 | - */ | |
| 1390 | - g.isHuman = 0; | |
| 1391 | - (void)exclude_spiders(0); | |
| 1392 | - cgi_reply(); | |
| 1393 | - fossil_exit(0); | |
| 1394 | -} | |
| 1395 | - | |
| 1396 | 1308 | /* |
| 1397 | 1309 | ** When this routine is called, we know that the request does not |
| 1398 | 1310 | ** have a login on the present repository. This routine checks to |
| 1399 | 1311 | ** see if their login cookie might be for another member of the |
| 1400 | 1312 | ** login-group. |
| @@ -1429,11 +1341,11 @@ | ||
| 1429 | 1341 | ** |
| 1430 | 1342 | ** g.userUid Database USER.UID value. Might be -1 for "nobody" |
| 1431 | 1343 | ** g.zLogin Database USER.LOGIN value. NULL for user "nobody" |
| 1432 | 1344 | ** g.perm Permissions granted to this user |
| 1433 | 1345 | ** g.anon Permissions that would be available to anonymous |
| 1434 | -** g.isHuman True if the user is human, not a spider or robot | |
| 1346 | +** g.isRobot True if the client is known to be a spider or robot | |
| 1435 | 1347 | ** g.perm Populated based on user account's capabilities |
| 1436 | 1348 | ** |
| 1437 | 1349 | */ |
| 1438 | 1350 | void login_check_credentials(void){ |
| 1439 | 1351 | int uid = 0; /* User id */ |
| @@ -1470,11 +1382,11 @@ | ||
| 1470 | 1382 | uid = db_int(0, "SELECT uid FROM user WHERE cap LIKE '%%s%%'"); |
| 1471 | 1383 | } |
| 1472 | 1384 | g.zLogin = db_text("?", "SELECT login FROM user WHERE uid=%d", uid); |
| 1473 | 1385 | zCap = "sxy"; |
| 1474 | 1386 | g.noPswd = 1; |
| 1475 | - g.isHuman = 1; | |
| 1387 | + g.isRobot = 0; | |
| 1476 | 1388 | zSeed = db_text("??", "SELECT uid||quote(login)||quote(pw)||quote(cookie)" |
| 1477 | 1389 | " FROM user WHERE uid=%d", uid); |
| 1478 | 1390 | login_create_csrf_secret(zSeed); |
| 1479 | 1391 | fossil_free(zSeed); |
| 1480 | 1392 | } |
| @@ -1604,12 +1516,15 @@ | ||
| 1604 | 1516 | login_create_csrf_secret("none"); |
| 1605 | 1517 | } |
| 1606 | 1518 | |
| 1607 | 1519 | login_set_uid(uid, zCap); |
| 1608 | 1520 | |
| 1609 | - /* Maybe restrict access to robots */ | |
| 1610 | - login_restrict_robot_access(); | |
| 1521 | + /* Maybe restrict access by robots */ | |
| 1522 | + if( g.zLogin==0 && robot_restrict(g.zPath) ){ | |
| 1523 | + cgi_reply(); | |
| 1524 | + fossil_exit(0); | |
| 1525 | + } | |
| 1611 | 1526 | } |
| 1612 | 1527 | |
| 1613 | 1528 | /* |
| 1614 | 1529 | ** Set the current logged in user to be uid. zCap is precomputed |
| 1615 | 1530 | ** (override) capabilities. If zCap==0, then look up the capabilities |
| @@ -1644,15 +1559,15 @@ | ||
| 1644 | 1559 | g.userUid = uid; |
| 1645 | 1560 | if( fossil_strcmp(g.zLogin,"nobody")==0 ){ |
| 1646 | 1561 | g.zLogin = 0; |
| 1647 | 1562 | } |
| 1648 | 1563 | if( PB("isrobot") ){ |
| 1649 | - g.isHuman = 0; | |
| 1564 | + g.isRobot = 1; | |
| 1650 | 1565 | }else if( g.zLogin==0 ){ |
| 1651 | - g.isHuman = isHuman(P("HTTP_USER_AGENT")); | |
| 1566 | + g.isRobot = !isHuman(P("HTTP_USER_AGENT")); | |
| 1652 | 1567 | }else{ |
| 1653 | - g.isHuman = 1; | |
| 1568 | + g.isRobot = 0; | |
| 1654 | 1569 | } |
| 1655 | 1570 | |
| 1656 | 1571 | /* Set the capabilities */ |
| 1657 | 1572 | login_replace_capabilities(zCap, 0); |
| 1658 | 1573 | |
| @@ -1662,11 +1577,11 @@ | ||
| 1662 | 1577 | ** enabled for this repository and make appropriate adjustments to the |
| 1663 | 1578 | ** permission flags if it is. This should be done before the permissions |
| 1664 | 1579 | ** are (potentially) copied to the anonymous permission set; otherwise, |
| 1665 | 1580 | ** those will be out-of-sync. |
| 1666 | 1581 | */ |
| 1667 | - if( zCap[0] && !g.perm.Hyperlink && g.isHuman ){ | |
| 1582 | + if( zCap[0] && !g.perm.Hyperlink && !g.isRobot ){ | |
| 1668 | 1583 | int autoLink = db_get_int("auto-hyperlink",1); |
| 1669 | 1584 | if( autoLink==1 ){ |
| 1670 | 1585 | g.jsHref = 1; |
| 1671 | 1586 | g.perm.Hyperlink = 1; |
| 1672 | 1587 | }else if( autoLink==2 ){ |
| 1673 | 1588 |
| --- src/login.c | |
| +++ src/login.c | |
| @@ -1303,98 +1303,10 @@ | |
| 1303 | } |
| 1304 | fossil_free(zDecode); |
| 1305 | return uid; |
| 1306 | } |
| 1307 | |
| 1308 | /* |
| 1309 | ** SETTING: robot-restrict width=40 block-text |
| 1310 | ** The VALUE of this setting is a list of GLOB patterns that match |
| 1311 | ** pages for which complex HTTP requests from robots should be disallowed. |
| 1312 | ** The recommended value for this setting is: |
| 1313 | ** |
| 1314 | ** timeline,vdiff,fdiff,annotate,blame |
| 1315 | ** |
| 1316 | */ |
| 1317 | |
| 1318 | /* |
| 1319 | ** Check to see if the current HTTP request is a complex request that |
| 1320 | ** is coming from a robot and if access should restricted for such robots. |
| 1321 | ** For the purposes of this module, a "complex request" is an HTTP |
| 1322 | ** request with one or more query parameters other than "name". |
| 1323 | ** |
| 1324 | ** If this routine determines that robots should be restricted, then |
| 1325 | ** this routine publishes a redirect to the honeypot and exits without |
| 1326 | ** returning to the caller. |
| 1327 | ** |
| 1328 | ** This routine believes that this is a complex request is coming from |
| 1329 | ** a robot if all of the following are true: |
| 1330 | ** |
| 1331 | ** * The user is "nobody". |
| 1332 | ** * Either the REFERER field of the HTTP header is missing or empty, |
| 1333 | ** or the USERAGENT field of the HTTP header suggests that |
| 1334 | ** the request as coming from a robot. |
| 1335 | ** * There are one or more query parameters other than "name". |
| 1336 | ** |
| 1337 | ** Robot restrictions are governed by settings. |
| 1338 | ** |
| 1339 | ** robot-restrict The value is a list of GLOB patterns for pages |
| 1340 | ** that should restrict robot access. No restrictions |
| 1341 | ** are applied if this setting is undefined or is |
| 1342 | ** an empty string. |
| 1343 | */ |
| 1344 | void login_restrict_robot_access(void){ |
| 1345 | const char *zGlob; |
| 1346 | int isMatch = 1; |
| 1347 | int nQP; /* Number of query parameters other than name= */ |
| 1348 | if( g.zLogin!=0 ) return; |
| 1349 | zGlob = db_get("robot-restrict",0); |
| 1350 | if( zGlob==0 || zGlob[0]==0 ) return; |
| 1351 | if( g.isHuman ){ |
| 1352 | const char *zReferer; |
| 1353 | const char *zAccept; |
| 1354 | const char *zBr; |
| 1355 | zReferer = P("HTTP_REFERER"); |
| 1356 | if( zReferer && zReferer[0]!=0 ) return; |
| 1357 | |
| 1358 | /* Robots typically do not accept the brotli encoding, at least not |
| 1359 | ** at the time of this writing (2025-04-01), but standard web-browser |
| 1360 | ** all generally do accept brotli. So if brotli is accepted, |
| 1361 | ** assume we are not talking to a robot. We might want to revisit this |
| 1362 | ** heuristic in the future... |
| 1363 | */ |
| 1364 | if( (zAccept = P("HTTP_ACCEPT_ENCODING"))!=0 |
| 1365 | && (zBr = strstr(zAccept,"br"))!=0 |
| 1366 | && !fossil_isalnum(zBr[2]) |
| 1367 | && (zBr==zAccept || !fossil_isalnum(zBr[-1])) |
| 1368 | ){ |
| 1369 | return; |
| 1370 | } |
| 1371 | } |
| 1372 | nQP = cgi_qp_count(); |
| 1373 | if( nQP<1 ) return; |
| 1374 | isMatch = glob_multi_match(zGlob, g.zPath); |
| 1375 | if( !isMatch ) return; |
| 1376 | |
| 1377 | /* Check for exceptions to the restriction on the number of query |
| 1378 | ** parameters. */ |
| 1379 | zGlob = db_get("robot-restrict-qp",0); |
| 1380 | if( zGlob && zGlob[0] ){ |
| 1381 | char *zPath = mprintf("%s/%d", g.zPath, nQP); |
| 1382 | isMatch = glob_multi_match(zGlob, zPath); |
| 1383 | fossil_free(zPath); |
| 1384 | if( isMatch ) return; |
| 1385 | } |
| 1386 | |
| 1387 | /* If we reach this point, it means we have a situation where we |
| 1388 | ** want to restrict the activity of a robot. |
| 1389 | */ |
| 1390 | g.isHuman = 0; |
| 1391 | (void)exclude_spiders(0); |
| 1392 | cgi_reply(); |
| 1393 | fossil_exit(0); |
| 1394 | } |
| 1395 | |
| 1396 | /* |
| 1397 | ** When this routine is called, we know that the request does not |
| 1398 | ** have a login on the present repository. This routine checks to |
| 1399 | ** see if their login cookie might be for another member of the |
| 1400 | ** login-group. |
| @@ -1429,11 +1341,11 @@ | |
| 1429 | ** |
| 1430 | ** g.userUid Database USER.UID value. Might be -1 for "nobody" |
| 1431 | ** g.zLogin Database USER.LOGIN value. NULL for user "nobody" |
| 1432 | ** g.perm Permissions granted to this user |
| 1433 | ** g.anon Permissions that would be available to anonymous |
| 1434 | ** g.isHuman True if the user is human, not a spider or robot |
| 1435 | ** g.perm Populated based on user account's capabilities |
| 1436 | ** |
| 1437 | */ |
| 1438 | void login_check_credentials(void){ |
| 1439 | int uid = 0; /* User id */ |
| @@ -1470,11 +1382,11 @@ | |
| 1470 | uid = db_int(0, "SELECT uid FROM user WHERE cap LIKE '%%s%%'"); |
| 1471 | } |
| 1472 | g.zLogin = db_text("?", "SELECT login FROM user WHERE uid=%d", uid); |
| 1473 | zCap = "sxy"; |
| 1474 | g.noPswd = 1; |
| 1475 | g.isHuman = 1; |
| 1476 | zSeed = db_text("??", "SELECT uid||quote(login)||quote(pw)||quote(cookie)" |
| 1477 | " FROM user WHERE uid=%d", uid); |
| 1478 | login_create_csrf_secret(zSeed); |
| 1479 | fossil_free(zSeed); |
| 1480 | } |
| @@ -1604,12 +1516,15 @@ | |
| 1604 | login_create_csrf_secret("none"); |
| 1605 | } |
| 1606 | |
| 1607 | login_set_uid(uid, zCap); |
| 1608 | |
| 1609 | /* Maybe restrict access to robots */ |
| 1610 | login_restrict_robot_access(); |
| 1611 | } |
| 1612 | |
| 1613 | /* |
| 1614 | ** Set the current logged in user to be uid. zCap is precomputed |
| 1615 | ** (override) capabilities. If zCap==0, then look up the capabilities |
| @@ -1644,15 +1559,15 @@ | |
| 1644 | g.userUid = uid; |
| 1645 | if( fossil_strcmp(g.zLogin,"nobody")==0 ){ |
| 1646 | g.zLogin = 0; |
| 1647 | } |
| 1648 | if( PB("isrobot") ){ |
| 1649 | g.isHuman = 0; |
| 1650 | }else if( g.zLogin==0 ){ |
| 1651 | g.isHuman = isHuman(P("HTTP_USER_AGENT")); |
| 1652 | }else{ |
| 1653 | g.isHuman = 1; |
| 1654 | } |
| 1655 | |
| 1656 | /* Set the capabilities */ |
| 1657 | login_replace_capabilities(zCap, 0); |
| 1658 | |
| @@ -1662,11 +1577,11 @@ | |
| 1662 | ** enabled for this repository and make appropriate adjustments to the |
| 1663 | ** permission flags if it is. This should be done before the permissions |
| 1664 | ** are (potentially) copied to the anonymous permission set; otherwise, |
| 1665 | ** those will be out-of-sync. |
| 1666 | */ |
| 1667 | if( zCap[0] && !g.perm.Hyperlink && g.isHuman ){ |
| 1668 | int autoLink = db_get_int("auto-hyperlink",1); |
| 1669 | if( autoLink==1 ){ |
| 1670 | g.jsHref = 1; |
| 1671 | g.perm.Hyperlink = 1; |
| 1672 | }else if( autoLink==2 ){ |
| 1673 |
| --- src/login.c | |
| +++ src/login.c | |
| @@ -1303,98 +1303,10 @@ | |
| 1303 | } |
| 1304 | fossil_free(zDecode); |
| 1305 | return uid; |
| 1306 | } |
| 1307 | |
| 1308 | /* |
| 1309 | ** When this routine is called, we know that the request does not |
| 1310 | ** have a login on the present repository. This routine checks to |
| 1311 | ** see if their login cookie might be for another member of the |
| 1312 | ** login-group. |
| @@ -1429,11 +1341,11 @@ | |
| 1341 | ** |
| 1342 | ** g.userUid Database USER.UID value. Might be -1 for "nobody" |
| 1343 | ** g.zLogin Database USER.LOGIN value. NULL for user "nobody" |
| 1344 | ** g.perm Permissions granted to this user |
| 1345 | ** g.anon Permissions that would be available to anonymous |
| 1346 | ** g.isRobot True if the client is known to be a spider or robot |
| 1347 | ** g.perm Populated based on user account's capabilities |
| 1348 | ** |
| 1349 | */ |
| 1350 | void login_check_credentials(void){ |
| 1351 | int uid = 0; /* User id */ |
| @@ -1470,11 +1382,11 @@ | |
| 1382 | uid = db_int(0, "SELECT uid FROM user WHERE cap LIKE '%%s%%'"); |
| 1383 | } |
| 1384 | g.zLogin = db_text("?", "SELECT login FROM user WHERE uid=%d", uid); |
| 1385 | zCap = "sxy"; |
| 1386 | g.noPswd = 1; |
| 1387 | g.isRobot = 0; |
| 1388 | zSeed = db_text("??", "SELECT uid||quote(login)||quote(pw)||quote(cookie)" |
| 1389 | " FROM user WHERE uid=%d", uid); |
| 1390 | login_create_csrf_secret(zSeed); |
| 1391 | fossil_free(zSeed); |
| 1392 | } |
| @@ -1604,12 +1516,15 @@ | |
| 1516 | login_create_csrf_secret("none"); |
| 1517 | } |
| 1518 | |
| 1519 | login_set_uid(uid, zCap); |
| 1520 | |
| 1521 | /* Maybe restrict access by robots */ |
| 1522 | if( g.zLogin==0 && robot_restrict(g.zPath) ){ |
| 1523 | cgi_reply(); |
| 1524 | fossil_exit(0); |
| 1525 | } |
| 1526 | } |
| 1527 | |
| 1528 | /* |
| 1529 | ** Set the current logged in user to be uid. zCap is precomputed |
| 1530 | ** (override) capabilities. If zCap==0, then look up the capabilities |
| @@ -1644,15 +1559,15 @@ | |
| 1559 | g.userUid = uid; |
| 1560 | if( fossil_strcmp(g.zLogin,"nobody")==0 ){ |
| 1561 | g.zLogin = 0; |
| 1562 | } |
| 1563 | if( PB("isrobot") ){ |
| 1564 | g.isRobot = 1; |
| 1565 | }else if( g.zLogin==0 ){ |
| 1566 | g.isRobot = !isHuman(P("HTTP_USER_AGENT")); |
| 1567 | }else{ |
| 1568 | g.isRobot = 0; |
| 1569 | } |
| 1570 | |
| 1571 | /* Set the capabilities */ |
| 1572 | login_replace_capabilities(zCap, 0); |
| 1573 | |
| @@ -1662,11 +1577,11 @@ | |
| 1577 | ** enabled for this repository and make appropriate adjustments to the |
| 1578 | ** permission flags if it is. This should be done before the permissions |
| 1579 | ** are (potentially) copied to the anonymous permission set; otherwise, |
| 1580 | ** those will be out-of-sync. |
| 1581 | */ |
| 1582 | if( zCap[0] && !g.perm.Hyperlink && !g.isRobot ){ |
| 1583 | int autoLink = db_get_int("auto-hyperlink",1); |
| 1584 | if( autoLink==1 ){ |
| 1585 | g.jsHref = 1; |
| 1586 | g.perm.Hyperlink = 1; |
| 1587 | }else if( autoLink==2 ){ |
| 1588 |
+2
-1
| --- src/main.c | ||
| +++ src/main.c | ||
| @@ -233,11 +233,12 @@ | ||
| 233 | 233 | * applicable when using SEE on Windows or Linux. */ |
| 234 | 234 | #endif |
| 235 | 235 | int useLocalauth; /* No login required if from 127.0.0.1 */ |
| 236 | 236 | int noPswd; /* Logged in without password (on 127.0.0.1) */ |
| 237 | 237 | int userUid; /* Integer user id */ |
| 238 | - int isHuman; /* True if access by a human, not a spider or bot */ | |
| 238 | + int isRobot; /* True if the client is definitely a robot. False | |
| 239 | + ** negatives are common for this flag */ | |
| 239 | 240 | int comFmtFlags; /* Zero or more "COMMENT_PRINT_*" bit flags, should be |
| 240 | 241 | ** accessed through get_comment_format(). */ |
| 241 | 242 | const char *zSockName; /* Name of the unix-domain socket file */ |
| 242 | 243 | const char *zSockMode; /* File permissions for unix-domain socket */ |
| 243 | 244 | const char *zSockOwner; /* Owner, or owner:group for unix-domain socket */ |
| 244 | 245 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -233,11 +233,12 @@ | |
| 233 | * applicable when using SEE on Windows or Linux. */ |
| 234 | #endif |
| 235 | int useLocalauth; /* No login required if from 127.0.0.1 */ |
| 236 | int noPswd; /* Logged in without password (on 127.0.0.1) */ |
| 237 | int userUid; /* Integer user id */ |
| 238 | int isHuman; /* True if access by a human, not a spider or bot */ |
| 239 | int comFmtFlags; /* Zero or more "COMMENT_PRINT_*" bit flags, should be |
| 240 | ** accessed through get_comment_format(). */ |
| 241 | const char *zSockName; /* Name of the unix-domain socket file */ |
| 242 | const char *zSockMode; /* File permissions for unix-domain socket */ |
| 243 | const char *zSockOwner; /* Owner, or owner:group for unix-domain socket */ |
| 244 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -233,11 +233,12 @@ | |
| 233 | * applicable when using SEE on Windows or Linux. */ |
| 234 | #endif |
| 235 | int useLocalauth; /* No login required if from 127.0.0.1 */ |
| 236 | int noPswd; /* Logged in without password (on 127.0.0.1) */ |
| 237 | int userUid; /* Integer user id */ |
| 238 | int isRobot; /* True if the client is definitely a robot. False |
| 239 | ** negatives are common for this flag */ |
| 240 | int comFmtFlags; /* Zero or more "COMMENT_PRINT_*" bit flags, should be |
| 241 | ** accessed through get_comment_format(). */ |
| 242 | const char *zSockName; /* Name of the unix-domain socket file */ |
| 243 | const char *zSockMode; /* File permissions for unix-domain socket */ |
| 244 | const char *zSockOwner; /* Owner, or owner:group for unix-domain socket */ |
| 245 |
+109
-60
| --- src/robot.c | ||
| +++ src/robot.c | ||
| @@ -22,19 +22,11 @@ | ||
| 22 | 22 | #include "config.h" |
| 23 | 23 | #include "robot.h" |
| 24 | 24 | #include <assert.h> |
| 25 | 25 | #include <time.h> |
| 26 | 26 | |
| 27 | -/* | |
| 28 | -** SETTING: robot-squelch width=10 default=200 | |
| 29 | -** The VALUE of is an integer between 0 and 1000 that determines how | |
| 30 | -** readily Fossil will squelch requests from robots. A value of 0 | |
| 31 | -** means "never squelch requests". A value of 1000 means "always | |
| 32 | -** squelch requests from user 'nobody'". For values greater than 0 | |
| 33 | -** and less than 1000, the decision to squelch is based on a variety | |
| 34 | -** of heuristics, but is more likely to occur the larger the number. | |
| 35 | -*/ | |
| 27 | +#define POW_COOKIE "fossil-proofofwork" | |
| 36 | 28 | |
| 37 | 29 | /* |
| 38 | 30 | ** Rewrite the current page with a robot squelch captcha and return 1. |
| 39 | 31 | ** |
| 40 | 32 | ** Or, if valid proof-of-work is present as either a query parameter or |
| @@ -71,14 +63,14 @@ | ||
| 71 | 63 | h2 = (h2 % 900000000) + 100000000; |
| 72 | 64 | |
| 73 | 65 | /* If there is already a proof-of-work cookie with this value |
| 74 | 66 | ** that means that the user agent has already authenticated. |
| 75 | 67 | */ |
| 76 | - z = P("fossil-proofofwork"); | |
| 68 | + z = P(POW_COOKIE); | |
| 77 | 69 | if( z |
| 78 | 70 | && (atoi(z)==h1 || atoi(z)==h2) |
| 79 | - && !cgi_is_qp("fossil-proofofwork") ){ | |
| 71 | + && !cgi_is_qp(POW_COOKIE) ){ | |
| 80 | 72 | return 0; |
| 81 | 73 | } |
| 82 | 74 | |
| 83 | 75 | /* Check for a proof query parameter. If found, that means that |
| 84 | 76 | ** the captcha has just now passed, so set the proof-of-work cookie |
| @@ -86,83 +78,140 @@ | ||
| 86 | 78 | */ |
| 87 | 79 | z = P("proof"); |
| 88 | 80 | if( z |
| 89 | 81 | && (atoi(z)==h1 || atoi(z)==h2) |
| 90 | 82 | ){ |
| 91 | - cgi_set_cookie("fossil-proofofwork",z,"/",900); | |
| 83 | + cgi_set_cookie(POW_COOKIE,z,"/",900); | |
| 92 | 84 | return 0; |
| 93 | 85 | } |
| 94 | 86 | cgi_tag_query_parameter("proof"); |
| 95 | 87 | |
| 96 | 88 | /* Ask the client to present proof-of-work */ |
| 97 | 89 | cgi_reset_content(); |
| 98 | 90 | cgi_set_content_type("text/html"); |
| 99 | - style_header("Captcha"); | |
| 100 | - @ <h1>Prove That You Are Human</h1> | |
| 91 | + style_header("Browser Verification"); | |
| 92 | + @ <h1 id="x1">Checking to see if you are a robot<span id="x2"></span></h1> | |
| 101 | 93 | @ <form method="GET"> |
| 102 | - @ <p>Press the button below</p><p> | |
| 94 | + @ <p id="x3" style="visibility:hidden;">\ | |
| 95 | + @ Press <input type="submit" id="x5" value="Ok" focus> to continue</p> | |
| 103 | 96 | cgi_query_parameters_to_hidden(); |
| 104 | - @ <input id="vx" type="hidden" name="proof" value="0"> | |
| 105 | - @ <input id="cx" type="submit" value="Wait..." disabled> | |
| 97 | + @ <input id="x4" type="hidden" name="proof" value="0"> | |
| 106 | 98 | @ </form> |
| 107 | 99 | @ <script nonce='%s(style_nonce())'> |
| 108 | - @ function Nhtot1520(x){return document.getElementById(x);} | |
| 109 | - @ function Aoxlxzajv(h){\ | |
| 110 | - @ Nhtot1520("vx").value=h;\ | |
| 111 | - @ Nhtot1520("cx").value="Ok";\ | |
| 112 | - @ Nhtot1520("cx").disabled=false;\ | |
| 113 | - @ } | |
| 114 | - @ function Vhcnyarsm(h,a){\ | |
| 115 | - @ if(a>0){setTimeout(Vhcnyarsm,1,h+a,a-1);}else{Aoxlxzajv(h);}\ | |
| 116 | - @ } | |
| 117 | - k = 200 + h2%99; | |
| 100 | + @ function aaa(x){return document.getElementById(x);} | |
| 101 | + @ function bbb(h,a){ | |
| 102 | + @ aaa("x4").value=h | |
| 103 | + @ if((a%%75)==0){ | |
| 104 | + @ aaa("x2").textContent=aaa("x2").textContent+"."; | |
| 105 | + @ } | |
| 106 | + @ if(a>0){ | |
| 107 | + @ setTimeout(bbb,1,h+a,a-1); | |
| 108 | + @ }else{ | |
| 109 | + @ aaa("x3").style.visibility="visible"; | |
| 110 | + @ aaa("x2").textContent=""; | |
| 111 | + @ aaa("x1").textContent="All clear"; | |
| 112 | + @ aaa("x5").focus(); | |
| 113 | + @ } | |
| 114 | + @ } | |
| 115 | + k = 800 + h2%99; | |
| 118 | 116 | h2 = (k*k + k)/2; |
| 119 | - @ setTimeout(function(){Vhcnyarsm(%u(h1-h2),%u(k));},10); | |
| 117 | + @ setTimeout(function(){bbb(%u(h1-h2),%u(k));},10); | |
| 120 | 118 | @ </script> |
| 121 | 119 | style_finish_page(); |
| 122 | 120 | return 1; |
| 123 | 121 | } |
| 124 | 122 | |
| 123 | +/* | |
| 124 | +** SETTING: robot-restrict width=40 block-text | |
| 125 | +** The VALUE of this setting is a list of GLOB patterns that match | |
| 126 | +** pages for which complex HTTP requests from unauthenicated clients | |
| 127 | +** should be disallowed. "Unauthenticated" means the user is "nobody". | |
| 128 | +** The recommended value for this setting is: | |
| 129 | +** | |
| 130 | +** timelineX,diff,annotate,zip,fileage,file | |
| 131 | +** | |
| 132 | +** The "diff" tag covers all diffing pages such as /vdiff, /fdiff, and | |
| 133 | +** /vpatch. The "annotate" tag also covers /blame and /praise. "zip" | |
| 134 | +** also covers /tarball and /sqlar. If a tag has an "X" character appended, | |
| 135 | +** then it only applies if query parameters are such that the page is | |
| 136 | +** particularly difficult to compute. | |
| 137 | +** | |
| 138 | +** In all other case, the tag should exactly match the page name. | |
| 139 | +*/ | |
| 125 | 140 | |
| 126 | 141 | /* |
| 127 | -** WEBPAGE functions can invoke this routine with an argument | |
| 128 | -** that is between 0 and 1000. Based on that argument, and on | |
| 129 | -** other factors, this routine decides whether or not to squelch | |
| 130 | -** the request. "Squelch" in this context, means to require the | |
| 131 | -** client to show proof-of-work before the request is processed. | |
| 132 | -** The idea here is to prevent server overload due to excess robot | |
| 133 | -** traffic. If a robot (or any client application really) wants us | |
| 134 | -** to spend a lot of CPU computing some result for it, then it needs | |
| 135 | -** to first demonstrate good faith by doing some make-work for us. | |
| 136 | -** | |
| 137 | -** This routine returns true for a squelch and false if the original | |
| 138 | -** request should go through. | |
| 139 | -** | |
| 140 | -** The input parameter is an estimate of how much CPU time | |
| 141 | -** and bandwidth is needed to compute a response. The higher the | |
| 142 | -** value of this parameter, the more likely this routine is to squelch | |
| 143 | -** the page. A value of zero means "never squelch". A value of | |
| 144 | -** 1000 means always squelch if the user is "nobody". | |
| 145 | -** | |
| 146 | -** Squelching only happens if the user is "nobody". If the request | |
| 147 | -** comes from any other user, including user "anonymous", the request | |
| 148 | -** is never squelched. | |
| 149 | -*/ | |
| 150 | -int robot_squelch(int n){ | |
| 151 | - const char *zToken; | |
| 152 | - int iSquelch; | |
| 153 | - assert( n>=0 && n<=1000 ); | |
| 154 | - if( g.zLogin ) return 0; /* Logged in users always get through */ | |
| 155 | - if( n==0 ) return 0; /* Squelch is completely disabled */ | |
| 142 | +** Return the default restriction GLOB | |
| 143 | +*/ | |
| 144 | +const char *robot_restrict_default(void){ | |
| 145 | + return "timelineX,diff,annotate,zip,fileage,file"; | |
| 146 | +} | |
| 147 | +/* | |
| 148 | +** Check to see if the page named in the argument is on the | |
| 149 | +** robot-restrict list. If it is on the list and if the user | |
| 150 | +** is "nobody" then bring up a captcha to test to make sure that | |
| 151 | +** client is not a robot. | |
| 152 | +** | |
| 153 | +** This routine returns true if a captcha was rendered and if subsequent | |
| 154 | +** page generation should be aborted. It returns false if the page | |
| 155 | +** should not be restricted and should be rendered normally. | |
| 156 | +*/ | |
| 157 | +int robot_restrict(const char *zPage){ | |
| 158 | + const char *zGlob; | |
| 159 | + const char *zToken; | |
| 160 | + if( g.zLogin ) return 0; /* Logged in users always get through */ | |
| 161 | + zGlob = db_get("robot-restrict",robot_restrict_default()); | |
| 162 | + if( zGlob==0 || zGlob[0]==0 ) return 0; | |
| 163 | + if( !glob_multi_match(zGlob, zPage) ) return 0; | |
| 156 | 164 | zToken = P("token"); |
| 157 | 165 | if( zToken!=0 |
| 158 | 166 | && db_exists("SELECT 1 FROM config WHERE name='token-%q'", zToken) |
| 159 | 167 | ){ |
| 160 | 168 | return 0; /* There is a valid token= query parameter */ |
| 161 | 169 | } |
| 162 | - iSquelch = db_get_int("robot-squelch",200); | |
| 163 | - if( iSquelch<=0 ) return 0; | |
| 164 | - if( n+iSquelch>=1000 && robot_proofofwork() ){ | |
| 170 | + if( robot_proofofwork() ){ | |
| 165 | 171 | return 1; |
| 166 | 172 | } |
| 167 | 173 | return 0; |
| 168 | 174 | } |
| 175 | + | |
| 176 | + | |
| 177 | +/* | |
| 178 | +** WEBPAGE: test-robotck | |
| 179 | +** | |
| 180 | +** Run the robot_restrict() function using the value of the "name=" | |
| 181 | +** query parameter as an argument. Used for testing the robot_restrict() | |
| 182 | +** logic. | |
| 183 | +** | |
| 184 | +** Whenever this page is successfully rendered (when it doesn't go to | |
| 185 | +** the captcha) it deletes the proof-of-work cookie. So reloading the | |
| 186 | +** page will reset the cookie and restart the verification. | |
| 187 | +*/ | |
| 188 | +void robot_restrict_test_page(void){ | |
| 189 | + const char *zName = P("name"); | |
| 190 | + const char *zP1 = P("proof"); | |
| 191 | + const char *zP2 = P(POW_COOKIE); | |
| 192 | + const char *z; | |
| 193 | + if( zName==0 || zName[0]==0 ) zName = g.zPath; | |
| 194 | + login_check_credentials(); | |
| 195 | + if( !g.perm.Admin ){ login_needed(0); return; } | |
| 196 | + g.zLogin = 0; | |
| 197 | + if( robot_restrict(zName) ) return; | |
| 198 | + style_set_current_feature("test"); | |
| 199 | + style_header("robot_restrict() test"); | |
| 200 | + @ <h1>Captcha passed</h1> | |
| 201 | + @ | |
| 202 | + @ <p> | |
| 203 | + if( zP1 && zP1[0] ){ | |
| 204 | + @ proof=%h(zP1)<br> | |
| 205 | + } | |
| 206 | + if( zP2 && zP2[0] ){ | |
| 207 | + @ fossil_proofofwork=%h(zP2)<br> | |
| 208 | + cgi_set_cookie(POW_COOKIE,"",0,-1); | |
| 209 | + } | |
| 210 | + z = db_get("robot-restrict",robot_restrict_default()); | |
| 211 | + if( z && z[0] ){ | |
| 212 | + @ robot-restrict=%h(z)</br> | |
| 213 | + } | |
| 214 | + @ </p> | |
| 215 | + @ <p><a href="%R/test-robotck/%h(zName)">Retry</a> | |
| 216 | + style_finish_page(); | |
| 217 | +} | |
| 169 | 218 |
| --- src/robot.c | |
| +++ src/robot.c | |
| @@ -22,19 +22,11 @@ | |
| 22 | #include "config.h" |
| 23 | #include "robot.h" |
| 24 | #include <assert.h> |
| 25 | #include <time.h> |
| 26 | |
| 27 | /* |
| 28 | ** SETTING: robot-squelch width=10 default=200 |
| 29 | ** The VALUE of is an integer between 0 and 1000 that determines how |
| 30 | ** readily Fossil will squelch requests from robots. A value of 0 |
| 31 | ** means "never squelch requests". A value of 1000 means "always |
| 32 | ** squelch requests from user 'nobody'". For values greater than 0 |
| 33 | ** and less than 1000, the decision to squelch is based on a variety |
| 34 | ** of heuristics, but is more likely to occur the larger the number. |
| 35 | */ |
| 36 | |
| 37 | /* |
| 38 | ** Rewrite the current page with a robot squelch captcha and return 1. |
| 39 | ** |
| 40 | ** Or, if valid proof-of-work is present as either a query parameter or |
| @@ -71,14 +63,14 @@ | |
| 71 | h2 = (h2 % 900000000) + 100000000; |
| 72 | |
| 73 | /* If there is already a proof-of-work cookie with this value |
| 74 | ** that means that the user agent has already authenticated. |
| 75 | */ |
| 76 | z = P("fossil-proofofwork"); |
| 77 | if( z |
| 78 | && (atoi(z)==h1 || atoi(z)==h2) |
| 79 | && !cgi_is_qp("fossil-proofofwork") ){ |
| 80 | return 0; |
| 81 | } |
| 82 | |
| 83 | /* Check for a proof query parameter. If found, that means that |
| 84 | ** the captcha has just now passed, so set the proof-of-work cookie |
| @@ -86,83 +78,140 @@ | |
| 86 | */ |
| 87 | z = P("proof"); |
| 88 | if( z |
| 89 | && (atoi(z)==h1 || atoi(z)==h2) |
| 90 | ){ |
| 91 | cgi_set_cookie("fossil-proofofwork",z,"/",900); |
| 92 | return 0; |
| 93 | } |
| 94 | cgi_tag_query_parameter("proof"); |
| 95 | |
| 96 | /* Ask the client to present proof-of-work */ |
| 97 | cgi_reset_content(); |
| 98 | cgi_set_content_type("text/html"); |
| 99 | style_header("Captcha"); |
| 100 | @ <h1>Prove That You Are Human</h1> |
| 101 | @ <form method="GET"> |
| 102 | @ <p>Press the button below</p><p> |
| 103 | cgi_query_parameters_to_hidden(); |
| 104 | @ <input id="vx" type="hidden" name="proof" value="0"> |
| 105 | @ <input id="cx" type="submit" value="Wait..." disabled> |
| 106 | @ </form> |
| 107 | @ <script nonce='%s(style_nonce())'> |
| 108 | @ function Nhtot1520(x){return document.getElementById(x);} |
| 109 | @ function Aoxlxzajv(h){\ |
| 110 | @ Nhtot1520("vx").value=h;\ |
| 111 | @ Nhtot1520("cx").value="Ok";\ |
| 112 | @ Nhtot1520("cx").disabled=false;\ |
| 113 | @ } |
| 114 | @ function Vhcnyarsm(h,a){\ |
| 115 | @ if(a>0){setTimeout(Vhcnyarsm,1,h+a,a-1);}else{Aoxlxzajv(h);}\ |
| 116 | @ } |
| 117 | k = 200 + h2%99; |
| 118 | h2 = (k*k + k)/2; |
| 119 | @ setTimeout(function(){Vhcnyarsm(%u(h1-h2),%u(k));},10); |
| 120 | @ </script> |
| 121 | style_finish_page(); |
| 122 | return 1; |
| 123 | } |
| 124 | |
| 125 | |
| 126 | /* |
| 127 | ** WEBPAGE functions can invoke this routine with an argument |
| 128 | ** that is between 0 and 1000. Based on that argument, and on |
| 129 | ** other factors, this routine decides whether or not to squelch |
| 130 | ** the request. "Squelch" in this context, means to require the |
| 131 | ** client to show proof-of-work before the request is processed. |
| 132 | ** The idea here is to prevent server overload due to excess robot |
| 133 | ** traffic. If a robot (or any client application really) wants us |
| 134 | ** to spend a lot of CPU computing some result for it, then it needs |
| 135 | ** to first demonstrate good faith by doing some make-work for us. |
| 136 | ** |
| 137 | ** This routine returns true for a squelch and false if the original |
| 138 | ** request should go through. |
| 139 | ** |
| 140 | ** The input parameter is an estimate of how much CPU time |
| 141 | ** and bandwidth is needed to compute a response. The higher the |
| 142 | ** value of this parameter, the more likely this routine is to squelch |
| 143 | ** the page. A value of zero means "never squelch". A value of |
| 144 | ** 1000 means always squelch if the user is "nobody". |
| 145 | ** |
| 146 | ** Squelching only happens if the user is "nobody". If the request |
| 147 | ** comes from any other user, including user "anonymous", the request |
| 148 | ** is never squelched. |
| 149 | */ |
| 150 | int robot_squelch(int n){ |
| 151 | const char *zToken; |
| 152 | int iSquelch; |
| 153 | assert( n>=0 && n<=1000 ); |
| 154 | if( g.zLogin ) return 0; /* Logged in users always get through */ |
| 155 | if( n==0 ) return 0; /* Squelch is completely disabled */ |
| 156 | zToken = P("token"); |
| 157 | if( zToken!=0 |
| 158 | && db_exists("SELECT 1 FROM config WHERE name='token-%q'", zToken) |
| 159 | ){ |
| 160 | return 0; /* There is a valid token= query parameter */ |
| 161 | } |
| 162 | iSquelch = db_get_int("robot-squelch",200); |
| 163 | if( iSquelch<=0 ) return 0; |
| 164 | if( n+iSquelch>=1000 && robot_proofofwork() ){ |
| 165 | return 1; |
| 166 | } |
| 167 | return 0; |
| 168 | } |
| 169 |
| --- src/robot.c | |
| +++ src/robot.c | |
| @@ -22,19 +22,11 @@ | |
| 22 | #include "config.h" |
| 23 | #include "robot.h" |
| 24 | #include <assert.h> |
| 25 | #include <time.h> |
| 26 | |
| 27 | #define POW_COOKIE "fossil-proofofwork" |
| 28 | |
| 29 | /* |
| 30 | ** Rewrite the current page with a robot squelch captcha and return 1. |
| 31 | ** |
| 32 | ** Or, if valid proof-of-work is present as either a query parameter or |
| @@ -71,14 +63,14 @@ | |
| 63 | h2 = (h2 % 900000000) + 100000000; |
| 64 | |
| 65 | /* If there is already a proof-of-work cookie with this value |
| 66 | ** that means that the user agent has already authenticated. |
| 67 | */ |
| 68 | z = P(POW_COOKIE); |
| 69 | if( z |
| 70 | && (atoi(z)==h1 || atoi(z)==h2) |
| 71 | && !cgi_is_qp(POW_COOKIE) ){ |
| 72 | return 0; |
| 73 | } |
| 74 | |
| 75 | /* Check for a proof query parameter. If found, that means that |
| 76 | ** the captcha has just now passed, so set the proof-of-work cookie |
| @@ -86,83 +78,140 @@ | |
| 78 | */ |
| 79 | z = P("proof"); |
| 80 | if( z |
| 81 | && (atoi(z)==h1 || atoi(z)==h2) |
| 82 | ){ |
| 83 | cgi_set_cookie(POW_COOKIE,z,"/",900); |
| 84 | return 0; |
| 85 | } |
| 86 | cgi_tag_query_parameter("proof"); |
| 87 | |
| 88 | /* Ask the client to present proof-of-work */ |
| 89 | cgi_reset_content(); |
| 90 | cgi_set_content_type("text/html"); |
| 91 | style_header("Browser Verification"); |
| 92 | @ <h1 id="x1">Checking to see if you are a robot<span id="x2"></span></h1> |
| 93 | @ <form method="GET"> |
| 94 | @ <p id="x3" style="visibility:hidden;">\ |
| 95 | @ Press <input type="submit" id="x5" value="Ok" focus> to continue</p> |
| 96 | cgi_query_parameters_to_hidden(); |
| 97 | @ <input id="x4" type="hidden" name="proof" value="0"> |
| 98 | @ </form> |
| 99 | @ <script nonce='%s(style_nonce())'> |
| 100 | @ function aaa(x){return document.getElementById(x);} |
| 101 | @ function bbb(h,a){ |
| 102 | @ aaa("x4").value=h |
| 103 | @ if((a%%75)==0){ |
| 104 | @ aaa("x2").textContent=aaa("x2").textContent+"."; |
| 105 | @ } |
| 106 | @ if(a>0){ |
| 107 | @ setTimeout(bbb,1,h+a,a-1); |
| 108 | @ }else{ |
| 109 | @ aaa("x3").style.visibility="visible"; |
| 110 | @ aaa("x2").textContent=""; |
| 111 | @ aaa("x1").textContent="All clear"; |
| 112 | @ aaa("x5").focus(); |
| 113 | @ } |
| 114 | @ } |
| 115 | k = 800 + h2%99; |
| 116 | h2 = (k*k + k)/2; |
| 117 | @ setTimeout(function(){bbb(%u(h1-h2),%u(k));},10); |
| 118 | @ </script> |
| 119 | style_finish_page(); |
| 120 | return 1; |
| 121 | } |
| 122 | |
| 123 | /* |
| 124 | ** SETTING: robot-restrict width=40 block-text |
| 125 | ** The VALUE of this setting is a list of GLOB patterns that match |
| 126 | ** pages for which complex HTTP requests from unauthenicated clients |
| 127 | ** should be disallowed. "Unauthenticated" means the user is "nobody". |
| 128 | ** The recommended value for this setting is: |
| 129 | ** |
| 130 | ** timelineX,diff,annotate,zip,fileage,file |
| 131 | ** |
| 132 | ** The "diff" tag covers all diffing pages such as /vdiff, /fdiff, and |
| 133 | ** /vpatch. The "annotate" tag also covers /blame and /praise. "zip" |
| 134 | ** also covers /tarball and /sqlar. If a tag has an "X" character appended, |
| 135 | ** then it only applies if query parameters are such that the page is |
| 136 | ** particularly difficult to compute. |
| 137 | ** |
| 138 | ** In all other case, the tag should exactly match the page name. |
| 139 | */ |
| 140 | |
| 141 | /* |
| 142 | ** Return the default restriction GLOB |
| 143 | */ |
| 144 | const char *robot_restrict_default(void){ |
| 145 | return "timelineX,diff,annotate,zip,fileage,file"; |
| 146 | } |
| 147 | /* |
| 148 | ** Check to see if the page named in the argument is on the |
| 149 | ** robot-restrict list. If it is on the list and if the user |
| 150 | ** is "nobody" then bring up a captcha to test to make sure that |
| 151 | ** client is not a robot. |
| 152 | ** |
| 153 | ** This routine returns true if a captcha was rendered and if subsequent |
| 154 | ** page generation should be aborted. It returns false if the page |
| 155 | ** should not be restricted and should be rendered normally. |
| 156 | */ |
| 157 | int robot_restrict(const char *zPage){ |
| 158 | const char *zGlob; |
| 159 | const char *zToken; |
| 160 | if( g.zLogin ) return 0; /* Logged in users always get through */ |
| 161 | zGlob = db_get("robot-restrict",robot_restrict_default()); |
| 162 | if( zGlob==0 || zGlob[0]==0 ) return 0; |
| 163 | if( !glob_multi_match(zGlob, zPage) ) return 0; |
| 164 | zToken = P("token"); |
| 165 | if( zToken!=0 |
| 166 | && db_exists("SELECT 1 FROM config WHERE name='token-%q'", zToken) |
| 167 | ){ |
| 168 | return 0; /* There is a valid token= query parameter */ |
| 169 | } |
| 170 | if( robot_proofofwork() ){ |
| 171 | return 1; |
| 172 | } |
| 173 | return 0; |
| 174 | } |
| 175 | |
| 176 | |
| 177 | /* |
| 178 | ** WEBPAGE: test-robotck |
| 179 | ** |
| 180 | ** Run the robot_restrict() function using the value of the "name=" |
| 181 | ** query parameter as an argument. Used for testing the robot_restrict() |
| 182 | ** logic. |
| 183 | ** |
| 184 | ** Whenever this page is successfully rendered (when it doesn't go to |
| 185 | ** the captcha) it deletes the proof-of-work cookie. So reloading the |
| 186 | ** page will reset the cookie and restart the verification. |
| 187 | */ |
| 188 | void robot_restrict_test_page(void){ |
| 189 | const char *zName = P("name"); |
| 190 | const char *zP1 = P("proof"); |
| 191 | const char *zP2 = P(POW_COOKIE); |
| 192 | const char *z; |
| 193 | if( zName==0 || zName[0]==0 ) zName = g.zPath; |
| 194 | login_check_credentials(); |
| 195 | if( !g.perm.Admin ){ login_needed(0); return; } |
| 196 | g.zLogin = 0; |
| 197 | if( robot_restrict(zName) ) return; |
| 198 | style_set_current_feature("test"); |
| 199 | style_header("robot_restrict() test"); |
| 200 | @ <h1>Captcha passed</h1> |
| 201 | @ |
| 202 | @ <p> |
| 203 | if( zP1 && zP1[0] ){ |
| 204 | @ proof=%h(zP1)<br> |
| 205 | } |
| 206 | if( zP2 && zP2[0] ){ |
| 207 | @ fossil_proofofwork=%h(zP2)<br> |
| 208 | cgi_set_cookie(POW_COOKIE,"",0,-1); |
| 209 | } |
| 210 | z = db_get("robot-restrict",robot_restrict_default()); |
| 211 | if( z && z[0] ){ |
| 212 | @ robot-restrict=%h(z)</br> |
| 213 | } |
| 214 | @ </p> |
| 215 | @ <p><a href="%R/test-robotck/%h(zName)">Retry</a> |
| 216 | style_finish_page(); |
| 217 | } |
| 218 |
+20
-37
| --- src/setup.c | ||
| +++ src/setup.c | ||
| @@ -495,20 +495,29 @@ | ||
| 495 | 495 | @ |
| 496 | 496 | @ <form action="%R/setup_robot" method="post"><div> |
| 497 | 497 | login_insert_csrf_secret(); |
| 498 | 498 | @ <input type="submit" name="submit" value="Apply Changes"></p> |
| 499 | 499 | @ <hr> |
| 500 | - entry_attribute("Robot Squelch", 6, "robot-squelch", "rsq", "200", 0); | |
| 501 | - @ <p>The "squelch" setting determines how aggressive Fossil is about | |
| 502 | - @ trying to weed out robots using captchas. Squelch only applies to | |
| 503 | - @ expensive requests from user "nobody". The higher the squelch setting, | |
| 504 | - @ the more likely the request is to generate a captcha instead of the | |
| 505 | - @ requested page. Squelch can be any integer between 0 and 1000. | |
| 506 | - @ 0 means squelch is disabled and all requests go through without a | |
| 507 | - @ captcha. 1000 means every expensive request from user "nobody" gets | |
| 508 | - @ a captcha. | |
| 509 | - @ (Property: "robot-squelch")</p> | |
| 500 | + @ <p><b>Do not allow robots access to these pages.</b> | |
| 501 | + @ <p> If the page name matches the GLOB pattern of this setting, and the | |
| 502 | + @ users is "nobody", and the client has not previously passed a captcha | |
| 503 | + @ test to show that it is not a robot, then the page is not displayed. | |
| 504 | + @ A captcha test is is rendered instead. | |
| 505 | + @ The recommended value for this setting is: | |
| 506 | + @ <p> | |
| 507 | + @    <tt>%h(robot_restrict_default())</tt> | |
| 508 | + @ <p> | |
| 509 | + @ The "diff" tag covers all diffing pages such as /vdiff, /fdiff, and | |
| 510 | + @ /vpatch. The "annotate" tag covers /annotate and also /blame and | |
| 511 | + @ /praise. The "zip" covers itself and also /tarball and /sqlar. If a | |
| 512 | + @ tag has an "X" character appended, then it only applies if query | |
| 513 | + @ parameters are such that the page is particularly difficult to compute. | |
| 514 | + @ In all other case, the tag should exactly match the page name. | |
| 515 | + @ (Property: robot-restrict) | |
| 516 | + @ <br> | |
| 517 | + textarea_attribute("", 2, 80, | |
| 518 | + "robot-restrict", "rbrestrict", robot_restrict_default(), 0); | |
| 510 | 519 | |
| 511 | 520 | @ <hr> |
| 512 | 521 | addAutoHyperlinkSettings(); |
| 513 | 522 | |
| 514 | 523 | @ <hr> |
| @@ -520,37 +529,11 @@ | ||
| 520 | 529 | @ computations here. Set this to 0.0 to disable the load average limit. |
| 521 | 530 | @ This limit is only enforced on Unix servers. On Linux systems, |
| 522 | 531 | @ access to the /proc virtual filesystem is required, which means this limit |
| 523 | 532 | @ might not work inside a chroot() jail. |
| 524 | 533 | @ (Property: "max-loadavg")</p> |
| 525 | - | |
| 526 | - @ <hr> | |
| 527 | - @ <p><b>Do not allow robots to make complex requests | |
| 528 | - @ against the following pages.</b> | |
| 529 | - @ <p> A "complex request" is an HTTP request that has one or more query | |
| 530 | - @ parameters. Some robots will spend hours juggling around query parameters | |
| 531 | - @ or even forging fake query parameters in an effort to discover new | |
| 532 | - @ behavior or to find an SQL injection opportunity or similar. This can | |
| 533 | - @ waste hours of CPU time and gigabytes of bandwidth on the server. A | |
| 534 | - @ suggested value for this setting is: | |
| 535 | - @ "<tt>timeline,*diff,vpatch,annotate,blame,praise,dir,tree</tt>". | |
| 536 | - @ (Property: robot-restrict) | |
| 537 | - @ <br> | |
| 538 | - textarea_attribute("", 2, 80, | |
| 539 | - "robot-restrict", "rbrestrict", "", 0); | |
| 540 | - @ <br> The following comma-separated GLOB pattern allows for exceptions | |
| 541 | - @ in the maximum number of query parameters before a request is considered | |
| 542 | - @ complex. If this GLOB pattern exists and is non-empty and if it | |
| 543 | - @ matches against the pagename followed by "/" and the number of query | |
| 544 | - @ parameters, then the request is allowed through. For example, the | |
| 545 | - @ suggested pattern of "timeline/[012]" allows the /timeline page to | |
| 546 | - @ pass with up to 2 query parameters besides "name". | |
| 547 | - @ (Property: robot-restrict-qp) | |
| 548 | - @ <br> | |
| 549 | - textarea_attribute("", 2, 80, | |
| 550 | - "robot-restrict-qp", "rbrestrictqp", "", 0); | |
| 551 | - | |
| 534 | + @ | |
| 552 | 535 | @ <hr> |
| 553 | 536 | @ <p><input type="submit" name="submit" value="Apply Changes"></p> |
| 554 | 537 | @ </div></form> |
| 555 | 538 | db_end_transaction(0); |
| 556 | 539 | style_finish_page(); |
| 557 | 540 |
| --- src/setup.c | |
| +++ src/setup.c | |
| @@ -495,20 +495,29 @@ | |
| 495 | @ |
| 496 | @ <form action="%R/setup_robot" method="post"><div> |
| 497 | login_insert_csrf_secret(); |
| 498 | @ <input type="submit" name="submit" value="Apply Changes"></p> |
| 499 | @ <hr> |
| 500 | entry_attribute("Robot Squelch", 6, "robot-squelch", "rsq", "200", 0); |
| 501 | @ <p>The "squelch" setting determines how aggressive Fossil is about |
| 502 | @ trying to weed out robots using captchas. Squelch only applies to |
| 503 | @ expensive requests from user "nobody". The higher the squelch setting, |
| 504 | @ the more likely the request is to generate a captcha instead of the |
| 505 | @ requested page. Squelch can be any integer between 0 and 1000. |
| 506 | @ 0 means squelch is disabled and all requests go through without a |
| 507 | @ captcha. 1000 means every expensive request from user "nobody" gets |
| 508 | @ a captcha. |
| 509 | @ (Property: "robot-squelch")</p> |
| 510 | |
| 511 | @ <hr> |
| 512 | addAutoHyperlinkSettings(); |
| 513 | |
| 514 | @ <hr> |
| @@ -520,37 +529,11 @@ | |
| 520 | @ computations here. Set this to 0.0 to disable the load average limit. |
| 521 | @ This limit is only enforced on Unix servers. On Linux systems, |
| 522 | @ access to the /proc virtual filesystem is required, which means this limit |
| 523 | @ might not work inside a chroot() jail. |
| 524 | @ (Property: "max-loadavg")</p> |
| 525 | |
| 526 | @ <hr> |
| 527 | @ <p><b>Do not allow robots to make complex requests |
| 528 | @ against the following pages.</b> |
| 529 | @ <p> A "complex request" is an HTTP request that has one or more query |
| 530 | @ parameters. Some robots will spend hours juggling around query parameters |
| 531 | @ or even forging fake query parameters in an effort to discover new |
| 532 | @ behavior or to find an SQL injection opportunity or similar. This can |
| 533 | @ waste hours of CPU time and gigabytes of bandwidth on the server. A |
| 534 | @ suggested value for this setting is: |
| 535 | @ "<tt>timeline,*diff,vpatch,annotate,blame,praise,dir,tree</tt>". |
| 536 | @ (Property: robot-restrict) |
| 537 | @ <br> |
| 538 | textarea_attribute("", 2, 80, |
| 539 | "robot-restrict", "rbrestrict", "", 0); |
| 540 | @ <br> The following comma-separated GLOB pattern allows for exceptions |
| 541 | @ in the maximum number of query parameters before a request is considered |
| 542 | @ complex. If this GLOB pattern exists and is non-empty and if it |
| 543 | @ matches against the pagename followed by "/" and the number of query |
| 544 | @ parameters, then the request is allowed through. For example, the |
| 545 | @ suggested pattern of "timeline/[012]" allows the /timeline page to |
| 546 | @ pass with up to 2 query parameters besides "name". |
| 547 | @ (Property: robot-restrict-qp) |
| 548 | @ <br> |
| 549 | textarea_attribute("", 2, 80, |
| 550 | "robot-restrict-qp", "rbrestrictqp", "", 0); |
| 551 | |
| 552 | @ <hr> |
| 553 | @ <p><input type="submit" name="submit" value="Apply Changes"></p> |
| 554 | @ </div></form> |
| 555 | db_end_transaction(0); |
| 556 | style_finish_page(); |
| 557 |
| --- src/setup.c | |
| +++ src/setup.c | |
| @@ -495,20 +495,29 @@ | |
| 495 | @ |
| 496 | @ <form action="%R/setup_robot" method="post"><div> |
| 497 | login_insert_csrf_secret(); |
| 498 | @ <input type="submit" name="submit" value="Apply Changes"></p> |
| 499 | @ <hr> |
| 500 | @ <p><b>Do not allow robots access to these pages.</b> |
| 501 | @ <p> If the page name matches the GLOB pattern of this setting, and the |
| 502 | @ users is "nobody", and the client has not previously passed a captcha |
| 503 | @ test to show that it is not a robot, then the page is not displayed. |
| 504 | @ A captcha test is is rendered instead. |
| 505 | @ The recommended value for this setting is: |
| 506 | @ <p> |
| 507 | @    <tt>%h(robot_restrict_default())</tt> |
| 508 | @ <p> |
| 509 | @ The "diff" tag covers all diffing pages such as /vdiff, /fdiff, and |
| 510 | @ /vpatch. The "annotate" tag covers /annotate and also /blame and |
| 511 | @ /praise. The "zip" covers itself and also /tarball and /sqlar. If a |
| 512 | @ tag has an "X" character appended, then it only applies if query |
| 513 | @ parameters are such that the page is particularly difficult to compute. |
| 514 | @ In all other case, the tag should exactly match the page name. |
| 515 | @ (Property: robot-restrict) |
| 516 | @ <br> |
| 517 | textarea_attribute("", 2, 80, |
| 518 | "robot-restrict", "rbrestrict", robot_restrict_default(), 0); |
| 519 | |
| 520 | @ <hr> |
| 521 | addAutoHyperlinkSettings(); |
| 522 | |
| 523 | @ <hr> |
| @@ -520,37 +529,11 @@ | |
| 529 | @ computations here. Set this to 0.0 to disable the load average limit. |
| 530 | @ This limit is only enforced on Unix servers. On Linux systems, |
| 531 | @ access to the /proc virtual filesystem is required, which means this limit |
| 532 | @ might not work inside a chroot() jail. |
| 533 | @ (Property: "max-loadavg")</p> |
| 534 | @ |
| 535 | @ <hr> |
| 536 | @ <p><input type="submit" name="submit" value="Apply Changes"></p> |
| 537 | @ </div></form> |
| 538 | db_end_transaction(0); |
| 539 | style_finish_page(); |
| 540 |
+1
-46
| --- src/style.c | ||
| +++ src/style.c | ||
| @@ -1390,55 +1390,10 @@ | ||
| 1390 | 1390 | */ |
| 1391 | 1391 | void page_test_env(void){ |
| 1392 | 1392 | webpage_error(""); |
| 1393 | 1393 | } |
| 1394 | 1394 | |
| 1395 | -/* | |
| 1396 | -** WEBPAGE: honeypot | |
| 1397 | -** This page is a honeypot for spiders and bots. | |
| 1398 | -*/ | |
| 1399 | -void honeypot_page(void){ | |
| 1400 | - unsigned int uSeed = captcha_seed(); | |
| 1401 | - const char *zDecoded = captcha_decode(uSeed, 0); | |
| 1402 | - int bAutoCaptcha = db_get_boolean("auto-captcha", 0); | |
| 1403 | - char *zCaptcha = captcha_render(zDecoded); | |
| 1404 | - style_header("I think you are a robot"); | |
| 1405 | - @ <p>You seem like a robot.</p> | |
| 1406 | - @ | |
| 1407 | - @ <p>Is that incorrect? Are you really human? | |
| 1408 | - @ If so, please prove it by transcribing the captcha text | |
| 1409 | - @ into the entry box below and pressing "Submit". | |
| 1410 | - @ <form action="%R/login" method="post"> | |
| 1411 | - @ <input type="hidden" id="u" name="u" value="anonymous"> | |
| 1412 | - @ <p> | |
| 1413 | - @ Captcha: <input type="text" id="p" name="p" value=""> | |
| 1414 | - @ <input type="submit" name="in" value="Submit"> | |
| 1415 | - @ | |
| 1416 | - @ <p>Alternatively, you can <a href="%R/login">log in</a> using an | |
| 1417 | - @ existing userid. | |
| 1418 | - @ | |
| 1419 | - @ <p><input type="hidden" name="cs" value="%u(uSeed)"> | |
| 1420 | - @ <div class="captcha"><table class="captcha"><tr><td>\ | |
| 1421 | - @ <pre class="captcha"> | |
| 1422 | - @ %h(zCaptcha) | |
| 1423 | - @ </pre></td></tr></table> | |
| 1424 | - if( bAutoCaptcha ) { | |
| 1425 | - @ <input type="button" value="Fill out captcha" id='autofillButton' \ | |
| 1426 | - @ data-af='%s(zDecoded)'> | |
| 1427 | - builtin_request_js("login.js"); | |
| 1428 | - } | |
| 1429 | - @ </div> | |
| 1430 | - free(zCaptcha); | |
| 1431 | - @ | |
| 1432 | - @ <p>We regret this inconvenience. However, robots have become so | |
| 1433 | - @ prolific and so aggressive that they will soak up too much CPU time | |
| 1434 | - @ and network bandwidth on our servers if allowed to run unchecked. | |
| 1435 | - @ Your cooperation in demonstrating that you are human is | |
| 1436 | - @ appreciated. | |
| 1437 | - style_finish_page(); | |
| 1438 | -} | |
| 1439 | - | |
| 1440 | 1395 | /* |
| 1441 | 1396 | ** Webpages that encounter an error due to missing or incorrect |
| 1442 | 1397 | ** query parameters can jump to this routine to render an error |
| 1443 | 1398 | ** message screen. |
| 1444 | 1399 | ** |
| @@ -1487,11 +1442,11 @@ | ||
| 1487 | 1442 | @ g.zHttpsURL = %h(g.zHttpsURL)<br> |
| 1488 | 1443 | @ g.zTop = %h(g.zTop)<br> |
| 1489 | 1444 | @ g.zPath = %h(g.zPath)<br> |
| 1490 | 1445 | @ g.userUid = %d(g.userUid)<br> |
| 1491 | 1446 | @ g.zLogin = %h(g.zLogin)<br> |
| 1492 | - @ g.isHuman = %d(g.isHuman)<br> | |
| 1447 | + @ g.isRobot = %d(g.isRobot)<br> | |
| 1493 | 1448 | @ g.jsHref = %d(g.jsHref)<br> |
| 1494 | 1449 | if( g.zLocalRoot ){ |
| 1495 | 1450 | @ g.zLocalRoot = %h(g.zLocalRoot)<br> |
| 1496 | 1451 | }else{ |
| 1497 | 1452 | @ g.zLocalRoot = <i>none</i><br> |
| 1498 | 1453 |
| --- src/style.c | |
| +++ src/style.c | |
| @@ -1390,55 +1390,10 @@ | |
| 1390 | */ |
| 1391 | void page_test_env(void){ |
| 1392 | webpage_error(""); |
| 1393 | } |
| 1394 | |
| 1395 | /* |
| 1396 | ** WEBPAGE: honeypot |
| 1397 | ** This page is a honeypot for spiders and bots. |
| 1398 | */ |
| 1399 | void honeypot_page(void){ |
| 1400 | unsigned int uSeed = captcha_seed(); |
| 1401 | const char *zDecoded = captcha_decode(uSeed, 0); |
| 1402 | int bAutoCaptcha = db_get_boolean("auto-captcha", 0); |
| 1403 | char *zCaptcha = captcha_render(zDecoded); |
| 1404 | style_header("I think you are a robot"); |
| 1405 | @ <p>You seem like a robot.</p> |
| 1406 | @ |
| 1407 | @ <p>Is that incorrect? Are you really human? |
| 1408 | @ If so, please prove it by transcribing the captcha text |
| 1409 | @ into the entry box below and pressing "Submit". |
| 1410 | @ <form action="%R/login" method="post"> |
| 1411 | @ <input type="hidden" id="u" name="u" value="anonymous"> |
| 1412 | @ <p> |
| 1413 | @ Captcha: <input type="text" id="p" name="p" value=""> |
| 1414 | @ <input type="submit" name="in" value="Submit"> |
| 1415 | @ |
| 1416 | @ <p>Alternatively, you can <a href="%R/login">log in</a> using an |
| 1417 | @ existing userid. |
| 1418 | @ |
| 1419 | @ <p><input type="hidden" name="cs" value="%u(uSeed)"> |
| 1420 | @ <div class="captcha"><table class="captcha"><tr><td>\ |
| 1421 | @ <pre class="captcha"> |
| 1422 | @ %h(zCaptcha) |
| 1423 | @ </pre></td></tr></table> |
| 1424 | if( bAutoCaptcha ) { |
| 1425 | @ <input type="button" value="Fill out captcha" id='autofillButton' \ |
| 1426 | @ data-af='%s(zDecoded)'> |
| 1427 | builtin_request_js("login.js"); |
| 1428 | } |
| 1429 | @ </div> |
| 1430 | free(zCaptcha); |
| 1431 | @ |
| 1432 | @ <p>We regret this inconvenience. However, robots have become so |
| 1433 | @ prolific and so aggressive that they will soak up too much CPU time |
| 1434 | @ and network bandwidth on our servers if allowed to run unchecked. |
| 1435 | @ Your cooperation in demonstrating that you are human is |
| 1436 | @ appreciated. |
| 1437 | style_finish_page(); |
| 1438 | } |
| 1439 | |
| 1440 | /* |
| 1441 | ** Webpages that encounter an error due to missing or incorrect |
| 1442 | ** query parameters can jump to this routine to render an error |
| 1443 | ** message screen. |
| 1444 | ** |
| @@ -1487,11 +1442,11 @@ | |
| 1487 | @ g.zHttpsURL = %h(g.zHttpsURL)<br> |
| 1488 | @ g.zTop = %h(g.zTop)<br> |
| 1489 | @ g.zPath = %h(g.zPath)<br> |
| 1490 | @ g.userUid = %d(g.userUid)<br> |
| 1491 | @ g.zLogin = %h(g.zLogin)<br> |
| 1492 | @ g.isHuman = %d(g.isHuman)<br> |
| 1493 | @ g.jsHref = %d(g.jsHref)<br> |
| 1494 | if( g.zLocalRoot ){ |
| 1495 | @ g.zLocalRoot = %h(g.zLocalRoot)<br> |
| 1496 | }else{ |
| 1497 | @ g.zLocalRoot = <i>none</i><br> |
| 1498 |
| --- src/style.c | |
| +++ src/style.c | |
| @@ -1390,55 +1390,10 @@ | |
| 1390 | */ |
| 1391 | void page_test_env(void){ |
| 1392 | webpage_error(""); |
| 1393 | } |
| 1394 | |
| 1395 | /* |
| 1396 | ** Webpages that encounter an error due to missing or incorrect |
| 1397 | ** query parameters can jump to this routine to render an error |
| 1398 | ** message screen. |
| 1399 | ** |
| @@ -1487,11 +1442,11 @@ | |
| 1442 | @ g.zHttpsURL = %h(g.zHttpsURL)<br> |
| 1443 | @ g.zTop = %h(g.zTop)<br> |
| 1444 | @ g.zPath = %h(g.zPath)<br> |
| 1445 | @ g.userUid = %d(g.userUid)<br> |
| 1446 | @ g.zLogin = %h(g.zLogin)<br> |
| 1447 | @ g.isRobot = %d(g.isRobot)<br> |
| 1448 | @ g.jsHref = %d(g.jsHref)<br> |
| 1449 | if( g.zLocalRoot ){ |
| 1450 | @ g.zLocalRoot = %h(g.zLocalRoot)<br> |
| 1451 | }else{ |
| 1452 | @ g.zLocalRoot = <i>none</i><br> |
| 1453 |
+1
-1
| --- src/tar.c | ||
| +++ src/tar.c | ||
| @@ -760,11 +760,11 @@ | ||
| 760 | 760 | Blob tarball; /* Tarball accumulated here */ |
| 761 | 761 | const char *z; |
| 762 | 762 | |
| 763 | 763 | login_check_credentials(); |
| 764 | 764 | if( !g.perm.Zip ){ login_needed(g.anon.Zip); return; } |
| 765 | - if( robot_squelch(900) ) return; | |
| 765 | + if( robot_restrict("zip") ) return; | |
| 766 | 766 | fossil_nice_default(); |
| 767 | 767 | zName = fossil_strdup(PD("name","")); |
| 768 | 768 | z = P("r"); |
| 769 | 769 | if( z==0 ) z = P("uuid"); |
| 770 | 770 | if( z==0 ) z = tar_uuid_from_name(&zName); |
| 771 | 771 |
| --- src/tar.c | |
| +++ src/tar.c | |
| @@ -760,11 +760,11 @@ | |
| 760 | Blob tarball; /* Tarball accumulated here */ |
| 761 | const char *z; |
| 762 | |
| 763 | login_check_credentials(); |
| 764 | if( !g.perm.Zip ){ login_needed(g.anon.Zip); return; } |
| 765 | if( robot_squelch(900) ) return; |
| 766 | fossil_nice_default(); |
| 767 | zName = fossil_strdup(PD("name","")); |
| 768 | z = P("r"); |
| 769 | if( z==0 ) z = P("uuid"); |
| 770 | if( z==0 ) z = tar_uuid_from_name(&zName); |
| 771 |
| --- src/tar.c | |
| +++ src/tar.c | |
| @@ -760,11 +760,11 @@ | |
| 760 | Blob tarball; /* Tarball accumulated here */ |
| 761 | const char *z; |
| 762 | |
| 763 | login_check_credentials(); |
| 764 | if( !g.perm.Zip ){ login_needed(g.anon.Zip); return; } |
| 765 | if( robot_restrict("zip") ) return; |
| 766 | fossil_nice_default(); |
| 767 | zName = fossil_strdup(PD("name","")); |
| 768 | z = P("r"); |
| 769 | if( z==0 ) z = P("uuid"); |
| 770 | if( z==0 ) z = tar_uuid_from_name(&zName); |
| 771 |
+1
| --- src/timeline.c | ||
| +++ src/timeline.c | ||
| @@ -1830,10 +1830,11 @@ | ||
| 1830 | 1830 | || (bisectLocal && !g.perm.Setup) |
| 1831 | 1831 | ){ |
| 1832 | 1832 | login_needed(g.anon.Read && g.anon.RdTkt && g.anon.RdWiki); |
| 1833 | 1833 | return; |
| 1834 | 1834 | } |
| 1835 | + if( zBefore && robot_restrict("timelineX") ) return; | |
| 1835 | 1836 | if( !bisectLocal ){ |
| 1836 | 1837 | etag_check(ETAG_QUERY|ETAG_COOKIE|ETAG_DATA|ETAG_CONFIG, 0); |
| 1837 | 1838 | } |
| 1838 | 1839 | cookie_read_parameter("y","y"); |
| 1839 | 1840 | zType = P("y"); |
| 1840 | 1841 |
| --- src/timeline.c | |
| +++ src/timeline.c | |
| @@ -1830,10 +1830,11 @@ | |
| 1830 | || (bisectLocal && !g.perm.Setup) |
| 1831 | ){ |
| 1832 | login_needed(g.anon.Read && g.anon.RdTkt && g.anon.RdWiki); |
| 1833 | return; |
| 1834 | } |
| 1835 | if( !bisectLocal ){ |
| 1836 | etag_check(ETAG_QUERY|ETAG_COOKIE|ETAG_DATA|ETAG_CONFIG, 0); |
| 1837 | } |
| 1838 | cookie_read_parameter("y","y"); |
| 1839 | zType = P("y"); |
| 1840 |
| --- src/timeline.c | |
| +++ src/timeline.c | |
| @@ -1830,10 +1830,11 @@ | |
| 1830 | || (bisectLocal && !g.perm.Setup) |
| 1831 | ){ |
| 1832 | login_needed(g.anon.Read && g.anon.RdTkt && g.anon.RdWiki); |
| 1833 | return; |
| 1834 | } |
| 1835 | if( zBefore && robot_restrict("timelineX") ) return; |
| 1836 | if( !bisectLocal ){ |
| 1837 | etag_check(ETAG_QUERY|ETAG_COOKIE|ETAG_DATA|ETAG_CONFIG, 0); |
| 1838 | } |
| 1839 | cookie_read_parameter("y","y"); |
| 1840 | zType = P("y"); |
| 1841 |
+1
-1
| --- src/zip.c | ||
| +++ src/zip.c | ||
| @@ -1012,11 +1012,11 @@ | ||
| 1012 | 1012 | int eType = ARCHIVE_ZIP; /* Type of archive to generate */ |
| 1013 | 1013 | char *zType; /* Human-readable archive type */ |
| 1014 | 1014 | |
| 1015 | 1015 | login_check_credentials(); |
| 1016 | 1016 | if( !g.perm.Zip ){ login_needed(g.anon.Zip); return; } |
| 1017 | - if( robot_squelch(900) ) return; | |
| 1017 | + if( robot_restrict("zip") ) return; | |
| 1018 | 1018 | if( fossil_strcmp(g.zPath, "sqlar")==0 ){ |
| 1019 | 1019 | eType = ARCHIVE_SQLAR; |
| 1020 | 1020 | zType = "SQL"; |
| 1021 | 1021 | /* For some reason, SQL-archives are like catnip for robots. So |
| 1022 | 1022 | ** don't allow them to be downloaded by user "nobody" */ |
| 1023 | 1023 |
| --- src/zip.c | |
| +++ src/zip.c | |
| @@ -1012,11 +1012,11 @@ | |
| 1012 | int eType = ARCHIVE_ZIP; /* Type of archive to generate */ |
| 1013 | char *zType; /* Human-readable archive type */ |
| 1014 | |
| 1015 | login_check_credentials(); |
| 1016 | if( !g.perm.Zip ){ login_needed(g.anon.Zip); return; } |
| 1017 | if( robot_squelch(900) ) return; |
| 1018 | if( fossil_strcmp(g.zPath, "sqlar")==0 ){ |
| 1019 | eType = ARCHIVE_SQLAR; |
| 1020 | zType = "SQL"; |
| 1021 | /* For some reason, SQL-archives are like catnip for robots. So |
| 1022 | ** don't allow them to be downloaded by user "nobody" */ |
| 1023 |
| --- src/zip.c | |
| +++ src/zip.c | |
| @@ -1012,11 +1012,11 @@ | |
| 1012 | int eType = ARCHIVE_ZIP; /* Type of archive to generate */ |
| 1013 | char *zType; /* Human-readable archive type */ |
| 1014 | |
| 1015 | login_check_credentials(); |
| 1016 | if( !g.perm.Zip ){ login_needed(g.anon.Zip); return; } |
| 1017 | if( robot_restrict("zip") ) return; |
| 1018 | if( fossil_strcmp(g.zPath, "sqlar")==0 ){ |
| 1019 | eType = ARCHIVE_SQLAR; |
| 1020 | zType = "SQL"; |
| 1021 | /* For some reason, SQL-archives are like catnip for robots. So |
| 1022 | ** don't allow them to be downloaded by user "nobody" */ |
| 1023 |