Skip to content

Commit d548774

Browse files
fix bug with old way to store rules (scheme = https), conflicted with new ones (scheme = *), with resolve conflict before add rule
1 parent aa8b90a commit d548774

File tree

10 files changed

+232
-39
lines changed

10 files changed

+232
-39
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "qjs",
3-
"version": "2.0.0",
3+
"version": "2.0.1",
44
"private": true,
55
"scripts": {
66
"serve": "vue-cli-service serve",

src/entry/background/actions.ts

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import {
2-
getDomainSetting,
3-
getJavascriptRuleSetting,
4-
getSubdomainSetting,
2+
3+
clearJavascriptRule,
54
getTabSetting,
65
removeJavascriptRule,
76
setJavascriptRule,
@@ -353,27 +352,33 @@ export const handleAllowUrl = async (tab: chrome.tabs.Tab) => {
353352

354353
export const handleClearSubdomain = async (tab: chrome.tabs.Tab) => {
355354
cl("CLEAR SUBDOMAIN", Log.ACTIONS);
356-
const primaryPattern = getSubdomainPatternFromUrl(tab.url!);
357-
if (primaryPattern) {
358-
await removeJavascriptRule({
359-
primaryPattern,
360-
scope: getScopeSetting(tab.incognito),
361-
});
362-
await updateContextMenus(); //not needed because we update tab
363-
reloadTab(tab);
355+
if (tab.url) {
356+
357+
const primaryPattern = getSubdomainPatternFromUrl(tab.url);
358+
if (primaryPattern) {
359+
await clearJavascriptRule({
360+
primaryPattern,
361+
scope: getScopeSetting(tab.incognito),
362+
tab
363+
});
364+
// await updateContextMenus(); //not needed because we update tab
365+
reloadTab(tab);
366+
}
364367
}
365368
};
366369
export const handleClearDomain = async (tab: chrome.tabs.Tab) => {
367370
cl("CLEAR DOMAIN", Log.ACTIONS);
368-
369-
const primaryPattern = getDomainPatternFromUrl(tab.url!);
370-
if (primaryPattern) {
371-
await removeJavascriptRule({
372-
primaryPattern,
373-
scope: getScopeSetting(tab.incognito),
374-
});
375-
await updateIcon(tab); //not needed because we update tab
376-
reloadTab(tab);
371+
if (tab.url) {
372+
const primaryPattern = getDomainPatternFromUrl(tab.url);
373+
if (primaryPattern) {
374+
await clearJavascriptRule({
375+
primaryPattern,
376+
scope: getScopeSetting(tab.incognito),
377+
tab
378+
});
379+
// await updateIcon(tab); //not needed because we update tab
380+
reloadTab(tab);
381+
}
377382
}
378383
};
379384

src/entry/background/contentsettings.ts

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { clearJavascriptRules, handleClear, reloadTab } from "./actions";
33
import { cl, isAllowedPattern, Log } from "./utils";
44
import { updateIcon } from "./icon";
55
import {
6+
getDomainStorageRulesFromUrl,
67
getStorageRules,
78
QJS,
89
setStorageRule,
@@ -34,13 +35,34 @@ export const getJavascriptRuleSetting = async ({
3435
incognito,
3536
},
3637
(details) => {
37-
cl(details, Log.RULES);
38+
cl('Current content setting:' + JSON.stringify(details), Log.RULES, 'CONTENT SETTINGS RULE: '+primaryUrl);
3839
resolve(details.setting);
3940
}
4041
);
4142
});
4243
};
4344

45+
export const removeConflictedRulesFromPattern = async (tabPattern: string) => {
46+
const { scheme: tabScheme, subdomain: tabSubdomain, domain: tabDomain } = getUrlAsObject(tabPattern);
47+
48+
const existingDomainRules = await getDomainStorageRulesFromUrl(tabPattern)
49+
50+
Object.entries(existingDomainRules).forEach(async ([storagePattern, rule]) => {
51+
const { scheme: storageScheme, subdomain: storageSubdomain, domain: storageDomain } = getUrlAsObject(storagePattern);
52+
cl({urlScheme: tabScheme, patternScheme: storageScheme, urlSubdomain: tabSubdomain, patternSubdomain: storageSubdomain, urlDomain: tabDomain, patternDomain: storageDomain}, Log.RULES, "Potential conflicted rules with: "+tabPattern)
53+
if (tabScheme !== storageScheme && tabSubdomain === storageSubdomain && tabDomain === storageDomain) {
54+
await removeJavascriptRule(rule)
55+
cl(`Conflicted rule removed: ${storagePattern} (conflict with url: ${tabPattern})`, Log.RULES)
56+
}
57+
if ((tabSubdomain === '*.' && storageSubdomain === '') && tabDomain === storageDomain) {
58+
console.warn(`Potential conflicted rule: ${storagePattern} (conflict with url: ${tabPattern})`)
59+
}
60+
})
61+
62+
//subdomain: `${scheme}${schemeSuffix}${subdomain}${domain}/*`,
63+
}
64+
65+
4466
export const removePrimaryPatternFromRules = (primaryPattern: string) => {};
4567

4668
export const setJavascriptRule = ({
@@ -71,6 +93,8 @@ export const setJavascriptRule = ({
7193
// } else {
7294
// await addJavascriptRule(rule);
7395
// }
96+
await removeConflictedRulesFromPattern(rule.primaryPattern)
97+
7498
await addJavascriptRule(rule);
7599
if (tab) {
76100
await updateIcon(tab); //not needed because we update tab
@@ -80,10 +104,42 @@ export const setJavascriptRule = ({
80104
});
81105
};
82106

107+
export const clearJavascriptRule = ({
108+
primaryPattern,
109+
scope,
110+
tab,
111+
}: {
112+
primaryPattern: QJS.ContentSettingRule["primaryPattern"];
113+
scope: QJS.ContentSettingRule["scope"];
114+
tab?: chrome.tabs.Tab;
115+
}) => {
116+
117+
return new Promise<void>(async (resolve, reject) => {
118+
const rule = {
119+
primaryPattern,
120+
scope,
121+
};
122+
123+
if (!isAllowedPattern(primaryPattern)) {
124+
return;
125+
}
126+
127+
// await removeConflictedRulesFromPattern(rule.primaryPattern)
128+
129+
await removeJavascriptRule(rule);
130+
if (tab) {
131+
await updateIcon(tab); //not needed because we update tab
132+
reloadTab(tab);
133+
}
134+
resolve();
135+
});
136+
}
137+
83138
export const addJavascriptRule = async (rule: QJS.ContentSettingRule) => {
84139
cl(rule, Log.RULES);
85-
return new Promise<void>((resolve, reject) => {
140+
return new Promise<void>(async (resolve, reject) => {
86141
console.log(chrome.contentSettings, "chrome.contentSettings");
142+
87143
chrome.contentSettings.javascript.set(rule, async () => {
88144
console.info(
89145
`${rule.setting} ${rule.primaryPattern} rule added to content settings`
@@ -114,9 +170,10 @@ export const rebaseJavascriptSettingsFromStorage = async () => {
114170
};
115171

116172
export const removeJavascriptRule = async (
117-
rule: Omit<QJS.ContentSettingRule, "setting">
173+
rule: Pick<QJS.ContentSettingRule, "primaryPattern" | "scope">
118174
) => {
119175
return new Promise<void>(async (resolve, reject) => {
176+
120177
const storageRules = await getStorageRules();
121178
if (
122179
storageRules &&

src/entry/background/contextmenus.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,7 @@ export const updateContextMenus = async () => {
467467
export const getDefaultShortcut = async () => {
468468
return new Promise((resolve, reject) => {
469469
chrome.commands.getAll((commands) => {
470-
console.log(commands, "commands");
470+
//console.info(commands, "commands");
471471
const shortcut =
472472
commands.find(
473473
// (command) => command.name === "_execute_bowser_action"

src/entry/background/state.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export const isPausedTab = async (tab: chrome.tabs.Tab) => {
4646
(stateTab) => stateTab && stateTab.id === tab.id && stateTab.paused === true
4747
);
4848

49-
cl(isPaused, undefined, "is paused?");
49+
//cl(isPaused, undefined, "is paused?");
5050
return isPaused;
5151
};
5252
export const isPausedTabs = async () => {

src/entry/background/storage.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { merge } from "lodash";
22
import { RuleSetting } from "./contentsettings";
33
import { getState, State } from "./state";
4-
import { cl, Log } from "./utils";
4+
import { cl, getDomainAndSubdomain, getUrlAsObject, Log } from "./utils";
55
import { Options } from "./_types";
66

77
// eslint-disable-next-line @typescript-eslint/no-namespace
@@ -98,6 +98,19 @@ export const getStorageRules = async () => {
9898
});
9999
};
100100

101+
export const getDomainStorageRulesFromUrl = async (url: string) => {
102+
const rules = await getStorageRules()
103+
return Object.entries(rules).reduce<QJS.ContentSettingRules>((acc, [pattern, setting]) => {
104+
const { domain: urlDomain } = getUrlAsObject(url);
105+
const { domain: patternDomain } = getUrlAsObject(pattern);
106+
107+
//const urlDomainAndSubdomain = getDomainAndSubdomain(url)
108+
cl(pattern, Log.STORAGE, 'Options rules contains primary url domain')
109+
//const isTrue = urlDomainAndSubdomain ? pattern.includes(urlDomainAndSubdomain) : false
110+
return urlDomain === patternDomain ? {...acc, ...{[pattern]: setting}} : acc
111+
}, {})
112+
}
113+
101114
export const getStorageOptions = async () => {
102115
return new Promise<Options>(async (resolve, reject) => {
103116
const options = ((await getStorage("options")) as Options) || {};

src/entry/background/utils.ts

Lines changed: 93 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ export const cl = (message: any, type?: Log, name?: string) => {
1616
[Log.ACTIONS]: true,
1717
[Log.TABS]: false,
1818
[Log.RULES]: true,
19-
[Log.STORAGE]: false,
20-
[Log.EVENTS]: false,
19+
[Log.STORAGE]: true,
20+
[Log.EVENTS]: true,
2121
[Log.ICON]: false,
2222
[Log.CONTEXT_MENUS]: false,
2323
};
@@ -113,30 +113,74 @@ export const getScopeSetting = (incognito: chrome.tabs.Tab["incognito"]) => {
113113
return incognito ? "incognito_session_only" : "regular";
114114
};
115115
export const getUrlAsObject = (url: string) => {
116-
const { domain, subdomain } = parse(url);
117-
const { pathname, protocol, hostname } = new URL(url);
116+
// Utiliser une regex pour capturer les différentes parties de l'URL manuellement
117+
const urlRegex = /^(.*?):\/\/([^\/]*)(\/?.*)$/;
118+
const matches = url.match(urlRegex);
118119

119-
/** http://, https:// etc... */
120-
const scheme = protocol.replace(/\:$/, "");
120+
let scheme = "";
121+
let hostname = "";
122+
let pathname = "";
121123

122-
const schemeSuffix = scheme === "file" ? ":///" : "://";
124+
if (matches) {
125+
scheme = matches[1]; // Récupérer le scheme (ex: http, https, *)
126+
hostname = matches[2]; // Récupérer le hostname (domaine + sous-domaine)
127+
pathname = matches[3]; // Récupérer le chemin (path)
128+
}
123129

130+
const schemeSuffix = scheme === "file" ? ":///" : "://";
124131
const pathnameUntilLastSlash = pathname.substr(0, pathname.lastIndexOf("/"));
125132

126-
const fixedSubdomain = subdomain && subdomain.length ? `${subdomain}.` : "";
133+
// Diviser le hostname en sous-domaine et domaine
134+
const domainParts = hostname.split(".");
135+
let domain = "";
136+
let subdomain = "";
137+
138+
if (domainParts.length > 2) {
139+
domain = domainParts.slice(-2).join(".");
140+
subdomain = domainParts.slice(0, -2).join(".");
141+
} else {
142+
domain = hostname;
143+
subdomain = "";
144+
}
145+
146+
const fixedSubdomain = subdomain.length ? `${subdomain}.` : "";
127147

128148
return {
129149
hostname,
130150
scheme,
131151
schemeSuffix,
132-
protocol,
133152
domain,
134153
subdomain: fixedSubdomain,
135154
pathname,
136155
path: pathname,
137156
pathnameUntilLastSlash,
138157
};
139158
};
159+
// export const getUrlAsObject = (url: string) => {
160+
// const { domain, subdomain } = parse(url);
161+
// const { pathname, protocol, hostname } = new URL(url);
162+
163+
// /** http://, https:// etc... */
164+
// const scheme = protocol.replace(/\:$/, "");
165+
166+
// const schemeSuffix = scheme === "file" ? ":///" : "://";
167+
168+
// const pathnameUntilLastSlash = pathname.substr(0, pathname.lastIndexOf("/"));
169+
170+
// const fixedSubdomain = subdomain && subdomain.length ? `${subdomain}.` : "";
171+
172+
// return {
173+
// hostname,
174+
// scheme,
175+
// schemeSuffix,
176+
// //protocol,
177+
// domain,
178+
// subdomain: fixedSubdomain,
179+
// pathname,
180+
// path: pathname,
181+
// pathnameUntilLastSlash,
182+
// };
183+
// };
140184

141185
export const isValidScheme = (scheme: string) => {
142186
return ["*", "http", "https", "file", "ftp", "urn"].includes(scheme)
@@ -201,3 +245,43 @@ export const retry = <T>(fn: () => Promise<T>, ms: number): Promise<T> =>
201245
}, ms);
202246
});
203247
});
248+
249+
export function sortUrlsByPatternPrecedence(urls: string[]) {
250+
// Fonction pour déterminer la priorité des motifs
251+
function getPatternScore(url: string) {
252+
let score = 0;
253+
254+
// Priorité par schéma (https > http)
255+
if (url.startsWith("https://")) score += 3;
256+
else if (url.startsWith("http://")) score += 2;
257+
258+
// Priorité par la spécificité du domaine
259+
const domainParts = url.split("/")[2].split(".");
260+
if (domainParts.length > 2) {
261+
// Plus le sous-domaine est spécifique, plus le score est élevé
262+
score += 1 * (domainParts.length - 2);
263+
}
264+
265+
// Priorité par longueur du chemin (plus c'est long, plus c'est spécifique)
266+
const pathLength = url.split("/").length - 3;
267+
score += pathLength;
268+
269+
return score;
270+
}
271+
272+
// Trier les URLs selon la priorité (score décroissant)
273+
return urls.sort((a, b) => getPatternScore(b) - getPatternScore(a));
274+
}
275+
276+
277+
export function getDomainAndSubdomain(url: string) {
278+
try {
279+
const parsedUrl = new URL(url);
280+
const hostname = parsedUrl.hostname;
281+
282+
return hostname;
283+
} catch (error) {
284+
console.error('Invalid url:', error);
285+
return null;
286+
}
287+
}

src/manifest.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
module.exports = {
22
manifest_version: 3,
33
name: "Quick Javascript Switcher",
4-
description: "The one-click JavaScript Switcher",
4+
description: "Disable JavaScript on any site in one click",
55
version: process.env.VUE_APP_VERSION.replace("-beta", ""),
66
minimum_chrome_version: "88.0",
77
homepage_url: "https://github.com/maximelebreton/quick-javascript-switcher",

src/view/options.vue

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -346,10 +346,8 @@ export default defineComponent({
346346
setup() {
347347
const { fetchRules } = useMethods();
348348
initState()
349-
const isMounted = ref(false)
350349
351350
onMounted(async () => {
352-
isMounted.value = true
353351
await fetchRules();
354352
355353
chrome.storage.onChanged.addListener(async () => {

0 commit comments

Comments
 (0)