diff --git a/developer-extension/manifest.json b/developer-extension/manifest.json index 7e245d2ce1..2f03196371 100644 --- a/developer-extension/manifest.json +++ b/developer-extension/manifest.json @@ -1,13 +1,14 @@ { - "manifest_version": 2, + "manifest_version": 3, "name": "Datadog Browser SDK developer extension", - "permissions": ["", "webRequest", "webRequestBlocking", "storage", "browsingData"], + "permissions": ["webRequest", "storage", "browsingData", "declarativeNetRequest"], + "host_permissions": [""], "icons": { "256": "icon.png" }, "background": { - "scripts": ["background.js"], - "persistent": true + "service_worker": "background.js", + "type": "module" }, "devtools_page": "devtools.html" } diff --git a/developer-extension/src/background/constants.ts b/developer-extension/src/background/constants.ts index 35cdb36eb7..0b5af3c20a 100644 --- a/developer-extension/src/background/constants.ts +++ b/developer-extension/src/background/constants.ts @@ -1,3 +1,16 @@ export const DEV_LOGS_URL = 'http://localhost:8080/datadog-logs.js' export const DEV_RUM_URL = 'http://localhost:8080/datadog-rum.js' export const DEV_RUM_SLIM_URL = 'http://localhost:8080/datadog-rum-slim.js' + +export const INTAKE_DOMAINS = [ + 'browser-intake-datadoghq.com', + 'browser-intake-datadoghq.eu', + 'browser-intake-ddog-gov.com', + 'browser-intake-us3-datadoghq.com', + 'browser-intake-us5-datadoghq.com', + ...['com', 'eu'].flatMap((tld) => [ + `public-trace-http-intake.logs.datadoghq.${tld}`, + `rum-http-intake.logs.datadoghq.${tld}`, + `browser-http-intake.logs.datadoghq.${tld}`, + ]), +] diff --git a/developer-extension/src/background/domain/blockIntakeRequests.ts b/developer-extension/src/background/domain/blockIntakeRequests.ts deleted file mode 100644 index bafd574b44..0000000000 --- a/developer-extension/src/background/domain/blockIntakeRequests.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { intakeUrlPatterns } from '../intakeUrlPatterns' -import { store } from '../store' - -chrome.webRequest.onBeforeRequest.addListener( - () => { - if (!store.blockIntakeRequests) { - return - } - return { cancel: true } - }, - { - urls: intakeUrlPatterns, - }, - ['blocking'] -) diff --git a/developer-extension/src/background/domain/refreshDevServerStatus.ts b/developer-extension/src/background/domain/refreshDevServerStatus.ts new file mode 100644 index 0000000000..d3c700b9fb --- /dev/null +++ b/developer-extension/src/background/domain/refreshDevServerStatus.ts @@ -0,0 +1,23 @@ +import { listenAction } from '../actions' +import { DEV_LOGS_URL } from '../constants' +import { setStore } from '../store' + +listenAction('getStore', () => { + refreshDevServerStatus().catch((error) => + console.error('syncRules: Unexpected error while refreshing dev server status:', error) + ) +}) + +async function refreshDevServerStatus() { + const timeoutId = setTimeout(() => setStore({ devServerStatus: 'checking' }), 500) + let isAvailable = false + try { + const response = await fetch(DEV_LOGS_URL, { method: 'HEAD' }) + isAvailable = response.status === 200 + } catch { + // The request can fail if nothing is listening on the URL port. In this case, consider the dev + // server 'unavailable'. + } + clearTimeout(timeoutId) + setStore({ devServerStatus: isAvailable ? 'available' : 'unavailable' }) +} diff --git a/developer-extension/src/background/domain/replaceBundles.ts b/developer-extension/src/background/domain/replaceBundles.ts deleted file mode 100644 index 52509dd151..0000000000 --- a/developer-extension/src/background/domain/replaceBundles.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { listenAction } from '../actions' -import { DEV_LOGS_URL, DEV_RUM_SLIM_URL, DEV_RUM_URL } from '../constants' -import { setStore, store } from '../store' - -chrome.webRequest.onBeforeRequest.addListener( - (info) => { - if (store.useDevBundles) { - const url = new URL(info.url) - if (url.pathname.includes('logs')) { - return { redirectUrl: DEV_LOGS_URL } - } - if (url.pathname.includes('rum')) { - return { - redirectUrl: store.useRumSlim ? DEV_RUM_SLIM_URL : DEV_RUM_URL, - } - } - } else if (store.useRumSlim && /\/datadog-rum(?!-slim)/.test(info.url)) { - return { - redirectUrl: info.url.replace(/datadog-rum/, 'datadog-rum-slim'), - } - } - return - }, - { - types: ['script'], - urls: [ - ...getBundleUrlPatterns('logs'), - ...getBundleUrlPatterns('rum'), - ...getBundleUrlPatterns('rum-slim'), - 'https://localhost:8443/static/datadog-rum-hotdog.js', - ], - }, - ['blocking'] -) - -listenAction('getStore', () => { - refreshDevServerStatus().catch((error) => - console.error('Unexpected error while refreshing dev server status:', error) - ) -}) - -listenAction('setStore', (newStore) => { - if ('useDevBundles' in newStore || 'useRumSlim' in newStore) { - void chrome.browsingData.removeCache({}) - } -}) - -function getBundleUrlPatterns(bundleName: string) { - return [ - `https://*/datadog-${bundleName}.js`, - `https://*/datadog-${bundleName}-v4.js`, - `https://*/datadog-${bundleName}-canary.js`, - `https://*/datadog-${bundleName}-staging.js`, - ] -} - -async function refreshDevServerStatus() { - const timeoutId = setTimeout(() => setStore({ devServerStatus: 'checking' }), 500) - let isAvailable = false - try { - const response = await fetch(DEV_LOGS_URL, { method: 'HEAD' }) - isAvailable = response.status === 200 - } catch { - // The request can fail if nothing is listening on the URL port. In this case, consider the dev - // server 'unavailable'. - } - clearTimeout(timeoutId) - setStore({ devServerStatus: isAvailable ? 'available' : 'unavailable' }) -} diff --git a/developer-extension/src/background/domain/syncRules.ts b/developer-extension/src/background/domain/syncRules.ts new file mode 100644 index 0000000000..b1bde9e92a --- /dev/null +++ b/developer-extension/src/background/domain/syncRules.ts @@ -0,0 +1,72 @@ +import { listenAction } from '../actions' +import { DEV_LOGS_URL, DEV_RUM_SLIM_URL, DEV_RUM_URL, INTAKE_DOMAINS } from '../constants' +import { store } from '../store' + +listenAction('setStore', (newStore) => { + if ('useDevBundles' in newStore || 'useRumSlim' in newStore || 'blockIntakeRequests' in newStore) { + void chrome.browsingData.removeCache({}) + syncRules() + } +}) + +function syncRules() { + console.log('syncRules: Syncing rules') + chrome.declarativeNetRequest + .getSessionRules() + .then((existingRules) => + chrome.declarativeNetRequest.updateSessionRules({ + removeRuleIds: existingRules.map((rule) => rule.id), + addRules: getRules(), + }) + ) + .catch((error) => console.error('syncRules: Error while syncing rules:', error)) +} + +function getRules() { + const rules: chrome.declarativeNetRequest.Rule[] = [] + let id = 1 + + if (store.useDevBundles) { + const devRumUrl = store.useRumSlim ? DEV_RUM_SLIM_URL : DEV_RUM_URL + console.log('syncRules: add redirect to dev bundles rules') + rules.push( + createRedirectRule(id++, /^https:\/\/.*\/datadog-rum(-v\d|canary|staging)?\.js$/, { url: devRumUrl }), + createRedirectRule(id++, /^https:\/\/.*\/datadog-rum-slim(-v\d|canary|staging)?\.js$/, { url: DEV_RUM_SLIM_URL }), + createRedirectRule(id++, /^https:\/\/.*\/datadog-logs(-v\d|canary|staging)?\.js$/, { url: DEV_LOGS_URL }), + createRedirectRule(id++, 'https://localhost:8443/static/datadog-rum-hotdog.js', { url: devRumUrl }) + ) + } else if (store.useRumSlim) { + console.log('syncRules: add redirect to rum slim rule') + rules.push(createRedirectRule(id++, /^(https:\/\/.*\/datadog-rum)(-slim)?/, { regexSubstitution: '\\1-slim' })) + } + + if (store.blockIntakeRequests) { + console.log('syncRules: add block intake rules') + for (const intakeDomain of INTAKE_DOMAINS) { + rules.push({ + id: id++, + condition: { urlFilter: `||${intakeDomain}` }, + action: { + type: chrome.declarativeNetRequest.RuleActionType.BLOCK, + }, + }) + } + } + + return rules +} + +function createRedirectRule( + id: number, + filter: RegExp | string, + redirect: chrome.declarativeNetRequest.Redirect +): chrome.declarativeNetRequest.Rule { + return { + id, + action: { + type: chrome.declarativeNetRequest.RuleActionType.REDIRECT, + redirect, + }, + condition: typeof filter === 'string' ? { urlFilter: `|${filter}|` } : { regexFilter: filter.source }, + } +} diff --git a/developer-extension/src/background/index.ts b/developer-extension/src/background/index.ts index 0fbf50b063..79ee8ec98f 100644 --- a/developer-extension/src/background/index.ts +++ b/developer-extension/src/background/index.ts @@ -1,2 +1,2 @@ -import './domain/replaceBundles' -import './domain/blockIntakeRequests' +import './domain/refreshDevServerStatus' +import './domain/syncRules' diff --git a/developer-extension/src/background/intakeUrlPatterns.ts b/developer-extension/src/background/intakeUrlPatterns.ts deleted file mode 100644 index a1457f0f20..0000000000 --- a/developer-extension/src/background/intakeUrlPatterns.ts +++ /dev/null @@ -1,18 +0,0 @@ -export const intakeUrlPatterns = [ - // TODO: implement a configuration page to add more URLs in this list. - 'https://*.browser-intake-datadoghq.com/*', - 'https://*.browser-intake-datadoghq.eu/*', - 'https://*.browser-intake-ddog-gov.com/*', - 'https://*.browser-intake-us3-datadoghq.com/*', - 'https://*.browser-intake-us5-datadoghq.com/*', - ...classicIntakesUrlsForSite('datadoghq.com'), - ...classicIntakesUrlsForSite('datadoghq.eu'), -] - -function classicIntakesUrlsForSite(site: string) { - return [ - `https://public-trace-http-intake.logs.${site}/*`, - `https://rum-http-intake.logs.${site}/*`, - `https://browser-http-intake.logs.${site}/*`, - ] -}