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

Phishing error page #972

Closed
wants to merge 24 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/special-pages/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export const support = {
'apple': ['copy', 'inline-html'],
},
/** @type {Partial<Record<ImportMeta['injectName'], string[]>>} */
sslerrorpage: {
specialerrorpage: {
'integration': ['copy', 'build-js'],
'apple': ['copy', 'build-js', 'inline-html'],
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
/**
* @module SSLError Page
* @module SpecialError Page
* @category Special Pages
*
* @description
*
* [[include:packages/special-pages/pages/sslerrorpage/readme.md]]
* [[include:packages/special-pages/pages/specialerrorpage/readme.md]]
*/

import { execTemplate } from './template.js'
import { defaultLoadData } from './defaults.js'
import { loadData } from './loadData.js'
import { createTypedMessages } from '@duckduckgo/messaging'
import { createSpecialPageMessaging } from '../../../../shared/create-special-page-messaging'

export class SslerrorpagePage {
export class SpecialerrorpagePage {
/**
* @param {import("@duckduckgo/messaging").Messaging} messaging
*/
Expand All @@ -35,10 +35,10 @@ export class SslerrorpagePage {
const messaging = createSpecialPageMessaging({
env: import.meta.env,
injectName: import.meta.injectName,
pageName: 'sslErrorPage'
pageName: 'specialErrorPage'
})

const page = new SslerrorpagePage(messaging)
const page = new SpecialerrorpagePage(messaging)
window.addEventListener('DOMContentLoaded', () => {
loadHTML()
bindEvents(page)
Expand All @@ -61,7 +61,7 @@ function loadHTML () {
if (!parsed.strings) {
console.warn('missing `strings` from the incoming json data')
}
const mergedStrings = { ...defaultLoadData.strings, ...parsed.strings }
const mergedStrings = { ...loadData.ssl.strings, ...parsed.strings }
container.innerHTML = execTemplate(mergedStrings).toString()
document.body.appendChild(container)
}
Expand All @@ -84,7 +84,7 @@ function domElements () {
}

/**
* @param {SslerrorpagePage} page
* @param {SpecialerrorpagePage} page
*/
function bindEvents (page) {
const dom = domElements()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
export const loadData = {
ssl: {
strings: {
header: 'Warning: This site may be insecure',
body: 'The certificate for this site is invalid. You might be connecting to a server that is pretending to be <b>example.com</b> which could put your confidential information at risk',
advancedInfoHeader: 'DuckDuckGo warns you when a website has an invalid certificate.',
advancedButton: 'Advanced...',
leaveSiteButton: 'Leave This Site',
specificMessage: 'The security certificate for <b>bad.example.com</b> is not trusted by your computer\'s operating system',
advancedInfoBody: 'It’s possible that the website is misconfigured or that an attacker has compromised your connection.',
visitSiteBody: 'Accept Risk and Visit Site'
}
},
phishing: {
strings: {
header: 'Warning: This site puts your personal information at risk',
body: 'This website may be impersonating a legitimate site in order to trick you into providing personal information, such as passwords or credit card numbers. <a href="https://duckduckgo.com/duckduckgo-help-pages/" target="_blank">Learn more</a>',
advancedInfoHeader: 'DuckDuckGo warns you when a website has been flagged as malicious.',
advancedButton: 'Advanced...',
leaveSiteButton: 'Leave This Site',
specificMessage: '',
advancedInfoBody: 'Warnings are shown for websites that have been reported to be deceptive. Deceptive websites try to trick you into believing they are legitimate websites you trust. If you understand the risks involved, you can continue anyway.<br><br>See our <a href="https://duckduckgo.com/duckduckgo-help-pages/" target="_blank">Phishing and Malware Protection help page</a> for more information.',
visitSiteBody: 'Accept Risk and Visit Site'
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export function execTemplate (strings) {
</div>
<div class="advanced-info closed">
<p>${strings.advancedInfoHeader}</p>
<p>${trustedUnsafeEscaped(strings.specificMessage)} ${strings.advancedInfoBody}</p>
<p>${trustedUnsafeEscaped(strings.specificMessage)} ${trustedUnsafeEscaped(strings.advancedInfoBody)}</p>
<button id="acceptRiskLink" class="accept-risk">${strings.visitSiteBody}</button>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,37 +1,40 @@
:root {
/* Light theme colors */
--background-color: #eee;
--background-color: #eee;
--text-color: rgba(0, 0, 0, 0.84);
--border-color: rgba(0, 0, 0, 0.10);
--warning-container-bg: #FFF;
--link-color: #000;
--border-color: rgba(0, 0, 0, 0.1);
--warning-container-bg: #fff;
--advanced-info-bg: rgba(0, 0, 0, 0.03);
--button-bg: #FFF;
--button-active-bg:#e0e0e0;
--button-text: #000000;
--leave-site-btn-bg: linear-gradient(180deg, #4266D8 0%, #224CD2 100%);
--button-bg: #fff;
--button-active-bg: #e0e0e0;
--button-text: #000;
--leave-site-btn-bg: linear-gradient(180deg, #4266d8 0%, #224cd2 100%);
--leave-site-btn-border-color: rgba(40, 145, 255, 0.05);
--leave-site-btn-shadow-color: rgba(40, 145, 255, 0.10);
--accept-risk-color: black;
--leave-site-btn-shadow-color: rgba(40, 145, 255, 0.1);
--accept-risk-color: #000;

/* Dark theme colors */
--background-color-dark: #333333;
--text-color-dark: #FFFFFFD6;
--background-color-dark: #333;
--text-color-dark: rgba(255, 255, 255, 0.84);
--link-color-dark: #ccc;
--border-color-dark: rgba(255, 255, 255, 0.3);
--warning-container-bg-dark: #222222;
--advanced-info-bg-dark: #2F2F2F;
--button-bg-dark: #333333;
--button-active-bg-dark:#757575;
--button-text-dark: #FFFFFF;
--leave-site-btn-bg-dark: linear-gradient(180deg, #4266D8 0%, #224CD2 100%);
--advanced-info-bg-dark: #2f2f2f;
--button-bg-dark: #333;
--button-active-bg-dark: #757575;
--button-text-dark: #fff;
--leave-site-btn-bg-dark: linear-gradient(180deg, #4266d8 0%, #224cd2 100%);
--leave-site-btn-border-color-dark: rgba(40, 145, 255, 0.2);
--leave-site-btn-shadow-color-dark: rgba(40, 145, 255, 0.3);
--accept-risk-color-dark: #CCCCCC;
--accept-risk-color-dark: #ccc;

--max-height-for-query: 320px;
}

/* Base styles */
html, body {
html,
body {
height: 100%;
margin: 0;
background-color: var(--background-color);
Expand Down Expand Up @@ -65,14 +68,14 @@ body {
.full-container {
@media (max-height: 320px) {
top: 40px;
transform: translateX(-50%)
transform: translateX(-50%);
}
}

.full-container[data-state=open] {
.full-container[data-state="open"] {
@media (max-height: 460px) {
top: 40px;
transform: translateX(-50%)
transform: translateX(-50%);
}
}

Expand Down Expand Up @@ -122,7 +125,7 @@ body {
opacity: 1;
}

[data-state=closed] .advanced-info {
[data-state="closed"] .advanced-info {
opacity: 0;
height: 0;
padding-block: 0;
Expand Down Expand Up @@ -154,10 +157,11 @@ body {
border: 0.5px solid var(--border-color);
background: var(--button-bg);
color: var(--button-text);
box-shadow: 0px 1px 1px 0px var(--border-color), 0px 0px 1px 0px var(--border-color);
box-shadow: 0px 1px 1px 0px var(--border-color),
0px 0px 1px 0px var(--border-color);
}

[data-state=open] .button.advanced {
[data-state="open"] .button.advanced {
display: none;
}

Expand All @@ -169,7 +173,8 @@ body {
color: white;
border: 0.5px solid var(--leave-site-btn-border-color);
background: var(--leave-site-btn-bg);
box-shadow: 0px 1px 1px 0px var(--leave-site-btn-shadow-color), 0px 0px 1px 0px var(--leave-site-btn-border-color);
box-shadow: 0px 1px 1px 0px var(--leave-site-btn-shadow-color),
0px 0px 1px 0px var(--leave-site-btn-border-color);
}

.leave-this-site:active {
Expand All @@ -185,15 +190,21 @@ body {
padding: 0;
}

.advanced-info a,
.warning-text a {
color: var(--link-color);
}

@media (prefers-color-scheme: dark) {
:root {
--background-color: var(--background-color-dark);
--text-color: var(--text-color-dark);
--link-color: var(--link-color-dark);
--border-color: var(--border-color-dark);
--warning-container-bg: var(--warning-container-bg-dark);
--advanced-info-bg: var(--advanced-info-bg-dark);
--button-bg: var(--button-bg-dark);
--button-active-bg:var(--button-active-bg-dark);
--button-active-bg: var(--button-active-bg-dark);
--button-text: var(--button-text-dark);
--leave-site-btn-bg: var(--leave-site-btn-bg-dark);
--leave-site-btn-border-color: var(--leave-site-btn-border-color-dark);
Expand Down
12 changes: 0 additions & 12 deletions packages/special-pages/pages/sslerrorpage/src/js/defaults.js

This file was deleted.

1 change: 1 addition & 0 deletions packages/special-pages/playwright.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export default defineConfig({
testMatch: [
'duckplayer.spec.js',
'onboarding.spec.js',
'specialerror.spec.js',
'sslerror.spec.js',
'release-notes.spec.js'
],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import { Mocks } from './mocks.js'
import { expect } from '@playwright/test'
import { perPlatform } from '../../../../integration-test/playwright/type-helpers.mjs'
import { join } from 'node:path'
import { readFileSync } from 'node:fs'
import { defaultLoadData } from '../../pages/sslerrorpage/src/js/defaults'
import { loadData } from '../../pages/specialerrorpage/src/js/loadData'

/**
* @typedef {import('../../../../integration-test/playwright/type-helpers.mjs').Build} Build
* @typedef {import('../../../../integration-test/playwright/type-helpers.mjs').PlatformInfo} PlatformInfo
*/

export class SSLErrorPage {
export class SpecialErrorPage {
/**
* @param {import("@playwright/test").Page} page
* @param {Build} build
Expand All @@ -30,8 +31,9 @@ export class SSLErrorPage {
/**
* Opens a page with optional parameters.
* This method ensures that mocks are installed and routes are set up before navigating to the page.
* @param {'ssl'|'phishing'} [errorType]
*/
async openPage () {
async openPage (errorType = 'ssl') {
await this.mocks.install()
await this.page.route('/**', (route, req) => {
const url = new URL(req.url())
Expand All @@ -40,7 +42,7 @@ export class SSLErrorPage {
if (filepath === '/') {
filepath = 'index.html'
const html = readFileSync(join(this.basePath, filepath), 'utf8')
const next = html.replace('$LOAD_TIME_DATA$', JSON.stringify(defaultLoadData))
const next = html.replace('$LOAD_TIME_DATA$', JSON.stringify(loadData[errorType])) // Strings File
return route.fulfill({
body: next,
status: 200,
Expand All @@ -62,7 +64,7 @@ export class SSLErrorPage {
*/
get basePath () {
return this.build.switch({
apple: () => '../../Sources/ContentScopeScripts/dist/pages/sslerrorpage'
apple: () => '../../Sources/ContentScopeScripts/dist/pages/specialerrorpage'
})
}

Expand All @@ -73,7 +75,7 @@ export class SSLErrorPage {
static create (page, testInfo) {
// Read the configuration object to determine which platform we're testing against
const { platformInfo, build } = perPlatform(testInfo.project.use)
return new SSLErrorPage(page, build, platformInfo)
return new SpecialErrorPage(page, build, platformInfo)
}

async darkMode () {
Expand All @@ -88,8 +90,34 @@ export class SSLErrorPage {
async visitsSite () {
const { page } = this
await page.pause()
await page.getByRole('button', { name: 'Advanced...' }).click()
this.showsAdvancedInfo()
await page.getByRole('button', { name: 'Accept Risk and Visit Site' }).click()
await this.mocks.waitForCallCount({ method: 'visitSite', count: 1 })
}

/**
* Clicks on advanced link to show expanded info
*/
async showsAdvancedInfo () {
const { page } = this
await page.getByRole('button', { name: 'Advanced...' }).click()
}

/**
* Clicks on link and expects it to open a URL in a new window
*
* @param {string} linkName
* @param {string} newPageURL
*/
async opensNewPage (linkName, newPageURL) {
const { page } = this
const newPagePromise = page.waitForEvent('popup')

await page.pause()
await expect(page.getByRole('link', { name: linkName })).toBeVisible()
await page.getByRole('link', { name: linkName }).click()

const newPage = await newPagePromise
await expect(newPage).toHaveURL(newPageURL)
}
}
22 changes: 22 additions & 0 deletions packages/special-pages/tests/specialerror.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { test } from '@playwright/test'
import { SpecialErrorPage } from './page-objects/specialerror'

test.describe('specialerror', () => {
test('leaves site', async ({ page }, workerInfo) => {
const special = SpecialErrorPage.create(page, workerInfo)
await special.openPage('ssl')
await special.leavesSite()
})
test('visits site', async ({ page }, workerInfo) => {
const special = SpecialErrorPage.create(page, workerInfo)
await special.openPage('ssl')
await special.visitsSite()
})
test('opens phishing help page in a new window', async ({ page }, workerInfo) => {
const special = SpecialErrorPage.create(page, workerInfo)
await special.openPage('phishing')
await special.opensNewPage('Learn more', 'https://duckduckgo.com/duckduckgo-help-pages/')
await special.showsAdvancedInfo()
await special.opensNewPage('Phishing and Malware Protection help page', 'https://duckduckgo.com/duckduckgo-help-pages/')
})
})
15 changes: 0 additions & 15 deletions packages/special-pages/tests/sslerror.spec.js

This file was deleted.

Loading
Loading