Add upstream

This commit is contained in:
root
2019-10-24 00:12:05 +02:00
parent 85d41e4216
commit ac980f592c
3504 changed files with 1049983 additions and 29971 deletions

View File

@@ -0,0 +1,612 @@
<?php
use Automattic\Jetpack\Connection\Client;
/**
* Class Jetpack_Protect_Blocked_Login_Page
*
* Instanciated on the wp-login page when Jetpack modules are loaded and $pagenow
* is available, or during the login_head hook.
*
* Class will only be instanciated if Protect has detected a hard blocked IP address.
*
*
*/
class Jetpack_Protect_Blocked_Login_Page {
private static $__instance = null;
public $can_send_recovery_emails;
public $ip_address;
public $valid_blocked_user_id;
public $email_address;
const HELP_URL = 'https://jetpack.com/support/security-features/#unblock';
const HTTP_STATUS_CODE_TOO_MANY_REQUESTS = 429;
/**
* Singleton implementation
*
* @return object
*/
public static function instance( $ip_address ) {
if ( ! is_a( self::$__instance, 'Jetpack_Protect_Blocked_Login_Page' ) ) {
self::$__instance = new Jetpack_Protect_Blocked_Login_Page( $ip_address );
}
return self::$__instance;
}
function __construct( $ip_address ) {
/**
* Filter controls if an email recovery form is shown to blocked IPs.
*
* A recovery form allows folks to re-gain access to the login form
* via an email link if their IP was mistakenly blocked.
*
* @module protect
*
* @since 5.6.0
*
* @param bool $can_send_recovery_emails Defaults to true.
*/
$this->can_send_recovery_emails = apply_filters( 'jetpack_protect_can_send_recovery_emails', true );
$this->ip_address = $ip_address;
add_filter( 'wp_authenticate_user', array( $this, 'check_valid_blocked_user' ), 10, 1 );
add_filter( 'site_url', array( $this, 'add_args_to_login_post_url' ), 10, 3 );
add_filter( 'network_site_url', array( $this, 'add_args_to_login_post_url' ), 10, 3 );
add_filter( 'lostpassword_url', array( $this, 'add_args_to_lostpassword_url' ), 10, 2 );
add_filter( 'login_url', array( $this, 'add_args_to_login_url' ), 10, 3 );
add_filter( 'lostpassword_redirect', array( $this, 'add_args_to_lostpassword_redirect_url' ), 10, 1 );
}
public function add_args_to_lostpassword_redirect_url( $url ) {
if ( $this->valid_blocked_user_id ) {
$url = empty( $url ) ? wp_login_url() : $url;
$url = add_query_arg(
array(
'validate_jetpack_protect_recovery' => $_GET['validate_jetpack_protect_recovery'],
'user_id' => $_GET['user_id'],
'checkemail' => 'confirm',
),
$url
);
}
return $url;
}
public function add_args_to_lostpassword_url( $url, $redirect ) {
if ( $this->valid_blocked_user_id ) {
$args = array(
'validate_jetpack_protect_recovery' => $_GET['validate_jetpack_protect_recovery'],
'user_id' => $_GET['user_id'],
'action' => 'lostpassword',
);
if ( ! empty( $redirect ) ) {
$args['redirect_to'] = $redirect;
}
$url = add_query_arg( $args, $url );
}
return $url;
}
public function add_args_to_login_post_url( $url, $path, $scheme ) {
if ( $this->valid_blocked_user_id && ( 'login_post' === $scheme || 'login' === $scheme ) ) {
$url = add_query_arg(
array(
'validate_jetpack_protect_recovery' => $_GET['validate_jetpack_protect_recovery'],
'user_id' => $_GET['user_id'],
),
$url
);
}
return $url;
}
public function add_args_to_login_url( $url, $redirect, $force_reauth ) {
if ( $this->valid_blocked_user_id ) {
$args = array(
'validate_jetpack_protect_recovery' => $_GET['validate_jetpack_protect_recovery'],
'user_id' => $_GET['user_id'],
);
if ( ! empty( $redirect ) ) {
$args['redirect_to'] = $redirect;
}
if ( ! empty( $force_reauth ) ) {
$args['reauth'] = '1';
}
$url = add_query_arg( $args, $url );
}
return $url;
}
public function check_valid_blocked_user( $user ) {
if ( $this->valid_blocked_user_id && $this->valid_blocked_user_id != $user->ID ) {
return new WP_Error( 'invalid_recovery_token', __( 'The recovery token is not valid for this user.', 'jetpack' ) );
}
return $user;
}
public function is_blocked_user_valid() {
if ( ! $this->can_send_recovery_emails ) {
return false;
}
if ( $this->valid_blocked_user_id ) {
return true;
}
if ( ! isset( $_GET['validate_jetpack_protect_recovery'], $_GET['user_id'] ) ) {
return false;
}
if ( ! $this->is_valid_protect_recovery_key( $_GET['validate_jetpack_protect_recovery'], $_GET['user_id'] ) ) {
return false;
}
$this->valid_blocked_user_id = (int) $_GET['user_id'];
return true;
}
public function is_valid_protect_recovery_key( $key, $user_id ) {
$path = sprintf( '/sites/%d/protect/recovery/confirm', Jetpack::get_option( 'id' ) );
$response = Client::wpcom_json_api_request_as_blog(
$path,
'1.1',
array(
'method' => 'post'
),
array(
'token' => $key,
'user_id' => $user_id,
'ip' => $this->ip_address,
)
);
$result = json_decode( wp_remote_retrieve_body( $response ) );
if ( is_wp_error( $result ) || empty( $result ) || isset( $result->error ) ) {
return false;
}
return true;
}
public function render_and_die() {
if ( ! $this->can_send_recovery_emails ) {
$this->render_blocked_login_message();
return;
}
if ( isset( $_GET['validate_jetpack_protect_recovery'] ) && $_GET['user_id'] ) {
$error = new WP_Error( 'invalid_token', __( "Oops, we couldn't validate the recovery token.", 'jetpack' ) );
$this->protect_die( $error );
return;
}
if (
isset( $_GET['jetpack-protect-recovery'] ) &&
isset( $_POST['_wpnonce'] ) &&
wp_verify_nonce( $_POST['_wpnonce'], 'bypass-protect' )
) {
$this->process_recovery_email();
return;
}
if ( isset( $_GET['loggedout'] ) && 'true' === $_GET['loggedout'] ) {
$this->protect_die( __( 'You successfully logged out.', 'jetpack' ) );
}
$this->render_recovery_form();
}
public function render_blocked_login_message() {
$this->protect_die( $this->get_html_blocked_login_message() );
}
function process_recovery_email() {
$sent = $this->send_recovery_email();
$show_recovery_form = true;
if ( is_wp_error( $sent ) ) {
if ( 'email_already_sent' === $sent->get_error_code() ) {
$show_recovery_form = false;
}
$this->protect_die( $sent,null,true, $show_recovery_form );
} else {
$this->render_recovery_success();
}
}
function send_recovery_email() {
$email = isset( $_POST['email'] ) ? $_POST['email'] : '';
if ( sanitize_email( $email ) !== $email || ! is_email( $email ) ) {
return new WP_Error( 'invalid_email', __( "Oops, looks like that's not the right email address. Please try again!", 'jetpack' ) );
}
$user = get_user_by( 'email', trim( $email ) );
if ( ! $user ) {
return new WP_Error( 'invalid_user', __( "Oops, we couldn't find a user with that email. Please try again!", 'jetpack' ) );
}
$this->email_address = $email;
$path = sprintf( '/sites/%d/protect/recovery/request', Jetpack::get_option( 'id' ) );
$response = Client::wpcom_json_api_request_as_blog(
$path,
'1.1',
array(
'method' => 'post'
),
array(
'user_id' => $user->ID,
'ip' => $this->ip_address
)
);
$code = wp_remote_retrieve_response_code( $response );
$result = json_decode( wp_remote_retrieve_body( $response ) );
if ( self::HTTP_STATUS_CODE_TOO_MANY_REQUESTS === $code ) {
return new WP_Error( 'email_already_sent', sprintf( __( 'Recovery instructions were sent to %s. Check your inbox!', 'jetpack' ), $this->email_address ) );
} else if ( is_wp_error( $result ) || empty( $result ) || isset( $result->error ) ) {
return new WP_Error( 'email_send_error', __( 'Oops, we were unable to send a recovery email. Try again.', 'jetpack' ) );
}
return true;
}
function protect_die( $content, $title = null, $back_link = false, $recovery_form = false ) {
if ( empty( $title ) ) {
$title = __( 'Jetpack has locked your site\'s login page.', 'jetpack' );
}
if ( is_wp_error( $content ) ) {
$svg = '<svg class="gridicon gridicons-notice" height="24" width="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g><path d="M12 2C6.477 2 2 6.477 2 12s4.477 10 10 10 10-4.477 10-10S17.523 2 12 2zm1 15h-2v-2h2v2zm0-4h-2l-.5-6h3l-.5 6z"/></g></svg>';
$content = '<span class="error"> '. $svg . $content->get_error_message() . '</span>';
}
$content = '<p>'. $content .'</p>';
// If for some reason the login pop up box show up in the wp-admin.
if ( isset( $_GET['interim-login'] ) ) {
$content = "<style>html{ background-color: #fff; } #error-message { margin:0 auto; padding: 1em; box-shadow: none; } </style>" . $content;
}
$this->display_page( $title, $content, $back_link, $recovery_form );
}
function render_recovery_form() {
$content = $this->get_html_blocked_login_message();
$this->protect_die( $content, null, null, true );
}
function render_recovery_success() {
$this->protect_die( sprintf( __( 'Recovery instructions were sent to %s. Check your inbox!', 'jetpack' ), $this->email_address ) );
}
function get_html_blocked_login_message() {
$icon = '<svg class="gridicon gridicons-spam" style="fill:#d94f4f" height="24" width="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g><path d="M17 2H7L2 7v10l5 5h10l5-5V7l-5-5zm-4 15h-2v-2h2v2zm0-4h-2l-.5-6h3l-.5 6z"/></g></svg>';
$ip = str_replace( 'http://', '', esc_url( 'http://' . $this->ip_address ) );
return sprintf(
__( '<p>Your IP address <code>%2$s</code> has been flagged for potential security violations. You can unlock your login by sending yourself a special link via email. <a href="%3$s">Learn More</a></p>', 'jetpack' ),
$icon,
$ip,
esc_url( self::HELP_URL )
);
}
function get_html_recovery_form() {
ob_start(); ?>
<div>
<form method="post" action="?jetpack-protect-recovery=true">
<?php echo wp_nonce_field( 'bypass-protect' ); ?>
<p><label for="email"><?php esc_html_e( 'Your email', 'jetpack' ); ?><br/></label>
<input type="email" name="email" class="text-input"/>
<input type="submit" class="button"
value="<?php esc_attr_e( 'Send email', 'jetpack' ); ?>"/>
</p>
</form>
</div>
<?php
$contents = ob_get_contents();
ob_end_clean();
return $contents;
}
function display_page( $title, $message, $back_button = false, $recovery_form = false ) {
if ( ! headers_sent() ) {
nocache_headers();
header( 'Content-Type: text/html; charset=utf-8' );
}
$text_direction = 'ltr';
if ( is_rtl() ) {
$text_direction = 'rtl';
}
?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" <?php if ( function_exists( 'language_attributes' ) && function_exists( 'is_rtl' ) ) {
language_attributes();
} else {
echo "dir='$text_direction'";
} ?>>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width">
<?php
if ( function_exists( 'wp_no_robots' ) ) {
wp_no_robots();
}
?>
<title><?php echo $title ?></title>
<style type="text/css">
html {
background: #f6f6f6;
}
body {
color: #2e4453;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
margin: 2em auto;
padding: 1em 2em;
max-width: 460px;
text-align: left;
}
body.is-rtl {
text-align: right;
}
h1 {
clear: both;
color: #3d596d;
font-size: 24px;
margin:0 0 24px 0;
padding: 0;
font-weight: 400;
}
#error-message {
box-sizing: border-box;
background: white;
box-shadow: 0 0 0 1px rgba(200, 215, 225, 0.5), 0 1px 2px #e9eff3;
padding: 24px;
}
#error-message img {
margin: 0 auto;
display: block;
}
#error-page {
margin-top: 50px;
}
#error-page p {
font-size: 14px;
line-height: 1.5;
margin: 24px 0 0;
}
#error-page code {
font-family: Consolas, Monaco, monospace;
}
ul li {
margin-bottom: 10px;
font-size: 14px;
}
a {
color: #00aadc;
}
label {
font-weight: bold;
font-size:16px;
}
a:hover,
a:active {
color: #0085be;
}
a:focus {
color: #124964;
-webkit-box-shadow: 0 0 0 1px #5b9dd9,
0 0 2px 1px rgba(30, 140, 190, .8);
box-shadow: 0 0 0 1px #5b9dd9,
0 0 2px 1px rgba(30, 140, 190, .8);
outline: none;
}
.button {
background: #00aadc;
color: white;
border-color: #008ab3;
border-style: solid;
border-width: 1px 1px 2px;
cursor: pointer;
display: inline-block;
margin: 0;
margin-right: 0px;
outline: 0;
overflow: hidden;
font-weight: 500;
text-overflow: ellipsis;
text-decoration: none;
vertical-align: top;
box-sizing: border-box;
font-size: 14px;
line-height: 21px;
border-radius: 4px;
padding: 7px 14px 9px;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
font-size: 14px;
width: 100%;
}
.button:hover,
.button:focus {
border-color: #005082;
outline: none;
}
.button:focus {
border-color: #005082;
-webkit-box-shadow: 0 0 3px rgba(0, 115, 170, .8);
box-shadow: 0 0 3px rgba(0, 115, 170, .8);
outline: none;
}
.button::-moz-focus-inner {
border: 0;
}
.button:active {
border-width: 2px 1px 1px;
}
.gridicon {
fill: currentColor;
vertical-align: middle;
}
#error-footer {
padding: 16px;
}
#error-footer a {
text-decoration: none;
line-height:20px;
font-size: 14px;
color: #4f748e;
}
#error-footer a:hover {
color: #2e4453;
}
#error-footer .gridicon{
width: 16px;
}
#error-footer .gridicons-help {
width: 24px;
margin-right:8px;
}
.is-rtl #error-footer .gridicons-help {
margin-left:8px;
}
.error {
background: #d94f4f;
color:#FFF;
display: block;
border-radius: 3px;
line-height: 1.5;
padding: 16px;
padding-left: 42px;
}
.is-rtl .error {
padding-right: 42px;
}
.error .gridicon {
float: left;
margin-left: -32px;
}
.is-rtl .error .gridicon {
float: right;
margin-right: -32px;
}
.text-input {
margin: 0;
padding: 7px 14px;
width: 100%;
color: #2e4453;
font-size: 16px;
line-height: 1.5;
border: 1px solid #c8d7e1;
background-color: white;
transition: all .15s ease-in-out;
box-sizing: border-box;
margin: 8px 0 16px;
}
#image {
display: block;
width: 200px;
margin: 0 auto;
}
<?php
$rtl_class = '';
if ( 'rtl' == $text_direction ) {
$rtl_class = 'class="is-rtl"';
echo 'body { font-family: Tahoma, Arial; }';
}
?>
</style>
</head>
<body id="error-page" <?php echo $rtl_class; ?>>
<h1 id="error-title"><?php echo esc_html( $title ); ?></h1>
<div id="error-message">
<svg id="image" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 250 134">
<path fill="#E9EFF4" d="M205.2,129.8c3.7-0.7,7.4-0.9,11.1-1.1l5.5-0.1l5.5,0c3.7,0,7.4,0.1,11.1,0.2c3.7,0.1,7.4,0.3,11.1,0.8 c0.3,0,0.5,0.3,0.5,0.6c0,0.2-0.2,0.4-0.5,0.5c-3.7,0.5-7.4,0.6-11.1,0.8c-3.7,0.1-7.4,0.2-11.1,0.2l-5.5,0l-5.5-0.1 c-3.7-0.1-7.4-0.4-11.1-1.1c-0.1,0-0.2-0.2-0.2-0.3C205,129.9,205.1,129.8,205.2,129.8"/>
<path fill="#E9EFF4" d="M0.2,130.9c3-0.7,5.9-0.9,8.9-1.1l4.4-0.1l4.4,0c3,0,5.9,0.1,8.9,0.2c3,0.1,5.9,0.3,8.9,0.8 c0.3,0,0.5,0.3,0.4,0.6c0,0.2-0.2,0.4-0.4,0.4c-3,0.5-5.9,0.6-8.9,0.8c-3,0.1-5.9,0.2-8.9,0.2l-4.4,0l-4.4-0.1 c-3-0.1-5.9-0.4-8.9-1.1c-0.1,0-0.2-0.2-0.2-0.3C0,131,0.1,130.9,0.2,130.9"/>
<path fill="#C8D7E2" d="M101.6,130.1H70.1V52.5c0-8.5,6.9-15.3,15.3-15.3h16.1V130.1z"/>
<path fill="#0DA9DD" d="M191.5,130.1h-73.8v-5.4c0-8.9,7.2-16.1,16.1-16.1h57.7V130.1z"/>
<path fill="#C7E9F5" d="M55.2,25.6l-0.1,9.8L55,57l-0.1,21.6c0,0.2,0.2,0.4,0.4,0.4c0.2,0,0.4-0.2,0.4-0.4L56.6,57l0.8-21.6 c0.1-3.3,0.2-6.5,0.3-9.8H55.2z"/>
<path fill="#C7E9F5" d="M203.1,25.6l0.1,18.1c0.2,28.8,0.4,57.6,1.2,86.3c0,0.4,0.4,0.8,0.8,0.8c0.4,0,0.8-0.3,0.8-0.8 c0.8-28.8,1-57.6,1.2-86.3l0.1-18.1H203.1z"/>
<path fill="#7FD3F2" d="M55.3,25.6v-8.2v-6.8c0-5.9,4-10.7,9-10.7h134c5,0,9,4.8,9,10.7v14.9H55.3z"/>
<path fill="#005083" d="M210.7,25.6c-13.3,1.1-26.7,1-40,1l-40,0.2l-40-0.2c-13.3-0.1-26.7,0-40-1V25c13.3-1.1,26.7-1,40-1l40-0.2 l40,0.2c13.3,0.1,26.7,0,40,1V25.6z"/>
<polygon fill="#C7E9F5" points="168.7,95.6 117.7,95.6 117.7,44.6 "/>
<path fill="#C8D7E2" d="M191.5,56.5c0,11-8.9,19.9-19.9,19.9c-11,0-19.9-8.9-19.9-19.9c0-11,8.9-19.9,19.9-19.9 C182.6,36.6,191.5,45.5,191.5,56.5"/>
<path fill="#FFFFFF" d="M213.2,95.5c-3.3-5.1-3.2-16.7-3.2-28.4h-32.3c0,0-5.2,25.5,4.6,33c7.5-0.1,29.9-0.6,29.9-0.6"/>
<path fill="#C8D7E2" d="M213.5,95.3l-0.1-0.1l-0.3-0.5c-0.2-0.4-0.3-0.7-0.5-1.1c-0.3-0.8-0.5-1.6-0.7-2.4c-0.1-0.5-0.2-1.1-0.3-1.6 c-0.4,0-0.8,0-1.2,0c0.5,2.1,1.1,4.3,2.4,6.1l0.2,0.2c0.2,0,0.4-0.1,0.5-0.3C213.6,95.5,213.6,95.4,213.5,95.3L213.5,95.3z"/>
<path fill="#C8D7E2" d="M212.5,98.6c-0.1,0-0.2,0-0.3,0l-0.1,0H212l-0.3,0l-0.6,0l-1.3,0l-2.5,0l-5,0l-19.5,0.2 c-1.9-1.7-3.1-4.1-3.8-6.5c-0.8-2.6-1.1-5.4-1.2-8.2c-0.2-5.2,0.3-10.4,1.1-15.6l5.7-0.1c0-0.9,0-1.8,0-2.6l-4.4,0l-2.5,0 c-0.4,0-0.8,0.2-1,0.5c-0.1,0.2-0.2,0.3-0.3,0.5l-0.1,0.3l-0.2,1.2c-0.3,1.7-0.5,3.3-0.7,5c-0.3,3.3-0.5,6.7-0.4,10.1 c0.1,3.4,0.5,6.7,1.5,10c0.5,1.6,1.2,3.2,2.2,4.7c0.5,0.7,1,1.4,1.7,2c0.3,0.3,0.6,0.6,1,0.9l0.1,0.1c0.1,0,0.2,0.1,0.3,0.2 c0.2,0.1,0.5,0.1,0.6,0.1l0.6,0l20-0.6l5-0.2l2.5-0.1l1.2,0l0.3,0l0.2,0c0,0,0.3,0,0.4-0.1c0.3-0.2,0.5-0.5,0.5-0.9 C213.1,99.1,212.9,98.7,212.5,98.6z"/>
<path fill="#FFFFFF" d="M223.1,84.8c-3.3-5.1-4.8-16.7-4.8-28.4h-32.3c0,0-3.5,25.5,6.3,33c7.5-0.1,29.9-0.6,29.9-0.6"/>
<path fill="#C8D7E2" d="M222.9,84.9c-1.3-2.1-2.2-4.4-2.8-6.7c-0.6-2.4-1.1-4.8-1.5-7.2c-0.7-4.8-1-9.1-1-13.9l0,0l-31,0.1l0,0 c-0.4,2.8-0.5,5.1-0.5,7.9c-0.1,2.9,0,5.7,0.3,8.6c0.3,2.8,0.8,5.7,1.7,8.3c0.9,2.6,2.3,5.2,4.5,6.9l-0.4-0.1l14.9-0.2 c5-0.1,10-0.1,14.9-0.1c0.1,0,0.3,0.1,0.3,0.3c0,0.1-0.1,0.3-0.2,0.3c-5,0.2-10,0.4-14.9,0.5l-14.9,0.4c-0.1,0-0.3,0-0.4-0.1l0,0 c-2.5-1.9-3.9-4.7-5-7.4c-1-2.8-1.5-5.7-1.9-8.6c-0.3-2.9-0.4-5.8-0.4-8.8c0.1-2.9,0.2-5.8,0.6-8.8c0-0.4,0.4-0.6,0.7-0.6h0 l32.3,0.1h0c0.3,0,0.6,0.3,0.6,0.6v0c0,4.8,0.2,9.6,0.7,14.4c0.3,2.4,0.6,4.8,1.2,7.1c0.5,2.3,1.2,4.7,2.4,6.8c0,0.1,0,0.1,0,0.2 C223.1,85,223,85,222.9,84.9"/>
<path fill="#C8D7E2" d="M192.1,67.1c1.6-0.9,3.4-1.2,5.1-1.3c1.7-0.2,3.5-0.2,5.2-0.2c3.5,0.1,6.9,0.2,10.3,1c0.1,0,0.2,0.2,0.2,0.3 c0,0.1-0.1,0.2-0.2,0.2c-3.4,0.2-6.9,0-10.3,0c-1.7,0-3.4,0-5.1,0c-1.7,0-3.4,0.1-5.1,0.3l0,0c-0.1,0-0.1,0-0.1-0.1 C192,67.2,192.1,67.1,192.1,67.1"/>
<path fill="#C8D7E2" d="M194.1,74c1.4,0,2.7,0,4.1,0c1.4,0,2.7,0,4.1,0c2.7,0,5.4-0.1,8.2-0.2c0.1,0,0.3,0.1,0.3,0.3 c0,0.1-0.1,0.2-0.2,0.3c-1.3,0.5-2.7,0.7-4.1,0.9c-1.4,0.2-2.8,0.2-4.2,0.3c-1.4,0-2.8,0-4.2-0.2c-1.4-0.2-2.8-0.4-4.1-1.1 c-0.1,0-0.1-0.1,0-0.2C193.9,74.1,194,74,194.1,74L194.1,74z"/>
<path fill="#86A6BD" d="M40.2,88.6c-0.5,0-0.8-0.4-0.9-0.9l-0.1-8.2c0-0.7,0-1.4,0-2.1c0.1-0.7,0.2-1.5,0.4-2.2c0.4-1.4,1-2.8,1.9-4 c1.7-2.5,4.3-4.3,7.1-5.1c0.7-0.2,1.5-0.3,2.2-0.5c0.7-0.1,1.5-0.1,2.2-0.1c1.3,0,2.9,0,4.4,0.4c2.9,0.7,5.6,2.5,7.4,4.9 c0.9,1.2,1.6,2.6,2.1,4c0.5,1.4,0.6,3,0.6,4.4l0,16.4c0,0.7-0.6,1.3-1.3,1.3l-6.7,0c-0.7,0-1.3-0.6-1.3-1.3v0l0-10.8l0-5.4 c0-1.4-0.7-2.8-1.8-3.5c-0.6-0.4-1.3-0.6-2-0.7c-0.7,0-1.9,0-2.5,0c-1.4,0.1-2.7,1-3.3,2.3c-0.3,0.7-0.4,1.3-0.4,2.1l0,2.7 l-0.1,5.4l0,0c0,0.5-0.4,0.9-1,0.9"/>
<path fill="#FFFFFF" d="M41.1,86.9l0.1-7.3c-0.1-2.6,0.7-5,2.1-7.1c1.4-2,3.6-3.5,5.9-4.1c0.6-0.2,1.2-0.3,1.8-0.3 c0.6,0,1.2-0.1,1.9,0c1.4,0,2.5,0,3.7,0.4c2.4,0.6,4.5,2,5.9,4c0.7,1,1.3,2.1,1.6,3.2c0.4,1.2,0.5,2.3,0.5,3.7l0,15.1l0,0l-4.2,0 l0-9.5l0-5.4c0-2.2-1.2-4.4-3-5.5c-0.9-0.6-2-0.9-3.1-1c-1.1,0-1.7,0-2.9,0c-2.2,0.2-4.2,1.7-5.1,3.6c-0.5,0.9-0.7,2.1-0.6,3.1 l0,2.7l0.1,4.4l0,0L41.1,86.9L41.1,86.9"/>
<path fill="#86A6BD" d="M36.3,133c-1.9,0-3.8-1.1-4.8-2.8c-0.5-0.8-0.7-1.8-0.7-2.8l0-2.4l0-9.6l-0.1-9.6l0-4.8c0-0.7,0-1.8,0.3-2.8 c0.3-1,0.9-1.8,1.7-2.5c0.8-0.6,1.7-1.1,2.7-1.3c1.1-0.2,1.8-0.1,2.6-0.1l4.8,0l9.6-0.1l19.2,0c2.1,0,4.1,1.2,5.1,3 c0.5,0.9,0.8,2,0.8,3l0,2.4l0,9.6l-0.1,9.6l0,4.8c0,0.7,0,1.8-0.4,2.8c-0.3,0.9-1,1.8-1.7,2.4c-0.8,0.6-1.7,1.1-2.7,1.2 c-1.1,0.1-1.8,0-2.6,0.1l-4.8,0l-9.6-0.1L36.3,133z"/>
<path fill="#FFFFFF" d="M74.8,112.3l-0.1-9.6l0-2.4c0-0.6-0.1-1.1-0.4-1.6c-0.6-1-1.7-1.6-2.8-1.6l-19.2,0L42.7,97l-4.8,0 c-0.8,0-1.7,0-2.2,0c-0.6,0.1-1.1,0.3-1.6,0.7c-0.5,0.4-0.8,0.9-1,1.4c-0.2,0.6-0.2,1.1-0.2,2l0,4.8l-0.1,9.6l0,9.6l0,2.4 c0,0.6,0.2,1.3,0.5,1.8c0.6,1.1,1.9,1.8,3.1,1.8l19.2-0.1l9.6-0.1l4.8,0c0.8,0,1.7,0,2.2-0.1c0.6-0.1,1.2-0.4,1.6-0.8 c0.5-0.4,0.8-0.9,1-1.5c0.2-0.6,0.2-1.1,0.2-2l0-4.8L74.8,112.3z"/>
<path fill="#86A6BD" d="M48.1,121.4l2.9-6.2c0.3-0.6,0.2-1.3-0.3-1.8c-1-1-1.5-2.5-1.2-4c0.3-1.7,1.7-3.1,3.4-3.4 c2.9-0.6,5.4,1.6,5.4,4.4c0,1.2-0.5,2.3-1.3,3.1c-0.5,0.5-0.6,1.2-0.3,1.8l2.9,6.2c0.1,0.2-0.1,0.5-0.3,0.5H48.4 C48.1,121.9,48,121.6,48.1,121.4"/>
</svg>
<?php echo $message; ?>
<?php if ( $recovery_form ) {
echo $this->get_html_recovery_form();
} ?>
</div>
<div id="error-footer">
<?php if ( $back_button && ! $recovery_form ) {
if ( 'rtl' == $text_direction ) {
$back_button_icon = '<svg class="gridicon gridicons-arrow-right" height="24" width="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g><path d="M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8-8-8z"/></g></svg>';
} else {
$back_button_icon = '<svg class="gridicon gridicons-arrow-left" height="24" width="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g><path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"/></g></svg>';
}
?>
<a href='javascript:history.back()'><?php printf( __( '%s Back' ), $back_button_icon ); ?></a>
<?php } else {
$help_icon = '<svg class="gridicon gridicons-help" height="24" width="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g><path d="M12 2C6.477 2 2 6.477 2 12s4.477 10 10 10 10-4.477 10-10S17.523 2 12 2zm1 16h-2v-2h2v2zm0-4.14V15h-2v-2c0-.552.448-1 1-1 1.103 0 2-.897 2-2s-.897-2-2-2-2 .897-2 2H8c0-2.21 1.79-4 4-4s4 1.79 4 4c0 1.862-1.278 3.413-3 3.86z"/></g></svg>';?>
<a href="<?php echo esc_url( self::HELP_URL ); ?>" rel="noopener noreferrer" target="_blank"><?php printf( __( '%s Get help unlocking your site' ), $help_icon );?></a>
<?php } ?>
</div>
</body>
</html>
<?php
die();
}
}

