Skip to content

Commit 2562b7e

Browse files
committed
Duplicate the WordPress nonce api
Use the mpt_ for the functions names Add to the api the simple methods, use the static class Use the mpt functions in the templates and methods for the built-in forms
1 parent 9741ae6 commit 2562b7e

14 files changed

+482
-140
lines changed

classes/helpers/class-nonces.php

Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
<?php
2+
class MPT_Nonces {
3+
4+
/**
5+
* Get the time-dependent variable for nonce creation.
6+
*
7+
* A nonce has a lifespan of two ticks. Nonces in their second tick may be
8+
* updated, e.g. by autosave.
9+
*
10+
* @since 0.6.0
11+
*
12+
* @return float Float value rounded up to the next highest integer.
13+
*/
14+
public static function nonce_tick() {
15+
/**
16+
* Filter the lifespan of nonces in seconds.
17+
*
18+
* @since 0.6.0
19+
*
20+
* @param int $lifespan Lifespan of nonces in seconds. Default 86,400 seconds, or one day.
21+
*/
22+
$nonce_life = apply_filters( 'mpt_nonce_life', DAY_IN_SECONDS );
23+
24+
return ceil(time() / ( $nonce_life / 2 ));
25+
}
26+
27+
/**
28+
* Verify that correct nonce was used with time limit.
29+
*
30+
* The user is given an amount of time to use the token, so therefore, since the
31+
* UID and $action remain the same, the independent variable is the time.
32+
*
33+
* @since 0.6.0
34+
*
35+
* @param string $nonce Nonce that was used in the form to verify
36+
* @param string|int $action Should give context to what is taking place and be the same when nonce was created.
37+
* @return bool Whether the nonce check passed or failed.
38+
*/
39+
public static function verify_nonce( $nonce, $action = -1 ) {
40+
$nonce = (string) $nonce;
41+
$member = mpt_get_current_member();
42+
$mid = !is_a( $member, 'MPT_Member' ) ? 0 : (int) $member->id;
43+
if ( ! $mid ) {
44+
/**
45+
* Filter whether the user who generated the nonce is logged out.
46+
*
47+
* @since 0.6.0
48+
*
49+
* @param int $mid ID of the nonce-owning member.
50+
* @param string $action The nonce action.
51+
*/
52+
$mid = apply_filters( 'nonce_mpt_logged_out', $mid, $action );
53+
}
54+
55+
if ( empty( $nonce ) ) {
56+
return false;
57+
}
58+
59+
$token = self::get_session_token();
60+
$i = self::nonce_tick();
61+
62+
// Nonce generated 0-12 hours ago
63+
$expected = substr( wp_hash( 'member-'.$i . '|' . $action . '|' . $mid . '|' . $token, 'nonce'), -12, 10 );
64+
if ( hash_equals( $expected, $nonce ) ) {
65+
return 1;
66+
}
67+
68+
// Nonce generated 12-24 hours ago
69+
$expected = substr( wp_hash( 'member-'.( $i - 1 ) . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 );
70+
if ( hash_equals( $expected, $nonce ) ) {
71+
return 2;
72+
}
73+
74+
// Invalid nonce
75+
return false;
76+
}
77+
78+
/**
79+
* @param int $action
80+
*
81+
* @return string
82+
* @author Nicolas Juen
83+
*/
84+
public static function create_nonce($action = -1) {
85+
$member = mpt_get_current_member();
86+
$mid = !is_a( $member, 'MPT_Member' ) ? 0 : (int) $member->id;
87+
if ( ! $mid ) {
88+
$mid = apply_filters( 'nonce_mpt_logged_out', $mid, $action );
89+
}
90+
91+
$token = self::get_session_token();
92+
$i = self::nonce_tick();
93+
94+
return substr( wp_hash( 'member-'.$i . '|' . $action . '|' . $mid . '|' . $token, 'nonce' ), -12, 10 );
95+
}
96+
97+
/**
98+
* Retrieve URL with nonce added to URL query.
99+
*
100+
* @since 0.6.0
101+
*
102+
* @param string $actionurl URL to add nonce action.
103+
* @param int|string $action Optional. Nonce action name. Default -1.
104+
* @param string $name Optional. Nonce name. Default '_mptnonce'.
105+
* @return string Escaped URL with nonce action added.
106+
*/
107+
public static function nonce_url( $actionurl, $action = -1, $name = '_mptnonce' ) {
108+
$actionurl = str_replace( '&amp;', '&', $actionurl );
109+
return esc_html( add_query_arg( $name, self::create_nonce( $action ), $actionurl ) );
110+
}
111+
112+
/**
113+
* Retrieve or display nonce hidden field for forms.
114+
*
115+
* The nonce field is used to validate that the contents of the form came from
116+
* the location on the current site and not somewhere else. The nonce does not
117+
* offer absolute protection, but should protect against most cases. It is very
118+
* important to use nonce field in forms.
119+
*
120+
* The $action and $name are optional, but if you want to have better security,
121+
* it is strongly suggested to set those two parameters. It is easier to just
122+
* call the function without any parameters, because validation of the nonce
123+
* doesn't require any parameters, but since crackers know what the default is
124+
* it won't be difficult for them to find a way around your nonce and cause
125+
* damage.
126+
*
127+
* The input name will be whatever $name value you gave. The input value will be
128+
* the nonce creation value.
129+
*
130+
* @since 0.6.0
131+
*
132+
* @param int|string $action Optional. Action name. Default -1.
133+
* @param string $name Optional. Nonce name. Default '_mptnonce'.
134+
* @param bool $referrer Optional. Whether to set the referrer field for validation. Default true.
135+
* @param bool $echo Optional. Whether to display or return hidden form field. Default true.
136+
* @return string Nonce field HTML markup.
137+
*/
138+
public static function nonce_field( $action = -1, $name = "_mptnonce", $referrer = true , $echo = true ) {
139+
$name = esc_attr( $name );
140+
$nonce_field = '<input type="hidden" id="' . $name . '" name="' . $name . '" value="' . self::create_nonce( $action ) . '" />';
141+
142+
if ( $referrer ) {
143+
$nonce_field .= self::referrer_field( false );
144+
}
145+
146+
if ( $echo ) {
147+
echo $nonce_field;
148+
}
149+
150+
return $nonce_field;
151+
}
152+
153+
/**
154+
* Retrieve or display referrer hidden field for forms.
155+
*
156+
* The referrer link is the current Request URI from the server super global. The
157+
* input name is '_mpt_http_referrer', in case you wanted to check manually.
158+
*
159+
* @since 0.6.0
160+
*
161+
* @param bool $echo Optional. Whether to echo or return the referrer field. Default true.
162+
* @return string referrer field HTML markup.
163+
*/
164+
public static function referrer_field( $echo = true ) {
165+
$referrer_field = '<input type="hidden" name="_mpt_http_referrer" value="'. esc_attr( wp_unslash( $_SERVER['REQUEST_URI'] ) ) . '" />';
166+
167+
if ( $echo ) {
168+
echo $referrer_field;
169+
}
170+
return $referrer_field;
171+
}
172+
173+
/**
174+
* Retrieve or display original referrer hidden field for forms.
175+
*
176+
* The input name is '_mpt_original_http_referrer' and will be either the same
177+
* value of self::referrer_field(), if that was posted already or it will be the
178+
* current page, if it doesn't exist.
179+
*
180+
* @since 0.6.0
181+
*
182+
* @param bool $echo Optional. Whether to echo the original http referrer. Default true.
183+
* @param string $jump_back_to Optional. Can be 'previous' or page you want to jump back to.
184+
* Default 'current'.
185+
* @return string Original referrer field.
186+
*/
187+
public static function original_referrer_field( $echo = true, $jump_back_to = 'current' ) {
188+
if ( ! $ref = self::get_original_referrer() ) {
189+
$ref = 'previous' == $jump_back_to ? self::get_referrer() : wp_unslash( $_SERVER['REQUEST_URI'] );
190+
}
191+
$orig_referrer_field = '<input type="hidden" name="_mpt_original_http_referrer" value="' . esc_attr( $ref ) . '" />';
192+
if ( $echo ) {
193+
echo $orig_referrer_field;
194+
}
195+
return $orig_referrer_field;
196+
}
197+
198+
/**
199+
* Retrieve referrer from '_mpt_http_referrer' or HTTP referrer.
200+
*
201+
* If it's the same as the current request URL, will return false.
202+
*
203+
* @since 0.6.0
204+
*
205+
* @return false|string False on failure. referrer URL on success.
206+
*/
207+
public static function get_referrer() {
208+
209+
$ref = false;
210+
if ( ! empty( $_REQUEST['_mpt_http_referrer'] ) ) {
211+
$ref = wp_unslash( $_REQUEST['_mpt_http_referrer'] );
212+
} else if ( ! empty( $_SERVER['HTTP_referrer'] ) ) {
213+
$ref = wp_unslash( $_SERVER['HTTP_referrer'] );
214+
}
215+
216+
if ( $ref && $ref !== wp_unslash( $_SERVER['REQUEST_URI'] ) ) {
217+
return wp_validate_redirect( $ref, false );
218+
}
219+
220+
return false;
221+
}
222+
223+
/**
224+
* Retrieve original referrer that was posted, if it exists.
225+
*
226+
* @since 0.6.0
227+
*
228+
* @return string|false False if no original referrer or original referrer if set.
229+
*/
230+
public static function get_original_referrer() {
231+
if ( ! empty( $_REQUEST['_wp_original_http_referrer'] ) ) {
232+
return wp_validate_redirect( wp_unslash( $_REQUEST['_mpt_original_http_referrer'] ), false );
233+
}
234+
return false;
235+
}
236+
237+
/**
238+
* Retrieve the current session token from the logged_in cookie.
239+
*
240+
* @since 0.6.0
241+
*
242+
* @return string Token.
243+
* @author Nicolas Juen
244+
*/
245+
public static function get_session_token() {
246+
$cookie = MPT_Member_Auth::parse_auth_cookie( '', 'logged_in' );
247+
return ! empty( $cookie['token'] ) ? $cookie['token'] : '';
248+
}
249+
}

classes/shortcodes/class-shortcode-change-password.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ public static function init() {
3838
$_POST['mptchangepwd'] = stripslashes_deep($_POST['mptchangepwd']);
3939

4040
// Check _NONCE
41-
$nonce = isset($_POST['_wpnonce']) ? $_POST['_wpnonce'] : '';
42-
if ( !wp_verify_nonce($nonce, 'mptchangepwd') ) {
41+
$nonce = isset($_POST['_mptnonce']) ? $_POST['_mptnonce'] : '';
42+
if ( !mpt_verify_nonce($nonce, 'mptchangepwd') ) {
4343
parent::set_message( 'check-nonce', 'Security check failed', 'error' );
4444
return false;
4545
}

classes/shortcodes/class-shortcode-login.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ public static function init() {
4141
$_POST['mptlogin'] = stripslashes_deep($_POST['mptlogin']);
4242

4343
// Check _NONCE
44-
$nonce = isset($_POST['_wpnonce']) ? $_POST['_wpnonce'] : '';
45-
if ( !wp_verify_nonce($nonce, 'mptlogin') ) {
44+
$nonce = isset($_POST['_mptnonce']) ? $_POST['_mptnonce'] : '';
45+
if ( !mpt_verify_nonce($nonce, 'mptlogin') ) {
4646
parent::set_message( 'check-nonce', 'Security check failed', 'error' );
4747
return false;
4848
}

classes/shortcodes/class-shortcode-lost-password.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ public static function check_step_1() {
5252
$_POST['mptlostpwd_s1'] = stripslashes_deep( $_POST['mptlostpwd_s1'] );
5353

5454
// Check _NONCE
55-
$nonce = isset( $_POST['_wpnonce'] ) ? $_POST['_wpnonce'] : '';
56-
if ( !wp_verify_nonce( $nonce, 'mptlostpwd_s1' ) ) {
55+
$nonce = isset( $_POST['_mptnonce'] ) ? $_POST['_mptnonce'] : '';
56+
if ( !mpt_verify_nonce( $nonce, 'mptlostpwd_s1' ) ) {
5757
parent::set_message( 'check-nonce', 'Security check failed', 'error' );
5858
return false;
5959
}
@@ -132,8 +132,8 @@ public static function check_step_2_url() {
132132
public static function check_step_2_form() {
133133
if ( isset( $_POST['mptlostpwd_s2'] ) ) {
134134
// Check _NONCE
135-
$nonce = isset( $_POST['_wpnonce'] ) ? $_POST['_wpnonce'] : '';
136-
if ( !wp_verify_nonce( $nonce, 'mptlostpwd_s2' ) ) {
135+
$nonce = isset( $_POST['_mptnonce'] ) ? $_POST['_mptnonce'] : '';
136+
if ( !mpt_verify_nonce( $nonce, 'mptlostpwd_s2' ) ) {
137137
parent::set_message( 'check-nonce', 'Security check failed', 'error' );
138138
return false;
139139
}

0 commit comments

Comments
 (0)