refactor(packages): migrate to yarn workspaces
24
.commitlintrc
Normal file
@ -0,0 +1,24 @@
|
||||
{
|
||||
"extends": [
|
||||
"@commitlint/config-conventional"
|
||||
],
|
||||
"rules": {
|
||||
"scope-case": [
|
||||
0
|
||||
],
|
||||
"header-max-length": [
|
||||
0,
|
||||
"always",
|
||||
110
|
||||
],
|
||||
"scope-enum": [
|
||||
2,
|
||||
"always",
|
||||
[
|
||||
"browser-extension",
|
||||
"packages",
|
||||
"report-service"
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
6
.gitignore
vendored
@ -1,2 +1,6 @@
|
||||
.DS_Store
|
||||
release
|
||||
.pnp.*
|
||||
.yarn/*
|
||||
!.yarn/releases
|
||||
!.yarn/plugins
|
||||
build
|
||||
|
4
.husky/commit-msg
Executable file
@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
yarn commitlint --edit "$1"
|
4
.husky/pre-commit
Executable file
@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
yarn lint-staged
|
6
.lintstagedrc
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"packages/**/*.{js,ts}": [
|
||||
"prettier --loglevel=silent --write",
|
||||
"yarn lint"
|
||||
]
|
||||
}
|
6
.prettierrc
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"tabWidth": 2,
|
||||
"trailingComma": "es5"
|
||||
}
|
6
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"files.associations": {
|
||||
".commitlintrc": "json",
|
||||
".lintstagedrc": "json",
|
||||
},
|
||||
}
|
33
.yarn/plugins/@yarnpkg/plugin-outdated.cjs
vendored
Normal file
28
.yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs
vendored
Normal file
785
.yarn/releases/yarn-3.2.0.cjs
vendored
Executable file
7
.yarnrc.yml
Normal file
@ -0,0 +1,7 @@
|
||||
plugins:
|
||||
- path: .yarn/plugins/@yarnpkg/plugin-outdated.cjs
|
||||
spec: "https://mskelton.dev/yarn-outdated/v2"
|
||||
- path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs
|
||||
spec: "@yarnpkg/plugin-workspace-tools"
|
||||
|
||||
yarnPath: .yarn/releases/yarn-3.2.0.cjs
|
@ -2,46 +2,7 @@
|
||||
|
||||
A browser extension that eats cookie consent dialogs.
|
||||
|
||||
## Downloads
|
||||
## Repositories
|
||||
|
||||
- [Chrome Web Store](https://chrome.google.com/webstore/detail/djcbfpkdhdkaflcigibkbpboflaplabg)
|
||||
- [Firefox Add-ons](https://addons.mozilla.org/firefox/addon/cookie-dialog-monster/)
|
||||
|
||||
## Compatibility
|
||||
|
||||
- Google Chrome 51+.
|
||||
- Microsoft Edge 15+.
|
||||
- Mozilla Firefox 54+.
|
||||
- Opera 38+.
|
||||
|
||||
## Installation (on Google Chrome)
|
||||
|
||||
1. Clone this repository.
|
||||
2. Go to [chrome://extensions](chrome://extensions).
|
||||
3. Enable **Developer mode** by clicking the toggle switch next to **Developer Mode**.
|
||||
4. Then, click the **LOAD UNPACKED** button and select the cloned folder.
|
||||
5. That's all, you have a development build of this extension.
|
||||
|
||||
## Installation (on Mozilla Firefox)
|
||||
|
||||
1. Clone this repository.
|
||||
2. Go to [about:debugging](about:debugging).
|
||||
3. Enter **This Firefox** section.
|
||||
4. Then, click the **LOAD TEMPORARY ADD-ON** button and select any file inside the cloned folder.
|
||||
5. That's all, you have a development build of this extension.
|
||||
|
||||
## Installation (on Microsoft Edge)
|
||||
|
||||
1. Clone this repository.
|
||||
2. Go to [edge://extensions](edge://extensions).
|
||||
3. Enable **Developer mode** by clicking the toggle switch next to **Developer Mode**.
|
||||
4. Then, click the **LOAD UNPACKED** button and select the cloned folder.
|
||||
5. That's all, you have a development build of this extension.
|
||||
|
||||
## Contributing
|
||||
|
||||
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
|
||||
|
||||
## License
|
||||
|
||||
[MIT](https://choosealicense.com/licenses/mit/)
|
||||
- [Browser extension](/packages/browser-extension/)
|
||||
- [Report service](/packages/report-service/)
|
||||
|
21
package.json
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "cookie-dialog-monster",
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"build": "yarn workspaces foreach -p run build",
|
||||
"lint": "yarn workspaces foreach -p run lint",
|
||||
"prepare": "husky install"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "^16.2.4",
|
||||
"@commitlint/config-conventional": "^16.2.4",
|
||||
"husky": "^7.0.4",
|
||||
"lint-staged": "^12.4.1",
|
||||
"prettier": "^2.6.2"
|
||||
},
|
||||
"workspaces": [
|
||||
"packages/*"
|
||||
],
|
||||
"packageManager": "yarn@3.2.0"
|
||||
}
|
12
packages/browser-extension/.eslintrc
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"env": {
|
||||
"es6": true
|
||||
},
|
||||
"extends": [
|
||||
"plugin:prettier/recommended"
|
||||
],
|
||||
"parserOptions": {
|
||||
"ecmaVersion": "latest"
|
||||
}
|
||||
}
|
||||
|
45
packages/browser-extension/docs/README.md
Normal file
@ -0,0 +1,45 @@
|
||||
# Cookie Monster Dialog Browser Extension
|
||||
|
||||
## Downloads
|
||||
|
||||
- [Chrome Web Store](https://chrome.google.com/webstore/detail/djcbfpkdhdkaflcigibkbpboflaplabg)
|
||||
- [Firefox Add-ons](https://addons.mozilla.org/firefox/addon/cookie-dialog-monster/)
|
||||
|
||||
## Compatibility
|
||||
|
||||
- Google Chrome 51+.
|
||||
- Microsoft Edge 15+.
|
||||
- Mozilla Firefox 54+.
|
||||
- Opera 38+.
|
||||
|
||||
## Installation (on Google Chrome)
|
||||
|
||||
1. Clone this repository.
|
||||
2. Go to [chrome://extensions](chrome://extensions).
|
||||
3. Enable **Developer mode** by clicking the toggle switch next to **Developer Mode**.
|
||||
4. Then, click the **LOAD UNPACKED** button and select the cloned folder.
|
||||
5. That's all, you have a development build of this extension.
|
||||
|
||||
## Installation (on Mozilla Firefox)
|
||||
|
||||
1. Clone this repository.
|
||||
2. Go to [about:debugging](about:debugging).
|
||||
3. Enter **This Firefox** section.
|
||||
4. Then, click the **LOAD TEMPORARY ADD-ON** button and select any file inside the cloned folder.
|
||||
5. That's all, you have a development build of this extension.
|
||||
|
||||
## Installation (on Microsoft Edge)
|
||||
|
||||
1. Clone this repository.
|
||||
2. Go to [edge://extensions](edge://extensions).
|
||||
3. Enable **Developer mode** by clicking the toggle switch next to **Developer Mode**.
|
||||
4. Then, click the **LOAD UNPACKED** button and select the cloned folder.
|
||||
5. That's all, you have a development build of this extension.
|
||||
|
||||
## Contributing
|
||||
|
||||
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
|
||||
|
||||
## License
|
||||
|
||||
[MIT](https://choosealicense.com/licenses/mit/)
|
18
packages/browser-extension/package.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "browser-extension",
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"build": "exit 1",
|
||||
"lint": "eslint src/**/*.js --fix"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "^8.8.0",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-plugin-prettier": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "16.x"
|
||||
},
|
||||
"packageManager": "yarn@3.2.0",
|
||||
"license": "MIT"
|
||||
}
|
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 6.5 KiB |
Before Width: | Height: | Size: 1016 B After Width: | Height: | Size: 1016 B |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
@ -2,7 +2,7 @@
|
||||
* @description Context menu identifier
|
||||
*/
|
||||
|
||||
const contextMenuId = "CDM_MENU";
|
||||
const contextMenuId = 'CDM_MENU';
|
||||
|
||||
/**
|
||||
* @description Cache initial state
|
||||
@ -18,7 +18,7 @@ const initial = {
|
||||
* @param {object} [cache]
|
||||
*/
|
||||
|
||||
const check = (cache) => typeof cache.enabled === "boolean";
|
||||
const check = (cache) => typeof cache.enabled === 'boolean';
|
||||
|
||||
/**
|
||||
* @description Disables icon
|
||||
@ -27,7 +27,7 @@ const check = (cache) => typeof cache.enabled === "boolean";
|
||||
|
||||
const disableIcon = (tabId) => {
|
||||
chrome.browserAction.setIcon({
|
||||
path: "assets/icons/disabled.png",
|
||||
path: 'assets/icons/disabled.png',
|
||||
tabId,
|
||||
});
|
||||
};
|
||||
@ -39,7 +39,7 @@ const disableIcon = (tabId) => {
|
||||
|
||||
const disablePopup = (tabId) => {
|
||||
chrome.browserAction.setPopup({
|
||||
popup: "",
|
||||
popup: '',
|
||||
tabId,
|
||||
});
|
||||
};
|
||||
@ -51,7 +51,7 @@ const disablePopup = (tabId) => {
|
||||
|
||||
const enableIcon = (tabId) => {
|
||||
chrome.browserAction.setIcon({
|
||||
path: "assets/icons/enabled.png",
|
||||
path: 'assets/icons/enabled.png',
|
||||
tabId,
|
||||
});
|
||||
};
|
||||
@ -63,7 +63,7 @@ const enableIcon = (tabId) => {
|
||||
|
||||
const enablePopup = (tabId) => {
|
||||
chrome.browserAction.setPopup({
|
||||
popup: "popup.html",
|
||||
popup: 'popup.html',
|
||||
tabId,
|
||||
});
|
||||
};
|
||||
@ -100,13 +100,13 @@ const getCache = (hostname, callback) => {
|
||||
const getClasses = async (callback) => {
|
||||
try {
|
||||
const url =
|
||||
"https://raw.githubusercontent.com/wanhose/cookie-dialog-monster/master/data/classes.txt";
|
||||
'https://raw.githubusercontent.com/wanhose/cookie-dialog-monster/master/data/classes.txt';
|
||||
const response = await fetch(url);
|
||||
const data = await response.text();
|
||||
|
||||
if (response.status !== 200) throw new Error();
|
||||
|
||||
callback({ classes: data.split("\n") });
|
||||
callback({ classes: data.split('\n') });
|
||||
} catch {
|
||||
callback({ classes: [] });
|
||||
}
|
||||
@ -122,13 +122,13 @@ const getClasses = async (callback) => {
|
||||
const getFixes = async (callback) => {
|
||||
try {
|
||||
const url =
|
||||
"https://raw.githubusercontent.com/wanhose/cookie-dialog-monster/master/data/fixes.txt";
|
||||
'https://raw.githubusercontent.com/wanhose/cookie-dialog-monster/master/data/fixes.txt';
|
||||
const response = await fetch(url);
|
||||
const data = await response.text();
|
||||
|
||||
if (response.status !== 200) throw new Error();
|
||||
|
||||
callback({ fixes: data.split("\n") });
|
||||
callback({ fixes: data.split('\n') });
|
||||
} catch {
|
||||
callback({ fixes: [] });
|
||||
}
|
||||
@ -144,13 +144,13 @@ const getFixes = async (callback) => {
|
||||
const getSelectors = async (callback) => {
|
||||
try {
|
||||
const url =
|
||||
"https://raw.githubusercontent.com/wanhose/cookie-dialog-monster/master/data/elements.txt";
|
||||
'https://raw.githubusercontent.com/wanhose/cookie-dialog-monster/master/data/elements.txt';
|
||||
const response = await fetch(url);
|
||||
const data = await response.text();
|
||||
|
||||
if (response.status !== 200) throw new Error();
|
||||
|
||||
callback({ selectors: data.split("\n") });
|
||||
callback({ selectors: data.split('\n') });
|
||||
} catch {
|
||||
callback({ selectors: [] });
|
||||
}
|
||||
@ -182,16 +182,16 @@ const report = () => {
|
||||
const version = chrome.runtime.getManifest().version;
|
||||
|
||||
if (tab) {
|
||||
fetch("https://cdm-report-service.herokuapp.com/rest/v1/report/", {
|
||||
fetch('https://cdm-report-service.herokuapp.com/rest/v1/report/', {
|
||||
body: JSON.stringify({
|
||||
text: `There's a problem with ${tab.url} using ${userAgent} in CDM ${version}`,
|
||||
to: "wanhose.development@gmail.com",
|
||||
subject: "Cookie Dialog Monster Report",
|
||||
to: 'wanhose.development@gmail.com',
|
||||
subject: 'Cookie Dialog Monster Report',
|
||||
}),
|
||||
headers: {
|
||||
"Content-type": "application/json",
|
||||
'Content-type': 'application/json',
|
||||
},
|
||||
method: "POST",
|
||||
method: 'POST',
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -210,7 +210,7 @@ const updateCache = (hostname, state) => {
|
||||
chrome.storage.local.set({
|
||||
[hostname]: {
|
||||
enabled:
|
||||
typeof state.enabled === "undefined"
|
||||
typeof state.enabled === 'undefined'
|
||||
? current.enabled
|
||||
: state.enabled,
|
||||
},
|
||||
@ -227,34 +227,34 @@ chrome.runtime.onMessage.addListener((request, sender, callback) => {
|
||||
let tabId = sender.tab ? sender.tab.id : undefined;
|
||||
|
||||
switch (request.type) {
|
||||
case "DISABLE_ICON":
|
||||
case 'DISABLE_ICON':
|
||||
if (hasPermission && tabId) disableIcon(tabId);
|
||||
break;
|
||||
case "DISABLE_POPUP":
|
||||
case 'DISABLE_POPUP':
|
||||
if (hasPermission && tabId) disablePopup(tabId);
|
||||
break;
|
||||
case "ENABLE_ICON":
|
||||
case 'ENABLE_ICON':
|
||||
if (hasPermission && tabId) enableIcon(tabId);
|
||||
break;
|
||||
case "ENABLE_POPUP":
|
||||
case 'ENABLE_POPUP':
|
||||
if (hasPermission && tabId) enablePopup(tabId);
|
||||
break;
|
||||
case "GET_CACHE":
|
||||
case 'GET_CACHE':
|
||||
getCache(request.hostname, callback);
|
||||
break;
|
||||
case "GET_CLASSES":
|
||||
case 'GET_CLASSES':
|
||||
getClasses(callback);
|
||||
break;
|
||||
case "GET_FIXES":
|
||||
case 'GET_FIXES':
|
||||
getFixes(callback);
|
||||
break;
|
||||
case "GET_SELECTORS":
|
||||
case 'GET_SELECTORS':
|
||||
getSelectors(callback);
|
||||
break;
|
||||
case "GET_TAB":
|
||||
case 'GET_TAB':
|
||||
getTab(callback);
|
||||
break;
|
||||
case "UPDATE_CACHE":
|
||||
case 'UPDATE_CACHE':
|
||||
updateCache(request.hostname, request.state);
|
||||
break;
|
||||
default:
|
||||
@ -269,9 +269,9 @@ chrome.runtime.onMessage.addListener((request, sender, callback) => {
|
||||
*/
|
||||
|
||||
chrome.contextMenus.create({
|
||||
contexts: ["all"],
|
||||
contexts: ['all'],
|
||||
id: contextMenuId,
|
||||
title: chrome.i18n.getMessage("contextMenuText"),
|
||||
title: chrome.i18n.getMessage('contextMenuText'),
|
||||
});
|
||||
|
||||
/**
|
@ -30,7 +30,7 @@ const hostname = document.location.hostname;
|
||||
*/
|
||||
|
||||
const isPreview =
|
||||
hostname.startsWith("consent.") || hostname.startsWith("myprivacy.");
|
||||
hostname.startsWith('consent.') || hostname.startsWith('myprivacy.');
|
||||
|
||||
/**
|
||||
* @description Options provided to observer
|
||||
@ -59,8 +59,8 @@ const target = document.body || document.documentElement;
|
||||
const check = (node) =>
|
||||
node instanceof HTMLElement &&
|
||||
node.parentElement &&
|
||||
!["BODY", "HTML"].includes(node.tagName) &&
|
||||
!(node.id && ["APP", "ROOT"].includes(node.id.toUpperCase?.()));
|
||||
!['BODY', 'HTML'].includes(node.tagName) &&
|
||||
!(node.id && ['APP', 'ROOT'].includes(node.id.toUpperCase?.()));
|
||||
|
||||
/**
|
||||
* @description Cleans DOM
|
||||
@ -69,7 +69,7 @@ const check = (node) =>
|
||||
const clean = () => {
|
||||
if (selectors.length) {
|
||||
const nodes = Array.from(document.querySelectorAll(selectors));
|
||||
nodes.filter(check).forEach((node) => (node.outerHTML = ""));
|
||||
nodes.filter(check).forEach((node) => (node.outerHTML = ''));
|
||||
}
|
||||
};
|
||||
|
||||
@ -82,30 +82,30 @@ const fix = () => {
|
||||
const html = document.documentElement;
|
||||
|
||||
body?.classList.remove(...classes);
|
||||
body?.style.setProperty("position", "initial", "important");
|
||||
body?.style.setProperty("overflow-y", "initial", "important");
|
||||
body?.style.setProperty('position', 'initial', 'important');
|
||||
body?.style.setProperty('overflow-y', 'initial', 'important');
|
||||
html?.classList.remove(...classes);
|
||||
html?.style.setProperty("position", "initial", "important");
|
||||
html?.style.setProperty("overflow-y", "initial", "important");
|
||||
html?.style.setProperty('position', 'initial', 'important');
|
||||
html?.style.setProperty('overflow-y', 'initial', 'important');
|
||||
|
||||
fixes.forEach((fix) => {
|
||||
const [match, selector, action, property] = fix.split("##");
|
||||
const [match, selector, action, property] = fix.split('##');
|
||||
|
||||
if (hostname.includes(match)) {
|
||||
switch (action) {
|
||||
case "click": {
|
||||
case 'click': {
|
||||
const node = document.querySelector(selector);
|
||||
node?.click();
|
||||
}
|
||||
case "remove": {
|
||||
case 'remove': {
|
||||
const node = document.querySelector(selector);
|
||||
node?.style?.removeProperty(property);
|
||||
}
|
||||
case "reset": {
|
||||
case 'reset': {
|
||||
const node = document.querySelector(selector);
|
||||
node?.style?.setProperty(property, "initial", "important");
|
||||
node?.style?.setProperty(property, 'initial', 'important');
|
||||
}
|
||||
case "resetAll": {
|
||||
case 'resetAll': {
|
||||
const nodes = document.querySelectorAll(selector);
|
||||
// prettier-ignore
|
||||
nodes.forEach((node) => node?.style?.setProperty(property, "initial", "important"));
|
||||
@ -126,7 +126,7 @@ const observer = new MutationObserver((mutations, instance) => {
|
||||
for (const node of mutation.addedNodes) {
|
||||
const valid = check(node);
|
||||
|
||||
if (valid && node.matches(selectors)) node.outerHTML = "";
|
||||
if (valid && node.matches(selectors)) node.outerHTML = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -141,7 +141,7 @@ const observer = new MutationObserver((mutations, instance) => {
|
||||
|
||||
const queryClasses = () =>
|
||||
new Promise((resolve) => {
|
||||
dispatch({ type: "GET_CLASSES" }, null, resolve);
|
||||
dispatch({ type: 'GET_CLASSES' }, null, resolve);
|
||||
});
|
||||
|
||||
/**
|
||||
@ -151,7 +151,7 @@ const queryClasses = () =>
|
||||
|
||||
const queryFixes = () =>
|
||||
new Promise((resolve) => {
|
||||
dispatch({ type: "GET_FIXES" }, null, resolve);
|
||||
dispatch({ type: 'GET_FIXES' }, null, resolve);
|
||||
});
|
||||
|
||||
/**
|
||||
@ -161,7 +161,7 @@ const queryFixes = () =>
|
||||
|
||||
const querySelectors = () =>
|
||||
new Promise((resolve) => {
|
||||
dispatch({ type: "GET_SELECTORS" }, null, resolve);
|
||||
dispatch({ type: 'GET_SELECTORS' }, null, resolve);
|
||||
});
|
||||
|
||||
/**
|
||||
@ -169,9 +169,9 @@ const querySelectors = () =>
|
||||
* @listens document#readystatechange
|
||||
*/
|
||||
|
||||
document.addEventListener("readystatechange", () => {
|
||||
dispatch({ hostname, type: "GET_CACHE" }, null, async ({ enabled }) => {
|
||||
if (document.readyState === "complete" && enabled && !isPreview) {
|
||||
document.addEventListener('readystatechange', () => {
|
||||
dispatch({ hostname, type: 'GET_CACHE' }, null, async ({ enabled }) => {
|
||||
if (document.readyState === 'complete' && enabled && !isPreview) {
|
||||
fix();
|
||||
clean();
|
||||
setTimeout(clean, 2000);
|
||||
@ -184,14 +184,14 @@ document.addEventListener("readystatechange", () => {
|
||||
* @listens window#unload
|
||||
*/
|
||||
|
||||
window.addEventListener("unload", () => {});
|
||||
window.addEventListener('unload', () => {});
|
||||
|
||||
/**
|
||||
* @description Setups everything and starts to observe if enabled
|
||||
*/
|
||||
|
||||
dispatch({ hostname, type: "GET_CACHE" }, null, async ({ enabled }) => {
|
||||
dispatch({ type: "ENABLE_POPUP" });
|
||||
dispatch({ hostname, type: 'GET_CACHE' }, null, async ({ enabled }) => {
|
||||
dispatch({ type: 'ENABLE_POPUP' });
|
||||
|
||||
if (enabled) {
|
||||
const promises = [queryClasses(), queryFixes(), querySelectors()];
|
||||
@ -201,6 +201,6 @@ dispatch({ hostname, type: "GET_CACHE" }, null, async ({ enabled }) => {
|
||||
fixes = results[1]?.fixes ?? [];
|
||||
selectors = results[2]?.selectors ?? [];
|
||||
observer.observe(target, options);
|
||||
dispatch({ type: "ENABLE_ICON" });
|
||||
dispatch({ type: 'ENABLE_ICON' });
|
||||
}
|
||||
});
|
139
packages/browser-extension/src/scripts/popup.js
Normal file
@ -0,0 +1,139 @@
|
||||
/**
|
||||
* @constant chromeUrl
|
||||
* @description Chrome Web Store link
|
||||
* @type {string}
|
||||
*/
|
||||
|
||||
const chromeUrl =
|
||||
'https://chrome.google.com/webstore/detail/djcbfpkdhdkaflcigibkbpboflaplabg';
|
||||
|
||||
/**
|
||||
* @constant dispatch
|
||||
* @description Shortcut to send messages to background script
|
||||
* @type {void}
|
||||
*/
|
||||
|
||||
const dispatch = chrome.runtime.sendMessage;
|
||||
|
||||
/**
|
||||
* @constant firefoxUrl
|
||||
* @description Firefox Add-ons link
|
||||
* @type {string}
|
||||
*/
|
||||
|
||||
const firefoxUrl =
|
||||
'https://addons.mozilla.org/es/firefox/addon/cookie-dialog-monster/';
|
||||
|
||||
/**
|
||||
* @constant isChromium
|
||||
* @description Is current browser an instance of Chromium?
|
||||
* @type {boolean}
|
||||
*/
|
||||
|
||||
const isChromium = chrome.runtime.getURL('').startsWith('chrome-extension://');
|
||||
|
||||
/**
|
||||
* @description Disables or enables extension on current page
|
||||
*/
|
||||
|
||||
const handlePowerChange = () => {
|
||||
dispatch({ type: 'GET_TAB' }, null, ({ hostname, id }) => {
|
||||
dispatch({ hostname, type: 'GET_CACHE' }, null, ({ enabled }) => {
|
||||
const power = document.getElementById('power');
|
||||
|
||||
dispatch({
|
||||
hostname,
|
||||
state: { enabled: !enabled },
|
||||
type: 'UPDATE_CACHE',
|
||||
});
|
||||
dispatch({
|
||||
type: !enabled === true ? 'ENABLE_ICON' : 'DISABLE_ICON',
|
||||
});
|
||||
if (!enabled === false) power.removeAttribute('checked');
|
||||
if (!enabled === true) power.setAttribute('checked', 'checked');
|
||||
chrome.tabs.reload(id, { bypassCache: true });
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @description Reload current page
|
||||
*/
|
||||
|
||||
const handleReload = () => {
|
||||
dispatch({ type: 'GET_TAB' }, null, ({ id }) => {
|
||||
chrome.tabs.reload(id, { bypassCache: true });
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @description Shows negative or positive messages
|
||||
* @param {MouseEvent} event
|
||||
*/
|
||||
|
||||
const handleRate = (event) => {
|
||||
const negative = document.getElementById('negative');
|
||||
const positive = document.getElementById('positive');
|
||||
|
||||
switch (event.currentTarget.id) {
|
||||
case 'unlike':
|
||||
positive.setAttribute('hidden', 'true');
|
||||
negative.removeAttribute('hidden');
|
||||
break;
|
||||
case 'like':
|
||||
negative.setAttribute('hidden', 'true');
|
||||
positive.removeAttribute('hidden');
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @description Setup stars handlers and result message links
|
||||
*/
|
||||
|
||||
const handleContentLoaded = () => {
|
||||
dispatch({ type: 'GET_TAB' }, null, ({ hostname }) => {
|
||||
dispatch({ hostname, type: 'GET_CACHE' }, null, ({ enabled }) => {
|
||||
translate();
|
||||
|
||||
const host = document.getElementById('host');
|
||||
const like = document.getElementById('like');
|
||||
const power = document.getElementById('power');
|
||||
const reload = document.getElementById('reload');
|
||||
const store = document.getElementById('store');
|
||||
const unlike = document.getElementById('unlike');
|
||||
|
||||
like.addEventListener('click', handleRate);
|
||||
power.addEventListener('change', handlePowerChange);
|
||||
reload.addEventListener('click', handleReload);
|
||||
store.setAttribute('href', isChromium ? chromeUrl : firefoxUrl);
|
||||
unlike.addEventListener('click', handleRate);
|
||||
if (location) host.innerText = hostname.replace('www.', '');
|
||||
if (!enabled) power.removeAttribute('checked');
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @description Applies translations to tags with i18n data attribute
|
||||
*/
|
||||
|
||||
const translate = () => {
|
||||
const nodes = document.querySelectorAll('[data-i18n]');
|
||||
|
||||
for (let i = nodes.length; i--; ) {
|
||||
const node = nodes[i];
|
||||
const { i18n } = node.dataset;
|
||||
|
||||
node.innerHTML = chrome.i18n.getMessage(i18n);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @description Listen to document ready
|
||||
* @listens document#ready
|
||||
*/
|
||||
|
||||
document.addEventListener('DOMContentLoaded', handleContentLoaded);
|
3
packages/report-service/.env
Normal file
@ -0,0 +1,3 @@
|
||||
CHROME_EXTENSION_ID=?
|
||||
MAIL_PASS=?
|
||||
MAIL_USER=?
|
19
packages/report-service/.eslintrc
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"env": {
|
||||
"es6": true,
|
||||
"jest": true,
|
||||
"node": true
|
||||
},
|
||||
"extends": [
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:prettier/recommended"
|
||||
],
|
||||
"globals": {
|
||||
"Atomics": "readonly",
|
||||
"SharedArrayBuffer": "readonly"
|
||||
},
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": "latest"
|
||||
}
|
||||
}
|
21
packages/report-service/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License Copyright (c) 2020 Juan José Vílchez Naranjo
|
||||
|
||||
Permission is hereby
|
||||
granted, free of charge, to any person obtaining a copy of this software and
|
||||
associated documentation files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to the
|
||||
following conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
(including the next paragraph) shall be included in all copies or substantial
|
||||
portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
|
||||
EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
9
packages/report-service/docs/README.md
Normal file
@ -0,0 +1,9 @@
|
||||
# Cookie Monster Dialog Report Service
|
||||
|
||||
## Contributing
|
||||
|
||||
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
|
||||
|
||||
## License
|
||||
|
||||
[MIT](https://choosealicense.com/licenses/mit/)
|
6
packages/report-service/nodemon.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"exec": "ts-node -r tsconfig-paths/register ./src/index.ts",
|
||||
"ext": ".ts",
|
||||
"ignore": [],
|
||||
"watch": ["src"]
|
||||
}
|
38
packages/report-service/package.json
Normal file
@ -0,0 +1,38 @@
|
||||
{
|
||||
"name": "report-service",
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"build": "rimraf build && tsc",
|
||||
"dev": "nodemon",
|
||||
"lint": "eslint src/**/*.ts --fix",
|
||||
"setup": "rimraf .husky && husky install && husky add .husky/pre-commit \"yarn lint-staged\" && husky add .husky/commit-msg 'npx --no -- commitlint --edit \"$1\"'",
|
||||
"start": "NODE_PATH=build node build/index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"dotenv": "^16.0.0",
|
||||
"fastify": "^3.27.1",
|
||||
"fastify-cors": "^6.0.2",
|
||||
"fastify-rate-limit": "^5.7.0",
|
||||
"nodemailer": "^6.7.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tsconfig/node16": "^1.0.2",
|
||||
"@types/node": "^17.0.16",
|
||||
"@types/nodemailer": "^6.4.4",
|
||||
"@typescript-eslint/eslint-plugin": "^5.11.0",
|
||||
"@typescript-eslint/parser": "^5.11.0",
|
||||
"eslint": "^8.8.0",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"nodemon": "^2.0.15",
|
||||
"rimraf": "^3.0.2",
|
||||
"ts-node": "^10.5.0",
|
||||
"tsconfig-paths": "^3.12.0",
|
||||
"typescript": "^4.5.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": "16.x"
|
||||
},
|
||||
"packageManager": "yarn@3.2.0",
|
||||
"license": "MIT"
|
||||
}
|
37
packages/report-service/src/index.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import fastify from 'fastify';
|
||||
import cors from 'fastify-cors';
|
||||
import rateLimit from 'fastify-rate-limit';
|
||||
import v1ReportRoutes from 'routes/v1/report';
|
||||
import environment from 'services/environment';
|
||||
|
||||
const server = fastify({ logger: true });
|
||||
|
||||
server.register(cors, {
|
||||
origin: (origin, callback) => {
|
||||
const moz =
|
||||
/moz-extension:\/\/[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}/g;
|
||||
|
||||
switch (true) {
|
||||
case environment.extension.chrome === origin:
|
||||
case moz.test(origin):
|
||||
callback(null, true);
|
||||
break;
|
||||
default:
|
||||
callback(new Error('Not allowed'), false);
|
||||
break;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
server.register(rateLimit, { max: 1, timeWindow: 30000 });
|
||||
|
||||
server.register(v1ReportRoutes, { prefix: '/rest/v1' });
|
||||
|
||||
server.listen(environment.port, '0.0.0.0', (error, address) => {
|
||||
if (error) {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(`Server listening at ${address}`);
|
||||
});
|
45
packages/report-service/src/routes/v1/report.ts
Normal file
@ -0,0 +1,45 @@
|
||||
import { FastifyInstance, RouteShorthandOptions } from 'fastify';
|
||||
import { sendMail } from 'services/mailing';
|
||||
|
||||
type PostReportBody = {
|
||||
subject: string;
|
||||
text: string;
|
||||
to: string;
|
||||
};
|
||||
|
||||
export default (
|
||||
server: FastifyInstance,
|
||||
options: RouteShorthandOptions,
|
||||
done: () => void
|
||||
) => {
|
||||
server.post<{ Body: PostReportBody }>(
|
||||
'/report/',
|
||||
{
|
||||
schema: {
|
||||
body: {
|
||||
properties: {
|
||||
subject: {
|
||||
type: 'string',
|
||||
},
|
||||
text: {
|
||||
type: 'string',
|
||||
},
|
||||
to: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
required: ['subject', 'text', 'to'],
|
||||
type: 'object',
|
||||
},
|
||||
},
|
||||
},
|
||||
async (request, reply) => {
|
||||
const { subject, text, to } = request.body;
|
||||
|
||||
sendMail({ text, to, subject });
|
||||
reply.send({ success: true });
|
||||
}
|
||||
);
|
||||
|
||||
done();
|
||||
};
|
14
packages/report-service/src/services/environment.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import dotenv from 'dotenv';
|
||||
|
||||
dotenv.config();
|
||||
|
||||
export default {
|
||||
extension: {
|
||||
chrome: process.env.CHROME_EXTENSION_ID ?? '',
|
||||
},
|
||||
mail: {
|
||||
pass: process.env.MAIL_PASS ?? '',
|
||||
user: process.env.MAIL_USER ?? '',
|
||||
},
|
||||
port: process.env.PORT ?? 8080,
|
||||
};
|
12
packages/report-service/src/services/mailing.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import nodemailer, { SendMailOptions } from 'nodemailer';
|
||||
import environment from './environment';
|
||||
|
||||
const mailing = nodemailer.createTransport({
|
||||
auth: { pass: environment.mail.pass, user: environment.mail.user },
|
||||
host: 'smtp.zoho.eu',
|
||||
port: 465,
|
||||
secure: true,
|
||||
});
|
||||
|
||||
export const sendMail = (options: SendMailOptions) =>
|
||||
mailing.sendMail({ ...options, from: environment.mail.user }, () => null);
|
12
packages/report-service/tsconfig.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": "src",
|
||||
"outDir": "build",
|
||||
"rootDir": "src"
|
||||
},
|
||||
"extends": "@tsconfig/node16/tsconfig.json",
|
||||
"include": ["src/**/*.ts"],
|
||||
"ts-node": {
|
||||
"files": true
|
||||
}
|
||||
}
|
139
scripts/popup.js
@ -1,139 +0,0 @@
|
||||
/**
|
||||
* @constant chromeUrl
|
||||
* @description Chrome Web Store link
|
||||
* @type {string}
|
||||
*/
|
||||
|
||||
const chromeUrl =
|
||||
"https://chrome.google.com/webstore/detail/djcbfpkdhdkaflcigibkbpboflaplabg";
|
||||
|
||||
/**
|
||||
* @constant dispatch
|
||||
* @description Shortcut to send messages to background script
|
||||
* @type {void}
|
||||
*/
|
||||
|
||||
const dispatch = chrome.runtime.sendMessage;
|
||||
|
||||
/**
|
||||
* @constant firefoxUrl
|
||||
* @description Firefox Add-ons link
|
||||
* @type {string}
|
||||
*/
|
||||
|
||||
const firefoxUrl =
|
||||
"https://addons.mozilla.org/es/firefox/addon/cookie-dialog-monster/";
|
||||
|
||||
/**
|
||||
* @constant isChromium
|
||||
* @description Is current browser an instance of Chromium?
|
||||
* @type {boolean}
|
||||
*/
|
||||
|
||||
const isChromium = chrome.runtime.getURL("").startsWith("chrome-extension://");
|
||||
|
||||
/**
|
||||
* @description Disables or enables extension on current page
|
||||
*/
|
||||
|
||||
const handlePowerChange = () => {
|
||||
dispatch({ type: "GET_TAB" }, null, ({ hostname, id }) => {
|
||||
dispatch({ hostname, type: "GET_CACHE" }, null, ({ enabled }) => {
|
||||
const power = document.getElementById("power");
|
||||
|
||||
dispatch({
|
||||
hostname,
|
||||
state: { enabled: !enabled },
|
||||
type: "UPDATE_CACHE",
|
||||
});
|
||||
dispatch({
|
||||
type: !enabled === true ? "ENABLE_ICON" : "DISABLE_ICON",
|
||||
});
|
||||
if (!enabled === false) power.removeAttribute("checked");
|
||||
if (!enabled === true) power.setAttribute("checked", "checked");
|
||||
chrome.tabs.reload(id, { bypassCache: true });
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @description Reload current page
|
||||
*/
|
||||
|
||||
const handleReload = () => {
|
||||
dispatch({ type: "GET_TAB" }, null, ({ id }) => {
|
||||
chrome.tabs.reload(id, { bypassCache: true });
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @description Shows negative or positive messages
|
||||
* @param {MouseEvent} event
|
||||
*/
|
||||
|
||||
const handleRate = (event) => {
|
||||
const negative = document.getElementById("negative");
|
||||
const positive = document.getElementById("positive");
|
||||
|
||||
switch (event.currentTarget.id) {
|
||||
case "unlike":
|
||||
positive.setAttribute("hidden", "true");
|
||||
negative.removeAttribute("hidden");
|
||||
break;
|
||||
case "like":
|
||||
negative.setAttribute("hidden", "true");
|
||||
positive.removeAttribute("hidden");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @description Setup stars handlers and result message links
|
||||
*/
|
||||
|
||||
const handleContentLoaded = () => {
|
||||
dispatch({ type: "GET_TAB" }, null, ({ hostname }) => {
|
||||
dispatch({ hostname, type: "GET_CACHE" }, null, ({ enabled }) => {
|
||||
translate();
|
||||
|
||||
const host = document.getElementById("host");
|
||||
const like = document.getElementById("like");
|
||||
const power = document.getElementById("power");
|
||||
const reload = document.getElementById("reload");
|
||||
const store = document.getElementById("store");
|
||||
const unlike = document.getElementById("unlike");
|
||||
|
||||
like.addEventListener("click", handleRate);
|
||||
power.addEventListener("change", handlePowerChange);
|
||||
reload.addEventListener("click", handleReload);
|
||||
store.setAttribute("href", isChromium ? chromeUrl : firefoxUrl);
|
||||
unlike.addEventListener("click", handleRate);
|
||||
if (location) host.innerText = hostname.replace("www.", "");
|
||||
if (!enabled) power.removeAttribute("checked");
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @description Applies translations to tags with i18n data attribute
|
||||
*/
|
||||
|
||||
const translate = () => {
|
||||
const nodes = document.querySelectorAll("[data-i18n]");
|
||||
|
||||
for (let i = nodes.length; i--; ) {
|
||||
const node = nodes[i];
|
||||
const { i18n } = node.dataset;
|
||||
|
||||
node.innerHTML = chrome.i18n.getMessage(i18n);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @description Listen to document ready
|
||||
* @listens document#ready
|
||||
*/
|
||||
|
||||
document.addEventListener("DOMContentLoaded", handleContentLoaded);
|