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 ( '& ' , '& ' , $ 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+ }
0 commit comments