diff --git a/src/html/consent.html b/src/html/consent.html new file mode 100644 index 000000000..9c812f26a --- /dev/null +++ b/src/html/consent.html @@ -0,0 +1,63 @@ + + + + FastForward + + + + + + + + +
+
+

Thank you for installing FastForward

+

+ This extension collects the tab url when you choose to add a website to the whitelist. +

+

+ If you consent to this data collection hit "Agree" to continue. Otherwise hit "Refuse" and the extension will be uninstalled. +

+ + +
+ + + diff --git a/src/html/consent.js b/src/html/consent.js new file mode 100644 index 000000000..2d284ce8d --- /dev/null +++ b/src/html/consent.js @@ -0,0 +1,26 @@ +// Function to save consent status +async function saveConsentStatus(consentStatus) { + return browser.storage.local.set({ consentStatus: consentStatus }); +} + +// Function to get consent status +async function getConsentStatus() { + return new Promise((resolve) => { + browser.storage.local.get('consentStatus').then((result) => { + resolve(result.consentStatus); + }); + }); +} + +// Event listener for "Agree" button +document.querySelector('#agree').addEventListener('click', async function () { + console.log("Agree button clicked."); + await saveConsentStatus('consent-granted'); + window.location.href = 'options.html'; +}); + +// Event listener for "Refuse" button +document.querySelector('#refuse').addEventListener('click', async function () { + console.log("Uninstalling extension."); + browser.management.uninstallSelf(); +}); \ No newline at end of file diff --git a/src/js/background.js b/src/js/background.js index b5af38feb..58d62ab07 100644 --- a/src/js/background.js +++ b/src/js/background.js @@ -1,172 +1,200 @@ import * as constants from './constants.js'; -const brws = typeof browser !== 'undefined' ? browser : chrome; -const fetchDomains = ['crowd.fastforward.team', 'redirect-api.work.ink']; //only allow requests to these domains -async function getOptions() { - return new Promise((resolve) => { - brws.storage.local.get('options').then((result) => { - resolve(result.options); - }); - }); -} +const isFirefox = /Firefox/i.test(navigator.userAgent); -function ffclipboardClear() { - brws.storage.local.set({ ff_clipboard: '{}' }); +// Check if the browser is Firefox +if (isFirefox) { + browser.runtime.onInstalled.addListener((details) => { + if (details.reason === 'install') { + browser.storage.local.get('consentStatus').then(function (data) { + const consentStatus = data.consentStatus; + if (consentStatus !== 'granted') { + browser.tabs.create({ + url: 'html/consent.html', + }); + } else { + // If consent has been already granted, execute background script + executeBackgroundScript(); + } + }); + } + }); +} else { + // For non-Firefox browsers, execute background script + executeBackgroundScript(); } -function clearCrowdIgnoredURLs() { - brws.storage.local.set({ crowd_ignore: '{}' }); -} +function executeBackgroundScript() { + const brws = typeof browser !== 'undefined' ? browser : chrome; + const fetchDomains = ['crowd.fastforward.team', 'redirect-api.work.ink']; //only allow requests to these domains -function firstrun(details) { - if (details.reason == 'install' || details.reason == 'update') { - brws.tabs.create({ url: 'https://fastforward.team/firstrun' }); - ffclipboardClear(); - brws.storage.local.set({ tempDisableCrowd: 'false' }); - brws.storage.local.set({ version: brws.runtime.getManifest().version }); - brws.runtime.openOptionsPage(); //required for loading default options, to do: implement a better way - brws.declarativeNetRequest.updateDynamicRules({ - addRules: constants.beforeNavigateRules, - removeRuleIds: constants.beforeNavigateRules.map((rule) => rule.id), + async function getOptions() { + return new Promise((resolve) => { + brws.storage.local.get('options').then((result) => { + resolve(result.options); + }); }); } -} -function preflight(details) { - let url = new URL(details.url); - if (url.hostname !== 'fastforward.team') { - return; + function ffclipboardClear() { + brws.storage.local.set({ ff_clipboard: '{}' }); } - //navigate - if (url.pathname === '/bypassed') { - let ext_url = new URL(brws.runtime.getURL('')); - url.hostname = ext_url.hostname; - url.protocol = ext_url.protocol; - url.pathname = '/html' + url.pathname; - if (url.searchParams.get('crowd') === 'true') { - url.pathname = - url.pathname.split('/').slice(0, -1).join('/') + '/crowd-bypassed.html'; - } else { - url.pathname = - url.pathname.split('/').slice(0, -1).join('/') + - '/before-navigate.html'; - } - brws.tabs.update(details.tabId, { - url: url.href, - }); + function clearCrowdIgnoredURLs() { + brws.storage.local.set({ crowd_ignore: '{}' }); } -} -// If user restarts the browser before the is alarm triggered -function reEnableCrowdBypassStartup() { - brws.storage.local.get(['tempDisableCrowd']).then((result) => { - if (result.tempDisableCrowd === 'true') { - brws.storage.local.get(['options']).then((result) => { - let opt = result.options; - opt.optionCrowdBypass = true; - brws.storage.local.set({ options: opt }); + function firstrun(details) { + if (details.reason == 'install' || details.reason == 'update') { + brws.tabs.create({ url: 'https://fastforward.team/firstrun' }); + ffclipboardClear(); + brws.storage.local.set({ tempDisableCrowd: 'false' }); + brws.storage.local.set({ version: brws.runtime.getManifest().version }); + brws.runtime.openOptionsPage(); //required for loading default options, to do: implement a better way + brws.declarativeNetRequest.updateDynamicRules({ + addRules: constants.beforeNavigateRules, + removeRuleIds: constants.beforeNavigateRules.map((rule) => rule.id), }); } - brws.storage.local.set({ tempDisableCrowd: 'false' }); - }); -} + } -// Add a listener for the temp crowd disable alarm -brws.alarms.onAlarm.addListener((alarm) => { - brws.storage.local.get(['tempDisableCrowd']).then((result) => { - if ( - alarm.name === 'enableCrowdBypass' && - result.tempDisableCrowd === 'true' - ) { - brws.storage.local.get(['options']).then((result) => { - let opt = result.options; - opt.optionCrowdBypass = true; - brws.storage.local.set({ options: opt }); - brws.storage.local.set({ tempDisableCrowd: 'false' }); + function preflight(details) { + let url = new URL(details.url); + if (url.hostname !== 'fastforward.team') { + return; + } + //navigate + if (url.pathname === '/bypassed') { + let ext_url = new URL(brws.runtime.getURL('')); + url.hostname = ext_url.hostname; + url.protocol = ext_url.protocol; + url.pathname = '/html' + url.pathname; + if (url.searchParams.get('crowd') === 'true') { + url.pathname = + url.pathname.split('/').slice(0, -1).join('/') + + '/crowd-bypassed.html'; + } else { + url.pathname = + url.pathname.split('/').slice(0, -1).join('/') + + '/before-navigate.html'; + } + + brws.tabs.update(details.tabId, { + url: url.href, }); } + } + + function reEnableCrowdBypassStartup() { + brws.storage.local.get(['tempDisableCrowd']).then((result) => { + if (result.tempDisableCrowd === 'true') { + brws.storage.local.get(['options']).then((result) => { + let opt = result.options; + opt.optionCrowdBypass = true; + brws.storage.local.set({ options: opt }); + }); + } + brws.storage.local.set({ tempDisableCrowd: 'false' }); + }); + } + + brws.alarms.onAlarm.addListener((alarm) => { + brws.storage.local.get(['tempDisableCrowd']).then((result) => { + if ( + alarm.name === 'enableCrowdBypass' && + result.tempDisableCrowd === 'true' + ) { + brws.storage.local.get(['options']).then((result) => { + let opt = result.options; + opt.optionCrowdBypass = true; + brws.storage.local.set({ options: opt }); + brws.storage.local.set({ tempDisableCrowd: 'false' }); + }); + } + }); }); -}); - -brws.runtime.onInstalled.addListener(firstrun); -brws.runtime.onStartup.addListener(() => { - ffclipboardClear(); - clearCrowdIgnoredURLs(); - reEnableCrowdBypassStartup(); - brws.storage.local.set({ version: brws.runtime.getManifest().version }); -}); - -brws.runtime.onMessage.addListener((request, _, sendResponse) => { - (async () => { - let options = await getOptions(); - if (options.optionCrowdBypass === false) { - return; - } - let url; - request.type === 'crowdQuery' - ? (url = 'https://crowd.fastforward.team/crowd/query_v1') - : (url = 'https://crowd.fastforward.team/crowd/contribute_v1'); - let params = new URLSearchParams(); + brws.runtime.onInstalled.addListener(firstrun); + brws.runtime.onStartup.addListener(() => { + ffclipboardClear(); + clearCrowdIgnoredURLs(); + reEnableCrowdBypassStartup(); + brws.storage.local.set({ version: brws.runtime.getManifest().version }); + }); - if (request.type !== 'followAndContribute') { - for (let key in request.detail) { - params.append(key, request.detail[key]); + brws.runtime.onMessage.addListener((request, _, sendResponse) => { + (async () => { + let options = await getOptions(); + if (options.optionCrowdBypass === false) { + return; } - } else { - //use fetch api to get final url after redirects from detail.target - for (let key in request.detail) { - if (key === 'target') { - let dest = new URL(request.detail[key]); - if (!fetchDomains.includes(dest.hostname)) { - return; - } - let res = await fetch(dest.href, { - method: 'GET', - redirect: 'follow', - }); - params.append(key, res.url); - } else { + let url; + request.type === 'crowdQuery' + ? (url = 'https://crowd.fastforward.team/crowd/query_v1') + : (url = 'https://crowd.fastforward.team/crowd/contribute_v1'); + + let params = new URLSearchParams(); + + if (request.type !== 'followAndContribute') { + for (let key in request.detail) { params.append(key, request.detail[key]); } + } else { + for (let key in request.detail) { + if (key === 'target') { + let dest = new URL(request.detail[key]); + if (!fetchDomains.includes(dest.hostname)) { + return; + } + let res = await fetch(dest.href, { + method: 'GET', + redirect: 'follow', + }); + params.append(key, res.url); + } else { + params.append(key, request.detail[key]); + } + } } - } - let response = await fetch(url, { - method: 'POST', - body: params.toString(), - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - }, - }); - if (request.type === 'crowdQuery') - response.text().then((res) => { - sendResponse(res); - }); - })(); - return true; -}); - -brws.storage.onChanged.addListener(() => { - getOptions().then((options) => { - if (options.optionBlockIpLoggers === false) { - brws.declarativeNetRequest.updateEnabledRulesets({ - disableRulesetIds: ['ipLoggerRuleset'], + let response = await fetch(url, { + method: 'POST', + body: params.toString(), + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, }); - } else { - brws.declarativeNetRequest.updateEnabledRulesets({ - enableRulesetIds: ['ipLoggerRuleset'], - }); - } - if (options.optionTrackerBypass === false) { - brws.declarativeNetRequest.updateEnabledRulesets({ - disableRulesetIds: ['trackerRuleset'], - }); - } else { - brws.declarativeNetRequest.updateEnabledRulesets({ - enableRulesetIds: ['trackerRuleset'], - }); - } + if (request.type === 'crowdQuery') + response.text().then((res) => { + sendResponse(res); + }); + })(); + return true; }); -}); + + brws.storage.onChanged.addListener(() => { + getOptions().then((options) => { + if (typeof options === 'undefined') { + return; + } + if (options.optionBlockIpLoggers === false) { + brws.declarativeNetRequest.updateEnabledRulesets({ + disableRulesetIds: ['ipLoggerRuleset'], + }); + } else { + brws.declarativeNetRequest.updateEnabledRulesets({ + enableRulesetIds: ['ipLoggerRuleset'], + }); + } + if (options.optionTrackerBypass === false) { + brws.declarativeNetRequest.updateEnabledRulesets({ + disableRulesetIds: ['trackerRuleset'], + }); + } else { + brws.declarativeNetRequest.updateEnabledRulesets({ + enableRulesetIds: ['trackerRuleset'], + }); + } + }); + }); +}