Completed
Push — renovate/babel-eslint-10.x ( cb89d5...6fd2a7 )
by
unknown
25:23 queued 18:32
created

Jetpack_Protect_Math_Authenticate::math_form()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
nc 3
nop 0
dl 0
loc 32
rs 9.408
c 0
b 0
f 0
1
<?php
2
3
if ( ! class_exists( 'Jetpack_Protect_Math_Authenticate' ) ) {
4
	/*
5
	 * The math captcha fallback if we can't talk to the Protect API
6
	 */
7
	class Jetpack_Protect_Math_Authenticate {
8
9
		static $loaded;
10
11
		function __construct() {
12
13
			if ( self::$loaded ) {
14
				return;
15
			}
16
17
			self::$loaded = 1;
18
19
			add_action( 'login_form', array( $this, 'math_form' ) );
20
21
			if( isset( $_POST[ 'jetpack_protect_process_math_form' ] ) ) {
22
				add_action( 'init', array( $this, 'process_generate_math_page' ) );
23
			}
24
		}
25
26
		private static function time_window() {
27
			return ceil( time() / ( MINUTE_IN_SECONDS * 2 ) );
28
		}
29
30
		/**
31
		 * Verifies that a user answered the math problem correctly while logging in.
32
		 *
33
		 * @return bool Returns true if the math is correct
34
		 * @throws Error if insuffient $_POST variables are present.
35
		 * @throws Error message if the math is wrong
36
		 */
37
		static function math_authenticate() {
38
			if( isset( $_COOKIE[ 'jpp_math_pass' ] ) ) {
39
				$jetpack_protect = Jetpack_Protect_Module::instance();
40
				$transient = $jetpack_protect->get_transient( 'jpp_math_pass_' . $_COOKIE[ 'jpp_math_pass' ] );
41
42
				if( !$transient || $transient < 1 ) {
43
					Jetpack_Protect_Math_Authenticate::generate_math_page();
44
				}
45
				return true;
46
			}
47
48
			$ans         = isset( $_POST['jetpack_protect_num'] ) ? (int) $_POST['jetpack_protect_num'] : '' ;
49
			$correct_ans = isset( $_POST[ 'jetpack_protect_answer' ] ) ? $_POST[ 'jetpack_protect_answer' ] : '' ;
50
51
			$time_window  = Jetpack_Protect_Math_Authenticate::time_window();
52
			$salt         = get_site_option( 'jetpack_protect_key' ) . '|' . get_site_option( 'admin_email' ) . '|';
53
			$salted_ans_1 = hash_hmac( 'sha1', $ans, $salt . $time_window );
54
			$salted_ans_2 = hash_hmac( 'sha1', $ans, $salt . ( $time_window - 1 ) );
55
56
			if ( ! $correct_ans || ! $ans ) {
57
				Jetpack_Protect_Math_Authenticate::generate_math_page();
58
			} elseif ( ! hash_equals( $salted_ans_1, $correct_ans ) && ! hash_equals( $salted_ans_2, $correct_ans ) ) {
59
				wp_die(
60
				__( '<strong>You failed to correctly answer the math problem.</strong>  This is used to combat spam when the Protect API is unavailable.  Please use your browser\'s back button to return to the login form, press the "refresh" button to generate a new math problem, and try to log in again.', 'jetpack' ),
61
				'',
62
				array ( 'response' => 401 )
63
				);
64
			} else {
65
				return true;
66
			}
67
		}
68
69
		/**
70
		 * Creates an interim page to collect answers to a math captcha
71
		 *
72
		 * @return none, execution stopped
0 ignored issues
show
Documentation introduced by
The doc-type none, could not be parsed: Expected "|" or "end of type", but got "," at position 4. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
73
		 */
74
		static function generate_math_page( $error = false ) {
75
			ob_start();
76
			?>
77
			<h2><?php esc_html_e( 'Please solve this math problem to prove that you are not a bot.  Once you solve it, you will need to log in again.', 'jetpack' ); ?></h2>
78
			<?php if ($error): ?>
79
				<h3><?php esc_html_e( 'Your answer was incorrect, please try again.', 'jetpack' ); ?></h3>
80
			<?php endif ?>
81
82
			<form action="<?php echo wp_login_url(); ?>" method="post" accept-charset="utf-8">
83
				<?php Jetpack_Protect_Math_Authenticate::math_form(); ?>
84
				<input type="hidden" name="jetpack_protect_process_math_form" value="1" id="jetpack_protect_process_math_form" />
85
				<p><input type="submit" value="<?php esc_attr_e( 'Continue &rarr;', 'jetpack' ); ?>"></p>
86
			</form>
87
		<?php
88
			$mathpage = ob_get_contents();
89
			ob_end_clean();
90
			wp_die(
91
				$mathpage,
92
				'',
93
				array ( 'response' => 401 )
94
			);
95
		}
96
97
		public function process_generate_math_page() {
98
			$ans         = isset( $_POST['jetpack_protect_num'] ) ? (int)$_POST['jetpack_protect_num'] : '';
99
			$correct_ans = isset( $_POST[ 'jetpack_protect_answer' ] ) ? $_POST[ 'jetpack_protect_answer' ] : '' ;
100
101
			$time_window  = Jetpack_Protect_Math_Authenticate::time_window();
102
			$salt         = get_site_option( 'jetpack_protect_key' ) . '|' . get_site_option( 'admin_email' ) . '|';
103
			$salted_ans_1 = hash_hmac( 'sha1', $ans, $salt . $time_window );
104
			$salted_ans_2 = hash_hmac( 'sha1', $ans, $salt . ( $time_window - 1 ) );
105
106
			if ( ! hash_equals( $salted_ans_1, $correct_ans ) && ! hash_equals( $salted_ans_2, $correct_ans ) ) {
107
				Jetpack_Protect_Math_Authenticate::generate_math_page(true);
108
			} else {
109
				$temp_pass = substr( hash_hmac( 'sha1', rand( 1, 100000000 ), get_site_option( 'jetpack_protect_key' ) ), 5, 25 );
110
111
				$jetpack_protect = Jetpack_Protect_Module::instance();
112
				$jetpack_protect->set_transient( 'jpp_math_pass_' . $temp_pass, 3, DAY_IN_SECONDS );
113
				setcookie('jpp_math_pass', $temp_pass, time() + DAY_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN, false);
114
				remove_action( 'login_form', array( $this, 'math_form' ) );
115
				return true;
116
			}
117
		}
118
119
		/**
120
		 * Requires a user to solve a simple equation. Added to any WordPress login form.
121
		 *
122
		 * @return VOID outputs html
123
		 */
124
		static function math_form() {
125
			// Check if jpp_math_pass cookie is set and it matches valid transient
126
			if( isset( $_COOKIE[ 'jpp_math_pass' ] ) ) {
127
				$jetpack_protect = Jetpack_Protect_Module::instance();
128
				$transient = $jetpack_protect->get_transient( 'jpp_math_pass_' . $_COOKIE[ 'jpp_math_pass' ] );
129
130
				if( $transient && $transient > 0 ) {
131
					return '';
132
				}
133
			}
134
135
			$num1 = rand( 0, 10 );
136
			$num2 = rand( 1, 10 );
137
			$ans  = $num1 + $num2;
138
139
			$time_window = Jetpack_Protect_Math_Authenticate::time_window();
140
			$salt        = get_site_option( 'jetpack_protect_key' ) . '|' . get_site_option( 'admin_email' ) . '|';
141
			$salted_ans  = hash_hmac( 'sha1', $ans, $salt . $time_window );
142
			?>
143
			<div style="margin: 5px 0 20px;">
144
				<label for="jetpack_protect_answer">
145
					<?php esc_html_e( 'Prove your humanity', 'jetpack' ); ?>
146
				</label>
147
				<br/>
148
				<span style="vertical-align:super;">
149
					<?php echo esc_html( "$num1 &nbsp; + &nbsp; $num2 &nbsp; = &nbsp;" ); ?>
150
				</span>
151
				<input type="text" id="jetpack_protect_answer" name="jetpack_protect_num" value="" size="2" style="width:30px;height:25px;vertical-align:middle;font-size:13px;" class="input" />
152
				<input type="hidden" name="jetpack_protect_answer" value="<?php echo esc_attr( $salted_ans ); ?>" />
153
			</div>
154
		<?php
155
		}
156
157
	}
158
}
159