Skip to content

Commit

Permalink
Jetpack: Add Account Protection security settings (#40938)
Browse files Browse the repository at this point in the history
* Add Account Protection toggle to Jetpack security settings

* Import package and run activation/deactivation on module toggle

* changelog

* Update changelog

* Make account protection class init static

* Remove user cxn req and banner

* Do not enabled module by default

* Add strict mode option and settings toggle

* changelog

* Use dynamic classes

* Update class dependencies

* Fix copy

* Revert unrelated changes

* Fix phan errors

* Changelog

* Update composer deps

* Update lock files, add constructor method

* Fix php warning

* Update @Package

* Enable module by default
  • Loading branch information
dkmyta authored and nateweller committed Feb 20, 2025
1 parent bcf6a1b commit e11c511
Show file tree
Hide file tree
Showing 26 changed files with 751 additions and 12 deletions.
2 changes: 0 additions & 2 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: added

Adds Account Protection requests
10 changes: 10 additions & 0 deletions projects/js-packages/api/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,16 @@ function JetpackRestApiClient( root, nonce ) {
getRequest( `${ wpcomOriginApiUrl }jetpack/v4/search/stats`, getParams )
.then( checkStatus )
.then( parseJsonResponse ),
fetchAccountProtectionSettings: () =>
getRequest( `${ apiRoot }jetpack/v4/account-protection`, getParams )
.then( checkStatus )
.then( parseJsonResponse ),
updateAccountProtectionSettings: newSettings =>
postRequest( `${ apiRoot }jetpack/v4/account-protection`, postParams, {
body: JSON.stringify( newSettings ),
} )
.then( checkStatus )
.then( parseJsonResponse ),
fetchWafSettings: () =>
getRequest( `${ apiRoot }jetpack/v4/waf`, getParams )
.then( checkStatus )
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: added

Adds handling for module activation and deactivation
4 changes: 3 additions & 1 deletion projects/packages/account-protection/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
"type": "jetpack-library",
"license": "GPL-2.0-or-later",
"require": {
"php": ">=7.2"
"php": ">=7.2",
"automattic/jetpack-connection": "@dev",
"automattic/jetpack-status": "@dev"
},
"require-dev": {
"yoast/phpunit-polyfills": "^1.1.1",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,97 @@
<?php
/**
* Package description here
* Class used to define Account Protection.
*
* @package automattic/jetpack-account-protection
*/

namespace Automattic\Jetpack;
namespace Automattic\Jetpack\Account_Protection;

use Automattic\Jetpack\Modules;

/**
* Class description.
* Class Account_Protection
*/
class Account_Protection {

const PACKAGE_VERSION = '0.1.0-alpha';
const PACKAGE_VERSION = '0.1.0-alpha';
const ACCOUNT_PROTECTION_MODULE_NAME = 'account-protection';
const STRICT_MODE_OPTION_NAME = 'jetpack_account_protection_strict_mode';

/**
* Modules instance.
*
* @var Modules
*/
private $modules;

/**
* Account_Protection constructor.
*
* @param ?Modules $modules Modules instance.
*/
public function __construct( ?Modules $modules = null ) {
$this->modules = $modules ?? new Modules();
}

/**
* Initializes the configurations needed for the account protection module.
*/
public function init() {
// Account protection activation/deactivation hooks
add_action( 'jetpack_activate_module_' . self::ACCOUNT_PROTECTION_MODULE_NAME, array( $this, 'on_account_protection_activation' ) );
add_action( 'jetpack_deactivate_module_' . self::ACCOUNT_PROTECTION_MODULE_NAME, array( $this, 'on_account_protection_deactivation' ) );

// Register REST routes
add_action( 'rest_api_init', array( new REST_Controller(), 'register_rest_routes' ) );
}

/**
* Activate the account protection on module activation.
*/
public function on_account_protection_activation() {
// Account protection activated
}

/**
* Deactivate the account protection on module activation.
*/
public function on_account_protection_deactivation() {
// Account protection deactivated
}

/**
* Determines if the account protection module is enabled on the site.
*
* @return bool
*/
public function is_enabled() {
return $this->modules->is_active( self::ACCOUNT_PROTECTION_MODULE_NAME );
}

/**
* Enables the account protection module.
*
* @return bool
*/
public function enable() {
// Return true if already enabled.
if ( $this->is_enabled() ) {
return true;
}
return $this->modules->activate( self::ACCOUNT_PROTECTION_MODULE_NAME, false, false );
}

/**
* Disables the account protection module.
*
* @return bool
*/
public function disable() {
// Return true if already disabled.
if ( ! $this->is_enabled() ) {
return true;
}
return $this->modules->deactivate( self::ACCOUNT_PROTECTION_MODULE_NAME );
}
}
106 changes: 106 additions & 0 deletions projects/packages/account-protection/src/class-rest-controller.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<?php
/**
* Class use to register REST API endpoints used by the Accont Protection module.
*
* @package automattic/jetpack-waf
*/

namespace Automattic\Jetpack\Account_Protection;

use Automattic\Jetpack\Connection\REST_Connector;
use WP_Error;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server;

/**
* Defines our endponts.
*/
class REST_Controller {
/**
* Tracks whether routes have already been registered.
*
* @var bool
*/
private $routes_registered = false;

/**
* Register REST API endpoints.
*
* @return void
*/
public function register_rest_routes() {
// Ensure routes are only initialized once.
if ( $this->routes_registered ) {
return;
}

register_rest_route(
'jetpack/v4',
'/account-protection',
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_settings' ),
'permission_callback' => array( $this, 'permissions_callback' ),
)
);

register_rest_route(
'jetpack/v4',
'/account-protection',
array(
'methods' => WP_REST_Server::EDITABLE,
'callback' => array( $this, 'update_settings' ),
'permission_callback' => array( $this, 'permissions_callback' ),
)
);

$this->routes_registered = true;
}

/**
* Account Protection Settings Endpoint
*
* @return WP_REST_Response
*/
public function get_settings() {
return rest_ensure_response(
array(
Account_Protection::STRICT_MODE_OPTION_NAME => get_option( Account_Protection::STRICT_MODE_OPTION_NAME ),
)
);
}

/**
* Update Account Protection Settings Endpoint
*
* @param WP_REST_Request $request The API request.
*
* @return WP_REST_Response|WP_Error
*/
public function update_settings( $request ) {
// Strict Mode
if ( isset( $request[ Account_Protection::STRICT_MODE_OPTION_NAME ] ) ) {
update_option( Account_Protection::STRICT_MODE_OPTION_NAME, $request[ Account_Protection::STRICT_MODE_OPTION_NAME ] ? '1' : '' );
}

return $this->get_settings();
}

/**
* Account Protection Endpoint Permissions Callback
*
* @return bool|WP_Error True if user can view the Jetpack admin page.
*/
public function permissions_callback() {
if ( current_user_can( 'manage_options' ) ) {
return true;
}

return new WP_Error(
'invalid_user_permission_manage_options',
REST_Connector::get_user_permissions_error_msg(),
array( 'status' => rest_authorization_required_code() )
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
/**
* Bootstrap.
*
* @package automattic/
* @package automattic/jetpack-account-protection
*/

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import PropTypes from 'prop-types';
import { Component } from 'react';
import { connect } from 'react-redux';
import {
fetchAccountProtectionSettings,
isFetchingAccountProtectionSettings,
} from 'state/account-protection';
import { isOfflineMode } from 'state/connection';

class QueryAccountProtectionSettings extends Component {
static propTypes = {
isFetchingAccountProtectionSettings: PropTypes.bool,
isOfflineMode: PropTypes.bool,
};

static defaultProps = {
isFetchingAccountProtectionSettings: false,
isOfflineMode: false,
};

componentDidMount() {
if ( ! this.props.isFetchingAccountProtectionSettings && ! this.props.isOfflineMode ) {
this.props.fetchAccountProtectionSettings();
}
}

render() {
return null;
}
}

export default connect(
state => {
return {
isFetchingAccountProtectionSettings: isFetchingAccountProtectionSettings( state ),
isOfflineMode: isOfflineMode( state ),
};
},
dispatch => {
return {
fetchAccountProtectionSettings: () => dispatch( fetchAccountProtectionSettings() ),
};
}
)( QueryAccountProtectionSettings );
2 changes: 2 additions & 0 deletions projects/plugins/jetpack/_inc/client/lib/plans/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,7 @@ export const FEATURE_POST_BY_EMAIL = 'post-by-email-jetpack';
export const FEATURE_JETPACK_SOCIAL = 'social-jetpack';
export const FEATURE_JETPACK_BLAZE = 'blaze-jetpack';
export const FEATURE_JETPACK_EARN = 'earn-jetpack';
export const FEATURE_JETPACK_ACCOUNT_PROTECTION = 'account-protection-jetpack';

// Upsells
export const JETPACK_FEATURE_PRODUCT_UPSELL_MAP = {
Expand All @@ -439,6 +440,7 @@ export const JETPACK_FEATURE_PRODUCT_UPSELL_MAP = {
[ FEATURE_VIDEOPRESS ]: PLAN_JETPACK_VIDEOPRESS,
[ FEATURE_NEWSLETTER_JETPACK ]: PLAN_JETPACK_CREATOR_YEARLY,
[ FEATURE_WORDADS_JETPACK ]: PLAN_JETPACK_SECURITY_T1_YEARLY,
[ FEATURE_JETPACK_ACCOUNT_PROTECTION ]: PLAN_JETPACK_FREE,
};

/**
Expand Down
Loading

0 comments on commit e11c511

Please sign in to comment.