Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Windows support for Malicious website protection #1423

Merged
merged 14 commits into from
Feb 20, 2025
1 change: 1 addition & 0 deletions special-pages/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
'special-error': {
integration: ['copy', 'build-js'],
apple: ['copy', 'build-js', 'inline-html'],
windows: ['copy', 'build-js', 'inline-html'],
},
/** @type {Partial<Record<ImportMeta['injectName'], string[]>>} */
'new-tab': {
Expand Down Expand Up @@ -99,7 +100,7 @@
const outputDir = join(pageOutputDirectory, 'dist');
buildJobs.push({
outputDir,
injectName: /** @type {ImportMeta['injectName']} */ (injectName),

Check warning on line 103 in special-pages/index.mjs

View workflow job for this annotation

GitHub Actions / unit (ubuntu-latest)

Expected property shorthand

Check warning on line 103 in special-pages/index.mjs

View workflow job for this annotation

GitHub Actions / unit (windows-latest)

Expected property shorthand
pageName,
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,14 @@ export function AdvancedInfo() {

return (
<div className={styles.wrapper}>
<div className={styles.container} onAnimationEnd={trigger}>
<AdvancedInfoHeading />
<div className={styles.animationContainer} onAnimationEnd={trigger}>
<div className={styles.container}>
<AdvancedInfoHeading />

<AdvancedInfoContent />
<AdvancedInfoContent />

<VisitSiteLink elemRef={ref} />
<VisitSiteLink elemRef={ref} />
</div>
</div>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
.animationContainer {
animation-duration: 300ms;
animation-fill-mode: forwards;
animation-name: appear;
}

.container {
align-items: flex-start;
display: flex;
flex-flow: column;
gap: var(--sp-4);
max-width: var(--ios-content-max-width);
padding: var(--sp-6) var(--sp-10);
width: 100%;

animation-duration: 300ms;
animation-fill-mode: forwards;
animation-name: appear;
}

.heading {
Expand Down Expand Up @@ -38,25 +41,15 @@

@keyframes appear {
0% {
padding: 0 var(--sp-10);
max-height: 0;
}
100% {
padding: var(--sp-6) var(--sp-10);
max-height: calc(400 * var(--px-in-rem));
}
}

/* Platform-specific styles */

/* macOS */
[data-platform-name="macos"] {
& .container {
background: var(--advanced-info-bg);
box-shadow: inset 0 1px 0 0 var(--border-color);
}
}

/* iOS */
[data-platform-name="ios"] {
& .wrapper {
Expand Down Expand Up @@ -90,3 +83,19 @@
line-height: calc(21 * var(--px-in-rem));
}
}

/* macOS */
[data-platform-name="macos"] {
& .container {
background: var(--advanced-info-bg);
box-shadow: inset 0 1px 0 0 var(--border-color);
}
}

/* windows */
[data-platform-name="windows"] {
& .container {
background: var(--advanced-info-bg);
box-shadow: inset 0 1px 0 0 var(--border-color);
}
}
21 changes: 17 additions & 4 deletions special-pages/pages/special-error/app/components/App.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ html,
body {
height: 100%;
margin: 0;

--theme-font-family: system, -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
}

.main {
Expand Down Expand Up @@ -36,6 +38,13 @@ body {

/* Platform-specific styles */

/* iOS */
[data-platform-name="ios"] {
& .container {
align-items: center;
}
}

/* macOS */
[data-platform-name="macos"] {
& .container {
Expand All @@ -47,9 +56,13 @@ body {
}
}

/* iOS */
[data-platform-name="ios"] {
/* Windows */
[data-platform-name="windows"] {
& .container {
align-items: center;
background: var(--container-bg);
border-radius: var(--sp-4);
border: 1px solid var(--border-color);
min-width: calc(400 * var(--px-in-rem));
width: calc(504 * var(--px-in-rem));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@ import { AdvancedInfoButton, LeaveSiteButton, Warning, WarningContent, WarningHe
* @typedef {SSLExpiredCertificate|SSLInvalidCertificate|SSLSelfSignedCertificate|SSLWrongHost} SSLError
*/

/** @type {Record<Extract<import("../../types/special-error.js").InitialSetupResponse['platform']['name'], "macos"|"ios">, string>} */
/** @type {Record<Extract<import("../../types/special-error.js").InitialSetupResponse['platform']['name'], "ios"|"macos"|"windows">, string>} */
const platforms = {
macos: 'macOS',
ios: 'iOS',
macos: 'macOS',
windows: 'Windows',
};

/**
Expand Down Expand Up @@ -58,8 +59,8 @@ export function Components() {
};

return (
<div data-theme={isDarkMode ? 'dark' : 'light'}>
<div className={styles.selector}>
<div>
<nav className={styles.selector}>
<fieldset>
<label for="platform-select">Platform:</label>
<select id="platform-select" onChange={(e) => handlePlatformChange(e.currentTarget?.value)}>
Expand All @@ -84,8 +85,8 @@ export function Components() {
})}
</select>
</fieldset>
</div>
<main class={styles.main} data-platform-name={platformName}>
</nav>
<main class={styles.main} data-platform-name={platformName} data-theme={isDarkMode ? 'dark' : 'light'}>
<h1>Special Error Components</h1>

<section>
Expand Down
55 changes: 36 additions & 19 deletions special-pages/pages/special-error/app/components/Warning.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import classNames from 'classnames';
import { useTypedTranslation } from '../types';
import { useMessaging } from '../providers/MessagingProvider';
import { useErrorData } from '../providers/SpecialErrorProvider';
import { usePlatformName } from '../providers/SettingsProvider';
import { usePlatformName, useIsMobile } from '../providers/SettingsProvider';
import { useWarningHeading, useWarningContent } from '../hooks/ErrorStrings';
import { Text } from '../../../../shared/components/Text/Text';
import { Button } from '../../../../shared/components/Button/Button';
Expand All @@ -16,15 +16,12 @@ import styles from './Warning.module.css';
*/
export function AdvancedInfoButton({ onClick }) {
const { t } = useTypedTranslation();
const platformName = usePlatformName();
const isMobile = useIsMobile();
const buttonVariant = isMobile ? 'ghost' : 'standard';

return (
<Button
variant={platformName === 'macos' ? 'standard' : 'ghost'}
className={classNames(styles.button, styles.advanced)}
onClick={onClick}
>
{platformName === 'ios' ? t('advancedButton') : t('advancedEllipsisButton')}
<Button variant={buttonVariant} className={classNames(styles.button, styles.advanced)} onClick={onClick}>
{isMobile ? t('advancedButton') : t('advancedEllipsisButton')}
</Button>
);
}
Expand All @@ -34,12 +31,22 @@ export function LeaveSiteButton() {
const { messaging } = useMessaging();
const platformName = usePlatformName();

/** @type {import('../../../../shared/components/Button/Button').ButtonProps['variant']} */
let buttonVariant;
switch (platformName) {
case 'ios':
case 'android':
buttonVariant = 'primary';
break;
case 'windows':
buttonVariant = 'accentBrand';
break;
default:
buttonVariant = 'accent';
}

return (
<Button
variant={platformName === 'macos' ? 'accent' : 'primary'}
className={classNames(styles.button, styles.leaveSite)}
onClick={() => messaging?.leaveSite()}
>
<Button variant={buttonVariant} className={classNames(styles.button, styles.leaveSite)} onClick={() => messaging?.leaveSite()}>
{t('leaveSiteButton')}
</Button>
);
Expand All @@ -49,16 +56,26 @@ export function WarningHeading() {
const { kind } = useErrorData();
const heading = useWarningHeading();
const platformName = usePlatformName();
const isMobile = useIsMobile();

/** @type {'title-2'|'title-2-emphasis'|'custom-title-1'} */
let textVariant;
switch (platformName) {
case 'ios':
case 'android':
textVariant = 'title-2';
break;
case 'windows':
textVariant = 'custom-title-1';
break;
default:
textVariant = 'title-2-emphasis';
}

return (
<header className={classNames(styles.heading, styles[kind])}>
<i className={styles.icon} aria-hidden="true" />
<Text
as="h1"
variant={platformName === 'macos' ? 'title-2-emphasis' : 'title-2'}
strictSpacing={platformName !== 'macos'}
className={styles.title}
>
<Text as="h1" variant={textVariant} strictSpacing={isMobile} className={styles.title}>
{heading}
</Text>
</header>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@
}
}


/* iOS */
[data-platform-name="ios"] {
& .container {
Expand Down Expand Up @@ -140,4 +139,53 @@
white-space: normal;
}
}
}

/* Windows */
[data-platform-name="windows"] {
--border-radius-sm: 6px;

& .icon {
align-self: flex-start;
flex: 0 0 var(--sp-12);
height: var(--sp-12);
width: var(--sp-12);
}

& .heading {
gap: var(--sp-4);
}

& .ssl.heading {
height: var(--sp-8);
}

& .ssl .icon {
background-image: url(../../../../shared/assets/img/icons/Shield-Alert-96.svg);
margin-left: calc(-1 * var(--sp-2));
margin-top: calc(-1 * var(--sp-2));
}

& .phishing .icon, & .malware .icon {
background-image: url(../../../../shared/assets/img/icons/Malware-Site-96.svg);
margin-left: calc(-1 * var(--sp-2));
margin-right: calc(-1 * var(--sp-1));
}

& .buttonContainer {
flex-flow: row-reverse;
gap: var(--sp-4);
justify-content: flex-end;
}

& .button {
flex: 0 0 calc(50% - var(--sp-2));

/* TODO: Move to shared? */
font-family: var(--theme-font-family);
font-size: calc(14 * var(--px-in-rem));
font-weight: 400;
line-height: normal;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,8 @@ export function SettingsProvider({ settings, children }) {
export function usePlatformName() {
return useContext(SettingsContext).settings.platform?.name;
}

export function useIsMobile() {
const platformName = useContext(SettingsContext).settings.platform?.name;
return platformName === 'android' || platformName === 'ios';
}
5 changes: 0 additions & 5 deletions special-pages/pages/special-error/app/styles/variables.css
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,4 @@
}
}

[data-platform-name="macos"], [data-platform-name="ios"] {
--theme-font: -apple-system, BlinkMacSystemFont, "Helvetica Neue", sans-serif;
}



Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/* global process */
import { expect, test } from '@playwright/test';
import { SpecialErrorPage } from './special-error';

const maxDiffPixels = 20;

test.describe('screenshots @screenshots', () => {
test.skip(process.env.CI === 'true');

test('SSL expired cert error', async ({ page }, workerInfo) => {
const special = SpecialErrorPage.create(page, workerInfo);
await special.openPage({ errorId: 'ssl.expired' });
await expect(page).toHaveScreenshot('ssl-expired-cert.png', { maxDiffPixels });
});

test('SSL expired cert error with reduced motion', async ({ page }, workerInfo) => {
const special = SpecialErrorPage.create(page, workerInfo);
await special.reducedMotion();
await special.openPage({ errorId: 'ssl.expired' });
await special.showsAdvancedInfo();
await expect(page).toHaveScreenshot('ssl-expired-cert-reduced-motion.png', { maxDiffPixels });
});

test('Phishing warning with advanced info', async ({ page }, workerInfo) => {
const special = SpecialErrorPage.create(page, workerInfo);
await special.openPage({ errorId: 'phishing' });
await special.showsAdvancedInfo();
await expect(page).toHaveScreenshot('phishing-warning-advanced.png', { maxDiffPixels });
});

test('Malware warning in Russian', async ({ page }, workerInfo) => {
const special = SpecialErrorPage.create(page, workerInfo);
await special.openPage({ errorId: 'malware', locale: 'ru' });
await expect(page).toHaveScreenshot('malware-warning-ru.png', { maxDiffPixels });
});
});
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading