Skip to content

Commit

Permalink
[mv3] Add urlskip support for strict-blocked page + extra info
Browse files Browse the repository at this point in the history
Add information about which ruleset caused a page to be strict-
blocked.

Whenever possible, add ability to URL-skip an incoming redirect
in a strict-blocked page.

Add new default list: "30-day Phishing Domain List"
  • Loading branch information
gorhill committed Dec 5, 2024
1 parent fb82db3 commit 38390ba
Show file tree
Hide file tree
Showing 15 changed files with 418 additions and 185 deletions.
8 changes: 8 additions & 0 deletions platform/mv3/extension/_locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,14 @@
"strictblockSentence1": {
"message": "uBO Lite has prevented the following page from loading:",
"description": "Sentence used in the strict-blocked page"
},
"strictblockReasonSentence1": {
"message": "The page was blocked because of a matching filter in {{listname}}.",
"description": "Text informing about what is causing the page to be blocked"
},
"strictblockRedirectSentence1": {
"message": "The blocked page wants to redirect to another site. If you choose to proceed, you will navigate directly to: {{url}}",
"description": "Text warning about an incoming redirect"
},
"strictblockNoParamsPrompt": {
"message": "without parameters",
Expand Down
2 changes: 1 addition & 1 deletion platform/mv3/extension/css/settings.css
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ h3 {

label + legend {
color: color-mix(in srgb, currentColor 69%, transparent);
font-size: small;
font-size: var(--font-size-smaller);
margin-inline-start: var(--default-gap-large);
}

Expand Down
12 changes: 12 additions & 0 deletions platform/mv3/extension/css/strictblock.css
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ body {
:root.mobile body {
padding: var(--default-gap-small);
}
body.loading {
visibility: hidden;
}

#rootContainer {
width: min(100%, 640px);
Expand All @@ -43,6 +46,9 @@ p {
a {
text-decoration: none;
}
q {
font-weight: bold;
}
.code {
font-size: 13px;
word-break: break-all;
Expand Down Expand Up @@ -128,6 +134,12 @@ body[dir="rtl"] #toggleParse {
font-weight: bold;
}

#urlskip a {
display: block;
overflow-y: auto;
word-break: break-all;
}

#actionContainer {
display: flex;
justify-content: space-between;
Expand Down
25 changes: 15 additions & 10 deletions platform/mv3/extension/js/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import {
excludeFromStrictBlock,
getEnabledRulesetsDetails,
getRulesetDetails,
patchDefaultRulesets,
setStrictBlockMode,
updateDynamicRules,
} from './ruleset-manager.js';
Expand Down Expand Up @@ -377,20 +378,24 @@ function onMessage(request, sender, callback) {
async function start() {
await loadRulesetConfig();

const currentVersion = getCurrentVersion();
const isNewVersion = currentVersion !== rulesetConfig.version;

// The default rulesets may have changed, find out new ruleset to enable,
// obsolete ruleset to remove.
if ( isNewVersion ) {
ubolLog(`Version change: ${rulesetConfig.version} => ${currentVersion}`);
rulesetConfig.version = currentVersion;
await patchDefaultRulesets();
saveRulesetConfig();
}

const rulesetsUpdated = process.wakeupRun === false &&
await enableRulesets(rulesetConfig.enabledRulesets);

// We need to update the regex rules only when ruleset version changes.
if ( process.wakeupRun === false ) {
const currentVersion = getCurrentVersion();
if ( currentVersion !== rulesetConfig.version ) {
ubolLog(`Version change: ${rulesetConfig.version} => ${currentVersion}`);
rulesetConfig.version = currentVersion;
saveRulesetConfig();
if ( rulesetsUpdated === false ) {
updateDynamicRules();
}
}
if ( isNewVersion && rulesetsUpdated === false ) {
updateDynamicRules();
}

// Permissions may have been removed while the extension was disabled
Expand Down
5 changes: 1 addition & 4 deletions platform/mv3/extension/js/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,11 @@ import {
sessionRead, sessionWrite,
} from './ext.js';

import { defaultRulesetsFromLanguage } from './ruleset-manager.js';

/******************************************************************************/

export const rulesetConfig = {
version: '',
enabledRulesets: [ 'default' ],
enabledRulesets: [],
autoReload: true,
showBlockedCount: true,
strictBlockMode: true,
Expand Down Expand Up @@ -67,7 +65,6 @@ export async function loadRulesetConfig() {
sessionWrite('rulesetConfig', rulesetConfig);
return;
}
rulesetConfig.enabledRulesets = await defaultRulesetsFromLanguage();
sessionWrite('rulesetConfig', rulesetConfig);
localWrite('rulesetConfig', rulesetConfig);
process.firstRun = true;
Expand Down
44 changes: 42 additions & 2 deletions platform/mv3/extension/js/ruleset-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -561,8 +561,6 @@ async function filteringModesToDNR(modes) {
/******************************************************************************/

async function defaultRulesetsFromLanguage() {
const out = await dnr.getEnabledRulesets();

const dropCountry = lang => {
const pos = lang.indexOf('-');
if ( pos === -1 ) { return lang; }
Expand All @@ -581,7 +579,12 @@ async function defaultRulesetsFromLanguage() {
);

const rulesetDetails = await getRulesetDetails();
const out = [];
for ( const [ id, details ] of rulesetDetails ) {
if ( details.enabled ) {
out.push(id);
continue;
}
if ( typeof details.lang !== 'string' ) { continue; }
if ( reTargetLang.test(details.lang) === false ) { continue; }
out.push(id);
Expand All @@ -591,6 +594,42 @@ async function defaultRulesetsFromLanguage() {

/******************************************************************************/

async function patchDefaultRulesets() {
const [
oldDefaultIds = [],
newDefaultIds,
newIds,
] = await Promise.all([
localRead('defaultRulesetIds'),
defaultRulesetsFromLanguage(),
getRulesetDetails(),
]);
const toAdd = [];
const toRemove = [];
for ( const id of newDefaultIds ) {
if ( oldDefaultIds.includes(id) ) { continue; }
toAdd.push(id);
}
for ( const id of oldDefaultIds ) {
if ( newDefaultIds.includes(id) ) { continue; }
toRemove.push(id);
}
for ( const id of rulesetConfig.enabledRulesets ) {
if ( newIds.has(id) ) { continue; }
toRemove.push(id);
}
localWrite('defaultRulesetIds', newDefaultIds);
if ( toAdd.length === 0 && toRemove.length === 0 ) { return; }
const enabledRulesets = new Set(rulesetConfig.enabledRulesets);
toAdd.forEach(id => enabledRulesets.add(id));
toRemove.forEach(id => enabledRulesets.delete(id));
const patchedRulesets = Array.from(enabledRulesets);
ubolLog(`Patched rulesets: ${rulesetConfig.enabledRulesets} => ${patchedRulesets}`);
rulesetConfig.enabledRulesets = patchedRulesets;
}

/******************************************************************************/

async function enableRulesets(ids) {
const afterIds = new Set(ids);
const [ beforeIds, adminIds, rulesetDetails ] = await Promise.all([
Expand Down Expand Up @@ -679,6 +718,7 @@ export {
filteringModesToDNR,
getRulesetDetails,
getEnabledRulesetsDetails,
patchDefaultRulesets,
setStrictBlockMode,
updateDynamicRules,
};
115 changes: 96 additions & 19 deletions platform/mv3/extension/js/strictblock.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,15 @@
*/

import { dom, qs$ } from './dom.js';
import { fetchJSON } from './fetch.js';
import { getEnabledRulesetsDetails } from './ruleset-manager.js';
import { i18n$ } from './i18n.js';
import { sendMessage } from './ext.js';
import { urlSkip } from './urlskip.js';

/******************************************************************************/

const toURL = new URL('about:blank');

function setURL(url) {
try {
toURL.href = url;
} catch(_) {
}
}

setURL(self.location.hash.slice(1));
const rulesetDetailsPromise = getEnabledRulesetsDetails();

/******************************************************************************/

Expand Down Expand Up @@ -66,6 +60,13 @@ async function proceed() {

/******************************************************************************/

const toURL = new URL('about:blank');

try {
toURL.href = self.location.hash.slice(1);
} catch(_) {
}

dom.clear('#theURL > p > span:first-of-type');
qs$('#theURL > p > span:first-of-type').append(urlToFragment(toURL.href));

Expand Down Expand Up @@ -152,16 +153,92 @@ qs$('#theURL > p > span:first-of-type').append(urlToFragment(toURL.href));

/******************************************************************************/

// Find which list caused the blocking.
(async ( ) => {
const rulesetDetails = await rulesetDetailsPromise;
let iList = -1;
const searchInList = async i => {
if ( iList !== -1 ) { return; }
const hostnames = new Set(
await fetchJSON(`/rulesets/strictblock/${rulesetDetails[i].id}`)
);
if ( iList !== -1 ) { return; }
let hn = toURL.hostname;
for (;;) {
if ( hostnames.has(hn) ) { iList = i; break; }
const pos = hn.indexOf('.');
if ( pos === -1 ) { break; }
hn = hn.slice(pos+1);
}
};
const toFetch = [];
for ( let i = 0; i < rulesetDetails.length; i++ ) {
if ( rulesetDetails[i].rules.strictblock === 0 ) { continue; }
toFetch.push(searchInList(i));
}
if ( toFetch.length === 0 ) { return; }
await Promise.all(toFetch);
if ( iList === -1 ) { return; }

const fragment = new DocumentFragment();
const text = i18n$('strictblockReasonSentence1');
const placeholder = '{{listname}}';
const pos = text.indexOf(placeholder);
if ( pos === -1 ) { return; }
const q = document.createElement('q');
q.append(rulesetDetails[iList].name);
fragment.append(text.slice(0, pos), q, text.slice(pos + placeholder.length));
qs$('#reason').append(fragment);
dom.attr('#reason', 'hidden', null);
})();

/******************************************************************************/

// Offer to skip redirection whenever possible
(async ( ) => {
const rulesetDetails = await rulesetDetailsPromise;
const toFetch = [];
for ( const details of rulesetDetails ) {
if ( details.rules.urlskip === 0 ) { continue; }
toFetch.push(fetchJSON(`/rulesets/urlskip/${details.id}`));
}
if ( toFetch.length === 0 ) { return; }
const urlskipLists = await Promise.all(toFetch);
for ( const urlskips of urlskipLists ) {
for ( const urlskip of urlskips ) {
const re = new RegExp(urlskip.re, urlskip.c ? undefined : 'i');
if ( re.test(toURL.href) === false ) { continue; }
const finalURL = urlSkip(toURL.href, false, urlskip.steps);
if ( finalURL === undefined ) { continue; }
const fragment = new DocumentFragment();
const text = i18n$('strictblockRedirectSentence1');
const linkPlaceholder = '{{url}}';
const pos = text.indexOf(linkPlaceholder);
if ( pos === -1 ) { return; }
const link = document.createElement('a');
link.href = finalURL;
dom.cl.add(link, 'code');
link.append(urlToFragment(finalURL));
fragment.append(
text.slice(0, pos),
link,
text.slice(pos + linkPlaceholder.length)
);
qs$('#urlskip').append(fragment);
dom.attr('#urlskip', 'hidden', null);
return;
}
}
})();

/******************************************************************************/

// https://www.reddit.com/r/uBlockOrigin/comments/breeux/
if ( window.history.length > 1 ) {
dom.on('#back', 'click', ( ) => {
window.history.back();
});
dom.on('#back', 'click', ( ) => { window.history.back(); });
qs$('#bye').style.display = 'none';
} else {
dom.on('#bye', 'click', ( ) => {
window.close();
});
dom.on('#bye', 'click', ( ) => { window.close(); });
qs$('#back').style.display = 'none';
}

Expand All @@ -171,8 +248,8 @@ dom.on('#disableWarning', 'change', ev => {
dom.cl.toggle('[data-i18n="strictblockClose"]', 'disabled', checked);
});

dom.on('#proceed', 'click', ( ) => {
proceed();
});
dom.on('#proceed', 'click', ( ) => { proceed(); });

dom.cl.remove(dom.body, 'loading');

/******************************************************************************/
Loading

0 comments on commit 38390ba

Please sign in to comment.