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 @@
+
+
+
+
+
+
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'],
+ });
+ }
+ });
+ });
+}