From c4277c4e09bb0fda01d147c9608f43da2c0b6d7c Mon Sep 17 00:00:00 2001 From: Jonathan Kingston Date: Fri, 27 Oct 2023 14:58:00 +0100 Subject: [PATCH] Expire storage and hash hostname --- shared/js/background/broken-site-report.js | 42 +++++++++++++++++++--- shared/js/background/events.js | 5 +++ 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/shared/js/background/broken-site-report.js b/shared/js/background/broken-site-report.js index 668628e382..f206720a4f 100644 --- a/shared/js/background/broken-site-report.js +++ b/shared/js/background/broken-site-report.js @@ -88,7 +88,17 @@ const requestCategoryMapping = { 'ignore-user': 'ignoredByUserRequests' } -function computeLastSentDay (urlString) { +async function digestMessage (message) { + const msgUint8 = new TextEncoder().encode(message) + const hashBuffer = await crypto.subtle.digest('SHA-256', msgUint8) + const hashArray = Array.from(new Uint8Array(hashBuffer)) + const hashHex = hashArray + .map((b) => b.toString(16).padStart(2, '0')) + .join('') + return hashHex +} + +async function computeLastSentDay (urlString) { const url = new URL(urlString) const time = new Date() // Round time to nearest day @@ -96,16 +106,38 @@ function computeLastSentDay (urlString) { // Output time as a string in the format YYYY-MM-DD const dayOutput = time.toISOString().split('T')[0] + // Use a sha256 hash prefix of the hostname so that we don't store the full hostname + const hash = await digestMessage(url.hostname) + const hostnameHashPrefix = hash.slice(0, 6) + const reportTimes = settings.getSetting('brokenSiteReportTimes') || {} - const lastSentDay = reportTimes[url.hostname] + const lastSentDay = reportTimes[hostnameHashPrefix] // Update existing time - reportTimes[url.hostname] = dayOutput + reportTimes[hostnameHashPrefix] = dayOutput settings.updateSetting('brokenSiteReportTimes', reportTimes) return lastSentDay } +/** + * Clears any expired broken site report times + * Called by an alarm every hour to remove entries older than 30 days + */ +export async function clearExpiredBrokenSiteReportTimes () { + await settings.ready() + const brokenSiteReports = settings.getSetting('brokenSiteReportTimes') || {} + // Expiry of 30 days + const expiryTime = new Date().getTime() - 30 * 24 * 60 * 60 * 1000 + for (const hashPrefix in brokenSiteReports) { + const reportTime = new Date(brokenSiteReports[hashPrefix]) + if (reportTime.getTime() < expiryTime) { + delete brokenSiteReports[hashPrefix] + } + } + settings.updateSetting('brokenSiteReportTimes', brokenSiteReports) +} + /** * Given an optional category and description, create a report for a given Tab instance. * @@ -121,7 +153,7 @@ function computeLastSentDay (urlString) { * @prop {string | undefined} arg.category - optional category * @prop {string | undefined} arg.description - optional description */ -export function breakageReportForTab ({ +export async function breakageReportForTab ({ tab, tds, remoteConfigEtag, remoteConfigVersion, category, description }) { @@ -155,7 +187,7 @@ export function breakageReportForTab ({ const debugFlags = tab.debugFlags.join(',') const errorDescriptions = JSON.stringify(tab.errorDescriptions) const httpErrorCodes = tab.httpErrorCodes.join(',') - const lastSentDay = computeLastSentDay(tab.url) + const lastSentDay = await computeLastSentDay(tab.url) const brokenSiteParams = new URLSearchParams({ siteUrl, diff --git a/shared/js/background/events.js b/shared/js/background/events.js index cbdfe512c3..b35021e531 100644 --- a/shared/js/background/events.js +++ b/shared/js/background/events.js @@ -17,6 +17,7 @@ import { import tdsStorage from './storage/tds' import httpsStorage from './storage/https' import ATB from './atb' +import { clearExpiredBrokenSiteReportTimes } from './broken-site-report' const utils = require('./utils') const experiment = require('./experiments') const settings = require('./settings') @@ -433,6 +434,8 @@ browserWrapper.createAlarm('clearExpiredHTTPSServiceCache', { periodInMinutes: 6 browserWrapper.createAlarm('rotateUserAgent', { periodInMinutes: 24 * 60 }) // Rotate the sessionKey browserWrapper.createAlarm('rotateSessionKey', { periodInMinutes: 24 * 60 }) +// Expire site breakage reports +browserWrapper.createAlarm('clearExpiredBrokenSiteReportTimes', { periodInMinutes: 24 * 60 }) browser.alarms.onAlarm.addListener(async alarmEvent => { // Warning: Awaiting in this function doesn't actually wait for the promise to resolve before unblocking the main thread. @@ -459,6 +462,8 @@ browser.alarms.onAlarm.addListener(async alarmEvent => { await utils.resetSessionKey() } else if (alarmEvent.name === REFETCH_ALIAS_ALARM) { fetchAlias() + } else if (alarmEvent.name === 'clearExpiredBrokenSiteReportTimes') { + await clearExpiredBrokenSiteReportTimes() } })