Fossil SCM
Robot defense uses a mousedown event rather than mouse motion as one of the signals that the request is from a human. This should make robot defense work better for users on mobile.
Commit
8d4e11432d2d54a7c3445b465d14c5ce99e2c10abfe97bbe5e659b31af5da146
Parent
5bb921dd0893a54…
4 files changed
+15
-10
+2
-2
+13
-9
+8
-6
+15
-10
| --- src/href.js | ||
| +++ src/href.js | ||
| @@ -12,14 +12,17 @@ | ||
| 12 | 12 | ** |
| 13 | 13 | ** {"delay":MILLISECONDS, "mouseover":BOOLEAN} |
| 14 | 14 | ** |
| 15 | 15 | ** The <script> must have an id='href-data'. DELAY is the number |
| 16 | 16 | ** milliseconds delay prior to populating href= and action=. If the |
| 17 | -** mouseover boolean is true, then the timer does not start until a | |
| 18 | -** mouse motion event occurs over top of the document. | |
| 17 | +** mouseover boolean is true, then the href= rewrite is further delayed | |
| 18 | +** until the first mousedown event that occurs after the timer expires. | |
| 19 | 19 | */ |
| 20 | -function setAllHrefs(){ | |
| 20 | +var antiRobotOnce = 0; | |
| 21 | +function antiRobotSetAllHrefs(){ | |
| 22 | + if( antiRobotOnce ) return; | |
| 23 | + antiRobotOnce = 1; | |
| 21 | 24 | var anchors = document.getElementsByTagName("a"); |
| 22 | 25 | for(var i=0; i<anchors.length; i++){ |
| 23 | 26 | var j = anchors[i]; |
| 24 | 27 | if(j.hasAttribute("data-href")) j.href=j.getAttribute("data-href"); |
| 25 | 28 | } |
| @@ -26,21 +29,23 @@ | ||
| 26 | 29 | var forms = document.getElementsByTagName("form"); |
| 27 | 30 | for(var i=0; i<forms.length; i++){ |
| 28 | 31 | var j = forms[i]; |
| 29 | 32 | if(j.hasAttribute("data-action")) j.action=j.getAttribute("data-action"); |
| 30 | 33 | } |
| 34 | +} | |
| 35 | +function antiRobotSetMouseEventHandler(){ | |
| 36 | + document.getElementsByTagName("body")[0].onmousedown=function(){ | |
| 37 | + antiRobotSetAllHrefs(); | |
| 38 | + document.getElementsByTagName("body")[0].onmousedown=null; | |
| 39 | + } | |
| 31 | 40 | } |
| 32 | 41 | function antiRobotDefense(){ |
| 33 | 42 | var x = document.getElementById("href-data"); |
| 34 | 43 | var jx = x.textContent || x.innerText; |
| 35 | 44 | var g = JSON.parse(jx); |
| 36 | - var isOperaMini = | |
| 37 | - Object.prototype.toString.call(window.operamini)==="[object OperaMini]"; | |
| 38 | - if(g.mouseover && !isOperaMini){ | |
| 39 | - document.getElementsByTagName("body")[0].onmousemove=function(){ | |
| 40 | - setTimeout(setAllHrefs, g.delay); | |
| 41 | - } | |
| 45 | + if( g.mouseover ){ | |
| 46 | + setTimeout(antiRobotSetMouseEventHandler, g.delay); | |
| 42 | 47 | }else{ |
| 43 | - setTimeout(setAllHrefs, g.delay); | |
| 48 | + setTimeout(antiRobotSetAllHrefs, g.delay); | |
| 44 | 49 | } |
| 45 | 50 | } |
| 46 | 51 | antiRobotDefense(); |
| 47 | 52 |
| --- src/href.js | |
| +++ src/href.js | |
| @@ -12,14 +12,17 @@ | |
| 12 | ** |
| 13 | ** {"delay":MILLISECONDS, "mouseover":BOOLEAN} |
| 14 | ** |
| 15 | ** The <script> must have an id='href-data'. DELAY is the number |
| 16 | ** milliseconds delay prior to populating href= and action=. If the |
| 17 | ** mouseover boolean is true, then the timer does not start until a |
| 18 | ** mouse motion event occurs over top of the document. |
| 19 | */ |
| 20 | function setAllHrefs(){ |
| 21 | var anchors = document.getElementsByTagName("a"); |
| 22 | for(var i=0; i<anchors.length; i++){ |
| 23 | var j = anchors[i]; |
| 24 | if(j.hasAttribute("data-href")) j.href=j.getAttribute("data-href"); |
| 25 | } |
| @@ -26,21 +29,23 @@ | |
| 26 | var forms = document.getElementsByTagName("form"); |
| 27 | for(var i=0; i<forms.length; i++){ |
| 28 | var j = forms[i]; |
| 29 | if(j.hasAttribute("data-action")) j.action=j.getAttribute("data-action"); |
| 30 | } |
| 31 | } |
| 32 | function antiRobotDefense(){ |
| 33 | var x = document.getElementById("href-data"); |
| 34 | var jx = x.textContent || x.innerText; |
| 35 | var g = JSON.parse(jx); |
| 36 | var isOperaMini = |
| 37 | Object.prototype.toString.call(window.operamini)==="[object OperaMini]"; |
| 38 | if(g.mouseover && !isOperaMini){ |
| 39 | document.getElementsByTagName("body")[0].onmousemove=function(){ |
| 40 | setTimeout(setAllHrefs, g.delay); |
| 41 | } |
| 42 | }else{ |
| 43 | setTimeout(setAllHrefs, g.delay); |
| 44 | } |
| 45 | } |
| 46 | antiRobotDefense(); |
| 47 |
| --- src/href.js | |
| +++ src/href.js | |
| @@ -12,14 +12,17 @@ | |
| 12 | ** |
| 13 | ** {"delay":MILLISECONDS, "mouseover":BOOLEAN} |
| 14 | ** |
| 15 | ** The <script> must have an id='href-data'. DELAY is the number |
| 16 | ** milliseconds delay prior to populating href= and action=. If the |
| 17 | ** mouseover boolean is true, then the href= rewrite is further delayed |
| 18 | ** until the first mousedown event that occurs after the timer expires. |
| 19 | */ |
| 20 | var antiRobotOnce = 0; |
| 21 | function antiRobotSetAllHrefs(){ |
| 22 | if( antiRobotOnce ) return; |
| 23 | antiRobotOnce = 1; |
| 24 | var anchors = document.getElementsByTagName("a"); |
| 25 | for(var i=0; i<anchors.length; i++){ |
| 26 | var j = anchors[i]; |
| 27 | if(j.hasAttribute("data-href")) j.href=j.getAttribute("data-href"); |
| 28 | } |
| @@ -26,21 +29,23 @@ | |
| 29 | var forms = document.getElementsByTagName("form"); |
| 30 | for(var i=0; i<forms.length; i++){ |
| 31 | var j = forms[i]; |
| 32 | if(j.hasAttribute("data-action")) j.action=j.getAttribute("data-action"); |
| 33 | } |
| 34 | } |
| 35 | function antiRobotSetMouseEventHandler(){ |
| 36 | document.getElementsByTagName("body")[0].onmousedown=function(){ |
| 37 | antiRobotSetAllHrefs(); |
| 38 | document.getElementsByTagName("body")[0].onmousedown=null; |
| 39 | } |
| 40 | } |
| 41 | function antiRobotDefense(){ |
| 42 | var x = document.getElementById("href-data"); |
| 43 | var jx = x.textContent || x.innerText; |
| 44 | var g = JSON.parse(jx); |
| 45 | if( g.mouseover ){ |
| 46 | setTimeout(antiRobotSetMouseEventHandler, g.delay); |
| 47 | }else{ |
| 48 | setTimeout(antiRobotSetAllHrefs, g.delay); |
| 49 | } |
| 50 | } |
| 51 | antiRobotDefense(); |
| 52 |
+2
-2
| --- src/security_audit.c | ||
| +++ src/security_audit.c | ||
| @@ -489,12 +489,12 @@ | ||
| 489 | 489 | @ <li>Remove the 'h' privilege from the |
| 490 | 490 | @ <a href="%R/setup_uedit?id=%d(nobodyId)">'nobody' user</a> so that |
| 491 | 491 | @ robots cannot see hyperlinks. |
| 492 | 492 | @ <li>Activate <a href="%R/setup_access#autoh">autohyperlink</a> so that |
| 493 | 493 | @ human readers can still see hyperlinks even if they are not logged in. |
| 494 | - @ Require mouse movement before enabling hyperlinks and set the | |
| 495 | - @ delay to at least 50 milliseconds. | |
| 494 | + @ Set the delay to at least 50 milliseconds and require a mousedown | |
| 495 | + @ event for maximum robot defense. | |
| 496 | 496 | if( anonId>0 ){ |
| 497 | 497 | @ <li>Perhaps set the 'h' privilege on the |
| 498 | 498 | @ <a href="%R/setup_uedit?id=%d(anonId)">'anonymous' user</a> so |
| 499 | 499 | @ that humans that have javascript disabled in their browsers can |
| 500 | 500 | @ still see hyperlinks if they will log in as "anonymous". |
| 501 | 501 |
| --- src/security_audit.c | |
| +++ src/security_audit.c | |
| @@ -489,12 +489,12 @@ | |
| 489 | @ <li>Remove the 'h' privilege from the |
| 490 | @ <a href="%R/setup_uedit?id=%d(nobodyId)">'nobody' user</a> so that |
| 491 | @ robots cannot see hyperlinks. |
| 492 | @ <li>Activate <a href="%R/setup_access#autoh">autohyperlink</a> so that |
| 493 | @ human readers can still see hyperlinks even if they are not logged in. |
| 494 | @ Require mouse movement before enabling hyperlinks and set the |
| 495 | @ delay to at least 50 milliseconds. |
| 496 | if( anonId>0 ){ |
| 497 | @ <li>Perhaps set the 'h' privilege on the |
| 498 | @ <a href="%R/setup_uedit?id=%d(anonId)">'anonymous' user</a> so |
| 499 | @ that humans that have javascript disabled in their browsers can |
| 500 | @ still see hyperlinks if they will log in as "anonymous". |
| 501 |
| --- src/security_audit.c | |
| +++ src/security_audit.c | |
| @@ -489,12 +489,12 @@ | |
| 489 | @ <li>Remove the 'h' privilege from the |
| 490 | @ <a href="%R/setup_uedit?id=%d(nobodyId)">'nobody' user</a> so that |
| 491 | @ robots cannot see hyperlinks. |
| 492 | @ <li>Activate <a href="%R/setup_access#autoh">autohyperlink</a> so that |
| 493 | @ human readers can still see hyperlinks even if they are not logged in. |
| 494 | @ Set the delay to at least 50 milliseconds and require a mousedown |
| 495 | @ event for maximum robot defense. |
| 496 | if( anonId>0 ){ |
| 497 | @ <li>Perhaps set the 'h' privilege on the |
| 498 | @ <a href="%R/setup_uedit?id=%d(anonId)">'anonymous' user</a> so |
| 499 | @ that humans that have javascript disabled in their browsers can |
| 500 | @ still see hyperlinks if they will log in as "anonymous". |
| 501 |
+13
-9
| --- src/setup.c | ||
| +++ src/setup.c | ||
| @@ -472,12 +472,13 @@ | ||
| 472 | 472 | @ <ol><li>the User-Agent string in the |
| 473 | 473 | @ HTTP header indicates that the request is coming from an actual human |
| 474 | 474 | @ being, and |
| 475 | 475 | @ <li>the user agent is able to |
| 476 | 476 | @ run Javascript in order to set the href= attribute of hyperlinks, and |
| 477 | - @ <li>mouse movement is detected (optional - see the checkbox below), and | |
| 478 | - @ <li>a number of milliseconds have passed since the page loaded.</ol> | |
| 477 | + @ <li>a number of milliseconds have passed since the page loaded, and | |
| 478 | + @ <li>a mousedown event is detected (optional - see the checkbox below) | |
| 479 | + @ </ol> | |
| 479 | 480 | @ |
| 480 | 481 | @ <p>This setting is designed to give easy access to humans while |
| 481 | 482 | @ keeping out robots and spiders. |
| 482 | 483 | @ You do not normally want a robot to walk your entire repository because |
| 483 | 484 | @ if it does, your server will end up computing diffs and annotations for |
| @@ -485,20 +486,23 @@ | ||
| 485 | 486 | @ every historical check-in, which can use a lot of CPU and bandwidth |
| 486 | 487 | @ even for relatively small projects.</p> |
| 487 | 488 | @ |
| 488 | 489 | @ <p>Additional parameters that control this behavior:</p> |
| 489 | 490 | @ <blockquote> |
| 490 | - onoff_attribute("Require mouse movement before enabling hyperlinks", | |
| 491 | - "auto-hyperlink-mouseover", "ahmo", 0, 0); | |
| 492 | - @ <br /> | |
| 493 | 491 | entry_attribute("Delay in milliseconds before enabling hyperlinks", 5, |
| 494 | 492 | "auto-hyperlink-delay", "ah-delay", "50", 0); |
| 493 | + @ <br /> | |
| 494 | + onoff_attribute("Also require a mousedown event before enabling hyperlinks", | |
| 495 | + "auto-hyperlink-mouseover", "ahmo", 0, 0); | |
| 495 | 496 | @ </blockquote> |
| 496 | - @ <p>For maximum robot defense, the "require mouse movement" should | |
| 497 | - @ be turned on and the "Delay" should be at least 50 milliseconds.</p> | |
| 498 | - @ (Properties: "auto-hyperlink", | |
| 499 | - @ "auto-hyperlink-mouseover", and "auto-hyperlink-delay")</p> | |
| 497 | + @ <p>For maximum robot defense, "Delay" should be at least 50 milliseconds | |
| 498 | + @ and "require a mousedown event" should turned on. To test to see that | |
| 499 | + @ this mechanism is working, visit the <a href="%R/test_env">/test_env</a> | |
| 500 | + @ page (from a separate web browser that is not logged in, even as | |
| 501 | + @ "anonymous") and verify that the "g.javascriptHyperlink" value is "1".</p> | |
| 502 | + @ <p>(Properties: "auto-hyperlink", "auto-hyperlink-delay", and | |
| 503 | + @ "auto-hyperlink-mouseover"")</p> | |
| 500 | 504 | |
| 501 | 505 | @ <hr /> |
| 502 | 506 | onoff_attribute("Require a CAPTCHA if not logged in", |
| 503 | 507 | "require-captcha", "reqcapt", 1, 0); |
| 504 | 508 | @ <p>Require a CAPTCHA for edit operations (appending, creating, or |
| 505 | 509 |
| --- src/setup.c | |
| +++ src/setup.c | |
| @@ -472,12 +472,13 @@ | |
| 472 | @ <ol><li>the User-Agent string in the |
| 473 | @ HTTP header indicates that the request is coming from an actual human |
| 474 | @ being, and |
| 475 | @ <li>the user agent is able to |
| 476 | @ run Javascript in order to set the href= attribute of hyperlinks, and |
| 477 | @ <li>mouse movement is detected (optional - see the checkbox below), and |
| 478 | @ <li>a number of milliseconds have passed since the page loaded.</ol> |
| 479 | @ |
| 480 | @ <p>This setting is designed to give easy access to humans while |
| 481 | @ keeping out robots and spiders. |
| 482 | @ You do not normally want a robot to walk your entire repository because |
| 483 | @ if it does, your server will end up computing diffs and annotations for |
| @@ -485,20 +486,23 @@ | |
| 485 | @ every historical check-in, which can use a lot of CPU and bandwidth |
| 486 | @ even for relatively small projects.</p> |
| 487 | @ |
| 488 | @ <p>Additional parameters that control this behavior:</p> |
| 489 | @ <blockquote> |
| 490 | onoff_attribute("Require mouse movement before enabling hyperlinks", |
| 491 | "auto-hyperlink-mouseover", "ahmo", 0, 0); |
| 492 | @ <br /> |
| 493 | entry_attribute("Delay in milliseconds before enabling hyperlinks", 5, |
| 494 | "auto-hyperlink-delay", "ah-delay", "50", 0); |
| 495 | @ </blockquote> |
| 496 | @ <p>For maximum robot defense, the "require mouse movement" should |
| 497 | @ be turned on and the "Delay" should be at least 50 milliseconds.</p> |
| 498 | @ (Properties: "auto-hyperlink", |
| 499 | @ "auto-hyperlink-mouseover", and "auto-hyperlink-delay")</p> |
| 500 | |
| 501 | @ <hr /> |
| 502 | onoff_attribute("Require a CAPTCHA if not logged in", |
| 503 | "require-captcha", "reqcapt", 1, 0); |
| 504 | @ <p>Require a CAPTCHA for edit operations (appending, creating, or |
| 505 |
| --- src/setup.c | |
| +++ src/setup.c | |
| @@ -472,12 +472,13 @@ | |
| 472 | @ <ol><li>the User-Agent string in the |
| 473 | @ HTTP header indicates that the request is coming from an actual human |
| 474 | @ being, and |
| 475 | @ <li>the user agent is able to |
| 476 | @ run Javascript in order to set the href= attribute of hyperlinks, and |
| 477 | @ <li>a number of milliseconds have passed since the page loaded, and |
| 478 | @ <li>a mousedown event is detected (optional - see the checkbox below) |
| 479 | @ </ol> |
| 480 | @ |
| 481 | @ <p>This setting is designed to give easy access to humans while |
| 482 | @ keeping out robots and spiders. |
| 483 | @ You do not normally want a robot to walk your entire repository because |
| 484 | @ if it does, your server will end up computing diffs and annotations for |
| @@ -485,20 +486,23 @@ | |
| 486 | @ every historical check-in, which can use a lot of CPU and bandwidth |
| 487 | @ even for relatively small projects.</p> |
| 488 | @ |
| 489 | @ <p>Additional parameters that control this behavior:</p> |
| 490 | @ <blockquote> |
| 491 | entry_attribute("Delay in milliseconds before enabling hyperlinks", 5, |
| 492 | "auto-hyperlink-delay", "ah-delay", "50", 0); |
| 493 | @ <br /> |
| 494 | onoff_attribute("Also require a mousedown event before enabling hyperlinks", |
| 495 | "auto-hyperlink-mouseover", "ahmo", 0, 0); |
| 496 | @ </blockquote> |
| 497 | @ <p>For maximum robot defense, "Delay" should be at least 50 milliseconds |
| 498 | @ and "require a mousedown event" should turned on. To test to see that |
| 499 | @ this mechanism is working, visit the <a href="%R/test_env">/test_env</a> |
| 500 | @ page (from a separate web browser that is not logged in, even as |
| 501 | @ "anonymous") and verify that the "g.javascriptHyperlink" value is "1".</p> |
| 502 | @ <p>(Properties: "auto-hyperlink", "auto-hyperlink-delay", and |
| 503 | @ "auto-hyperlink-mouseover"")</p> |
| 504 | |
| 505 | @ <hr /> |
| 506 | onoff_attribute("Require a CAPTCHA if not logged in", |
| 507 | "require-captcha", "reqcapt", 1, 0); |
| 508 | @ <p>Require a CAPTCHA for edit operations (appending, creating, or |
| 509 |
+8
-6
| --- src/style.c | ||
| +++ src/style.c | ||
| @@ -114,17 +114,18 @@ | ||
| 114 | 114 | ** g.perm.Hyperlink g.javascriptHyperlink Returned anchor format |
| 115 | 115 | ** ---------------- --------------------- ------------------------ |
| 116 | 116 | ** 0 0 (empty string) |
| 117 | 117 | ** 0 1 (empty string) |
| 118 | 118 | ** 1 0 <a href="URL"> |
| 119 | -** 1 1 <a id="ID"> | |
| 119 | +** 1 1 <a data-href="URL"> | |
| 120 | 120 | ** |
| 121 | 121 | ** No anchor tag is generated if g.perm.Hyperlink is false. |
| 122 | 122 | ** The href="URL" form is used if g.javascriptHyperlink is false. |
| 123 | -** If g.javascriptHyperlink is true then the id="ID" form is used and | |
| 124 | -** javascript is generated in the footer to cause href values to be | |
| 125 | -** inserted after the page has loaded. The use of the id="ID" form | |
| 123 | +** If g.javascriptHyperlink is true then the data-href="URL" and | |
| 124 | +** href="/honeypot" is generated and javascript is added to the footer | |
| 125 | +** to cause data-href values to be inserted into href | |
| 126 | +** after the page has loaded. The use of the data-href="URL" form | |
| 126 | 127 | ** instead of href="URL" is a defense against bots. |
| 127 | 128 | ** |
| 128 | 129 | ** If the user lacks the Hyperlink (h) property and the "auto-hyperlink" |
| 129 | 130 | ** setting is true, then g.perm.Hyperlink is changed from 0 to 1 and |
| 130 | 131 | ** g.javascriptHyperlink is set to 1 by login_check_credentials(). Thus |
| @@ -142,12 +143,12 @@ | ||
| 142 | 143 | ** |
| 143 | 144 | ** User has "h" auto-hyperlink Returned anchor format |
| 144 | 145 | ** ------------ -------------- ---------------------- |
| 145 | 146 | ** 0 0 (empty string) |
| 146 | 147 | ** 1 0 <a href="URL"> |
| 147 | -** 0 1 <a id="ID"> | |
| 148 | -** 1 1 (can't happen) | |
| 148 | +** 0 1 <a data-href="URL"> | |
| 149 | +** 1 1 <a href="URL"> | |
| 149 | 150 | ** |
| 150 | 151 | ** The name of these routines are deliberately kept short so that can be |
| 151 | 152 | ** easily used within @-lines. Example: |
| 152 | 153 | ** |
| 153 | 154 | ** @ %z(href("%R/artifact/%s",zUuid))%h(zFN)</a> |
| @@ -1375,10 +1376,11 @@ | ||
| 1375 | 1376 | @ g.zTop = %h(g.zTop)<br /> |
| 1376 | 1377 | @ g.zPath = %h(g.zPath)<br /> |
| 1377 | 1378 | @ g.userUid = %d(g.userUid)<br /> |
| 1378 | 1379 | @ g.zLogin = %h(g.zLogin)<br /> |
| 1379 | 1380 | @ g.isHuman = %d(g.isHuman)<br /> |
| 1381 | + @ g.javascriptHyperlink = %d(g.javascriptHyperlink)<br /> | |
| 1380 | 1382 | if( g.nRequest ){ |
| 1381 | 1383 | @ g.nRequest = %d(g.nRequest)<br /> |
| 1382 | 1384 | } |
| 1383 | 1385 | if( g.nPendingRequest>1 ){ |
| 1384 | 1386 | @ g.nPendingRequest = %d(g.nPendingRequest)<br /> |
| 1385 | 1387 |
| --- src/style.c | |
| +++ src/style.c | |
| @@ -114,17 +114,18 @@ | |
| 114 | ** g.perm.Hyperlink g.javascriptHyperlink Returned anchor format |
| 115 | ** ---------------- --------------------- ------------------------ |
| 116 | ** 0 0 (empty string) |
| 117 | ** 0 1 (empty string) |
| 118 | ** 1 0 <a href="URL"> |
| 119 | ** 1 1 <a id="ID"> |
| 120 | ** |
| 121 | ** No anchor tag is generated if g.perm.Hyperlink is false. |
| 122 | ** The href="URL" form is used if g.javascriptHyperlink is false. |
| 123 | ** If g.javascriptHyperlink is true then the id="ID" form is used and |
| 124 | ** javascript is generated in the footer to cause href values to be |
| 125 | ** inserted after the page has loaded. The use of the id="ID" form |
| 126 | ** instead of href="URL" is a defense against bots. |
| 127 | ** |
| 128 | ** If the user lacks the Hyperlink (h) property and the "auto-hyperlink" |
| 129 | ** setting is true, then g.perm.Hyperlink is changed from 0 to 1 and |
| 130 | ** g.javascriptHyperlink is set to 1 by login_check_credentials(). Thus |
| @@ -142,12 +143,12 @@ | |
| 142 | ** |
| 143 | ** User has "h" auto-hyperlink Returned anchor format |
| 144 | ** ------------ -------------- ---------------------- |
| 145 | ** 0 0 (empty string) |
| 146 | ** 1 0 <a href="URL"> |
| 147 | ** 0 1 <a id="ID"> |
| 148 | ** 1 1 (can't happen) |
| 149 | ** |
| 150 | ** The name of these routines are deliberately kept short so that can be |
| 151 | ** easily used within @-lines. Example: |
| 152 | ** |
| 153 | ** @ %z(href("%R/artifact/%s",zUuid))%h(zFN)</a> |
| @@ -1375,10 +1376,11 @@ | |
| 1375 | @ g.zTop = %h(g.zTop)<br /> |
| 1376 | @ g.zPath = %h(g.zPath)<br /> |
| 1377 | @ g.userUid = %d(g.userUid)<br /> |
| 1378 | @ g.zLogin = %h(g.zLogin)<br /> |
| 1379 | @ g.isHuman = %d(g.isHuman)<br /> |
| 1380 | if( g.nRequest ){ |
| 1381 | @ g.nRequest = %d(g.nRequest)<br /> |
| 1382 | } |
| 1383 | if( g.nPendingRequest>1 ){ |
| 1384 | @ g.nPendingRequest = %d(g.nPendingRequest)<br /> |
| 1385 |
| --- src/style.c | |
| +++ src/style.c | |
| @@ -114,17 +114,18 @@ | |
| 114 | ** g.perm.Hyperlink g.javascriptHyperlink Returned anchor format |
| 115 | ** ---------------- --------------------- ------------------------ |
| 116 | ** 0 0 (empty string) |
| 117 | ** 0 1 (empty string) |
| 118 | ** 1 0 <a href="URL"> |
| 119 | ** 1 1 <a data-href="URL"> |
| 120 | ** |
| 121 | ** No anchor tag is generated if g.perm.Hyperlink is false. |
| 122 | ** The href="URL" form is used if g.javascriptHyperlink is false. |
| 123 | ** If g.javascriptHyperlink is true then the data-href="URL" and |
| 124 | ** href="/honeypot" is generated and javascript is added to the footer |
| 125 | ** to cause data-href values to be inserted into href |
| 126 | ** after the page has loaded. The use of the data-href="URL" form |
| 127 | ** instead of href="URL" is a defense against bots. |
| 128 | ** |
| 129 | ** If the user lacks the Hyperlink (h) property and the "auto-hyperlink" |
| 130 | ** setting is true, then g.perm.Hyperlink is changed from 0 to 1 and |
| 131 | ** g.javascriptHyperlink is set to 1 by login_check_credentials(). Thus |
| @@ -142,12 +143,12 @@ | |
| 143 | ** |
| 144 | ** User has "h" auto-hyperlink Returned anchor format |
| 145 | ** ------------ -------------- ---------------------- |
| 146 | ** 0 0 (empty string) |
| 147 | ** 1 0 <a href="URL"> |
| 148 | ** 0 1 <a data-href="URL"> |
| 149 | ** 1 1 <a href="URL"> |
| 150 | ** |
| 151 | ** The name of these routines are deliberately kept short so that can be |
| 152 | ** easily used within @-lines. Example: |
| 153 | ** |
| 154 | ** @ %z(href("%R/artifact/%s",zUuid))%h(zFN)</a> |
| @@ -1375,10 +1376,11 @@ | |
| 1376 | @ g.zTop = %h(g.zTop)<br /> |
| 1377 | @ g.zPath = %h(g.zPath)<br /> |
| 1378 | @ g.userUid = %d(g.userUid)<br /> |
| 1379 | @ g.zLogin = %h(g.zLogin)<br /> |
| 1380 | @ g.isHuman = %d(g.isHuman)<br /> |
| 1381 | @ g.javascriptHyperlink = %d(g.javascriptHyperlink)<br /> |
| 1382 | if( g.nRequest ){ |
| 1383 | @ g.nRequest = %d(g.nRequest)<br /> |
| 1384 | } |
| 1385 | if( g.nPendingRequest>1 ){ |
| 1386 | @ g.nPendingRequest = %d(g.nPendingRequest)<br /> |
| 1387 |