Skip to content

Instantly share code, notes, and snippets.

@JLChnToZ
Last active December 7, 2017 16:31
Show Gist options
  • Save JLChnToZ/a0922d1645ba388c2f742775483a0598 to your computer and use it in GitHub Desktop.
Save JLChnToZ/a0922d1645ba388c2f742775483a0598 to your computer and use it in GitHub Desktop.
Inject external JavaScript like a ninja
var ninjectScript = (function(window, document) {
var head = document.head || document.getElementsByTagName('head')[0],
BlobBuilder,
builderPrefixes = [
'webkit', 'Webkit', 'WebKit',
'moz', 'Moz', 'o', 'O',
'ms', 'Ms', 'MS',
'khtml', 'Khtml', ''
];
return function(src, loadCallback) {
var request = getXHR();
if(!request) return injectScriptOld(src, loadCallback);
request.responseType = 'blob';
request._load = loadCallback;
request.onload = onXHRLoad;
request.open('GET', src);
request.send();
};
function injectScriptOld(src, loadCallback) {
var script = document.createElement('script');
script._load = loadCallback;
script.onload = onScriptLoad;
script.src = src;
head.appendChild(script);
}
function onXHRLoad() {
var response = this.response, useText;
if(typeof response === 'string') {
var blobResponse = getBlob(response, 'text/javascript');
useText = !blobResponse;
response = blobResponse || response;
}
var script = document.createElement('script');
if(useText) {
if(Object.getOwnPropertyDescriptor(script, 'textContent'))
script.textContent = response;
else
script.innerHTML = response;
setTimeout(onScriptContentLoad, 1, script, this._load);
} else {
script._load = this._load;
script.onload = onScriptLoad;
script.async = true;
script.src = URL.createObjectURL(response);
}
head.appendChild(script);
}
function onScriptLoad(e) {
try {
URL.revokeObjectURL(this.src);
} catch(ex) {}
onScriptContentLoad(this, this._load);
}
function onScriptContentLoad(script, loadCallback) {
try {
script.parentElement.removeChild(script);
} catch(err) {}
try {
if(typeof loadCallback === 'function')
loadCallback.call(script);
} catch(err) {}
}
function getXHR() {
if(window.XMLHttpRequest) return new window.XMLHttpRequest();
try {
return new ActiveXObject('MSXML2.XMLHTTP.6.0');
} catch(err) {}
try {
return new ActiveXObject('MSXML2.XMLHTTP.3.0');
} catch(err) {}
}
function getBlob(content, type) {
if(window.Blob)
return new window.Blob([content], { type: type });
if(!BlobBuilder) {
if(BlobBuilder === null) return;
if(window.BlobBuilder)
BlobBuilder = window.BlobBuilder;
else
for(var i = 0; !BlobBuilder || i < builderPrefixes.length; i++)
BlobBuilder = window[builderPrefixes[i] + 'BlobBuilder'];
if(!BlobBuilder) BlobBuilder = null;
}
var builder = new BlobBuilder();
builder.append(content);
return builder.getBlob(type);
}
})(window, document);
// Optional snippet that can be placed at the end of your script
// It will make your inline <script> tag become invisible:
(function(element) {
try { if(element) element.parentElement.removeChild(element); } catch(err) {}
})(document.currentScript);
// Usage:
ninjectScript('https://example.com/something/invisible.js', function() {
console.log('Script loaded with Ninjector, and you can\'t see where it has loadad to, even inspecting it:\n%s', this.src);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment