Skip to content

Instantly share code, notes, and snippets.

@csprance
Last active January 13, 2018 23:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save csprance/b5f4787772fa2cca79acd34ef2f2580f to your computer and use it in GitHub Desktop.
Save csprance/b5f4787772fa2cca79acd34ef2f2580f to your computer and use it in GitHub Desktop.
/**
* Name: rconUtils
* Created by chris on 4/26/2017.
* Description: Sends a command to a Miscreated server and parses the response
* // RCON Steps
* --- 1 ---
* // Request: challenge
* // Response: uptime
* --- 2 ---
* // Request: md5(uptime:password)
* // Response: AuthResponse
* --- 3 ---
* // Request: CommandString
* // Response: RCONResult
*/
const axios = require('axios');
const Promise = require('bluebird');
const {parseString} = require('xml2js');
const md5 = require('md5');
const http = require('http');
/**
* Sends a command via XMLRPC to a server and returns a promise response
* @constructor
* @param {Object} options object containing user credentials and command
* {ip:[ip], port:[port], password:[password], command: [command]}
* @returns{promise} response returns a promise that resolves to a String
*/
const sendRCONCommandToServer = (options) => {
// return a promise so we can use .then(res=> function );
return new Promise(function (resolve, reject) {
// the server url to send the commands to
const serverUrl = `http://${options.ip}:${options.port}/rpc2`;
// axios config
const config = {
headers: {'Content-Type': 'text/xml'},
httpAgent: new http.Agent({keepAlive: true}),
};
// create the initial challenge string to send to the server
const challengeString = createChallengeString();
// send the initial challenge
// Request: challenge
axios.post(serverUrl, challengeString, config).then(res => {
// create challengeResponseRequest String
// Response: uptime
let upTime = getUpTimeFromChallengeResponse(res.data);
console.log(upTime);
let challengeResponseRequest = createChallengeResponseString(upTime, options.password);
// send the challenge request back to the server
// Request: md5(uptime:password)
return axios.post(serverUrl, challengeResponseRequest, config);
}).then(res => {
// handle auth error send reject so we can catch promise errors
// Response: AuthResponse
parseAuthResponse(res.data, reject);
// build the command to send to the server from the user
let commandString = createCommandString(options.command);
// execute axios post request
// Request: CommandString
axios.post(serverUrl, commandString, config).then(res => {
// resolve the string response back
// Response: RCONResult
resolve(parseCommandResponse(res.data));
});
// END OF THE LINE!
})
});
};
function createChallengeString() {
return `<methodCall><methodName>challenge</methodName><params></params></methodCall>`;
}
function createChallengeResponseString(upTime, password) {
// by doing md5(uptime:password)
return `<methodCall><methodName>authenticate</methodName><params><param><value><string>${md5(`${upTime}:${password}`)}</string></value></param></params></methodCall>`;
}
function createCommandString(command) {
return `<methodCall><methodName>${command}</methodName><params></params></methodCall>`;
}
function getUpTimeFromChallengeResponse(str) {
// server response looks like
// <methodResponse><params><param><value><string>31268616.000000</string></value></param></params></methodResponse>
//get the uptime by parsing the xml
let uptime = '';
parseString(str, (err, result) => {
uptime = result.methodResponse.params[0].param[0].value[0].string[0];
});
return uptime;
}
function parseCommandResponse(str) {
// server response looks like
//<methodResponse><params><param><value><string>{server response}</string></value></param></params></methodResponse>
let res = '';
parseString(str, (err, result) => {
// parse the response
res = result.methodResponse.params[0].param[0].value[0].string[0];
});
return res;
}
const parseAuthResponse = (data, reject) => {
// server response looks like this
// <?xml version="1.0"?><methodResponse><params><param><value><string>authorized</string></value></param></params></methodResponse>
// stub function
// sometimes auth passes after a few tries it just keeps the connection open
// Handle auth failed here
let authResults = '';
parseString(data, (err, result) => {
authResults = result.methodResponse.params[0].param[0].value[0].string[0];
console.log('authResults: ', authResults);
// if (authResults !== 'authorized') {
// reject('Incorrect Password');
// }
});
return authResults;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment