Files
2025-09-29 00:52:08 +02:00

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)
}
}