View File

@@ -0,0 +1,158 @@
<?php
if ( ! class_exists( 'Jetpack_Protect_Math_Authenticate' ) ) {
/*
* The math captcha fallback if we can't talk to the Protect API
*/
class Jetpack_Protect_Math_Authenticate {
static $loaded;
function __construct() {
if ( self::$loaded ) {
return;
}
self::$loaded = 1;
add_action( 'login_form', array( $this, 'math_form' ) );
if( isset( $_POST[ 'jetpack_protect_process_math_form' ] ) ) {
add_action( 'init', array( $this, 'process_generate_math_page' ) );
}
}
private static function time_window() {
return ceil( time() / ( MINUTE_IN_SECONDS * 2 ) );
}
/**
* Verifies that a user answered the math problem correctly while logging in.
*
* @return bool Returns true if the math is correct
* @throws Error if insuffient $_POST variables are present.
* @throws Error message if the math is wrong
*/
static function math_authenticate() {
if( isset( $_COOKIE[ 'jpp_math_pass' ] ) ) {
$jetpack_protect = Jetpack_Protect_Module::instance();
$transient = $jetpack_protect->get_transient( 'jpp_math_pass_' . $_COOKIE[ 'jpp_math_pass' ] );
if( !$transient || $transient < 1 ) {
Jetpack_Protect_Math_Authenticate::generate_math_page();
}
return true;
}
$ans = isset( $_POST['jetpack_protect_num'] ) ? (int) $_POST['jetpack_protect_num'] : '' ;
$correct_ans = isset( $_POST[ 'jetpack_protect_answer' ] ) ? $_POST[ 'jetpack_protect_answer' ] : '' ;
$time_window = Jetpack_Protect_Math_Authenticate::time_window();
$salt = get_site_option( 'jetpack_protect_key' ) . '|' . get_site_option( 'admin_email' ) . '|';
$salted_ans_1 = hash_hmac( 'sha1', $ans, $salt . $time_window );
$salted_ans_2 = hash_hmac( 'sha1', $ans, $salt . ( $time_window - 1 ) );
if ( ! $correct_ans || ! $ans ) {
Jetpack_Protect_Math_Authenticate::generate_math_page();
} elseif ( ! hash_equals( $salted_ans_1, $correct_ans ) && ! hash_equals( $salted_ans_2, $correct_ans ) ) {
wp_die(
__( '<strong>You failed to correctly answer the math problem.</strong> This is used to combat spam when the Protect API is unavailable. Please use your browser\'s back button to return to the login form, press the "refresh" button to generate a new math problem, and try to log in again.', 'jetpack' ),
'',
array ( 'response' => 401 )
);
} else {
return true;
}
}
/**
* Creates an interim page to collect answers to a math captcha
*
* @return none, execution stopped
*/
static function generate_math_page( $error = false ) {
ob_start();
?>
<h2><?php esc_html_e( 'Please solve this math problem to prove that you are not a bot. Once you solve it, you will need to log in again.', 'jetpack' ); ?></h2>
<?php if ($error): ?>
<h3><?php esc_html_e( 'Your answer was incorrect, please try again.', 'jetpack' ); ?></h3>
<?php endif ?>
<form action="<?php echo wp_login_url(); ?>" method="post" accept-charset="utf-8">
<?php Jetpack_Protect_Math_Authenticate::math_form(); ?>
<input type="hidden" name="jetpack_protect_process_math_form" value="1" id="jetpack_protect_process_math_form" />
<p><input type="submit" value="<?php esc_attr_e( 'Continue &rarr;', 'jetpack' ); ?>"></p>
</form>
<?php
$mathpage = ob_get_contents();
ob_end_clean();
wp_die(
$mathpage,
'',
array ( 'response' => 401 )
);
}
public function process_generate_math_page() {
$ans = isset( $_POST['jetpack_protect_num'] ) ? (int)$_POST['jetpack_protect_num'] : '';
$correct_ans = isset( $_POST[ 'jetpack_protect_answer' ] ) ? $_POST[ 'jetpack_protect_answer' ] : '' ;
$time_window = Jetpack_Protect_Math_Authenticate::time_window();
$salt = get_site_option( 'jetpack_protect_key' ) . '|' . get_site_option( 'admin_email' ) . '|';
$salted_ans_1 = hash_hmac( 'sha1', $ans, $salt . $time_window );
$salted_ans_2 = hash_hmac( 'sha1', $ans, $salt . ( $time_window - 1 ) );
if ( ! hash_equals( $salted_ans_1, $correct_ans ) && ! hash_equals( $salted_ans_2, $correct_ans ) ) {
Jetpack_Protect_Math_Authenticate::generate_math_page(true);
} else {
$temp_pass = substr( hash_hmac( 'sha1', rand( 1, 100000000 ), get_site_option( 'jetpack_protect_key' ) ), 5, 25 );
$jetpack_protect = Jetpack_Protect_Module::instance();
$jetpack_protect->set_transient( 'jpp_math_pass_' . $temp_pass, 3, DAY_IN_SECONDS );
setcookie('jpp_math_pass', $temp_pass, time() + DAY_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN, false);
remove_action( 'login_form', array( $this, 'math_form' ) );
return true;
}
}
/**
* Requires a user to solve a simple equation. Added to any WordPress login form.
*
* @return VOID outputs html
*/
static function math_form() {
// Check if jpp_math_pass cookie is set and it matches valid transient
if( isset( $_COOKIE[ 'jpp_math_pass' ] ) ) {
$jetpack_protect = Jetpack_Protect_Module::instance();
$transient = $jetpack_protect->get_transient( 'jpp_math_pass_' . $_COOKIE[ 'jpp_math_pass' ] );
if( $transient && $transient > 0 ) {
return '';
}
}
$num1 = rand( 0, 10 );
$num2 = rand( 1, 10 );
$ans = $num1 + $num2;
$time_window = Jetpack_Protect_Math_Authenticate::time_window();
$salt = get_site_option( 'jetpack_protect_key' ) . '|' . get_site_option( 'admin_email' ) . '|';
$salted_ans = hash_hmac( 'sha1', $ans, $salt . $time_window );
?>
<div style="margin: 5px 0 20px;">
<label for="jetpack_protect_answer">
<?php esc_html_e( 'Prove your humanity', 'jetpack' ); ?>
</label>
<br/>
<span style="vertical-align:super;">
<?php echo esc_html( "$num1 &nbsp; + &nbsp; $num2 &nbsp; = &nbsp;" ); ?>
</span>
<input type="text" id="jetpack_protect_answer" name="jetpack_protect_num" value="" size="2" style="width:30px;height:25px;vertical-align:middle;font-size:13px;" class="input" />
<input type="hidden" name="jetpack_protect_answer" value="<?php echo esc_attr( $salted_ans ); ?>" />
</div>
<?php
}
}
}

View File

@@ -0,0 +1,117 @@
/* Do not modify this file directly. It is concatenated from individual module CSS files. */
/* loads inline on wp-admin in order to reduce http requests */
#protect_dashboard_widget .inside {
margin: 0;
padding: 0;
text-align: center;
}
.jetpack-security * {
box-sizing: border-box;
}
/* alert msgs */
#protect_dashboard_widget .msg {
color: #fff;
text-align: center;
padding: 10px;
}
#protect_dashboard_widget .msg.working {
background: #7BAC48;
}
#protect_dashboard_widget .msg.attn {
background: #d94f4f;
}
#protect_dashboard_widget .msg a {
color: #fff;
text-decoration: underline;
}
#protect_dashboard_widget .msg a:hover {
text-decoration: none;
}
#protect_dashboard_widget .msg .dashicons {
float: left;
text-decoration: none;
border-radius: 2px;
}
#protect_dashboard_widget .msg.working .dashicons {
color: #609643;
}
#protect_dashboard_widget .msg.working .dashicons:hover {
background: #609643;
color: #7BAC48;
}
#protect_dashboard_widget .msg.attn .dashicons {
color: #a93838;
}
#protect_dashboard_widget .msg.attn .dashicons:hover {
background: #a93838;
color: #d94f4f;
}
.blocked-attacks,
.file-scanning {
position: relative;
}
.blocked-attacks {
background: #fafafa;
border-bottom: 1px #eee solid;
padding-bottom: 35px;
}
.jetpack-security-sharing {
width: 60px;
display: inline-block;
position: absolute;
left: 0;
top: 10px;
}
.jetpack-security-sharing a {
color: #dcdcdc;
}
.jetpack-security-sharing a:hover {
color: #cdcbcb;
}
.blocked-attacks h2,
.blocked-attacks h3 {
color: #7BAC48;
font-weight: 300;
}
.blocked-attacks h2 {
font-size: 4em;
line-height: 110%;
margin: 0;
padding: 10px 12px 10px 12px;
}
.blocked-attacks h3 {
font-size: 1.1em;
line-height: 110%;
padding: 0 12px 10px 12px;
margin: 0;
}
.jetpack-protect-logo {
width: 50px;
position: relative;
}
.file-scanning {
margin-top: -30px;
padding: 0 12px;
}

View File

@@ -0,0 +1 @@
#protect_dashboard_widget .inside{margin:0;padding:0;text-align:center}.jetpack-security *{box-sizing:border-box}#protect_dashboard_widget .msg{color:#fff;text-align:center;padding:10px}#protect_dashboard_widget .msg.working{background:#7bac48}#protect_dashboard_widget .msg.attn{background:#d94f4f}#protect_dashboard_widget .msg a{color:#fff;text-decoration:underline}#protect_dashboard_widget .msg a:hover{text-decoration:none}#protect_dashboard_widget .msg .dashicons{float:left;text-decoration:none;border-radius:2px}#protect_dashboard_widget .msg.working .dashicons{color:#609643}#protect_dashboard_widget .msg.working .dashicons:hover{background:#609643;color:#7bac48}#protect_dashboard_widget .msg.attn .dashicons{color:#a93838}#protect_dashboard_widget .msg.attn .dashicons:hover{background:#a93838;color:#d94f4f}.blocked-attacks,.file-scanning{position:relative}.blocked-attacks{background:#fafafa;border-bottom:1px #eee solid;padding-bottom:35px}.jetpack-security-sharing{width:60px;display:inline-block;position:absolute;left:0;top:10px}.jetpack-security-sharing a{color:#dcdcdc}.jetpack-security-sharing a:hover{color:#cdcbcb}.blocked-attacks h2,.blocked-attacks h3{color:#7bac48;font-weight:300}.blocked-attacks h2{font-size:4em;line-height:110%;margin:0;padding:10px 12px 10px 12px}.blocked-attacks h3{font-size:1.1em;line-height:110%;padding:0 12px 10px 12px;margin:0}.jetpack-protect-logo{width:50px;position:relative}.file-scanning{margin-top:-30px;padding:0 12px}

View File

@@ -0,0 +1,116 @@
/* loads inline on wp-admin in order to reduce http requests */
#protect_dashboard_widget .inside {
margin: 0;
padding: 0;
text-align: center;
}
.jetpack-security * {
box-sizing: border-box;
}
/* alert msgs */
#protect_dashboard_widget .msg {
color: #fff;
text-align: center;
padding: 10px;
}
#protect_dashboard_widget .msg.working {
background: #7BAC48;
}
#protect_dashboard_widget .msg.attn {
background: #d94f4f;
}
#protect_dashboard_widget .msg a {
color: #fff;
text-decoration: underline;
}
#protect_dashboard_widget .msg a:hover {
text-decoration: none;
}
#protect_dashboard_widget .msg .dashicons {
float: right;
text-decoration: none;
border-radius: 2px;
}
#protect_dashboard_widget .msg.working .dashicons {
color: #609643;
}
#protect_dashboard_widget .msg.working .dashicons:hover {
background: #609643;
color: #7BAC48;
}
#protect_dashboard_widget .msg.attn .dashicons {
color: #a93838;
}
#protect_dashboard_widget .msg.attn .dashicons:hover {
background: #a93838;
color: #d94f4f;
}
.blocked-attacks,
.file-scanning {
position: relative;
}
.blocked-attacks {
background: #fafafa;
border-bottom: 1px #eee solid;
padding-bottom: 35px;
}
.jetpack-security-sharing {
width: 60px;
display: inline-block;
position: absolute;
right: 0;
top: 10px;
}
.jetpack-security-sharing a {
color: #dcdcdc;
}
.jetpack-security-sharing a:hover {
color: #cdcbcb;
}
.blocked-attacks h2,
.blocked-attacks h3 {
color: #7BAC48;
font-weight: 300;
}
.blocked-attacks h2 {
font-size: 4em;
line-height: 110%;
margin: 0;
padding: 10px 12px 10px 12px;
}
.blocked-attacks h3 {
font-size: 1.1em;
line-height: 110%;
padding: 0 12px 10px 12px;
margin: 0;
}
.jetpack-protect-logo {
width: 50px;
position: relative;
}
.file-scanning {
margin-top: -30px;
padding: 0 12px;
}

View File

@@ -0,0 +1,2 @@
/* Do not modify this file directly. It is concatenated from individual module CSS files. */
#protect_dashboard_widget .inside{margin:0;padding:0;text-align:center}.jetpack-security *{box-sizing:border-box}#protect_dashboard_widget .msg{color:#fff;text-align:center;padding:10px}#protect_dashboard_widget .msg.working{background:#7bac48}#protect_dashboard_widget .msg.attn{background:#d94f4f}#protect_dashboard_widget .msg a{color:#fff;text-decoration:underline}#protect_dashboard_widget .msg a:hover{text-decoration:none}#protect_dashboard_widget .msg .dashicons{float:right;text-decoration:none;border-radius:2px}#protect_dashboard_widget .msg.working .dashicons{color:#609643}#protect_dashboard_widget .msg.working .dashicons:hover{background:#609643;color:#7bac48}#protect_dashboard_widget .msg.attn .dashicons{color:#a93838}#protect_dashboard_widget .msg.attn .dashicons:hover{background:#a93838;color:#d94f4f}.blocked-attacks,.file-scanning{position:relative}.blocked-attacks{background:#fafafa;border-bottom:1px #eee solid;padding-bottom:35px}.jetpack-security-sharing{width:60px;display:inline-block;position:absolute;right:0;top:10px}.jetpack-security-sharing a{color:#dcdcdc}.jetpack-security-sharing a:hover{color:#cdcbcb}.blocked-attacks h2,.blocked-attacks h3{color:#7bac48;font-weight:300}.blocked-attacks h2{font-size:4em;line-height:110%;margin:0;padding:10px 12px 10px 12px}.blocked-attacks h3{font-size:1.1em;line-height:110%;padding:0 12px 10px 12px;margin:0}.jetpack-protect-logo{width:50px;position:relative}.file-scanning{margin-top:-30px;padding:0 12px}

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -0,0 +1,316 @@
<?php
/**
* These functions are shared by the Protect module and its related json-endpoints
*/
/**
* Returns an array of IP objects that will never be blocked by the Protect module
*
* The array is segmented into a local whitelist which applies only to the current site
* and a global whitelist which, for multisite installs, applies to the entire networko
*
* @return array
*/
function jetpack_protect_format_whitelist() {
$local_whitelist = jetpack_protect_get_local_whitelist();
$formatted = array(
'local' => array(),
);
foreach ( $local_whitelist as $item ) {
if ( $item->range ) {
$formatted['local'][] = $item->range_low . ' - ' . $item->range_high;
} else {
$formatted['local'][] = $item->ip_address;
}
}
if ( is_multisite() && current_user_can( 'manage_network' ) ) {
$formatted['global'] = array();
$global_whitelist = jetpack_protect_get_global_whitelist();
if ( false === $global_whitelist ) {
// If the global whitelist has never been set, check for a legacy option set prior to 3.6.
$global_whitelist = get_site_option( 'jetpack_protect_whitelist', array() );
}
foreach ( $global_whitelist as $item ) {
if ( $item->range ) {
$formatted['global'][] = $item->range_low . ' - ' . $item->range_high;
} else {
$formatted['global'][] = $item->ip_address;
}
}
}
return $formatted;
}
/**
* Gets the local Protect whitelist
*
* The 'local' part of the whitelist only really applies to multisite installs,
* which can have a network wide whitelist, as well as a local list that applies
* only to the current site. On single site installs, there will only be a local
* whitelist.
*
* @return array A list of IP Address objects or an empty array
*/
function jetpack_protect_get_local_whitelist() {
$whitelist = Jetpack_Options::get_option( 'protect_whitelist' );
if ( false === $whitelist ) {
// The local whitelist has never been set.
if ( is_multisite() ) {
// On a multisite, we can check for a legacy site_option that existed prior to v 3.6, or default to an empty array.
$whitelist = get_site_option( 'jetpack_protect_whitelist', array() );
} else {
// On a single site, we can just use an empty array.
$whitelist = array();
}
}
return $whitelist;
}
/**
* Get the global, network-wide whitelist
*
* It will revert to the legacy site_option if jetpack_protect_global_whitelist has never been set.
*
* @return array
*/
function jetpack_protect_get_global_whitelist() {
$whitelist = get_site_option( 'jetpack_protect_global_whitelist' );
if ( false === $whitelist ) {
// The global whitelist has never been set. Check for legacy site_option, or default to an empty array.
$whitelist = get_site_option( 'jetpack_protect_whitelist', array() );
}
return $whitelist;
}
/**
* Jetpack Protect Save Whitelist.
*
* @access public
* @param mixed $whitelist Whitelist.
* @param bool $global (default: false) Global.
* @return Bool.
*/
function jetpack_protect_save_whitelist( $whitelist, $global = false ) {
$whitelist_error = false;
$new_items = array();
if ( ! is_array( $whitelist ) ) {
return new WP_Error( 'invalid_parameters', __( 'Expecting an array', 'jetpack' ) );
}
if ( $global && ! is_multisite() ) {
return new WP_Error( 'invalid_parameters', __( 'Cannot use global flag on non-multisites', 'jetpack' ) );
}
if ( $global && ! current_user_can( 'manage_network' ) ) {
return new WP_Error( 'permission_denied', __( 'Only super admins can edit the global whitelist', 'jetpack' ) );
}
// Validate each item.
foreach ( $whitelist as $item ) {
$item = trim( $item );
if ( empty( $item ) ) {
continue;
}
$range = false;
if ( strpos( $item, '-' ) ) {
$item = explode( '-', $item );
$range = true;
}
$new_item = new stdClass();
$new_item->range = $range;
if ( ! empty( $range ) ) {
$low = trim( $item[0] );
$high = trim( $item[1] );
if ( ! filter_var( $low, FILTER_VALIDATE_IP ) || ! filter_var( $high, FILTER_VALIDATE_IP ) ) {
$whitelist_error = true;
break;
}
if ( ! jetpack_convert_ip_address( $low ) || ! jetpack_convert_ip_address( $high ) ) {
$whitelist_error = true;
break;
}
$new_item->range_low = $low;
$new_item->range_high = $high;
} else {
if ( ! filter_var( $item, FILTER_VALIDATE_IP ) ) {
$whitelist_error = true;
break;
}
if ( ! jetpack_convert_ip_address( $item ) ) {
$whitelist_error = true;
break;
}
$new_item->ip_address = $item;
}
$new_items[] = $new_item;
} // End item loop.
if ( ! empty( $whitelist_error ) ) {
return new WP_Error( 'invalid_ip', __( 'One of your IP addresses was not valid.', 'jetpack' ) );
}
if ( $global ) {
update_site_option( 'jetpack_protect_global_whitelist', $new_items );
// Once a user has saved their global whitelist, we can permanently remove the legacy option.
delete_site_option( 'jetpack_protect_whitelist' );
} else {
Jetpack_Options::update_option( 'protect_whitelist', $new_items );
}
return true;
}
/**
* Jetpack Protect Get IP.
*
* @access public
* @return IP.
*/
function jetpack_protect_get_ip() {
$trusted_header_data = get_site_option( 'trusted_ip_header' );
if ( isset( $trusted_header_data->trusted_header ) && isset( $_SERVER[ $trusted_header_data->trusted_header ] ) ) {
$ip = $_SERVER[ $trusted_header_data->trusted_header ];
$segments = $trusted_header_data->segments;
$reverse_order = $trusted_header_data->reverse;
} else {
$ip = $_SERVER['REMOTE_ADDR'];
}
if ( ! $ip ) {
return false;
}
$ips = explode( ',', $ip );
if ( ! isset( $segments ) || ! $segments ) {
$segments = 1;
}
if ( isset( $reverse_order ) && $reverse_order ) {
$ips = array_reverse( $ips );
}
$ip_count = count( $ips );
if ( 1 === $ip_count ) {
return jetpack_clean_ip( $ips[0] );
} elseif ( $ip_count >= $segments ) {
$the_one = $ip_count - $segments;
return jetpack_clean_ip( $ips[ $the_one ] );
} else {
return jetpack_clean_ip( $_SERVER['REMOTE_ADDR'] );
}
}
/**
* Jetpack Clean IP.
*
* @access public
* @param mixed $ip IP.
* @return $ip IP.
*/
function jetpack_clean_ip( $ip ) {
// Some misconfigured servers give back extra info, which comes after "unless"
$ips = explode( ' unless ', $ip );
$ip = $ips[0];
$ip = trim( $ip );
// Check for IPv4 IP cast as IPv6.
if ( preg_match( '/^::ffff:(\d+\.\d+\.\d+\.\d+)$/', $ip, $matches ) ) {
$ip = $matches[1];
}
if ( function_exists( 'parse_url' ) ) {
$parsed_url = parse_url( $ip );
if ( isset( $parsed_url['host'] ) ) {
$ip = $parsed_url['host'];
} elseif ( isset( $parsed_url['path'] ) ) {
$ip = $parsed_url['path'];
}
} else {
$colon_count = substr_count( $ip, ':' );
if ( 1 == $colon_count ) {
$ips = explode( ':', $ip );
$ip = $ips[0];
}
}
return $ip;
}
/**
* Checks an IP to see if it is within a private range.
*
* @param int $ip IP.
* @return bool
*/
function jetpack_protect_ip_is_private( $ip ) {
// We are dealing with ipv6, so we can simply rely on filter_var.
if ( false === strpos( $ip, '.' ) ) {
return ! filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE );
}
// We are dealing with ipv4.
$private_ip4_addresses = array(
'10.0.0.0|10.255.255.255', // Single class A network.
'172.16.0.0|172.31.255.255', // 16 contiguous class B network.
'192.168.0.0|192.168.255.255', // 256 contiguous class C network.
'169.254.0.0|169.254.255.255', // Link-local address also referred to as Automatic Private IP Addressing.
'127.0.0.0|127.255.255.255', // localhost.
);
$long_ip = ip2long( $ip );
if ( -1 !== $long_ip ) {
foreach ( $private_ip4_addresses as $pri_addr ) {
list ( $start, $end ) = explode( '|', $pri_addr );
if ( $long_ip >= ip2long( $start ) && $long_ip <= ip2long( $end ) ) {
return true;
}
}
}
return false;
}
/**
* Uses inet_pton if available to convert an IP address to a binary string.
* If inet_pton is not available, ip2long will convert the address to an integer.
* Returns false if an invalid IP address is given.
*
* NOTE: ip2long will return false for any ipv6 address. servers that do not support
* inet_pton will not support ipv6
*
* @access public
* @param mixed $ip IP.
* @return int|string|bool
*/
function jetpack_convert_ip_address( $ip ) {
if ( function_exists( 'inet_pton' ) ) {
return inet_pton( $ip );
}
return ip2long( $ip );
}
/**
* Checks that a given IP address is within a given low - high range.
* Servers that support inet_pton will use that function to convert the ip to number,
* while other servers will use ip2long.
*
* NOTE: servers that do not support inet_pton cannot support ipv6.
*
* @access public
* @param mixed $ip IP.
* @param mixed $range_low Range Low.
* @param mixed $range_high Range High.
* @return Bool.
*/
function jetpack_protect_ip_address_is_in_range( $ip, $range_low, $range_high ) {
// The inet_pton will give us binary string of an ipv4 or ipv6.
// We can then use strcmp to see if the address is in range.
if ( function_exists( 'inet_pton' ) ) {
$ip_num = inet_pton( $ip );
$ip_low = inet_pton( $range_low );
$ip_high = inet_pton( $range_high );
if ( $ip_num && $ip_low && $ip_high && strcmp( $ip_num, $ip_low ) >= 0 && strcmp( $ip_num, $ip_high ) <= 0 ) {
return true;
}
// The ip2long will give us an integer of an ipv4 address only. it will produce FALSE for ipv6.
} else {
$ip_num = ip2long( $ip );
$ip_low = ip2long( $range_low );
$ip_high = ip2long( $range_high );
if ( $ip_num && $ip_low && $ip_high && $ip_num >= $ip_low && $ip_num <= $ip_high ) {
return true;
}
}
return false;
}

View File

@@ -0,0 +1,58 @@
<?php
/*
Adapted from Purge Transients by Seebz
https://github.com/Seebz/Snippets/tree/master/Wordpress/plugins/purge-transients
*/
if ( ! function_exists( 'jp_purge_transients' ) ) {
/**
* Jetpack Purge Transients.
*
* @access public
* @param string $older_than (default: '1 hour') Older Than.
* @return void
*/
function jp_purge_transients( $older_than = '1 hour' ) {
global $wpdb;
$older_than_time = strtotime( '-' . $older_than );
if ( $older_than_time > time() || $older_than_time < 1 ) {
return false;
}
$sql = $wpdb->prepare( "
SELECT REPLACE(option_name, '_transient_timeout_jpp_', '') AS transient_name
FROM {$wpdb->options}
WHERE option_name LIKE '\_transient\_timeout\_jpp\__%%'
AND option_value < %d
", $older_than_time );
$transients = $wpdb->get_col( $sql );
$options_names = array();
foreach ( $transients as $transient ) {
$options_names[] = '_transient_jpp_' . $transient;
$options_names[] = '_transient_timeout_jpp_' . $transient;
}
if ( $options_names ) {
$option_names_string = implode( ', ', array_fill( 0, count( $options_names ), '%s' ) );
$delete_sql = "DELETE FROM {$wpdb->options} WHERE option_name IN ($option_names_string)";
$delete_sql = call_user_func_array( array( $wpdb, 'prepare' ), array_merge( array( $delete_sql ), $options_names ) );
$result = $wpdb->query( $delete_sql );
if ( ! $result ) {
return false;
}
}
return;
}
}
/**
* Jetpack Purge Transients Activation.
*
* @access public
* @return void
*/
function jp_purge_transients_activation() {
if ( ! wp_next_scheduled( 'jp_purge_transients_cron' ) ) {
wp_schedule_event( time(), 'daily', 'jp_purge_transients_cron' );
}
}
add_action( 'admin_init', 'jp_purge_transients_activation' );
add_action( 'jp_purge_transients_cron', 'jp_purge_transients' );