Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ What are bangs?: <https://duckduckgo.com/bangs>
- Description: Create new !ghh bang that redirects to <https://githistory.xyz>
- Advanced:
- Process matches: URL decode

### Fast DuckDuckGo.com !bangs

Go directly to frequently used DuckDuckGo bangs to avoid intermediary network requests.
Expand All @@ -85,9 +85,9 @@ Go directly to frequently used DuckDuckGo bangs to avoid intermediary network re
- Redirect to: `https://google.com/search?hl=en&q=$1+$2`
- Pattern type: Regular Expression
- Description: DuckDuckGo → Google !bang shortcut (prefix AND suffix)
- Pattern Description: Avoid extraneous + in URL with two separate patterns
- Pattern Description: Avoid extraneous + in URL with two separate patterns
###

- Example URL: `https://duckduckgo.com/?q=foo+bar+%21google`
- Include pattern: `^https://duckduckgo\.com/\?q=(.*?)\+?(?:%21|!)google\b\+?(.*?)(?:&|$)`
- Redirect to: `https://google.com/search?hl=en&q=$1$2`
Expand Down
143 changes: 110 additions & 33 deletions js/background.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

//This is the background script. It is responsible for actually redirecting requests,
//as well as monitoring changes in the redirects and the disabled status and reacting to them.
function log(msg, force) {
Expand All @@ -7,12 +6,16 @@ function log(msg, force) {
}
}
log.enabled = false;
var enableNotifications=false;
let
enableNotifications = false,
disableContextMenu = false

function isDarkMode() {
return window.matchMedia('(prefers-color-scheme: dark)').matches;
}
var isFirefox = !!navigator.userAgent.match(/Firefox/i);
const
isFirefox = navigator.userAgent.includes(' Firefox/'),
isChromium = navigator.userAgent.includes(' Chrome/')

var storageArea = chrome.storage.local;
//Redirects partitioned by request type, so we have to run through
Expand All @@ -33,7 +36,7 @@ var justRedirected = {
var redirectThreshold = 3;

function setIcon(image) {
var data = {
var data = {
path: {}
};

Expand All @@ -47,7 +50,7 @@ function setIcon(image) {
//If not checked we will get unchecked errors in the background page console...
log('Error in SetIcon: ' + err.message);
}
});
});
}

//This is the actual function that gets called for each request and must
Expand All @@ -74,7 +77,7 @@ function checkRedirects(details) {
return {};
}


for (var i = 0; i < list.length; i++) {
var r = list[i];
var result = r.getMatch(details.url);
Expand All @@ -94,7 +97,7 @@ function checkRedirects(details) {
if (data.count >= redirectThreshold) {
log('Ignoring ' + details.url + ' because we have redirected it ' + data.count + ' times in the last ' + threshold + 'ms');
return {};
}
}
}


Expand All @@ -103,18 +106,92 @@ function checkRedirects(details) {
sendNotifications(r, details.url, result.redirectTo);
}
ignoreNextRequest[result.redirectTo] = new Date().getTime();

return { redirectUrl: result.redirectTo };
}
}

return {};
return {};
}

// https://pastebin.com/mpCxwADU kind of inconsistently worked on Firefox.
// I think with some refactoring + better data structures, it could've been made consistent.
// However, Chromium's `contextMenus` API's way too limited, conditional target `link` types just aren't possible when supporting Chromium.
// https://issues.chromium.org/issues/40467152

let
hasRedirect = false,
linkUrl

const
id = 'copyWithRedirect',
initContextMenu = () => {
chrome.storage.local.get({ disableContextMenu: false }, obj => {
if (obj.disableContextMenu) {
chrome.contextMenus.remove(id)
return
}

chrome.contextMenus.create({
id,
title: 'Copy with Redirect',
contexts: ['link'],
documentUrlPatterns: ['http://*/*', 'https://*/*']
})

chrome.contextMenus.onClicked.addListener(async info => {
if (info.menuItemId !== id) {
chrome.contextMenus.remove(id)
return
}

hasRedirect = false
linkUrl = info.linkUrl

redirects:
for (const requestType in partitionedRedirects)
for (let redirect of partitionedRedirects[requestType])
if (!redirect.disabled && (redirect = redirect.getMatch(linkUrl)).isMatch) {
hasRedirect = true
linkUrl = redirect.redirectTo
break redirects
}

try {
// https://issues.chromium.org/issues/40738001
if (isChromium) {
const textarea = document.createElement('textarea')
textarea.style.position = 'fixed'
textarea.style.opacity = 0
textarea.value = linkUrl
document.body.appendChild(textarea)
textarea.select()
document.execCommand('copy')
document.body.removeChild(textarea)
}
else
await navigator.clipboard.writeText(linkUrl)

if (enableNotifications)
chrome.notifications.create({
type: 'basic',
title: 'Redirector - Copied URL',
message: `Copied${hasRedirect ? ' redirected': ''} URL: ${linkUrl}`,
iconUrl: `images/icon-${isDarkMode() ? 'dark' : 'light'}-theme-48.png`
})
}
catch (err) {
log('Failed to copy URL to clipboard: ' + err.message)
}
})
})
}
initContextMenu()

