Last active
December 7, 2017 16:31
-
-
Save JLChnToZ/a0922d1645ba388c2f742775483a0598 to your computer and use it in GitHub Desktop.
Inject external JavaScript like a ninja
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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