-
Notifications
You must be signed in to change notification settings - Fork 1
/
Server.js
146 lines (120 loc) · 4.46 KB
/
Server.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
const net = require("net");
const crypto = require("crypto");
const fs = require("fs");
const cmds = require("./commands.js");
const protocol = require("./protocol.js");
const util = require("./util.js");
let config = JSON.parse(fs.readFileSync("./config.json"));
require("./import.js");
if (!fs.existsSync("./config.json")) {
while (true); // Hang, tsuimporter.js will close the process
}
function reloadConf() {
config = JSON.parse(fs.readFileSync("./config.json"));
protocol.reloadConf();
}
// Server Listener
const server = net.createServer((socket) => {
const SOCKETNAME = socket.remoteAddress + ":" + socket.remotePort;
let client = {
oocmute: false,
cemute: false,
mute: false,
area: 0,
websocket: false,
name: SOCKETNAME,
socket: socket,
id: util.clients.length
};
reloadConf();
util.players = util.clients.length;
util.clients.push(client);
// WebSockets have 750ms to send a handshake
// After that, it is assumed the client is an AO client
let wsTimeout = setTimeout(() => {
if (!socket.destroyed)
socket.write("decryptor#34#%");
}, config.wsTime);
if (config.mods.includes(socket.remoteAddress)) {
client.moderator = true;
}
if (config.bans.includes(socket.remoteAddress)) {
socket.end();
}
socket.on("data", (data) => {
console.log(data.toString("utf8").split("\r\n"))
if (data.length == 0)
return;
let packetContents;
let allPackets;
// If client is confirmed WebSocket, process.
// If the client isn't a confirmed WebSocket connection
// Then wait for a WS header and if we get one, handshake
if (client.websocket) {
let content = util.decodeWs(data, socket);
if (content == null)
return;
allPackets = content.split("%");
} else {
let ws = data.toString("utf8").split("\r\n");
if (ws[0].includes("HTTP/1.1")) {
// Handle websocket
clearTimeout(wsTimeout);
let key;
ws.forEach((line) => {
let fields = line.split(": ");
if (fields[0] == "Sec-WebSocket-Key")
key = fields[1];
});
key = key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
key = crypto.createHash("sha1").update(key).digest("base64");
let response = "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: " + key + "\r\n\r\n"
socket.write(response);
util.send(socket, "decryptor", ["34"], true);
client.websocket = true;
return;
}
allPackets = data.toString("utf-8").split("%");
}
allPackets.pop(); // Remove entry after last delimiter
allPackets.forEach(packet => {
// extremely verbose info for testing reasons
console.log(`data on wire: ${packet}`);
packetContents = packet.toString("utf-8").split("#");
if (packetContents == null)
return;
if (packetContents[0] == "") // for some reason random packets start with a #
packetContents.shift();
let header = util.fantaDecrypt(packetContents[0], 5);
packetContents.shift();
packetContents.pop();
if (protocol.PacketHandler[header] == undefined) {
console.log("Unimplemented packet: " + header);
console.log(packetContents);
console.log(SOCKETNAME);
return;
}
protocol.PacketHandler[header](packetContents, socket, client);
});
});
})
server.on('error', (e) => {
console.log(e);
});
server.on('close', () => {
util.cleanup(client, protocol);
});
server.listen(config.port, () => {
console.log(`Server listening on port ${config.port}`)
});
process.on('uncaughtException', function (err) {
console.error(err);
});
// Master server advertiser
if (!config.private) {
let client = new net.Socket();
client.connect(config.msport, config.msip, () => {
console.log("Master server connection established");
client.write(util.packetBuilder("SCC", [`${config.port}&${config.port}`, config.name, config.description, `bengoshi v${util.softVersion}`]));
});
}