Skip to content

Commit bb863fb

Browse files
committed
add chrome-ext redirect interceptors - v.0.0.4
1 parent fed66d1 commit bb863fb

11 files changed

Lines changed: 194 additions & 4 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,4 @@ npm-debug.log*
2727
yarn-debug.log*
2828
yarn-error.log*
2929
dist
30+
localhostify-ext

.localhostify.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
module.exports = {
2+
staging: {
3+
port: 3001,
4+
target: {
5+
host: 'https://staging.domain.com',
6+
matchUrl: '^\\/api.*',
7+
},
8+
externalRedirects: [
9+
{
10+
match: '/api/auth/callback',
11+
replace: ['https://staging.domain.com', 'http://localhost:3001'],
12+
},
13+
],
14+
},
15+
prod: {
16+
port: 3002,
17+
target: {
18+
host: 'https://prod.domain.com',
19+
matchUrl: '^\\/api.*',
20+
},
21+
externalRedirects: [
22+
{
23+
match: '/api/auth/callback',
24+
replace: ['https://prod.domain.com', 'http://localhost:3002'],
25+
},
26+
],
27+
},
28+
};

.npmignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,6 @@ node_modules/*
55
src/
66
.eslintignore
77
.eslintrc.json
8+
.prettierrc
9+
localhostify-ext/*
10+
.localhostify.js

.prettierrc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"semi": true,
3+
"trailingComma": "all",
4+
"singleQuote": true,
5+
"printWidth": 120,
6+
"tabWidth": 3,
7+
"endOfLine": "lf"
8+
}

bin/createConfig.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
const fs = require('fs');
2+
3+
const config = require(process.cwd() + '/.localhostify.js');
4+
const externalRedirects = Object.values(config).reduce((all, v) => [...all, ...v.externalRedirects], []);
5+
const chromeConfig = '__LOCALHOSTIFY__ = ' + JSON.stringify({ externalRedirects }, 0, 3);
6+
7+
const extDir = process.cwd() + '/localhostify-ext';
8+
9+
if (!fs.existsSync(extDir)) {
10+
fs.mkdirSync(extDir);
11+
}
12+
if (!fs.existsSync(extDir + '/scripts')) {
13+
fs.mkdirSync(extDir + '/scripts');
14+
}
15+
16+
fs.writeFileSync(process.cwd() + '/localhostify-ext/config.js', chromeConfig);
17+
fs.copyFileSync(__dirname + '/../chrome-ext/manifest.json', process.cwd() + '/localhostify-ext/manifest.json');
18+
fs.copyFileSync(__dirname + '/../chrome-ext/scripts/http.js', process.cwd() + '/localhostify-ext/scripts/http.js');
19+
fs.copyFileSync(__dirname + '/../chrome-ext/scripts/fetch.js', process.cwd() + '/localhostify-ext/scripts/fetch.js');
20+
21+
console.log("Localhostify: Chrome Ext created in localhostify-ext folder.");

bin/localhostify.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
#!/usr/bin/env node
2+
const env = process.argv[2];
23

3-
require('../dist/index');
4-
5-
4+
if (env === '--chrome-ext') {
5+
require('./createConfig.js');
6+
} else {
7+
require('../dist/index.js');
8+
}

chrome-ext/config.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
__LOCALHOSTIFY__ = {
2+
"externalRedirects": [
3+
]
4+
}

chrome-ext/manifest.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"name": "Localhostify",
3+
"version": "0.0.1",
4+
"manifest_version": 2,
5+
"description": "Localhostify: External redirects interceptor",
6+
"background": {
7+
"scripts": ["config.js", "scripts/http.js"]
8+
},
9+
"content_scripts": [
10+
{
11+
"all_frames": true,
12+
"js": ["config.js", "scripts/fetch.js"],
13+
"matches": ["http://*/*", "https://*/*"],
14+
"run_at": "document_start"
15+
}
16+
],
17+
"permissions": ["tabs", "webRequest", "webRequestBlocking", "<all_urls>"]
18+
}

