Skip to content

Commit dd36253

Browse files
committed
Improved blocked and global cache handling
1 parent 9e5ec53 commit dd36253

File tree

2 files changed

+91
-99
lines changed

2 files changed

+91
-99
lines changed

src/main/background.js

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1258,11 +1258,21 @@
12581258
return;
12591259
}
12601260

1261-
const hostnameString = `*.${hostname}`;
1261+
const dotIndex = hostname.indexOf(".");
1262+
let hostnameString;
12621263

1263-
// Adds the hostname to the global allowed cache
1264+
if (dotIndex === -1) {
1265+
hostnameString = `*.${hostname}`;
1266+
} else {
1267+
// Only go one level up if the parent is itself a proper domain (has a dot), not a bare TLD
1268+
const parent = hostname.slice(dotIndex + 1);
1269+
hostnameString = parent.includes(".") ? `*.${parent}` : `*.${hostname}`;
1270+
}
1271+
1272+
// Adds the hostname to the global allowed cache and removes it from all blocked caches
12641273
console.debug(`Adding hostname to the global allowed cache: ${hostnameString}`);
12651274
CacheManager.addStringToAllowedCache(hostnameString, "global");
1275+
CacheManager.removeUrlFromBlockedCache(blockedUrlObject, "all");
12661276

12671277
// Validates the continue URL
12681278
const continueUrlResult = Validate.validateHttpUrl(message.continueUrl, validProtocols);

src/main/util/CacheManager.js

