diff --git a/shared/js/background/broken-site-report.js b/shared/js/background/broken-site-report.js index 3e4e3f524..69532f952 100644 --- a/shared/js/background/broken-site-report.js +++ b/shared/js/background/broken-site-report.js @@ -5,6 +5,9 @@ * tooling for those anonymous broken site reports. * * Learn more at: https://duckduckgo.com/duckduckgo-help-pages/privacy/web-tracking-protections/#remotely-configured-exceptions + * + * @typedef {import('@duckduckgo/privacy-dashboard/schema/__generated__/schema.types').ToggleReportScreen} DisclosureDetails + * @typedef {import('@duckduckgo/privacy-dashboard/schema/__generated__/schema.types').DataItemId} DisclosureParamId */ const browser = require('webextension-polyfill'); @@ -12,12 +15,49 @@ const load = require('./load'); const browserWrapper = require('./wrapper'); const settings = require('./settings'); const parseUserAgentString = require('../shared-utils/parse-user-agent-string'); -const { getURLWithoutQueryString } = require('./utils'); +const { getCurrentTab, getURLWithoutQueryString } = require('./utils'); const { getURL } = require('./pixels'); const tdsStorage = require('./storage/tds').default; const tabManager = require('./tab-manager'); const maxPixelLength = 7000; +/** + * When the user clicks to see what a breakage report will include, the details + * displayed are based on these param IDs. + * + * Notes: + * - The naming system is similar, but not quite the same as the breakage + * report parameter names themselves. See the docs[1] for a list of all the + * possible values. + * - Take care to update this list as the privacy-dashboard dependency is + * updated, and when breakage parameters are added/removed. + * - The UI displays the parameters in the order the IDs are listed here, so + * consider the ordering when adjusting the array. + * + * TODO: In the future, it would be better for the UI to accept all of the + * actual parameter names instead. Needing to update the list here + * manually seems error-prone. Likewise with the ordering, it would be + * better for the UI to decide the display order for the parameters, + * to ensure they are displayed consistently between platforms. + * + * 1 - https://duckduckgo.github.io/privacy-dashboard/documents/Guides.Toggle_Report.html#md:appendix-data-disclosure-item-ids-and-their-meanings + * + * @type {DisclosureParamId[]} + */ +const PARAM_IDS = [ + 'siteUrl', + 'atb', + 'errorDescriptions', + 'extensionVersion', + 'features', + 'httpErrorCodes', + 'jsPerformance', + 'locale', + 'openerContext', + 'requests', + 'userRefreshCount', +]; + /** * * Fire a pixel @@ -225,9 +265,8 @@ export async function breakageReportForTab({ const jsPerformance = pageParams.jsPerformance ? pageParams.jsPerformance : undefined; const locale = tab.locale; - // Note: Take care to update the `ToggleReports.PARAM_IDS` array (see - // './components/toggle-reports.js') when adding/removing breakage - // parameters! + // Note: Take care to update the `PARAM_IDS` array (see above) when + // adding/removing breakage parameters! const brokenSiteParams = new URLSearchParams({ siteUrl, tds, @@ -306,3 +345,30 @@ export async function sendBreakageReportForCurrentTab({ pixelName, currentTab, c reportFlow, }); } + +/** + * Returns the breakage report details as expected by the + * "getBreakageFormOptions" and "getToggleReportOptions" messages. + * + * @returns {Promise} + */ +export async function getDisclosureDetails() { + let siteUrl = null; + const currentTabUrl = (await getCurrentTab())?.url; + if (currentTabUrl) { + siteUrl = getURLWithoutQueryString(currentTabUrl); + } + + /** @type {DisclosureDetails} */ + const response = { data: [] }; + + for (const paramId of PARAM_IDS) { + if (paramId === 'siteUrl' && siteUrl) { + response.data.push({ id: 'siteUrl', additional: { url: siteUrl } }); + } else { + response.data.push({ id: paramId }); + } + } + + return response; +} diff --git a/shared/js/background/components/toggle-reports.js b/shared/js/background/components/toggle-reports.js index b6fe7b2fd..4586517ff 100644 --- a/shared/js/background/components/toggle-reports.js +++ b/shared/js/background/components/toggle-reports.js @@ -1,14 +1,9 @@ -/** - * @typedef {import('@duckduckgo/privacy-dashboard/schema/__generated__/schema.types').ToggleReportScreen} ToggleReportOptions - * @typedef {import('@duckduckgo/privacy-dashboard/schema/__generated__/schema.types').DataItemId} ToggleReportParamId - */ - import browser from 'webextension-polyfill'; import { registerMessageHandler } from '../message-handlers'; import { postPopupMessage } from '../popupMessaging'; import settings from '../settings'; -import { getCurrentTab, getFeatureSettings, getURLWithoutQueryString, reloadCurrentTab, resolveAfterDelay } from '../utils'; -import { sendBreakageReportForCurrentTab } from '../broken-site-report'; +import { getFeatureSettings, reloadCurrentTab, resolveAfterDelay } from '../utils'; +import { getDisclosureDetails, sendBreakageReportForCurrentTab } from '../broken-site-report'; import { createAlarm } from '../wrapper'; import tabManager from '../tab-manager'; @@ -28,43 +23,6 @@ import tabManager from '../tab-manager'; export default class ToggleReports { static ALARM_NAME = 'toggleReportsClearExpired'; - /** - * When prompting the user to submit a breakage report, context is shown to - * explain what will be included in the report. This is to help the user - * make an informed decision. That context is based on this list of - * parameter IDs. The naming system is similar, but not quite the same as - * the breakage report parameter names themselves. See the docs[1] for a - * list of all the possible values. Take care to update this list as the - * privacy-dashboard dependency is updated, and when breakage parameters are - * added/removed (see '../broken-site-report.js'). - * - * Note: The UI displays the parameters in the order the IDs are listed - * here, so consider the ordering when adjusting the array. - * - * TODO: In the future, it would be better for the UI to accept all of the - * actual parameter names instead. Needing to update the list here - * manually seems error-prone. Likewise with the ordering, it would be - * better for the UI to decide the display order for the parameters, - * to ensure they are displayed consistently between platforms. - * - * 1 - https://duckduckgo.github.io/privacy-dashboard/modules/Toggle_Report.html - * - * @type {ToggleReportParamId[]} - */ - static PARAM_IDS = [ - 'siteUrl', - 'atb', - 'errorDescriptions', - 'extensionVersion', - 'features', - 'httpErrorCodes', - 'jsPerformance', - 'locale', - 'openerContext', - 'requests', - 'userRefreshCount', - ]; - constructor() { this.onDisconnect = this.toggleReportFinished.bind(this, false); @@ -90,7 +48,7 @@ export default class ToggleReports { * UI flow begins. * * @param {browser.Runtime.Port} sender - * @returns {Promise} + * @returns {Promise} */ async toggleReportStarted(sender) { // If the browser closes the popup UI during the "toggle reports" flow @@ -98,24 +56,7 @@ export default class ToggleReports { // this event will fire. sender?.onDisconnect?.addListener(this.onDisconnect); - let siteUrl = null; - const currentTabUrl = (await getCurrentTab())?.url; - if (currentTabUrl) { - siteUrl = getURLWithoutQueryString(currentTabUrl); - } - - /** @type {ToggleReportOptions} */ - const response = { data: [] }; - - for (const paramId of ToggleReports.PARAM_IDS) { - if (paramId === 'siteUrl' && siteUrl) { - response.data.push({ id: 'siteUrl', additional: { url: siteUrl } }); - } else { - response.data.push({ id: paramId }); - } - } - - return response; + return getDisclosureDetails(); } /** diff --git a/shared/js/background/message-handlers.js b/shared/js/background/message-handlers.js index 8dee923ea..25accfbbe 100644 --- a/shared/js/background/message-handlers.js +++ b/shared/js/background/message-handlers.js @@ -1,6 +1,6 @@ import browser from 'webextension-polyfill'; import { dashboardDataFromTab } from './classes/privacy-dashboard-data'; -import { sendBreakageReportForCurrentTab } from './broken-site-report'; +import { getDisclosureDetails, sendBreakageReportForCurrentTab } from './broken-site-report'; import parseUserAgentString from '../shared-utils/parse-user-agent-string'; import { getExtensionURL } from './wrapper'; import { isFeatureEnabled, reloadCurrentTab } from './utils'; @@ -345,6 +345,7 @@ const messageHandlers = { getBrowser, openOptions, submitBrokenSiteReport, + getBreakageFormOptions: getDisclosureDetails, getPrivacyDashboardData, getTopBlockedByPages, getClickToLoadState, diff --git a/unit-test/background/broken-site-report.js b/unit-test/background/broken-site-report.js new file mode 100644 index 000000000..800617591 --- /dev/null +++ b/unit-test/background/broken-site-report.js @@ -0,0 +1,59 @@ +import browser from 'webextension-polyfill'; +import { getDisclosureDetails } from '../../shared/js/background/broken-site-report'; + +describe('broke-site-report', () => { + let currentTabDetails = null; + + beforeAll(async () => { + // Stub the necessary browser.tabs.* APIs. + spyOn(browser.tabs, 'query').and.callFake(() => { + const result = []; + + if (currentTabDetails) { + result.push(currentTabDetails); + } + + return Promise.resolve(result); + }); + }); + + beforeEach(() => { + currentTabDetails = null; + }); + + it('getDisclosureDetails()', async () => { + expect(await getDisclosureDetails()).toEqual({ + data: [ + { id: 'siteUrl' }, + { id: 'atb' }, + { id: 'errorDescriptions' }, + { id: 'extensionVersion' }, + { id: 'features' }, + { id: 'httpErrorCodes' }, + { id: 'jsPerformance' }, + { id: 'locale' }, + { id: 'openerContext' }, + { id: 'requests' }, + { id: 'userRefreshCount' }, + ], + }); + + currentTabDetails = { url: 'https://domain.example/path?param=value' }; + + expect(await getDisclosureDetails()).toEqual({ + data: [ + { id: 'siteUrl', additional: { url: 'https://domain.example/path' } }, + { id: 'atb' }, + { id: 'errorDescriptions' }, + { id: 'extensionVersion' }, + { id: 'features' }, + { id: 'httpErrorCodes' }, + { id: 'jsPerformance' }, + { id: 'locale' }, + { id: 'openerContext' }, + { id: 'requests' }, + { id: 'userRefreshCount' }, + ], + }); + }); +});