Version Description
- Bugfix: PHP 5.4 notices
- Feature: Add the possibility to ignore frequent updates on some postmeta keys.
Download this release
Release Info
Developer | xknown |
Plugin | VaultPress |
Version | 1.4.6 |
Comparing to | |
See all releases |
Code changes from version 1.2.8 to 1.4.6
- class.vaultpress-database.php +214 -12
- class.vaultpress-filesystem.php +51 -4
- class.vaultpress-hotfixes.php +255 -54
- class.vaultpress-ixr-ssl-client.php +2 -2
- cron-tasks.php +115 -39
- readme.txt +26 -10
- vaultpress.php +387 -52
- vp-scanner.php +77 -79
class.vaultpress-database.php
CHANGED
@@ -12,8 +12,11 @@ class VaultPress_Database {
|
|
12 |
function __construct() {
|
13 |
}
|
14 |
|
15 |
-
function attach( $table ) {
|
16 |
$this->table=$table;
|
|
|
|
|
|
|
17 |
}
|
18 |
|
19 |
function get_tables( $filter=null ) {
|
@@ -49,7 +52,7 @@ class VaultPress_Database {
|
|
49 |
if ( !is_array( $signatures ) || !count( $signatures ) )
|
50 |
return false;
|
51 |
if ( !$this->table )
|
52 |
-
|
53 |
$table = $wpdb->escape( $this->table );
|
54 |
$diff = array();
|
55 |
foreach ( $signatures as $where => $signature ) {
|
@@ -73,7 +76,7 @@ class VaultPress_Database {
|
|
73 |
if ( !is_array( $columns ) || !count( $columns ) )
|
74 |
return false;
|
75 |
if ( !$this->table )
|
76 |
-
|
77 |
$table = $wpdb->escape( $this->table );
|
78 |
$column = $wpdb->escape( array_shift( $columns ) );
|
79 |
return $wpdb->get_var( "SELECT COUNT( $column ) FROM `$table`" );
|
@@ -124,17 +127,216 @@ class VaultPress_Database {
|
|
124 |
// We don't need to actually record a real cron option value, just an empty array
|
125 |
if ( isset( $row->option_name ) && $row->option_name == 'cron' )
|
126 |
$row->option_value = serialize( array() );
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
134 |
}
|
135 |
-
$row->hash = md5( sprintf( "(%s) VALUES(%s)", implode( ',',$keys ), implode( ',',$vals ) ) );
|
136 |
$rval[]=$row;
|
137 |
}
|
138 |
return $rval;
|
139 |
}
|
140 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
12 |
function __construct() {
|
13 |
}
|
14 |
|
15 |
+
function attach( $table, $parse_create_table = false ) {
|
16 |
$this->table=$table;
|
17 |
+
if ( $parse_create_table ) {
|
18 |
+
$this->structure = $this->parse_create_table( $this->show_create() );
|
19 |
+
}
|
20 |
}
|
21 |
|
22 |
function get_tables( $filter=null ) {
|
52 |
if ( !is_array( $signatures ) || !count( $signatures ) )
|
53 |
return false;
|
54 |
if ( !$this->table )
|
55 |
+
return false;
|
56 |
$table = $wpdb->escape( $this->table );
|
57 |
$diff = array();
|
58 |
foreach ( $signatures as $where => $signature ) {
|
76 |
if ( !is_array( $columns ) || !count( $columns ) )
|
77 |
return false;
|
78 |
if ( !$this->table )
|
79 |
+
return false;
|
80 |
$table = $wpdb->escape( $this->table );
|
81 |
$column = $wpdb->escape( array_shift( $columns ) );
|
82 |
return $wpdb->get_var( "SELECT COUNT( $column ) FROM `$table`" );
|
127 |
// We don't need to actually record a real cron option value, just an empty array
|
128 |
if ( isset( $row->option_name ) && $row->option_name == 'cron' )
|
129 |
$row->option_value = serialize( array() );
|
130 |
+
if ( !empty( $this->structure ) ) {
|
131 |
+
$hash = md5( $this->convert_to_sql_string( $row, $this->structure->columns ) );
|
132 |
+
foreach ( get_object_vars( $row ) as $i => $v ) {
|
133 |
+
if ( !in_array( $i, $columns ) )
|
134 |
+
unset( $row->$i );
|
135 |
+
}
|
136 |
+
|
137 |
+
$row->hash = $hash;
|
138 |
+
} else {
|
139 |
+
$keys = array();
|
140 |
+
$vals = array();
|
141 |
+
foreach ( get_object_vars( $row ) as $i => $v ) {
|
142 |
+
$keys[] = sprintf( "`%s`", $wpdb->escape( $i ) );
|
143 |
+
$vals[] = sprintf( "'%s'", $wpdb->escape( $v ) );
|
144 |
+
if ( !in_array( $i, $columns ) )
|
145 |
+
unset( $row->$i );
|
146 |
+
}
|
147 |
+
$row->hash = md5( sprintf( "(%s) VALUES(%s)", implode( ',',$keys ), implode( ',',$vals ) ) );
|
148 |
}
|
|
|
149 |
$rval[]=$row;
|
150 |
}
|
151 |
return $rval;
|
152 |
}
|
153 |
+
|
154 |
+
/**
|
155 |
+
* Convert a PHP object to a mysqldump compatible string, using the provided data type information.
|
156 |
+
**/
|
157 |
+
function convert_to_sql_string( $data, $datatypes ) {
|
158 |
+
global $wpdb;
|
159 |
+
if ( !is_object( $data ) || !is_object( $datatypes ) )
|
160 |
+
return false;
|
161 |
+
|
162 |
+
foreach ( array_keys( (array)$data ) as $key )
|
163 |
+
$keys[] = sprintf( "`%s`", $wpdb->escape( $key ) );
|
164 |
+
foreach ( (array)$data as $key => $val ) {
|
165 |
+
if ( null === $val ) {
|
166 |
+
$vals[] = 'NULL';
|
167 |
+
continue;
|
168 |
+
}
|
169 |
+
$type = 'text';
|
170 |
+
if ( isset( $datatypes->$key->type ) )
|
171 |
+
$type= strtolower( $datatypes->$key->type );
|
172 |
+
if ( preg_match( '/int|double|float|decimal|bool/i', $type ) )
|
173 |
+
$type = 'number';
|
174 |
+
|
175 |
+
if ( 'number' === $type ) {
|
176 |
+
// do not add quotes to numeric types.
|
177 |
+
$vals[] = $val;
|
178 |
+
} else {
|
179 |
+
$val = $wpdb->escape( $val );
|
180 |
+
// Escape characters that aren't escaped by $wpdb->escape(): \n, \r, etc.
|
181 |
+
$val = str_replace( array( "\x0a", "\x0d", "\x1a" ), array( '\n', '\r', '\Z' ), $val );
|
182 |
+
$vals[] = sprintf( "'%s'", $val );
|
183 |
+
}
|
184 |
+
}
|
185 |
+
if ( !count($keys) )
|
186 |
+
return false;
|
187 |
+
// format the row as a mysqldump line: (`column1`, `column2`) VALUES (numeric_value1,'text value 2')
|
188 |
+
return sprintf( "(%s) VALUES (%s)", implode( ', ',$keys ), implode( ',',$vals ) );
|
189 |
+
}
|
190 |
+
|
191 |
+
|
192 |
+
|
193 |
+
function parse_create_table( $sql ) {
|
194 |
+
$table = new stdClass();
|
195 |
+
|
196 |
+
$table->raw = $sql;
|
197 |
+
$table->columns = new stdClass();
|
198 |
+
$table->primary = null;
|
199 |
+
$table->uniques = new stdClass();
|
200 |
+
$table->keys = new stdClass();
|
201 |
+
$sql = explode( "\n", trim( $sql ) );
|
202 |
+
$table->engine = preg_replace( '/^.+ ENGINE=(\S+) .+$/i', "$1", $sql[(count($sql)-1)] );
|
203 |
+
$table->charset = preg_replace( '/^.+ DEFAULT CHARSET=(\S+)( .+)?$/i', "$1", $sql[(count($sql)-1)] );
|
204 |
+
$table->single_int_paging_column = null;
|
205 |
+
|
206 |
+
foreach ( $sql as $idx => $val )
|
207 |
+
$sql[$idx] = trim($val);
|
208 |
+
$columns = preg_grep( '/^\s*`[^`]+`\s*\S*/', $sql );
|
209 |
+
if ( !$columns )
|
210 |
+
return false;
|
211 |
+
|
212 |
+
$table->name = preg_replace( '/(^[^`]+`|`[^`]+$)/', '', array_shift( preg_grep( '/^CREATE\s+TABLE\s+/', $sql ) ) );
|
213 |
+
|
214 |
+
foreach ( $columns as $line ) {
|
215 |
+
preg_match( '/^`([^`]+)`\s+([a-z]+)(\(\d+\))?\s*/', $line, $m );
|
216 |
+
$name = $m[1];
|
217 |
+
$table->columns->$name = new stdClass();
|
218 |
+
$table->columns->$name->null = (bool)stripos( $line, ' NOT NULL ' );
|
219 |
+
$table->columns->$name->type = $m[2];
|
220 |
+
if ( isset($m[3]) ) {
|
221 |
+
if ( substr( $m[3], 0, 1 ) == '(' )
|
222 |
+
$table->columns->$name->length = substr( $m[3], 1, -1 );
|
223 |
+
else
|
224 |
+
$table->columns->$name->length = $m[3];
|
225 |
+
} else {
|
226 |
+
$table->columns->$name->length = null;
|
227 |
+
}
|
228 |
+
if ( preg_match( '/ character set (\S+)/i', $line, $m ) ) {
|
229 |
+
$table->columns->$name->charset = $m[1];
|
230 |
+
} else {
|
231 |
+
$table->columns->$name->charset = '';
|
232 |
+
}
|
233 |
+
if ( preg_match( '/ collate (\S+)/i', $line, $m ) ) {
|
234 |
+
$table->columns->$name->collate = $m[1];
|
235 |
+
} else {
|
236 |
+
$table->columns->$name->collate = '';
|
237 |
+
}
|
238 |
+
if ( preg_match( '/ DEFAULT (.+),$/i', $line, $m ) ) {
|
239 |
+
if ( substr( $m[1], 0, 1 ) == "'" )
|
240 |
+
$table->columns->$name->default = substr( $m[1], 1, -1 );
|
241 |
+
else
|
242 |
+
$table->columns->$name->default = $m[1];
|
243 |
+
} else {
|
244 |
+
$table->columns->$name->default = null;
|
245 |
+
}
|
246 |
+
$table->columns->$name->line = $line;
|
247 |
+
}
|
248 |
+
$pk = preg_grep( '/^PRIMARY\s+KEY\s+/i', $sql );
|
249 |
+
if ( count( $pk ) ) {
|
250 |
+
$pk = array_pop( $pk );
|
251 |
+
$pk = preg_replace( '/(^[^\(]+\(`|`\),?$)/', '', $pk );
|
252 |
+
$pk = preg_replace( '/\([0-9]+\)/', '', $pk );
|
253 |
+
$pk = explode( '`,`', $pk );
|
254 |
+
$table->primary = $pk;
|
255 |
+
}
|
256 |
+
if ( is_array( $table->primary ) && count( $table->primary ) == 1 ) {
|
257 |
+
$pk_column_name = $table->primary[0];
|
258 |
+
switch( strtolower( $table->columns->$pk_column_name->type ) ) {
|
259 |
+
// Integers, exact value
|
260 |
+
case 'tinyint':
|
261 |
+
case 'smallint':
|
262 |
+
case 'int':
|
263 |
+
case 'integer':
|
264 |
+
case 'bigint':
|
265 |
+
// Fixed point, exact value
|
266 |
+
case 'decimal':
|
267 |
+
case 'numeric':
|
268 |
+
// Floating point, approximate value
|
269 |
+
case 'float':
|
270 |
+
case 'double':
|
271 |
+
case 'real':
|
272 |
+
// Date and Time
|
273 |
+
case 'date':
|
274 |
+
case 'datetime':
|
275 |
+
case 'timestamp':
|
276 |
+
$table->single_int_paging_column = $pk_column_name;
|
277 |
+
break;
|
278 |
+
}
|
279 |
+
}
|
280 |
+
$keys = preg_grep( '/^((?:UNIQUE )?INDEX|(?:UNIQUE )?KEY)\s+/i', $sql );
|
281 |
+
if ( !count( $keys ) )
|
282 |
+
return $table;
|
283 |
+
foreach ( $keys as $idx => $key ) {
|
284 |
+
if ( 0 === strpos( $key, 'UNIQUE' ) )
|
285 |
+
$is_unique = false;
|
286 |
+
else
|
287 |
+
$is_unique = true;
|
288 |
+
|
289 |
+
// for KEY `refresh` (`ip`,`time_last`) USING BTREE,
|
290 |
+
$key = preg_replace( '/ USING \S+ ?(,?)$/', '$1', $key );
|
291 |
+
|
292 |
+
// for KEY `id` USING BTREE (`id`),
|
293 |
+
$key = preg_replace( '/` USING \S+ \(/i', '` (', $key );
|
294 |
+
|
295 |
+
$key = preg_replace( '/^((?:UNIQUE )?INDEX|(?:UNIQUE )?KEY)\s+/i', '', $key );
|
296 |
+
$key = preg_replace( '/\([0-9]+\)/', '', $key );
|
297 |
+
preg_match( '/^`([^`]+)`\s+\(`(.+)`\),?$/', $key, $m );
|
298 |
+
$key = $m[1]; //preg_replace( '/\([^)]+\)/', '', $m[1]);
|
299 |
+
if ( !$key )
|
300 |
+
continue;
|
301 |
+
if ( $is_unique )
|
302 |
+
$table->keys->$key = explode( '`,`', $m[2] );
|
303 |
+
else
|
304 |
+
$table->uniques->$key = explode( '`,`', $m[2] );
|
305 |
+
}
|
306 |
+
|
307 |
+
$uniques = get_object_vars( $table->uniques );
|
308 |
+
foreach( $uniques as $idx => $val ) {
|
309 |
+
if ( is_array( $val ) && count( $val ) == 1 ) {
|
310 |
+
$pk_column_name = $val[0];
|
311 |
+
switch( strtolower( $table->columns->$pk_column_name->type ) ) {
|
312 |
+
// Integers, exact value
|
313 |
+
case 'tinyint':
|
314 |
+
case 'smallint':
|
315 |
+
case 'int':
|
316 |
+
case 'integer':
|
317 |
+
case 'bigint':
|
318 |
+
// Fixed point, exact value
|
319 |
+
case 'decimal':
|
320 |
+
case 'numeric':
|
321 |
+
// Floating point, approximate value
|
322 |
+
case 'float':
|
323 |
+
case 'double':
|
324 |
+
case 'real':
|
325 |
+
// Date and Time
|
326 |
+
case 'date':
|
327 |
+
case 'datetime':
|
328 |
+
case 'timestamp':
|
329 |
+
$table->single_int_paging_column = $pk_column_name;
|
330 |
+
break;
|
331 |
+
}
|
332 |
+
}
|
333 |
+
}
|
334 |
+
|
335 |
+
if ( empty( $table->primary ) ) {
|
336 |
+
if ( !empty( $uniques ) )
|
337 |
+
$table->primary = array_shift( $uniques );
|
338 |
+
}
|
339 |
+
|
340 |
+
return $table;
|
341 |
+
}
|
342 |
+
}
|
class.vaultpress-filesystem.php
CHANGED
@@ -48,8 +48,20 @@ class VaultPress_Filesystem {
|
|
48 |
header("Content-Type: application/octet-stream;");
|
49 |
header("Content-Transfer-Encoding: binary");
|
50 |
@ob_end_clean();
|
51 |
-
if ( !file_exists( $file ) || !is_readable( $file ) )
|
52 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
53 |
if ( !is_file( $file ) && !is_link( $file ) )
|
54 |
die( "can only dump files" );
|
55 |
$fp = @fopen( $file, 'rb' );
|
@@ -75,19 +87,33 @@ class VaultPress_Filesystem {
|
|
75 |
if ( $sha1 )
|
76 |
$rval['sha1'] = sha1_file( $file );
|
77 |
}
|
78 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
79 |
return $rval;
|
80 |
}
|
81 |
|
82 |
function ls( $what, $md5=false, $sha1=false, $limit=null, $offset=null ) {
|
83 |
clearstatcache();
|
84 |
$path = realpath($this->dir . $what);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
85 |
if ( is_file($path) )
|
86 |
return $this->stat( $path, $md5, $sha1 );
|
87 |
if ( is_dir($path) ) {
|
88 |
$entries = array();
|
89 |
$current = 0;
|
90 |
$offset = (int)$offset;
|
|
|
91 |
$limit = $offset + (int)$limit;
|
92 |
foreach ( (array)$this->scan_dir( $path ) as $i ) {
|
93 |
$current++;
|
@@ -95,6 +121,11 @@ class VaultPress_Filesystem {
|
|
95 |
continue;
|
96 |
if ( $limit && $limit < $current )
|
97 |
break;
|
|
|
|
|
|
|
|
|
|
|
98 |
$entries[] = $this->stat( $i, $md5, $sha1 );
|
99 |
}
|
100 |
return $entries;
|
@@ -103,11 +134,18 @@ class VaultPress_Filesystem {
|
|
103 |
|
104 |
function validate( $file ) {
|
105 |
$rpath = realpath( $this->dir.$file );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
106 |
if ( !$rpath )
|
107 |
die( serialize( array( 'type' => 'null', 'path' => $file ) ) );
|
108 |
if ( is_dir( $rpath ) )
|
109 |
$rpath = "$rpath/";
|
110 |
-
if ( strpos( $rpath, $
|
111 |
return false;
|
112 |
return true;
|
113 |
}
|
@@ -188,8 +226,17 @@ class VaultPress_Filesystem {
|
|
188 |
|
189 |
function scan_dir( $path ) {
|
190 |
$files = array();
|
|
|
|
|
|
|
|
|
|
|
191 |
$dh = opendir( $path );
|
192 |
|
|
|
|
|
|
|
|
|
193 |
while ( false !== ( $file = readdir( $dh ) ) ) {
|
194 |
if ( $file == '.' || $file == '..' ) continue;
|
195 |
$files[] = "$path/$file";
|
48 |
header("Content-Type: application/octet-stream;");
|
49 |
header("Content-Transfer-Encoding: binary");
|
50 |
@ob_end_clean();
|
51 |
+
if ( !file_exists( $file ) || !is_readable( $file ) ) {
|
52 |
+
$file_name = basename( $file );
|
53 |
+
if ( 'wp-config.php' == $file_name ) {
|
54 |
+
$dir = dirname( $file );
|
55 |
+
$dir = explode( DIRECTORY_SEPARATOR, $dir );
|
56 |
+
array_pop( $dir );
|
57 |
+
$dir = implode( DIRECTORY_SEPARATOR, $dir );
|
58 |
+
$file = trailingslashit( $dir ) . $file_name;
|
59 |
+
if ( !file_exists( $file ) || !is_readable( $file ) )
|
60 |
+
die( "no such file" );
|
61 |
+
} else {
|
62 |
+
die( "no such file" );
|
63 |
+
}
|
64 |
+
}
|
65 |
if ( !is_file( $file ) && !is_link( $file ) )
|
66 |
die( "can only dump files" );
|
67 |
$fp = @fopen( $file, 'rb' );
|
87 |
if ( $sha1 )
|
88 |
$rval['sha1'] = sha1_file( $file );
|
89 |
}
|
90 |
+
$dir = $this->dir;
|
91 |
+
if ( 0 !== strpos( $file, $dir ) && 'wp-config.php' == basename( $file ) ) {
|
92 |
+
$dir = explode( DIRECTORY_SEPARATOR, $dir );
|
93 |
+
array_pop( $dir );
|
94 |
+
$dir = implode( DIRECTORY_SEPARATOR, $dir );
|
95 |
+
}
|
96 |
+
$rval['path'] = str_replace( $dir, '', $file );
|
97 |
return $rval;
|
98 |
}
|
99 |
|
100 |
function ls( $what, $md5=false, $sha1=false, $limit=null, $offset=null ) {
|
101 |
clearstatcache();
|
102 |
$path = realpath($this->dir . $what);
|
103 |
+
$dir = $this->dir;
|
104 |
+
if ( !$path && '/wp-config.php' == $what ) {
|
105 |
+
$dir = explode( DIRECTORY_SEPARATOR, $dir );
|
106 |
+
array_pop( $dir );
|
107 |
+
$dir = implode( DIRECTORY_SEPARATOR, $dir );
|
108 |
+
$path = realpath( $dir . $what );
|
109 |
+
}
|
110 |
if ( is_file($path) )
|
111 |
return $this->stat( $path, $md5, $sha1 );
|
112 |
if ( is_dir($path) ) {
|
113 |
$entries = array();
|
114 |
$current = 0;
|
115 |
$offset = (int)$offset;
|
116 |
+
$orig_limit = (int)$limit;
|
117 |
$limit = $offset + (int)$limit;
|
118 |
foreach ( (array)$this->scan_dir( $path ) as $i ) {
|
119 |
$current++;
|
121 |
continue;
|
122 |
if ( $limit && $limit < $current )
|
123 |
break;
|
124 |
+
|
125 |
+
// don't sha1 files over 100MB if we are batching due to memory consumption
|
126 |
+
if ( $sha1 && $orig_limit > 1 && is_file( $i ) && (int)@filesize( $i ) > 104857600 )
|
127 |
+
$sha1 = false;
|
128 |
+
|
129 |
$entries[] = $this->stat( $i, $md5, $sha1 );
|
130 |
}
|
131 |
return $entries;
|
134 |
|
135 |
function validate( $file ) {
|
136 |
$rpath = realpath( $this->dir.$file );
|
137 |
+
$dir = $this->dir;
|
138 |
+
if ( !$rpath && '/wp-config.php' == $file ) {
|
139 |
+
$dir = explode( DIRECTORY_SEPARATOR, $dir );
|
140 |
+
array_pop( $dir );
|
141 |
+
$dir = implode( DIRECTORY_SEPARATOR, $dir );
|
142 |
+
$rpath = realpath( $dir . $file );
|
143 |
+
}
|
144 |
if ( !$rpath )
|
145 |
die( serialize( array( 'type' => 'null', 'path' => $file ) ) );
|
146 |
if ( is_dir( $rpath ) )
|
147 |
$rpath = "$rpath/";
|
148 |
+
if ( strpos( $rpath, $dir ) !== 0 )
|
149 |
return false;
|
150 |
return true;
|
151 |
}
|
226 |
|
227 |
function scan_dir( $path ) {
|
228 |
$files = array();
|
229 |
+
|
230 |
+
if ( false === is_readable( $path ) ) {
|
231 |
+
return array();
|
232 |
+
}
|
233 |
+
|
234 |
$dh = opendir( $path );
|
235 |
|
236 |
+
if ( false === $dh ) {
|
237 |
+
return array();
|
238 |
+
}
|
239 |
+
|
240 |
while ( false !== ( $file = readdir( $dh ) ) ) {
|
241 |
if ( $file == '.' || $file == '..' ) continue;
|
242 |
$files[] = "$path/$file";
|
class.vaultpress-hotfixes.php
CHANGED
@@ -14,7 +14,7 @@ class VaultPress_Hotfixes {
|
|
14 |
if ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST && version_compare( $wp_version, '3.0.3', '<' ) )
|
15 |
add_action( 'xmlrpc_call', array( $this, 'r16803' ) );
|
16 |
|
17 |
-
if ( version_compare( $wp_version, '3.
|
18 |
add_filter( 'pre_kses', array( $this, 'r17172_wp_kses' ), 1, 3 );
|
19 |
add_filter( 'clean_url', array( $this, 'r17172_esc_url' ), 1, 3 );
|
20 |
}
|
@@ -47,6 +47,180 @@ class VaultPress_Hotfixes {
|
|
47 |
add_filter( 'sanitize_option_new_admin_email', array( $this, 'r18346_sanitize_admin_email_on_save' ) );
|
48 |
}
|
49 |
add_filter( 'option_new_admin_email', array( $this, 'r18346_sanitize_admin_email' ) );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
50 |
}
|
51 |
|
52 |
function r16625( $query ) {
|
@@ -204,15 +378,21 @@ EOD;
|
|
204 |
|
205 |
function r17172_esc_url( $url, $original_url, $_context ) {
|
206 |
$url = $original_url;
|
|
|
207 |
if ( '' == $url )
|
208 |
return $url;
|
209 |
$url = preg_replace('|[^a-z0-9-~+_.?#=!&;,/:%@$\|*\'()\\x80-\\xff]|i', '', $url);
|
210 |
$strip = array('%0d', '%0a', '%0D', '%0A');
|
211 |
$url = _deep_replace($strip, $url);
|
212 |
$url = str_replace(';//', '://', $url);
|
213 |
-
|
214 |
-
|
|
|
|
|
|
|
|
|
215 |
$url = 'http://' . $url;
|
|
|
216 |
// Replace ampersands and single quotes only when displaying.
|
217 |
if ( 'display' == $_context ) {
|
218 |
$url = wp_kses_normalize_entities( $url );
|
@@ -226,6 +406,8 @@ EOD;
|
|
226 |
return $url;
|
227 |
}
|
228 |
|
|
|
|
|
229 |
function r17172_wp_kses( $string, $html, $protocols ) {
|
230 |
return VaultPress_kses::wp_kses( $string, $html, $protocols );
|
231 |
}
|
@@ -337,6 +519,7 @@ EOD;
|
|
337 |
}
|
338 |
}
|
339 |
|
|
|
340 |
$needs_class_fix = version_compare( $wp_version, '3.1', '>=') && version_compare( $wp_version, '3.1.3', '<' );
|
341 |
if ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST && $needs_class_fix ) {
|
342 |
include_once( ABSPATH . WPINC . '/class-IXR.php' );
|
@@ -366,12 +549,12 @@ class VaultPress_kses {
|
|
366 |
global $pass_allowed_html, $pass_allowed_protocols;
|
367 |
$pass_allowed_html = $allowed_html;
|
368 |
$pass_allowed_protocols = $allowed_protocols;
|
369 |
-
return preg_replace_callback( '%(
|
370 |
}
|
371 |
|
372 |
static function _vp_kses_split_callback( $match ) {
|
373 |
global $pass_allowed_html, $pass_allowed_protocols;
|
374 |
-
return VaultPress_kses::wp_kses_split2( $match[
|
375 |
}
|
376 |
|
377 |
static function wp_kses_split2($string, $allowed_html, $allowed_protocols) {
|
@@ -381,9 +564,9 @@ class VaultPress_kses {
|
|
381 |
return '>';
|
382 |
# It matched a ">" character
|
383 |
|
384 |
-
if (
|
385 |
-
$string = str_replace(array('<!--', '-->'), '', $
|
386 |
-
while ( $string != $newstring = VaultPress_kses::wp_kses($string, $allowed_html, $allowed_protocols) )
|
387 |
$string = $newstring;
|
388 |
if ( $string == '' )
|
389 |
return '';
|
@@ -403,15 +586,15 @@ class VaultPress_kses {
|
|
403 |
$elem = $matches[2];
|
404 |
$attrlist = $matches[3];
|
405 |
|
406 |
-
if (
|
407 |
return '';
|
408 |
# They are using a not allowed HTML element
|
409 |
|
410 |
if ($slash != '')
|
411 |
-
return "
|
412 |
# No attributes are allowed for closing elements
|
413 |
|
414 |
-
return VaultPress_kses::wp_kses_attr(
|
415 |
}
|
416 |
|
417 |
static function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols) {
|
@@ -422,60 +605,56 @@ class VaultPress_kses {
|
|
422 |
$xhtml_slash = ' /';
|
423 |
|
424 |
# Are any attributes allowed at all for this element?
|
425 |
-
|
426 |
-
if (@ count($allowed_html[strtolower($element)]) == 0)
|
427 |
return "<$element$xhtml_slash>";
|
428 |
|
429 |
# Split it
|
430 |
-
|
431 |
$attrarr = VaultPress_kses::wp_kses_hair($attr, $allowed_protocols);
|
432 |
|
433 |
# Go through $attrarr, and save the allowed attributes for this element
|
434 |
# in $attr2
|
435 |
-
|
436 |
$attr2 = '';
|
437 |
|
|
|
438 |
foreach ($attrarr as $arreach) {
|
439 |
-
if (
|
440 |
continue; # the attribute is not allowed
|
441 |
|
442 |
-
$current = $
|
443 |
-
if ($current == '')
|
444 |
continue; # the attribute is not allowed
|
445 |
|
446 |
-
if (
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
447 |
$attr2 .= ' '.$arreach['whole'];
|
448 |
# there are no checks
|
449 |
|
450 |
-
else {
|
451 |
# there are some checks
|
452 |
$ok = true;
|
453 |
-
foreach ($current as $currkey => $currval)
|
454 |
-
if (!wp_kses_check_attr_val($arreach['value'], $arreach['vless'], $currkey, $currval)) {
|
455 |
$ok = false;
|
456 |
break;
|
457 |
}
|
458 |
-
|
459 |
-
if ( strtolower($arreach['name']) == 'style' ) {
|
460 |
-
$orig_value = $arreach['value'];
|
461 |
-
|
462 |
-
$value = safecss_filter_attr($orig_value);
|
463 |
-
|
464 |
-
if ( empty($value) )
|
465 |
-
continue;
|
466 |
-
|
467 |
-
$arreach['value'] = $value;
|
468 |
-
|
469 |
-
$arreach['whole'] = str_replace($orig_value, $value, $arreach['whole']);
|
470 |
}
|
471 |
|
472 |
-
if ($ok)
|
473 |
$attr2 .= ' '.$arreach['whole']; # it passed them
|
474 |
} # if !is_array($current)
|
475 |
} # foreach
|
476 |
|
477 |
# Remove any "<" or ">" characters
|
478 |
-
|
479 |
$attr2 = preg_replace('/[<>]/', '', $attr2);
|
480 |
|
481 |
return "<$element$attr2$xhtml_slash>";
|
@@ -517,7 +696,7 @@ class VaultPress_kses {
|
|
517 |
{
|
518 |
$working = 1;
|
519 |
$mode = 0;
|
520 |
-
if(
|
521 |
$attrarr[$attrname] = array ('name' => $attrname, 'value' => '', 'whole' => $attrname, 'vless' => 'y');
|
522 |
}
|
523 |
$attr = preg_replace('/^\s+/', '', $attr);
|
@@ -534,7 +713,7 @@ class VaultPress_kses {
|
|
534 |
if ( in_array(strtolower($attrname), $uris) )
|
535 |
$thisval = VaultPress_kses::wp_kses_bad_protocol($thisval, $allowed_protocols);
|
536 |
|
537 |
-
if(
|
538 |
$attrarr[$attrname] = array ('name' => $attrname, 'value' => $thisval, 'whole' => "$attrname=\"$thisval\"", 'vless' => 'n');
|
539 |
}
|
540 |
$working = 1;
|
@@ -550,7 +729,7 @@ class VaultPress_kses {
|
|
550 |
if ( in_array(strtolower($attrname), $uris) )
|
551 |
$thisval = VaultPress_kses::wp_kses_bad_protocol($thisval, $allowed_protocols);
|
552 |
|
553 |
-
if(
|
554 |
$attrarr[$attrname] = array ('name' => $attrname, 'value' => $thisval, 'whole' => "$attrname='$thisval'", 'vless' => 'n');
|
555 |
}
|
556 |
$working = 1;
|
@@ -566,7 +745,7 @@ class VaultPress_kses {
|
|
566 |
if ( in_array(strtolower($attrname), $uris) )
|
567 |
$thisval = VaultPress_kses::wp_kses_bad_protocol($thisval, $allowed_protocols);
|
568 |
|
569 |
-
if(
|
570 |
$attrarr[$attrname] = array ('name' => $attrname, 'value' => $thisval, 'whole' => "$attrname=\"$thisval\"", 'vless' => 'n');
|
571 |
}
|
572 |
# We add quotes to conform to W3C's HTML spec.
|
@@ -585,7 +764,7 @@ class VaultPress_kses {
|
|
585 |
}
|
586 |
} # while
|
587 |
|
588 |
-
if ($mode == 1 &&
|
589 |
# special case, for when the attribute list ends with a valueless
|
590 |
# attribute like "selected"
|
591 |
$attrarr[$attrname] = array ('name' => $attrname, 'value' => '', 'whole' => $attrname, 'vless' => 'y');
|
@@ -595,20 +774,33 @@ class VaultPress_kses {
|
|
595 |
|
596 |
static function wp_kses_bad_protocol($string, $allowed_protocols) {
|
597 |
$string = wp_kses_no_null($string);
|
598 |
-
$
|
599 |
|
600 |
-
|
601 |
-
$
|
602 |
$string = VaultPress_kses::wp_kses_bad_protocol_once($string, $allowed_protocols);
|
603 |
-
}
|
|
|
|
|
|
|
604 |
|
605 |
return $string;
|
606 |
}
|
607 |
|
608 |
-
static function wp_kses_bad_protocol_once($string, $allowed_protocols) {
|
609 |
$string2 = preg_split( '/:|�*58;|�*3a;/i', $string, 2 );
|
610 |
-
if ( isset($string2[1]) && ! preg_match('%/\?%', $string2[0]) )
|
611 |
-
$string =
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
612 |
|
613 |
return $string;
|
614 |
}
|
@@ -620,12 +812,11 @@ class VaultPress_kses {
|
|
620 |
$string2 = strtolower($string2);
|
621 |
|
622 |
$allowed = false;
|
623 |
-
foreach ( (array) $allowed_protocols as $one_protocol )
|
624 |
-
if ( strtolower($one_protocol)
|
625 |
-
|
626 |
-
|
627 |
-
|
628 |
-
}
|
629 |
|
630 |
if ($allowed)
|
631 |
return "$string2:";
|
@@ -634,3 +825,13 @@ class VaultPress_kses {
|
|
634 |
}
|
635 |
|
636 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
14 |
if ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST && version_compare( $wp_version, '3.0.3', '<' ) )
|
15 |
add_action( 'xmlrpc_call', array( $this, 'r16803' ) );
|
16 |
|
17 |
+
if ( version_compare( $wp_version, '3.3.2', '<' ) ) {
|
18 |
add_filter( 'pre_kses', array( $this, 'r17172_wp_kses' ), 1, 3 );
|
19 |
add_filter( 'clean_url', array( $this, 'r17172_esc_url' ), 1, 3 );
|
20 |
}
|
47 |
add_filter( 'sanitize_option_new_admin_email', array( $this, 'r18346_sanitize_admin_email_on_save' ) );
|
48 |
}
|
49 |
add_filter( 'option_new_admin_email', array( $this, 'r18346_sanitize_admin_email' ) );
|
50 |
+
|
51 |
+
if ( version_compare( $wp_version, '3.3.2', '<' ) ) {
|
52 |
+
remove_filter( 'comment_text', 'make_clickable' );
|
53 |
+
add_filter( 'comment_text', array( $this, 'r20493_make_clickable' ), 9 );
|
54 |
+
|
55 |
+
add_filter( 'comment_post_redirect', array( $this, 'r20486_comment_post_redirect' ) );
|
56 |
+
}
|
57 |
+
|
58 |
+
// WooThemes < 3.8.3, foxypress, asset-manager, wordpress-member-private-conversation.
|
59 |
+
$end_execution = false;
|
60 |
+
if ( isset( $_SERVER['SCRIPT_FILENAME'] ) )
|
61 |
+
foreach ( array( 'preview-shortcode-external.php', 'uploadify.php', 'doupload.php', 'cef-upload.php', 'upload.php' ) as $vulnerable_script )
|
62 |
+
if ( $vulnerable_script == basename( $_SERVER['SCRIPT_FILENAME'] ) ) {
|
63 |
+
switch( $vulnerable_script ) {
|
64 |
+
case 'upload.php':
|
65 |
+
$pma_config_file = realpath( dirname( $_SERVER['SCRIPT_FILENAME'] ) . DIRECTORY_SEPARATOR . 'paam-config-ajax.php' );
|
66 |
+
if ( !in_array( $pma_config_file, get_included_files() ) )
|
67 |
+
break;
|
68 |
+
default:
|
69 |
+
$end_execution = true;
|
70 |
+
break 2;
|
71 |
+
}
|
72 |
+
}
|
73 |
+
if ( $end_execution )
|
74 |
+
die( 'Disabled for security reasons' );
|
75 |
+
|
76 |
+
if ( version_compare( $wp_version, '3.3.2', '>') && version_compare( $wp_version, '3.4.1', '<' ) ) {
|
77 |
+
add_filter( 'map_meta_cap', array( $this, 'r21138_xmlrpc_edit_posts' ), 10, 4 );
|
78 |
+
add_action( 'map_meta_cap', array( $this, 'r21152_unfiltered_html' ), 10, 4 );
|
79 |
+
}
|
80 |
+
|
81 |
+
// https://core.trac.wordpress.org/changeset/21083
|
82 |
+
if ( version_compare( $wp_version, '3.3', '>=') && version_compare( $wp_version, '3.3.3', '<' ) )
|
83 |
+
add_filter( 'editable_slug', 'esc_textarea' );
|
84 |
+
|
85 |
+
add_filter( 'get_pagenum_link', array( $this, 'get_pagenum_link' ) );
|
86 |
+
}
|
87 |
+
|
88 |
+
function r21138_xmlrpc_edit_posts( $caps, $cap, $user_id, $args ) {
|
89 |
+
if ( ! isset( $args[0] ) || isset( $args[1] ) && $args[1] === 'hotfixed' )
|
90 |
+
return $caps;
|
91 |
+
foreach ( get_post_types( array(), 'objects' ) as $post_type_object ) {
|
92 |
+
if ( $cap === $post_type_object->cap->edit_posts )
|
93 |
+
return map_meta_cap( $post_type_object->cap->edit_post, $user_id, $args[0], 'hotfixed' );
|
94 |
+
}
|
95 |
+
return $caps;
|
96 |
+
}
|
97 |
+
|
98 |
+
function r21152_unfiltered_html( $caps, $cap, $user_id, $args ) {
|
99 |
+
if ( $cap !== 'unfiltered_html' )
|
100 |
+
return $caps;
|
101 |
+
if ( defined( 'DISALLOW_UNFILTERED_HTML' ) && DISALLOW_UNFILTERED_HTML )
|
102 |
+
return $caps;
|
103 |
+
$key = array_search( 'do_not_allow', $caps );
|
104 |
+
if ( false !== $key )
|
105 |
+
return $caps;
|
106 |
+
if ( is_multisite() && ! is_super_admin( $user_id ) )
|
107 |
+
$caps[$key] = 'do_not_allow';
|
108 |
+
return $caps;
|
109 |
+
}
|
110 |
+
|
111 |
+
function get_pagenum_link( $url ) {
|
112 |
+
return esc_url_raw( $url );
|
113 |
+
}
|
114 |
+
|
115 |
+
function r20486_comment_post_redirect( $location ) {
|
116 |
+
$location = wp_sanitize_redirect( $location );
|
117 |
+
$location = wp_validate_redirect( $location, admin_url() );
|
118 |
+
|
119 |
+
return $location;
|
120 |
+
}
|
121 |
+
|
122 |
+
function r20493_make_clickable( $text ) {
|
123 |
+
$r = '';
|
124 |
+
$textarr = preg_split( '/(<[^<>]+>)/', $text, -1, PREG_SPLIT_DELIM_CAPTURE ); // split out HTML tags
|
125 |
+
foreach ( $textarr as $piece ) {
|
126 |
+
if ( empty( $piece ) || ( $piece[0] == '<' && ! preg_match('|^<\s*[\w]{1,20}+://|', $piece) ) ) {
|
127 |
+
$r .= $piece;
|
128 |
+
continue;
|
129 |
+
}
|
130 |
+
|
131 |
+
// Long strings might contain expensive edge cases ...
|
132 |
+
if ( 10000 < strlen( $piece ) ) {
|
133 |
+
// ... break it up
|
134 |
+
foreach ( $this->r20493_split_str_by_whitespace( $piece, 2100 ) as $chunk ) { // 2100: Extra room for scheme and leading and trailing paretheses
|
135 |
+
if ( 2101 < strlen( $chunk ) ) {
|
136 |
+
$r .= $chunk; // Too big, no whitespace: bail.
|
137 |
+
} else {
|
138 |
+
$r .= $this->r20493_make_clickable( $chunk );
|
139 |
+
}
|
140 |
+
}
|
141 |
+
} else {
|
142 |
+
$ret = " $piece "; // Pad with whitespace to simplify the regexes
|
143 |
+
|
144 |
+
$url_clickable = '~
|
145 |
+
([\\s(<.,;:!?]) # 1: Leading whitespace, or punctuation
|
146 |
+
( # 2: URL
|
147 |
+
[\\w]{1,20}+:// # Scheme and hier-part prefix
|
148 |
+
(?=\S{1,2000}\s) # Limit to URLs less than about 2000 characters long
|
149 |
+
[\\w\\x80-\\xff#%\\~/@\\[\\]*(+=&$-]*+ # Non-punctuation URL character
|
150 |
+
(?: # Unroll the Loop: Only allow puctuation URL character if followed by a non-punctuation URL character
|
151 |
+
[\'.,;:!?)] # Punctuation URL character
|
152 |
+
[\\w\\x80-\\xff#%\\~/@\\[\\]*(+=&$-]++ # Non-punctuation URL character
|
153 |
+
)*
|
154 |
+
)
|
155 |
+
(\)?) # 3: Trailing closing parenthesis (for parethesis balancing post processing)
|
156 |
+
~xS'; // The regex is a non-anchored pattern and does not have a single fixed starting character.
|
157 |
+
// Tell PCRE to spend more time optimizing since, when used on a page load, it will probably be used several times.
|
158 |
+
|
159 |
+
$ret = preg_replace_callback( $url_clickable, array( $this, 'r20493_make_url_clickable_cb') , $ret );
|
160 |
+
|
161 |
+
$ret = preg_replace_callback( '#([\s>])((www|ftp)\.[\w\\x80-\\xff\#$%&~/.\-;:=,?@\[\]+]+)#is', '_make_web_ftp_clickable_cb', $ret );
|
162 |
+
$ret = preg_replace_callback( '#([\s>])([.0-9a-z_+-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,})#i', '_make_email_clickable_cb', $ret );
|
163 |
+
|
164 |
+
$ret = substr( $ret, 1, -1 ); // Remove our whitespace padding.
|
165 |
+
$r .= $ret;
|
166 |
+
}
|
167 |
+
}
|
168 |
+
|
169 |
+
// Cleanup of accidental links within links
|
170 |
+
$r = preg_replace( '#(<a( [^>]+?>|>))<a [^>]+?>([^>]+?)</a></a>#i', "$1$3</a>", $r );
|
171 |
+
return $r;
|
172 |
+
}
|
173 |
+
|
174 |
+
function r20493_make_url_clickable_cb($matches) {
|
175 |
+
$url = $matches[2];
|
176 |
+
|
177 |
+
if ( ')' == $matches[3] && strpos( $url, '(' ) ) {
|
178 |
+
// If the trailing character is a closing parethesis, and the URL has an opening parenthesis in it, add the closing parenthesis to the URL.
|
179 |
+
// Then we can let the parenthesis balancer do its thing below.
|
180 |
+
$url .= $matches[3];
|
181 |
+
$suffix = '';
|
182 |
+
} else {
|
183 |
+
$suffix = $matches[3];
|
184 |
+
}
|
185 |
+
|
186 |
+
// Include parentheses in the URL only if paired
|
187 |
+
while ( substr_count( $url, '(' ) < substr_count( $url, ')' ) ) {
|
188 |
+
$suffix = strrchr( $url, ')' ) . $suffix;
|
189 |
+
$url = substr( $url, 0, strrpos( $url, ')' ) );
|
190 |
+
}
|
191 |
+
|
192 |
+
$url = esc_url($url);
|
193 |
+
if ( empty($url) )
|
194 |
+
return $matches[0];
|
195 |
+
|
196 |
+
return $matches[1] . "<a href=\"$url\" rel=\"nofollow\">$url</a>" . $suffix;
|
197 |
+
}
|
198 |
+
|
199 |
+
function r20493_split_str_by_whitespace( $string, $goal ) {
|
200 |
+
$chunks = array();
|
201 |
+
|
202 |
+
$string_nullspace = strtr( $string, "\r\n\t\v\f ", "\000\000\000\000\000\000" );
|
203 |
+
|
204 |
+
while ( $goal < strlen( $string_nullspace ) ) {
|
205 |
+
$pos = strrpos( substr( $string_nullspace, 0, $goal + 1 ), "\000" );
|
206 |
+
|
207 |
+
if ( false === $pos ) {
|
208 |
+
$pos = strpos( $string_nullspace, "\000", $goal + 1 );
|
209 |
+
if ( false === $pos ) {
|
210 |
+
break;
|
211 |
+
}
|
212 |
+
}
|
213 |
+
|
214 |
+
$chunks[] = substr( $string, 0, $pos + 1 );
|
215 |
+
$string = substr( $string, $pos + 1 );
|
216 |
+
$string_nullspace = substr( $string_nullspace, $pos + 1 );
|
217 |
+
}
|
218 |
+
|
219 |
+
if ( $string ) {
|
220 |
+
$chunks[] = $string;
|
221 |
+
}
|
222 |
+
|
223 |
+
return $chunks;
|
224 |
}
|
225 |
|
226 |
function r16625( $query ) {
|
378 |
|
379 |
function r17172_esc_url( $url, $original_url, $_context ) {
|
380 |
$url = $original_url;
|
381 |
+
|
382 |
if ( '' == $url )
|
383 |
return $url;
|
384 |
$url = preg_replace('|[^a-z0-9-~+_.?#=!&;,/:%@$\|*\'()\\x80-\\xff]|i', '', $url);
|
385 |
$strip = array('%0d', '%0a', '%0D', '%0A');
|
386 |
$url = _deep_replace($strip, $url);
|
387 |
$url = str_replace(';//', '://', $url);
|
388 |
+
/* If the URL doesn't appear to contain a scheme, we
|
389 |
+
* presume it needs http:// appended (unless a relative
|
390 |
+
* link starting with /, # or ? or a php file).
|
391 |
+
*/
|
392 |
+
if ( strpos($url, ':') === false && ! in_array( $url[0], array( '/', '#', '?' ) ) &&
|
393 |
+
! preg_match('/^[a-z0-9-]+?\.php/i', $url) )
|
394 |
$url = 'http://' . $url;
|
395 |
+
|
396 |
// Replace ampersands and single quotes only when displaying.
|
397 |
if ( 'display' == $_context ) {
|
398 |
$url = wp_kses_normalize_entities( $url );
|
406 |
return $url;
|
407 |
}
|
408 |
|
409 |
+
// http://core.trac.wordpress.org/changeset/17172
|
410 |
+
// http://core.trac.wordpress.org/changeset/20541
|
411 |
function r17172_wp_kses( $string, $html, $protocols ) {
|
412 |
return VaultPress_kses::wp_kses( $string, $html, $protocols );
|
413 |
}
|
519 |
}
|
520 |
}
|
521 |
|
522 |
+
global $wp_version;
|
523 |
$needs_class_fix = version_compare( $wp_version, '3.1', '>=') && version_compare( $wp_version, '3.1.3', '<' );
|
524 |
if ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST && $needs_class_fix ) {
|
525 |
include_once( ABSPATH . WPINC . '/class-IXR.php' );
|
549 |
global $pass_allowed_html, $pass_allowed_protocols;
|
550 |
$pass_allowed_html = $allowed_html;
|
551 |
$pass_allowed_protocols = $allowed_protocols;
|
552 |
+
return preg_replace_callback( '%(<!--.*?(-->|$))|(<[^>]*(>|$)|>)%', 'VaultPress_kses::_vp_kses_split_callback', $string );
|
553 |
}
|
554 |
|
555 |
static function _vp_kses_split_callback( $match ) {
|
556 |
global $pass_allowed_html, $pass_allowed_protocols;
|
557 |
+
return VaultPress_kses::wp_kses_split2( $match[0], $pass_allowed_html, $pass_allowed_protocols );
|
558 |
}
|
559 |
|
560 |
static function wp_kses_split2($string, $allowed_html, $allowed_protocols) {
|
564 |
return '>';
|
565 |
# It matched a ">" character
|
566 |
|
567 |
+
if ( '<!--' == substr( $string, 0, 4 ) ) {
|
568 |
+
$string = str_replace( array('<!--', '-->'), '', $string );
|
569 |
+
while ( $string != ($newstring = VaultPress_kses::wp_kses($string, $allowed_html, $allowed_protocols)) )
|
570 |
$string = $newstring;
|
571 |
if ( $string == '' )
|
572 |
return '';
|
586 |
$elem = $matches[2];
|
587 |
$attrlist = $matches[3];
|
588 |
|
589 |
+
if ( ! isset($allowed_html[strtolower($elem)]) )
|
590 |
return '';
|
591 |
# They are using a not allowed HTML element
|
592 |
|
593 |
if ($slash != '')
|
594 |
+
return "</$elem>";
|
595 |
# No attributes are allowed for closing elements
|
596 |
|
597 |
+
return VaultPress_kses::wp_kses_attr( $elem, $attrlist, $allowed_html, $allowed_protocols );
|
598 |
}
|
599 |
|
600 |
static function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols) {
|
605 |
$xhtml_slash = ' /';
|
606 |
|
607 |
# Are any attributes allowed at all for this element?
|
608 |
+
if ( ! isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0 )
|
|
|
609 |
return "<$element$xhtml_slash>";
|
610 |
|
611 |
# Split it
|
|
|
612 |
$attrarr = VaultPress_kses::wp_kses_hair($attr, $allowed_protocols);
|
613 |
|
614 |
# Go through $attrarr, and save the allowed attributes for this element
|
615 |
# in $attr2
|
|
|
616 |
$attr2 = '';
|
617 |
|
618 |
+
$allowed_attr = $allowed_html[strtolower($element)];
|
619 |
foreach ($attrarr as $arreach) {
|
620 |
+
if ( ! isset( $allowed_attr[strtolower($arreach['name'])] ) )
|
621 |
continue; # the attribute is not allowed
|
622 |
|
623 |
+
$current = $allowed_attr[strtolower($arreach['name'])];
|
624 |
+
if ( $current == '' )
|
625 |
continue; # the attribute is not allowed
|
626 |
|
627 |
+
if ( strtolower( $arreach['name'] ) == 'style' ) {
|
628 |
+
$orig_value = $arreach['value'];
|
629 |
+
$value = safecss_filter_attr( $orig_value );
|
630 |
+
|
631 |
+
if ( empty( $value ) )
|
632 |
+
continue;
|
633 |
+
|
634 |
+
$arreach['value'] = $value;
|
635 |
+
$arreach['whole'] = str_replace( $orig_value, $value, $arreach['whole'] );
|
636 |
+
}
|
637 |
+
|
638 |
+
if ( ! is_array($current) ) {
|
639 |
$attr2 .= ' '.$arreach['whole'];
|
640 |
# there are no checks
|
641 |
|
642 |
+
} else {
|
643 |
# there are some checks
|
644 |
$ok = true;
|
645 |
+
foreach ($current as $currkey => $currval) {
|
646 |
+
if ( ! wp_kses_check_attr_val($arreach['value'], $arreach['vless'], $currkey, $currval) ) {
|
647 |
$ok = false;
|
648 |
break;
|
649 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
650 |
}
|
651 |
|
652 |
+
if ( $ok )
|
653 |
$attr2 .= ' '.$arreach['whole']; # it passed them
|
654 |
} # if !is_array($current)
|
655 |
} # foreach
|
656 |
|
657 |
# Remove any "<" or ">" characters
|
|
|
658 |
$attr2 = preg_replace('/[<>]/', '', $attr2);
|
659 |
|
660 |
return "<$element$attr2$xhtml_slash>";
|
696 |
{
|
697 |
$working = 1;
|
698 |
$mode = 0;
|
699 |
+
if(false === array_key_exists($attrname, $attrarr)) {
|
700 |
$attrarr[$attrname] = array ('name' => $attrname, 'value' => '', 'whole' => $attrname, 'vless' => 'y');
|
701 |
}
|
702 |
$attr = preg_replace('/^\s+/', '', $attr);
|
713 |
if ( in_array(strtolower($attrname), $uris) )
|
714 |
$thisval = VaultPress_kses::wp_kses_bad_protocol($thisval, $allowed_protocols);
|
715 |
|
716 |
+
if(false === array_key_exists($attrname, $attrarr)) {
|
717 |
$attrarr[$attrname] = array ('name' => $attrname, 'value' => $thisval, 'whole' => "$attrname=\"$thisval\"", 'vless' => 'n');
|
718 |
}
|
719 |
$working = 1;
|
729 |
if ( in_array(strtolower($attrname), $uris) )
|
730 |
$thisval = VaultPress_kses::wp_kses_bad_protocol($thisval, $allowed_protocols);
|
731 |
|
732 |
+
if(false === array_key_exists($attrname, $attrarr)) {
|
733 |
$attrarr[$attrname] = array ('name' => $attrname, 'value' => $thisval, 'whole' => "$attrname='$thisval'", 'vless' => 'n');
|
734 |
}
|
735 |
$working = 1;
|
745 |
if ( in_array(strtolower($attrname), $uris) )
|
746 |
$thisval = VaultPress_kses::wp_kses_bad_protocol($thisval, $allowed_protocols);
|
747 |
|
748 |
+
if(false === array_key_exists($attrname, $attrarr)) {
|
749 |
$attrarr[$attrname] = array ('name' => $attrname, 'value' => $thisval, 'whole' => "$attrname=\"$thisval\"", 'vless' => 'n');
|
750 |
}
|
751 |
# We add quotes to conform to W3C's HTML spec.
|
764 |
}
|
765 |
} # while
|
766 |
|
767 |
+
if ($mode == 1 && false === array_key_exists($attrname, $attrarr))
|
768 |
# special case, for when the attribute list ends with a valueless
|
769 |
# attribute like "selected"
|
770 |
$attrarr[$attrname] = array ('name' => $attrname, 'value' => '', 'whole' => $attrname, 'vless' => 'y');
|
774 |
|
775 |
static function wp_kses_bad_protocol($string, $allowed_protocols) {
|
776 |
$string = wp_kses_no_null($string);
|
777 |
+
$iterations = 0;
|
778 |
|
779 |
+
do {
|
780 |
+
$original_string = $string;
|
781 |
$string = VaultPress_kses::wp_kses_bad_protocol_once($string, $allowed_protocols);
|
782 |
+
} while ( $original_string != $string && ++$iterations < 6 );
|
783 |
+
|
784 |
+
if ( $original_string != $string )
|
785 |
+
return '';
|
786 |
|
787 |
return $string;
|
788 |
}
|
789 |
|
790 |
+
static function wp_kses_bad_protocol_once($string, $allowed_protocols, $count = 1) {
|
791 |
$string2 = preg_split( '/:|�*58;|�*3a;/i', $string, 2 );
|
792 |
+
if ( isset($string2[1]) && ! preg_match('%/\?%', $string2[0]) ) {
|
793 |
+
$string = trim( $string2[1] );
|
794 |
+
$protocol = VaultPress_kses::wp_kses_bad_protocol_once2( $string2[0], $allowed_protocols );
|
795 |
+
if ( 'feed:' == $protocol ) {
|
796 |
+
if ( $count > 2 )
|
797 |
+
return '';
|
798 |
+
$string = VaultPress_kses::wp_kses_bad_protocol_once( $string, $allowed_protocols, ++$count );
|
799 |
+
if ( empty( $string ) )
|
800 |
+
return $string;
|
801 |
+
}
|
802 |
+
$string = $protocol . $string;
|
803 |
+
}
|
804 |
|
805 |
return $string;
|
806 |
}
|
812 |
$string2 = strtolower($string2);
|
813 |
|
814 |
$allowed = false;
|
815 |
+
foreach ( (array) $allowed_protocols as $one_protocol )
|
816 |
+
if ( strtolower($one_protocol) == $string2 ) {
|
817 |
+
$allowed = true;
|
818 |
+
break;
|
819 |
+
}
|
|
|
820 |
|
821 |
if ($allowed)
|
822 |
return "$string2:";
|
825 |
}
|
826 |
|
827 |
}
|
828 |
+
|
829 |
+
if ( !function_exists( 'get_available_languages' ) ) {
|
830 |
+
function get_available_languages( $dir = null ) {
|
831 |
+
$languages = array();
|
832 |
+
foreach( glob( ( is_null( $dir) ? WP_LANG_DIR : $dir ) . '/*.mo' ) as $lang_file )
|
833 |
+
if ( false === strpos( $lang_file, 'continents-cities' ) )
|
834 |
+
$languages[] = basename($lang_file, '.mo');
|
835 |
+
return $languages;
|
836 |
+
}
|
837 |
+
}
|
class.vaultpress-ixr-ssl-client.php
CHANGED
@@ -39,7 +39,7 @@ class VaultPress_IXR_SSL_Client extends IXR_Client {
|
|
39 |
'method' => 'POST',
|
40 |
'body' => $xml,
|
41 |
'headers' => $this->headers,
|
42 |
-
'sslverify' =>
|
43 |
);
|
44 |
if ( $this->timeout )
|
45 |
$args['timeout'] = $this->timeout;
|
@@ -129,4 +129,4 @@ class VaultPress_IXR_SSL_Client extends IXR_Client {
|
|
129 |
// Message must be OK
|
130 |
return true;
|
131 |
}
|
132 |
-
}
|
39 |
'method' => 'POST',
|
40 |
'body' => $xml,
|
41 |
'headers' => $this->headers,
|
42 |
+
'sslverify' => true,
|
43 |
);
|
44 |
if ( $this->timeout )
|
45 |
$args['timeout'] = $this->timeout;
|
129 |
// Message must be OK
|
130 |
return true;
|
131 |
}
|
132 |
+
}
|
cron-tasks.php
CHANGED
@@ -1,40 +1,116 @@
|
|
1 |
<?php
|
2 |
include_once dirname( __FILE__ ) . '/vp-scanner.php';
|
3 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
|
5 |
class VP_Site_Scanner {
|
6 |
function VP_Site_Scanner() {
|
7 |
self::__construct();
|
8 |
}
|
9 |
function __construct() {
|
10 |
-
|
11 |
-
|
12 |
-
|
|
|
|
|
|
|
13 |
|
14 |
$signatures = get_option( '_vp_signatures' );
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
}
|
20 |
|
21 |
function _custom_cron( $schedules ) {
|
22 |
-
$schedules['
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
return $schedules;
|
27 |
}
|
28 |
|
29 |
function _scan_site() {
|
30 |
-
if ( !
|
31 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
32 |
}
|
33 |
|
34 |
function _scan_batch() {
|
35 |
-
|
36 |
-
|
37 |
-
|
|
|
|
|
|
|
|
|
|
|
38 |
|
39 |
$default_batch_limit = 400;
|
40 |
if ( function_exists( 'set_time_limit' ) )
|
@@ -42,36 +118,36 @@ class VP_Site_Scanner {
|
|
42 |
else
|
43 |
$default_batch_limit = 100; // avoid timeouts
|
44 |
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
|
|
|
|
49 |
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
}
|
54 |
|
|
|
55 |
$results = array();
|
56 |
-
|
57 |
$verdict = vp_scan_file( $file );
|
58 |
if ( !empty( $verdict ) )
|
59 |
-
|
60 |
-
|
61 |
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
}
|
67 |
|
68 |
-
function &init() {
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
}
|
77 |
VP_Site_Scanner::init();
|
1 |
<?php
|
2 |
include_once dirname( __FILE__ ) . '/vp-scanner.php';
|
3 |
|
4 |
+
if ( !function_exists( 'apply_filters_ref_array' ) ) :
|
5 |
+
|
6 |
+
function apply_filters_ref_array($tag, $args) {
|
7 |
+
global $wp_filter, $merged_filters, $wp_current_filter;
|
8 |
+
|
9 |
+
// Do 'all' actions first
|
10 |
+
if ( isset($wp_filter['all']) ) {
|
11 |
+
$wp_current_filter[] = $tag;
|
12 |
+
$all_args = func_get_args();
|
13 |
+
_wp_call_all_hook($all_args);
|
14 |
+
}
|
15 |
+
|
16 |
+
if ( !isset($wp_filter[$tag]) ) {
|
17 |
+
if ( isset($wp_filter['all']) )
|
18 |
+
array_pop($wp_current_filter);
|
19 |
+
return $args[0];
|
20 |
+
}
|
21 |
+
|
22 |
+
if ( !isset($wp_filter['all']) )
|
23 |
+
$wp_current_filter[] = $tag;
|
24 |
+
|
25 |
+
// Sort
|
26 |
+
if ( !isset( $merged_filters[ $tag ] ) ) {
|
27 |
+
ksort($wp_filter[$tag]);
|
28 |
+
$merged_filters[ $tag ] = true;
|
29 |
+
}
|
30 |
+
|
31 |
+
reset( $wp_filter[ $tag ] );
|
32 |
+
|
33 |
+
do {
|
34 |
+
foreach( (array) current($wp_filter[$tag]) as $the_ )
|
35 |
+
if ( !is_null($the_['function']) )
|
36 |
+
$args[0] = call_user_func_array($the_['function'], array_slice($args, 0, (int) $the_['accepted_args']));
|
37 |
+
|
38 |
+
} while ( next($wp_filter[$tag]) !== false );
|
39 |
+
|
40 |
+
array_pop( $wp_current_filter );
|
41 |
+
|
42 |
+
return $args[0];
|
43 |
+
}
|
44 |
+
|
45 |
+
endif;
|
46 |
|
47 |
class VP_Site_Scanner {
|
48 |
function VP_Site_Scanner() {
|
49 |
self::__construct();
|
50 |
}
|
51 |
function __construct() {
|
52 |
+
// Only scan once in multisites.
|
53 |
+
if( function_exists( 'is_main_site' ) && !is_main_site() )
|
54 |
+
return;
|
55 |
+
add_action( 'vp_scan_site' , array( $this, '_scan_site') );
|
56 |
+
add_filter( 'cron_schedules' , array( $this, '_custom_cron' ) );
|
57 |
+
add_action( 'vp_scan_next_batch', array( $this, '_scan_batch' ) );
|
58 |
|
59 |
$signatures = get_option( '_vp_signatures' );
|
60 |
+
if ( $signatures && ! wp_next_scheduled( 'vp_scan_site' ) )
|
61 |
+
wp_schedule_event( time(), 'daily', 'vp_scan_site' );
|
62 |
+
if ( $signatures && ! wp_next_scheduled( 'vp_scan_next_batch' ) )
|
63 |
+
wp_schedule_event( time(), 'five_minutes_interval', 'vp_scan_next_batch' );
|
64 |
}
|
65 |
|
66 |
function _custom_cron( $schedules ) {
|
67 |
+
$schedules['five_minutes_interval'] = array(
|
68 |
+
'interval' => 300,
|
69 |
+
'display' => __( 'Once every five minutes' , 'vaultpress'),
|
70 |
+
);
|
71 |
return $schedules;
|
72 |
}
|
73 |
|
74 |
function _scan_site() {
|
75 |
+
if ( !get_option( '_vp_current_scan' ) ) {
|
76 |
+
$ignore_symlinks = get_option( '_vp_ignore_symlinks', false );
|
77 |
+
$paths = array( 'root' => new VP_FileScan( ABSPATH, $ignore_symlinks ) );
|
78 |
+
|
79 |
+
// Is WP_CONTENT_DIR inside ABSPATH?
|
80 |
+
if ( is_dir( WP_CONTENT_DIR ) && strpos( realpath( WP_CONTENT_DIR ), realpath( ABSPATH ) . DIRECTORY_SEPARATOR ) !== 0 )
|
81 |
+
$paths['content'] = new VP_FileScan( WP_CONTENT_DIR, $ignore_symlinks );
|
82 |
+
|
83 |
+
// Is WP_PLUGIN_DIR inside ABSPATH or WP_CONTENT_DIR?
|
84 |
+
if ( is_dir( WP_PLUGIN_DIR ) && strpos( realpath( WP_PLUGIN_DIR ), realpath( WP_CONTENT_DIR ) . DIRECTORY_SEPARATOR ) !== 0 && strpos( realpath( WP_PLUGIN_DIR ), realpath( ABSPATH ) . DIRECTORY_SEPARATOR ) !== 0 )
|
85 |
+
$paths['plugins'] = new VP_FileScan( WP_PLUGIN_DIR, $ignore_symlinks );
|
86 |
+
|
87 |
+
// Is WPMU_PLUGIN_DIR inside ABSPATH or WP_CONTENT_DIR?
|
88 |
+
if ( is_dir( WPMU_PLUGIN_DIR ) && strpos( realpath( WPMU_PLUGIN_DIR ), realpath( WP_CONTENT_DIR ) . DIRECTORY_SEPARATOR ) !== 0 && strpos( realpath( WPMU_PLUGIN_DIR ), realpath( ABSPATH ) . DIRECTORY_SEPARATOR ) !== 0 )
|
89 |
+
$paths['mu-plugins'] = new VP_FileScan( WPMU_PLUGIN_DIR, $ignore_symlinks );
|
90 |
+
|
91 |
+
update_option( '_vp_current_scan', $paths );
|
92 |
+
}
|
93 |
+
}
|
94 |
+
|
95 |
+
function _scan_clean_up( &$paths, $type = null ) {
|
96 |
+
if( is_array( $paths ) )
|
97 |
+
unset( $paths[$type] );
|
98 |
+
if ( empty( $paths ) || !is_array( $paths ) ) {
|
99 |
+
delete_option( '_vp_current_scan' );
|
100 |
+
return true;
|
101 |
+
}
|
102 |
+
return false;
|
103 |
}
|
104 |
|
105 |
function _scan_batch() {
|
106 |
+
$paths = get_option( '_vp_current_scan' );
|
107 |
+
if ( empty( $paths ) || $this->_scan_clean_up( $paths ) )
|
108 |
+
return false;
|
109 |
+
|
110 |
+
reset( $paths );
|
111 |
+
list( $type, $current ) = each( $paths );
|
112 |
+
if ( !is_object( $current ) || empty( $current->last_dir ) )
|
113 |
+
return $this->_scan_clean_up( $paths, $type );
|
114 |
|
115 |
$default_batch_limit = 400;
|
116 |
if ( function_exists( 'set_time_limit' ) )
|
118 |
else
|
119 |
$default_batch_limit = 100; // avoid timeouts
|
120 |
|
121 |
+
$GLOBALS['vp_signatures'] = get_option( '_vp_signatures' );
|
122 |
+
if ( empty( $GLOBALS['vp_signatures'] ) )
|
123 |
+
return false;
|
124 |
+
|
125 |
+
$limit = get_option( '_vp_batch_file_size', $default_batch_limit );
|
126 |
+
$files = $current->get_files( $limit );
|
127 |
|
128 |
+
// No more files to scan.
|
129 |
+
if ( !$current->last_dir || count( $files ) < $limit )
|
130 |
+
unset( $paths[$type] );
|
|
|
131 |
|
132 |
+
update_option( '_vp_current_scan', $paths );
|
133 |
$results = array();
|
134 |
+
foreach ( $files as $file ) {
|
135 |
$verdict = vp_scan_file( $file );
|
136 |
if ( !empty( $verdict ) )
|
137 |
+
$results[$file] = array( 'hash' => @md5_file( $file ), 'verdict' => $verdict );
|
138 |
+
}
|
139 |
|
140 |
+
if ( !empty( $results ) ) {
|
141 |
+
$vaultpress = VaultPress::init();
|
142 |
+
$vaultpress->add_ping( 'security', array( 'suspicious_v2' => $results ) );
|
143 |
+
}
|
144 |
}
|
145 |
|
146 |
+
static function &init() {
|
147 |
+
static $instance = false;
|
148 |
+
if ( !$instance )
|
149 |
+
$instance = new VP_Site_Scanner();
|
150 |
+
return $instance;
|
151 |
+
}
|
|
|
|
|
152 |
}
|
153 |
VP_Site_Scanner::init();
|
readme.txt
CHANGED
@@ -1,9 +1,10 @@
|
|
1 |
=== VaultPress ===
|
2 |
-
Contributors: automattic,
|
3 |
Tags: security, malware, virus, backups, scanning
|
4 |
Requires at least: 2.9.2
|
5 |
-
Tested up to: 3.2
|
6 |
-
Stable tag: 1.
|
|
|
7 |
|
8 |
VaultPress is a subscription service offering realtime backup, automated security scanning, and support from WordPress experts.
|
9 |
|
@@ -21,21 +22,21 @@ For more information, check out [VaultPress.com](http://vaultpress.com/).
|
|
21 |
2. Visit `wp-admin/plugins.php` and activate the VaultPress plugin.
|
22 |
3. Head to `wp-admin/admin.php?page=vaultpress` and enter your site’s registration key. You can purchase your registration key at [VaultPress.com](http://vaultpress.com/plugin/?utm_source=plugin-readme&utm_medium=installation&utm_campaign=1.0)
|
23 |
|
24 |
-
You can find more detailed instructions at [http://vaultpress.com/
|
25 |
|
26 |
== Frequently Asked Questions ==
|
27 |
|
28 |
-
View our full list of FAQs at [http://vaultpress.com/
|
29 |
|
30 |
= What’s included in each VaultPress plan? =
|
31 |
|
32 |
-
All plans include Realtime Backups, Downloadable Archives for Restoring, Vitality Statistics, and the Activity Log.
|
33 |
|
34 |
-
The
|
35 |
|
36 |
-
The
|
37 |
|
38 |
-
The
|
39 |
|
40 |
Update-to-date pricing and features can always be found on the [Plans & Pricing](http://vaultpress.com/plugin/?utm_source=plugin-readme&utm_medium=installation&utm_campaign=1.0) page.
|
41 |
|
@@ -45,9 +46,24 @@ A VaultPress subscription is for a single WordPress site. You can purchase addit
|
|
45 |
|
46 |
= Does VaultPress work with WordPress 3.0 Multisite installs? =
|
47 |
|
48 |
-
|
49 |
|
50 |
== Changelog ==
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
51 |
|
52 |
= 1.0 =
|
53 |
* First public release!
|
1 |
=== VaultPress ===
|
2 |
+
Contributors: automattic, apokalyptik, briancolinger, josephscott, shaunandrews, xknown
|
3 |
Tags: security, malware, virus, backups, scanning
|
4 |
Requires at least: 2.9.2
|
5 |
+
Tested up to: 3.5.2
|
6 |
+
Stable tag: 1.4.6
|
7 |
+
License: GPLv2
|
8 |
|
9 |
VaultPress is a subscription service offering realtime backup, automated security scanning, and support from WordPress experts.
|
10 |
|
22 |
2. Visit `wp-admin/plugins.php` and activate the VaultPress plugin.
|
23 |
3. Head to `wp-admin/admin.php?page=vaultpress` and enter your site’s registration key. You can purchase your registration key at [VaultPress.com](http://vaultpress.com/plugin/?utm_source=plugin-readme&utm_medium=installation&utm_campaign=1.0)
|
24 |
|
25 |
+
You can find more detailed instructions at [http://vaultpress.com/](http://help.vaultpress.com/install-vaultpress/?utm_source=plugin-readme&utm_medium=description&utm_campaign=1.0)
|
26 |
|
27 |
== Frequently Asked Questions ==
|
28 |
|
29 |
+
View our full list of FAQs at [http://help.vaultpress.com/faq/](http://help.vaultpress.com/faq/?utm_source=plugin-readme&utm_medium=faq&utm_campaign=1.0)
|
30 |
|
31 |
= What’s included in each VaultPress plan? =
|
32 |
|
33 |
+
All plans include Daily or Realtime Backups, Downloadable Archives for Restoring, Vitality Statistics, and the Activity Log.
|
34 |
|
35 |
+
The Lite plan provides Daily Backups, a 30-day backup archive and automated restores.
|
36 |
|
37 |
+
The Basic plan provides Realtime Backups to protect your changes as they happen and support services.
|
38 |
|
39 |
+
The Premium plan provides priority recovery and support services, along with site migration assistance. The Premium plan provides automated security scanning of Core, Theme, and Plugin files.
|
40 |
|
41 |
Update-to-date pricing and features can always be found on the [Plans & Pricing](http://vaultpress.com/plugin/?utm_source=plugin-readme&utm_medium=installation&utm_campaign=1.0) page.
|
42 |
|
46 |
|
47 |
= Does VaultPress work with WordPress 3.0 Multisite installs? =
|
48 |
|
49 |
+
Yes, VaultPress supports Multisite installs. Each site will require its own subscription.
|
50 |
|
51 |
== Changelog ==
|
52 |
+
= 1.4.6 =
|
53 |
+
* Bugfix: PHP 5.4 notices
|
54 |
+
* Feature: Add the possibility to ignore frequent updates on some postmeta keys.
|
55 |
+
|
56 |
+
= 1.3.9 =
|
57 |
+
* Feature: Request decoding (base64/rot13)
|
58 |
+
* Feature: Response encoding (base64/rot13)
|
59 |
+
|
60 |
+
= 1.3.8 =
|
61 |
+
* Bugfix: Validate IPv4-mapped IPv6 addresses in the internal firewall.
|
62 |
+
* Bugfix: Fix hooks not being properly added under certain circumstances.
|
63 |
+
|
64 |
+
= 1.3.7 =
|
65 |
+
* Bugfix: Protect against infinite loop due to a PHP bug.
|
66 |
+
* Bugfix: Encode remote ping requests.
|
67 |
|
68 |
= 1.0 =
|
69 |
* First public release!
|
vaultpress.php
CHANGED
@@ -3,7 +3,7 @@
|
|
3 |
* Plugin Name: VaultPress
|
4 |
* Plugin URI: http://vaultpress.com/?utm_source=plugin-uri&utm_medium=plugin-description&utm_campaign=1.0
|
5 |
* Description: Protect your content, themes, plugins, and settings with <strong>realtime backup</strong> and <strong>automated security scanning</strong> from <a href="http://vaultpress.com/?utm_source=wp-admin&utm_medium=plugin-description&utm_campaign=1.0" rel="nofollow">VaultPress</a>. Activate, enter your registration key, and never worry again. <a href="http://vaultpress.com/help/?utm_source=wp-admin&utm_medium=plugin-description&utm_campaign=1.0" rel="nofollow">Need some help?</a>
|
6 |
-
* Version: 1.
|
7 |
* Author: Automattic
|
8 |
* Author URI: http://vaultpress.com/?utm_source=author-uri&utm_medium=plugin-description&utm_campaign=1.0
|
9 |
* License: GPL2+
|
@@ -17,8 +17,8 @@ if ( !defined( 'ABSPATH' ) )
|
|
17 |
|
18 |
class VaultPress {
|
19 |
var $option_name = 'vaultpress';
|
20 |
-
var $db_version =
|
21 |
-
var $plugin_version = '1.
|
22 |
|
23 |
function VaultPress() {
|
24 |
$this->__construct();
|
@@ -48,11 +48,16 @@ class VaultPress {
|
|
48 |
if ( is_admin() )
|
49 |
$this->add_admin_actions_and_filters();
|
50 |
|
51 |
-
if ( $this->is_registered() )
|
52 |
-
$this->
|
|
|
|
|
|
|
|
|
|
|
53 |
}
|
54 |
|
55 |
-
function &init() {
|
56 |
static $instance = false;
|
57 |
|
58 |
if ( !$instance ) {
|
@@ -110,6 +115,12 @@ class VaultPress {
|
|
110 |
$this->update_option( 'db_version', $this->db_version );
|
111 |
$this->clear_connection();
|
112 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
113 |
}
|
114 |
|
115 |
function get_option( $key ) {
|
@@ -192,6 +203,7 @@ class VaultPress {
|
|
192 |
<style type="text/css">
|
193 |
#toplevel_page_vaultpress div.wp-menu-image {
|
194 |
background: url(<?php echo esc_url( $this->server_url() ); ?>images/vp-icon-sprite.png?20111216) center top no-repeat;
|
|
|
195 |
}
|
196 |
|
197 |
.admin-color-classic #toplevel_page_vaultpress div.wp-menu-image {
|
@@ -202,6 +214,12 @@ class VaultPress {
|
|
202 |
#toplevel_page_vaultpress:hover div.wp-menu-image {
|
203 |
background-position: center bottom;
|
204 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
205 |
</style>
|
206 |
|
207 |
<?php
|
@@ -224,14 +242,68 @@ class VaultPress {
|
|
224 |
}
|
225 |
|
226 |
add_action( "load-$hook", array( $this, 'ui_load' ) );
|
227 |
-
add_action( 'admin_print_styles', array( $this, '
|
228 |
}
|
229 |
|
230 |
-
function
|
|
|
|
|
|
|
231 |
// force the cache to bust every day
|
232 |
wp_enqueue_style( 'vaultpress', $this->server_url() . 'css/plugin.css' , false, date( 'Ymd' ) );
|
233 |
}
|
234 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
235 |
function server_url() {
|
236 |
if ( !isset( $this->_server_url ) ) {
|
237 |
$scheme = is_ssl() ? 'https' : 'http';
|
@@ -281,7 +353,7 @@ class VaultPress {
|
|
281 |
|
282 |
// link to the VaultPress page if we're not already there
|
283 |
if ( !isset( $_GET['page'] ) || 'vaultpress' != $_GET['page'] )
|
284 |
-
$error_message .= ' ' . sprintf( '<a href="%s">%s</a>', admin_url( 'admin.php?page=vaultpress' ), __( 'Visit the VaultPress page' ) );
|
285 |
|
286 |
if ( !empty( $error_message ) )
|
287 |
$this->ui_message( $error_message, 'error' );
|
@@ -468,6 +540,10 @@ class VaultPress {
|
|
468 |
$val = $this->get_option_name_ignore( true );
|
469 |
update_option( '_vp_config_option_name_ignore', $val );
|
470 |
break;
|
|
|
|
|
|
|
|
|
471 |
}
|
472 |
return $val;
|
473 |
}
|
@@ -489,6 +565,17 @@ class VaultPress {
|
|
489 |
return array_unique( array_merge( $defaults, $ignore_names ) );
|
490 |
}
|
491 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
492 |
###
|
493 |
### Section: Backup Notification Hooks
|
494 |
###
|
@@ -628,7 +715,7 @@ class VaultPress {
|
|
628 |
$this->add_ping( 'db', array( 'commentmeta' => $meta_id ) );
|
629 |
}
|
630 |
|
631 |
-
function commentmeta_modification_handler( $object_id, $meta_key, $meta_value
|
632 |
if ( !is_array( $meta_id ) )
|
633 |
return $this->add_ping( 'db', array( 'commentmeta' => $meta_id ) );
|
634 |
foreach ( $meta_id as $id ) {
|
@@ -638,10 +725,16 @@ class VaultPress {
|
|
638 |
|
639 |
// Handle Notifying VaultPress of PostMeta changes via newfangled metadata functions
|
640 |
function postmeta_insert_handler( $meta_id, $post_id, $meta_key, $meta_value='' ) {
|
|
|
|
|
|
|
641 |
$this->add_ping( 'db', array( 'postmeta' => $meta_id ) );
|
642 |
}
|
643 |
|
644 |
function postmeta_modification_handler( $meta_id, $object_id, $meta_key, $meta_value ) {
|
|
|
|
|
|
|
645 |
if ( !is_array( $meta_id ) )
|
646 |
return $this->add_ping( 'db', array( 'postmeta' => $meta_id ) );
|
647 |
foreach ( $meta_id as $id ) {
|
@@ -650,7 +743,10 @@ class VaultPress {
|
|
650 |
}
|
651 |
|
652 |
// Handle Notifying VaultPress of PostMeta changes via old school cherypicked hooks
|
653 |
-
function postmeta_action_handler( $meta_id ) {
|
|
|
|
|
|
|
654 |
if ( !is_array($meta_id) )
|
655 |
return $this->add_ping( 'db', array( 'postmeta' => $meta_id ) );
|
656 |
foreach ( $meta_id as $id )
|
@@ -810,9 +906,9 @@ class VaultPress {
|
|
810 |
}
|
811 |
|
812 |
function update_firewall() {
|
813 |
-
$args = array( 'timeout' => $this->get_option( 'timeout' ) );
|
814 |
$hostname = $this->get_option( 'hostname' );
|
815 |
-
$data = wp_remote_get( "
|
816 |
|
817 |
if ( $data )
|
818 |
$data = @unserialize( $data['body'] );
|
@@ -820,10 +916,34 @@ class VaultPress {
|
|
820 |
if ( $data ) {
|
821 |
$newval = array( 'updated' => time(), 'data' => $data );
|
822 |
$this->update_option( 'service_ips', $newval );
|
823 |
-
return $data;
|
824 |
}
|
825 |
|
826 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
827 |
}
|
828 |
|
829 |
function check_connection( $force_check = false ) {
|
@@ -871,6 +991,13 @@ class VaultPress {
|
|
871 |
return false;
|
872 |
}
|
873 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
874 |
// test connection between the site and the servers
|
875 |
$connect = (string)$this->contact_service( 'test', array( 'type' => 'connect' ) );
|
876 |
if ( 'ok' != $connect ) {
|
@@ -902,6 +1029,110 @@ class VaultPress {
|
|
902 |
return true;
|
903 |
}
|
904 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
905 |
function parse_request( $wp ) {
|
906 |
if ( !isset( $_GET['vaultpress'] ) || $_GET['vaultpress'] !== 'true' )
|
907 |
return $wp;
|
@@ -910,6 +1141,11 @@ class VaultPress {
|
|
910 |
|
911 |
// just in case we have any plugins that decided to spit some data out already...
|
912 |
@ob_end_clean();
|
|
|
|
|
|
|
|
|
|
|
913 |
|
914 |
if ( isset( $_GET['ticker'] ) && function_exists( 'current_user_can' ) && current_user_can( 'manage_options' ) )
|
915 |
die( (string)$this->contact_service( 'ticker' ) );
|
@@ -920,7 +1156,36 @@ class VaultPress {
|
|
920 |
define( 'VAULTPRESS_API', true );
|
921 |
|
922 |
if ( !$this->validate_api_signature() ) {
|
923 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
924 |
}
|
925 |
|
926 |
if ( !isset( $bdb ) ) {
|
@@ -965,10 +1230,10 @@ class VaultPress {
|
|
965 |
$code = $_POST['code'];
|
966 |
if ( !$code )
|
967 |
$this->response( "No Code Found" );
|
968 |
-
$syntax_check = @eval( 'return true;' . $
|
969 |
if ( !$syntax_check )
|
970 |
$this->response( "Code Failed Syntax Check" );
|
971 |
-
$this->response( eval( $
|
972 |
die();
|
973 |
break;
|
974 |
case 'catchup:get':
|
@@ -985,9 +1250,9 @@ class VaultPress {
|
|
985 |
case 'general:ping':
|
986 |
global $wp_version, $wp_db_version, $manifest_version;
|
987 |
@error_reporting(0);
|
988 |
-
$
|
989 |
$httpd = null;
|
990 |
-
if (
|
991 |
if ( isset( $_POST['apache_modules'] ) && $_POST['apache_modules'] == 1 )
|
992 |
$http_modules = apache_get_modules();
|
993 |
else
|
@@ -1015,6 +1280,8 @@ class VaultPress {
|
|
1015 |
foreach ( $wpdb->get_results( "SHOW VARIABLES" ) as $row )
|
1016 |
$mvars["$row->Variable_name"] = $row->Value;
|
1017 |
}
|
|
|
|
|
1018 |
|
1019 |
$ms_global_tables = array_merge( $wpdb->global_tables, $wpdb->ms_global_tables );
|
1020 |
$tinfo = array();
|
@@ -1069,10 +1336,12 @@ class VaultPress {
|
|
1069 |
$loadavg = sys_getloadavg();
|
1070 |
else
|
1071 |
$loadavg = null;
|
1072 |
-
if ( !function_exists( 'get_plugin_data' ) )
|
1073 |
-
require_once ABSPATH . '/wp-admin/includes/plugin.php';
|
1074 |
|
1075 |
-
|
|
|
|
|
|
|
|
|
1076 |
$vaultpress_response_info['deferred_pings'] = (int)$this->ai_ping_count();
|
1077 |
$vaultpress_response_info['vaultpress_hostname'] = $this->get_option( 'hostname' );
|
1078 |
$vaultpress_response_info['vaultpress_timeout'] = $this->get_option( 'timeout' );
|
@@ -1107,8 +1376,8 @@ class VaultPress {
|
|
1107 |
'prefix' => $wpdb->prefix,
|
1108 |
'is_multisite' => $this->is_multisite(),
|
1109 |
'is_main_site' => $this->is_main_site(),
|
1110 |
-
'blog_id' => $current_blog->blog_id,
|
1111 |
-
'theme' => get_current_theme(),
|
1112 |
'plugins' => preg_replace( '#/.*$#', '', get_option( 'active_plugins' ) ),
|
1113 |
'tables' => $tinfo,
|
1114 |
'name' => get_bloginfo( 'name' ),
|
@@ -1123,7 +1392,7 @@ class VaultPress {
|
|
1123 |
'load' => $loadavg,
|
1124 |
'info' => @php_uname( "a" ),
|
1125 |
'time' => time(),
|
1126 |
-
'php' => array( 'version' => phpversion(), 'ini' => $ini_vals ),
|
1127 |
'httpd' => array(
|
1128 |
'type' => $httpd,
|
1129 |
'modules' => $http_modules,
|
@@ -1175,8 +1444,10 @@ class VaultPress {
|
|
1175 |
else
|
1176 |
$where = null;
|
1177 |
|
1178 |
-
if ( isset( $_POST['table'] ) )
|
1179 |
-
$
|
|
|
|
|
1180 |
|
1181 |
switch ( array_pop( explode( ':', $_GET['action'] ) ) ) {
|
1182 |
case 'diff':
|
@@ -1324,7 +1595,8 @@ class VaultPress {
|
|
1324 |
$args['args'] = '';
|
1325 |
$old_timeout = ini_get( 'default_socket_timeout' );
|
1326 |
$timeout = $this->get_option( 'timeout' );
|
1327 |
-
|
|
|
1328 |
$hostname = $this->get_option( 'hostname' );
|
1329 |
|
1330 |
if ( !class_exists( 'VaultPress_IXR_SSL_Client' ) )
|
@@ -1356,9 +1628,10 @@ class VaultPress {
|
|
1356 |
$this->_fix_ixr_null_to_string( $args );
|
1357 |
$args['signature'] = $this->sign_string( serialize( $args ), $this->get_option( 'secret' ), $salt ).":$salt";
|
1358 |
|
1359 |
-
$client->query( 'vaultpress.'.$action, $args );
|
1360 |
$rval = $client->message ? $client->getResponse() : '';
|
1361 |
-
|
|
|
1362 |
|
1363 |
// we got an error from the servers
|
1364 |
if ( is_array( $rval ) && isset( $rval['faultCode'] ) ) {
|
@@ -1372,18 +1645,28 @@ class VaultPress {
|
|
1372 |
|
1373 |
function validate_api_signature() {
|
1374 |
global $__vp_validate_error;
|
1375 |
-
if (
|
1376 |
-
|
1377 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
1378 |
return false;
|
|
|
1379 |
|
1380 |
$secret = $this->get_option( 'secret' );
|
1381 |
if ( !$secret ) {
|
1382 |
-
$__vp_validate_error =
|
1383 |
return false;
|
1384 |
}
|
1385 |
if ( !$this->get_option( 'disable_firewall' ) ) {
|
1386 |
$rxs = $this->get_option( 'service_ips' );
|
|
|
|
|
|
|
1387 |
if ( $rxs ) {
|
1388 |
$timeout = time() - 86400;
|
1389 |
if ( $rxs ) {
|
@@ -1400,14 +1683,12 @@ class VaultPress {
|
|
1400 |
if ( $data = $this->update_firewall() )
|
1401 |
$rxs = $data;
|
1402 |
}
|
1403 |
-
if ( !$this->validate_ip_address( $rxs ) )
|
1404 |
-
$__vp_validate_error = "firewall_fail";
|
1405 |
return false;
|
1406 |
-
}
|
1407 |
}
|
1408 |
$sig = explode( ':', $sig );
|
1409 |
-
if ( !is_array( $sig ) || count( $sig ) != 2 ||
|
1410 |
-
$__vp_validate_error =
|
1411 |
return false;
|
1412 |
}
|
1413 |
|
@@ -1421,16 +1702,32 @@ class VaultPress {
|
|
1421 |
ksort( $post );
|
1422 |
$to_sign = serialize( array( 'uri' => $uri, 'post' => $post ) );
|
1423 |
$signature = $this->sign_string( $to_sign, $secret, $sig[1] );
|
1424 |
-
if ( $sig[0]
|
1425 |
return true;
|
1426 |
|
1427 |
-
$__vp_validate_error =
|
1428 |
return false;
|
1429 |
}
|
1430 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1431 |
function validate_ip_address( $rxs ) {
|
1432 |
-
|
|
|
|
|
1433 |
return false;
|
|
|
1434 |
|
1435 |
$remote_ips = array();
|
1436 |
|
@@ -1440,11 +1737,17 @@ class VaultPress {
|
|
1440 |
if ( !empty( $_SERVER['REMOTE_ADDR'] ) )
|
1441 |
$remote_ips[] = $_SERVER['REMOTE_ADDR'];
|
1442 |
|
|
|
|
|
|
|
|
|
|
|
1443 |
$iprx = '/^([0-9]+\.[0-9]+\.[0-9]+\.)([0-9]+)$/';
|
1444 |
|
1445 |
-
foreach ( $remote_ips as $
|
|
|
1446 |
if ( !preg_match( $iprx, $remote_ip, $r ) ) {
|
1447 |
-
$__vp_validate_error = "remote_addr_fail";
|
1448 |
return false;
|
1449 |
}
|
1450 |
|
@@ -1463,6 +1766,7 @@ class VaultPress {
|
|
1463 |
}
|
1464 |
}
|
1465 |
}
|
|
|
1466 |
|
1467 |
return false;
|
1468 |
}
|
@@ -1472,8 +1776,19 @@ class VaultPress {
|
|
1472 |
}
|
1473 |
|
1474 |
function response( $response, $raw = false ) {
|
1475 |
-
|
1476 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1477 |
list( $usec, $sec ) = explode( " ", microtime() );
|
1478 |
$r = new stdClass();
|
1479 |
$r->req_vector = floatval( $_GET['vector'] );
|
@@ -1491,7 +1806,14 @@ class VaultPress {
|
|
1491 |
else
|
1492 |
$r->memory_usage = false;
|
1493 |
$r->response = $response;
|
1494 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1495 |
}
|
1496 |
|
1497 |
function reset_pings() {
|
@@ -1694,11 +2016,14 @@ class VaultPress {
|
|
1694 |
|
1695 |
function add_admin_actions_and_filters() {
|
1696 |
add_action( 'admin_init', array( $this, 'admin_init' ) );
|
1697 |
-
add_action( 'admin_menu', array( $this, 'admin_menu' ) );
|
1698 |
add_action( 'admin_head', array( $this, 'admin_head' ) );
|
1699 |
}
|
1700 |
|
1701 |
function add_listener_actions_and_filters() {
|
|
|
|
|
|
|
1702 |
// Comments
|
1703 |
add_action( 'delete_comment', array( $this, 'comment_action_handler' ) );
|
1704 |
add_action( 'wp_set_comment_status', array( $this, 'comment_action_handler' ) );
|
@@ -1748,9 +2073,9 @@ class VaultPress {
|
|
1748 |
add_action( 'updated_post_meta', array( $this, 'postmeta_modification_handler' ), 10, 4 );
|
1749 |
add_action( 'delete_post_meta', array( $this, 'postmeta_modification_handler' ), 10, 4 );
|
1750 |
add_action( 'deleted_post_meta', array( $this, 'postmeta_modification_handler' ), 10, 4 );
|
1751 |
-
add_action( 'added_postmeta', array( $this, 'postmeta_action_handler' ) );
|
1752 |
-
add_action( 'update_postmeta', array( $this, 'postmeta_action_handler' ) );
|
1753 |
-
add_action( 'delete_postmeta', array( $this, 'postmeta_action_handler' ) );
|
1754 |
|
1755 |
// Links
|
1756 |
add_action( 'edit_link', array( $this, 'link_action_handler' ) );
|
@@ -1781,6 +2106,16 @@ class VaultPress {
|
|
1781 |
add_action( 'updated_option', array( $this, 'option_handler' ), 1 );
|
1782 |
add_action( 'added_option', array( $this, 'option_handler' ), 1 );
|
1783 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1784 |
// Report back to VaultPress
|
1785 |
add_action( 'shutdown', array( $this, 'do_pings' ) );
|
1786 |
|
3 |
* Plugin Name: VaultPress
|
4 |
* Plugin URI: http://vaultpress.com/?utm_source=plugin-uri&utm_medium=plugin-description&utm_campaign=1.0
|
5 |
* Description: Protect your content, themes, plugins, and settings with <strong>realtime backup</strong> and <strong>automated security scanning</strong> from <a href="http://vaultpress.com/?utm_source=wp-admin&utm_medium=plugin-description&utm_campaign=1.0" rel="nofollow">VaultPress</a>. Activate, enter your registration key, and never worry again. <a href="http://vaultpress.com/help/?utm_source=wp-admin&utm_medium=plugin-description&utm_campaign=1.0" rel="nofollow">Need some help?</a>
|
6 |
+
* Version: 1.4.6
|
7 |
* Author: Automattic
|
8 |
* Author URI: http://vaultpress.com/?utm_source=author-uri&utm_medium=plugin-description&utm_campaign=1.0
|
9 |
* License: GPL2+
|
17 |
|
18 |
class VaultPress {
|
19 |
var $option_name = 'vaultpress';
|
20 |
+
var $db_version = 3;
|
21 |
+
var $plugin_version = '1.4.6';
|
22 |
|
23 |
function VaultPress() {
|
24 |
$this->__construct();
|
48 |
if ( is_admin() )
|
49 |
$this->add_admin_actions_and_filters();
|
50 |
|
51 |
+
if ( $this->is_registered() ) {
|
52 |
+
$do_not_backup = $this->get_option( 'do_not_backup' ) || $this->get_option( 'do_not_send_backup_pings' );
|
53 |
+
if ( $do_not_backup )
|
54 |
+
$this->add_vp_required_filters();
|
55 |
+
else
|
56 |
+
$this->add_listener_actions_and_filters();
|
57 |
+
}
|
58 |
}
|
59 |
|
60 |
+
static function &init() {
|
61 |
static $instance = false;
|
62 |
|
63 |
if ( !$instance ) {
|
115 |
$this->update_option( 'db_version', $this->db_version );
|
116 |
$this->clear_connection();
|
117 |
}
|
118 |
+
|
119 |
+
if ( $current_db_version < 3 ) {
|
120 |
+
$this->update_firewall();
|
121 |
+
$this->update_option( 'db_version', $this->db_version );
|
122 |
+
$this->clear_connection();
|
123 |
+
}
|
124 |
}
|
125 |
|
126 |
function get_option( $key ) {
|
203 |
<style type="text/css">
|
204 |
#toplevel_page_vaultpress div.wp-menu-image {
|
205 |
background: url(<?php echo esc_url( $this->server_url() ); ?>images/vp-icon-sprite.png?20111216) center top no-repeat;
|
206 |
+
background-size: 28px 84px;
|
207 |
}
|
208 |
|
209 |
.admin-color-classic #toplevel_page_vaultpress div.wp-menu-image {
|
214 |
#toplevel_page_vaultpress:hover div.wp-menu-image {
|
215 |
background-position: center bottom;
|
216 |
}
|
217 |
+
|
218 |
+
@media only screen and (-moz-min-device-pixel-ratio: 1.5), only screen and (-o-min-device-pixel-ratio: 3/2), only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-device-pixel-ratio: 1.5) {
|
219 |
+
#toplevel_page_vaultpress div.wp-menu-image {
|
220 |
+
background-image: url(<?php echo esc_url( $this->server_url() ); ?>images/vp-icon-sprite-2x.png?20111216);
|
221 |
+
}
|
222 |
+
}
|
223 |
</style>
|
224 |
|
225 |
<?php
|
242 |
}
|
243 |
|
244 |
add_action( "load-$hook", array( $this, 'ui_load' ) );
|
245 |
+
add_action( 'admin_print_styles', array( $this, 'styles' ) );
|
246 |
}
|
247 |
|
248 |
+
function styles() {
|
249 |
+
if ( !current_user_can( 'manage_options' ) || !is_admin() )
|
250 |
+
return;
|
251 |
+
|
252 |
// force the cache to bust every day
|
253 |
wp_enqueue_style( 'vaultpress', $this->server_url() . 'css/plugin.css' , false, date( 'Ymd' ) );
|
254 |
}
|
255 |
|
256 |
+
// display a security threat notice if one exists
|
257 |
+
function toolbar( $wp_admin_bar ) {
|
258 |
+
global $wp_version;
|
259 |
+
|
260 |
+
// these new toolbar functions were introduced in 3.3
|
261 |
+
// http://codex.wordpress.org/Function_Reference/add_node
|
262 |
+
if ( version_compare( $wp_version, '3.3', '<') )
|
263 |
+
return;
|
264 |
+
|
265 |
+
if ( !current_user_can( 'manage_options' ) )
|
266 |
+
return;
|
267 |
+
|
268 |
+
$messages = $this->get_messages();
|
269 |
+
if ( !empty( $messages['security_notice_count'] ) ) {
|
270 |
+
$count = (int)$messages['security_notice_count'];
|
271 |
+
if ( $count > 0 ) {
|
272 |
+
$count = number_format( $count, 0 );
|
273 |
+
$wp_admin_bar->add_node( array(
|
274 |
+
'id' => 'vp-notice',
|
275 |
+
'title' => '<strong><span class="ab-icon"></span>' .
|
276 |
+
sprintf( _n( '%s Security Threat', '%s Security Threats', $count , 'vaultpress'), $count ) .
|
277 |
+
' </strong>',
|
278 |
+
'parent' => 'top-secondary',
|
279 |
+
'href' => sprintf( 'https://dashboard.vaultpress.com/%d/security/', $messages['site_id'] ),
|
280 |
+
'meta' => array(
|
281 |
+
'title' => __( 'Visit VaultPress Security' , 'vaultpress'),
|
282 |
+
'onclick' => 'window.open( this.href ); return false;',
|
283 |
+
'class' => 'error'
|
284 |
+
),
|
285 |
+
) );
|
286 |
+
}
|
287 |
+
}
|
288 |
+
}
|
289 |
+
|
290 |
+
// get any messages from the VP servers
|
291 |
+
function get_messages( $force_reload = false ) {
|
292 |
+
$last_contact = $this->get_option( 'messages_last_contact' );
|
293 |
+
|
294 |
+
// only run the messages check every 30 minutes
|
295 |
+
if ( ( time() - (int)$last_contact ) > 1800 || $force_reload ) {
|
296 |
+
$messages = base64_decode( $this->contact_service( 'messages', array() ) );
|
297 |
+
$messages = unserialize( $messages );
|
298 |
+
$this->update_option( 'messages_last_contact', time() );
|
299 |
+
$this->update_option( 'messages', $messages );
|
300 |
+
} else {
|
301 |
+
$messages = $this->get_option( 'messages' );
|
302 |
+
}
|
303 |
+
|
304 |
+
return $messages;
|
305 |
+
}
|
306 |
+
|
307 |
function server_url() {
|
308 |
if ( !isset( $this->_server_url ) ) {
|
309 |
$scheme = is_ssl() ? 'https' : 'http';
|
353 |
|
354 |
// link to the VaultPress page if we're not already there
|
355 |
if ( !isset( $_GET['page'] ) || 'vaultpress' != $_GET['page'] )
|
356 |
+
$error_message .= ' ' . sprintf( '<a href="%s">%s</a>', admin_url( 'admin.php?page=vaultpress' ), __( 'Visit the VaultPress page' , 'vaultpress') );
|
357 |
|
358 |
if ( !empty( $error_message ) )
|
359 |
$this->ui_message( $error_message, 'error' );
|
540 |
$val = $this->get_option_name_ignore( true );
|
541 |
update_option( '_vp_config_option_name_ignore', $val );
|
542 |
break;
|
543 |
+
case '_vp_config_post_meta_name_ignore':
|
544 |
+
$val = $this->get_post_meta_name_ignore( true );
|
545 |
+
update_option( '_vp_config_post_meta_name_ignore', $val );
|
546 |
+
break;
|
547 |
}
|
548 |
return $val;
|
549 |
}
|
565 |
return array_unique( array_merge( $defaults, $ignore_names ) );
|
566 |
}
|
567 |
|
568 |
+
// post meta name patterns to ignore
|
569 |
+
function get_post_meta_name_ignore( $return_defaults = false ) {
|
570 |
+
$defaults = array(
|
571 |
+
'pvc_views'
|
572 |
+
);
|
573 |
+
if ( $return_defaults )
|
574 |
+
return $defaults;
|
575 |
+
$ignore_names = $this->get_config( '_vp_config_post_meta_name_ignore' );
|
576 |
+
return array_unique( array_merge( $defaults, $ignore_names ) );
|
577 |
+
}
|
578 |
+
|
579 |
###
|
580 |
### Section: Backup Notification Hooks
|
581 |
###
|
715 |
$this->add_ping( 'db', array( 'commentmeta' => $meta_id ) );
|
716 |
}
|
717 |
|
718 |
+
function commentmeta_modification_handler( $meta_id, $object_id, $meta_key, $meta_value ) {
|
719 |
if ( !is_array( $meta_id ) )
|
720 |
return $this->add_ping( 'db', array( 'commentmeta' => $meta_id ) );
|
721 |
foreach ( $meta_id as $id ) {
|
725 |
|
726 |
// Handle Notifying VaultPress of PostMeta changes via newfangled metadata functions
|
727 |
function postmeta_insert_handler( $meta_id, $post_id, $meta_key, $meta_value='' ) {
|
728 |
+
if ( in_array( $meta_key, $this->get_post_meta_name_ignore() ) )
|
729 |
+
return;
|
730 |
+
|
731 |
$this->add_ping( 'db', array( 'postmeta' => $meta_id ) );
|
732 |
}
|
733 |
|
734 |
function postmeta_modification_handler( $meta_id, $object_id, $meta_key, $meta_value ) {
|
735 |
+
if ( in_array( $meta_key, $this->get_post_meta_name_ignore() ) )
|
736 |
+
return;
|
737 |
+
|
738 |
if ( !is_array( $meta_id ) )
|
739 |
return $this->add_ping( 'db', array( 'postmeta' => $meta_id ) );
|
740 |
foreach ( $meta_id as $id ) {
|
743 |
}
|
744 |
|
745 |
// Handle Notifying VaultPress of PostMeta changes via old school cherypicked hooks
|
746 |
+
function postmeta_action_handler( $meta_id, $post_id = null, $meta_key = null ) {
|
747 |
+
if ( in_array( $meta_key, $this->get_post_meta_name_ignore() ) )
|
748 |
+
return;
|
749 |
+
|
750 |
if ( !is_array($meta_id) )
|
751 |
return $this->add_ping( 'db', array( 'postmeta' => $meta_id ) );
|
752 |
foreach ( $meta_id as $id )
|
906 |
}
|
907 |
|
908 |
function update_firewall() {
|
909 |
+
$args = array( 'timeout' => $this->get_option( 'timeout' ), 'sslverify' => true );
|
910 |
$hostname = $this->get_option( 'hostname' );
|
911 |
+
$data = wp_remote_get( "https://$hostname/service-ips", $args );
|
912 |
|
913 |
if ( $data )
|
914 |
$data = @unserialize( $data['body'] );
|
916 |
if ( $data ) {
|
917 |
$newval = array( 'updated' => time(), 'data' => $data );
|
918 |
$this->update_option( 'service_ips', $newval );
|
|
|
919 |
}
|
920 |
|
921 |
+
$external_data = wp_remote_get( "https://$hostname/service-ips-external", $args );
|
922 |
+
if ( $external_data )
|
923 |
+
$external_data = @unserialize( $external_data['body'] );
|
924 |
+
|
925 |
+
if ( $external_data ) {
|
926 |
+
$external_newval = array( 'updated' => time(), 'data' => $external_data );
|
927 |
+
update_option( 'vaultpress_service_ips_external', $external_newval );
|
928 |
+
}
|
929 |
+
|
930 |
+
if ( !empty( $data ) && !empty( $external_data ) )
|
931 |
+
$data = array_merge( $data, $external_data );
|
932 |
+
|
933 |
+
if ( $data ) {
|
934 |
+
return $data;
|
935 |
+
} else {
|
936 |
+
return null;
|
937 |
+
}
|
938 |
+
}
|
939 |
+
|
940 |
+
// Update local cache of VP plan settings, based on a ping or connection test result
|
941 |
+
function update_plan_settings( $message ) {
|
942 |
+
if ( array_key_exists( 'do_backups', $message ) )
|
943 |
+
$this->update_option( 'do_not_backup', ( false === $message['do_backups'] ) );
|
944 |
+
|
945 |
+
if ( array_key_exists( 'do_backup_pings', $message ) )
|
946 |
+
$this->update_option( 'do_not_send_backup_pings', ( false === $message['do_backup_pings'] ) );
|
947 |
}
|
948 |
|
949 |
function check_connection( $force_check = false ) {
|
991 |
return false;
|
992 |
}
|
993 |
|
994 |
+
$this->update_plan_settings( $connect );
|
995 |
+
|
996 |
+
if ( !empty( $connect['signatures'] ) ) {
|
997 |
+
delete_option( '_vp_signatures' );
|
998 |
+
add_option( '_vp_signatures', maybe_unserialize( $connect['signatures'] ), '', 'no' );
|
999 |
+
}
|
1000 |
+
|
1001 |
// test connection between the site and the servers
|
1002 |
$connect = (string)$this->contact_service( 'test', array( 'type' => 'connect' ) );
|
1003 |
if ( 'ok' != $connect ) {
|
1029 |
return true;
|
1030 |
}
|
1031 |
|
1032 |
+
function get_login_tokens() {
|
1033 |
+
// By default the login token is valid for 30 minutes.
|
1034 |
+
$nonce_life = $this->get_option( 'nonce_life' ) ? $this->get_option( 'nonce_life' ) : 1800;
|
1035 |
+
$salt = wp_salt( 'nonce' ) . md5( $this->get_option( 'secret' ) );
|
1036 |
+
$nonce_life /= 2;
|
1037 |
+
|
1038 |
+
return array(
|
1039 |
+
'previous' => substr( hash_hmac( 'md5', 'vp-login' . ceil( time() / $nonce_life - 1 ), $salt ), -12, 10 ),
|
1040 |
+
'current' => substr( hash_hmac( 'md5', 'vp-login' . ceil( time() / $nonce_life ), $salt ), -12, 10 ),
|
1041 |
+
);
|
1042 |
+
}
|
1043 |
+
function add_js_token() {
|
1044 |
+
$nonce = $this->get_login_tokens();
|
1045 |
+
$token = $nonce['current'];
|
1046 |
+
|
1047 |
+
// Uglyfies the JS code before sending it to the browser.
|
1048 |
+
$whitelist = array( 'charAt', 'all', 'setAttribute', 'document', 'createElement', 'appendChild', 'input', 'hidden', 'type', 'name', 'value', 'getElementById', 'loginform', '_vp' );
|
1049 |
+
shuffle( $whitelist );
|
1050 |
+
$whitelist = array_flip( $whitelist );
|
1051 |
+
|
1052 |
+
$set = array(
|
1053 |
+
0 => array( '+[]', 'e^e' ),
|
1054 |
+
1 => array( '+!![]', '2>>1', "e[{$whitelist['type']}].charCodeAt(3)>>6" ),
|
1055 |
+
2 => array( '(+!![])<<1', "e[{$whitelist['_vp']}].replace(/_/,'').length" ),
|
1056 |
+
3 => array( "(Math.log(2<<4)+[])[e[{$whitelist['charAt']}]](0)", "e[{$whitelist['_vp']}].length" ),
|
1057 |
+
4 => array( '(+!![])<<2', "e[{$whitelist['input']}].length^1", "e[{$whitelist['name']}].length" ),
|
1058 |
+
5 => array( '((1<<2)+1)', 'parseInt("f",0x10)/3' ),
|
1059 |
+
6 => array( '(7^1)', "e[{$whitelist['hidden']}].length" ),
|
1060 |
+
7 => array( '(3<<1)+1', "e[{$whitelist['hidden']}].length^1" ),
|
1061 |
+
8 => array( '(0x101>>5)', "e[{$whitelist['document']}].length" ),
|
1062 |
+
9 => array( '(0x7^4)*(3+[])', "e[{$whitelist['loginform']}].length", "(1<<e[{$whitelist['_vp']}].length)^1" ),
|
1063 |
+
'a' => array( "(![]+\"\")[e[{$whitelist['charAt']}]](1)", "e[{$whitelist['appendChild']}][e[{$whitelist['charAt']}]](0)", "e[{$whitelist['name']}][e[{$whitelist['charAt']}]](1)" ),
|
1064 |
+
'b' => array( "([]+{})[e[{$whitelist['charAt']}]](2)", "({}+[])[e[{$whitelist['charAt']}]](2)" ),
|
1065 |
+
'c' => array( "([]+{})[e[{$whitelist['charAt']}]](5)", "e[{$whitelist['createElement']}][e[{$whitelist['charAt']}]](0)" ),
|
1066 |
+
'd' => array( "([][0]+\"\")[e[{$whitelist['charAt']}]](2)", "([][0]+[])[e[{$whitelist['charAt']}]](2)" ),
|
1067 |
+
'e' => array( "(!![]+[])[e[{$whitelist['charAt']}]](3)", "(!![]+\"\")[e[{$whitelist['charAt']}]](3)" ),
|
1068 |
+
'f' => array( "(![]+[])[e[{$whitelist['charAt']}]](0)", "([]+![])[e[{$whitelist['charAt']}]](e^e)", "([]+![])[e[{$whitelist['charAt']}]](0)" ),
|
1069 |
+
);
|
1070 |
+
|
1071 |
+
$js_code = <<<JS
|
1072 |
+
<script type="text/javascript">
|
1073 |
+
/* <![CDATA[ */
|
1074 |
+
(function(){
|
1075 |
+
var i,e='%s'.split('|'),_=[%s],s=function(a,b,c){a[b]=c};
|
1076 |
+
if(this[e[{$whitelist['document']}]][e[{$whitelist['all']}]]){
|
1077 |
+
try {
|
1078 |
+
i=this[e[{$whitelist['document']}]][e[{$whitelist['createElement']}]]('<'+e[{$whitelist['input']}]+' '+e[{$whitelist['name']}]+'='+(e[{$whitelist['_vp']}]+(!![]))+' />');
|
1079 |
+
}catch(e){}
|
1080 |
+
}
|
1081 |
+
if(!i){
|
1082 |
+
i=this[e[{$whitelist['document']}]][e[{$whitelist['createElement']}]](e[{$whitelist['input']}]);
|
1083 |
+
s(i,e[{$whitelist['name']}],e[{$whitelist['_vp']}]+(!![]));
|
1084 |
+
}
|
1085 |
+
s(i,e[{$whitelist['type']}],e[{$whitelist['hidden']}]).
|
1086 |
+
s(i,e[{$whitelist['value']}],(%s+""));
|
1087 |
+
try {
|
1088 |
+
var __=this[e[{$whitelist['document']}]][e[{$whitelist['getElementById']}]](e[{$whitelist['loginform']}]);
|
1089 |
+
__[e[{$whitelist['appendChild']}]](i);
|
1090 |
+
} catch(e){}
|
1091 |
+
})();
|
1092 |
+
/* ]]> */
|
1093 |
+
</script>
|
1094 |
+
JS;
|
1095 |
+
$chars = array();
|
1096 |
+
for ( $i = 0; $i < strlen( $token ); $i++ ) {
|
1097 |
+
if ( isset( $set[$token{$i}] ) ) {
|
1098 |
+
$k = array_rand( $set[$token{$i}], 1 );
|
1099 |
+
$chars[] = $set[$token{$i}][$k];
|
1100 |
+
} else {
|
1101 |
+
$chars[] = $token{$i};
|
1102 |
+
}
|
1103 |
+
}
|
1104 |
+
$random = array_unique( $chars );
|
1105 |
+
shuffle( $random );
|
1106 |
+
$random = array_flip( $random );
|
1107 |
+
|
1108 |
+
foreach( $chars as $i => $v )
|
1109 |
+
$chars[$i] = sprintf( '_[%d]', $random[$v] );
|
1110 |
+
|
1111 |
+
$code = preg_replace(
|
1112 |
+
"#[\n\r\t]#",
|
1113 |
+
'',
|
1114 |
+
sprintf( $js_code,
|
1115 |
+
join( '|', array_keys( $whitelist ) ),
|
1116 |
+
join( ',', array_keys( $random ) ),
|
1117 |
+
join( '+"")+(', $chars )
|
1118 |
+
)
|
1119 |
+
);
|
1120 |
+
echo $code;
|
1121 |
+
}
|
1122 |
+
|
1123 |
+
function authenticate( $user, $username, $password ) {
|
1124 |
+
if ( is_wp_error( $user ) )
|
1125 |
+
return $user;
|
1126 |
+
if ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST || defined( 'APP_REQUEST' ) && APP_REQUEST ) {
|
1127 |
+
// Try to log in with the username and password.
|
1128 |
+
}
|
1129 |
+
$retval = $user;
|
1130 |
+
if ( empty( $_POST['_vptrue'] ) || !in_array( $_POST['_vptrue'], $this->get_login_tokens(), true ) )
|
1131 |
+
$retval = new WP_Error( 'invalid_token', __( 'Invalid token. Please try to log in again.' ) );
|
1132 |
+
|
1133 |
+
return $retval;
|
1134 |
+
}
|
1135 |
+
|
1136 |
function parse_request( $wp ) {
|
1137 |
if ( !isset( $_GET['vaultpress'] ) || $_GET['vaultpress'] !== 'true' )
|
1138 |
return $wp;
|
1141 |
|
1142 |
// just in case we have any plugins that decided to spit some data out already...
|
1143 |
@ob_end_clean();
|
1144 |
+
// Headers to avoid search engines indexing "invalid api call signature" pages.
|
1145 |
+
if ( !headers_sent() ) {
|
1146 |
+
header( 'X-Robots-Tag: none' );
|
1147 |
+
header( 'X-Robots-Tag: unavailable_after: 1 Oct 2012 00:00:00 PST', false );
|
1148 |
+
}
|
1149 |
|
1150 |
if ( isset( $_GET['ticker'] ) && function_exists( 'current_user_can' ) && current_user_can( 'manage_options' ) )
|
1151 |
die( (string)$this->contact_service( 'ticker' ) );
|
1156 |
define( 'VAULTPRESS_API', true );
|
1157 |
|
1158 |
if ( !$this->validate_api_signature() ) {
|
1159 |
+
global $__vp_validate_error;
|
1160 |
+
die( 'invalid api call signature [' . base64_encode( serialize( $__vp_validate_error ) ) . ']' );
|
1161 |
+
}
|
1162 |
+
|
1163 |
+
if ( !empty( $_GET['ge'] ) ) {
|
1164 |
+
// "ge" -- "GET encoding"
|
1165 |
+
if ( '1' === $_GET['ge'] )
|
1166 |
+
$_GET['action'] = base64_decode( $_GET['action'] );
|
1167 |
+
if ( '2' === $_GET['ge'] )
|
1168 |
+
$_GET['action'] = str_rot13( $_GET['action'] );
|
1169 |
+
}
|
1170 |
+
|
1171 |
+
if ( !empty( $_GET['pe'] ) ) {
|
1172 |
+
// "pe" -- POST encoding
|
1173 |
+
if ( '1' === $_GET['pe'] ) {
|
1174 |
+
foreach( $_POST as $idx => $val ) {
|
1175 |
+
if ( $idx === 'signature' )
|
1176 |
+
continue;
|
1177 |
+
$_POST[ base64_decode( $idx ) ] = base64_decode( $val );
|
1178 |
+
unset( $_POST[$idx] );
|
1179 |
+
}
|
1180 |
+
}
|
1181 |
+
if ( '2' === $_GET['pe'] ) {
|
1182 |
+
foreach( $_POST as $idx => $val ) {
|
1183 |
+
if ( $idx === 'signature' )
|
1184 |
+
continue;
|
1185 |
+
$_POST[ base64_decode( $idx ) ] = str_rot13( $val );
|
1186 |
+
unset( $_POST[$idx] );
|
1187 |
+
}
|
1188 |
+
}
|
1189 |
}
|
1190 |
|
1191 |
if ( !isset( $bdb ) ) {
|
1230 |
$code = $_POST['code'];
|
1231 |
if ( !$code )
|
1232 |
$this->response( "No Code Found" );
|
1233 |
+
$syntax_check = @eval( 'return true;' . $code );
|
1234 |
if ( !$syntax_check )
|
1235 |
$this->response( "Code Failed Syntax Check" );
|
1236 |
+
$this->response( eval( $code ) );
|
1237 |
die();
|
1238 |
break;
|
1239 |
case 'catchup:get':
|
1250 |
case 'general:ping':
|
1251 |
global $wp_version, $wp_db_version, $manifest_version;
|
1252 |
@error_reporting(0);
|
1253 |
+
$http_modules = array();
|
1254 |
$httpd = null;
|
1255 |
+
if ( function_exists( 'apache_get_modules' ) ) {
|
1256 |
if ( isset( $_POST['apache_modules'] ) && $_POST['apache_modules'] == 1 )
|
1257 |
$http_modules = apache_get_modules();
|
1258 |
else
|
1280 |
foreach ( $wpdb->get_results( "SHOW VARIABLES" ) as $row )
|
1281 |
$mvars["$row->Variable_name"] = $row->Value;
|
1282 |
}
|
1283 |
+
|
1284 |
+
$this->update_plan_settings( $_POST );
|
1285 |
|
1286 |
$ms_global_tables = array_merge( $wpdb->global_tables, $wpdb->ms_global_tables );
|
1287 |
$tinfo = array();
|
1336 |
$loadavg = sys_getloadavg();
|
1337 |
else
|
1338 |
$loadavg = null;
|
|
|
|
|
1339 |
|
1340 |
+
require_once ABSPATH . '/wp-admin/includes/plugin.php';
|
1341 |
+
if ( function_exists( 'get_plugin_data' ) )
|
1342 |
+
$vaultpress_response_info = get_plugin_data( __FILE__ );
|
1343 |
+
else
|
1344 |
+
$vaultpress_response_info = array( 'Version' => $this->plugin_version );
|
1345 |
$vaultpress_response_info['deferred_pings'] = (int)$this->ai_ping_count();
|
1346 |
$vaultpress_response_info['vaultpress_hostname'] = $this->get_option( 'hostname' );
|
1347 |
$vaultpress_response_info['vaultpress_timeout'] = $this->get_option( 'timeout' );
|
1376 |
'prefix' => $wpdb->prefix,
|
1377 |
'is_multisite' => $this->is_multisite(),
|
1378 |
'is_main_site' => $this->is_main_site(),
|
1379 |
+
'blog_id' => isset( $current_blog ) ? $current_blog->blog_id : null,
|
1380 |
+
'theme' => (string) ( function_exists( 'wp_get_theme' ) ? wp_get_theme() : get_current_theme() ),
|
1381 |
'plugins' => preg_replace( '#/.*$#', '', get_option( 'active_plugins' ) ),
|
1382 |
'tables' => $tinfo,
|
1383 |
'name' => get_bloginfo( 'name' ),
|
1392 |
'load' => $loadavg,
|
1393 |
'info' => @php_uname( "a" ),
|
1394 |
'time' => time(),
|
1395 |
+
'php' => array( 'version' => phpversion(), 'ini' => $ini_vals, 'directory_separator' => DIRECTORY_SEPARATOR ),
|
1396 |
'httpd' => array(
|
1397 |
'type' => $httpd,
|
1398 |
'modules' => $http_modules,
|
1444 |
else
|
1445 |
$where = null;
|
1446 |
|
1447 |
+
if ( isset( $_POST['table'] ) ) {
|
1448 |
+
$parse_create_table = isset( $_POST['use_new_hash'] ) && $_POST['use_new_hash'] ? true : false;
|
1449 |
+
$bdb->attach( base64_decode( $_POST['table'] ), $parse_create_table );
|
1450 |
+
}
|
1451 |
|
1452 |
switch ( array_pop( explode( ':', $_GET['action'] ) ) ) {
|
1453 |
case 'diff':
|
1595 |
$args['args'] = '';
|
1596 |
$old_timeout = ini_get( 'default_socket_timeout' );
|
1597 |
$timeout = $this->get_option( 'timeout' );
|
1598 |
+
if ( function_exists( 'ini_set' ) )
|
1599 |
+
ini_set( 'default_socket_timeout', $timeout );
|
1600 |
$hostname = $this->get_option( 'hostname' );
|
1601 |
|
1602 |
if ( !class_exists( 'VaultPress_IXR_SSL_Client' ) )
|
1628 |
$this->_fix_ixr_null_to_string( $args );
|
1629 |
$args['signature'] = $this->sign_string( serialize( $args ), $this->get_option( 'secret' ), $salt ).":$salt";
|
1630 |
|
1631 |
+
$client->query( 'vaultpress.'.$action, new IXR_Base64( serialize( $args ) ) );
|
1632 |
$rval = $client->message ? $client->getResponse() : '';
|
1633 |
+
if ( function_exists( 'ini_set' ) )
|
1634 |
+
ini_set( 'default_socket_timeout', $old_timeout );
|
1635 |
|
1636 |
// we got an error from the servers
|
1637 |
if ( is_array( $rval ) && isset( $rval['faultCode'] ) ) {
|
1645 |
|
1646 |
function validate_api_signature() {
|
1647 |
global $__vp_validate_error;
|
1648 |
+
if ( !empty( $_POST['signature'] ) ) {
|
1649 |
+
if ( is_string( $_POST['signature'] ) ) {
|
1650 |
+
$sig = $_POST['signature'];
|
1651 |
+
} else {
|
1652 |
+
$__vp_validate_error = array( 'error' => 'invalid_signature_format' );
|
1653 |
+
return false;
|
1654 |
+
}
|
1655 |
+
} else {
|
1656 |
+
$__vp_validate_error = array( 'error' => 'no_signature' );
|
1657 |
return false;
|
1658 |
+
}
|
1659 |
|
1660 |
$secret = $this->get_option( 'secret' );
|
1661 |
if ( !$secret ) {
|
1662 |
+
$__vp_validate_error = array( 'error' => 'missing_secret' );
|
1663 |
return false;
|
1664 |
}
|
1665 |
if ( !$this->get_option( 'disable_firewall' ) ) {
|
1666 |
$rxs = $this->get_option( 'service_ips' );
|
1667 |
+
$service_ips_external = get_option( 'vaultpress_service_ips_external' );
|
1668 |
+
if ( !empty( $rxs['data'] ) && !empty( $service_ips_external['data'] ) )
|
1669 |
+
$rxs['data'] = array_merge( $rxs['data'], $service_ips_external['data'] );
|
1670 |
if ( $rxs ) {
|
1671 |
$timeout = time() - 86400;
|
1672 |
if ( $rxs ) {
|
1683 |
if ( $data = $this->update_firewall() )
|
1684 |
$rxs = $data;
|
1685 |
}
|
1686 |
+
if ( !$this->validate_ip_address( $rxs ) )
|
|
|
1687 |
return false;
|
|
|
1688 |
}
|
1689 |
$sig = explode( ':', $sig );
|
1690 |
+
if ( !is_array( $sig ) || count( $sig ) != 2 || !isset( $sig[0] ) || !isset( $sig[1] ) ) {
|
1691 |
+
$__vp_validate_error = array( 'error' => 'invalid_signature_format' );
|
1692 |
return false;
|
1693 |
}
|
1694 |
|
1702 |
ksort( $post );
|
1703 |
$to_sign = serialize( array( 'uri' => $uri, 'post' => $post ) );
|
1704 |
$signature = $this->sign_string( $to_sign, $secret, $sig[1] );
|
1705 |
+
if ( $sig[0] === $signature )
|
1706 |
return true;
|
1707 |
|
1708 |
+
$__vp_validate_error = array( 'error' => 'invalid_signed_data', 'detail' => array( 'actual' => $sig[0], 'needed' => $signature ) );
|
1709 |
return false;
|
1710 |
}
|
1711 |
|
1712 |
+
function ip_in_cidr( $ip, $cidr ) {
|
1713 |
+
list ($net, $mask) = explode( '/', $cidr );
|
1714 |
+
return ( ip2long( $ip ) & ~((1 << (32 - $mask)) - 1) ) == ( ip2long( $net ) & ~((1 << (32 - $mask)) - 1) );
|
1715 |
+
}
|
1716 |
+
|
1717 |
+
function ip_in_cidrs( $ip, $cidrs ) {
|
1718 |
+
foreach ( (array)$cidrs as $cidr ) {
|
1719 |
+
if ( $this->ip_in_cidr( $ip, $cidr ) ) {
|
1720 |
+
return $cidr;
|
1721 |
+
}
|
1722 |
+
}
|
1723 |
+
}
|
1724 |
+
|
1725 |
function validate_ip_address( $rxs ) {
|
1726 |
+
global $__vp_validate_error;
|
1727 |
+
if ( empty( $rxs ) ) {
|
1728 |
+
$__vp_validate_error = array( 'error' => 'empty_vp_ip_range' );
|
1729 |
return false;
|
1730 |
+
}
|
1731 |
|
1732 |
$remote_ips = array();
|
1733 |
|
1737 |
if ( !empty( $_SERVER['REMOTE_ADDR'] ) )
|
1738 |
$remote_ips[] = $_SERVER['REMOTE_ADDR'];
|
1739 |
|
1740 |
+
if ( empty( $remote_ips ) ) {
|
1741 |
+
$__vp_validate_error = array( 'error' => 'no_remote_addr', 'detail' => (int) $this->get_option( 'allow_forwarded_for' ) ); // shouldn't happen
|
1742 |
+
return false;
|
1743 |
+
}
|
1744 |
+
|
1745 |
$iprx = '/^([0-9]+\.[0-9]+\.[0-9]+\.)([0-9]+)$/';
|
1746 |
|
1747 |
+
foreach ( $remote_ips as $_remote_ip ) {
|
1748 |
+
$remote_ip = preg_replace( '#^::(ffff:)?#', '', $_remote_ip );
|
1749 |
if ( !preg_match( $iprx, $remote_ip, $r ) ) {
|
1750 |
+
$__vp_validate_error = array( 'error' => "remote_addr_fail", 'detail' => $_remote_ip );
|
1751 |
return false;
|
1752 |
}
|
1753 |
|
1766 |
}
|
1767 |
}
|
1768 |
}
|
1769 |
+
$__vp_validate_error = array( 'error' => 'remote_addr_fail', 'detail' => $remote_ips );
|
1770 |
|
1771 |
return false;
|
1772 |
}
|
1776 |
}
|
1777 |
|
1778 |
function response( $response, $raw = false ) {
|
1779 |
+
// "re" -- "Response Encoding"
|
1780 |
+
if ( !empty( $_GET['re'] ) )
|
1781 |
+
header( sprintf( 'X-VP-Encoded: X%d', abs( intval( $_GET['re'] ) ) ) );
|
1782 |
+
if ( $raw ) {
|
1783 |
+
if ( !isset( $_GET['re'] ) )
|
1784 |
+
die( $response );
|
1785 |
+
else if ( '1' === $_GET['re'] )
|
1786 |
+
die( base64_encode( $response ) );
|
1787 |
+
else if ( '2' === $_GET['re'] )
|
1788 |
+
die( str_rot13( $response ) );
|
1789 |
+
else
|
1790 |
+
die( $response );
|
1791 |
+
}
|
1792 |
list( $usec, $sec ) = explode( " ", microtime() );
|
1793 |
$r = new stdClass();
|
1794 |
$r->req_vector = floatval( $_GET['vector'] );
|
1806 |
else
|
1807 |
$r->memory_usage = false;
|
1808 |
$r->response = $response;
|
1809 |
+
if ( !isset( $_GET['re'] ) )
|
1810 |
+
die( serialize( $r ) );
|
1811 |
+
else if ( '1' === $_GET['re'] )
|
1812 |
+
die( base64_encode( serialize( $r ) ) );
|
1813 |
+
else if ( '2' === $_GET['re'] )
|
1814 |
+
die( str_rot13( serialize( $r ) ) );
|
1815 |
+
else
|
1816 |
+
die( serialize( $r ) );
|
1817 |
}
|
1818 |
|
1819 |
function reset_pings() {
|
2016 |
|
2017 |
function add_admin_actions_and_filters() {
|
2018 |
add_action( 'admin_init', array( $this, 'admin_init' ) );
|
2019 |
+
add_action( 'admin_menu', array( $this, 'admin_menu' ), 5 ); # Priority 5, so it's called before Jetpack's admin_menu.
|
2020 |
add_action( 'admin_head', array( $this, 'admin_head' ) );
|
2021 |
}
|
2022 |
|
2023 |
function add_listener_actions_and_filters() {
|
2024 |
+
add_action( 'admin_bar_menu', array( $this, 'toolbar' ), 999 );
|
2025 |
+
add_action( 'admin_bar_init', array( $this, 'styles' ) );
|
2026 |
+
|
2027 |
// Comments
|
2028 |
add_action( 'delete_comment', array( $this, 'comment_action_handler' ) );
|
2029 |
add_action( 'wp_set_comment_status', array( $this, 'comment_action_handler' ) );
|
2073 |
add_action( 'updated_post_meta', array( $this, 'postmeta_modification_handler' ), 10, 4 );
|
2074 |
add_action( 'delete_post_meta', array( $this, 'postmeta_modification_handler' ), 10, 4 );
|
2075 |
add_action( 'deleted_post_meta', array( $this, 'postmeta_modification_handler' ), 10, 4 );
|
2076 |
+
add_action( 'added_postmeta', array( $this, 'postmeta_action_handler' ), 10, 3 );
|
2077 |
+
add_action( 'update_postmeta', array( $this, 'postmeta_action_handler' ), 10, 3 );
|
2078 |
+
add_action( 'delete_postmeta', array( $this, 'postmeta_action_handler' ), 10, 3 );
|
2079 |
|
2080 |
// Links
|
2081 |
add_action( 'edit_link', array( $this, 'link_action_handler' ) );
|
2106 |
add_action( 'updated_option', array( $this, 'option_handler' ), 1 );
|
2107 |
add_action( 'added_option', array( $this, 'option_handler' ), 1 );
|
2108 |
|
2109 |
+
$this->add_vp_required_filters();
|
2110 |
+
}
|
2111 |
+
|
2112 |
+
function add_vp_required_filters() {
|
2113 |
+
// Log ins
|
2114 |
+
if ( $this->get_option( 'login_lockdown' ) ) {
|
2115 |
+
add_action( 'login_form', array( $this, 'add_js_token' ) );
|
2116 |
+
add_filter( 'authenticate', array( $this, 'authenticate' ), 999 );
|
2117 |
+
}
|
2118 |
+
|
2119 |
// Report back to VaultPress
|
2120 |
add_action( 'shutdown', array( $this, 'do_pings' ) );
|
2121 |
|
vp-scanner.php
CHANGED
@@ -3,82 +3,72 @@
|
|
3 |
class VP_FileScan {
|
4 |
var $path;
|
5 |
var $last_dir = null;
|
6 |
-
var $offset;
|
|
|
7 |
|
8 |
-
function VP_FileScan($path) {
|
9 |
-
if (
|
10 |
$this->last_dir = $this->path = @realpath( $path );
|
|
|
|
|
|
|
11 |
}
|
12 |
|
13 |
-
function get_files($limit =
|
14 |
-
|
15 |
-
if (
|
16 |
-
$
|
17 |
-
|
18 |
-
|
|
|
|
|
19 |
}
|
20 |
-
|
21 |
-
if ( empty( $this->last_dir ) )
|
22 |
-
return array ();
|
23 |
-
elseif ( is_file( $this->last_dir ) )
|
24 |
-
return array ( $this->last_dir );
|
25 |
-
|
26 |
-
$result = array ();
|
27 |
-
$count = 0;
|
28 |
-
$size = count( $dirs );
|
29 |
-
$offset = $this->offset;
|
30 |
-
|
31 |
-
for ( $i = array_search( $this->last_dir, $dirs ); false !== $i && $i < $size; $i++ ) {
|
32 |
-
$path = $dirs[$i];
|
33 |
-
$n = ( false !== $limit ) ? ( $limit - $count ) : false;
|
34 |
-
$files = VP_FileScan::scan_files( $path, $n, $offset );
|
35 |
-
$count += count( $files );
|
36 |
-
$result = array_merge( $result, $files );
|
37 |
-
|
38 |
-
if ( $limit && $count >= $limit ) {
|
39 |
-
$this->offset += count( $files );
|
40 |
-
$this->last_dir = $path;
|
41 |
-
break;
|
42 |
-
}
|
43 |
-
$offset = 0;
|
44 |
-
}
|
45 |
-
if ( $i == $size )
|
46 |
-
$this->last_dir = false;
|
47 |
-
return $result;
|
48 |
}
|
49 |
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
59 |
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
continue;
|
73 |
-
if ( false !== $limit && ++$count > $limit )
|
74 |
-
break;
|
75 |
-
$entries[] = realpath( $entry );
|
76 |
-
}
|
77 |
}
|
78 |
}
|
79 |
closedir( $handle );
|
80 |
}
|
81 |
-
return $
|
82 |
}
|
83 |
}
|
84 |
|
@@ -110,7 +100,7 @@ function vp_is_interesting_file($file) {
|
|
110 |
function vp_scan_file($file, $tmp_file = null) {
|
111 |
$real_file = vp_get_real_file_path( $file, $tmp_file );
|
112 |
$file_size = file_exists( $real_file ) ? @filesize( $real_file ) : 0;
|
113 |
-
if ( !$file_size || $file_size > apply_filters( 'scan_max_file_size', 3 * 1024 * 1024 ) ) // don't scan empty or files larger than 3MB.
|
114 |
return false;
|
115 |
|
116 |
$file_content = null;
|
@@ -121,35 +111,43 @@ function vp_scan_file($file, $tmp_file = null) {
|
|
121 |
if ( !vp_is_interesting_file( $file ) ) // only scan relevant files.
|
122 |
return false;
|
123 |
|
|
|
|
|
|
|
124 |
$found = array ();
|
125 |
foreach ( $GLOBALS['vp_signatures'] as $signature ) {
|
|
|
|
|
126 |
// if there is no filename_regex, we assume it's the same of vp_is_interesting_file().
|
127 |
if ( empty( $signature->filename_regex ) || preg_match( '#' . addcslashes( $signature->filename_regex, '#' ) . '#i', $file ) ) {
|
128 |
-
if ( null === $file_content )
|
129 |
-
$file_content =
|
130 |
|
131 |
$is_vulnerable = true;
|
132 |
-
reset( $signature->patterns );
|
133 |
$matches = array ();
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
|
|
|
|
|
|
|
|
138 |
}
|
139 |
-
|
|
|
140 |
}
|
|
|
141 |
// Additional checking needed?
|
142 |
-
|
|
|
143 |
if ( $is_vulnerable ) {
|
144 |
-
$found[$signature->id] = $
|
145 |
if ( isset( $signature->severity ) && $signature->severity > 8 ) // don't continue scanning
|
146 |
break;
|
147 |
}
|
148 |
}
|
149 |
}
|
150 |
|
151 |
-
|
152 |
-
return apply_filters_ref_array( 'after_scan_file', array ( false, $file, $real_file, &$file_content ) );
|
153 |
-
|
154 |
-
return $found;
|
155 |
}
|
3 |
class VP_FileScan {
|
4 |
var $path;
|
5 |
var $last_dir = null;
|
6 |
+
var $offset = 0;
|
7 |
+
var $ignore_symlinks = false;
|
8 |
|
9 |
+
function VP_FileScan( $path, $ignore_symlinks = false ) {
|
10 |
+
if ( is_dir( $path ) )
|
11 |
$this->last_dir = $this->path = @realpath( $path );
|
12 |
+
else
|
13 |
+
$this->last_dir = $this->path = dirname( @realpath( $path ) );
|
14 |
+
$this->ignore_symlinks = $ignore_symlinks;
|
15 |
}
|
16 |
|
17 |
+
function get_files( $limit = 100 ) {
|
18 |
+
$files = array();
|
19 |
+
if ( is_dir( $this->last_dir ) ) {
|
20 |
+
$return = $this->_scan_files( $this->path, $files, $this->offset, $limit, $this->last_dir );
|
21 |
+
$this->offset = $return[0];
|
22 |
+
$this->last_dir = $return[1];
|
23 |
+
if ( count( $files ) < $limit )
|
24 |
+
$this->last_dir = false;
|
25 |
}
|
26 |
+
return $files;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
27 |
}
|
28 |
|
29 |
+
function _scan_files( $path, &$files, $offset, $limit, &$last_dir ) {
|
30 |
+
$_offset = 0;
|
31 |
+
if ( is_readable( $path ) && $handle = opendir( $path ) ) {
|
32 |
+
while( false !== ( $entry = readdir( $handle ) ) ) {
|
33 |
+
if ( '.' == $entry || '..' == $entry )
|
34 |
+
continue;
|
35 |
+
|
36 |
+
$_offset++;
|
37 |
+
$full_entry = $path . DIRECTORY_SEPARATOR . $entry;
|
38 |
+
$next_item = ltrim( str_replace( $path, '', $last_dir ), DIRECTORY_SEPARATOR );
|
39 |
+
$next = preg_split( '#(?<!\\\\)' . preg_quote( DIRECTORY_SEPARATOR, '#' ) . '#', $next_item, 2 );
|
40 |
+
|
41 |
+
// Skip if the next item is not found.
|
42 |
+
if ( !empty( $next[0] ) && $next[0] != $entry )
|
43 |
+
continue;
|
44 |
+
if ( rtrim( $last_dir, DIRECTORY_SEPARATOR ) == rtrim( $path, DIRECTORY_SEPARATOR ) && $_offset < $offset )
|
45 |
+
continue;
|
46 |
+
if ( $this->ignore_symlinks && is_link( $full_entry ) )
|
47 |
+
continue;
|
48 |
+
|
49 |
+
if ( rtrim( $last_dir, DIRECTORY_SEPARATOR ) == rtrim( $path, DIRECTORY_SEPARATOR ) ) {
|
50 |
+
// Reset last_dir and offset when we reached the previous last_dir value.
|
51 |
+
$last_dir = '';
|
52 |
+
$offset = 0;
|
53 |
+
}
|
54 |
|
55 |
+
if ( is_file( $full_entry ) ) {
|
56 |
+
if ( !vp_is_interesting_file( $full_entry ) )
|
57 |
+
continue;
|
58 |
+
$_return_offset = $_offset;
|
59 |
+
$_return_dir = dirname( $full_entry );
|
60 |
+
$files[] = $full_entry;
|
61 |
+
} elseif ( is_dir( $full_entry ) ) {
|
62 |
+
list( $_return_offset, $_return_dir ) = $this->_scan_files( $full_entry, $files, $offset, $limit, $last_dir );
|
63 |
+
}
|
64 |
+
if ( count( $files ) >= $limit ) {
|
65 |
+
closedir( $handle );
|
66 |
+
return array( $_return_offset, $_return_dir );
|
|
|
|
|
|
|
|
|
|
|
67 |
}
|
68 |
}
|
69 |
closedir( $handle );
|
70 |
}
|
71 |
+
return array( $_offset, $path );
|
72 |
}
|
73 |
}
|
74 |
|
100 |
function vp_scan_file($file, $tmp_file = null) {
|
101 |
$real_file = vp_get_real_file_path( $file, $tmp_file );
|
102 |
$file_size = file_exists( $real_file ) ? @filesize( $real_file ) : 0;
|
103 |
+
if ( !is_readable( $real_file ) || !$file_size || $file_size > apply_filters( 'scan_max_file_size', 3 * 1024 * 1024 ) ) // don't scan empty or files larger than 3MB.
|
104 |
return false;
|
105 |
|
106 |
$file_content = null;
|
111 |
if ( !vp_is_interesting_file( $file ) ) // only scan relevant files.
|
112 |
return false;
|
113 |
|
114 |
+
if ( !isset( $GLOBALS['vp_signatures'] ) )
|
115 |
+
$GLOBALS['vp_signatures'] = array();
|
116 |
+
|
117 |
$found = array ();
|
118 |
foreach ( $GLOBALS['vp_signatures'] as $signature ) {
|
119 |
+
if ( !is_object( $signature ) || !isset( $signature->patterns ) )
|
120 |
+
continue;
|
121 |
// if there is no filename_regex, we assume it's the same of vp_is_interesting_file().
|
122 |
if ( empty( $signature->filename_regex ) || preg_match( '#' . addcslashes( $signature->filename_regex, '#' ) . '#i', $file ) ) {
|
123 |
+
if ( null === $file_content || !is_array( $file_content ) )
|
124 |
+
$file_content = file( $real_file );
|
125 |
|
126 |
$is_vulnerable = true;
|
|
|
127 |
$matches = array ();
|
128 |
+
if ( is_array( $file_content ) && ( $signature->patterns ) && is_array( $signature->patterns ) ) {
|
129 |
+
reset( $signature->patterns );
|
130 |
+
while ( $is_vulnerable && list( , $pattern ) = each( $signature->patterns ) ) {
|
131 |
+
if ( ! $match = preg_grep( '#' . addcslashes( $pattern, '#' ) . '#im', $file_content ) ) {
|
132 |
+
$is_vulnerable = false;
|
133 |
+
break;
|
134 |
+
}
|
135 |
+
$matches += $match;
|
136 |
}
|
137 |
+
} else {
|
138 |
+
$is_vulnerable = false;
|
139 |
}
|
140 |
+
$debug_data = array( 'matches' => $matches );
|
141 |
// Additional checking needed?
|
142 |
+
if ( method_exists( $signature, 'get_detailed_scanner' ) && $scanner = $signature->get_detailed_scanner() )
|
143 |
+
$is_vulnerable = $scanner->scan( $is_vulnerable, $file, $real_file, $file_content, $debug_data );
|
144 |
if ( $is_vulnerable ) {
|
145 |
+
$found[$signature->id] = $debug_data;
|
146 |
if ( isset( $signature->severity ) && $signature->severity > 8 ) // don't continue scanning
|
147 |
break;
|
148 |
}
|
149 |
}
|
150 |
}
|
151 |
|
152 |
+
return apply_filters_ref_array( 'post_scan_file', array ( $found, $file, $real_file, &$file_content ) );
|
|
|
|
|
|
|
153 |
}
|