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 | |
| 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 |
}
|
