-
Notifications
You must be signed in to change notification settings - Fork 1
/
main.js
163 lines (143 loc) · 4.96 KB
/
main.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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
require('dotenv').config();
const path = require('path')
const fs = require('fs');
const redis = require('redis');
var express = require('express')
var https = require('https')
var http = require('http')
var ws = require('ws');
var app = express()
const morganMiddleware = require("./middlewares/morgan.middleware");
const logger = require("./utils/logger");
// SSL Certificate
//==================================================
// The Certbot way!!
//
// apt install certbot python3-certbot-dns-route53
// Make your ~/.aws/credentials
// # certbot certonly --dns-route53 -d yourdomain.tld
const options = {
key: fs.readFileSync(process.env.WEB_KEY),
ca: fs.readFileSync(process.env.WEB_CA),
cert: fs.readFileSync(process.env.WEB_CERT),
};
// Prepare WebServer and WebSocket
const server = https.createServer(options, app)
logger.info("WebSocket initialized, with zlib compression, concurrency limit = 10");
const wss = new ws.Server({
server,
perMessageDeflate: {
zlibDeflateOptions: {
chunkSize: 1024,
memLevel: 7,
level: 3
},
zlibInflateOptions: {
chunkSize: 10 * 1024
},
clientNoContextTakeover: true,
serverNoContextTakeover: true,
serverMaxWindowBits: 10,
concurrencyLimit: 10,
threshold: 1024
}
})
// Prepare Redis client for "sub"
// Point to map_redis host and add following to tpot.yml for map_redis
// ports:
// - "64379:6379"
logger.info("Redis client initialized");
const redisClient = redis.createClient({ url: process.env.MAP_REDIS_URL, password: process.env.MAP_REDIS_PASSWORD } );
// Overall error handler
// Will reach Simple 500 handler etc and use status code
function error(status, msg) {
var err = new Error(msg);
err.status = status;
return err;
}
// Heartbeat function for websocket clients
function heartbeat() {
this.isAlive = true;
}
// Websocket handler for "connections"
wss.on('connection', (ws,req) => {
const ip = req.socket.remoteAddress;
logger.info(ip+" WEBSOCKET client connection established");
ws.isAlive = true;
ws.on('pong', heartbeat); // On PONG confirm alive :)
ws.on('error', (error) => { logger.error(error) });
// Setup Ping / Pong heartbeat every 30sec to make sure we
// have no dead connections hannging
const intervalHeartbeat = setInterval(function ping() {
if (ws.isAlive === false) {
logger.info(ip+" WEBSOCKET client connection terminated");
return ws.terminate();
}
ws.isAlive = false;
ws.ping();
}, 30000);
// On propper disconnect, dont forget to stop the heartbeat :)
ws.on('close', () => {
logger.info(ip+" WEBSOCKET client disconnected");
clearInterval(intervalHeartbeat);
});
});
// Redis Subscriber handler
// When ever this is triggered (ie. something was published!)
// We make sure to send it to all connected websockets!!
(async () => {
const subscriber = await redisClient.duplicate();
subscriber.on('error', err => { logger.error("[Redis-Subscibe handler] "+err) });
subscriber.on('connect', () => { logger.info('[Redis-Subscibe handler] Connected to remote redis server') });
subscriber.on('reconnecting', () => { logger.warn('[Redis-Subscibe handler] Trying to re-connect to remote redis server') });
subscriber.on('ready', () => { logger.info('[Redis-Subscibe handler] Connection ready, subscribing to channel!') });
await subscriber.connect();
await subscriber.subscribe('attack-map-production', (message) => {
wss.clients.forEach( (client) => {
if (client !== ws && client.readyState === ws.OPEN) client.send(message);
});
});
})();
// Websocket Timed messages
// Send server date every 1 sec
(async () => {
setInterval(() => {
const data = JSON.stringify({'type': 'Keepalive', 'keepalive': new Date().valueOf() });
wss.clients.forEach( (client) => {
if (client !== ws && client.readyState === ws.OPEN) client.send(data);
});
}, 1000);
})();
var dateOptions = {
hourCycle: 'h24',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
year: 'numeric', month: 'numeric', day: 'numeric'
};
(async () => {
setInterval(() => {
const data = JSON.stringify({'type': 'Time', 'time': new Date().toLocaleDateString("en-US", dateOptions)});
wss.clients.forEach( (client) => {
if (client !== ws && client.readyState === ws.OPEN) client.send(data);
});
}, 30000);
})();
// Web server setup, serve web page under static folder
app.use(morganMiddleware);
app.use(express.static(path.join(__dirname, 'static')))
// Simple 500 handler
app.use(function(err, req, res, next){
res.status(err.status || 500);
res.send({ error: err.message });
});
// Simple 404
app.use(function(req, res){
res.status(404);
res.send({ error: "Not found" })
});
//start our server
logger.warn("Web Attack Map - Web Server (https) & Websocket (wss) starting up")
server.listen(process.env.WEB_PORT, () => {
logger.warn("Web Attack Map - Now listing for connections on port "+server.address().port)
});