Skip to content

Commit

Permalink
Protect: Integrate ScanReport (#40420)
Browse files Browse the repository at this point in the history
  • Loading branch information
dkmyta authored and nateweller committed Dec 18, 2024
1 parent bacace2 commit 2a53e76
Show file tree
Hide file tree
Showing 11 changed files with 106 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ import {
wordpress as coreIcon,
} from '@wordpress/icons';

export const STATUS_TYPES = [
{ value: 'checked', label: __( 'Checked', 'jetpack-components' ) },
{ value: 'unchecked', label: __( 'Unchecked', 'jetpack-components' ) },
{ value: 'threat', label: __( 'Threat', 'jetpack-components' ) },
];

export const TYPES = [
{ value: 'core', label: __( 'WordPress', 'jetpack-components' ) },
{ value: 'plugins', label: __( 'Plugin', 'jetpack-components' ) },
Expand Down
48 changes: 43 additions & 5 deletions projects/js-packages/components/components/scan-report/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
DataViews,
filterSortAndPaginate,
} from '@wordpress/dataviews';
import { __ } from '@wordpress/i18n';
import { __, _n } from '@wordpress/i18n';
import { Icon } from '@wordpress/icons';
import { useCallback, useMemo, useState } from 'react';
import ShieldIcon from '../shield-icon';
Expand All @@ -17,6 +17,7 @@ import {
FIELD_ICON,
FIELD_STATUS,
FIELD_TYPE,
STATUS_TYPES,
TYPES,
ICONS,
} from './constants';
Expand All @@ -26,12 +27,13 @@ import styles from './styles.module.scss';
* DataViews component for displaying a scan report.
*
* @param {object} props - Component props.
* @param {string} props.dataSource - Data source.
* @param {Array} props.data - Scan report data.
* @param {Function} props.onChangeSelection - Callback function run when an item is selected.
*
* @return {JSX.Element} The ScanReport component.
*/
export default function ScanReport( { data, onChangeSelection } ): JSX.Element {
export default function ScanReport( { dataSource, data, onChangeSelection } ): JSX.Element {
const baseView = {
search: '',
filters: [],
Expand Down Expand Up @@ -84,8 +86,19 @@ export default function ScanReport( { data, onChangeSelection } ): JSX.Element {
const result: Field< ScanReportExtension >[] = [
{
id: FIELD_STATUS,
elements: STATUS_TYPES,
label: __( 'Status', 'jetpack-components' ),
getValue( { item } ) {
if ( item.checked ) {
if ( item.threats.length > 0 ) {
return 'threat';
}
return 'checked';
}
return 'unchecked';
},
render( { item }: { item: ScanReportExtension } ) {
const scanApi = 'scan_api' === dataSource;
let variant: 'info' | 'warning' | 'success' = 'info';
let text = __(
'This item was added to your site after the most recent scan. We will check for threats during the next scheduled one.',
Expand All @@ -95,10 +108,34 @@ export default function ScanReport( { data, onChangeSelection } ): JSX.Element {
if ( item.checked ) {
if ( item.threats.length > 0 ) {
variant = 'warning';
text = __( 'Threat detected.', 'jetpack-components' );
text = _n(
'Vulnerability detected.',
'Vulnerabilities detected.',
item.threats.length,
'jetpack-components'
);

if ( scanApi ) {
text = _n(
'Threat detected.',
'Threats detected.',
item.threats.length,
'jetpack-components'
);
}
} else {
variant = 'success';
text = __( 'No known threats found that affect this version.', 'jetpack-components' );
text = __(
'No known vulnerabilities found that affect this version.',
'jetpack-components'
);

if ( scanApi ) {
text = __(
'No known threats found that affect this version.',
'jetpack-components'
);
}
}
}

Expand Down Expand Up @@ -127,6 +164,7 @@ export default function ScanReport( { data, onChangeSelection } ): JSX.Element {
{
id: FIELD_VERSION,
label: __( 'Version', 'jetpack-components' ),
enableSorting: false,
enableGlobalSearch: true,
getValue( { item }: { item: ScanReportExtension } ) {
return item.version ? item.version : '';
Expand Down Expand Up @@ -155,7 +193,7 @@ export default function ScanReport( { data, onChangeSelection } ): JSX.Element {
];

return result;
}, [ view ] );
}, [ view, dataSource ] );

/**
* Apply the view settings (i.e. filters, sorting, pagination) to the dataset.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export default {

export const Default = args => <ScanReport { ...args } />;
Default.args = {
dataSource: 'scan_api',
data: [
{
id: 1,
Expand Down Expand Up @@ -64,6 +65,12 @@ Default.args = {
title: 'Malicious code found in file: jptt_eicar.php',
severity: 1,
},
{
id: 198352407,
signature: 'EICAR_AV_Test_Suspicious',
title: 'Malicious code found in file: jptt_eicar.php',
severity: 1,
},
],
checked: true,
type: 'files',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export const THREAT_TYPES = [
{ value: 'themes', label: __( 'Theme', 'jetpack-components' ) },
{ value: 'core', label: __( 'WordPress', 'jetpack-components' ) },
{ value: 'file', label: __( 'File', 'jetpack-components' ) },
{ value: '', label: __( 'Unknown', 'jetpack-components' ) },
];

export const THREAT_ICONS = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -265,18 +265,7 @@ export default function ThreatsDataViews( {
label: __( 'Type', 'jetpack-components' ),
elements: THREAT_TYPES,
getValue( { item }: { item: Threat } ) {
switch ( getThreatType( item ) ) {
case 'core':
return __( 'WordPress', 'jetpack-components' );
case 'plugins':
return __( 'Plugin', 'jetpack-components' );
case 'themes':
return __( 'Theme', 'jetpack-components' );
case 'file':
return __( 'File', 'jetpack-components' );
default:
return __( 'Unknown', 'jetpack-components' );
}
return getThreatType( item ) ?? '';
},
},
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: added

Adds ScanReport to HomeRoute
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,12 @@ const FirewallAdminSectionHero = () => {
<AdminSectionHero>
<AdminSectionHero.Main>
<Status
className={ styles.status }
status={ 'on' === status ? 'active' : 'inactive' }
label={ statusLabel }
className={ styles.status }
/>
<AdminSectionHero.Heading>{ heading }</AdminSectionHero.Heading>
<Text>{ subheading }</Text>
{ subheading }
</AdminSectionHero.Main>
{ wafSupported && (
<AdminSectionHero.Aside>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import { Text, useBreakpointMatch, StatCard } from '@automattic/jetpack-components';
import { useBreakpointMatch, StatCard } from '@automattic/jetpack-components';
import { __, sprintf } from '@wordpress/i18n';
import { Icon, shield, chartBar } from '@wordpress/icons';
import { useCallback, useMemo } from 'react';
import usePlan from '../../hooks/use-plan';
import useWafData from '../../hooks/use-waf-data';
import styles from './styles.module.scss';

const FirewallStatCards = () => {
const { hasPlan } = usePlan();
const {
config: { bruteForceProtection: isBruteForceModuleEnabled },
isEnabled: isWafModuleEnabled,
Expand All @@ -22,26 +20,22 @@ const FirewallStatCards = () => {
const { currentDay: currentDayBlockCount, thirtyDays: thirtyDayBlockCounts } = stats
? stats.blockedRequests
: { currentDay: 0, thirtyDays: 0 };
const isFeatureDisabled = ! isSupportedWafFeatureEnabled || ! hasPlan;

const defaultArgs = useMemo(
() => ( {
className: isFeatureDisabled ? styles.disabled : styles.active,
className: ! isSupportedWafFeatureEnabled ? styles.disabled : styles.active,
variant: isSmall ? 'horizontal' : 'square',
} ),
[ isFeatureDisabled, isSmall ]
[ isSupportedWafFeatureEnabled, isSmall ]
);

const StatCardIcon = useCallback(
( { icon } ) => (
<span className={ styles[ 'stat-card-icon' ] }>
<Icon icon={ icon } />
{ ! isSmall && ! hasPlan && (
<Text variant="label">{ __( 'Paid feature', 'jetpack-protect' ) }</Text>
) }
</span>
),
[ isSmall, hasPlan ]
[]
);

const StatCardLabel = useCallback(
Expand Down Expand Up @@ -77,19 +71,19 @@ const FirewallStatCards = () => {
...defaultArgs,
icon: <StatCardIcon icon={ shield } />,
label: <StatCardLabel period={ 24 } units="hours" />,
value: isFeatureDisabled ? 0 : currentDayBlockCount,
value: ! isSupportedWafFeatureEnabled ? 0 : currentDayBlockCount,
} ),
[ defaultArgs, StatCardIcon, StatCardLabel, isFeatureDisabled, currentDayBlockCount ]
[ defaultArgs, StatCardIcon, StatCardLabel, isSupportedWafFeatureEnabled, currentDayBlockCount ]
);

const thirtyDaysArgs = useMemo(
() => ( {
...defaultArgs,
icon: <StatCardIcon icon={ chartBar } />,
label: <StatCardLabel period={ 30 } units="days" />,
value: isFeatureDisabled ? 0 : thirtyDayBlockCounts,
value: ! isSupportedWafFeatureEnabled ? 0 : thirtyDayBlockCounts,
} ),
[ defaultArgs, StatCardIcon, StatCardLabel, isFeatureDisabled, thirtyDayBlockCounts ]
[ defaultArgs, StatCardIcon, StatCardLabel, isSupportedWafFeatureEnabled, thirtyDayBlockCounts ]
);

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ const HomeAdminSectionHero: React.FC = () => {
)
: __(
'We stay ahead of security vulnerabilities to keep your site protected.',
'jetpack-protect'
'jetpack-protect',
/* dummy arg to avoid bad minification */ 0
) }
</Text>
<Button
Expand Down
26 changes: 23 additions & 3 deletions projects/plugins/protect/src/js/routes/home/index.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { AdminSection, Container, Col } from '@automattic/jetpack-components';
import { AdminSection, Container, Col, ScanReport } from '@automattic/jetpack-components';
import AdminPage from '../../components/admin-page';
import useScanStatusQuery from '../../data/scan/use-scan-status-query';
import HomeAdminSectionHero from './home-admin-section-hero';
import styles from './styles.module.scss';

/**
* Home Page
Expand All @@ -10,12 +12,30 @@ import HomeAdminSectionHero from './home-admin-section-hero';
* @return {Component} The root component for the scan page.
*/
const HomePage = () => {
const { data: status } = useScanStatusQuery( { usePolling: true } );
const { core, plugins, themes, files } = status;

const data = [
core,
...plugins,
...themes,
{ checked: true, threats: files, type: 'files' },
].map( ( item, index ) => {
return { id: index + 1, ...item };
} );

return (
<AdminPage>
<HomeAdminSectionHero />
<AdminSection>
<Container horizontalSpacing={ 7 } horizontalGap={ 4 }>
<Col>{ /* TODO: Add ScanReport component here */ }</Col>
<Container
className={ styles[ 'scan-report-container' ] }
horizontalSpacing={ 5 }
horizontalGap={ 4 }
>
<Col>
<ScanReport dataSource={ status.dataSource } data={ data } />
</Col>
</Container>
</AdminSection>
</AdminPage>
Expand Down
13 changes: 9 additions & 4 deletions projects/plugins/protect/src/js/routes/home/styles.module.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
.product-section, .info-section {
margin-top: calc( var( --spacing-base ) * 7 ); // 56px
margin-bottom: calc( var( --spacing-base ) * 7 ); // 56px
.scan-report-container {
padding-left: 0;
padding-right: 0;
overflow: hidden;

> * {
margin-left: calc( var( --spacing-base ) * -3 ); // -24px
margin-right: calc( var( --spacing-base ) * -3 ); // -24px
}
}

.view-scan-report {
Expand Down Expand Up @@ -56,7 +62,6 @@
text-align: left;
}


@media ( max-width: 599px ) {
.stat-cards-wrapper {
flex-direction: column;
Expand Down

0 comments on commit 2a53e76

Please sign in to comment.