Skip to content

Commit

Permalink
Merge branch 'add/protect-threat-history' into add/protect-threat-his…
Browse files Browse the repository at this point in the history
…tory-hooks-refactor
  • Loading branch information
nateweller authored Aug 6, 2024
2 parents 631d2c2 + 9d976a8 commit 28fc596
Show file tree
Hide file tree
Showing 16 changed files with 372 additions and 41 deletions.
33 changes: 33 additions & 0 deletions projects/plugins/protect/src/class-rest-controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,18 @@ public static function register_rest_endpoints() {
)
);

register_rest_route(
'jetpack-protect/v1',
'unignore-threat',
array(
'methods' => \WP_REST_Server::EDITABLE,
'callback' => __CLASS__ . '::api_unignore_threat',
'permission_callback' => function () {
return current_user_can( 'manage_options' );
},
)
);

register_rest_route(
'jetpack-protect/v1',
'fix-threats',
Expand Down Expand Up @@ -233,6 +245,27 @@ public static function api_ignore_threat( $request ) {
return new WP_REST_Response( 'Threat ignored.' );
}

/**
* Unignores a threat for the API endpoint
*
* @param WP_REST_Request $request The request object.
*
* @return WP_REST_Response
*/
public static function api_unignore_threat( $request ) {
if ( ! $request['threat_id'] ) {
return new WP_REST_Response( 'Missing threat ID.', 400 );
}

$threat_ignored = Threats::unignore_threat( $request['threat_id'] );

if ( ! $threat_ignored ) {
return new WP_REST_Response( 'An error occured while attempting to unignore the threat.', 500 );
}

return new WP_REST_Response( 'Threat unignored.' );
}

/**
* Fixes threats for the API endpoint
*
Expand Down
11 changes: 11 additions & 0 deletions projects/plugins/protect/src/class-threats.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,17 @@ public static function ignore_threat( $threat_id ) {
return self::update_threat( $threat_id, array( 'ignore' => true ) );
}

/**
* Unignore Threat
*
* @param string $threat_id The threat ID.
*
* @return bool
*/
public static function unignore_threat( $threat_id ) {
return self::update_threat( $threat_id, array( 'unignore' => true ) );
}

/**
* Fix Threats
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ const IgnoreThreatModal = ( { id, title, label, icon, severity } ) => {
<Text mb={ 4 }>
{ createInterpolateElement(
__(
'By ignoring this threat you confirm that you have reviewed the detected code and assume the risks of keeping a potentially malicious or vulnerable file on your site. If you are unsure please request an estimate with <codeableLink>Codeable</codeableLink>.',
'By choosing to ignore this threat, you acknowledge that you have reviewed the detected code. You are accepting the risks of maintaining a potentially malicious or vulnerable file on your site. If you are unsure, please request an estimate with <codeableLink>Codeable</codeableLink>.',
'jetpack-protect'
),
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { SCAN_STATUS_SCHEDULED } from '../../../../constants';

export const jetpackProtectInitialState = {
apiRoot: 'http://localhost/wp-json/',
apiNonce: 'f2d2d42e2a',
Expand All @@ -7,7 +9,7 @@ export const jetpackProtectInitialState = {
num_threats: 6,
num_plugins_threats: 3,
num_themes_threats: 3,
status: 'scheduled',
status: SCAN_STATUS_SCHEDULED,
wordpress: {
version: '5.9.3',
threats: [],
Expand Down
2 changes: 2 additions & 0 deletions projects/plugins/protect/src/js/components/modal/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ import FixAllThreatsModal from '../fix-all-threats-modal';
import FixThreatModal from '../fix-threat-modal';
import IgnoreThreatModal from '../ignore-threat-modal';
import StandaloneModeModal from '../standalone-mode-modal';
import UnignoreThreatModal from '../unignore-threat-modal';
import styles from './styles.module.scss';

const MODAL_COMPONENTS = {
IGNORE_THREAT: IgnoreThreatModal,
UNIGNORE_THREAT: UnignoreThreatModal,
FIX_THREAT: FixThreatModal,
FIX_ALL_THREATS: FixAllThreatsModal,
CREDENTIALS_NEEDED: CredentialsNeededModal,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@ const ScanHistoryDetails = ( { detectedAt, fixedOn, status } ) => {
</span>
</>
) }
{ 'ignored' === status && (
<>
<span className={ styles[ 'accordion-header-status-separator' ] }></span>
<span className={ styles[ 'is-ignored' ] }>
{ __( 'Threat ignored', 'jetpack-protect' ) }
</span>
</>
) }
</Text>
) }
{ ( 'fixed' === status || 'ignored' === status ) && (
Expand Down
29 changes: 19 additions & 10 deletions projects/plugins/protect/src/js/components/pricing-table/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const ConnectedPricingTable = ( { onScanAdd } ) => {
skipUserConnection: true,
} );

const { refreshPlan, refreshStatus } = useDispatch( STORE_ID );
const { refreshPlan, refreshStatus, startScanOptimistically } = useDispatch( STORE_ID );

const [ getProtectFreeButtonIsLoading, setGetProtectFreeButtonIsLoading ] = useState( false );
const [ getScanButtonIsLoading, setGetScanButtonIsLoading ] = useState( false );
Expand All @@ -54,17 +54,26 @@ const ConnectedPricingTable = ( { onScanAdd } ) => {
onScanAdd();
} );

const getProtectFree = useCallback( () => {
const getProtectFree = useCallback( async () => {
recordEvent( 'jetpack_protect_connected_product_activated' );
setGetProtectFreeButtonIsLoading( true );
handleRegisterSite()
.then( () => setGetProtectFreeButtonIsLoading( false ) )
.then( () => {
refreshPlan();
refreshWaf();
refreshStatus( true );
} );
}, [ handleRegisterSite, recordEvent, refreshWaf, refreshPlan, refreshStatus ] );
try {
await handleRegisterSite();
startScanOptimistically();
await refreshPlan();
await refreshWaf();
await refreshStatus( true );
} finally {
setGetProtectFreeButtonIsLoading( false );
}
}, [
handleRegisterSite,
recordEvent,
refreshWaf,
refreshPlan,
refreshStatus,
startScanOptimistically,
] );

const args = {
title: __( 'Stay one step ahead of threats', 'jetpack-protect' ),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,16 @@ const ThreatAccordionItem = ( {
};
};

const handleUnignoreThreatClick = () => {
return event => {
event.preventDefault();
setModal( {
type: 'UNIGNORE_THREAT',
props: { id, label, title, icon, severity },
} );
};
};

const handleFixThreatClick = () => {
return event => {
event.preventDefault();
Expand Down Expand Up @@ -126,15 +136,30 @@ const ThreatAccordionItem = ( {
) }
{ ! description && <div className={ styles[ 'threat-section' ] }>{ learnMoreButton }</div> }
<div className={ styles[ 'threat-footer' ] }>
{ status !== 'ignored' && status !== 'fixed' && (
<Button isDestructive={ true } variant="secondary" onClick={ handleIgnoreThreatClick() }>
{ __( 'Ignore threat', 'jetpack-protect' ) }
{ 'ignored' === status && (
<Button
isDestructive={ true }
variant="secondary"
onClick={ handleUnignoreThreatClick() }
>
{ __( 'Unignore threat', 'jetpack-protect' ) }
</Button>
) }
{ fixable && status !== 'fixed' && (
<Button disabled={ fixerInProgress } onClick={ handleFixThreatClick() }>
{ __( 'Fix threat', 'jetpack-protect' ) }
</Button>
{ 'current' === status && (
<>
<Button
isDestructive={ true }
variant="secondary"
onClick={ handleIgnoreThreatClick() }
>
{ __( 'Ignore threat', 'jetpack-protect' ) }
</Button>
{ fixable && (
<Button disabled={ fixerInProgress } onClick={ handleFixThreatClick() }>
{ __( 'Fix threat', 'jetpack-protect' ) }
</Button>
) }
</>
) }
</div>
</PaidAccordionItem>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { Button, Text } from '@automattic/jetpack-components';
import { useDispatch, useSelect } from '@wordpress/data';
import { __ } from '@wordpress/i18n';
import { Icon } from '@wordpress/icons';
import { STORE_ID } from '../../state/store';
import ThreatSeverityBadge from '../severity';
import UserConnectionGate from '../user-connection-gate';
import styles from './styles.module.scss';

const UnignoreThreatModal = ( { id, title, label, icon, severity } ) => {
const { setModal, unignoreThreat } = useDispatch( STORE_ID );
const threatsUpdating = useSelect( select => select( STORE_ID ).getThreatsUpdating() );

const handleCancelClick = () => {
return event => {
event.preventDefault();
setModal( { type: null } );
};
};

const handleUnignoreClick = () => {
return async event => {
event.preventDefault();
unignoreThreat( id, () => {
setModal( { type: null } );
} );
};
};

return (
<UserConnectionGate>
<Text variant="title-medium" mb={ 2 }>
{ __( 'Do you really want to unignore this threat?', 'jetpack-protect' ) }
</Text>
<Text mb={ 3 }>{ __( 'Jetpack will unignore the threat:', 'jetpack-protect' ) }</Text>

<div className={ styles.threat }>
<Icon icon={ icon } className={ styles.threat__icon } />
<div className={ styles.threat__summary }>
<Text className={ styles.threat__summary__label } mb={ 1 }>
{ label }
</Text>
<Text className={ styles.threat__summary__title }>{ title }</Text>
</div>
<div className={ styles.threat__severity }>
<ThreatSeverityBadge severity={ severity } />
</div>
</div>

<div className={ styles.footer }>
<Button variant="secondary" onClick={ handleCancelClick() }>
{ __( 'Cancel', 'jetpack-protect' ) }
</Button>
<Button
isDestructive={ true }
isLoading={ Boolean( threatsUpdating && threatsUpdating[ id ] ) }
onClick={ handleUnignoreClick() }
>
{ __( 'Unignore threat', 'jetpack-protect' ) }
</Button>
</div>
</UserConnectionGate>
);
};

export default UnignoreThreatModal;
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
.threat {
border: 1px solid var( --jp-gray );
border-radius: var( --jp-border-radius );
padding: calc( var( --spacing-base ) * 2 ); // 16px
display: flex;
margin-bottom: calc( var( --spacing-base ) * 3 ); // 24px

&__icon {
margin-right: calc( var( --spacing-base ) * 2 ); // 16px
min-width: 24px;
}

&__summary {
width: 100%;
}

&__summary__label {
font-size: 18px;
line-height: 24px;
font-weight: 600;
margin-bottom: 0;
}

&__summary__title {
font-size: 14px;
line-height: 21px;
color: var( --jp-gray-80 );
}

&__severity {
align-self: center;
margin-left: calc( var( --spacing-base ) * 2 ); // 16px
margin-right: var( --spacing-base ); // 8px
}
}

.footer {
display: flex;
justify-content: space-between;
}
14 changes: 14 additions & 0 deletions projects/plugins/protect/src/js/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,17 @@ export const FREE_PLUGIN_SUPPORT_URL = 'https://wordpress.org/support/plugin/jet
export const PAID_PLUGIN_SUPPORT_URL = 'https://jetpack.com/contact-support/?rel=support';

export const JETPACK_SCAN_SLUG = 'jetpack_scan';

/**
* Scan Status Constants
*/
export const SCAN_STATUS_SCHEDULED = 'scheduled';
export const SCAN_STATUS_SCANNING = 'scanning';
export const SCAN_STATUS_OPTIMISTICALLY_SCANNING = 'optimistically_scanning';
export const SCAN_STATUS_IDLE = 'idle';
export const SCAN_STATUS_UNAVAILABLE = 'unavailable';
export const SCAN_IN_PROGRESS_STATUSES = [
SCAN_STATUS_SCHEDULED,
SCAN_STATUS_SCANNING,
SCAN_STATUS_OPTIMISTICALLY_SCANNING,
];
Loading

0 comments on commit 28fc596

Please sign in to comment.