chat-client/scripts/communications.js

657 lines
14 KiB
JavaScript
Raw Normal View History

2019-03-24 17:22:44 +11:00
// Load the settings
var settings = require("./settings.json");
2019-04-09 19:18:47 +10:00
// Create an rsa key
var rsa_key;
function toBuffer(bytes)
{
2019-04-09 19:18:47 +10:00
// String
if(typeof(bytes) == 'string')
{
// Create a buffer
var buffer = new Buffer.alloc(bytes.length);
2019-03-24 17:22:44 +11:00
2019-04-09 19:18:47 +10:00
// Loop over the bytes
for(var i=0;i<bytes.length;i++)
{
// Save to the buffer
buffer[i] = bytes[i].charCodeAt(0);
}
2019-03-24 17:22:44 +11:00
2019-04-09 19:18:47 +10:00
// Return the buffer
return buffer;
}
2019-04-09 19:18:47 +10:00
// Return if this is anything else
return bytes;
}
2019-04-09 19:18:47 +10:00
function toBytes(buffer)
{
// Make sure the buffer is a buffer
buffer = toBuffer(buffer);
// Create some bytes
var bytes = "";
2019-04-09 19:18:47 +10:00
// Loop over the buffer
for(var i=0;i<buffer.length;i++)
{
2019-04-09 19:18:47 +10:00
// Add to the bytes string
bytes += String.fromCharCode(buffer[i]);
}
2019-04-09 19:18:47 +10:00
// Return the bytes
return bytes;
}
function socks_new(hostname, port)
{
// Setup some handles
var connect_handle;
var close_handle;
var data_handle;
// Set the first varible
var first = true;
// Proxy task
var proxy = child_process.fork(
path.resolve('proxy.js'), [],
{
stdio: [ 'pipe', 'pipe', 'pipe', 'ipc' ],
silent: false,
2019-04-19 11:04:23 +10:00
execPath: "node"
}
);
// Wait for a message
proxy.on("message", function(data)
{
// If first
if(first)
{
// If the data is the initial connection
if(data == "connected")
{
// Set first to false
first = false;
// Call the connect handle
connect_handle();
}
}
else
{
// Call the data handle
data_handle(Buffer.from(data));
}
});
proxy.stdout.on("data", function(data)
{
console.log("socks_new stdout:", data.toString())
})
proxy.stderr.on("data", function(data)
{
console.log("socks_new stderr:", data.toString())
})
var options = {
connect: function(s_port, s_hostname, callback)
{
// Send some data
proxy.send(JSON.stringify({
connect: {
host: s_hostname,
port: s_port
},
proxy: {
host: hostname,
port: port
}
}));
// Set the connect handle
connect_handle = callback;
},
on: function(watch, callback)
{
// On data
if(watch == "data")
{
// Set the callback
data_handle = callback;
}
// On close
if(watch == "close")
{
// Set the callback
close_handle = callback;
// Set the close handle
proxy.on("close", close_handle);
}
},
write: function(data)
{
// Send the specified data
proxy.send(data);
},
destroy: function()
{
// Destroy the proxy
proxy.kill();
}
};
return options;
}
function test_socks_test(text)
{
var socket = socks_new("localhost", 8080)
socket.on("data", function(data)
{
console.log(data.toString())
socket.destroy();
});
socket.connect(12346,"192.168.1.14",function()
{
console.log("connected")
});
socket.write(text);
}
2019-04-09 19:18:47 +10:00
// Recieve helper global varibles
var recieve_buffer = new Buffer.alloc(0);
var recieve_get = false;
var recieve_size = 0;
2019-04-09 19:18:47 +10:00
function recieve_ordered(data, callback)
{
// Convert the data into a buffer
data = toBuffer(data);
// Loop over the data
for(var i=0;i<data.length;i++)
{
// Add the data to the buffer
recieve_buffer = new Buffer.concat([recieve_buffer, Buffer.from([data[i]])]);
2019-04-09 19:18:47 +10:00
// Is the buffer getting data
if(!recieve_get)
{
// Does the buffer contain a number
if(recieve_buffer.length >= 4)
{
2019-04-09 19:18:47 +10:00
// 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;
}
}
2019-04-09 19:18:47 +10:00
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;
}
}
}
2019-04-09 19:18:47 +10:00
}
2019-04-09 19:18:47 +10:00
function send_ordered(data)
{
// Convert the data into a buffer
data = toBuffer(data);
2019-04-09 19:18:47 +10:00
// Get the size of the data
var size = data.length;
2019-04-09 19:18:47 +10:00
// Turn it into a 32 bit buffer
var bytes = new Buffer.alloc(4);
bytes.writeUInt32BE(size, 0);
2019-04-09 19:18:47 +10:00
// Return the buffer and the data
return new Buffer.concat([bytes, data]);
}
2019-04-09 19:18:47 +10:00
function string_decrypt(key, string)
{
// Convert the string to a buffer
var buff = toBuffer(string);
2019-04-09 19:18:47 +10:00
// Create some new data
var decrypted = new Buffer.alloc(buff.length);
2019-04-09 19:18:47 +10:00
// Iterate over the string
for(var i=0;i<string.length;i++)
{
2019-04-09 19:18:47 +10:00
// Convert the string item to a number
var d = buff[i]-key.str[key.at.rx];
while(d < 0) d += 256;
decrypted[i] = d;
2019-04-09 19:18:47 +10:00
// Add 1 to the key counter
key.at.rx += 1;
2019-03-24 17:22:44 +11:00
2019-04-09 19:18:47 +10:00
// Is the key counter out of range
if(key.at.rx >= key.str.length)
{
// Set to zero
key.at.rx = 0;
}
}
2019-04-09 19:18:47 +10:00
// Return the encrypted data
return decrypted;
}
2019-04-09 19:18:47 +10:00
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<string.length;i++)
{
2019-04-09 19:18:47 +10:00
// Convert the string item to a number
var e = buff[i]+key.str[key.at.tx];
while(e > 255) e -= 256;
encrypted[i] = e;
2019-04-09 19:18:47 +10:00
// 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;
}
}
2019-04-09 19:18:47 +10:00
// Return the encrypted data
return encrypted;
}
2019-04-09 19:18:47 +10:00
function make_encryption_key(string)
{
// Make a new key
var key = new Object();
2019-04-09 19:18:47 +10:00
// Set the varibles
key.str = toBuffer(string);
2019-04-09 19:18:47 +10:00
key.at = new Object();
key.at.rx = 0;
key.at.tx = 0;
2019-04-10 13:09:40 +10:00
//console.log("make_encryption_key:", key.str);
2019-04-09 19:18:47 +10:00
// Return the key
return key;
}
function socket_write(socket, encryption, data)
{
2019-04-10 13:09:40 +10:00
//console.log("socket_write() b4:", data);
2019-04-09 19:18:47 +10:00
// Convert the data to JSON
data = JSON.stringify(data);
2019-04-10 13:09:40 +10:00
//console.log("socket_write() stringify:", data);
2019-04-09 19:18:47 +10:00
// Encrypt the data
data = string_encrypt(encryption, data);
2019-04-10 13:09:40 +10:00
//console.log("socket_write() encrypt:", data);
2019-04-09 19:18:47 +10:00
// Order the request
data = send_ordered(data);
2019-04-10 13:09:40 +10:00
//console.log("socket_write() ordered:", data);
2019-04-09 19:18:47 +10:00
// Send the data
socket.write(data);
}
2019-04-10 15:47:50 +10:00
function connect(profile, connection_id)
2019-04-09 19:18:47 +10:00
{
2019-04-10 15:47:50 +10:00
// Setup the port and hostname varibles
var port = profile.port;
var hostname = profile.hostname;
2019-04-09 19:18:47 +10:00
// Make an accessible global object
var g = new Object();
// Setup some global varibles
2019-04-13 16:34:16 +10:00
g.chats = [];
g.users = {};
2019-04-09 19:18:47 +10:00
// RSA child task
g.rsa_task = child_process.fork(
path.resolve('rsa.js'), [],
{
2019-04-09 19:18:47 +10:00
stdio: [ 'pipe', 'pipe', 'pipe', 'ipc' ],
silent: false
}
);
2019-04-09 19:18:47 +10:00
g.rsa_task.stdout.on('data', function(data)
{
2019-04-10 13:09:40 +10:00
//console.log("child stdout:", data.toString());
2019-04-09 19:18:47 +10:00
});
2019-04-09 19:18:47 +10:00
g.rsa_task.stderr.on('data', function(data)
{
console.log("child stderr:", data.toString());
});
2019-04-09 19:18:47 +10:00
g.rsa_task.on('error', function(error)
{
console.log("Error on child process:", error);
})
2019-04-09 19:18:47 +10:00
g.rsa_task.on('exit', function(code, signal)
{
console.log("Child process closed:", code, signal);
});
2019-04-09 19:18:47 +10:00
// Encryption varibles
g.encryption;
2019-04-09 19:18:47 +10:00
// Set new
g.sock_new = 2;
2019-04-09 19:18:47 +10:00
// Set a temporary encryption varible
g.raw_encryption_data = "";
g.raw_encryption_data_upto = 0;
g.raw_encryption_data_size = 0;
2019-04-09 19:18:47 +10:00
// 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;
}
2019-04-09 19:18:47 +10:00
function rsa_task_send(data)
{
2019-04-10 13:09:40 +10:00
//console.log("Send to child:", JSON.stringify(data));
2019-04-09 19:18:47 +10:00
g.rsa_task.send(JSON.stringify(data));
}
2019-04-09 19:18:47 +10:00
// Connect to the server
console.log(profile.mode, port, hostname, client)
2019-04-09 19:18:47 +10:00
client.connect(port, hostname, function()
{
console.log("Connected", profile.mode);
2019-04-09 19:18:47 +10:00
// Load the RSA key
rsa_task_send({
mode: "load"
});
});
2019-04-09 19:18:47 +10:00
// Wait for data
client.on('data', function(data)
{
// Recieve data in order
recieve_ordered(data, function(data)
{
2019-04-10 13:09:40 +10:00
/*console.log("RAW: ", {
2019-04-09 19:18:47 +10:00
input: data,
sock_new:g.sock_new,
raw_encryption_data_upto: g.raw_encryption_data_upto,
bsplit_length: bsplit(data, Buffer.from("\n")).length
2019-04-10 13:09:40 +10:00
});*/
2019-04-09 19:18:47 +10:00
if(g.sock_new != 0)
{
// Parse the string
data = JSON.parse(toBytes(data));
2019-04-09 19:18:47 +10:00
// 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;
}
}
2019-04-09 19:18:47 +10:00
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;
// Remove the disabled class
$("#profile_button_"+connection_id).removeClass("disabled");
// Set onclick
$("#profile_button_"+connection_id).on("click", function()
{
// Switch to the profile id
profile_switch_to(connection_id);
});
// Set the href
document.getElementById("profile_button_"+connection_id).href = "#";
// 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);
}
}
2019-04-13 10:19:14 +10:00
// 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);
}
}
2019-04-13 16:34:16 +10:00
// New message
if(data.mode == "new_message")
{
console.log("Recieved new message from "+data.from
2019-04-17 16:40:22 +10:00
+" in channel "+data.channel.toString(), data.date);
2019-04-13 16:34:16 +10:00
// Push the new messages to the chat
g.chats[data.channel].messages.push({
message: data.message,
2019-04-17 16:40:22 +10:00
from: data.from,
date: data.date
2019-04-13 16:34:16 +10:00
});
// Is the chat and server active
if(data.channel == active_chat && connection_id == active_profile)
{
// Refresh the chat
chat_switch_to(active_chat);
}
}
}
2019-04-09 19:18:47 +10:00
});
});
client.on('close', function(data)
{
console.log("Connection closed:", connection_id)
2019-04-10 15:47:50 +10:00
// 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);
});
2019-03-24 17:22:44 +11:00
2019-04-09 19:18:47 +10:00
g.rsa_task.on('message', function(message)
{
2019-04-10 13:09:40 +10:00
//console.log(message)
2019-04-09 19:18:47 +10:00
// 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']));
2019-04-10 13:09:40 +10:00
//console.log("Sending 1:", data['out']);
2019-04-09 19:18:47 +10:00
// 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();
2019-04-09 19:18:47 +10:00
}
});
// Return the global varibles
return g;
}