33use CrowdSecBouncer \Bouncer ;
44use CrowdSecBouncer \Constants ;
55
6- // Captcha repeat delay in seconds
7- define ('CROWDSEC_CAPTCHA_REPEAT_MIN_DELAY ' , 15 * 60 ); // TODO P3 Dynamize this value
8-
96
107function bounceCurrentIp ()
118{
129 $ ip = $ _SERVER ["REMOTE_ADDR " ];
1310
14- function displayCaptchaPage ( $ ip , $ error = false )
11+ function displayCaptchaWall ( )
1512 {
16- if (!isset ($ _SESSION ['phrase ' ])) {
17- $ captchaCouple = Bouncer::buildCaptchaCouple ();
18- $ _SESSION ['phrase ' ] = $ captchaCouple ['phrase ' ];
19- $ _SESSION ['img ' ] = $ captchaCouple ['inlineImage ' ];
20- }
21- $ captchaImageSrc = $ _SESSION ['img ' ];
22- $ captchaResolutionFormUrl = '' ;
23- echo Bouncer::getCaptchaHtmlTemplate ($ error , $ captchaImageSrc , $ captchaResolutionFormUrl );
13+ header ('HTTP/1.0 401 Unauthorized ' );
14+ echo Bouncer::getCaptchaHtmlTemplate ($ _SESSION ["crowdsec_captcha_resolution_failed " ], $ _SESSION ['crowdsec_captcha_inline_image ' ], '' );
2415 die ();
2516 }
2617
27- function handleBanRemediation (Bouncer $ bouncer , $ ip )
18+ function handleBanRemediation ()
2819 {
29- // TODO P3 make a function instead of this
3020 header ('HTTP/1.0 403 Forbidden ' );
3121 echo Bouncer::getAccessForbiddenHtmlTemplate ();
3222 die ();
3323 }
3424
35- function checkCaptcha ( string $ ip )
25+ function storeNewCaptchaCoupleInSession ( )
3626 {
37- //error_log("crowdsec-wp: " . $ip . " is in captcha mode"); TODO P2 check how
27+ $ captchaCouple = Bouncer::buildCaptchaCouple ();
28+ $ _SESSION ['crowdsec_captcha_phrase_to_guess ' ] = $ captchaCouple ['phrase ' ];
29+ $ _SESSION ['crowdsec_captcha_inline_image ' ] = $ captchaCouple ['inlineImage ' ];
30+ }
3831
39- if ($ _SERVER ['REQUEST_METHOD ' ] === 'POST ' && isset ($ _POST ['crowdsec_captcha ' ])) {
32+ function clearCaptchaSessionContext ()
33+ {
34+ unset($ _SESSION ['crowdsec_captcha_has_to_be_resolved ' ]);
35+ unset($ _SESSION ['crowdsec_captcha_phrase_to_guess ' ]);
36+ unset($ _SESSION ['crowdsec_captcha_inline_image ' ]);
37+ unset($ _SESSION ['crowdsec_captcha_resolution_failed ' ]);
38+ }
4039
41- // Handle image refresh.
42- $ refreshImage = (isset ($ _POST ['refresh ' ]) && (bool )(int )$ _POST ['refresh ' ]);
40+ function handleCaptchaResolutionForm (string $ ip )
41+ {
42+ // Early return if no captcha has to be resolved.
43+ if (!isset ($ _SESSION ["crowdsec_captcha_has_to_be_resolved " ])) {
44+ return ;
45+ }
4346
44- if ($ refreshImage ) {
45- // generate new image
46- $ captchaCouple = Bouncer::buildCaptchaCouple ();
47- $ _SESSION ['phrase ' ] = $ captchaCouple ['phrase ' ];
48- $ _SESSION ['img ' ] = $ captchaCouple ['inlineImage ' ];
47+ // Captcha already resolved.
48+ if (!$ _SESSION ["crowdsec_captcha_has_to_be_resolved " ]) {
49+ return ;
50+ }
4951
50- // display captcha page
51- $ _SESSION [ " captchaResolved " ] = false ;
52- displayCaptchaPage ( $ ip , true ) ;
53- }
52+ // Early return if no form captcha form has been filled.
53+ if (( $ _SERVER [ ' REQUEST_METHOD ' ] !== ' POST ' || ! isset ( $ _POST [ ' crowdsec_captcha ' ]))) {
54+ return ;
55+ }
5456
57+ // Handle image refresh.
58+ if (isset ($ _POST ['refresh ' ]) && (bool )(int )$ _POST ['refresh ' ]) {
59+ // Generate new captcha image for the user
60+ storeNewCaptchaCoupleInSession ();
61+ $ _SESSION ["crowdsec_captcha_resolution_failed " ] = false ;
62+ return ;
63+ }
5564
56- // Handle captcha resolve.
65+ // Handle a captcha resolution try
66+ if (isset ($ _POST ['phrase ' ])) {
5767 $ bouncer = getBouncerInstance ();
58- $ captchaCorrectlyFilled = (isset ($ _POST ['phrase ' ]) && $ bouncer ->checkCaptcha ($ _SESSION ['phrase ' ], $ _POST ['phrase ' ], $ ip ));
59- if ($ captchaCorrectlyFilled ) {
60- $ _SESSION ["captchaResolved " ] = true ;
61- $ _SESSION ["captchaResolvedAt " ] = time ();
62- unset($ _SESSION ['phrase ' ]);
63- return ;
68+ if ($ bouncer ->checkCaptcha ($ _SESSION ['crowdsec_captcha_phrase_to_guess ' ], $ _POST ['phrase ' ], $ ip )) {
69+
70+ // User has correctly fill the captcha
71+
72+ $ _SESSION ["crowdsec_captcha_has_to_be_resolved " ] = false ;
73+ unset($ _SESSION ['crowdsec_captcha_phrase_to_guess ' ]);
74+ unset($ _SESSION ['crowdsec_captcha_inline_image ' ]);
75+ unset($ _SESSION ['crowdsec_captcha_resolution_failed ' ]);
76+ } else {
77+
78+ // The user failed to resolve the captcha.
79+
80+ $ _SESSION ["crowdsec_captcha_resolution_failed " ] = true ;
6481 }
6582 }
66- $ _SESSION ["captchaResolved " ] = false ;
67- displayCaptchaPage ($ ip , true );
6883 }
6984
70- function handleCaptchaRemediation (string $ ip )
85+ function handleCaptchaRemediation ($ ip )
7186 {
72- // Never displayed to user.
73- if (!isset ($ _SESSION ["captchaResolved " ])) {
74- displayCaptchaPage ($ ip );
75- }
76- // User was unable to resolve.
77- if (!$ _SESSION ["captchaResolved " ]) {
78- displayCaptchaPage ($ ip );
79- }
8087
88+ // Check captcha resolution form
89+ handleCaptchaResolutionForm ($ ip );
8190
82- // User resolved too long ago.
83- $ resolvedTooLongAgo = ((time () - $ _SESSION ["captchaResolvedAt " ]) > CROWDSEC_CAPTCHA_REPEAT_MIN_DELAY );
84- if ($ resolvedTooLongAgo ) {
85- displayCaptchaPage ($ ip );
91+ if (!isset ($ _SESSION ["crowdsec_captcha_has_to_be_resolved " ])) {
92+
93+ // Setup the first captcha remediation.
94+
95+ storeNewCaptchaCoupleInSession ();
96+ $ _SESSION ["crowdsec_captcha_has_to_be_resolved " ] = true ;
97+ $ _SESSION ["crowdsec_captcha_resolution_failed " ] = false ;
98+ }
99+
100+ // Display captcha page if this is required.
101+ if ($ _SESSION ["crowdsec_captcha_has_to_be_resolved " ]) {
102+ displayCaptchaWall ();
86103 }
87104 }
88105
89- function handleRemediation (string $ remediation , string $ ip, Bouncer $ bouncer )
106+ function handleRemediation (string $ remediation , string $ ip )
90107 {
108+ if ($ remediation !== Constants::REMEDIATION_CAPTCHA && isset ($ _SESSION ["crowdsec_captcha_has_to_be_resolved " ])) {
109+ clearCaptchaSessionContext ();
110+ }
91111 switch ($ remediation ) {
92112 case Constants::REMEDIATION_BYPASS :
93113 return ;
94114 case Constants::REMEDIATION_CAPTCHA :
95115 handleCaptchaRemediation ($ ip );
96116 break ;
97117 case Constants::REMEDIATION_BAN :
98- handleBanRemediation ($ bouncer , $ ip );
118+ handleBanRemediation ();
99119 }
100120 }
101121
102- // Control Captcha
103- if (isset ($ _SESSION ['phrase ' ])) {
104- checkCaptcha ($ ip );
105- }
106-
107122 $ bouncingLevel = esc_attr (get_option ("crowdsec_bouncing_level " ));
108123 $ shouldBounce = ($ bouncingLevel !== CROWDSEC_BOUNCING_LEVEL_DISABLED );
109124
110125 if ($ shouldBounce ) {
111126 try {
112127 $ bouncer = getBouncerInstance ();
113128 $ remediation = $ bouncer ->getRemediationForIp ($ ip );
114- handleRemediation ($ remediation , $ ip, $ bouncer );
129+ handleRemediation ($ remediation , $ ip );
115130 } catch (WordpressCrowdSecBouncerException $ e ) {
116131 // TODO log error for debug mode only.
117132 }
@@ -138,7 +153,6 @@ function safelyBounceCurrentIp()
138153 bounceCurrentIp ();
139154 }
140155 restore_error_handler ();
141-
142156 } catch (\Exception $ e ) {
143157 getCrowdSecLoggerInstance ()->error (null , [
144158 'type ' => 'WP_EXCEPTION_WHILE_BOUNCING ' ,
0 commit comments