Skip to content

Commit

Permalink
Update threats data handling in Protect
Browse files Browse the repository at this point in the history
changelog

Update My Jetpack for latest compatibility with protect-status package

changelog
  • Loading branch information
nateweller committed Oct 22, 2024
1 parent cb52442 commit f234dd1
Show file tree
Hide file tree
Showing 58 changed files with 698 additions and 3,621 deletions.
38 changes: 8 additions & 30 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
Expand Up @@ -2,11 +2,12 @@ import { __ } from '@wordpress/i18n';

export const PAID_PLUGIN_SUPPORT_URL = 'https://jetpack.com/contact-support/?rel=support';

export const THREAT_STATUSES = [
{ value: 'current', label: __( 'Active', 'jetpack' ) },
{ value: 'fixed', label: __( 'Fixed', 'jetpack' ) },
{ value: 'ignored', label: __( 'Ignored', 'jetpack' ) },
];
export const THREAT_STATUSES: { value: string; label: string; variant?: 'success' | 'warning' }[] =
[
{ value: 'current', label: __( 'Active', 'jetpack' ), variant: 'warning' },
{ value: 'fixed', label: __( 'Fixed', 'jetpack' ), variant: 'success' },
{ value: 'ignored', label: __( 'Ignored', 'jetpack' ) },
];

