const fs = require('fs');
const https = require('https');
const seedrandom = require('seedrandom');
const express = require('express');
const app = express();
const options = {
key: fs.readFileSync("ssl/private.key"),
cert: fs.readFileSync("ssl/certificate.crt"),
ca: [fs.readFileSync('ssl/ca_bundle.crt')]
};
const server = https.createServer(options, app);
const io = require('socket.io')(server);
const PORT = 443;
const admins = {
'André': 'passwort'
}
var users = [];
var bannedIps = [];
fs.readFile("config/ban.json", "utf8", (err, data) => {
if (!err) {
bannedIps = JSON.parse(data);
}
})
const randomColors = [
'#c42020',
'#de801e',
'#f6c60b',
'#19ce19',
'#129696',
'#2c53e3',
'#6f23e3',
'#883f88',
];
const HISTORY_SIZE = 50;
var history = [];
app.use(express.static(__dirname + '/www'));
app.use('/node_modules', express.static(__dirname + '/node_modules'));
app.get('/img/ava/:username', (req, res) => {
var file = '';
if (fs.existsSync(__dirname + '/www/img/ava/' + req.params.username + '.png')) {
file = __dirname + '/www/img/ava/' + req.params.username + '.png';
} else {
const files = fs.readdirSync(__dirname + '/www/img/ava/random/').filter((f) => f.toLowerCase().endsWith('.png'));
const seededRandom = seedrandom(req.params.username)();
const randomFile = files[Math.floor(seededRandom * files.length)];
file = __dirname + '/www/img/ava/random/' + randomFile;
}
res.sendFile(file);
});
io.on('connection', (socket) => {
const ip = socket.handshake.address;
log('- New user joined the server:', ip);
for (const bannedItem of bannedIps) {
if (bannedItem.ip == ip) {
log('- User blacklisted, kicking:', ip)
socket.emit('serverKick');
socket.disconnect();
break;
}
}
socket.emit('serverHandshake');
const user = {ip: ip, socket: socket};
users.push(user);
socket.on('login', (username, password) => {
if (!username) {
socket.emit('usernameInvalid');
return;
}
for (let user of users) {
if (user.name == username) {
socket.emit('usernameTaken');
return;
}
}
if (admins && admins[username]) {
if (!password) {
log('- Attempted login as admin without password.', username, '(' + ip + ')');
socket.emit('passwordRequired');
return;
} else if (admins[username] != password) {
log('- Attempted login as admin with wrong password.', username, '(' + ip + ')');
socket.emit('passwordWrong');
return;
}
log('- Admin "' + username + '" login successful');
user.admin = true;
socket.on('requestKick', (userToBeKicked) => {
log('- Admin "' + username + '" requested kick of User "' + userToBeKicked.name + '"');
kickUser(userToBeKicked);
});
socket.on('requestLiftBan', (ip) => {
log('- Admin "' + username + '" requested to lift ban for ip "' + ip + '"');
liftBan(ip);
});
}
log('- New user logged in:', username, '(' + ip + ')');
user.name = username;
user.color = getRandomColor(username);
socket.emit('serverLogin', getCleanUser(user), history);
io.emit('userJoined', username);
updateUsers();
updateBanned();
socket.on('disconnect', () => {
log('- User joined the server:', ip);
users = users.filter((listUser) => listUser !== user);
io.emit('userLeft', username);
updateUsers();
});
socket.on('message', (msg) => {
if (msg) {
if (!user.admin) {
const regex = /( |<([^>]+)>)/ig;
msg = msg.replace(regex, "");
}
msg = msg.replace(/(? {
if (url.toLowerCase().endsWith('.jpg')
|| url.toLowerCase().endsWith('.gif')
|| url.toLowerCase().endsWith('.png')) {
return '';
}
var faviconUrl;
try {
faviconUrl = new URL(url).origin + '/favicon.ico';
} catch (e) {
log('Error getting favicon for "' + url + '"');
}
return '' + url + '';
});
log(user.name + ':', msg, '(' + user.ip + ')');
if (history.length >= HISTORY_SIZE) {
history = history.slice(1);
}
history.push({msg: msg, user: getCleanUser(user), timestamp: Date.now()});
io.emit('message', msg, getCleanUser(user), Date.now());
}
});
});
});
function updateUsers() {
io.emit('usersUpdated', users.filter((user) => user.name != null).map(getCleanUser));
}
function getCleanUser(user) {
return {
name: user.name,
admin: user.admin,
color: user.color
}
}
function kickUser(user) {
let ip;
for (const exUser of users) {
if (exUser.name == user.name) {
ip = exUser.ip;
break;
}
}
bannedIps.push({ip: ip, user: user});
updateBanned();
for (const exUser of users) {
if (exUser.ip == ip) {
exUser.socket.emit('serverKick');
exUser.socket.disconnect();
}
}
}
function liftBan(ip) {
bannedIps = bannedIps.filter((listItem) => listItem.ip != ip);
updateBanned();
}
function updateBanned() {
fs.writeFile('config/ban.json', JSON.stringify(bannedIps), (e) => {
});
io.emit('bannedUpdated', bannedIps);
}
function getRandomColor(seed) {
return randomColors[Math.floor(seedrandom(seed)() * randomColors.length)];
}
function log(...inputs) {
var output = '[' + new Date().toISOString().substr(0, 19).replace('T', ', ') + '] ';
for (const i of inputs) {
output += i + ' ';
}
console.log(output);
fs.appendFile('log.txt', '' + output + '\n', (e) => {
});
}
server.listen(PORT, () => {
log('- Server up and running at port ' + PORT);
});