/** * @project iii-client * @author Valentin Popov * @license See LICENSE.md file included in this distribution. */ var http = require('http'); exports.connect = connect; /** * Connects to the server and returns the connection data. * @param {String} uuid - The bot UUID. * @param {requestCallback} callback - The callback that handles the response. */ function connect(uuid, callback) { uuid = uuid || ''; if (!_verification(uuid)) { throw new Error('The UUID is not a valid value!'); } const query = { port: 80, hostname: 'iii.ru', path: '/api/2.0/json/Chat.init/' + uuid + '/', method: 'GET', }; const request = http.request(query, function(response) { var json = ''; response.on('data', (raw) => json = _decryptJSON(raw)); response.on('end', () => callback(json.result)); }); request.on('error', (error) => Error(error.message)); request.end(); } exports.send = send; /** * Send a message to the server and return a response. * @param {Object} raw - The data to send. * @param {String} raw.cuid - Session identifier. * @param {String} raw.text - Message text. * @param {requestCallback} callback - The callback that handles the response. */ function send(raw, callback) { raw = raw || {}; const query = { port: 80, hostname: 'iii.ru', path: '/api/2.0/json/Chat.request', method: 'POST', }; const data = _createPackage(raw); const request = http.request(query, function(response) { var json = ''; response.on('data', (raw) => json = _decryptJSON(raw)); response.on('end', () => callback(json)); }); request.on('error', (error) => Error(error)); request.write(data); request.end(); } exports._encrypt = _encrypt; /** * Encrypts the incoming data. * @param {String} raw - Decrypted data. * @returns {String} - Encrypted string. */ function _encrypt(raw) { raw = raw || ''; var base64 = Buffer.from(raw).toString('base64'); var string = Buffer.from(base64); return _merger(string).toString('base64'); } exports._decrypt = _decrypt; /** * Decrypts the incoming data. * @param {String} raw - Encrypted data. * @returns {String} - Decrypted string. */ function _decrypt(raw) { raw = raw || ''; var string = Buffer.from(raw, 'base64'); var decrypted = _merger(string).toString(); return Buffer.from(decrypted, 'base64'); } exports._decryptJSON = _decryptJSON; /** * Decrypts an encrypted JSON object. * @param {String} raw - Encrypted data. * @returns {Object} - Decrypted JSON. */ function _decryptJSON(raw) { raw = raw || ''; var string = raw.toString('ascii'); var data = _decrypt(string); return JSON.parse(data); } exports._merger = _merger; /** * Merge and convert a string. * @param {String} raw - The string to convert. * @returns {String} - The converted string. */ function _merger(data) { data = data || ''; const salt = Buffer.from('some very-very long string without any non-latin characters due to different string representations inside of variable programming languages'); for (var i = 0; i < data.length; i++) { data[i] = data[i] ^ salt[i % salt.length]; } return data; } exports._createPackage = _createPackage; /** * Creates an encrypted package to send. * @param {Object} raw - The data to send. * @param {String} raw.cuid - Session identifier. * @param {String} raw.text - Message text. * @returns {String} - Encrypted string. */ function _createPackage(raw) { raw = raw || {}; if (!raw.text) { throw new Error('There is no data to send!'); } if (!_verification(raw.cuid)) { throw new Error('Parameter \'CUID\' is not a valid UUID value!'); } var data = []; data.push(raw.cuid); data.push(raw.text.toString()); var json = JSON.stringify(data); return _encrypt(json); } exports._verification = _verification; /** * Validation UUID format string. * @param {String} data - The string to check. * @returns {Boolean} */ function _verification(data) { data = data || ''; const regexp = new RegExp('^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$', 'i'); return regexp.test(data); }