Back

100% Statements 8/8
69.23% Branches 9/13
100% Functions 4/4
100% Lines 8/8

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123                        1x 1x 1x                       1x         1x                                                                     1x     4x                                                                         2x                                
import { __, sprintf } from '@wordpress/i18n';
import { Dialog, Stack, Text } from '@wordpress/ui';
import { SELF_CHECK_RULE_ID } from './firewall-test';
import type { TestResult } from './firewall-test';
 
/**
 * The request's path and query, with the spent token shortened.
 *
 * @param url - The test URL.
 * @return For example `/?jetpack_waf_test=3aa897…`.
 */
function getShortRequest( url: string ): string {
	const { pathname, searchParams } = new URL( url );
	const [ [ name, token ] = [ '', '' ] ] = Array.from( searchParams );
	return `${ pathname }?${ name }=${ token.slice( 0, 6 ) }…`;
}
 
/**
 * The steps the firewall test took, so its result can be checked rather than trusted.
 *
 * @param props          - Component props.
 * @param props.result   - The test's result.
 * @param props.recorded - Whether a new "firewall test" block appeared in the log.
 * @return The steps.
 */
function TestSteps( { result, recorded }: { result: TestResult; recorded: boolean } ) {
	const loggedNote = sprintf(
		/* translators: %d is a firewall rule's ID. */
		__( 'It’s in Recently blocked requests as rule %d.', 'jetpack-protect-pkg' ),
		SELF_CHECK_RULE_ID
	);
	const steps = [
		{
			title: __( 'Created a one-time test token', 'jetpack-protect-pkg' ),
			detail: __(
				'Saved on your server for 60 seconds. The firewall checks for it before any of its rules, so the test works even with automatic rules off.',
				'jetpack-protect-pkg'
			),
		},
		{
			title: __( 'Requested your site as a logged-out visitor', 'jetpack-protect-pkg' ),
			code: `GET ${ getShortRequest( result.url ) }`,
		},
		{
			title: __( 'Got a response', 'jetpack-protect-pkg' ),
			code: [
				`${ result.status } ${ result.statusText }`.trim(),
				result.wafHeader && `X-JetpackWAF-Blocked: ${ result.wafHeader }`,
			]
				.filter( Boolean )
				.join( '\n' ),
			detail: result.wafHeader
				? undefined
				: __(
						'No firewall header, so the firewall didn’t act on the request.',
						'jetpack-protect-pkg'
					),
		},
		{
			title: recorded
				? __( 'Logged the block', 'jetpack-protect-pkg' )
				: __( 'Nothing was logged', 'jetpack-protect-pkg' ),
			detail: recorded ? loggedNote : undefined,
		},
	];
 
	return (
		<ol className="jp-protect-firewall-test">
			{ steps.map( step => (
				<li key={ step.title } className="jp-protect-firewall-test__step">
					<Stack direction="column" gap="xs">
						<Text variant="body-md">{ step.title }</Text>
						{ step.code && <pre className="jp-protect-firewall-test__code">{ step.code }</pre> }
						{ step.detail && (
							<Text variant="body-sm" className="jp-protect-card__muted">
								{ step.detail }
							</Text>
						) }
					</Stack>
				</li>
			) ) }
		</ol>
	);
}
 
/**
 * The test's steps in a dialog, opened from the result's "Learn more".
 *
 * @param props              - Component props.
 * @param props.result       - The test's result.
 * @param props.recorded     - Whether a new "firewall test" block appeared in the log.
 * @param props.open         - Whether the dialog is open.
 * @param props.onOpenChange - Opens or closes the dialog.
 * @return The dialog.
 */
export default function TestDetails( {
	result,
	recorded,
	open,
	onOpenChange,
}: {
	result: TestResult;
	recorded: boolean;
	open: boolean;
	onOpenChange: ( open: boolean ) => void;
} ) {
	return (
		<Dialog.Root open={ open } onOpenChange={ onOpenChange }>
			<Dialog.Popup>
				<Dialog.Header>
					<Dialog.Title>
						{ __( 'How the firewall test works', 'jetpack-protect-pkg' ) }
					</Dialog.Title>
					<Dialog.CloseIcon />
				</Dialog.Header>
				<Dialog.Content>
					<TestSteps result={ result } recorded={ recorded } />
				</Dialog.Content>
			</Dialog.Popup>
		</Dialog.Root>
	);
}