const mysql = require('mysql') const Spawner = require('child_process'); const crypto = require('crypto'); const request = require('request'); const cheerio = require('cheerio'); class Child { /** * * @param {String} userID -User's Hash */ constructor(userID) { this.ID = userID; this.child = Spawner.fork('./worker.js',[this.ID]); this.birth = process.uptime(); this.timeOut = setTimeout(() => { this.child.kill('SIGINT'); },2*60*60*1000); } get EOL() { const EOL = Math.trunc((this.timeOut._idleTimeout - ((process.uptime()*1000)-this.birth))/1000); return EOL>0?EOL:0; } getMapData() { return new Promise((resolve, reject)=> { this.child.send('MapData'); this.child.on('message', m=> { if(typeof m == Object) { resolve(m.name); } }) }) } waitStart() { return new Promise((resolve, reject)=> { var status = setInterval(() => { if(this.isOpen) { clearInterval(status); resolve(true) } }, 100); }) } createMapImage() { return new Promise((resolve, reject)=> { this.child.send('MapImage') this.child.on('message', m=> { if(typeof m == String && m === 'Done') { resolve(m); } }) }) } getConsole() { return new Promise((resolve, reject)=> { this.child.send('Console') this.child.on('message', m=> { resolve(m); }) }) } }module.exports.Child = Child; class playerCache { /** * * @param {String} Name * @param {String} SteamID * @param {Number} Ping * @param {String} Address IP * @param {Number} ConnectedSeconds * @param {Number} Health * @param {Object} Teammates ??'Not in a team' * @param {String} Position ??'Not spawned yet' */ constructor(Name, SteamID, Ping, Address,ConnectedSeconds, Health, Teammates, Position) { this.Displayname = Name; this.SteamID = SteamID; this.Address = Address; this.Health = Health; this.Teammates = Teammates??'NOT IN A TEAM'; this.Position = Position??'NOT SPAWNED YET'; this.Ping = Ping; this.ConnectedSeconds = ConnectedSeconds; } }module.exports.playerCache = playerCache; class ServerCache { constructor(ID,Hostname,MaxPlayers, GameTime, Framerate, NetworkIn, NetworkOut, Seed, WorldSize) { this.ID = ID; this.Hostname=Hostname; this.MaxPlayers =MaxPlayers; this.GameTime = GameTime; this.Framerate = Framerate; this.NetworkIn = NetworkIn; this.NetworkOut = NetworkOut; this.Seed = Seed; this.WorldSize = WorldSize; this.Console = []; } get WorldData () { return { Seed:this.Seed, Size:this.WorldSize, Time:this.GameTime } } get NetWorkData () { return { Framerate:this.Framerate, In:this.NetworkIn, Out:this.NetworkIn } } get ConsoleData () { return this.Console; } get BasicData () { return { HostName:this.Hostname, MaxPlayers:this.MaxPlayers, GameTime:this.GameTime } } }module.exports.ServerCache = ServerCache; class pChild { constructor(ip, port, pw) { this.ip = ip; this.port = port; this.pw = pw; this.child = Spawner.fork('./pWorker.js'); } /** * @argument {*} - Anything */ sendData() { for (var i = 0; i < arguments.length; i++) { } } /** * To be used with programmed commands * @param {String} command - Command to be sent */ send(command) { return new Promise((resolve, reject)=> { this.child.send({'command':command, 'ip':this.ip, 'port':this.port, 'pw':this.pw}); this.child.on('message', (m)=> { if(typeof m=='string') { if(m ==='end') { resolve(); } } else { reject("Worker didn't respond to querry.") } }) }) } close () { return new Promise((resolve, reject)=> { resolve(this.child.disconnect()); }) } }module.exports.pChild = pChild; class rustChild { constructor(size, seed) { this.child = Spawner.exec(`cmd /c updateServer.bat ${size} ${seed}`) } }module.exports.rustChild = rustChild; class DBConnection { constructor() { this.connection = mysql.createConnection( { host:'localhost', user:'root', password:'root', database:'legendary' }) this.connection.connect(); } close() { setTimeout(() => { this.connection.destroy(); }, 2000); } //User get Users() { return new Promise((resolve, reject)=> { this.connection.query('Select * from administrator', (e, r, f)=> { if(!e) { let aux = JSON.parse(JSON.stringify(r)) var payload =[]; for( var i = 0; i { this.UData(Hash).then( m=> { if(m.Server=='No server') { reject(false) } else { resolve(true) } } ) }) } UData(HASH) { return new Promise((resolve, reject)=> { this.connection.query(`SELECT * FROM administrator WHERE Hash = '${HASH}' `, (e, r, f)=> { if(e)reject(e); r = JSON.parse(JSON.stringify(r))[0]; resolve({ id:r.A_ID, Hash:r.Hash, Email:r.EHash, Server:r.IP || 'No server', Port: JSON.stringify(r.Port) || 'No server', SPW:r.sv_pw, Epoch:r.Epoch }) this.close(); }) }) } get_ID(hash) { return new Promise((resolve, reject)=> { //User this.Users.then((x)=> { for(var i =0; i { resolve(m.id); }) .catch(()=>reject('no ID for this hash')) } } }).catch(m=> { console.log(m); reject('no ID for this HASH'); }); }) } getCommands(Hash) { return new Promise((resolve, reject)=> { this.get_ID(Hash).then(id=> { this.connection.query(`Select * from legendary.timed_com where administrator_A_ID = '${id}'`, (e, r, f)=> { if(e)reject(e); resolve(JSON.parse(JSON.stringify(r))); }) }) }) } addCommand(Hash, Command, Loop, Send, tz) { this.get_ID(Hash).then(id=> { this.connection.query(`INSERT INTO legendary.timed_com (\`Command\`, \`Loop\`, \`Send\`, \`administrator_A_ID\`) VALUES ('${Command}', '${Loop}', '${Send}', '${id}')`); this.close(); }) } removeCommand(id) { return new Promise((resolve, reject)=> { this.connection.query(`DELETE FROM legendary.timed_com WHERE (T_ID = ${id});`, (e, r, f)=> { if(e)reject(e) if(r.affectedRows>0)resolve() }) this.close() }) } editCommand(id, Command, Loop, Send, tz) { this.connection.query(`UPDATE legendary.timed_com SET \`Command\` = '${Command}', \`Loop\` = '${Loop}',\`Send\` = '${Send}' WHERE (T_ID = '${id}')`) this.close() } addUser(Hash, EHash, Epoch) { if(Hash||EHash||Epoch) { this.connection.query(`INSERT INTO legendary.administrator (Hash, EHash, Epoch) VALUES ('${Hash}', '${EHash}', '${Epoch}')`) this.close() } } updateUser(HASH, NewHASH) { return new Promise((resolve, reject)=> { this.get_ID(HASH).then((m)=> { this.connection.query(`UPDATE administrator SET Hash='${NewHASH}' WHERE A_ID = ${m}`); this.close(); resolve(NewHASH); }).catch((err)=>reject(err)); }) } addServer(HASH, IP, PW, PORT) { //needs to know what user should it be connected to this.connection.query(`INSERT INTO adminsitrator (ServerIP, ServerPW, ServerPort) VALUES ('${HASH}', '${IP}','${PW}', '${PORT}')`) this.close(); } updateServer(Hash, IP, PW, PORT) { this.get_ID(Hash).then((id)=> { this.connection.query(`UPDATE administrator SET IP = '${IP}', sv_pw = '${PW}', port='${PORT}' WHERE A_ID = ${id}`); this.close(); }).catch(e=>console.log('error',e)) } get_Players(Hash) { return new Promise((resolve, reject)=> { this.connection.query(`SELECT * FROM player INNER JOIN time ON player.p_id = time.player_p_id where administrator_a_id = (SELECT A_ID FROM administrator WHERE Hash = '${Hash}') order by player_p_id asc;`,(e,r,f)=> { if(e)reject(e);this.close; try { // console.log('Classes: DBConnection: Get_Players: r: ', r); r = JSON.parse(JSON.stringify(r)); resolve(r) } catch (err) { reject(err) } this.close; }) }) } }module.exports.DBConnection = DBConnection; class _Crypto { constructor(User, Password) { this.salt = 'H$44Q3RVCd9X8Ef63tB4'; this.secret = 'mYFUZX9NSx7K74r7Jh@O'; this.pepper = String.fromCharCode(this.getRandomInt(65, 90)); this.password = Password; this.user = User; this.algorithm = 'aes-192-cbc'; } get Hash() // to use on register { return this.hash() } hash(p) { if(!p) { return crypto.createHmac('sha256', this.secret).update(this.user+this.password+this.salt+this.pepper).digest('hex'); } else { return crypto.createHmac('sha256', this.secret).update(this.user+this.password+this.salt+p).digest('hex'); } } eHash(Email) { return new Buffer.from(Email).toString('base64'); } decrypt(eHash) { return new Buffer.from(eHash, 'base64').toString('utf8'); } getRandomInt(min, max) { min = Math.ceil(min); max = Math.floor(max); return Math.floor(Math.random() * (max - min)) + min; } compare() // to use on login { return new Promise((resolve, reject)=> { new DBConnection().Users .then((Users)=> { for(var i=0; i<26;i++) { const nPepper = String.fromCharCode(65+i); const hash = this.hash(nPepper); for(var j = 0; j { console.log('error'+m); }) }); } }module.exports._Crypto = _Crypto; class Epoch { /** * * @param {Number} Days - Must be and integer. */ constructor(Days) { this.Days = (Days*(24*60*60)); this.epoch = this.epocher(); } epocher() { return Math.floor(this.Days + Date.now()/1000) } /** * @param {String} time - Must follow the format of '18:12'. */ sEpoch(time) { let hours = time.split(':')[0]; let minutes = time.split(':')[1]; return Math.floor(this.next(hours, minutes)/1000); } /** * @param {Number} time - Must be and integer. */ toDate(time) { //console.log('classes:toDate:', time) const d = new Date(time*1000); return d.getHours()+':'+ d.getMinutes(); } /** * Returns the next possible time for the command to be sent. Meaning if the hours inputed by the user * have already gone past this day then the epoch will be set for the next. * If not the epoch will be created like usual. * * @param {Number} hours * @param {Number} minutes */ next(hours, minutes) { var d= new Date(); var payload = new Date(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), hours, minutes, 0, 0).getTime(); //console.log('Classes:Next:',hours, minutes, payload) return payload; } }module.exports.Epoch = Epoch; class IPTranslator { constructor(IP) { this.IP = IP; } translate() { return new Promise((resolve, reject)=> { request(`http://ip-api.com/json/${this.IP}`, (e,r,b)=> { var body if(!e) { try { body = JSON.parse(b); } catch (error) { console.log('IP Transalator: Bad Parse.'); resolve('Err') } resolve(body); } else { resolve( {'status':'error'}); } }) }) } CC() { return new Promise((resolve, reject)=> { this.translate().then(m=>resolve(m.countryCode)).catch(e=> { console.log('IP Translator: CountryCode:'+e); reject(e); }) }) } }module.exports.IPTranslator = IPTranslator; class VAC { constructor(SteamID) { this.SteamID = SteamID; } get ban() { return new Promise((resolve,reject)=> { request(`http://vacbanned.com/engine/check?qsearch=${this.SteamID}`, (e,r,b)=> { if(e)reject('VAC: Request:'+e) const $ = cheerio.load(b); // console.log('Worker: VAC: body: ', $('td').text()); $('.strong').remove() request(`http://api.steampowered.com/IPlayerService/GetOwnedGames/v0001/?key=DCA47FAA9F3D1485FA8C1F4FA15A5266&steamid=${this.SteamID}&format=json`, (e,r,steamb)=> { if(e)reject('VAC: FS: Request:'+e) var fs; let aux //console.log('Vac class: SteamAPI', steamb) try { aux = JSON.parse(steamb)['response'].games; } catch (error) { console.log('JSON parse error: ',error); } if(aux) { for (let i = 0; i < aux.length; i++) { // console.log('VAC: FS: Request2: '+aux[i].appid, '252490'); if(aux[i].appid) { if(aux[i].appid=='252490') { i = aux.length; fs = 'NO' } else { fs='Yes' } } } var vac; try { vac = $('td').text().replace(/ /g, '').split('Hex)')[1].replace(/\n/g, 'SPLIT').split('SPLIT')[1]; } catch (error) { vac = 'Error'; } let payload = { 'vac':vac, 'fs':fs } // console.log('VAC: Payload: ', payload) resolve(payload); } else { var vac; try { vac = $('td').text().replace(/ /g, '').split('Hex)')[1].replace(/\n/g, 'SPLIT').split('SPLIT')[1]; } catch (error) { vac = 'Error'; } let payload = { 'vac':vac, 'fs':fs } resolve(payload); } }) }); }) } }module.exports.VAC = VAC; /** * Use it to transform an hour value into miliseconds. * @param {Number} Hours - Hours to transform */ function hours(Hours) { return Hours*60*60*1000; } /** * This function writes a cookie on the client side. * Primary use: Store users Hash for every other page. * @argument {Response} res - Response: express response object. * @argument {String} name - Name of the cookie. * @argument {*} value - Value of the cookie. */ exports.baker = (res, name, value) => { return new Promise((resolve,reject)=> { try { res.cookie(name, '',{maxAge:0}); res.cookie(name, value, {maxAge:hours(2),path:'/',secure:false,httpOnly:false}); resolve(); } catch (e) { reject(e) } }) } /** * Hash used on register to check if there is already a user with the same credentials. * @param {String} user - User's email * @param {String} password - User's Password * @param {String} hash - User's identifying hash */ exports.bouncer = (user, password, hash) => { return new Promise((resolve, reject)=> { new _Crypto(user, password).compare().then(m=> { if(hash) { if(m==hash) { resolve(m) } else { reject('You are on a different account.') } } else { resolve(m) } }).catch(m=> { reject(m) }) }) } /** * Reduces the number of decimal cases to the required value. * @param {Number} num - The number you want to cut to size. * @param {Number} decimal - Ammount of decimal cases. */ exports.toFixed = (num, decimal)=> { decimal = decimal || 0; decimal = Math.pow(10, decimal); return Math.floor(num * decimal) / decimal; } /** * Transforms a value into a 0-1 value given the max value it could take. * @param {Number} val - Value to transform to percentage * @param {Number} max - Maximum the value could be */ exports.toPercent = (val, max)=> { return val/max; } /** * Removes the timezone difference to a time. * @param {String} time - Must follow 'HH:MM' format. * @param {Number} offSet - Number of minutes from gmt+0. */ exports.removeTZ = (time, offSet)=> { var h = parseInt(time.split(':')[0]); var maux = parseInt(time.split(':')[1]); var m = maux - offSet; var d = new Date(); var payload = new Date(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), h, m, 0, 0).toString().split(' ')[4].split(' ')[0].slice(0,-3); return payload; } /** * Adds timezone difference to a time. * @param {String} time - Must follow 'HH:MM' format. * @param {Number} offset - Number of minutes from gmt+0. */ exports.addTZ = (time, offset) => { offset = parseInt(offset); let h = parseInt(time.split(':')[0]); let m = parseInt(time.split(':')[1])+offset; var d= new Date(); return payload = new Date(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDay(), h, m, 0, 0).toString().split(' ')[4].split(' ')[0].slice(0,-3); }