1
|
|
|
<?php |
2
|
|
|
// don't call the file directly |
3
|
|
|
defined( 'ABSPATH' ) or die(); |
4
|
|
|
|
5
|
|
|
class VaultPress_Hotfixes { |
6
|
|
|
function __construct() { |
7
|
|
|
global $wp_version; |
8
|
|
|
|
9
|
|
|
if ( version_compare( $wp_version, '3.0.2', '<' ) ) |
10
|
|
|
add_filter( 'query', array( $this, 'r16625' ) ); |
11
|
|
|
|
12
|
|
|
if ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST && version_compare( $wp_version, '4.3.1', '<' ) ) |
13
|
|
|
add_action( 'xmlrpc_call', array( $this, 'filter_xmlrpc_methods' ) ); |
14
|
|
|
|
15
|
|
|
if ( version_compare( $wp_version, '3.3.2', '<' ) ) { |
16
|
|
|
add_filter( 'pre_kses', array( $this, 'r17172_wp_kses' ), 1, 3 ); |
17
|
|
|
add_filter( 'clean_url', array( $this, 'r17172_esc_url' ), 1, 3 ); |
18
|
|
|
} |
19
|
|
|
|
20
|
|
|
if ( version_compare( $wp_version, '3.1.3', '<' ) ) { |
21
|
|
|
add_filter( 'sanitize_file_name', array( $this, 'r17990' ) ); |
22
|
|
|
|
23
|
|
|
if ( ! empty( $_POST ) ) { |
24
|
|
|
$this->r17994( $_POST ); |
25
|
|
|
} |
26
|
|
|
// Protect add_meta, update_meta used by the XML-RPC API. |
27
|
|
|
add_filter( 'wp_xmlrpc_server_class', 'r17994_xmlrpc_server' ); |
28
|
|
|
|
29
|
|
|
// clean post_mime_type and guid (r17994) |
30
|
|
|
add_filter( 'pre_post_mime_type', array( $this, 'r17994_sanitize_mime_type' ) ); |
31
|
|
|
add_filter( 'post_mime_type', array( $this, 'r17994_sanitize_mime_type' ) ); |
32
|
|
|
add_filter( 'pre_post_guid', 'esc_url_raw' ); |
33
|
|
|
add_filter( 'post_guid', 'esc_url' ); |
34
|
|
|
} |
35
|
|
|
|
36
|
|
|
if ( version_compare( $wp_version, '3.1.4', '<' ) ) { |
37
|
|
|
add_filter( 'wp_insert_post_data', array( $this, 'r18368' ), 1, 2 ); |
38
|
|
|
|
39
|
|
|
// Add click jacking protection |
40
|
|
|
// login_init does not exist before 17826. |
41
|
|
|
$action = isset( $_REQUEST['action'] ) ? $_REQUEST['action'] : 'login'; |
42
|
|
|
add_action( 'login_form_' . $action, array( $this, 'r17826_send_frame_options_header' ), 10, 0 ); |
43
|
|
|
add_action( 'admin_init', array( $this, 'r17826_send_frame_options_header' ), 10, 0 ); |
44
|
|
|
|
45
|
|
|
add_filter( 'sanitize_option_WPLANG', array( $this, 'r18346_sanitize_lang_on_save' ) ); |
46
|
|
|
add_filter( 'sanitize_option_new_admin_email', array( $this, 'r18346_sanitize_admin_email_on_save' ) ); |
47
|
|
|
} |
48
|
|
|
add_filter( 'option_new_admin_email', array( $this, 'r18346_sanitize_admin_email' ) ); |
49
|
|
|
|
50
|
|
|
if ( version_compare( $wp_version, '3.3.2', '<' ) ) { |
51
|
|
|
remove_filter( 'comment_text', 'make_clickable' ); |
52
|
|
|
add_filter( 'comment_text', array( $this, 'r20493_make_clickable' ), 9 ); |
53
|
|
|
|
54
|
|
|
add_filter( 'comment_post_redirect', array( $this, 'r20486_comment_post_redirect' ) ); |
55
|
|
|
} |
56
|
|
|
|
57
|
|
|
// WooThemes < 3.8.3, foxypress, asset-manager, wordpress-member-private-conversation. |
58
|
|
|
$end_execution = false; |
59
|
|
|
if ( isset( $_SERVER['SCRIPT_FILENAME'] ) ) |
60
|
|
|
foreach ( array( 'preview-shortcode-external.php', 'uploadify.php', 'doupload.php', 'cef-upload.php', 'upload.php' ) as $vulnerable_script ) { |
61
|
|
|
if ( $vulnerable_script == basename( $_SERVER['SCRIPT_FILENAME'] ) ) { |
62
|
|
|
switch ( $vulnerable_script ) { |
63
|
|
|
case 'upload.php': |
64
|
|
|
$pma_config_file = realpath( dirname( $_SERVER['SCRIPT_FILENAME'] ) . DIRECTORY_SEPARATOR . 'paam-config-ajax.php' ); |
65
|
|
|
if ( false === $pma_config_file || ! in_array( $pma_config_file, get_included_files() ) ) { |
66
|
|
|
break; |
67
|
|
|
} |
68
|
|
|
default: |
69
|
|
|
$end_execution = true; |
70
|
|
|
break 2; |
71
|
|
|
} |
72
|
|
|
} |
73
|
|
|
} |
74
|
|
|
if ( $end_execution ) |
75
|
|
|
die( 'Disabled for security reasons' ); |
76
|
|
|
|
77
|
|
|
if ( version_compare( $wp_version, '3.3.2', '>') && version_compare( $wp_version, '3.4.1', '<' ) ) { |
78
|
|
|
add_filter( 'map_meta_cap', array( $this, 'r21138_xmlrpc_edit_posts' ), 10, 4 ); |
79
|
|
|
add_action( 'map_meta_cap', array( $this, 'r21152_unfiltered_html' ), 10, 4 ); |
80
|
|
|
} |
81
|
|
|
|
82
|
|
|
// https://core.trac.wordpress.org/changeset/21083 |
83
|
|
|
if ( version_compare( $wp_version, '3.3', '>=') && version_compare( $wp_version, '3.3.3', '<' ) ) |
84
|
|
|
add_filter( 'editable_slug', 'esc_textarea' ); |
85
|
|
|
|
86
|
|
|
if ( version_compare( $wp_version, '4.1', '>=' ) && version_compare( $wp_version, '4.1.2', '<' ) ) |
87
|
|
|
add_filter( 'wp_check_filetype_and_ext', array( $this, 'wp_check_filetype_and_ext' ), 20, 4 ); |
88
|
|
|
|
89
|
|
|
if ( version_compare( $wp_version, '4.2', '<=' ) ) |
90
|
|
|
add_filter( 'preprocess_comment', array( $this, 'filter_long_comment_xss' ), 10, 1 ); |
91
|
|
|
|
92
|
|
|
add_filter( 'get_pagenum_link', array( $this, 'get_pagenum_link' ) ); |
93
|
|
|
|
94
|
|
|
add_filter( 'jetpack_xmlrpc_methods', array( $this, 'disable_jetpack_xmlrpc_methods_293' ), 20, 3 ); |
95
|
|
|
add_filter( 'xmlrpc_methods', array( $this, 'disable_xmlrpc_methods_293' ), 20 ); |
96
|
|
|
|
97
|
|
|
// Protect All-in-one SEO from non-authorized users making changes, and script injection attacks. |
98
|
|
|
add_action( 'wp_ajax_aioseop_ajax_save_meta', array( $this, 'protect_aioseo_ajax' ), 1 ); |
99
|
|
|
|
100
|
|
|
// Protect The MailPoet plugin (wysija-newsletters) from remote file upload. Affects versions <= 2.6.6 |
101
|
|
|
add_action( 'admin_init', array( $this , 'protect_wysija_newsletters_verify_capability' ), 1 ); |
102
|
|
|
|
103
|
|
|
// Protect the Revolution Slider plugin (revslider) from local file inclusion. Affects versions < 4.2 |
104
|
|
|
add_action( 'init', array( $this , 'protect_revslider_lfi' ), 1 ); |
105
|
|
|
|
106
|
|
|
// Protect WooCommerce from object injection via PayPal IPN notifications. Affects 2.0.20 -> 2.3.10 |
107
|
|
|
add_action( 'init', array( $this , 'protect_woocommerce_paypal_object_injection' ), 1 ); |
108
|
|
|
|
109
|
|
|
// Protect Jetpack from comments-based XSS attack |
110
|
|
|
add_action( 'plugins_loaded', array( $this, 'protect_jetpack_402_from_oembed_xss' ), 1 ); |
111
|
|
|
|
112
|
|
|
if ( version_compare( $wp_version, '3.1', '>=') && version_compare( $wp_version, '4.3', '<=' ) ) { |
113
|
|
|
if ( is_admin() ) { |
114
|
|
|
add_filter( 'user_email', array( $this, 'patch_user_email' ), 10 , 3 ); |
115
|
|
|
} |
116
|
|
|
|
117
|
|
|
remove_shortcode( 'wp_caption' ); |
118
|
|
|
remove_shortcode( 'caption' ); |
119
|
|
|
add_shortcode( 'wp_caption', array( $this, 'filtered_caption_shortcode' ) ); |
120
|
|
|
add_shortcode( 'caption', array( $this, 'filtered_caption_shortcode' ) ); |
121
|
|
|
} |
122
|
|
|
|
123
|
|
|
// Protect Akismet < 3.1.5 from stored XSS in admin page |
124
|
|
|
add_filter( 'init', array( $this, 'protect_akismet_comment_xss' ), 50 ); |
125
|
|
|
|
126
|
|
|
if ( version_compare( $wp_version, '4.7.1', '<=' ) ) { |
127
|
|
|
// Protect WordPress 4.4 - 4.7.1 against WP REST type abuse |
128
|
|
|
if ( version_compare( $wp_version, '4.4', '>=' ) ) { |
129
|
|
|
add_filter( 'rest_pre_dispatch', array( $this, 'protect_rest_type_juggling' ), 10, 3 ); |
130
|
|
|
} |
131
|
|
|
|
132
|
|
|
// Protect WordPress 4.0 - 4.7.1 against faulty youtube embeds |
133
|
|
|
if ( version_compare( $wp_version, '4.0', '>=' ) ) { |
134
|
|
|
$this->protect_youtube_embeds(); |
135
|
|
|
} |
136
|
|
|
} |
137
|
|
|
|
138
|
|
|
} |
139
|
|
|
|
140
|
|
|
function protect_rest_type_juggling( $replace, $server, $request ) { |
141
|
|
|
if ( isset( $request['id'] ) ) { |
142
|
|
|
$request['id'] = intval( $request['id'] ); |
143
|
|
|
} |
144
|
|
|
|
145
|
|
|
return $replace; |
146
|
|
|
} |
147
|
|
|
|
148
|
|
|
function protect_youtube_embeds() { |
149
|
|
|
if ( ! apply_filters( 'load_default_embeds', true ) ) { |
150
|
|
|
return; |
151
|
|
|
} |
152
|
|
|
|
153
|
|
|
wp_embed_unregister_handler( 'youtube_embed_url' ); |
154
|
|
|
wp_embed_register_handler( 'youtube_embed_url', '#https?://(www.)?youtube\.com/(?:v|embed)/([^/]+)#i', array( $this, 'safe_embed_handler_youtube' ), 9, 4 ); |
155
|
|
|
} |
156
|
|
|
|
157
|
|
|
function safe_embed_handler_youtube( $matches, $attr, $url, $rawattr ) { |
158
|
|
|
$matches[2] = urlencode( $matches[2] ); |
159
|
|
|
return( wp_embed_handler_youtube( $matches, $attr, $url, $rawattr ) ); |
160
|
|
|
} |
161
|
|
|
|
162
|
|
|
function protect_jetpack_402_from_oembed_xss() { |
163
|
|
|
if ( $this->needs_jetpack_402_fix() ) { |
164
|
|
|
add_filter( 'jetpack_comments_allow_oembed', array( $this, 'disable_jetpack_oembed' ) ); |
165
|
|
|
} |
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
function needs_jetpack_402_fix() { |
169
|
|
|
if ( ! defined( 'JETPACK__VERSION' ) ) { |
170
|
|
|
return false; |
171
|
|
|
} |
172
|
|
|
|
173
|
|
|
if ( version_compare( JETPACK__VERSION, '2.0.7', '<' ) ) { |
174
|
|
|
return true; |
175
|
|
|
} |
176
|
|
|
|
177
|
|
|
if ( version_compare( JETPACK__VERSION, '4.0.2', '>' ) ) { |
178
|
|
|
return false; |
179
|
|
|
} |
180
|
|
|
|
181
|
|
|
$secure_jetpacks = array( |
182
|
|
|
'2.1' => '2.1.5', |
183
|
|
|
'2.2' => '2.2.8', |
184
|
|
|
'2.3' => '2.3.8', |
185
|
|
|
'2.4' => '2.4.5', |
186
|
|
|
'2.5' => '2.5.3', |
187
|
|
|
'2.6' => '2.6.4', |
188
|
|
|
'2.7' => '2.7.3', |
189
|
|
|
'2.8' => '2.8.3', |
190
|
|
|
'2.9' => '2.9.4', |
191
|
|
|
'3.0' => '3.0.4', |
192
|
|
|
'3.1' => '3.1.3', |
193
|
|
|
'3.2' => '3.2.3', |
194
|
|
|
'3.3' => '3.3.4', |
195
|
|
|
'3.4' => '3.4.4', |
196
|
|
|
'3.5' => '3.5.4', |
197
|
|
|
'3.6' => '3.6.2', |
198
|
|
|
'3.7' => '3.7.3', |
199
|
|
|
'3.8' => '3.8.3', |
200
|
|
|
'3.9' => '3.9.7', |
201
|
|
|
'4.0' => '4.0.3', |
202
|
|
|
); |
203
|
|
|
|
204
|
|
|
$parts = explode( '.', JETPACK__VERSION, 3 ); |
205
|
|
|
if ( count( $parts ) < 2 ) { |
206
|
|
|
// no/not enough periods in the version; |
207
|
|
|
return false; |
208
|
|
|
} |
209
|
|
|
|
210
|
|
|
// pull out the first two components, cast to int to get rid of weird 'beta2' junk |
211
|
|
|
$int_parts = array(); |
212
|
|
|
$int_parts[0] = intval( $parts[0] ); |
213
|
|
|
$int_parts[1] = intval( $parts[1] ); |
214
|
|
|
|
215
|
|
|
// and find the secure version for this branch |
216
|
|
|
$branch = sprintf( '%d.%d', $int_parts[0], $int_parts[1] ); |
217
|
|
|
if ( ! isset( $secure_jetpacks[ $branch ] ) ) { |
218
|
|
|
return false; |
219
|
|
|
} |
220
|
|
|
return version_compare( JETPACK__VERSION, $secure_jetpacks[ $branch ], '<' ); |
221
|
|
|
} |
222
|
|
|
|
223
|
|
|
function disable_jetpack_oembed( $enabled ) { |
224
|
|
|
return false; |
225
|
|
|
} |
226
|
|
|
|
227
|
|
|
function filter_long_comment_xss( $commentdata ) { |
228
|
|
|
if ( strlen( $commentdata['comment_content'] ) > 65500 ) |
229
|
|
|
wp_die( 'Comment too long', 'Invalid comment' ); |
230
|
|
|
|
231
|
|
|
return $commentdata; |
232
|
|
|
} |
233
|
|
|
|
234
|
|
|
function wp_check_filetype_and_ext( $filetype, $file, $filename, $mimes ) { |
235
|
|
|
if ( empty( $mimes ) ) |
236
|
|
|
$mimes = get_allowed_mime_types(); |
237
|
|
|
$type = false; |
238
|
|
|
$ext = false; |
239
|
|
|
foreach ( $mimes as $ext_preg => $mime_match ) { |
240
|
|
|
$ext_preg = '!\.(' . $ext_preg . ')$!i'; |
241
|
|
|
if ( preg_match( $ext_preg, $filename, $ext_matches ) ) { |
242
|
|
|
$type = $mime_match; |
243
|
|
|
$ext = $ext_matches[1]; |
244
|
|
|
break; |
245
|
|
|
} |
246
|
|
|
} |
247
|
|
|
$filetype['ext'] = $ext; |
248
|
|
|
$filetype['type'] = $type; |
249
|
|
|
return $filetype; |
250
|
|
|
} |
251
|
|
|
|
252
|
|
|
function disable_jetpack_xmlrpc_methods_293( $jetpack_methods, $core_methods, $user = false ) { |
253
|
|
|
if ( $this->needs_jetpack_293_fix() && !$user ) |
254
|
|
|
unset( $jetpack_methods['jetpack.jsonAPI'], $jetpack_methods['jetpack.verifyAction'] ); |
255
|
|
|
return $jetpack_methods; |
256
|
|
|
} |
257
|
|
|
|
258
|
|
|
function disable_xmlrpc_methods_293( $core_methods ) { |
259
|
|
|
if ( $this->needs_jetpack_293_fix() ) |
260
|
|
|
unset( $core_methods['jetpack.verifyAction'] ); |
261
|
|
|
return $core_methods; |
262
|
|
|
} |
263
|
|
|
|
264
|
|
|
function needs_jetpack_293_fix() { |
265
|
|
|
if ( ! defined( 'JETPACK__VERSION' ) ) |
266
|
|
|
return false; |
267
|
|
|
$secure_jetpacks = array( |
268
|
|
|
'1.9' => '1.9.3', |
269
|
|
|
'2.0' => '2.0.5', |
270
|
|
|
'2.1' => '2.1.3', |
271
|
|
|
'2.2' => '2.2.6', |
272
|
|
|
'2.3' => '2.3.6', |
273
|
|
|
'2.4' => '2.4.3', |
274
|
|
|
'2.5' => '2.5.1', |
275
|
|
|
'2.6' => '2.6.2', |
276
|
|
|
'2.7' => '2.7.1', |
277
|
|
|
'2.8' => '2.8.1', |
278
|
|
|
'2.9' => '2.9.3', |
279
|
|
|
); |
280
|
|
|
$float_version = (string) floatval( JETPACK__VERSION ); |
281
|
|
|
if ( ! isset( $secure_jetpacks[ $float_version ] ) ) |
282
|
|
|
return false; |
283
|
|
|
return version_compare( JETPACK__VERSION, $secure_jetpacks[ $float_version ], '<' ); |
284
|
|
|
} |
285
|
|
|
|
286
|
|
|
function r21138_xmlrpc_edit_posts( $caps, $cap, $user_id, $args ) { |
287
|
|
|
if ( ! isset( $args[0] ) || isset( $args[1] ) && $args[1] === 'hotfixed' ) |
288
|
|
|
return $caps; |
289
|
|
|
foreach ( get_post_types( array(), 'objects' ) as $post_type_object ) { |
290
|
|
|
if ( $cap === $post_type_object->cap->edit_posts ) |
291
|
|
|
return map_meta_cap( $post_type_object->cap->edit_post, $user_id, $args[0], 'hotfixed' ); |
292
|
|
|
} |
293
|
|
|
return $caps; |
294
|
|
|
} |
295
|
|
|
|
296
|
|
|
function r21152_unfiltered_html( $caps, $cap, $user_id, $args ) { |
297
|
|
|
if ( $cap !== 'unfiltered_html' ) |
298
|
|
|
return $caps; |
299
|
|
|
if ( defined( 'DISALLOW_UNFILTERED_HTML' ) && DISALLOW_UNFILTERED_HTML ) |
300
|
|
|
return $caps; |
301
|
|
|
$key = array_search( 'do_not_allow', $caps ); |
302
|
|
|
if ( false !== $key ) |
303
|
|
|
return $caps; |
304
|
|
|
if ( is_multisite() && ! is_super_admin( $user_id ) ) |
305
|
|
|
$caps[$key] = 'do_not_allow'; |
306
|
|
|
return $caps; |
307
|
|
|
} |
308
|
|
|
|
309
|
|
|
function get_pagenum_link( $url ) { |
310
|
|
|
return esc_url_raw( $url ); |
311
|
|
|
} |
312
|
|
|
|
313
|
|
|
function r20486_comment_post_redirect( $location ) { |
314
|
|
|
$location = wp_sanitize_redirect( $location ); |
315
|
|
|
$location = wp_validate_redirect( $location, admin_url() ); |
316
|
|
|
|
317
|
|
|
return $location; |
318
|
|
|
} |
319
|
|
|
|
320
|
|
|
function r20493_make_clickable( $text ) { |
321
|
|
|
$r = ''; |
322
|
|
|
$textarr = preg_split( '/(<[^<>]+>)/', $text, -1, PREG_SPLIT_DELIM_CAPTURE ); // split out HTML tags |
323
|
|
|
foreach ( $textarr as $piece ) { |
324
|
|
|
if ( empty( $piece ) || ( $piece[0] == '<' && ! preg_match('|^<\s*[\w]{1,20}+://|', $piece) ) ) { |
325
|
|
|
$r .= $piece; |
326
|
|
|
continue; |
327
|
|
|
} |
328
|
|
|
|
329
|
|
|
// Long strings might contain expensive edge cases ... |
330
|
|
|
if ( 10000 < strlen( $piece ) ) { |
331
|
|
|
// ... break it up |
332
|
|
|
foreach ( $this->r20493_split_str_by_whitespace( $piece, 2100 ) as $chunk ) { // 2100: Extra room for scheme and leading and trailing paretheses |
333
|
|
|
if ( 2101 < strlen( $chunk ) ) { |
334
|
|
|
$r .= $chunk; // Too big, no whitespace: bail. |
335
|
|
|
} else { |
336
|
|
|
$r .= $this->r20493_make_clickable( $chunk ); |
337
|
|
|
} |
338
|
|
|
} |
339
|
|
|
} else { |
340
|
|
|
$ret = " $piece "; // Pad with whitespace to simplify the regexes |
341
|
|
|
|
342
|
|
|
$url_clickable = '~ |
343
|
|
|
([\\s(<.,;:!?]) # 1: Leading whitespace, or punctuation |
344
|
|
|
( # 2: URL |
345
|
|
|
[\\w]{1,20}+:// # Scheme and hier-part prefix |
346
|
|
|
(?=\S{1,2000}\s) # Limit to URLs less than about 2000 characters long |
347
|
|
|
[\\w\\x80-\\xff#%\\~/@\\[\\]*(+=&$-]*+ # Non-punctuation URL character |
348
|
|
|
(?: # Unroll the Loop: Only allow puctuation URL character if followed by a non-punctuation URL character |
349
|
|
|
[\'.,;:!?)] # Punctuation URL character |
350
|
|
|
[\\w\\x80-\\xff#%\\~/@\\[\\]*(+=&$-]++ # Non-punctuation URL character |
351
|
|
|
)* |
352
|
|
|
) |
353
|
|
|
(\)?) # 3: Trailing closing parenthesis (for parethesis balancing post processing) |
354
|
|
|
~xS'; // The regex is a non-anchored pattern and does not have a single fixed starting character. |
355
|
|
|
// Tell PCRE to spend more time optimizing since, when used on a page load, it will probably be used several times. |
356
|
|
|
|
357
|
|
|
$ret = preg_replace_callback( $url_clickable, array( $this, 'r20493_make_url_clickable_cb') , $ret ); |
358
|
|
|
|
359
|
|
|
$ret = preg_replace_callback( '#([\s>])((www|ftp)\.[\w\\x80-\\xff\#$%&~/.\-;:=,?@\[\]+]+)#is', '_make_web_ftp_clickable_cb', $ret ); |
360
|
|
|
$ret = preg_replace_callback( '#([\s>])([.0-9a-z_+-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,})#i', '_make_email_clickable_cb', $ret ); |
361
|
|
|
|
362
|
|
|
$ret = substr( $ret, 1, -1 ); // Remove our whitespace padding. |
363
|
|
|
$r .= $ret; |
364
|
|
|
} |
365
|
|
|
} |
366
|
|
|
|
367
|
|
|
// Cleanup of accidental links within links |
368
|
|
|
$r = preg_replace( '#(<a( [^>]+?>|>))<a [^>]+?>([^>]+?)</a></a>#i', "$1$3</a>", $r ); |
369
|
|
|
return $r; |
370
|
|
|
} |
371
|
|
|
|
372
|
|
|
function r20493_make_url_clickable_cb($matches) { |
373
|
|
|
$url = $matches[2]; |
374
|
|
|
|
375
|
|
|
if ( ')' == $matches[3] && strpos( $url, '(' ) ) { |
376
|
|
|
// If the trailing character is a closing parethesis, and the URL has an opening parenthesis in it, add the closing parenthesis to the URL. |
377
|
|
|
// Then we can let the parenthesis balancer do its thing below. |
378
|
|
|
$url .= $matches[3]; |
379
|
|
|
$suffix = ''; |
380
|
|
|
} else { |
381
|
|
|
$suffix = $matches[3]; |
382
|
|
|
} |
383
|
|
|
|
384
|
|
|
// Include parentheses in the URL only if paired |
385
|
|
|
while ( substr_count( $url, '(' ) < substr_count( $url, ')' ) ) { |
386
|
|
|
$suffix = strrchr( $url, ')' ) . $suffix; |
387
|
|
|
$url = substr( $url, 0, strrpos( $url, ')' ) ); |
388
|
|
|
} |
389
|
|
|
|
390
|
|
|
$url = esc_url($url); |
391
|
|
|
if ( empty($url) ) |
392
|
|
|
return $matches[0]; |
393
|
|
|
|
394
|
|
|
return $matches[1] . "<a href=\"$url\" rel=\"nofollow\">$url</a>" . $suffix; |
395
|
|
|
} |
396
|
|
|
|
397
|
|
|
function r20493_split_str_by_whitespace( $string, $goal ) { |
398
|
|
|
$chunks = array(); |
399
|
|
|
|
400
|
|
|
$string_nullspace = strtr( $string, "\r\n\t\v\f ", "\000\000\000\000\000\000" ); |
401
|
|
|
|
402
|
|
|
while ( $goal < strlen( $string_nullspace ) ) { |
403
|
|
|
$pos = strrpos( substr( $string_nullspace, 0, $goal + 1 ), "\000" ); |
404
|
|
|
|
405
|
|
|
if ( false === $pos ) { |
406
|
|
|
$pos = strpos( $string_nullspace, "\000", $goal + 1 ); |
407
|
|
|
if ( false === $pos ) { |
408
|
|
|
break; |
409
|
|
|
} |
410
|
|
|
} |
411
|
|
|
|
412
|
|
|
$chunks[] = substr( $string, 0, $pos + 1 ); |
413
|
|
|
$string = substr( $string, $pos + 1 ); |
414
|
|
|
$string_nullspace = substr( $string_nullspace, $pos + 1 ); |
415
|
|
|
} |
416
|
|
|
|
417
|
|
|
if ( $string ) { |
418
|
|
|
$chunks[] = $string; |
419
|
|
|
} |
420
|
|
|
|
421
|
|
|
return $chunks; |
422
|
|
|
} |
423
|
|
|
|
424
|
|
|
function r16625( $query ) { |
425
|
|
|
// Hotfixes: http://core.trac.wordpress.org/changeset/16625 |
426
|
|
|
|
427
|
|
|
// Punt as fast as possible if this isn't an UPDATE |
428
|
|
|
if ( substr( $query, 0, 6 ) != "UPDATE" ) |
429
|
|
|
return $query; |
430
|
|
|
global $wpdb; |
431
|
|
|
|
432
|
|
|
// Determine what the prefix of the bad query would look like and punt if this query doesn't match |
433
|
|
|
$badstring = "UPDATE $wpdb->posts SET to_ping = TRIM(REPLACE(to_ping, '"; |
434
|
|
|
if ( substr( $query, 0, strlen( $badstring ) ) != $badstring ) |
435
|
|
|
return $query; |
436
|
|
|
|
437
|
|
|
// Pull the post_id which is the last thing in the origin query, after a space, no quotes |
438
|
|
|
$query_parts = explode( " ", $query ); |
439
|
|
|
$post_id = array_pop( $query_parts ); |
440
|
|
|
|
441
|
|
|
// Chop off the beginning and end of the original query to get our unsanitized $tb_ping |
442
|
|
|
$tb_ping = substr( |
443
|
|
|
$query, |
444
|
|
|
strlen( $badstring ), |
445
|
|
|
( |
446
|
|
|
strlen( $query ) - ( |
447
|
|
|
strlen( $badstring ) + strlen( sprintf( "', '')) WHERE ID = %d", $post_id ) ) |
448
|
|
|
) |
449
|
|
|
) |
450
|
|
|
); |
451
|
|
|
|
452
|
|
|
// Return the fixed query |
453
|
|
|
return $wpdb->prepare( "UPDATE $wpdb->posts SET to_ping = TRIM(REPLACE(to_ping, %s, '')) WHERE ID = %d", $tb_ping, $post_id ); |
454
|
|
|
} |
455
|
|
|
|
456
|
|
|
function filter_xmlrpc_methods( $xmlrpc_method ) { |
457
|
|
|
// Hotfixes: http://core.trac.wordpress.org/changeset/16803 |
458
|
|
|
global $wp_xmlrpc_server; |
459
|
|
|
// Pretend that we are an xmlrpc method, freshly called |
460
|
|
|
$args = $wp_xmlrpc_server->message->params; |
461
|
|
|
$error_code = 401; |
462
|
|
|
switch( $xmlrpc_method ) { |
463
|
|
|
case 'metaWeblog.newPost': |
464
|
|
|
$content_struct = $args[3]; |
465
|
|
|
$publish = isset( $args[4] ) ? $args[4] : 0; |
466
|
|
|
if ( !empty( $content_struct['post_type'] ) ) { |
467
|
|
|
if ( $content_struct['post_type'] == 'page' ) { |
468
|
|
|
if ( $publish || 'publish' == $content_struct['page_status'] ) |
469
|
|
|
$cap = 'publish_pages'; |
470
|
|
|
else |
471
|
|
|
$cap = 'edit_pages'; |
472
|
|
|
$error_message = __( 'Sorry, you are not allowed to publish pages on this site.' ); |
473
|
|
View Code Duplication |
} elseif ( $content_struct['post_type'] == 'post' ) { |
474
|
|
|
if ( $publish || 'publish' == $content_struct['post_status'] ) |
475
|
|
|
$cap = 'publish_posts'; |
476
|
|
|
else |
477
|
|
|
$cap = 'edit_posts'; |
478
|
|
|
$error_message = __( 'Sorry, you are not allowed to publish posts on this site.' ); |
479
|
|
|
} else { |
480
|
|
|
$error_message = __( 'Invalid post type.' ); |
481
|
|
|
} |
482
|
|
View Code Duplication |
} else { |
483
|
|
|
if ( $publish || 'publish' == $content_struct['post_status'] ) |
484
|
|
|
$cap = 'publish_posts'; |
485
|
|
|
else |
486
|
|
|
$cap = 'edit_posts'; |
487
|
|
|
$error_message = __( 'Sorry, you are not allowed to publish posts on this site.' ); |
488
|
|
|
} |
489
|
|
|
if ( current_user_can( $cap ) ) |
|
|
|
|
490
|
|
|
return true; |
491
|
|
|
break; |
492
|
|
|
case 'metaWeblog.editPost': |
493
|
|
|
$post_ID = (int) $args[0]; |
|
|
|
|
494
|
|
|
$content_struct = $args[3]; |
495
|
|
|
$publish = $args[4] || ( isset( $content_struct['post_status'] ) && in_array( $content_struct['post_status'], array( 'publish', 'private' ) ) ); |
496
|
|
|
$cap = ( $publish ) ? 'publish_posts' : 'edit_posts'; |
497
|
|
|
$error_message = __( 'Sorry, you are not allowed to publish posts on this site.' ); |
498
|
|
|
if ( !empty( $content_struct['post_type'] ) ) { |
499
|
|
|
if ( $content_struct['post_type'] == 'page' ) { |
500
|
|
|
$error_message = __( 'Sorry, you are not allowed to publish pages on this site.' ); |
501
|
|
|
} elseif ( $content_struct['post_type'] == 'post' ) { |
502
|
|
|
$error_message = __( 'Sorry, you are not allowed to publish posts on this site.' ); |
503
|
|
|
} else { |
504
|
|
|
$error_message = __( 'Invalid post type.' ); |
505
|
|
|
} |
506
|
|
|
} |
507
|
|
|
if ( current_user_can( $cap ) ) |
508
|
|
|
return true; |
509
|
|
|
break; |
510
|
|
|
case 'mt.publishPost': |
511
|
|
|
$post_ID = (int) $args[0]; |
512
|
|
|
if ( current_user_can( 'publish_posts' ) && current_user_can( 'edit_post', $post_ID ) ) |
513
|
|
|
return true; |
514
|
|
|
$error_message = __( 'Sorry, you cannot edit this post.' ); |
515
|
|
|
break; |
516
|
|
|
case 'blogger.deletePost': |
517
|
|
|
$post_ID = (int) $args[1]; |
518
|
|
|
if ( current_user_can( 'delete_post', $post_ID ) ) |
519
|
|
|
return true; |
520
|
|
|
$error_message = __( 'Sorry, you do not have the right to delete this post.' ); |
521
|
|
|
break; |
522
|
|
|
case 'wp.getPageStatusList': |
523
|
|
|
if ( current_user_can( 'edit_pages' ) ) |
524
|
|
|
return true; |
525
|
|
|
$error_code = 403; |
526
|
|
|
$error_message = __( 'You are not allowed access to details about this site.' ); |
527
|
|
|
break; |
528
|
|
|
case 'wp.deleteComment': |
529
|
|
|
case 'wp.editComment': |
530
|
|
|
$comment_ID = (int) $args[3]; |
531
|
|
|
if ( !$comment = get_comment( $comment_ID ) ) |
532
|
|
|
return true; // This will be handled in the calling function explicitly |
533
|
|
|
if ( current_user_can( 'edit_post', $comment->comment_post_ID ) ) |
534
|
|
|
return true; |
535
|
|
|
$error_code = 403; |
536
|
|
|
$error_message = __( 'You are not allowed to moderate comments on this site.' ); |
537
|
|
|
break; |
538
|
|
|
default: |
539
|
|
|
return true; |
540
|
|
|
} |
541
|
|
|
// If we are here then this was a handlable xmlrpc call and the capability checks above all failed |
542
|
|
|
// ( otherwise they would have returned to the do_action from the switch statement above ) so it's |
543
|
|
|
// time to exit with whatever error we've determined is the problem (thus short circuiting the |
544
|
|
|
// original XMLRPC method call, and enforcing the above capability checks -- with an ax. We'll |
545
|
|
|
// mimic the behavior from the end of IXR_Server::serve() |
546
|
|
|
$r = new IXR_Error( $error_code, $error_message ); |
547
|
|
|
$resultxml = $r->getXml(); |
548
|
|
|
$xml = <<<EOD |
549
|
|
|
<methodResponse> |
550
|
|
|
<params> |
551
|
|
|
<param> |
552
|
|
|
<value> |
553
|
|
|
$resultxml |
554
|
|
|
</value> |
555
|
|
|
</param> |
556
|
|
|
</params> |
557
|
|
|
</methodResponse> |
558
|
|
|
EOD; |
559
|
|
|
$wp_xmlrpc_server->output( $xml ); |
560
|
|
|
// For good measure... |
561
|
|
|
die(); |
562
|
|
|
} |
563
|
|
|
|
564
|
|
|
function r17172_esc_url( $url, $original_url, $_context ) { |
565
|
|
|
$url = $original_url; |
566
|
|
|
|
567
|
|
|
if ( '' == $url ) |
568
|
|
|
return $url; |
569
|
|
|
$url = preg_replace('|[^a-z0-9-~+_.?#=!&;,/:%@$\|*\'()\\x80-\\xff]|i', '', $url); |
570
|
|
|
$strip = array('%0d', '%0a', '%0D', '%0A'); |
571
|
|
|
$url = _deep_replace($strip, $url); |
572
|
|
|
$url = str_replace(';//', '://', $url); |
573
|
|
|
/* If the URL doesn't appear to contain a scheme, we |
574
|
|
|
* presume it needs http:// appended (unless a relative |
575
|
|
|
* link starting with /, # or ? or a php file). |
576
|
|
|
*/ |
577
|
|
|
if ( strpos($url, ':') === false && ! in_array( $url[0], array( '/', '#', '?' ) ) && |
578
|
|
|
! preg_match('/^[a-z0-9-]+?\.php/i', $url) ) |
579
|
|
|
$url = 'http://' . $url; |
580
|
|
|
|
581
|
|
|
// Replace ampersands and single quotes only when displaying. |
582
|
|
|
if ( 'display' == $_context ) { |
583
|
|
|
$url = wp_kses_normalize_entities( $url ); |
584
|
|
|
$url = str_replace( '&', '&', $url ); |
585
|
|
|
$url = str_replace( "'", ''', $url ); |
586
|
|
|
} |
587
|
|
|
|
588
|
|
|
$protocols = array ('http', 'https', 'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp', 'feed', 'telnet', 'mms', 'rtsp', 'svn'); |
589
|
|
|
if ( VaultPress_kses::wp_kses_bad_protocol( $url, $protocols ) != $url ) |
590
|
|
|
return ''; |
591
|
|
|
return $url; |
592
|
|
|
} |
593
|
|
|
|
594
|
|
|
// http://core.trac.wordpress.org/changeset/17172 |
595
|
|
|
// http://core.trac.wordpress.org/changeset/20541 |
596
|
|
|
function r17172_wp_kses( $string, $html, $protocols ) { |
597
|
|
|
return VaultPress_kses::wp_kses( $string, $html, $protocols ); |
598
|
|
|
} |
599
|
|
|
|
600
|
|
|
// http://core.trac.wordpress.org/changeset/17990 |
601
|
|
|
function r17990( $filename ) { |
602
|
|
|
$parts = explode('.', $filename); |
603
|
|
|
$filename = array_shift($parts); |
604
|
|
|
$extension = array_pop($parts); |
605
|
|
|
$mimes = get_allowed_mime_types(); |
606
|
|
|
|
607
|
|
|
// Loop over any intermediate extensions. Munge them with a trailing underscore if they are a 2 - 5 character |
608
|
|
|
// long alpha string not in the extension whitelist. |
609
|
|
|
foreach ( (array) $parts as $part) { |
610
|
|
|
$filename .= '.' . $part; |
611
|
|
|
|
612
|
|
|
if ( preg_match("/^[a-zA-Z]{2,5}\d?$/", $part) ) { |
613
|
|
|
$allowed = false; |
614
|
|
|
foreach ( $mimes as $ext_preg => $mime_match ) { |
615
|
|
|
$ext_preg = '!^(' . $ext_preg . ')$!i'; |
616
|
|
|
if ( preg_match( $ext_preg, $part ) ) { |
617
|
|
|
$allowed = true; |
618
|
|
|
break; |
619
|
|
|
} |
620
|
|
|
} |
621
|
|
|
if ( !$allowed ) |
622
|
|
|
$filename .= '_'; |
623
|
|
|
} |
624
|
|
|
} |
625
|
|
|
$filename .= '.' . $extension; |
626
|
|
|
return $filename; |
627
|
|
|
} |
628
|
|
|
|
629
|
|
|
/* |
630
|
|
|
* Hotfixes: http://core.trac.wordpress.org/changeset/18368 |
631
|
|
|
*/ |
632
|
|
|
function r18368( $post, $raw_post ) { |
633
|
|
|
if ( isset( $post['filter'] ) || isset ( $raw_post['filter'] ) ) { |
634
|
|
|
unset( $post['filter'], $raw_post['filter'] ); // to ensure the post is properly sanitized |
635
|
|
|
$post = sanitize_post($post, 'db'); |
636
|
|
|
} |
637
|
|
|
if ( empty( $post['ID'] ) ) |
638
|
|
|
unset( $post['ID'] ); // sanitize_post |
639
|
|
|
unset( $post['filter'] ); // sanitize_post |
640
|
|
|
return $post; |
641
|
|
|
} |
642
|
|
|
|
643
|
|
|
/** |
644
|
|
|
* Protect WordPress internal metadata. |
645
|
|
|
* |
646
|
|
|
* The post data is passed as a parameter to (unit) test this method. |
647
|
|
|
* @param $post_data|array the $_POST array. |
648
|
|
|
*/ |
649
|
|
|
function r17994( &$post_data ) { |
650
|
|
|
// Protect admin-ajax add_meta |
651
|
|
|
$metakeyselect = isset( $post_data['metakeyselect'] ) ? stripslashes( trim( $post_data['metakeyselect'] ) ) : ''; |
652
|
|
|
$metakeyinput = isset( $post_data['metakeyinput'] ) ? stripslashes( trim( $post_data['metakeyinput'] ) ) : ''; |
653
|
|
|
|
654
|
|
|
if ( ( $metakeyselect && '_' == $metakeyselect[0] ) || ( $metakeyinput && '_' == $metakeyinput[0] ) ) { |
655
|
|
|
unset( $_POST['metakeyselect'], $_POST['metakeyinput'] ); |
656
|
|
|
} |
657
|
|
|
|
658
|
|
|
// Protect admin-ajax update_meta |
659
|
|
|
if ( isset( $post_data['meta'] ) ) { |
660
|
|
|
foreach ( (array)$post_data['meta'] as $mid => $value ) { |
661
|
|
|
$key = stripslashes( $post_data['meta'][$mid]['key'] ); |
662
|
|
|
if ( $key && '_' == $key[0] ) |
663
|
|
|
unset( $post_data['meta'][$mid] ); |
664
|
|
|
} |
665
|
|
|
} |
666
|
|
|
} |
667
|
|
|
|
668
|
|
|
function r17994_sanitize_mime_type( $mime_type ) { |
669
|
|
|
$sani_mime_type = preg_replace( '/[^\-*.a-zA-Z0-9\/+]/', '', $mime_type ); |
670
|
|
|
return apply_filters( 'sanitize_mime_type', $sani_mime_type, $mime_type ); |
|
|
|
|
671
|
|
|
} |
672
|
|
|
|
673
|
|
|
function r17826_send_frame_options_header() { |
674
|
|
|
@header( 'X-Frame-Options: SAMEORIGIN' ); |
|
|
|
|
675
|
|
|
} |
676
|
|
|
|
677
|
|
|
function r18346_sanitize_admin_email_on_save($value) { |
678
|
|
|
$value = sanitize_email( $value ); |
679
|
|
|
if ( !is_email( $value ) ) { |
680
|
|
|
$value = get_option( 'new_admin_email' ); // Resets option to stored value in the case of failed sanitization |
681
|
|
|
if ( function_exists( 'add_settings_error' ) ) |
682
|
|
|
add_settings_error( 'new_admin_email', 'invalid_admin_email', __( 'The email address entered did not appear to be a valid email address. Please enter a valid email address.' ) ); |
683
|
|
|
} |
684
|
|
|
return $value; |
685
|
|
|
} |
686
|
|
|
|
687
|
|
|
function r18346_sanitize_admin_email( $value ) { |
688
|
|
|
return sanitize_email( $value ); // Is it enough ? |
689
|
|
|
} |
690
|
|
|
|
691
|
|
|
function r18346_sanitize_lang_on_save( $value ) { |
692
|
|
|
$value = $this->r18346_sanitize_lang( $value ); // sanitize the new value. |
693
|
|
|
if ( empty( $value ) ) |
694
|
|
|
$value = get_option( 'WPLANG' ); |
695
|
|
|
return $value; |
696
|
|
|
} |
697
|
|
|
|
698
|
|
|
function r18346_sanitize_lang( $value ) { |
699
|
|
|
$allowed = apply_filters( 'available_languages', get_available_languages() ); // add a filter to unit test |
700
|
|
|
if ( !empty( $value ) && !in_array( $value, $allowed ) ) |
701
|
|
|
return false; |
702
|
|
|
else |
703
|
|
|
return $value; |
704
|
|
|
} |
705
|
|
|
|
706
|
|
|
// Protect All-in-one SEO AJAX calls from script injection and changes without privileges. Affects versions <= 2.1.5 |
707
|
|
|
function protect_aioseo_ajax() { |
708
|
|
|
if ( defined( 'AIOSEOP_VERSION' ) && version_compare( AIOSEOP_VERSION, '2.1.5', '>' ) ) |
709
|
|
|
return; |
710
|
|
|
|
711
|
|
|
if ( ! isset( $_POST['post_id'] ) || ! isset( $_POST['target_meta'] ) ) |
712
|
|
|
die(); |
713
|
|
|
|
714
|
|
|
// Ensure the current user has permission to write to the post. |
715
|
|
|
if ( ! current_user_can( 'edit_post', intval( $_POST['post_id'] ) ) ) |
716
|
|
|
die(); |
717
|
|
|
|
718
|
|
|
// Limit the fields that can be written to |
719
|
|
|
if ( ! in_array( $_POST['target_meta'], array( 'title', 'description', 'keywords' ) ) ) |
720
|
|
|
die(); |
721
|
|
|
|
722
|
|
|
// Strip tags from the metadata value. |
723
|
|
|
$_POST['new_meta'] = strip_tags( $_POST['new_meta'] ); |
724
|
|
|
} |
725
|
|
|
|
726
|
|
|
// Protect The MailPoet plugin (wysija-newsletters) from remote file upload. Affects versions <= 2.6.6 |
727
|
|
|
function protect_wysija_newsletters_verify_capability() { |
728
|
|
|
if ( !class_exists( 'WYSIJA_object' ) ) |
729
|
|
|
return true; |
730
|
|
|
if ( version_compare( WYSIJA::get_version(), '2.6.7', '>=' ) ) |
731
|
|
|
return true; |
732
|
|
|
if ( !defined( 'DOING_AJAX' ) && !defined( 'WYSIJA_ITF' ) ) |
733
|
|
|
return true; |
734
|
|
|
if( isset( $_REQUEST['page'] ) && substr( $_REQUEST['page'] ,0 ,7 ) == 'wysija_' ){ |
735
|
|
|
|
736
|
|
|
switch( $_REQUEST['page'] ){ |
737
|
|
|
case 'wysija_campaigns': |
738
|
|
|
$role_needed = 'wysija_newsletters'; |
739
|
|
|
break; |
740
|
|
|
case 'wysija_subscribers': |
741
|
|
|
$role_needed = 'wysija_subscribers'; |
742
|
|
|
break; |
743
|
|
|
case 'wysija_config': |
744
|
|
|
$role_needed = 'wysija_config'; |
745
|
|
|
break; |
746
|
|
|
case 'wysija_statistics': |
747
|
|
|
$role_needed = 'wysija_stats_dashboard'; |
748
|
|
|
break; |
749
|
|
|
default: |
750
|
|
|
$role_needed = 'switch_themes'; |
751
|
|
|
} |
752
|
|
|
|
753
|
|
|
if( current_user_can( $role_needed ) ){ |
754
|
|
|
return true; |
755
|
|
|
} else{ |
756
|
|
|
die( 'You are not allowed here.' ); |
757
|
|
|
} |
758
|
|
|
|
759
|
|
|
}else{ |
760
|
|
|
// this is not a wysija interface/action we can let it pass |
761
|
|
|
return true; |
762
|
|
|
} |
763
|
|
|
} |
764
|
|
|
|
765
|
|
|
// Protect the Revolution Slider plugin (revslider) from local file inclusion. Affects versions < 4.2 |
766
|
|
|
function protect_revslider_lfi() { |
767
|
|
|
if ( isset( $_GET['action'] ) && 'revslider_show_image' == $_GET['action'] ) { |
768
|
|
|
$img = ''; |
769
|
|
|
if ( isset( $_GET['img'] ) ) |
770
|
|
|
$img = $_GET['img']; |
771
|
|
|
if ( is_numeric( $img ) ) |
772
|
|
|
return; |
773
|
|
|
$validate = validate_file( $img ); |
774
|
|
|
if ( 0 !== $validate ) |
775
|
|
|
die( 'invalid file' ); |
776
|
|
|
if ( !file_exists( $img ) ) |
777
|
|
|
die( 'file does not exist' ); |
778
|
|
|
} |
779
|
|
|
} |
780
|
|
|
|
781
|
|
|
// Protect WooCommerce 2.0.20 - 2.3.10 from PayPal IPN object injection attack. |
782
|
|
|
function protect_woocommerce_paypal_object_injection() { |
783
|
|
|
global $woocommerce; |
784
|
|
|
if ( ! isset( $woocommerce ) ) |
785
|
|
|
return; |
786
|
|
|
|
787
|
|
|
$wc_version = $woocommerce->version; |
788
|
|
|
if ( version_compare( $wc_version, '2.0.20', '<' ) || version_compare( $wc_version, '2.3.11', '>=' ) ) |
789
|
|
|
return; |
790
|
|
|
|
791
|
|
|
if ( isset( $_REQUEST['paypalListener'] ) ) { |
792
|
|
|
$check_fields = array( 'custom', 'cm' ); |
793
|
|
|
foreach ( $check_fields as $field ) { |
794
|
|
|
if ( isset( $_REQUEST[ $field ] ) && preg_match( '/[CO]:\+?[0-9]+:/', $_REQUEST[ $field ] ) ) { |
795
|
|
|
die(); |
796
|
|
|
} |
797
|
|
|
} |
798
|
|
|
} |
799
|
|
|
} |
800
|
|
|
|
801
|
|
|
// Protect WordPress 3.1.0 -> WordPress 4.3.0 from code injection via user email |
802
|
|
|
function patch_user_email( $value, $user_id, $context ) { |
803
|
|
|
if ( 'display' === $context && class_exists( 'WP_Users_List_Table' ) ) { |
804
|
|
|
return esc_attr( $value ); |
805
|
|
|
} |
806
|
|
|
|
807
|
|
|
return $value; |
808
|
|
|
} |
809
|
|
|
|
810
|
|
|
// Protect WordPress < 4.3.1 from evil tags inside caption shortcodes |
811
|
|
|
function filtered_caption_shortcode( $attr, $content = null ) { |
812
|
|
|
if ( isset( $attr['caption'] ) && strpos( $attr['caption'], '<' ) !== false ) { |
813
|
|
|
$attr['caption'] = wp_kses( $attr['caption'], 'post' ); |
814
|
|
|
} |
815
|
|
|
|
816
|
|
|
return img_caption_shortcode( $attr, $content ); |
817
|
|
|
} |
818
|
|
|
|
819
|
|
|
// Protect Akismet < 3.1.5 from stored XSS in admin page |
820
|
|
|
function protect_akismet_comment_xss() { |
821
|
|
|
remove_filter( 'comment_text', array( 'Akismet_Admin', 'text_add_link_class' ) ); |
822
|
|
|
} |
823
|
|
|
} |
824
|
|
|
|
825
|
|
|
global $wp_version; |
826
|
|
|
$needs_class_fix = version_compare( $wp_version, '3.1', '>=') && version_compare( $wp_version, '3.1.3', '<' ); |
827
|
|
|
if ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST && $needs_class_fix ) { |
828
|
|
|
include_once( ABSPATH . WPINC . '/class-IXR.php' ); |
829
|
|
|
include_once( ABSPATH . WPINC . '/class-wp-xmlrpc-server.php' ); |
830
|
|
|
|
831
|
|
|
class VaultPress_XMLRPC_Server_r17994 extends wp_xmlrpc_server { |
832
|
|
|
function set_custom_fields( $post_id, $fields ) { |
833
|
|
|
foreach( $fields as $k => $meta ) { |
834
|
|
|
$key = stripslashes( trim( $meta['key'] ) ); |
835
|
|
|
if ( $key && '_' == $key[0] ) |
836
|
|
|
unset( $fields[$k] ); |
837
|
|
|
} |
838
|
|
|
parent::set_custom_fields( $post_id, $fields ); |
839
|
|
|
} |
840
|
|
|
} |
841
|
|
|
|
842
|
|
|
function r17994_xmlrpc_server() { |
843
|
|
|
return 'VaultPress_XMLRPC_Server_r17994'; |
844
|
|
|
} |
845
|
|
|
} |
846
|
|
|
|
847
|
|
|
class VaultPress_kses { |
848
|
|
|
static function wp_kses($string, $allowed_html, $allowed_protocols = array ()) { |
849
|
|
|
$string = wp_kses_no_null($string); |
850
|
|
|
$string = wp_kses_js_entities($string); |
851
|
|
|
$string = wp_kses_normalize_entities($string); |
852
|
|
|
return VaultPress_kses::wp_kses_split($string, $allowed_html, $allowed_protocols); |
853
|
|
|
} |
854
|
|
|
|
855
|
|
|
static function wp_kses_split($string, $allowed_html, $allowed_protocols) { |
856
|
|
|
global $pass_allowed_html, $pass_allowed_protocols; |
857
|
|
|
$pass_allowed_html = $allowed_html; |
858
|
|
|
$pass_allowed_protocols = $allowed_protocols; |
859
|
|
|
return preg_replace_callback( '%(<!--.*?(-->|$))|(<[^>]*(>|$)|>)%', 'VaultPress_kses::_vp_kses_split_callback', $string ); |
860
|
|
|
} |
861
|
|
|
|
862
|
|
|
static function _vp_kses_split_callback( $match ) { |
863
|
|
|
global $pass_allowed_html, $pass_allowed_protocols; |
864
|
|
|
return VaultPress_kses::wp_kses_split2( $match[0], $pass_allowed_html, $pass_allowed_protocols ); |
865
|
|
|
} |
866
|
|
|
|
867
|
|
|
static function wp_kses_split2($string, $allowed_html, $allowed_protocols) { |
868
|
|
|
$string = wp_kses_stripslashes($string); |
869
|
|
|
|
870
|
|
|
if (substr($string, 0, 1) != '<') |
871
|
|
|
return '>'; |
872
|
|
|
# It matched a ">" character |
873
|
|
|
|
874
|
|
|
if ( '<!--' == substr( $string, 0, 4 ) ) { |
875
|
|
|
$string = str_replace( array('<!--', '-->'), '', $string ); |
876
|
|
|
while ( $string != ($newstring = VaultPress_kses::wp_kses($string, $allowed_html, $allowed_protocols)) ) |
877
|
|
|
$string = $newstring; |
878
|
|
|
if ( $string == '' ) |
879
|
|
|
return ''; |
880
|
|
|
// prevent multiple dashes in comments |
881
|
|
|
$string = preg_replace('/--+/', '-', $string); |
882
|
|
|
// prevent three dashes closing a comment |
883
|
|
|
$string = preg_replace('/-$/', '', $string); |
884
|
|
|
return "<!--{$string}-->"; |
885
|
|
|
} |
886
|
|
|
# Allow HTML comments |
887
|
|
|
|
888
|
|
|
if (!preg_match('%^<\s*(/\s*)?([a-zA-Z0-9]+)([^>]*)>?$%', $string, $matches)) |
889
|
|
|
return ''; |
890
|
|
|
# It's seriously malformed |
891
|
|
|
|
892
|
|
|
$slash = trim($matches[1]); |
893
|
|
|
$elem = $matches[2]; |
894
|
|
|
$attrlist = $matches[3]; |
895
|
|
|
|
896
|
|
|
if ( ! isset($allowed_html[strtolower($elem)]) ) |
897
|
|
|
return ''; |
898
|
|
|
# They are using a not allowed HTML element |
899
|
|
|
|
900
|
|
|
if ($slash != '') |
901
|
|
|
return "</$elem>"; |
902
|
|
|
# No attributes are allowed for closing elements |
903
|
|
|
|
904
|
|
|
return VaultPress_kses::wp_kses_attr( $elem, $attrlist, $allowed_html, $allowed_protocols ); |
905
|
|
|
} |
906
|
|
|
|
907
|
|
|
static function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols) { |
908
|
|
|
# Is there a closing XHTML slash at the end of the attributes? |
909
|
|
|
|
910
|
|
|
$xhtml_slash = ''; |
911
|
|
|
if (preg_match('%\s*/\s*$%', $attr)) |
912
|
|
|
$xhtml_slash = ' /'; |
913
|
|
|
|
914
|
|
|
# Are any attributes allowed at all for this element? |
915
|
|
|
if ( ! isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0 ) |
916
|
|
|
return "<$element$xhtml_slash>"; |
917
|
|
|
|
918
|
|
|
# Split it |
919
|
|
|
$attrarr = VaultPress_kses::wp_kses_hair($attr, $allowed_protocols); |
920
|
|
|
|
921
|
|
|
# Go through $attrarr, and save the allowed attributes for this element |
922
|
|
|
# in $attr2 |
923
|
|
|
$attr2 = ''; |
924
|
|
|
|
925
|
|
|
$allowed_attr = $allowed_html[strtolower($element)]; |
926
|
|
|
foreach ($attrarr as $arreach) { |
927
|
|
|
if ( ! isset( $allowed_attr[strtolower($arreach['name'])] ) ) |
928
|
|
|
continue; # the attribute is not allowed |
929
|
|
|
|
930
|
|
|
$current = $allowed_attr[strtolower($arreach['name'])]; |
931
|
|
|
if ( $current == '' ) |
932
|
|
|
continue; # the attribute is not allowed |
933
|
|
|
|
934
|
|
|
if ( strtolower( $arreach['name'] ) == 'style' ) { |
935
|
|
|
$orig_value = $arreach['value']; |
936
|
|
|
$value = safecss_filter_attr( $orig_value ); |
937
|
|
|
|
938
|
|
|
if ( empty( $value ) ) |
939
|
|
|
continue; |
940
|
|
|
|
941
|
|
|
$arreach['value'] = $value; |
942
|
|
|
$arreach['whole'] = str_replace( $orig_value, $value, $arreach['whole'] ); |
943
|
|
|
} |
944
|
|
|
|
945
|
|
|
if ( ! is_array($current) ) { |
946
|
|
|
$attr2 .= ' '.$arreach['whole']; |
947
|
|
|
# there are no checks |
948
|
|
|
|
949
|
|
|
} else { |
950
|
|
|
# there are some checks |
951
|
|
|
$ok = true; |
952
|
|
|
foreach ($current as $currkey => $currval) { |
953
|
|
|
if ( ! wp_kses_check_attr_val($arreach['value'], $arreach['vless'], $currkey, $currval) ) { |
954
|
|
|
$ok = false; |
955
|
|
|
break; |
956
|
|
|
} |
957
|
|
|
} |
958
|
|
|
|
959
|
|
|
if ( $ok ) |
960
|
|
|
$attr2 .= ' '.$arreach['whole']; # it passed them |
961
|
|
|
} # if !is_array($current) |
962
|
|
|
} # foreach |
963
|
|
|
|
964
|
|
|
# Remove any "<" or ">" characters |
965
|
|
|
$attr2 = preg_replace('/[<>]/', '', $attr2); |
966
|
|
|
|
967
|
|
|
return "<$element$attr2$xhtml_slash>"; |
968
|
|
|
} |
969
|
|
|
|
970
|
|
|
static function wp_kses_hair($attr, $allowed_protocols) { |
971
|
|
|
$attrarr = array (); |
972
|
|
|
$mode = 0; |
973
|
|
|
$attrname = ''; |
974
|
|
|
$uris = array('xmlns', 'profile', 'href', 'src', 'cite', 'classid', 'codebase', 'data', 'usemap', 'longdesc', 'action'); |
975
|
|
|
|
976
|
|
|
# Loop through the whole attribute list |
977
|
|
|
|
978
|
|
|
while (strlen($attr) != 0) { |
979
|
|
|
$working = 0; # Was the last operation successful? |
980
|
|
|
|
981
|
|
|
switch ($mode) { |
982
|
|
|
case 0 : # attribute name, href for instance |
983
|
|
|
|
984
|
|
|
if (preg_match('/^([-a-zA-Z]+)/', $attr, $match)) { |
985
|
|
|
$attrname = $match[1]; |
986
|
|
|
$working = $mode = 1; |
987
|
|
|
$attr = preg_replace('/^[-a-zA-Z]+/', '', $attr); |
988
|
|
|
} |
989
|
|
|
|
990
|
|
|
break; |
991
|
|
|
|
992
|
|
|
case 1 : # equals sign or valueless ("selected") |
993
|
|
|
|
994
|
|
|
if (preg_match('/^\s*=\s*/', $attr)) # equals sign |
995
|
|
|
{ |
996
|
|
|
$working = 1; |
997
|
|
|
$mode = 2; |
998
|
|
|
$attr = preg_replace('/^\s*=\s*/', '', $attr); |
999
|
|
|
break; |
1000
|
|
|
} |
1001
|
|
|
|
1002
|
|
|
if (preg_match('/^\s+/', $attr)) # valueless |
1003
|
|
|
{ |
1004
|
|
|
$working = 1; |
1005
|
|
|
$mode = 0; |
1006
|
|
|
if(false === array_key_exists($attrname, $attrarr)) { |
1007
|
|
|
$attrarr[$attrname] = array ('name' => $attrname, 'value' => '', 'whole' => $attrname, 'vless' => 'y'); |
1008
|
|
|
} |
1009
|
|
|
$attr = preg_replace('/^\s+/', '', $attr); |
1010
|
|
|
} |
1011
|
|
|
|
1012
|
|
|
break; |
1013
|
|
|
|
1014
|
|
|
case 2 : # attribute value, a URL after href= for instance |
1015
|
|
|
|
1016
|
|
View Code Duplication |
if (preg_match('%^"([^"]*)"(\s+|/?$)%', $attr, $match)) |
1017
|
|
|
# "value" |
1018
|
|
|
{ |
1019
|
|
|
$thisval = $match[1]; |
1020
|
|
|
if ( in_array(strtolower($attrname), $uris) ) |
1021
|
|
|
$thisval = VaultPress_kses::wp_kses_bad_protocol($thisval, $allowed_protocols); |
1022
|
|
|
|
1023
|
|
|
if(false === array_key_exists($attrname, $attrarr)) { |
1024
|
|
|
$attrarr[$attrname] = array ('name' => $attrname, 'value' => $thisval, 'whole' => "$attrname=\"$thisval\"", 'vless' => 'n'); |
1025
|
|
|
} |
1026
|
|
|
$working = 1; |
1027
|
|
|
$mode = 0; |
1028
|
|
|
$attr = preg_replace('/^"[^"]*"(\s+|$)/', '', $attr); |
1029
|
|
|
break; |
1030
|
|
|
} |
1031
|
|
|
|
1032
|
|
View Code Duplication |
if (preg_match("%^'([^']*)'(\s+|/?$)%", $attr, $match)) |
1033
|
|
|
# 'value' |
1034
|
|
|
{ |
1035
|
|
|
$thisval = $match[1]; |
1036
|
|
|
if ( in_array(strtolower($attrname), $uris) ) |
1037
|
|
|
$thisval = VaultPress_kses::wp_kses_bad_protocol($thisval, $allowed_protocols); |
1038
|
|
|
|
1039
|
|
|
if(false === array_key_exists($attrname, $attrarr)) { |
1040
|
|
|
$attrarr[$attrname] = array ('name' => $attrname, 'value' => $thisval, 'whole' => "$attrname='$thisval'", 'vless' => 'n'); |
1041
|
|
|
} |
1042
|
|
|
$working = 1; |
1043
|
|
|
$mode = 0; |
1044
|
|
|
$attr = preg_replace("/^'[^']*'(\s+|$)/", '', $attr); |
1045
|
|
|
break; |
1046
|
|
|
} |
1047
|
|
|
|
1048
|
|
View Code Duplication |
if (preg_match("%^([^\s\"']+)(\s+|/?$)%", $attr, $match)) |
1049
|
|
|
# value |
1050
|
|
|
{ |
1051
|
|
|
$thisval = $match[1]; |
1052
|
|
|
if ( in_array(strtolower($attrname), $uris) ) |
1053
|
|
|
$thisval = VaultPress_kses::wp_kses_bad_protocol($thisval, $allowed_protocols); |
1054
|
|
|
|
1055
|
|
|
if(false === array_key_exists($attrname, $attrarr)) { |
1056
|
|
|
$attrarr[$attrname] = array ('name' => $attrname, 'value' => $thisval, 'whole' => "$attrname=\"$thisval\"", 'vless' => 'n'); |
1057
|
|
|
} |
1058
|
|
|
# We add quotes to conform to W3C's HTML spec. |
1059
|
|
|
$working = 1; |
1060
|
|
|
$mode = 0; |
1061
|
|
|
$attr = preg_replace("%^[^\s\"']+(\s+|$)%", '', $attr); |
1062
|
|
|
} |
1063
|
|
|
|
1064
|
|
|
break; |
1065
|
|
|
} # switch |
1066
|
|
|
|
1067
|
|
|
if ($working == 0) # not well formed, remove and try again |
1068
|
|
|
{ |
1069
|
|
|
$attr = wp_kses_html_error($attr); |
1070
|
|
|
$mode = 0; |
1071
|
|
|
} |
1072
|
|
|
} # while |
1073
|
|
|
|
1074
|
|
|
if ($mode == 1 && false === array_key_exists($attrname, $attrarr)) |
1075
|
|
|
# special case, for when the attribute list ends with a valueless |
1076
|
|
|
# attribute like "selected" |
1077
|
|
|
$attrarr[$attrname] = array ('name' => $attrname, 'value' => '', 'whole' => $attrname, 'vless' => 'y'); |
1078
|
|
|
|
1079
|
|
|
return $attrarr; |
1080
|
|
|
} |
1081
|
|
|
|
1082
|
|
|
static function wp_kses_bad_protocol($string, $allowed_protocols) { |
1083
|
|
|
$string = wp_kses_no_null($string); |
1084
|
|
|
$iterations = 0; |
1085
|
|
|
|
1086
|
|
|
do { |
1087
|
|
|
$original_string = $string; |
1088
|
|
|
$string = VaultPress_kses::wp_kses_bad_protocol_once($string, $allowed_protocols); |
1089
|
|
|
} while ( $original_string != $string && ++$iterations < 6 ); |
1090
|
|
|
|
1091
|
|
|
if ( $original_string != $string ) |
1092
|
|
|
return ''; |
1093
|
|
|
|
1094
|
|
|
return $string; |
1095
|
|
|
} |
1096
|
|
|
|
1097
|
|
|
static function wp_kses_bad_protocol_once($string, $allowed_protocols, $count = 1) { |
1098
|
|
|
$string2 = preg_split( '/:|�*58;|�*3a;/i', $string, 2 ); |
1099
|
|
|
if ( isset($string2[1]) && ! preg_match('%/\?%', $string2[0]) ) { |
1100
|
|
|
$string = trim( $string2[1] ); |
1101
|
|
|
$protocol = VaultPress_kses::wp_kses_bad_protocol_once2( $string2[0], $allowed_protocols ); |
1102
|
|
|
if ( 'feed:' == $protocol ) { |
1103
|
|
|
if ( $count > 2 ) |
1104
|
|
|
return ''; |
1105
|
|
|
$string = VaultPress_kses::wp_kses_bad_protocol_once( $string, $allowed_protocols, ++$count ); |
1106
|
|
|
if ( empty( $string ) ) |
1107
|
|
|
return $string; |
1108
|
|
|
} |
1109
|
|
|
$string = $protocol . $string; |
1110
|
|
|
} |
1111
|
|
|
|
1112
|
|
|
return $string; |
1113
|
|
|
} |
1114
|
|
|
|
1115
|
|
|
static function wp_kses_bad_protocol_once2( $string, $allowed_protocols ) { |
1116
|
|
|
$string2 = wp_kses_decode_entities($string); |
1117
|
|
|
$string2 = preg_replace('/\s/', '', $string2); |
1118
|
|
|
$string2 = wp_kses_no_null($string2); |
1119
|
|
|
$string2 = strtolower($string2); |
1120
|
|
|
|
1121
|
|
|
$allowed = false; |
1122
|
|
|
foreach ( (array) $allowed_protocols as $one_protocol ) { |
1123
|
|
|
if ( strtolower( $one_protocol ) == $string2 ) { |
1124
|
|
|
$allowed = true; |
1125
|
|
|
break; |
1126
|
|
|
} |
1127
|
|
|
} |
1128
|
|
|
|
1129
|
|
|
if ($allowed) |
1130
|
|
|
return "$string2:"; |
1131
|
|
|
else |
1132
|
|
|
return ''; |
1133
|
|
|
} |
1134
|
|
|
|
1135
|
|
|
} |
1136
|
|
|
|
1137
|
|
|
if ( !function_exists( 'get_available_languages' ) ) { |
1138
|
|
|
function get_available_languages( $dir = null ) { |
1139
|
|
|
$languages = array(); |
1140
|
|
|
foreach( glob( ( is_null( $dir) ? WP_LANG_DIR : $dir ) . '/*.mo' ) as $lang_file ) |
1141
|
|
|
if ( false === strpos( $lang_file, 'continents-cities' ) ) |
1142
|
|
|
$languages[] = basename($lang_file, '.mo'); |
1143
|
|
|
return $languages; |
1144
|
|
|
} |
1145
|
|
|
} |
1146
|
|
|
|
If you define a variable conditionally, it can happen that it is not defined for all execution paths.
Let’s take a look at an example:
In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.
Available Fixes
Check for existence of the variable explicitly:
Define a default value for the variable:
Add a value for the missing path: