rebase from live enviornment
This commit is contained in:
@@ -0,0 +1,183 @@
|
||||
<?php
|
||||
|
||||
class wfRESTAuthenticationController {
|
||||
|
||||
const NONCE_AGE = 600;
|
||||
|
||||
public static function generateNonce($tickOffset = 0) {
|
||||
add_filter('nonce_life', 'wfRESTAuthenticationController::nonceAge');
|
||||
|
||||
$i = wp_nonce_tick();
|
||||
$salt = wp_salt('nonce');
|
||||
$nonce = hash_hmac('sha256', ($i + $tickOffset) . '|wordfence-rest-api-auth', $salt);
|
||||
|
||||
remove_filter('nonce_life', 'wfRESTAuthenticationController::nonceAge');
|
||||
|
||||
return $nonce;
|
||||
}
|
||||
|
||||
public static function generateToken() {
|
||||
return new wfJWT(wfConfig::get('wordfenceCentralSiteID'));
|
||||
}
|
||||
|
||||
public static function nonceAge() {
|
||||
return self::NONCE_AGE;
|
||||
}
|
||||
|
||||
public function registerRoutes() {
|
||||
register_rest_route('wordfence/v1', '/authenticate', array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array($this, 'nonce'),
|
||||
'permission_callback' => '__return_true',
|
||||
));
|
||||
register_rest_route('wordfence/v1', '/authenticate', array(
|
||||
'methods' => WP_REST_Server::CREATABLE,
|
||||
'callback' => array($this, 'authenticate'),
|
||||
'permission_callback' => '__return_true',
|
||||
));
|
||||
register_rest_route('wordfence/v1', '/authenticate-premium', array(
|
||||
'methods' => WP_REST_Server::CREATABLE,
|
||||
'callback' => array($this, 'authenticatePremium'),
|
||||
'permission_callback' => '__return_true',
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WP_REST_Request $request
|
||||
* @return mixed|WP_REST_Response
|
||||
*/
|
||||
public function nonce($request) {
|
||||
$response = rest_ensure_response(array(
|
||||
'nonce' => self::generateNonce(),
|
||||
'admin_url' => network_admin_url(),
|
||||
));
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WP_REST_Request $request
|
||||
* @return mixed|WP_REST_Response
|
||||
*/
|
||||
public function authenticate($request) {
|
||||
require_once(WORDFENCE_PATH . '/lib/sodium_compat_fast.php');
|
||||
|
||||
$siteID = wfConfig::get('wordfenceCentralSiteID');
|
||||
if (!$siteID) {
|
||||
return new WP_Error('rest_forbidden_context',
|
||||
__('Site is not connected to Wordfence Central.', 'wordfence'),
|
||||
array('status' => rest_authorization_required_code()));
|
||||
}
|
||||
|
||||
// verify signature.
|
||||
$data = $request->get_param('data');
|
||||
$dataChunks = explode('|', $data, 2);
|
||||
if (count($dataChunks) !== 2) {
|
||||
return new WP_Error('rest_forbidden_context',
|
||||
__('Data is invalid.', 'wordfence'),
|
||||
array('status' => rest_authorization_required_code()));
|
||||
}
|
||||
if (!preg_match('/[0-9a-f]{64}/i', $dataChunks[0])) {
|
||||
return new WP_Error('rest_forbidden_context',
|
||||
__('Nonce format is invalid.', 'wordfence'),
|
||||
array('status' => rest_authorization_required_code()));
|
||||
}
|
||||
if (!preg_match('/[0-9a-f\-]{36}/i', $dataChunks[1])) {
|
||||
return new WP_Error('rest_forbidden_context',
|
||||
__('Site ID is invalid.', 'wordfence'),
|
||||
array('status' => rest_authorization_required_code()));
|
||||
}
|
||||
if (!hash_equals($siteID, $dataChunks[1])) {
|
||||
return new WP_Error('rest_forbidden_context',
|
||||
__('Site ID is invalid.', 'wordfence'),
|
||||
array('status' => rest_authorization_required_code()));
|
||||
}
|
||||
|
||||
$signature = $request->get_param('signature');
|
||||
$nonce1 = self::generateNonce();
|
||||
$nonce2 = self::generateNonce(-1);
|
||||
$verfiedNonce = hash_equals($nonce1, $dataChunks[0]) || hash_equals($nonce2, $dataChunks[0]);
|
||||
|
||||
if (!$verfiedNonce) {
|
||||
return new WP_Error('rest_forbidden_context',
|
||||
__('Nonce is invalid.', 'wordfence'),
|
||||
array('status' => rest_authorization_required_code()));
|
||||
}
|
||||
$signature = pack('H*', $signature);
|
||||
if (!ParagonIE_Sodium_Compat::crypto_sign_verify_detached($signature, $data, wfConfig::get('wordfenceCentralPK'))) {
|
||||
return new WP_Error('rest_forbidden_context',
|
||||
__('Signature is invalid.', 'wordfence'),
|
||||
array('status' => rest_authorization_required_code()));
|
||||
}
|
||||
|
||||
$response = rest_ensure_response(array(
|
||||
'token' => (string) self::generateToken(),
|
||||
));
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WP_REST_Request $request
|
||||
* @return mixed|WP_REST_Response
|
||||
*/
|
||||
public function authenticatePremium($request) {
|
||||
require_once(WORDFENCE_PATH . '/lib/sodium_compat_fast.php');
|
||||
|
||||
// verify signature.
|
||||
$data = $request->get_param('data');
|
||||
$dataChunks = explode('|', $data, 2);
|
||||
if (count($dataChunks) !== 2) {
|
||||
return new WP_Error('rest_forbidden_context',
|
||||
__('Data is invalid.', 'wordfence'),
|
||||
array('status' => rest_authorization_required_code()));
|
||||
}
|
||||
if (!preg_match('/[0-9a-f]{64}/i', $dataChunks[0])) {
|
||||
return new WP_Error('rest_forbidden_context',
|
||||
__('Nonce format is invalid.', 'wordfence'),
|
||||
array('status' => rest_authorization_required_code()));
|
||||
}
|
||||
if (!is_email($dataChunks[1])) {
|
||||
return new WP_Error('rest_forbidden_context',
|
||||
__('Email address is invalid.', 'wordfence'),
|
||||
array('status' => rest_authorization_required_code()));
|
||||
}
|
||||
|
||||
$adminEmail = $dataChunks[1];
|
||||
|
||||
$signature = $request->get_param('signature');
|
||||
$nonce1 = self::generateNonce();
|
||||
$nonce2 = self::generateNonce(-1);
|
||||
$verfiedNonce = hash_equals($nonce1, $dataChunks[0]) || hash_equals($nonce2, $dataChunks[0]);
|
||||
|
||||
if (!$verfiedNonce) {
|
||||
return new WP_Error('rest_forbidden_context',
|
||||
__('Nonce is invalid.', 'wordfence'),
|
||||
array('status' => rest_authorization_required_code()));
|
||||
}
|
||||
$signature = pack('H*', $signature);
|
||||
if (!ParagonIE_Sodium_Compat::crypto_sign_verify_detached($signature, $data, WORDFENCE_CENTRAL_PUBLIC_KEY)) {
|
||||
return new WP_Error('rest_forbidden_context',
|
||||
__('Signature is invalid.', 'wordfence'),
|
||||
array('status' => rest_authorization_required_code()));
|
||||
}
|
||||
|
||||
$user_query = new WP_User_Query(array(
|
||||
'role' => 'administrator',
|
||||
'search' => $adminEmail,
|
||||
'search_columns' => array('user_email')
|
||||
));
|
||||
$users = $user_query->get_results();
|
||||
if (is_array($users) && count($users) === 1) {
|
||||
$jwt = new wfJWT('wordfence-central-premium');
|
||||
$jwt->addClaims(array('email' => $adminEmail));
|
||||
$response = rest_ensure_response(array(
|
||||
'token' => (string) $jwt,
|
||||
));
|
||||
return $response;
|
||||
}
|
||||
|
||||
return new WP_Error('rest_forbidden_context',
|
||||
__('Admin user with this email address not found.', 'wordfence'),
|
||||
array('status' => rest_authorization_required_code()));
|
||||
}
|
||||
|
||||
}
|
||||
87
wp/plugins/wordfence/lib/rest-api/wfRESTBaseController.php
Normal file
87
wp/plugins/wordfence/lib/rest-api/wfRESTBaseController.php
Normal file
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
abstract class wfRESTBaseController {
|
||||
|
||||
protected $tokenData;
|
||||
|
||||
/**
|
||||
* @param WP_REST_Request $request
|
||||
* @return WP_Error|bool
|
||||
*/
|
||||
public function verifyToken($request) {
|
||||
$validToken = $this->isTokenValid($request);
|
||||
|
||||
if ($validToken &&
|
||||
!is_wp_error($validToken) &&
|
||||
$this->tokenData['body']['sub'] === wfConfig::get('wordfenceCentralSiteID')
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (is_wp_error($validToken)) {
|
||||
return $validToken;
|
||||
}
|
||||
|
||||
return new WP_Error('rest_forbidden_context',
|
||||
__('Token is invalid.', 'wordfence'),
|
||||
array('status' => rest_authorization_required_code()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WP_REST_Request $request
|
||||
* @return WP_Error|bool
|
||||
*/
|
||||
public function verifyTokenPremium($request) {
|
||||
$validToken = $this->isTokenValid($request);
|
||||
|
||||
if ($validToken &&
|
||||
!is_wp_error($validToken) &&
|
||||
$this->tokenData['body']['sub'] === 'wordfence-central-premium'
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (is_wp_error($validToken)) {
|
||||
return $validToken;
|
||||
}
|
||||
|
||||
return new WP_Error('rest_forbidden_context',
|
||||
__('Token is invalid.', 'wordfence'),
|
||||
array('status' => rest_authorization_required_code()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WP_REST_Request $request
|
||||
* @return bool|WP_Error
|
||||
*/
|
||||
public function isTokenValid($request) {
|
||||
$authHeader = $request->get_header('Authorization');
|
||||
if (!$authHeader) {
|
||||
$authHeader = $request->get_header('X-Authorization');
|
||||
}
|
||||
if (stripos($authHeader, 'bearer ') !== 0) {
|
||||
return new WP_Error('rest_forbidden_context',
|
||||
__('Authorization header format is invalid.', 'wordfence'),
|
||||
array('status' => rest_authorization_required_code()));
|
||||
}
|
||||
|
||||
$token = trim(substr($authHeader, 7));
|
||||
$jwt = new wfJWT();
|
||||
|
||||
try {
|
||||
$this->tokenData = $jwt->decode($token);
|
||||
|
||||
} catch (wfJWTException $e) {
|
||||
return new WP_Error('rest_forbidden_context',
|
||||
$e->getMessage(),
|
||||
array('status' => rest_authorization_required_code()));
|
||||
|
||||
} catch (Exception $e) {
|
||||
return new WP_Error('rest_forbidden_context',
|
||||
__('Token is invalid.', 'wordfence'),
|
||||
array('status' => rest_authorization_required_code()));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
341
wp/plugins/wordfence/lib/rest-api/wfRESTConfigController.php
Normal file
341
wp/plugins/wordfence/lib/rest-api/wfRESTConfigController.php
Normal file
@@ -0,0 +1,341 @@
|
||||
<?php
|
||||
|
||||
use WordfenceLS\Controller_Settings;
|
||||
|
||||
require_once(dirname(__FILE__) . '/wfRESTBaseController.php');
|
||||
|
||||
class wfRESTConfigController extends wfRESTBaseController {
|
||||
|
||||
public static function disconnectConfig($adminEmail = null) {
|
||||
global $wpdb;
|
||||
delete_transient('wordfenceCentralJWT' . wfConfig::get('wordfenceCentralSiteID'));
|
||||
|
||||
if (is_null($adminEmail)) {
|
||||
$adminEmail = wfConfig::get('wordfenceCentralConnectEmail');
|
||||
}
|
||||
|
||||
$result = $wpdb->query('DELETE FROM ' . wfDB::networkTable('wfConfig') . " WHERE name LIKE 'wordfenceCentral%'");
|
||||
|
||||
wfConfig::set('wordfenceCentralDisconnected', true);
|
||||
wfConfig::set('wordfenceCentralDisconnectTime', time());
|
||||
wfConfig::set('wordfenceCentralDisconnectEmail', $adminEmail);
|
||||
wfConfig::set('wordfenceCentralConfigurationIssue', false);
|
||||
|
||||
return !!$result;
|
||||
}
|
||||
|
||||
public function registerRoutes() {
|
||||
register_rest_route('wordfence/v1', '/config', array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array($this, 'getConfig'),
|
||||
'permission_callback' => array($this, 'verifyToken'),
|
||||
'fields' => array(
|
||||
'description' => __('Specific config options to return.', 'wordfence'),
|
||||
'type' => 'array',
|
||||
'required' => false,
|
||||
),
|
||||
));
|
||||
register_rest_route('wordfence/v1', '/config', array(
|
||||
'methods' => WP_REST_Server::EDITABLE,
|
||||
'callback' => array($this, 'setConfig'),
|
||||
'permission_callback' => array($this, 'verifyToken'),
|
||||
'fields' => array(
|
||||
'description' => __('Specific config options to set.', 'wordfence'),
|
||||
'type' => 'array',
|
||||
'required' => true,
|
||||
),
|
||||
));
|
||||
register_rest_route('wordfence/v1', '/disconnect', array(
|
||||
'methods' => WP_REST_Server::EDITABLE,
|
||||
'callback' => array($this, 'disconnect'),
|
||||
'permission_callback' => array($this, 'verifyToken'),
|
||||
));
|
||||
register_rest_route('wordfence/v1', '/premium-connect', array(
|
||||
'methods' => WP_REST_Server::EDITABLE,
|
||||
'callback' => array($this, 'premiumConnect'),
|
||||
'permission_callback' => array($this, 'verifyTokenPremium'),
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WP_REST_Request $request
|
||||
* @return mixed|WP_REST_Response
|
||||
*/
|
||||
public function getConfig($request) {
|
||||
$fields = (array) $request['fields'];
|
||||
|
||||
$config = array();
|
||||
|
||||
$firewall = new wfFirewall();
|
||||
$wafFields = array(
|
||||
'autoPrepend' => $firewall->protectionMode() === wfFirewall::PROTECTION_MODE_EXTENDED,
|
||||
'avoid_php_input' => wfWAF::getInstance()->getStorageEngine()->getConfig('avoid_php_input', false) ? 1 : 0,
|
||||
'disabledRules' => array_keys((array) wfWAF::getInstance()->getStorageEngine()->getConfig('disabledRules')),
|
||||
'ruleCount' => count((array) wfWAF::getInstance()->getRules()),
|
||||
'disableWAFBlacklistBlocking' => wfWAF::getInstance()->getStorageEngine()->getConfig('disableWAFBlacklistBlocking'),
|
||||
'enabled' => $firewall->wafStatus() !== wfFirewall::FIREWALL_MODE_DISABLED,
|
||||
'firewallMode' => $firewall->firewallMode(),
|
||||
'learningModeGracePeriod' => wfWAF::getInstance()->getStorageEngine()->getConfig('learningModeGracePeriod'),
|
||||
'learningModeGracePeriodEnabled' => wfWAF::getInstance()->getStorageEngine()->getConfig('learningModeGracePeriodEnabled'),
|
||||
'subdirectoryInstall' => $firewall->isSubDirectoryInstallation(),
|
||||
'wafStatus' => $firewall->wafStatus(),
|
||||
);
|
||||
$lsFields = array(
|
||||
Controller_Settings::OPTION_XMLRPC_ENABLED => Controller_Settings::shared()->get(Controller_Settings::OPTION_XMLRPC_ENABLED),
|
||||
Controller_Settings::OPTION_2FA_WHITELISTED => Controller_Settings::shared()->get(Controller_Settings::OPTION_2FA_WHITELISTED),
|
||||
Controller_Settings::OPTION_IP_SOURCE => Controller_Settings::shared()->get(Controller_Settings::OPTION_IP_SOURCE),
|
||||
Controller_Settings::OPTION_IP_TRUSTED_PROXIES => Controller_Settings::shared()->get(Controller_Settings::OPTION_IP_TRUSTED_PROXIES),
|
||||
Controller_Settings::OPTION_REQUIRE_2FA_ADMIN => Controller_Settings::shared()->get(Controller_Settings::OPTION_REQUIRE_2FA_ADMIN),
|
||||
Controller_Settings::OPTION_REQUIRE_2FA_GRACE_PERIOD_ENABLED => Controller_Settings::shared()->get(Controller_Settings::OPTION_REQUIRE_2FA_GRACE_PERIOD_ENABLED),
|
||||
Controller_Settings::OPTION_GLOBAL_NOTICES => Controller_Settings::shared()->get(Controller_Settings::OPTION_GLOBAL_NOTICES),
|
||||
Controller_Settings::OPTION_REMEMBER_DEVICE_ENABLED => Controller_Settings::shared()->get(Controller_Settings::OPTION_REMEMBER_DEVICE_ENABLED),
|
||||
Controller_Settings::OPTION_REMEMBER_DEVICE_DURATION => Controller_Settings::shared()->get(Controller_Settings::OPTION_REMEMBER_DEVICE_DURATION),
|
||||
Controller_Settings::OPTION_ALLOW_XML_RPC => Controller_Settings::shared()->get(Controller_Settings::OPTION_ALLOW_XML_RPC),
|
||||
Controller_Settings::OPTION_ENABLE_AUTH_CAPTCHA => Controller_Settings::shared()->get(Controller_Settings::OPTION_ENABLE_AUTH_CAPTCHA),
|
||||
Controller_Settings::OPTION_RECAPTCHA_THRESHOLD => Controller_Settings::shared()->get(Controller_Settings::OPTION_RECAPTCHA_THRESHOLD),
|
||||
Controller_Settings::OPTION_LAST_SECRET_REFRESH => Controller_Settings::shared()->get(Controller_Settings::OPTION_LAST_SECRET_REFRESH),
|
||||
);
|
||||
// Convert the database strings to typed values.
|
||||
foreach ($lsFields as $lsField => $value) {
|
||||
$lsFields[$lsField] = Controller_Settings::shared()->clean($lsField, $value);
|
||||
}
|
||||
|
||||
if (!$fields) {
|
||||
foreach (wfConfig::$defaultConfig as $group => $groupOptions) {
|
||||
foreach ($groupOptions as $field => $values) {
|
||||
$fields[] = $field;
|
||||
}
|
||||
}
|
||||
foreach ($wafFields as $wafField => $value) {
|
||||
$fields[] = 'waf.' . $wafField;
|
||||
}
|
||||
foreach ($lsFields as $lsField => $value) {
|
||||
$fields[] = 'wfls_settings_' . $lsField;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($fields as $field) {
|
||||
if (strpos($field, 'waf.') === 0) {
|
||||
$wafField = substr($field, 4);
|
||||
if (array_key_exists($wafField, $wafFields)) {
|
||||
$config['waf'][$wafField] = $wafFields[$wafField];
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strpos($field, 'wfls_settings_') === 0) {
|
||||
$lsField = substr($field, 14);
|
||||
if (array_key_exists($lsField, $lsFields)) {
|
||||
$config['wfls_settings_' . $lsField] = $lsFields[$lsField];
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (array_key_exists($field, wfConfig::$defaultConfig['checkboxes'])) {
|
||||
$config[$field] = (bool) wfConfig::get($field);
|
||||
|
||||
} else if (array_key_exists($field, wfConfig::$defaultConfig['otherParams']) ||
|
||||
array_key_exists($field, wfConfig::$defaultConfig['defaultsOnly'])) {
|
||||
|
||||
$configConfig = !empty(wfConfig::$defaultConfig['otherParams'][$field]) ?
|
||||
wfConfig::$defaultConfig['otherParams'][$field] : wfConfig::$defaultConfig['defaultsOnly'][$field];
|
||||
|
||||
if (!empty($configConfig['validation']['type'])) {
|
||||
switch ($configConfig['validation']['type']) {
|
||||
case wfConfig::TYPE_INT:
|
||||
$config[$field] = wfConfig::getInt($field);
|
||||
break;
|
||||
|
||||
case wfConfig::TYPE_DOUBLE:
|
||||
case wfConfig::TYPE_FLOAT:
|
||||
$config[$field] = floatval(wfConfig::get($field));
|
||||
break;
|
||||
|
||||
case wfConfig::TYPE_BOOL:
|
||||
$config[$field] = (bool) wfConfig::get($field);
|
||||
break;
|
||||
|
||||
case wfConfig::TYPE_ARRAY:
|
||||
$config[$field] = wfConfig::get_ser($field);
|
||||
break;
|
||||
|
||||
case wfConfig::TYPE_STRING:
|
||||
default:
|
||||
$config[$field] = wfConfig::get($field);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
$config[$field] = wfConfig::get($field);
|
||||
}
|
||||
|
||||
} else if (in_array($field, wfConfig::$serializedOptions)) {
|
||||
$config[$field] = wfConfig::get_ser($field);
|
||||
}
|
||||
}
|
||||
|
||||
$api = new wfAPI(wfConfig::get('apiKey'), wfUtils::getWPVersion());
|
||||
parse_str($api->makeAPIQueryString(), $qs);
|
||||
$systemInfo = json_decode(wfUtils::base64url_decode($qs['s']), true);
|
||||
$systemInfo['output_buffering'] = ini_get('output_buffering');
|
||||
$systemInfo['ip'] = wfUtils::getIPAndServerVariable();
|
||||
$systemInfo['detected_ips'] = wfUtils::getAllServerVariableIPs();
|
||||
$systemInfo['admin_url'] = network_admin_url();
|
||||
|
||||
$response = rest_ensure_response(array(
|
||||
'config' => $config,
|
||||
'info' => $systemInfo,
|
||||
));
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WP_REST_Request $request
|
||||
* @return mixed|WP_REST_Response
|
||||
*/
|
||||
public function setConfig($request) {
|
||||
wfCentral::preventConfigurationSync();
|
||||
|
||||
$fields = $request['fields'];
|
||||
if (is_array($fields) && $fields) {
|
||||
$loginSecurityConfig = array();
|
||||
foreach ($fields as $key => $value) {
|
||||
if (strpos($key, 'wfls_settings_') === 0) {
|
||||
$lsField = substr($key, 14);
|
||||
$loginSecurityConfig[$lsField] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
if ($loginSecurityConfig) {
|
||||
$errors = Controller_Settings::shared()->validate_multiple($loginSecurityConfig);
|
||||
|
||||
if ($errors !== true) {
|
||||
if (count($errors) == 1) {
|
||||
return new WP_Error('rest_set_config_error',
|
||||
sprintf(
|
||||
/* translators: Error message. */
|
||||
__('An error occurred while saving the configuration: %s', 'wordfence'), $errors[0]['error']),
|
||||
array('status' => 422));
|
||||
|
||||
} else if (count($errors) > 1) {
|
||||
$compoundMessage = array();
|
||||
foreach ($errors as $e) {
|
||||
$compoundMessage[] = $e['error'];
|
||||
}
|
||||
return new WP_Error('rest_set_config_error',
|
||||
sprintf(
|
||||
/* translators: Error message. */
|
||||
__('Errors occurred while saving the configuration: %s', 'wordfence'), implode(', ', $compoundMessage)),
|
||||
array('status' => 422));
|
||||
}
|
||||
|
||||
return new WP_Error('rest_set_config_error',
|
||||
__('Errors occurred while saving the configuration.', 'wordfence'),
|
||||
array('status' => 422));
|
||||
}
|
||||
|
||||
try {
|
||||
Controller_Settings::shared()->set_multiple($loginSecurityConfig);
|
||||
foreach ($fields as $key => $value) {
|
||||
if (strpos($key, 'wfls_settings_') === 0) {
|
||||
unset($fields[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
return new WP_Error('rest_save_config_error',
|
||||
sprintf(
|
||||
/* translators: Error message. */
|
||||
__('A server error occurred while saving the configuration: %s', 'wordfence'), $e->getMessage()),
|
||||
array('status' => 500));
|
||||
}
|
||||
}
|
||||
|
||||
$errors = wfConfig::validate($fields);
|
||||
if ($errors !== true) {
|
||||
if (count($errors) == 1) {
|
||||
return new WP_Error('rest_set_config_error',
|
||||
sprintf(
|
||||
/* translators: Error message. */
|
||||
__('An error occurred while saving the configuration: %s', 'wordfence'), $errors[0]['error']),
|
||||
array('status' => 422));
|
||||
|
||||
} else if (count($errors) > 1) {
|
||||
$compoundMessage = array();
|
||||
foreach ($errors as $e) {
|
||||
$compoundMessage[] = $e['error'];
|
||||
}
|
||||
return new WP_Error('rest_set_config_error',
|
||||
sprintf(
|
||||
/* translators: Error message. */
|
||||
__('Errors occurred while saving the configuration: %s', 'wordfence'), implode(', ', $compoundMessage)),
|
||||
array('status' => 422));
|
||||
}
|
||||
|
||||
return new WP_Error('rest_set_config_error',
|
||||
__('Errors occurred while saving the configuration.', 'wordfence'),
|
||||
array('status' => 422));
|
||||
}
|
||||
|
||||
try {
|
||||
wfConfig::save($fields);
|
||||
return rest_ensure_response(array(
|
||||
'success' => true,
|
||||
));
|
||||
|
||||
} catch (Exception $e) {
|
||||
return new WP_Error('rest_save_config_error',
|
||||
sprintf(
|
||||
/* translators: Error message. */
|
||||
__('A server error occurred while saving the configuration: %s', 'wordfence'), $e->getMessage()),
|
||||
array('status' => 500));
|
||||
}
|
||||
}
|
||||
return new WP_Error('rest_save_config_error',
|
||||
__("Validation error: 'fields' parameter is empty or not an array.", 'wordfence'),
|
||||
array('status' => 422));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WP_REST_Request $request
|
||||
* @return mixed|WP_REST_Response
|
||||
*/
|
||||
public function disconnect($request) {
|
||||
self::disconnectConfig();
|
||||
return rest_ensure_response(array(
|
||||
'success' => true,
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WP_REST_Request $request
|
||||
* @return mixed|WP_REST_Response
|
||||
*/
|
||||
public function premiumConnect($request) {
|
||||
require_once(WORDFENCE_PATH . '/lib/sodium_compat_fast.php');
|
||||
|
||||
// Store values sent by Central.
|
||||
$wordfenceCentralPK = $request['public-key'];
|
||||
$wordfenceCentralSiteData = $request['site-data'];
|
||||
$wordfenceCentralSiteID = $request['site-id'];
|
||||
|
||||
$keypair = ParagonIE_Sodium_Compat::crypto_sign_keypair();
|
||||
$publicKey = ParagonIE_Sodium_Compat::crypto_sign_publickey($keypair);
|
||||
$secretKey = ParagonIE_Sodium_Compat::crypto_sign_secretkey($keypair);
|
||||
wfConfig::set('wordfenceCentralSecretKey', $secretKey);
|
||||
|
||||
wfConfig::set('wordfenceCentralConnected', 1);
|
||||
wfConfig::set('wordfenceCentralCurrentStep', 6);
|
||||
wfConfig::set('wordfenceCentralPK', pack("H*", $wordfenceCentralPK));
|
||||
wfConfig::set('wordfenceCentralSiteData', json_encode($wordfenceCentralSiteData));
|
||||
wfConfig::set('wordfenceCentralSiteID', $wordfenceCentralSiteID);
|
||||
wfConfig::set('wordfenceCentralConnectTime', time());
|
||||
wfConfig::set('wordfenceCentralConnectEmail', !empty($this->tokenData['adminEmail']) ? $this->tokenData['adminEmail'] : null);
|
||||
|
||||
// Return values created by Wordfence.
|
||||
return rest_ensure_response(array(
|
||||
'success' => true,
|
||||
'public-key' => ParagonIE_Sodium_Compat::bin2hex($publicKey),
|
||||
));
|
||||
}
|
||||
}
|
||||
163
wp/plugins/wordfence/lib/rest-api/wfRESTScanController.php
Normal file
163
wp/plugins/wordfence/lib/rest-api/wfRESTScanController.php
Normal file
@@ -0,0 +1,163 @@
|
||||
<?php
|
||||
|
||||
require_once(dirname(__FILE__) . '/wfRESTBaseController.php');
|
||||
|
||||
class wfRESTScanController extends wfRESTBaseController {
|
||||
|
||||
/**
|
||||
* @todo Setup routes to modify scan results.
|
||||
*/
|
||||
public function registerRoutes() {
|
||||
register_rest_route('wordfence/v1', '/scan/issues', array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array($this, 'getIssuesList'),
|
||||
'permission_callback' => array($this, 'verifyToken'),
|
||||
'group' => array(
|
||||
'description' => __('Scan result group or all results.', 'wordfence'),
|
||||
'type' => 'string',
|
||||
'required' => false,
|
||||
),
|
||||
'offset' => array(
|
||||
'description' => __('Offset of scan results to return.', 'wordfence'),
|
||||
'type' => 'int',
|
||||
'required' => false,
|
||||
),
|
||||
'limit' => array(
|
||||
'description' => __('Number of scan results to return.', 'wordfence'),
|
||||
'type' => 'int',
|
||||
'required' => false,
|
||||
),
|
||||
));
|
||||
register_rest_route('wordfence/v1', '/scan', array(
|
||||
'methods' => WP_REST_Server::CREATABLE,
|
||||
'callback' => array($this, 'startScan'),
|
||||
'permission_callback' => array($this, 'verifyToken'),
|
||||
));
|
||||
register_rest_route('wordfence/v1', '/scan', array(
|
||||
'methods' => WP_REST_Server::DELETABLE,
|
||||
'callback' => array($this, 'stopScan'),
|
||||
'permission_callback' => array($this, 'verifyToken'),
|
||||
));
|
||||
register_rest_route('wordfence/v1', '/scan/issue', array(
|
||||
'methods' => WP_REST_Server::EDITABLE,
|
||||
'callback' => array($this, 'updateIssue'),
|
||||
'permission_callback' => array($this, 'verifyToken'),
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WP_REST_Request $request
|
||||
* @return mixed|WP_REST_Response
|
||||
*/
|
||||
public function getIssuesList($request) {
|
||||
$group = $request['group'] ? $request['group'] : 'all';
|
||||
$offset = absint($request['offset']);
|
||||
$limit = absint($request['limit']);
|
||||
if ($limit === 0) {
|
||||
$limit = 100;
|
||||
}
|
||||
switch ($group) {
|
||||
case 'pending':
|
||||
$count = wfIssues::shared()->getPendingIssueCount();
|
||||
$issues = wfIssues::shared()->getPendingIssues($offset, $limit);
|
||||
break;
|
||||
|
||||
default: // Return all issues.
|
||||
$count = wfIssues::shared()->getIssueCount();
|
||||
$issues = wfIssues::shared()->getIssues($offset, $limit);
|
||||
break;
|
||||
}
|
||||
|
||||
$response = rest_ensure_response(array(
|
||||
'count' => $count,
|
||||
'last-scan-time' => wfConfig::get('scanTime'),
|
||||
'issues' => $issues,
|
||||
));
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WP_REST_Request $request
|
||||
* @return mixed|WP_REST_Response
|
||||
*/
|
||||
public function startScan($request) {
|
||||
wordfence::status(1, 'info', sprintf(/* translators: Localized date. */ __('Wordfence scan starting at %s from Wordfence Central', 'wordfence'),
|
||||
date('l jS \of F Y h:i:s A', current_time('timestamp'))));
|
||||
|
||||
try {
|
||||
wfScanEngine::startScan();
|
||||
|
||||
} catch (wfScanEngineTestCallbackFailedException $e) {
|
||||
wfConfig::set('lastScanCompleted', $e->getMessage());
|
||||
wfConfig::set('lastScanFailureType', wfIssues::SCAN_FAILED_CALLBACK_TEST_FAILED);
|
||||
wfUtils::clearScanLock();
|
||||
$response = rest_ensure_response(array(
|
||||
'success' => false,
|
||||
'error-code' => $e->getCode(),
|
||||
'error' => $e->getMessage(),
|
||||
));
|
||||
return $response;
|
||||
|
||||
} catch (Exception $e) {
|
||||
if ($e->getCode() != wfScanEngine::SCAN_MANUALLY_KILLED) {
|
||||
wfConfig::set('lastScanCompleted', $e->getMessage());
|
||||
wfConfig::set('lastScanFailureType', wfIssues::SCAN_FAILED_GENERAL);
|
||||
|
||||
$response = rest_ensure_response(array(
|
||||
'success' => false,
|
||||
'error-code' => $e->getCode(),
|
||||
'error' => $e->getMessage(),
|
||||
));
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
||||
$response = rest_ensure_response(array(
|
||||
'success' => true,
|
||||
));
|
||||
return $response;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WP_REST_Request $request
|
||||
* @return mixed|WP_REST_Response
|
||||
*/
|
||||
public function stopScan($request) {
|
||||
wordfence::status(1, 'info', __('Scan stop request received from Wordfence Central.', 'wordfence'));
|
||||
wordfence::status(10, 'info', __('SUM_KILLED:A request was received to stop the previous scan from Wordfence Central.', 'wordfence'));
|
||||
wfUtils::clearScanLock(); //Clear the lock now because there may not be a scan running to pick up the kill request and clear the lock
|
||||
wfScanEngine::requestKill();
|
||||
wfConfig::remove('scanStartAttempt');
|
||||
wfConfig::set('lastScanFailureType', false);
|
||||
$response = rest_ensure_response(array(
|
||||
'success' => true,
|
||||
));
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WP_REST_Request $request
|
||||
* @return mixed|WP_REST_Response
|
||||
*/
|
||||
public function updateIssue($request) {
|
||||
$issue = $request['issue'];
|
||||
$id = is_array($issue) && array_key_exists('id', $issue) ? $issue['id'] : null;
|
||||
$status = is_array($issue) && array_key_exists('status', $issue) ? $issue['status'] : null;
|
||||
|
||||
if ($id) {
|
||||
$wfdb = new wfDB();
|
||||
$wfdb->queryWrite("update " . wfDB::networkTable('wfIssues') . " set status='%s' where id=%d", $status, $id);
|
||||
$response = rest_ensure_response(array(
|
||||
'success' => true,
|
||||
));
|
||||
return $response;
|
||||
}
|
||||
$response = rest_ensure_response(array(
|
||||
'success' => false,
|
||||
'error' => 'Issue not found.',
|
||||
));
|
||||
return $response;
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user