Lines changed: 79 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ const CacheManager = (() => {
3030

3131
// Caches for allowed, blocked, and processing entries
3232
let allowedCaches = Object.create(null);
33+
let allowedPatternCaches = Object.create(null);
3334
let blockedCaches = Object.create(null);
3435
let processingCaches = Object.create(null);
3536

@@ -83,6 +84,7 @@ const CacheManager = (() => {
8384
// Initialize caches for each provider
8485
for (const name of providers) {
8586
allowedCaches[name] = new Map();
87+
allowedPatternCaches[name] = new Set();
8688
blockedCaches[name] = new Map();
8789
processingCaches[name] = new Map();
8890
}
@@ -114,9 +116,18 @@ const CacheManager = (() => {
114116
const entries = Object.entries(callback[name]).filter(([key]) => !DANGEROUS_KEYS.has(key));
115117

116118
blockedCaches[name] = new Map(
117-
entries.map(([url, entry]) => [
118-
url, {exp: entry.exp, resultType: entry.resultType}
119-
])
119+
entries.flatMap(([url, {exp, resultType}]) => {
120+
if (!Number.isFinite(exp) && exp !== 0 || !Number.isFinite(resultType)) {
121+
console.warn(`Skipping invalid blocked cache entry for "${url}": invalid exp or resultType`);
122+
return [];
123+
}
124+
125+
if (!validResultTypes.has(resultType)) {
126+
console.warn(`Skipping blocked cache entry for "${url}": unrecognized resultType ${resultType}`);
127+
return [];
128+
}
129+
return [[url, {exp, resultType}]];
130+
})
120131
);
121132
}
122133
}
@@ -129,8 +140,8 @@ const CacheManager = (() => {
129140
* @param {Object} [callback] The callback function to execute after loading the processing caches.
130141
*/
131142
StorageUtil.getFromSessionStore(processingKey, callback => {
132-
for (const name of Object.keys(processingCaches)) {
133-
if (callback && typeof callback === 'object') {
143+
if (callback && typeof callback === 'object') {
144+
for (const name of Object.keys(processingCaches)) {
134145
if (callback[name] && typeof callback[name] === 'object') {
135146
const entries = Object.entries(callback[name]).filter(([key]) => !DANGEROUS_KEYS.has(key));
136147
processingCaches[name] = new Map(entries);
@@ -224,9 +235,18 @@ const CacheManager = (() => {
224235
}
225236
};
226237

227-
cleanGroup(allowedCaches, () => updateLocalStorage());
228-
cleanGroup(blockedCaches, () => updateLocalStorage());
238+
let localDirty = false;
239+
cleanGroup(allowedCaches, () => {
240+
localDirty = true;
241+
});
242+
cleanGroup(blockedCaches, () => {
243+
localDirty = true;
244+
});
229245
cleanGroup(processingCaches, () => updateSessionStorage());
246+
247+
if (localDirty) {
248+
updateLocalStorage();
249+
}
230250
return totalRemoved;
231251
};
232252

@@ -307,31 +327,6 @@ const CacheManager = (() => {
307327
return false;
308328
};
309329

310-
/**
311-
* Checks if a string is in the allowed cache for a specific provider.
312-
*
313-
* @param {string} str The string to check.
314-
* @param {string} name The name of the provider (e.g., "precisionSec").
315-
* @returns {boolean} Returns true if the string is in the allowed cache and not expired, false otherwise.
316-
*/
317-
const isStringInAllowedCache = (str, name) => {
318-
try {
319-
const map = allowedCaches[name];
320-
321-
if (!map) {
322-
console.warn(`Allowed cache "${name}" not found`);
323-
return false;
324-
}
325-
326-
if (map.has(str)) {
327-
return true;
328-
}
329-
} catch (error) {
330-
console.error(`Error checking allowed cache for string "${str}":`, error);
331-
}
332-
return false;
333-
};
334-
335330
/**
336331
* Checks if a string is in the allowed cache for a specific provider.
337332
*
@@ -340,9 +335,13 @@ const CacheManager = (() => {
340335
* @returns {boolean} Returns true if the string is in the allowed cache and not expired, false otherwise.
341336
*/
342337
const isPatternInAllowedCache = (str, name) => {
343-
// Returns if the string is too long
344338
if (typeof str !== 'string' || str.length > 2048) {
345-
console.warn(`Invalid string provided for allowed cache pattern check: "${str}"`);
339+
console.warn(`Invalid string provided: "${str}"`);
340+
return false;
341+
}
342+
343+
if (name !== "all" && !providersSet.has(name)) {
344+
console.warn(`Unknown cache provider name: "${name}"`);
346345
return false;
347346
}
348347

@@ -354,16 +353,23 @@ const CacheManager = (() => {
354353
return false;
355354
}
356355

357-
// Checks if any key in the map (patterns, like *.example.com) matches the string
358-
for (const pattern of map.keys()) {
359-
// Uses a simple pattern matching logic
360-
if (pattern.startsWith("*.")) {
361-
const domain = pattern.slice(2);
356+
// O(1) exact-key check
357+
if (map.has(str)) {
358+
return true;
359+
}
362360

363-
if (str === domain || str.endsWith("." + domain)) {
364-
return true;
365-
}
366-
} else if (str === pattern) {
361+
// O(1) wildcard pattern check for *.str
362+
if (patternCache.has("*." + str)) {
363+
return true;
364+
}
365+
366+
const dotIndex = str.indexOf(".");
367+
368+
// O(n) wildcard pattern check for str with subdomains (e.g., sub.str)
369+
if (dotIndex !== -1) {
370+
const wildcardKey = "*." + str.slice(dotIndex + 1);
371+
372+
if (patternCache.has(wildcardKey)) {
367373
return true;
368374
}
369375
}
@@ -418,10 +424,20 @@ const CacheManager = (() => {
418424

419425
if (name === "all") {
420426
for (const cache of Object.values(allowedCaches)) {
421-
cache.set(str, expTime);
427+
cache.set(str, 0);
428+
}
429+
430+
if (str.startsWith("*.")) {
431+
for (const patternCache of Object.values(allowedPatternCaches)) {
432+
patternCache.add(str);
433+
}
422434
}
423435
} else if (allowedCaches[name]) {
424-
allowedCaches[name].set(str, expTime);
436+
allowedCaches[name].set(str, 0);
437+
438+
if (str.startsWith("*.")) {
439+
allowedPatternCaches[name].add(str);
440+
}
425441
} else {
426442
console.warn(`Cache "${name}" not found`);
427443
}
@@ -489,11 +505,11 @@ const CacheManager = (() => {
489505
const cache = blockedCaches[name];
490506

491507
if (name === "all") {
492-
for (const cache of Object.values(blockedCaches)) {
493-
cache.set(key, {exp: expTime, resultType: resultType});
508+
for (const providerCache of Object.values(blockedCaches)) {
509+
providerCache.set(key, {exp: expTime, resultType});
494510
}
495511
} else if (cache) {
496-
cache.set(key, {exp: expTime, resultType: resultType});
512+
cache.set(key, {exp: expTime, resultType});
497513
} else {
498514
console.warn(`Cache "${name}" not found`);
499515
}
@@ -530,16 +546,15 @@ const CacheManager = (() => {
530546

531547
if (entry.exp > Date.now()) {
532548
return entry.resultType;
533-
} else {
534-
// Entry expired, remove it
535-
cache.delete(key);
536-
updateLocalStorage();
537549
}
550+
551+
// Entry expired, remove it
552+
cache.delete(key);
553+
updateLocalStorage();
538554
} catch (error) {
539555
console.error(`Error getting blocked result type for ${url}:`, error);
556+
console.warn(`Returning default result type for ${url} in provider "${name}" due to error`);
540557
}
541-
542-
console.warn(`Returning default result type for ${url} in provider "${name}" due to error or missing entry`);
543558
return ProtectionResult.ResultType.FAILED;
544559
};
545560

@@ -631,7 +646,7 @@ const CacheManager = (() => {
631646
}
632647

633648
const expTime = Date.now() + 60 * 1000; // Expiration for processing cache is 60 seconds
634-
const entry = {exp: expTime, tabId: tabId};
649+
const entry = {exp: expTime, tabId};
635650

636651
if (name === "all") {
637652
for (const cache of Object.values(processingCaches)) {
@@ -680,41 +695,6 @@ const CacheManager = (() => {
680695
}
681696
};
682697

683-
/**
684-
* Retrieve all normalized-URL keys (or string keys) in the processing cache for a given provider
685-
* that are associated with the specified tabId and not yet expired.
686-
*
687-
* @param {string} name The name of the provider (e.g., "precisionSec").
688-
* @param {number} tabId The ID of the tab to filter by.
689-
* @returns {string[]} An array of keys (normalized URLs or strings) that match the criteria.
690-
*/
691-
const getKeysByTabId = (name, tabId) => {
692-
const results = [];
693-
const map = processingCaches[name];
694-
695-
// Checks if the map is valid
696-
if (!map) {
697-
console.warn(`Processing cache "${name}" not found`);
698-
return results;
699-
}
700-
701-
const now = Date.now();
702-
703-
// Removes expired keys from the map
704-
for (const [key, entry] of map.entries()) {
705-
if (entry.tabId === tabId) {
706-
if (entry.exp > now) {
707-
results.push(key);
708-
} else {
709-
map.delete(key);
710-
}
711-
}
712-
}
713-
714-
updateSessionStorage();
715-
return results;
716-
};
717-
718698
/**
719699
* Remove all entries in the processing cache for all keys associated with a specific tabId.
720700
*
@@ -726,18 +706,23 @@ const CacheManager = (() => {
726706
for (const name of Object.keys(processingCaches)) {
727707
const map = processingCaches[name];
728708

729-
// Checks if the cache is valid
730709
if (!map) {
731710
console.warn(`Processing cache "${name}" not found`);
732711
continue;
733712
}
734713

714+
const toRemove = [];
715+
735716
for (const [key, entry] of map.entries()) {
736717
if (entry.tabId === tabId) {
737-
removedCount++;
738-
map.delete(key);
718+
toRemove.push(key);
739719
}
740720
}
721+
722+
for (const key of toRemove) {
723+
map.delete(key);
724+
removedCount++;
725+
}
741726
}
742727

743728
// Persist the changes to session storage
@@ -752,7 +737,6 @@ const CacheManager = (() => {
752737
clearBlockedCache,
753738
clearProcessingCache,
754739
isUrlInAllowedCache,
755-
isStringInAllowedCache,
756740
isPatternInAllowedCache,
757741
addUrlToAllowedCache,
758742
addStringToAllowedCache,
@@ -763,8 +747,6 @@ const CacheManager = (() => {
763747
isUrlInProcessingCache,
764748
addUrlToProcessingCache,
765749
removeUrlFromProcessingCache,
766-
getKeysByTabId,
767-
removeKeysByTabId,
768-
providers
750+
removeKeysByTabId
769751
});
770752
})();

0 commit comments

Comments
 (0)