Index: lib/filterListener.js |
=================================================================== |
--- a/lib/filterListener.js |
+++ b/lib/filterListener.js |
@@ -209,23 +209,48 @@ function removeFilter(filter) |
{ |
if (filter instanceof CSSPropertyFilter) |
CSSRules.remove(filter); |
else |
ElemHide.remove(filter); |
} |
} |
+const primes = [101, 109, 131, 149, 163, 179, 193, 211, 229, 241]; |
+ |
+function addFilters(filters) |
+{ |
+ // We add filters using pseudo-random ordering. Reason is that ElemHide will |
+ // assign consecutive filter IDs that might be visible to the website. The |
+ // randomization makes sure that no conclusion can be made about the actual |
+ // filters applying there. We have ten prime numbers to use as iteration step, |
+ // any of those can be chosen as long as the array length isn't divisible by |
+ // it. |
+ let len = filters.length; |
+ if (!len) |
+ return; |
+ |
+ let current = (Math.random() * len) | 0; |
+ let step; |
+ do |
+ { |
+ step = primes[(Math.random() * primes.length) | 0]; |
+ } while (len % step == 0); |
+ |
+ for (let i = 0; i < len; i++, current = (current + step) % len) |
+ addFilter(filters[current]); |
+} |
+ |
function onSubscriptionAdded(subscription) |
{ |
FilterListener.setDirty(1); |
if (!subscription.disabled) |
{ |
- subscription.filters.forEach(addFilter); |
+ addFilters(subscription.filters); |
flushElemHide(); |
} |
} |
function onSubscriptionRemoved(subscription) |
{ |
FilterListener.setDirty(1); |
@@ -238,32 +263,32 @@ function onSubscriptionRemoved(subscript |
function onSubscriptionDisabled(subscription, newValue) |
{ |
FilterListener.setDirty(1); |
if (subscription.url in FilterStorage.knownSubscriptions) |
{ |
if (newValue == false) |
- subscription.filters.forEach(addFilter); |
+ addFilters(subscription.filters); |
else |
subscription.filters.forEach(removeFilter); |
flushElemHide(); |
} |
} |
function onSubscriptionUpdated(subscription) |
{ |
FilterListener.setDirty(1); |
if (subscription.url in FilterStorage.knownSubscriptions && |
!subscription.disabled) |
{ |
subscription.oldFilters.forEach(removeFilter); |
- subscription.filters.forEach(addFilter); |
+ addFilters(subscription.filters); |
flushElemHide(); |
} |
} |
function onFilterHitCount(filter, newValue) |
{ |
if (newValue == 0) |
FilterListener.setDirty(0); |
@@ -318,16 +343,16 @@ function onLoad() |
{ |
isDirty = 0; |
defaultMatcher.clear(); |
ElemHide.clear(); |
CSSRules.clear(); |
for (let subscription of FilterStorage.subscriptions) |
if (!subscription.disabled) |
- subscription.filters.forEach(addFilter); |
+ addFilters(subscription.filters); |
flushElemHide(); |
} |
function onSave() |
{ |
isDirty = 0; |
} |