chrome-ext/scripts/fetch.js

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/* handle custom redirects after fetch */
2+
3+
function interceptor() {
4+
const externalMatches = ['accounts.google.com'];
5+
const needIntercept = (url) => externalMatches.some((d) => new RegExp(d).test(url));
6+
const { externalRedirects } = window.__LOCALHOSTIFY__;
7+
8+
const onReadyStateChange = function () {
9+
if (this.readyState === 4 && needIntercept(this.responseURL)) {
10+
const { responseURL, responseType, response } = this;
11+
12+
if (responseType === '' || responseType === 'text') {
13+
Object.defineProperty(this, 'responseText', {
14+
get: function () {
15+
let replacedResponse = response;
16+
17+
externalRedirects.forEach((rule) => {
18+
if (new RegExp(rule.match).test(replacedResponse)) {
19+
replacedResponse = replacedResponse.replace(rule.replace[0], rule.replace[1]);
20+
}
21+
});
22+
23+
if (response !== replacedResponse) {
24+
console.log('Localhostify -> ', JSON.stringify({ responseURL, response, replacedResponse }, 0, 2));
25+
}
26+
return replacedResponse;
27+
},
28+
});
29+
}
30+
}
31+
};
32+
33+
const XHR = XMLHttpRequest;
34+
XMLHttpRequest = function () {
35+
const xhr = new XHR();
36+
xhr.requestURL;
37+
xhr.addEventListener('readystatechange', onReadyStateChange.bind(xhr), false);
38+
return xhr;
39+
};
40+
41+
XMLHttpRequest.prototype = XHR.prototype;
42+
Object.entries(XHR).map(([key, val]) => {
43+
XMLHttpRequest[key] = val;
44+
});
45+
46+
const open = XMLHttpRequest.prototype.open;
47+
XMLHttpRequest.prototype.open = function (method) {
48+
this.method = method;
49+
open.apply(this, arguments);
50+
};
51+
52+
const send = XMLHttpRequest.prototype.send;
53+
XMLHttpRequest.prototype.send = function (data) {
54+
this.requestData = data;
55+
send.apply(this, arguments);
56+
};
57+
58+
let setRequestHeader = XMLHttpRequest.prototype.setRequestHeader;
59+
XMLHttpRequest.prototype.setRequestHeader = function (header, value) {
60+
this.requestHeaders = this.requestHeaders || {};
61+
this.requestHeaders[header] = value;
62+
setRequestHeader.apply(this, arguments);
63+
};
64+
}
65+
66+
const interceptorScript = interceptor.toString();
67+
const config = 'window.__LOCALHOSTIFY__=' + JSON.stringify(window.__LOCALHOSTIFY__, 0, 2) + ';';
68+
69+
const script = document.createElement('script');
70+
script.className = 'localhostify';
71+
script.type = 'text/javascript';
72+
script.appendChild(document.createTextNode(`${config} (${interceptorScript})()`));
73+
74+
const parent = document.head || document.documentElement;
75+
parent.appendChild(script);

chrome-ext/scripts/http.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/* HTTP headers Location redirect */
2+
3+
const { externalRedirects } = window.__LOCALHOSTIFY__;
4+
5+
chrome.webRequest.onHeadersReceived.addListener(
6+
function (details) {
7+
const headers = details.responseHeaders;
8+
9+
for (var i = 0, l = headers.length; i < l; ++i) {
10+
if (headers[i].name.toLowerCase() === 'location') {
11+
const originalLocation = headers[i].value;
12+
13+
externalRedirects.forEach((rule) => {
14+
if (new RegExp(rule.match).test(headers[i].value)) {
15+
headers[i].value = headers[i].value.replace(rule.replace[0], rule.replace[1]);
16+
}
17+
});
18+
19+
if (originalLocation !== headers[i].value) {
20+
const { url, documentUrl } = details;
21+
console.log('Localhostify -> ', { url, documentUrl, originalLocation, location: headers[i].value });
22+
}
23+
}
24+
}
25+
return { responseHeaders: headers };
26+
},
27+
{ urls: ['<all_urls>'] },
28+
['responseHeaders', 'blocking'],
29+
);

0 commit comments

Comments
 (0)