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

Add getBreakageFormOptions message handler #2866

Merged
merged 1 commit into from
Dec 19, 2024
Merged
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
74 changes: 70 additions & 4 deletions shared/js/background/broken-site-report.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,59 @@
* 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');
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
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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<DisclosureDetails>}
*/
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;
}
67 changes: 4 additions & 63 deletions shared/js/background/components/toggle-reports.js
Original file line number Diff line number Diff line change
@@ -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';

Expand All @@ -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);

Expand All @@ -90,32 +48,15 @@ export default class ToggleReports {
* UI flow begins.
*
* @param {browser.Runtime.Port} sender
* @returns {Promise<ToggleReportOptions>}
* @returns {Promise<import('../broken-site-report').DisclosureDetails>}
*/
async toggleReportStarted(sender) {
// If the browser closes the popup UI during the "toggle reports" flow
// (e.g. because the user clicked away), the connection will drop and
// 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();
}

/**
Expand Down
3 changes: 2 additions & 1 deletion shared/js/background/message-handlers.js
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -345,6 +345,7 @@ const messageHandlers = {
getBrowser,
openOptions,
submitBrokenSiteReport,
getBreakageFormOptions: getDisclosureDetails,
kzar marked this conversation as resolved.
Show resolved Hide resolved
getPrivacyDashboardData,
getTopBlockedByPages,
getClickToLoadState,
Expand Down
59 changes: 59 additions & 0 deletions unit-test/background/broken-site-report.js
Original file line number Diff line number Diff line change
@@ -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' },
],
});
});
});
Loading