@automattic/jetpack-scan 0.5.8 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/build/components/index.d.ts +4 -0
- package/build/components/index.js +4 -0
- package/build/components/threat-fixer-button/index.d.ts +16 -0
- package/build/components/threat-fixer-button/index.js +56 -0
- package/build/components/threat-modal/fixer-state-notice.d.ts +19 -0
- package/build/components/threat-modal/fixer-state-notice.js +44 -0
- package/build/components/threat-modal/index.d.ts +51 -0
- package/build/components/threat-modal/index.js +45 -0
- package/build/components/threat-modal/threat-actions.d.ts +7 -0
- package/build/components/threat-modal/threat-actions.js +40 -0
- package/build/components/threat-modal/threat-fix-confirmation.d.ts +7 -0
- package/build/components/threat-modal/threat-fix-confirmation.js +19 -0
- package/build/components/threat-modal/threat-fix-details.d.ts +7 -0
- package/build/components/threat-modal/threat-fix-details.js +40 -0
- package/build/components/threat-modal/threat-notice.d.ts +16 -0
- package/build/components/threat-modal/threat-notice.js +23 -0
- package/build/components/threat-modal/threat-summary.d.ts +7 -0
- package/build/components/threat-modal/threat-summary.js +16 -0
- package/build/components/threat-modal/threat-technical-details.d.ts +7 -0
- package/build/components/threat-modal/threat-technical-details.js +26 -0
- package/build/components/threat-severity-badge/index.d.ts +4 -0
- package/build/components/threat-severity-badge/index.js +13 -0
- package/build/components/threat-severity-badge/test/index.test.d.ts +1 -0
- package/build/components/threat-severity-badge/test/index.test.js +9 -0
- package/build/components/threats-data-views/constants.d.ts +33 -0
- package/build/components/threats-data-views/constants.js +37 -0
- package/build/components/threats-data-views/index.d.ts +29 -0
- package/build/components/threats-data-views/index.js +412 -0
- package/build/components/threats-data-views/test/index.test.d.ts +1 -0
- package/build/components/threats-data-views/test/index.test.js +51 -0
- package/build/components/threats-data-views/threats-status-toggle-group-control.d.ts +15 -0
- package/build/components/threats-data-views/threats-status-toggle-group-control.js +95 -0
- package/build/index.d.ts +4 -3
- package/build/index.js +4 -3
- package/build/types/index.d.ts +3 -3
- package/build/types/index.js +3 -3
- package/build/types/status.d.ts +1 -1
- package/build/types/threats.d.ts +1 -1
- package/build/utils/index.d.ts +2 -2
- package/build/utils/index.js +7 -9
- package/package.json +23 -18
- package/src/components/index.js +4 -0
- package/src/components/threat-fixer-button/index.tsx +101 -0
- package/src/components/threat-fixer-button/styles.module.scss +16 -0
- package/src/components/threat-modal/fixer-state-notice.tsx +63 -0
- package/src/components/threat-modal/index.tsx +109 -0
- package/src/components/threat-modal/styles.module.scss +82 -0
- package/src/components/threat-modal/threat-actions.tsx +93 -0
- package/src/components/threat-modal/threat-fix-confirmation.tsx +54 -0
- package/src/components/threat-modal/threat-fix-details.tsx +64 -0
- package/src/components/threat-modal/threat-notice.tsx +84 -0
- package/src/components/threat-modal/threat-summary.tsx +29 -0
- package/src/components/threat-modal/threat-technical-details.tsx +65 -0
- package/src/components/threat-severity-badge/index.tsx +24 -0
- package/src/components/threat-severity-badge/styles.module.scss +27 -0
- package/src/components/threat-severity-badge/test/index.test.jsx +9 -0
- package/src/components/threats-data-views/constants.ts +49 -0
- package/src/components/threats-data-views/index.tsx +533 -0
- package/src/components/threats-data-views/styles.module.scss +40 -0
- package/src/components/threats-data-views/test/index.test.jsx +56 -0
- package/src/components/threats-data-views/threats-status-toggle-group-control.tsx +158 -0
- package/src/index.ts +4 -3
- package/src/types/index.ts +3 -3
- package/src/types/status.ts +1 -1
- package/src/types/threats.ts +1 -1
- package/src/utils/index.ts +3 -3
- /package/src/{index.test.ts → index.test.js} +0 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { ContextualUpgradeTrigger, Text } from '@automattic/jetpack-components';
|
|
2
|
+
import { __, sprintf } from '@wordpress/i18n';
|
|
3
|
+
import React, { useMemo, useContext } from 'react';
|
|
4
|
+
import { getFixerDescription } from '@automattic/jetpack-scan';
|
|
5
|
+
import { ThreatModalContext } from './index.tsx';
|
|
6
|
+
import styles from './styles.module.scss';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* ThreatFixDetails component
|
|
10
|
+
*
|
|
11
|
+
* @return {JSX.Element | null} The rendered fix details or null if no fixable details are available.
|
|
12
|
+
*/
|
|
13
|
+
const ThreatFixDetails = (): JSX.Element => {
|
|
14
|
+
const { threat, handleUpgradeClick } = useContext( ThreatModalContext );
|
|
15
|
+
|
|
16
|
+
const title = useMemo( () => {
|
|
17
|
+
if ( threat.status === 'fixed' ) {
|
|
18
|
+
return __( 'How did Jetpack fix it?', 'jetpack-scan' );
|
|
19
|
+
}
|
|
20
|
+
if ( threat.status === 'current' && threat.fixable ) {
|
|
21
|
+
return __( 'How can Jetpack auto-fix this threat?', 'jetpack-scan' );
|
|
22
|
+
}
|
|
23
|
+
return __( 'How to fix it?', 'jetpack-scan' );
|
|
24
|
+
}, [ threat ] );
|
|
25
|
+
|
|
26
|
+
const fix = useMemo( () => {
|
|
27
|
+
// The threat has a fixed version available, but no auto-fix is available.
|
|
28
|
+
// The user needs to update the extension to the fixed version.
|
|
29
|
+
if ( ! threat.fixable && threat.fixedIn ) {
|
|
30
|
+
return sprintf(
|
|
31
|
+
/* translators: Translates to Updates to version. %1$s: Name. %2$s: Fixed version */
|
|
32
|
+
__( 'Update %1$s to version %2$s.', 'jetpack-scan' ),
|
|
33
|
+
threat.extension.name,
|
|
34
|
+
threat.fixedIn
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// The threat has an auto-fix available.
|
|
39
|
+
return getFixerDescription( threat );
|
|
40
|
+
}, [ threat ] );
|
|
41
|
+
|
|
42
|
+
if ( ! threat.fixable && ! threat.fixedIn ) {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<div className={ styles.section }>
|
|
48
|
+
<Text variant="title-small">{ title }</Text>
|
|
49
|
+
<Text>{ fix }</Text>
|
|
50
|
+
{ handleUpgradeClick && (
|
|
51
|
+
<ContextualUpgradeTrigger
|
|
52
|
+
description={ __(
|
|
53
|
+
'Looking for advanced scan results and one-click fixes?',
|
|
54
|
+
'jetpack-scan'
|
|
55
|
+
) }
|
|
56
|
+
cta={ __( 'Upgrade Jetpack now', 'jetpack-scan' ) }
|
|
57
|
+
onClick={ handleUpgradeClick }
|
|
58
|
+
/>
|
|
59
|
+
) }
|
|
60
|
+
</div>
|
|
61
|
+
);
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export default ThreatFixDetails;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { Text, Button } from '@automattic/jetpack-components';
|
|
2
|
+
import { Notice, Spinner } from '@wordpress/components';
|
|
3
|
+
import { __ } from '@wordpress/i18n';
|
|
4
|
+
import { Icon, warning } from '@wordpress/icons';
|
|
5
|
+
import { useContext } from 'react';
|
|
6
|
+
import { ThreatModalContext } from './index.tsx';
|
|
7
|
+
import styles from './styles.module.scss';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* ThreatNotice component
|
|
11
|
+
*
|
|
12
|
+
* @param {object} props - The component props.
|
|
13
|
+
* @param {string} props.status - The status of the notice.
|
|
14
|
+
* @param {string} props.title - The title of the notice.
|
|
15
|
+
* @param {string} props.content - The content of the notice.
|
|
16
|
+
*
|
|
17
|
+
* @return {JSX.Element} The rendered ThreatNotice component.
|
|
18
|
+
*/
|
|
19
|
+
const ThreatNotice = ( {
|
|
20
|
+
status = 'warning',
|
|
21
|
+
title,
|
|
22
|
+
content,
|
|
23
|
+
}: {
|
|
24
|
+
status?: 'warning' | 'error' | 'success' | undefined;
|
|
25
|
+
title: string;
|
|
26
|
+
content: string;
|
|
27
|
+
} ): JSX.Element => {
|
|
28
|
+
const {
|
|
29
|
+
userConnectionNeeded,
|
|
30
|
+
userIsConnecting,
|
|
31
|
+
handleConnectUser,
|
|
32
|
+
siteCredentialsNeeded,
|
|
33
|
+
credentialsRedirectUrl,
|
|
34
|
+
credentialsIsFetching,
|
|
35
|
+
} = useContext( ThreatModalContext );
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<Notice
|
|
39
|
+
status={ status }
|
|
40
|
+
isDismissible={ false }
|
|
41
|
+
children={
|
|
42
|
+
<div className={ styles.notice }>
|
|
43
|
+
<div className={ styles.notice__title }>
|
|
44
|
+
{ status === 'success' ? (
|
|
45
|
+
<Spinner className={ styles.spinner } />
|
|
46
|
+
) : (
|
|
47
|
+
<Icon icon={ warning } size={ 30 } />
|
|
48
|
+
) }
|
|
49
|
+
<Text variant="title-small" mb={ 2 }>
|
|
50
|
+
{ title }
|
|
51
|
+
</Text>
|
|
52
|
+
</div>
|
|
53
|
+
<Text>{ content }</Text>
|
|
54
|
+
<div className={ styles.notice__actions }>
|
|
55
|
+
{ userConnectionNeeded && (
|
|
56
|
+
<Button
|
|
57
|
+
className={ styles.notice__action }
|
|
58
|
+
isExternalLink={ true }
|
|
59
|
+
weight="regular"
|
|
60
|
+
isLoading={ userIsConnecting }
|
|
61
|
+
onClick={ handleConnectUser }
|
|
62
|
+
>
|
|
63
|
+
{ __( 'Connect your user account', 'jetpack-scan' ) }
|
|
64
|
+
</Button>
|
|
65
|
+
) }
|
|
66
|
+
{ siteCredentialsNeeded && (
|
|
67
|
+
<Button
|
|
68
|
+
className={ styles.notice__action }
|
|
69
|
+
isExternalLink={ true }
|
|
70
|
+
weight="regular"
|
|
71
|
+
href={ credentialsRedirectUrl }
|
|
72
|
+
isLoading={ credentialsIsFetching }
|
|
73
|
+
>
|
|
74
|
+
{ __( 'Enter server credentials', 'jetpack-scan' ) }
|
|
75
|
+
</Button>
|
|
76
|
+
) }
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
79
|
+
}
|
|
80
|
+
/>
|
|
81
|
+
);
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export default ThreatNotice;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Button, Text } from '@automattic/jetpack-components';
|
|
2
|
+
import { __ } from '@wordpress/i18n';
|
|
3
|
+
import { useContext } from 'react';
|
|
4
|
+
import { ThreatModalContext } from './index.tsx';
|
|
5
|
+
import styles from './styles.module.scss';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* ThreatSummary component
|
|
9
|
+
*
|
|
10
|
+
* @return {JSX.Element} The rendered threat summary.
|
|
11
|
+
*/
|
|
12
|
+
const ThreatSummary = (): JSX.Element => {
|
|
13
|
+
const { threat } = useContext( ThreatModalContext );
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<div className={ styles.section }>
|
|
17
|
+
{ !! threat.description && <Text>{ threat.description }</Text> }
|
|
18
|
+
{ !! threat.source && (
|
|
19
|
+
<div>
|
|
20
|
+
<Button variant="link" isExternalLink={ true } weight="regular" href={ threat.source }>
|
|
21
|
+
{ __( 'See more technical details of this threat', 'jetpack-scan' ) }
|
|
22
|
+
</Button>
|
|
23
|
+
</div>
|
|
24
|
+
) }
|
|
25
|
+
</div>
|
|
26
|
+
);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export default ThreatSummary;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Text, Button, DiffViewer, MarkedLines } from '@automattic/jetpack-components';
|
|
2
|
+
import { __ } from '@wordpress/i18n';
|
|
3
|
+
import { chevronDown, chevronUp, Icon } from '@wordpress/icons';
|
|
4
|
+
import { useState, useCallback, useContext } from 'react';
|
|
5
|
+
import { ThreatModalContext } from './index.tsx';
|
|
6
|
+
import styles from './styles.module.scss';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* ThreatTechnicalDetails component
|
|
10
|
+
*
|
|
11
|
+
* @return {JSX.Element | null} The rendered technical details or null if no details are available.
|
|
12
|
+
*/
|
|
13
|
+
const ThreatTechnicalDetails = (): JSX.Element => {
|
|
14
|
+
const { threat } = useContext( ThreatModalContext );
|
|
15
|
+
|
|
16
|
+
const [ open, setOpen ] = useState( false );
|
|
17
|
+
|
|
18
|
+
const toggleOpen = useCallback( () => {
|
|
19
|
+
setOpen( ! open );
|
|
20
|
+
}, [ open ] );
|
|
21
|
+
|
|
22
|
+
if ( ! threat.filename && ! threat.context && ! threat.diff ) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<div className={ styles.section }>
|
|
28
|
+
<div className={ styles.section__title }>
|
|
29
|
+
<Button
|
|
30
|
+
variant="link"
|
|
31
|
+
className={ styles.section__toggle }
|
|
32
|
+
aria-expanded={ open }
|
|
33
|
+
aria-controls={ `threat-details-${ threat.id }` }
|
|
34
|
+
onClick={ toggleOpen }
|
|
35
|
+
>
|
|
36
|
+
<div className={ styles.section__toggle__content }>
|
|
37
|
+
<Text variant="title-small" mb={ 0 }>
|
|
38
|
+
{ open
|
|
39
|
+
? __( 'Hide the technical details', 'jetpack-scan' )
|
|
40
|
+
: __( 'Show the technical details', 'jetpack-scan' ) }
|
|
41
|
+
</Text>
|
|
42
|
+
<Icon icon={ open ? chevronUp : chevronDown } size={ 24 } />
|
|
43
|
+
</div>
|
|
44
|
+
</Button>
|
|
45
|
+
</div>
|
|
46
|
+
{ open && (
|
|
47
|
+
<div
|
|
48
|
+
className={ open ? styles.section__open : styles.section__closed }
|
|
49
|
+
id={ `threat-details-${ threat.id }` }
|
|
50
|
+
>
|
|
51
|
+
{ threat.filename && (
|
|
52
|
+
<>
|
|
53
|
+
<Text>{ __( 'Threat found in file:', 'jetpack-scan' ) }</Text>
|
|
54
|
+
<pre className={ styles.filename }>{ threat.filename }</pre>
|
|
55
|
+
</>
|
|
56
|
+
) }
|
|
57
|
+
{ threat.context && <MarkedLines context={ threat.context } /> }
|
|
58
|
+
{ threat.diff && <DiffViewer diff={ threat.diff } /> }
|
|
59
|
+
</div>
|
|
60
|
+
) }
|
|
61
|
+
</div>
|
|
62
|
+
);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export default ThreatTechnicalDetails;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Badge } from '@automattic/jetpack-components';
|
|
2
|
+
import { _x } from '@wordpress/i18n';
|
|
3
|
+
|
|
4
|
+
const ThreatSeverityBadge = ( { severity } ) => {
|
|
5
|
+
if ( severity >= 5 ) {
|
|
6
|
+
return (
|
|
7
|
+
<Badge variant="danger">
|
|
8
|
+
{ _x( 'Critical', 'Severity label for issues rated 5 or higher.', 'jetpack-scan' ) }
|
|
9
|
+
</Badge>
|
|
10
|
+
);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if ( severity >= 3 && severity < 5 ) {
|
|
14
|
+
return (
|
|
15
|
+
<Badge variant="warning">
|
|
16
|
+
{ _x( 'High', 'Severity label for issues rated between 3 and 5.', 'jetpack-scan' ) }
|
|
17
|
+
</Badge>
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return <Badge>{ _x( 'Low', 'Severity label for issues rated below 3.', 'jetpack-scan' ) }</Badge>;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export default ThreatSeverityBadge;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
.threat-severity-badge {
|
|
2
|
+
border-radius: 32px;
|
|
3
|
+
flex-shrink: 0;
|
|
4
|
+
font-size: 12px;
|
|
5
|
+
font-style: normal;
|
|
6
|
+
font-weight: 600;
|
|
7
|
+
line-height: 16px;
|
|
8
|
+
padding: calc( var( --spacing-base ) / 2 ); // 4px
|
|
9
|
+
position: relative;
|
|
10
|
+
text-align: center;
|
|
11
|
+
width: 60px;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.is-critical {
|
|
15
|
+
background: var( --jp-red-5 );
|
|
16
|
+
color: var( --jp-red-60 );
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.is-high {
|
|
20
|
+
background: var( --jp-yellow-5 );
|
|
21
|
+
color: var( --jp-yellow-60 );
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.is-low {
|
|
25
|
+
background: var( --jp-gray-0 );
|
|
26
|
+
color: var( --jp-gray-50 );
|
|
27
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { render, screen } from '@testing-library/react';
|
|
2
|
+
import ThreatSeverityBadge from '../index.tsx';
|
|
3
|
+
|
|
4
|
+
describe( 'ThreatSeverityBadge', () => {
|
|
5
|
+
it( 'renders the correct severity label', () => {
|
|
6
|
+
render( <ThreatSeverityBadge severity={ 4 } /> );
|
|
7
|
+
expect( screen.getByText( 'High' ) ).toBeInTheDocument();
|
|
8
|
+
} );
|
|
9
|
+
} );
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { __ } from '@wordpress/i18n';
|
|
2
|
+
import {
|
|
3
|
+
code as fileIcon,
|
|
4
|
+
color as themeIcon,
|
|
5
|
+
plugins as pluginIcon,
|
|
6
|
+
shield as shieldIcon,
|
|
7
|
+
wordpress as coreIcon,
|
|
8
|
+
} from '@wordpress/icons';
|
|
9
|
+
|
|
10
|
+
export const THREAT_STATUSES: { value: string; label: string; variant?: 'success' | 'warning' }[] =
|
|
11
|
+
[
|
|
12
|
+
{ value: 'current', label: __( 'Active', 'jetpack-scan' ), variant: 'warning' },
|
|
13
|
+
{ value: 'fixed', label: __( 'Fixed', 'jetpack-scan' ), variant: 'success' },
|
|
14
|
+
{ value: 'ignored', label: __( 'Ignored', 'jetpack-scan' ) },
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
export const THREAT_TYPES = [
|
|
18
|
+
{ value: 'plugins', label: __( 'Plugin', 'jetpack-scan' ) },
|
|
19
|
+
{ value: 'themes', label: __( 'Theme', 'jetpack-scan' ) },
|
|
20
|
+
{ value: 'core', label: __( 'WordPress', 'jetpack-scan' ) },
|
|
21
|
+
{ value: 'file', label: __( 'File', 'jetpack-scan' ) },
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
export const THREAT_ICONS = {
|
|
25
|
+
plugins: pluginIcon,
|
|
26
|
+
themes: themeIcon,
|
|
27
|
+
core: coreIcon,
|
|
28
|
+
file: fileIcon,
|
|
29
|
+
default: shieldIcon,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const THREAT_FIELD_THREAT = 'threat';
|
|
33
|
+
export const THREAT_FIELD_TITLE = 'title';
|
|
34
|
+
export const THREAT_FIELD_DESCRIPTION = 'description';
|
|
35
|
+
export const THREAT_FIELD_ICON = 'icon';
|
|
36
|
+
export const THREAT_FIELD_STATUS = 'status';
|
|
37
|
+
export const THREAT_FIELD_TYPE = 'type';
|
|
38
|
+
export const THREAT_FIELD_EXTENSION = 'extension';
|
|
39
|
+
export const THREAT_FIELD_PLUGIN = 'plugin';
|
|
40
|
+
export const THREAT_FIELD_THEME = 'theme';
|
|
41
|
+
export const THREAT_FIELD_SEVERITY = 'severity';
|
|
42
|
+
export const THREAT_FIELD_SIGNATURE = 'signature';
|
|
43
|
+
export const THREAT_FIELD_FIRST_DETECTED = 'first-detected';
|
|
44
|
+
export const THREAT_FIELD_FIXED_ON = 'fixed-on';
|
|
45
|
+
export const THREAT_FIELD_AUTO_FIX = 'auto-fix';
|
|
46
|
+
|
|
47
|
+
export const THREAT_ACTION_FIX = 'fix';
|
|
48
|
+
export const THREAT_ACTION_IGNORE = 'ignore';
|
|
49
|
+
export const THREAT_ACTION_UNIGNORE = 'unignore';
|