// Load the settings var settings = require("./settings.json"); // Create an rsa key var rsa_key; function toBuffer(bytes) { // String if(typeof(bytes) == 'string') { // Create a buffer var buffer = new Buffer.alloc(bytes.length); // Loop over the bytes for(var i=0;i= 4) { // Get the number recieve_size = recieve_buffer.readUInt32BE(0); // Reset the buffer recieve_buffer = new Buffer.alloc(0); // Set the get data mode to true recieve_get = true; } } else { // Is the recieve buffer as big as the size if(recieve_buffer.length == recieve_size) { // Call the callback callback(recieve_buffer); // Reset the buffer and the size recieve_buffer = new Buffer.alloc(0); recieve_size = 0; // Set the get data mode to false recieve_get = false; } } } } function send_ordered(data) { // Convert the data into a buffer data = toBuffer(data); // Get the size of the data var size = data.length; // Turn it into a 32 bit buffer var bytes = new Buffer.alloc(4); bytes.writeUInt32BE(size, 0); // Return the buffer and the data return new Buffer.concat([bytes, data]); } function string_decrypt(key, string) { // Convert the string to a buffer var buff = toBuffer(string); // Create some new data var decrypted = new Buffer.alloc(buff.length); // Iterate over the string for(var i=0;i= key.str.length) { // Set to zero key.at.rx = 0; } } // Return the encrypted data return decrypted; } function string_encrypt(key, string) { // Convert the string to a buffer var buff = toBuffer(string); // Create some new data var encrypted = new Buffer.alloc(buff.length); // Iterate over the string for(var i=0;i 255) e -= 256; encrypted[i] = e; // Add 1 to the key counter key.at.tx += 1; // Is the key counter out of range if(key.at.tx >= key.str.length) { // Set to zero key.at.tx = 0; } } // Return the encrypted data return encrypted; } function make_encryption_key(string) { // Make a new key var key = new Object(); // Set the varibles key.str = toBuffer(string); key.at = new Object(); key.at.rx = 0; key.at.tx = 0; //console.log("make_encryption_key:", key.str); // Return the key return key; } function socket_write(socket, encryption, data) { //console.log("socket_write() b4:", data); // Convert the data to JSON data = JSON.stringify(data); //console.log("socket_write() stringify:", data); // Encrypt the data data = string_encrypt(encryption, data); //console.log("socket_write() encrypt:", data); // Order the request data = send_ordered(data); //console.log("socket_write() ordered:", data); // Send the data socket.write(data); } function connect(profile, connection_id) { // Setup the port and hostname varibles var port = profile.port; var hostname = profile.hostname; // Make an accessible global object var g = new Object(); // Setup some global varibles g.chats = []; g.users = {}; // RSA child task g.rsa_task = child_process.fork( path.resolve('rsa.js'), [], { stdio: [ 'pipe', 'pipe', 'pipe', 'ipc' ], silent: false } ); g.rsa_task.stdout.on('data', function(data) { //console.log("child stdout:", data.toString()); }); g.rsa_task.stderr.on('data', function(data) { console.log("child stderr:", data.toString()); }); g.rsa_task.on('error', function(error) { console.log("Error on child process:", error); }) g.rsa_task.on('exit', function(code, signal) { console.log("Child process closed:", code, signal); }); // Encryption varibles g.encryption; // Set new g.sock_new = 2; // Set a temporary encryption varible g.raw_encryption_data = ""; g.raw_encryption_data_upto = 0; g.raw_encryption_data_size = 0; // Create a client var client; // Is this direct mode if(profile.mode == "direct") { // Set the client to a direct connection client = new net.Socket(); g.client = client; } // Is this socks5 mode if(profile.mode == "socks5") { // Set the client as a socks proxy client = socks_new(profile.proxy.hostname, profile.proxy.port); console.log("Connecting with socks5", profile.proxy.hostname, profile.proxy.port) g.client = client; } function rsa_task_send(data) { //console.log("Send to child:", JSON.stringify(data)); g.rsa_task.send(JSON.stringify(data)); } // Connect to the server console.log(profile.mode, port, hostname, client) client.connect(port, hostname, function() { console.log("Connected", profile.mode); // Load the RSA key rsa_task_send({ mode: "load" }); }); // Wait for data client.on('data', function(data) { // Recieve data in order recieve_ordered(data, function(data) { /*console.log("RAW: ", { input: data, sock_new:g.sock_new, raw_encryption_data_upto: g.raw_encryption_data_upto, bsplit_length: bsplit(data, Buffer.from("\n")).length });*/ if(g.sock_new != 0) { // Parse the string data = JSON.parse(toBytes(data)); // Is this the key if(data.mode == "encryption_key") { // Send the key to be decrypted g.rsa_task.send(JSON.stringify({ mode: "decrypt", data: data.key })); // Set sock new g.sock_new = 0; } } else { // Decrypt the data data = string_decrypt(g.encryption, data); // Convert it from JSON data = JSON.parse(data); // Is this an error if(data.mode == "error") { // Is this an authentication error if(data.error == "auth") { // Destroy the connection client.destroy(); // Delete the connections delete connections[connection_id]; delete profiles[connection_id]; // Update the profiles profiles_export(); profiles_reload(); } } // Logged in if(data.mode == "login") { console.log("Recieved details:", data.chats, data.users); // Save the varibles sent g.users = data.users; g.chats = data.chats; // Switch to this chat profile_switch_to(connection_id); } // New user if(data.mode == "new_user") { console.log("User signed up") // Set the data g.users[data.user] = data.data; // Is this screen active if(active_profile == connection_id) { // Refresh this profile profile_switch_to(connection_id); } } // New chat if(data.mode == "new_chat") { console.log("New chat created"); // Set the data g.chats.push({ name: data.name, messages: [] }); // Update the screen if its active if(active_profile == connection_id) { // Refresh this profile profile_switch_to(connection_id); } } // New message if(data.mode == "new_message") { console.log("Recieved new message from "+data.from +" in channel "+data.channel.toString(), data.date); // Push the new messages to the chat g.chats[data.channel].messages.push({ message: data.message, from: data.from, date: data.date }); // Is the chat and server active if(data.channel == active_chat && connection_id == active_profile) { // Refresh the chat chat_switch_to(active_chat); } } } }); }); client.on('close', function(data) { console.log("Connection closed:", connection_id) // Close the connection delete connections[connection_id]; // Attempt to restart the connection in 10 seconds console.log("Attempting reconnection...") setTimeout(function() { // Attempt reconnection console.log("Attempted reconection."); try { profile_connect(connection_id); } catch(e) { console.log("Caught error", e); } }, 1000); }); g.rsa_task.on('message', function(message) { //console.log(message) // Parse the message from JSON var data = JSON.parse(message); // Is this a rsa load response if(data['mode'] == 'load') { // Get the rsa key g.rsa_task.send(JSON.stringify({ mode: "get" })); } // Is this an rsa get response if(data['mode'] == 'get') { // Send the public key to the server client.write(send_ordered(JSON.stringify({ key: data['public'], mode: "pubkey" }))); } // Is this an rsa data decrypt response if(data['mode'] == 'decrypt') { // Set the key g.encryption = make_encryption_key(atob(data['out'])); //console.log("Sending 1:", data['out']); // Send login console.log("Sending login") socket_write(client, g.encryption, { mode: "login", username: profile.username, password: profile.password }); // Save the details g.username = profile.username; // Kill the process, nolonger needed g.rsa_task.kill(); } }); // Return the global varibles return g; }