123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238 |
- 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(/(?<!href=")(\b[\w]+:\/\/[\w-?&;#~=\.\/\@%]+[\w\/])/g, (url) => {
- if (url.toLowerCase().endsWith('.jpg')
- || url.toLowerCase().endsWith('.gif')
- || url.toLowerCase().endsWith('.png')) {
- return '<a href="' + url + '"><img src="' + url + '" alt="" /></a>';
- }
- var faviconUrl;
- try {
- faviconUrl = new URL(url).origin + '/favicon.ico';
- } catch (e) {
- log('Error getting favicon for "' + url + '"');
- }
- return '<a href="' + url + '"><img class="favicon" src="' + faviconUrl + '" alt="" />' + url + '</a>';
- });
- 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);
- });
|