//Monitor changes in data, and setup everything again.
//This could probably be optimized to not do everything on every change
//but why bother?
function monitorChanges(changes, namespace) {
function monitorChanges(changes) {
if (changes.disabled) {
updateIcon();

Expand All @@ -133,13 +210,15 @@ function monitorChanges(changes, namespace) {
setUpRedirectListener();
}

if (changes.logging) {
log.enabled = changes.logging.newValue;
log('Logging settings have changed to ' + changes.logging.newValue, true); //Always want this to be logged...
}
if (changes.enableNotifications){
log('notifications setting changed to ' + changes.enableNotifications.newValue);
enableNotifications = changes.enableNotifications.newValue;
if (changes.logging)
log('Logging settings have changed to ' + (log.enabled = changes.logging.newValue), true) // Always want this to be logged...

if (changes.enableNotifications)
log('Notifications setting changed to ' + (enableNotifications = changes.enableNotifications.newValue))

if (changes.disableContextMenu) {
log('Disable context menu setting has been changed to ' + (disableContextMenu = changes.disableContextMenu.newValue))
initContextMenu()
}
}
chrome.storage.onChanged.addListener(monitorChanges);
Expand All @@ -149,7 +228,7 @@ chrome.storage.onChanged.addListener(monitorChanges);
function createFilter(redirects) {
var types = [];
for (var i = 0; i < redirects.length; i++) {
redirects[i].appliesTo.forEach(function(type) {
redirects[i].appliesTo.forEach(function(type) {
// Added this condition below as part of fix for issue 115 https://github.com/einaregilsson/Redirector/issues/115
// Firefox considers responsive web images request as imageset. Chrome doesn't.
// Chrome throws an error for imageset type, so let's add to 'types' only for the values that chrome or firefox supports
Expand Down Expand Up @@ -177,13 +256,13 @@ function createPartitionedRedirects(redirects) {
for (var j=0; j<redirect.appliesTo.length;j++) {
var requestType = redirect.appliesTo[j];
if (partitioned[requestType]) {
partitioned[requestType].push(redirect);
partitioned[requestType].push(redirect);
} else {
partitioned[requestType] = [redirect];
}
}
}
return partitioned;
return partitioned;
}

//Sets up the listener, partitions the redirects, creates the appropriate filters etc.
Expand Down Expand Up @@ -232,7 +311,7 @@ function updateIcon() {
chrome.storage.local.get({disabled:false}, function(obj) {

//Do this here so even in Chrome we get the icon not too long after an dark/light mode switch...
if (!isFirefox) {
if (!isFirefox) {
if (isDarkMode()) {
setIcon('icon-dark-theme');
} else {
Expand All @@ -253,7 +332,7 @@ function updateIcon() {
chrome.browserAction.setBadgeTextColor({color: '#fafafa'});
}
}
});
});
}


Expand Down Expand Up @@ -311,7 +390,7 @@ chrome.runtime.onMessage.addListener(
if (size > storageArea.QUOTA_BYTES_PER_ITEM) {
log("size of redirects " + size + " is greater than allowed for Sync which is " + storageArea.QUOTA_BYTES_PER_ITEM);
// Setting storageArea back to Local.
storageArea = chrome.storage.local;
storageArea = chrome.storage.local;
sendResponse({
message: "Sync Not Possible - size of Redirects larger than what's allowed by Sync. Refer Help page"
});
Expand All @@ -325,7 +404,7 @@ chrome.runtime.onMessage.addListener(
log('redirects moved from Local to Sync Storage Area');
//Remove Redirects from Local storage
chrome.storage.local.remove("redirects");
// Call setupRedirectListener to setup the redirects
// Call setupRedirectListener to setup the redirects
setUpRedirectListener();
sendResponse({
message: "sync-enabled"
Expand All @@ -351,7 +430,7 @@ chrome.runtime.onMessage.addListener(
log('redirects moved from Sync to Local Storage Area');
//Remove Redirects from sync storage
chrome.storage.sync.remove("redirects");
// Call setupRedirectListener to setup the redirects
// Call setupRedirectListener to setup the redirects
setUpRedirectListener();
sendResponse({
message: "sync-disabled"
Expand Down Expand Up @@ -393,11 +472,9 @@ chrome.storage.local.get({
storageArea = chrome.storage.local;
}
// Now we know which storageArea to use, call setupInitial function
setupInitial();
setupInitial();
});

//wrapped the below inside a function so that we can call this once we know the value of storageArea from above.

function setupInitial() {
chrome.storage.local.get({enableNotifications:false},function(obj){
enableNotifications = obj.enableNotifications;
Expand All @@ -416,7 +493,7 @@ function setupInitial() {
log('Redirector starting up...');


// Below is a feature request by an user who wished to see visual indication for an Redirect rule being applied on URL
// Below is a feature request by an user who wished to see visual indication for an Redirect rule being applied on URL
// https://github.com/einaregilsson/Redirector/issues/72
// By default, we will have it as false. If user wishes to enable it from settings page, we can make it true until user disables it (or browser is restarted)

Expand All @@ -428,13 +505,13 @@ function sendNotifications(redirect, originalUrl, redirectedUrl ){
//Firefox and other browsers does not yet support "list" type notification like in Chrome.
// Console.log(JSON.stringify(chrome.notifications)); -- This will still show "list" as one option but it just won't work as it's not implemented by Firefox yet
// Can't check if "chrome" typeof either, as Firefox supports both chrome and browser namespace.
// So let's use useragent.
// So let's use useragent.
// Opera UA has both chrome and OPR. So check against that ( Only chrome which supports list) - other browsers to get BASIC type notifications.

let icon = isDarkMode() ? "images/icon-dark-theme-48.png": "images/icon-light-theme-48.png";

if(navigator.userAgent.toLowerCase().indexOf("chrome") > -1 && navigator.userAgent.toLowerCase().indexOf("opr")<0){

var items = [{title:"Original page: ", message: originalUrl},{title:"Redirected to: ",message: redirectedUrl}];
var head = "Redirector - Applied rule : " + redirect.description;
chrome.notifications.create({
Expand All @@ -443,7 +520,7 @@ function sendNotifications(redirect, originalUrl, redirectedUrl ){
title : head,
message : head,
iconUrl : icon
});
});
}
else{
var message = "Applied rule : " + redirect.description + " and redirected original page " + originalUrl + " to " + redirectedUrl;
Expand All @@ -469,4 +546,4 @@ function handleStartup(){
//This doesn't work yet in Chrome, but we'll put it here anyway, in case it starts working...
let darkModeMql = window.matchMedia('(prefers-color-scheme: dark)');
darkModeMql.onchange = updateIcon;
}
}
5 changes: 3 additions & 2 deletions js/popup.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ function openRedirectorSettings() {

//switch to open one if we have it to minimize conflicts
var url = chrome.extension.getURL('redirector.html');

//FIREFOXBUG: Firefox chokes on url:url filter if the url is a moz-extension:// url
//so we don't use that, do it the more manual way instead.
chrome.tabs.query({currentWindow:true}, function(tabs) {
Expand All @@ -41,12 +41,13 @@ function openRedirectorSettings() {


function pageLoad() {
storage.get({logging:false, enableNotifications:false, disabled: false}, function(obj) {
storage.get({ logging: false, enableNotifications: false, disableContextMenu: false, disabled: false }, function(obj) {
viewModel = obj;
applyBinding();
})

el('#enable-notifications').addEventListener('input', () => toggle('enableNotifications'));
el('#disable-context-menu').addEventListener('input', () => toggle('disableContextMenu'));
el('#enable-logging').addEventListener('input', () => toggle('logging'));
el('#toggle-disabled').addEventListener('click', () => toggle('disabled'));
el('#open-redirector-settings').addEventListener('click', openRedirectorSettings);
Expand Down
6 changes: 4 additions & 2 deletions manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@
"tabs",
"http://*/*",
"https://*/*",
"notifications"
"notifications",
"contextMenus",
"clipboardWrite"
],
"applications": {
"gecko": {
Expand Down Expand Up @@ -89,4 +91,4 @@
}
]
}
}
}
1 change: 1 addition & 0 deletions popup.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ <h1>REDIRECTOR</h1>
<button id="open-redirector-settings">Edit Redirects</button>
<label><input id="enable-logging" type="checkbox" data-bind="logging" /> <span>Enable logging</span></label>
<label><input id="enable-notifications" type="checkbox" data-bind="enableNotifications" /> <span>Enable notifications</span></label>
<label><input id="disable-context-menu" type="checkbox" data-bind="disableContextMenu" /> <span>Disable context menu</span></label>
<script src="js/stub.js"></script>
<script src="js/util.js"></script>
<script src="js/popup.js"></script>
Expand Down