208 lines
5.6 KiB
JavaScript
Executable File
208 lines
5.6 KiB
JavaScript
Executable File
var url = require('url')
|
|
, http = require('http')
|
|
, fs = require('fs')
|
|
, WebSocketServer = require('ws').Server
|
|
, express = require('express')
|
|
, app = express()
|
|
, RpcProxyClient = require('./RpcProxyClient.js')
|
|
, ScsAccessToken = require('./scsaccesstoken')
|
|
|
|
const LOG_FILE = "./websocket.log"
|
|
|
|
function socketPair(clientSocket, serverSocket){
|
|
this.client = clientSocket,
|
|
this.server = serverSocket
|
|
}
|
|
|
|
module.exports = RpcProxyServer = function(target, port, modifyMessageToClient, modifyMessageToServer, logger)
|
|
{
|
|
this.sockets = [];
|
|
this.target = target;
|
|
this.clientModify = modifyMessageToServer;
|
|
this.serverModify = modifyMessageToClient;
|
|
this.logger = logger;
|
|
this.logSocket = null;
|
|
|
|
//Setting up file write stream for log file
|
|
this.logStream = fs.createWriteStream(LOG_FILE, {
|
|
defaultEncoding : 'utf8',
|
|
autoClose : true,
|
|
})
|
|
this.logStream.on('close',()=>{
|
|
console.log('Connection to LogFile closed')
|
|
this.logStream = undefined;
|
|
})
|
|
this.logStream.on('error',(err)=>{
|
|
console.error(err)
|
|
})
|
|
|
|
if(!port)
|
|
port = 8181
|
|
this.port = port;
|
|
}
|
|
|
|
RpcProxyServer.prototype.start = function(){
|
|
var self = this;
|
|
|
|
//Proxy Websocket Server
|
|
var server = http.createServer();
|
|
var wss = new WebSocketServer({
|
|
server: server,
|
|
handleProtocols: self.handleProtocols,
|
|
verifyClient: self.verifyClientConnection
|
|
})
|
|
|
|
wss.on('connection', function connection(ws) {
|
|
self.initProxyServer(ws)
|
|
});
|
|
|
|
//Turn on Proxy HTTP server
|
|
server.on('request', app);
|
|
server.listen(self.port, function () { console.log('RPC Websocket Server listening on ' + server.address().port) });
|
|
|
|
|
|
if(self.logger){
|
|
logHTTP = http.createServer();
|
|
|
|
var lss = new WebSocketServer({
|
|
server: logHTTP,
|
|
// handleProtocols: self.handleProtocols,
|
|
verifyClient: self.verifyClientConnection
|
|
})
|
|
|
|
lss.on('connection', function connection(ws) {
|
|
self.IsConnected = true;
|
|
ws.onmessage = (evt)=>{
|
|
self.handleLoggerPacket(evt,self)
|
|
};
|
|
|
|
self.logSocket = ws;
|
|
});
|
|
|
|
logHTTP.listen(4444, ()=>{ console.log("Logger websocket listening on 4444")});
|
|
}
|
|
}
|
|
|
|
RpcProxyServer.prototype.initProxyServer = function(ws) {
|
|
var self = this;
|
|
|
|
var location = url.parse(ws.upgradeReq.url, true);
|
|
|
|
//Get SCS Token from auth query string
|
|
var scsToken = new ScsAccessToken();
|
|
if(!scsToken.decode(location.query.auth)){
|
|
console.error("Decoding SCS Token failed, killing socket")
|
|
console.error("SCSToken: %o",scsToken)
|
|
ws.close();
|
|
return false;
|
|
}
|
|
|
|
console.log("Websocket Index: "+ self.sockets.length + " | Account : " + scsToken)
|
|
|
|
//Websocket to communicate with Game Client Socket
|
|
var clientSock = new RpcProxyClient(null, scsToken, self.clientModify, self.sockets.length, self);
|
|
|
|
//Websocket to communicate with Server Socket
|
|
var serverSock = new RpcProxyClient(self.target, scsToken, self.serverModify, self.sockets.length, self);
|
|
|
|
//Loads up the client socket with the websocket that resulted from the game client connecting to the proxy
|
|
clientSock.load(ws,serverSock);
|
|
|
|
//Connects the server socket to the target server, using the path provided by the game client
|
|
serverSock.connect(location.path,clientSock);
|
|
|
|
//Create socketPair object, and add to list.
|
|
var pair = new socketPair(clientSock, serverSock)
|
|
self.sockets.push(pair);
|
|
|
|
console.log('Client Connected');
|
|
}
|
|
|
|
RpcProxyServer.prototype.handleProtocols = function(protocols, callback) {
|
|
var protos = ["mux.json-rpc.rockstargames.com","json-rpc.rockstargames.com"];
|
|
|
|
console.log("Client offered these protocols: "+ protocols);
|
|
callback(true,protocols[0])
|
|
}
|
|
|
|
RpcProxyServer.prototype.verifyClientConnection = function(info, callback) {
|
|
console.log("Origin header: " + info.origin)
|
|
console.log("Client request: ")
|
|
console.log("%s %s \n", info.req.method, info.req.url, info.req.headers,'\n')
|
|
console.log("Secure connection: " + info.secure)
|
|
|
|
callback(true);
|
|
}
|
|
|
|
RpcProxyServer.prototype.log = function(msg, index, isServer, channel, scsToken){
|
|
var self = this;
|
|
|
|
if(typeof(msg) !== 'string'){
|
|
console.error("\nLog server expects string as data payload\n")
|
|
return false;
|
|
}
|
|
|
|
try{
|
|
var msgObj = JSON.parse(msg)
|
|
}catch(err){
|
|
console.error("\n\nLog payload does not seem to be valid JSON\n")
|
|
console.error(err)
|
|
msgObj = msg
|
|
}
|
|
|
|
var logObj = {
|
|
data : msgObj,
|
|
target : {
|
|
index : index,
|
|
to : (isServer ? 'client' : 'server'),
|
|
channel : channel.toString('hex'),
|
|
token : scsToken
|
|
}
|
|
};
|
|
|
|
try{
|
|
var logPacket = JSON.stringify(logObj)
|
|
}catch(err){
|
|
console.error("\n\nError parsing log packet\n")
|
|
console.error(err)
|
|
return false
|
|
}
|
|
|
|
//Write to log file
|
|
if(self.logStream){
|
|
self.writeToLog(self.logStream, logPacket)
|
|
}
|
|
|
|
//Send to log socket
|
|
if(self.logger && self.logSocket){
|
|
self.logSocket.send(logPacket);
|
|
}
|
|
}
|
|
|
|
RpcProxyServer.prototype.writeToLog = function(stream, str) {
|
|
var result = stream.write(str+'\n','utf8')
|
|
if(!result){
|
|
stream.once('drain', writeToLog)
|
|
}
|
|
}
|
|
|
|
RpcProxyServer.prototype.handleLoggerPacket = function(evt, server) {
|
|
var self = this;
|
|
try{
|
|
var txt = new Buffer(evt.data).toString()
|
|
console.log("From Logger:\n")
|
|
console.log(txt,'\n')
|
|
var msg = JSON.parse(txt)
|
|
var target = msg.target;
|
|
var data = msg.data;
|
|
|
|
var socks = server.sockets[target.index];
|
|
var payload = JSON.stringify(data);
|
|
var packet = socks[target.to].encodeChannelMessage(payload, new Buffer(target.channel, 'hex'))
|
|
socks[target.to].send(packet)
|
|
|
|
console.log("\n---------------------------------------------\n")
|
|
}catch(err){
|
|
console.error(err)
|
|
}
|
|
} |