export const THREAT_TYPES = [
{ value: 'plugin', label: __( 'Plugin', 'jetpack' ) },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ import {
Action,
DataViews,
Field,
FieldType,
Filter,
filterSortAndPaginate,
SortDirection,
SupportedLayouts,
type View,
} from '@wordpress/dataviews';
import { dateI18n } from '@wordpress/date';
import { __, _x } from '@wordpress/i18n';
import { useCallback, useMemo, useState } from 'react';
import Badge from '../badge';
Expand Down Expand Up @@ -62,7 +64,7 @@ export default function ThreatsDataView( {
search: '',
filters: filters || [],
page: 1,
perPage: 25,
perPage: 20,
};

/**
Expand Down Expand Up @@ -209,6 +211,15 @@ export default function ThreatsDataView( {
THREAT_STATUSES.find( ( { value } ) => value === item.status )?.value ?? item.status
);
},
render( { item }: { item: DataViewThreat } ) {
if ( item.status ) {
const status = THREAT_STATUSES.find( ( { value } ) => value === item.status );
if ( status ) {
return <Badge variant={ status?.variant }>{ status?.label }</Badge>;
}
}
return <Badge variant="warning">{ __( 'Active', 'jetpack' ) }</Badge>;
},
},
{
id: 'extension',
Expand Down Expand Up @@ -322,6 +333,44 @@ export default function ThreatsDataView( {
},
]
: [] ),
...( dataFields.includes( 'firstDetected' )
? [
{
id: 'first-detected',
label: __( 'First Detected', 'jetpack' ),
type: 'datetime' as FieldType,
getValue( { item }: { item: DataViewThreat } ) {
return new Date( item.firstDetected );
},
render( { item }: { item: DataViewThreat } ) {
return (
<span className={ styles.threat__firstDetected }>
{ dateI18n( 'F j Y', item.firstDetected, false ) }
</span>
);
},
},
]
: [] ),
...( dataFields.includes( 'fixedOn' )
? [
{
id: 'fixed-on',
label: __( 'Fixed On', 'jetpack' ),
type: 'datetime' as FieldType,
getValue( { item }: { item: DataViewThreat } ) {
return new Date( item.firstDetected );
},
render( { item }: { item: DataViewThreat } ) {
return (
<span className={ styles.threat__fixedOn }>
{ dateI18n( 'F j Y', item.firstDetected, false ) }
</span>
);
},
},
]
: [] ),
];

return result;
Expand Down Expand Up @@ -351,6 +400,9 @@ export default function ThreatsDataView( {
return !! item.fixable;
},
icon: 'check',
// RenderModal: item => {
// return <div>Hello World!</div>;
// },
} );
}

Expand Down Expand Up @@ -411,6 +463,7 @@ export default function ThreatsDataView( {
* @see https://github.com/WordPress/gutenberg/blob/trunk/packages/dataviews/src/filter-and-sort-data-view.ts
*/
const { data: processedData, paginationInfo } = useMemo( () => {
// to do: secondary sort for status, detected on, etc.
return filterSortAndPaginate( data, view, fields );
}, [ data, view, fields ] );

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,15 @@
font-size: 12px;
}

.threat__fixedOn,
.threat__firstDetected {
white-space: nowrap;
}

.threat__fixedOn {
color: var( --jp-green-70 );
}

.icon-spinner {
svg {
margin: 0;
Expand Down
1 change: 1 addition & 0 deletions projects/js-packages/scan/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
"@wordpress/api-fetch": "7.9.0",
"@wordpress/element": "6.9.0",
"@wordpress/i18n": "5.9.0",
"@wordpress/icons": "10.9.0",
"@wordpress/url": "4.9.0",
"debug": "4.3.4",
"react": "^18.2.0",
Expand Down
1 change: 1 addition & 0 deletions projects/js-packages/scan/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './utils.js';
40 changes: 40 additions & 0 deletions projects/js-packages/scan/src/types/fixers.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
export type FixerStatus = 'not_started' | 'in_progress' | 'fixed' | 'not_fixed';

/**
* Threat Fix Status
*
* Individual fixer status for a threat.
*/
export type ThreatFixStatusError = {
error: string;
};

export type ThreatFixStatusSuccess = {
status: FixerStatus;
last_updated: string;
};

export type ThreatFixStatus = ThreatFixStatusError | ThreatFixStatusSuccess;

/**
* Fixers Status
*
* Overall status of all fixers.
*/
type FixersStatusBase = {
ok: boolean; // Discriminator for overall success
};

export type FixersStatusError = FixersStatusBase & {
ok: false;
error: string;
};

export type FixersStatusSuccess = FixersStatusBase & {
ok: true;
threats: {
[ key: number ]: ThreatFixStatus;
};
};

export type FixersStatus = FixersStatusSuccess | FixersStatusError;
8 changes: 8 additions & 0 deletions projects/js-packages/scan/src/types/threat.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,12 @@ export type Threat = {

/** The diff showing the threat's modified file contents. */
diff?: string;

/** The affected extension. */
extension?: {
slug: string;
name: string;
version: string;
type: 'plugin' | 'theme' | 'core';
};
};
77 changes: 77 additions & 0 deletions projects/js-packages/scan/src/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { code, color, grid, plugins, shield, wordpress } from '@wordpress/icons';
import { ThreatFixStatus } from './types/fixers.js';
import { Threat } from './types/threat.js';

export const getThreatIcon = ( threat: Threat ) => {
const type = getThreatType( threat );

switch ( type ) {
case 'plugin':
return plugins;
case 'theme':
return color;
case 'core':
return wordpress;
case 'file':
return code;
case 'database':
return grid;
default:
return shield;
}
};

export const getThreatType = ( threat: Threat ) => {
if ( threat.signature === 'Vulnerable.WP.Core' ) {
return 'core';
}
if ( threat.extension ) {
return threat.extension.type;
}
if ( threat.filename ) {
return 'file';
}
if ( threat.table ) {
return 'database';
}

return null;
};

export const getThreatSubtitle = ( threat: Threat ) => {
const type = getThreatType( threat );

switch ( type ) {
case 'plugin':
case 'theme':
return `${ threat.extension?.name } (${ threat.extension?.version })`;
case 'core':
return 'WordPress Core';
case 'file':
// Trim leading slash
if ( threat.filename.startsWith( '/' ) ) {
return threat.filename.slice( 1 );
}
return threat.filename;
case 'database':
return threat.table;
default:
return '';
}
};

const FIXER_IS_STALE_THRESHOLD = 1000 * 60 * 60 * 24; // 24 hours

export const fixerTimestampIsStale = ( lastUpdatedTimestamp: string ) => {
const now = new Date();
const lastUpdated = new Date( lastUpdatedTimestamp );
return now.getTime() - lastUpdated.getTime() >= FIXER_IS_STALE_THRESHOLD;
};

export const fixerStatusIsStale = ( fixerStatus: ThreatFixStatus ) => {
return (
'status' in fixerStatus &&
fixerStatus.status === 'in_progress' &&
fixerTimestampIsStale( fixerStatus.last_updated )
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -24,28 +24,14 @@ export const ScanAndThreatStatus = () => {
const {
protect: { scanData },
} = getMyJetpackWindowInitialState();
const { plugins, themes, num_threats: numThreats = 0 } = scanData || {};
const numThreats = scanData.threats.length;

const criticalScanThreatCount = useMemo( () => {
const { core, database, files, num_plugins_threats, num_themes_threats } = scanData || {};
const pluginsThreats = num_plugins_threats
? plugins.reduce( ( accum, plugin ) => accum.concat( plugin.threats ), [] )
: [];
const themesThreats = num_themes_threats
? themes.reduce( ( accum, theme ) => accum.concat( theme.threats ), [] )
: [];
const allThreats = [
...pluginsThreats,
...themesThreats,
...( core?.threats ?? [] ),
...database,
...files,
];
return allThreats.reduce(
return scanData.threats.reduce(
( accum, threat ) => ( threat.severity >= 5 ? ( accum += 1 ) : accum ),
0
);
}, [ plugins, themes, scanData ] );
}, [ scanData.threats ] );

if ( isPluginActive && isSiteConnected ) {
if ( hasProtectPaidPlan ) {
Expand Down
Loading

0 comments on commit f234dd1

Please sign in to comment.