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
5 changes: 3 additions & 2 deletions assets/js/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,8 @@ function registerRedirectHandlers() {
for (let targetParam in REDIRECT_DATA_BY_TARGET_PARAM) {
const {
patterns: urls,
types
types,
paramDelimiters = ['&'],
} = REDIRECT_DATA_BY_TARGET_PARAM[targetParam];

// Don't do anything stupid.
Expand All @@ -132,7 +133,7 @@ function registerRedirectHandlers() {
return {};
}

const targetUrl = extractRedirectTarget(details.url, targetParam);
const targetUrl = extractRedirectTarget(details.url, targetParam, paramDelimiters);
if (!targetUrl) {
return {};
}
Expand Down
16 changes: 12 additions & 4 deletions assets/js/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,19 @@ function getOptionsFromStorage(cb, options) {
}


function findQueryParam(targetParam, url) {
function findQueryParam(targetParam, url, paramDelimiter = '&') {
url = url || window.location.href;

if (!(targetParam && url)) {
if (!(targetParam && url && paramDelimiter)) {
return false;
}

// For now we'll support query stryings that take one of 2 forms:
// 1) key1=value1&key2=value2&key3=value3
// 2) key1(value1)key2(value2)key3(value3)
// So...base the key/value delimiter based on the param delimiter
const kvDelimiter = paramDelimiter === '&' ? '=' : '(';

// Find the first occurrance of '?' character. I've seen URLs that have embedded
// URLs that are not properly encoded, e.g.:
// https://www.google.com/url?hl=en&q=http://t.dd.delta.org/r/?id%3Dxxxxx,yyyyyy,zzzzz&source=gmail&ust=1516647918588000&usg=AFQjCNEV1C1cwHSrU8r1kyYmaPe4IAsb-Q
Expand All @@ -42,21 +48,23 @@ function findQueryParam(targetParam, url) {
if (queryString) {

// Get the key/value pairs from the query string
const keyVals = queryString.split('&');
const keyVals = queryString.split(paramDelimiter);
// Figure out how many pairs we have
const kvsLength = keyVals.length;
// For each iteration fo the loop
let kv;

for(let i=0; i < kvsLength; i++) {
// Get this key/value pair and split it up into its pieces
kv = keyVals[i].split('=');
kv = keyVals[i].split(kvDelimiter);
// We are looking for "url=blahblahblah", so see if this is the one
if (kv[0] === targetParam) {
return kv[1];
}
}
}

return false;
}


Expand Down
113 changes: 71 additions & 42 deletions assets/js/redirects.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ const SCHEMA = '<SCHEMA>';
const SUBDOMAIN = '<SUBDOMAIN>';
const PATH = '<PATH>';
const QS_VALUE = '<QSVALUE>';
const QS_KVS = '<QSKVS>';
const QS_KVS_1 = '<QSKVS1>';
const QS_KVS_2 = '<QSKVS2>';


const KNOWN_REDIRECTS = [
Expand Down Expand Up @@ -93,6 +94,7 @@ const KNOWN_REDIRECTS = [
{
name: 'Tradedoubler',
targetParam: 'url',
paramDelimiters: ['&', ')'],
patterns: [
`${SCHEMA}${SUBDOMAIN}.tradedoubler.com/click?`
],
Expand Down Expand Up @@ -126,7 +128,13 @@ const KNOWN_REDIRECTS = [
name: 'Slack',
targetParam: 'url',
patterns: [
`${SCHEMA}slack-redir.net/link?`
`${SCHEMA}slack-redir.net/link?`,
],
types: ['main_frame']
name: 'Digidip',
targetParam: 'url',
patterns: [
`${SCHEMA}${SUBDOMAIN}.digidip.net/visit?`,
],
types: ['main_frame']
}
Expand All @@ -139,30 +147,32 @@ const KNOWN_REDIRECTS = [
// using a closure-like approach to prevent having to scan the URL again
// to figure out which pattern it matched, and then finally extract the
// target for that pattern. Should result in things being much faster in
// then end.
// the end.
// Use 'var' here so that it's not scoped incorrectly.
var REDIRECT_DATA_BY_TARGET_PARAM = {};

KNOWN_REDIRECTS.forEach(KNOWN_REDIRECT => {

// Pluck out the param and the patterns
const targetParam = KNOWN_REDIRECT.targetParam;
const orginalPatterns = KNOWN_REDIRECT.patterns;
const types = KNOWN_REDIRECT.types;
const {
targetParam,
paramDelimiters = ['&'],
patterns: orginalPatterns,
types,
} = KNOWN_REDIRECT;

// Make sure everything looks good
if (!(targetParam && orginalPatterns && orginalPatterns.length && types && types.length)) {
if (!(targetParam && orginalPatterns && orginalPatterns.length && types && types.length && paramDelimiters && paramDelimiters.length)) {
return;
}

// Prep the Object if necessary
if (!(REDIRECT_DATA_BY_TARGET_PARAM[targetParam])) {
REDIRECT_DATA_BY_TARGET_PARAM[targetParam] = {
patterns: [],
regexes: [],
types: []
};
}
REDIRECT_DATA_BY_TARGET_PARAM[targetParam] = REDIRECT_DATA_BY_TARGET_PARAM[targetParam] || {
paramDelimiters: [],
patterns: [],
regexes: [],
types: [],
};

// Go through every 'type' for this redirect
types.forEach(type => {
Expand All @@ -172,24 +182,38 @@ KNOWN_REDIRECTS.forEach(KNOWN_REDIRECT => {
}
});

paramDelimiters.forEach(paramDelimiter => {
if (!REDIRECT_DATA_BY_TARGET_PARAM[targetParam].paramDelimiters.includes(paramDelimiter)) {
REDIRECT_DATA_BY_TARGET_PARAM[targetParam].paramDelimiters.push(paramDelimiter);
}
});

const newPatterns = [];
const newClipboardRegexes = [];

// Go through each of these patterns and create any combinations we need to
orginalPatterns.forEach(originalPattern => {

// Create the key/value placeholder for the target param
const targetParamKv = `${targetParam}=${QS_VALUE}`;

// We need to generate a few variations on this original pattern for URL matching
// 1) support the URL param as the first param
newPatterns.push(replacePlaceholders(`${originalPattern}${targetParamKv}`));
// 2) support the URL param as a non-first param
newPatterns.push(replacePlaceholders(`${originalPattern}${QS_KVS}${targetParamKv}`));

// The regex only needs 1 variation which includes optional query string key/values
const regexPattern = replacePlaceholdersRegex(`${originalPattern}${QS_KVS}${targetParamKv}`);
newClipboardRegexes.push(new RegExp(regexPattern));
paramDelimiters.forEach(paramDelimiter => {
// For now we'll support query stryings that take one of 2 forms:
// 1) key1=value1&key2=value2&key3=value3
// 2) key1(value1)key2(value2)key3(value3)
// So...base the key/value delimiter based on the param delimiter
const kvDelimiter = paramDelimiter === '&' ? '=' : '(';
const kvPlaceholder = paramDelimiter === '&' ? QS_KVS_1 : QS_KVS_2;

// Create the key/value placeholder for the target param
const targetParamKv = `${targetParam}${kvDelimiter}${QS_VALUE}`;

// We need to generate a few variations on this original pattern for URL matching
// 1) support the URL param as the first param
newPatterns.push(replacePlaceholders(`${originalPattern}${targetParamKv}`));
// 2) support the URL param as a non-first param
newPatterns.push(replacePlaceholders(`${originalPattern}${kvPlaceholder}${targetParamKv}`));

// The regex only needs 1 variation which includes optional query string key/values
const regexPattern = replacePlaceholdersRegex(`${originalPattern}${kvPlaceholder}${targetParamKv}`);
newClipboardRegexes.push(new RegExp(regexPattern));
});
});

// Add these patterns to the array of patterns for this target param
Expand All @@ -199,7 +223,6 @@ KNOWN_REDIRECTS.forEach(KNOWN_REDIRECT => {
REDIRECT_DATA_BY_TARGET_PARAM[targetParam].regexes.push(...newClipboardRegexes);
});


// Escape all of the literals
function escapeRegExp(str) {
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
Expand All @@ -211,7 +234,8 @@ function replacePlaceholders(pattern) {
.replace(SCHEMA, '*://')
.replace(SUBDOMAIN, '*')
.replace(PATH, '/*')
.replace(QS_KVS, '*&')
.replace(QS_KVS_1, '*&')
.replace(QS_KVS_2, '*)')
.replace(QS_VALUE, '*');
}

Expand All @@ -225,12 +249,14 @@ function replacePlaceholdersRegex(pattern) {
// This one required text on either side of the '=' sign, when I've seen
// some places build junk that would not match. Not sure if this is a good idea
// to "fix" or not.
// pattern = pattern.replace(QS_KVS, '([\\w]+\\=[\\w]+\\&)*');
// pattern = pattern.replace(QS_KVS_1, '([\\w]+\\=[\\w]+\\&)*');
// This would be the "fix" for the above. It allows blanks on either side of the
// '=' sign.
// pattern = pattern.replace(QS_KVS, '([\\w*+\\=[\\w]*\\&)*');
// pattern = pattern.replace(QS_KVS_1, '([\\w*+\\=[\\w]*\\&)*');
// OK, this one handles even more scenarios that are acceptable
.replace(QS_KVS, '([\\w*+\\=?[\\w]*\\&)*')
.replace(QS_KVS_1, '([\\w*+\\=?[\\w]*\\&)*')
// foo(bar)baz(bop)...
.replace(QS_KVS_2, '(\\w*\\(\\w*\\))*')
.replace(QS_VALUE, '\\w');
}

Expand All @@ -240,21 +266,23 @@ function replacePlaceholdersCreateExample(pattern) {
.replace(SCHEMA, 'https://')
.replace(SUBDOMAIN, 'foo')
.replace(PATH, '/path/to/whatever')
.replace(QS_KVS, '&')
.replace(QS_KVS_1, '&')
.replace(QS_VALUE, 'foo');
}


// Extract the redirect target from a URL given the target parameter
function extractRedirectTarget(url, targetParam = 'url') {
// See if we can find a target in the URL.
let target = findQueryParam(targetParam, url);
function extractRedirectTarget(url, targetParam = 'url', paramDelimiters = ['&']) {
for (let paramDelimiter of paramDelimiters) {
// See if we can find a target in the URL.
let target = findQueryParam(targetParam, url, paramDelimiter);

if (typeof target === 'string' && target.startsWith('http')) {
return decodeURIComponent(target);
}
if (typeof target === 'string' && target.startsWith('http')) {
return decodeURIComponent(target);
}
};

return false;
return false
}


Expand All @@ -267,15 +295,16 @@ function followRedirect(url) {
for (let targetParam in REDIRECT_DATA_BY_TARGET_PARAM) {
// Get the regexes for this target param
const {
regexes = []
regexes = [],
paramDelimiters = ['&'],
} = REDIRECT_DATA_BY_TARGET_PARAM[targetParam];

// Go through each regex for this target param
for (let regex, i=0; i < regexes.length; i++) {
regex = regexes[i];
// If the URL matches this redirect pattern, then extract the redirect.
if (regex.test(url)) {
url = extractRedirectTarget(url, targetParam) || url;
url = extractRedirectTarget(url, targetParam, paramDelimiters) || url;
// All done with this regex stuff.
break outerLoop;
}
Expand Down
2 changes: 1 addition & 1 deletion assets/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"manifest_version": 2,
"name": "URL Tracking Stripper & Redirect Skipper",
"short_name": "URL Tracking Stripper & Redirect Skipper",
"version": "5.0.1",
"version": "5.1.0",
"description": "Increase the speed & privacy of your browsing. Skip/remove tracking parameters & redirects from URLs to keep them shorter & cleaner.",
"homepage_url": "https://github.com/newhouse/url-tracking-stripper",
"icons": {
Expand Down