Skip to content

Commit 80da9e1

Browse files
committed
Scam protection
1 parent 35085ff commit 80da9e1

File tree

11 files changed

+105
-47
lines changed

11 files changed

+105
-47
lines changed

special-pages/pages/special-error/app/components/App.jsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,9 @@ function PageTitle() {
3434
useEffect(() => {
3535
switch (kind) {
3636
case 'malware':
37-
document.title = t('malwareTabTitle');
38-
break;
3937
case 'phishing':
40-
document.title = t('phishingTabTitle');
38+
case 'scam':
39+
document.title = t('maliciousSiteTabTitle');
4140
break;
4241
default:
4342
document.title = t('sslPageHeading');

special-pages/pages/special-error/app/components/Components.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ const platforms = {
2929
*/
3030
function idForError(errorData) {
3131
const { kind } = errorData;
32-
if (kind === 'phishing' || kind === 'malware') {
32+
if (kind === 'malware' || kind === 'phishing' || kind === 'scam') {
3333
return kind;
3434
}
3535

special-pages/pages/special-error/app/components/Warning.module.css

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@
6060
margin-top: calc(-1 * var(--sp-2));
6161
}
6262

63-
& .phishing .icon, & .malware .icon {
63+
& .phishing .icon, & .malware .icon, & .scam .icon {
6464
background-image: url(../../../../shared/assets/img/icons/Malware-Site-96.svg);
6565
margin-left: calc(-1 * var(--sp-2));
6666
margin-right: calc(-1 * var(--sp-1));
@@ -116,7 +116,7 @@
116116
background-image: url(../../../../shared/assets/img/icons/Shield-Alert-128.svg);
117117
}
118118

119-
& .phishing .icon, & .malware .icon {
119+
& .phishing .icon, & .malware .icon, & .scam .icon {
120120
background-image: url(../../../../shared/assets/img/icons/Malware-Site-128.svg);
121121
}
122122

@@ -166,7 +166,7 @@
166166
margin-top: calc(-1 * var(--sp-2));
167167
}
168168

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

special-pages/pages/special-error/app/hooks/ErrorStrings.jsx

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ const reportSiteAnchorTagParams = (urlParam) => {
4949
* @typedef {import("../../types/special-error.js").SSLInvalidCertificate} SSLInvalidCertificate
5050
* @typedef {import("../../types/special-error.js").SSLSelfSignedCertificate} SSLSelfSignedCertificate
5151
* @typedef {import("../../types/special-error.js").SSLWrongHost} SSLWrongHost
52-
* @typedef {import("../../types/special-error.js").PhishingAndMalware} PhishingAndMalware
52+
* @typedef {import("../../types/special-error.js").MaliciousSite} MaliciousSite
5353
* @typedef {SSLExpiredCertificate|SSLInvalidCertificate|SSLSelfSignedCertificate|SSLWrongHost} SSLError
5454
*/
5555

@@ -60,16 +60,15 @@ export function useWarningHeading() {
6060
const { t } = useTypedTranslation();
6161
const { kind } = useErrorData();
6262

63-
if (kind === 'phishing') {
64-
return t('phishingPageHeading').replace('{newline}', '\n');
65-
}
66-
67-
if (kind === 'malware') {
68-
return t('malwarePageHeading').replace('{newline}', '\n');
69-
}
70-
71-
if (kind === 'ssl') {
72-
return t('sslPageHeading');
63+
switch(kind) {
64+
case 'ssl':
65+
return t('sslPageHeading');
66+
case 'malware':
67+
case 'phishing':
68+
case 'scam':
69+
const translationKey = /** @type {"malwarePageHeading"|"phishingPageHeading"|"scamPageHeading"} */(`${kind}PageHeading`);
70+
return t(translationKey).replace('{newline}', '\n');
71+
default:
7372
}
7473

7574
throw new Error(`Unhandled error kind ${kind}`);
@@ -93,6 +92,11 @@ export function useWarningContent() {
9392
return [<Trans str={text} values={{ a: helpPageAnchorTagParams }} />];
9493
}
9594

95+
if (kind === 'scam') {
96+
const text = t('scamWarningText').replace('{newline}', '\n');
97+
return [<Trans str={text} values={{ a: helpPageAnchorTagParams }} />];
98+
}
99+
96100
if (kind === 'ssl') {
97101
const { domain } = /** @type {SSLError}} */ (errorData);
98102
return [<Trans str={t('sslWarningText', { domain })} values="" />];
@@ -109,16 +113,17 @@ export function useAdvancedInfoHeading() {
109113
const errorData = useErrorData();
110114
const { kind } = errorData;
111115

112-
if (kind === 'phishing' || kind === 'malware') {
113-
const { url } = /** @type {PhishingAndMalware} */ (errorData);
114-
const anchorTagParams = reportSiteAnchorTagParams(url);
115-
const translatioKey = kind === 'phishing' ? 'phishingAdvancedInfoHeading' : 'malwareAdvancedInfoHeading';
116-
117-
return <Trans str={t(translatioKey)} values={{ a: anchorTagParams }} />;
118-
}
119-
120-
if (kind === 'ssl') {
121-
return t('sslAdvancedInfoHeading');
116+
switch(kind) {
117+
case 'ssl':
118+
return t('sslAdvancedInfoHeading');
119+
case 'malware':
120+
case 'phishing':
121+
case 'scam':
122+
const { url } = /** @type {MaliciousSite} */ (errorData);
123+
const anchorTagParams = reportSiteAnchorTagParams(url);
124+
const translationKey = /** @type {"malwareAdvancedInfoHeading"|"phishingAdvancedInfoHeading"|"scamAdvancedInfoHeading"} */(`${kind}AdvancedInfoHeading`);
125+
return <Trans str={t(translationKey)} values={{ a: anchorTagParams }} />;
126+
default:
122127
}
123128

124129
throw new Error(`Unhandled error kind ${kind}`);
@@ -132,7 +137,7 @@ export function useAdvancedInfoContent() {
132137
const errorData = useErrorData();
133138
const { kind } = errorData;
134139

135-
if (kind === 'phishing' || kind === 'malware') {
140+
if (kind === 'malware' || kind === 'phishing' || kind === 'scam') {
136141
return [];
137142
}
138143

special-pages/pages/special-error/integration-tests/special-error-screenshots.spec.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,11 @@ test.describe('screenshots @screenshots', () => {
3333
await special.openPage({ errorId: 'malware', locale: 'ru' });
3434
await expect(page).toHaveScreenshot('malware-warning-ru.png', { maxDiffPixels });
3535
});
36+
37+
test('Scam warning with advanced info', async ({ page }, workerInfo) => {
38+
const special = SpecialErrorPage.create(page, workerInfo);
39+
await special.openPage({ errorId: 'scam' });
40+
await special.showsAdvancedInfo();
41+
await expect(page).toHaveScreenshot('scam-warning-advanced.png', { maxDiffPixels });
42+
});
3643
});

special-pages/pages/special-error/integration-tests/special-error.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,27 @@ export class SpecialErrorPage {
295295
).toBeVisible();
296296
}
297297

298+
async showsScamPage() {
299+
const { page } = this;
300+
301+
await this.showsPageTitle('Warning: Security Risk');
302+
303+
await expect(page.getByText('Warning: This site may be a security risk', { exact: true })).toBeVisible();
304+
await expect(
305+
page.getByText(
306+
'DuckDuckGo blocked this page because it may be trying to deceive or manipulate you into transferring money, buying counterfeit goods, or installing malware under false pretenses. Learn more',
307+
{ exact: true },
308+
),
309+
).toBeVisible();
310+
await this.showsAdvancedInfo();
311+
await expect(
312+
page.getByText(
313+
'If you believe this website is safe, you can report an error. You can still visit the website at your own risk.',
314+
{ exact: true },
315+
),
316+
).toBeVisible();
317+
}
318+
298319
/**
299320
* Clicks on advanced link to show expanded info
300321
*

special-pages/pages/special-error/integration-tests/special-error.spec.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,12 @@ test.describe('special-error', () => {
6060
await special.showsMalwarePage();
6161
});
6262

63+
test('shows scam warning', async ({ page }, workerInfo) => {
64+
const special = SpecialErrorPage.create(page, workerInfo);
65+
await special.openPage({ errorId: 'scam' });
66+
await special.showsScamPage();
67+
});
68+
6369
test('leaves site', async ({ page }, workerInfo) => {
6470
const special = SpecialErrorPage.create(page, workerInfo);
6571
await special.openPage({ errorId: 'ssl.expired' });
@@ -92,6 +98,16 @@ test.describe('special-error', () => {
9298
await special.opensNewPage('Learn more', expectedURL);
9399
});
94100

101+
test('opens scam help page in a new window', async ({ page }, workerInfo) => {
102+
const special = SpecialErrorPage.create(page, workerInfo);
103+
await special.overrideTestLinks();
104+
105+
const expectedURL = `${phishingMalwareHelpPageURL}`;
106+
107+
await special.openPage({ errorId: 'scam' });
108+
await special.opensNewPage('Learn more', expectedURL);
109+
});
110+
95111
test('opens report form in a new window', async ({ page, browser }, workerInfo) => {
96112
const special = SpecialErrorPage.create(page, workerInfo);
97113
await special.overrideTestLinks();

special-pages/pages/special-error/messages/initialSetup.response.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,12 @@
2525
"oneOf": [
2626
{
2727
"type": "object",
28-
"title": "Phishing and Malware",
28+
"title": "Malicious Site",
2929
"required": ["kind", "url"],
3030
"properties": {
3131
"kind": {
3232
"type": "string",
33-
"enum": ["phishing", "malware"]
33+
"enum": ["phishing", "malware", "scam"]
3434
},
3535
"url": {
3636
"type": "string"

special-pages/pages/special-error/public/locales/en/special-error.json

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,14 @@
2525
"title": "Accept Risk and Visit Site",
2626
"note": "Button shown in an error page that warns users of security risks on a website due to Phishing or Malware issues. The buttons allows the user to visit the website anyway despite the risks."
2727
},
28+
"maliciousSiteTabTitle": {
29+
"title": "Warning: Security Risk",
30+
"note": "Title shown in the browser window or tab when the current page may be a security risk due to phishing"
31+
},
2832
"malwarePageHeading": {
2933
"title": "Warning: This site may be a{newline}security risk",
3034
"note": "Title shown in an error page that warn users of security risks on a website due to malware distribution. The {newline} tag should not be translated. It should be placed within the sentence to avoid having a single word hanging on the last line"
3135
},
32-
"malwareTabTitle": {
33-
"title": "Warning: Security Risk",
34-
"note": "Title shown in the browser window or tab when the current page may be a security risk due to malware"
35-
},
3636
"malwareWarningText": {
3737
"title": "DuckDuckGo blocked this page because it may be distributing malware designed to compromise your device or steal your personal information.{newline}<a>Learn more</a>",
3838
"note": "Error description shown in an error page that warns users of security risks on a website due to malware distribution. The {newline} tag should not be translated. It should be placed before the translated <a>Learn More</a> text."
@@ -45,10 +45,6 @@
4545
"title": "Warning: This site may be a{newline}security risk",
4646
"note": "Title shown in an error page that warn users of security risks on a website due to Phishing issues. The {newline} tag should not be translated. It should be placed within the sentence to avoid having a single word hanging on the last line"
4747
},
48-
"phishingTabTitle": {
49-
"title": "Warning: Security Risk",
50-
"note": "Title shown in the browser window or tab when the current page may be a security risk due to phishing"
51-
},
5248
"phishingWarningText": {
5349
"title": "This website may be impersonating a legitimate site in order to trick you into providing personal information, such as passwords or credit card numbers.{newline}<a>Learn more</a>",
5450
"note": "Error description shown in an error page that warns users of security risks on a website due to Phishing issues. The {newline} tag should not be translated. It should be placed before the translated <a>Learn More</a> text."
@@ -57,6 +53,18 @@
5753
"title": "If you believe this website is safe, you can <a>report an error</a>. You can still visit the website at your own risk.",
5854
"note": "Title of the Advanced info section shown in an error page that warns users of security risks on a website due to malware distribution."
5955
},
56+
"scamPageHeading": {
57+
"title": "Warning: This site may be a{newline}security risk",
58+
"note": "Title shown in an error page that warn users of security risks on a website due to suspected scam attempts. The {newline} tag should not be translated. It should be placed within the sentence to avoid having a single word hanging on the last line"
59+
},
60+
"scamWarningText": {
61+
"title": "DuckDuckGo blocked this page because it may be trying to deceive or manipulate you into transferring money, buying counterfeit goods, or installing malware under false pretenses.{newline}<a>Learn more</a>",
62+
"note": "Error description shown in an error page that warns users of security risks on a website due to suspected scam attempts. The {newline} tag should not be translated. It should be placed before the translated <a>Learn More</a> text."
63+
},
64+
"scamAdvancedInfoHeading": {
65+
"title": "If you believe this website is safe, you can <a>report an error</a>. You can still visit the website at your own risk.",
66+
"note": "Title of the Advanced info section shown in an error page that warns users of security risks on a website due to suspected scam attempts."
67+
},
6068
"sslPageHeading": {
6169
"title": "Warning: This site may be insecure",
6270
"note": "Title shown in an error page that warn users of security risks on a website due to SSL issues"

special-pages/pages/special-error/src/sampleData.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@ export const sampleData = {
1414
url: 'https://privacy-test-pages.site/security/badware/malware.html?query=param&some=other',
1515
},
1616
},
17+
scam: {
18+
name: 'Scam',
19+
data: {
20+
kind: 'scam',
21+
url: 'https://privacy-test-pages.site/security/badware/malware.html?query=param&some=other',
22+
}, // TODO: Update with actual test page
23+
},
1724
'ssl.expired': {
1825
name: 'Expired',
1926
data: {

special-pages/pages/special-error/types/special-error.ts

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -69,19 +69,14 @@ export interface InitialSetupResponse {
6969
platform: {
7070
name: "macos" | "windows" | "android" | "ios";
7171
};
72-
errorData:
73-
| PhishingAndMalware
74-
| SSLExpiredCertificate
75-
| SSLInvalidCertificate
76-
| SSLSelfSignedCertificate
77-
| SSLWrongHost;
72+
errorData: MaliciousSite | SSLExpiredCertificate | SSLInvalidCertificate | SSLSelfSignedCertificate | SSLWrongHost;
7873
/**
7974
* Optional locale-specific strings
8075
*/
8176
localeStrings?: string;
8277
}
83-
export interface PhishingAndMalware {
84-
kind: "phishing" | "malware";
78+
export interface MaliciousSite {
79+
kind: "phishing" | "malware" | "scam";
8580
url: string;
8681
}
8782
export interface SSLExpiredCertificate {

0 commit comments

Comments
 (0)