Repository navigation
Expand file tree
/
Copy pathbackend.js
More file actions
271 lines (257 loc) · 11.2 KB
/
Copy pathbackend.js
File metadata and controls
271 lines (257 loc) · 11.2 KB
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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
// Imports
const config = require("./config.json");
const passport = require('passport');
const multer = require('multer');
const bodyParser = require('body-parser');
const session = require('express-session');
const express = require("express");
const flash = require('express-flash');
const chalk = require('chalk');
const figlet = require('figlet');
const utils = require('hyperz-utils');
const pjson = require('./package.json');
const axios = require('axios');
const bcrypt = require('bcrypt');
const Discord = require('discord.js');
// Basic Variable Setup
let projectName = 'Boss Status'
let storedAppVariable;
let dbcon;
// Init Function
async function init(app, con) {
if (Number(process.version.slice(1).split(".")[0] < 16)) throw new Error(`Node.js v16 or higher is required, Discord.JS relies on this version, please update @ https://nodejs.org`);
var multerStorage = multer.memoryStorage(); // req.body setup
app.use(multer({ storage: multerStorage }).any()); // req.body setup
app.use(bodyParser.urlencoded({ extended: false })); // req.body setup
app.use(express.json()); // req.body setup
app.use(flash()); // passport flash system for live messages
app.use(session({ // passport session setup
secret: 'keyboard cat',
resave: false,
saveUninitialized: false,
cookie: {maxAge: 31556952000},
}));
app.use(passport.initialize()); // passport initialization
app.use(passport.session()); // passport session initialization
app.set('views', './src/views'); // setting views folder
app.set('view engine', 'ejs'); // setting views engine
app.use(express.static('public')); // making public folder "public"
app.use(express.static('src/static')); // making static folder "public"
app.use('/assets', express.static(__dirname + 'public/assets')); // creating shortcut
app.use('/static', express.static(__dirname + 'src/static/assets')); // creating shortcut
dbcon = con; // setting con variable for this file (MySQL Connection)
// BEGIN FANCY CONSOLE LOGGING STUFF
figlet.text(projectName, { font: "Standard", width: 700 }, function(err, data) {
if(err) throw err;
let str = `${data}\n-------------------------------------------\n${projectName} is up and running on port ${config.port}!`
console.log(chalk.bold(chalk.blue(str)));
});
setTimeout(async function() {
runPings();
constantPings();
}, 3000); // 3 seconds (startup)
setInterval(function() {
constantPings();
}, 360000); // 6 minutes
setInterval(function() {
runPings();
}, 57600000) // 16 Hours
sqlLoop(con); // Keep SQL connection alive
markSqlConnected(); // Mark SQL connected in console
await resetAppLocals(app); // Reset app locals to be ready for next render (do this on every page load)
};
async function runPings() {
dbcon.query(`SELECT * FROM services WHERE status="dynamic"`, function(err, services) {
if(err) throw err;
services.forEach(async function(service) {
let pingAttempt = await axios({
method: 'get',
url: `http://${service.ip}:${service.port}`,
timeout: config.pingTimeout || 1800
}).then(() => {return true;}).catch(e => {return false;});
dbcon.query(`SELECT * FROM pings WHERE serviceid="${service.uniqueid}"`, function(err, row) {
if(err) throw err;
if(row.length >= 28) {
let toDelete = row.sort((a, b) => { return a.id - b.id; })[0]
dbcon.query(`DELETE FROM pings WHERE id=${toDelete.id}`, function(err, row) {
if(err) throw err;
});
};
if(row.length < 27) {
let arrayOf27Items = [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];
arrayOf27Items.forEach(function(ignoreThis) {
dbcon.query(`INSERT INTO pings (serviceid, online) VALUES ("${service.uniqueid}", 2)`, function(err, row) {
if(err) throw err;
});
});
};
dbcon.query(`INSERT INTO pings (serviceid, online) VALUES ("${service.uniqueid}", ${pingAttempt})`, function(err, row) {
if(err) throw err;
});
});
});
});
};
async function prepService(serviceid) {
dbcon.query(`SELECT * FROM services WHERE uniqueid="${serviceid}"`, async function(err, row) {
if(err) throw err;
let service = row[0];
let pingAttempt = await axios({
method: 'get',
url: `http://${service.ip}:${service.port}`,
timeout: config.pingTimeout || 1800
}).then(() => {return true;}).catch(e => {return false;});
dbcon.query(`SELECT * FROM pings WHERE serviceid="${service.uniqueid}"`, function(err, row) {
if(err) throw err;
if(row.length >= 28) {
let toDelete = row.sort((a, b) => { return a.id - b.id; })[0]
dbcon.query(`DELETE FROM pings WHERE id=${toDelete.id}`, function(err, row) {
if(err) throw err;
});
};
if(row.length < 27) {
let arrayOf27Items = [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];
arrayOf27Items.forEach(function(ignoreThis) {
dbcon.query(`INSERT INTO pings (serviceid, online) VALUES ("${service.uniqueid}", 2)`, function(err, row) {
if(err) throw err;
});
});
};
dbcon.query(`INSERT INTO pings (serviceid, online) VALUES ("${service.uniqueid}", ${pingAttempt})`, function(err, row) {
if(err) throw err;
});
});
});
};
async function constantPings() {
dbcon.query(`SELECT * FROM services WHERE status="dynamic"`, function(err, services) {
if(err) throw err;
services.forEach(async function(service) {
let pingAttempt = await axios({
method: 'get',
url: `http://${service.ip}:${service.port}`,
timeout: config.pingTimeout || 1800
}).then(() => {return true;}).catch(e => {return false;});
if(service.lastpingonline == true && pingAttempt == false) {
// Gone Offline
dbcon.query(`UPDATE services SET lastpingonline=false WHERE uniqueid="${service.uniqueid}"`, function(err, row) {
if(err) throw err;
});
if(service.alerts) sendWebhook(service.webhook, 'Service Offline!', `**${service.name}** has gone offline!`, '#fc1c1c');
} else if(service.lastpingonline == false && pingAttempt == true) {
// Gone Online
dbcon.query(`UPDATE services SET lastpingonline=true WHERE uniqueid="${service.uniqueid}"`, function(err, row) {
if(err) throw err;
});
if(service.alerts) sendWebhook(service.webhook, 'Service Online!', `**${service.name}** is back online!`, '#1cfc79');
} else {
dbcon.query(`UPDATE services SET lastpingonline=${pingAttempt} WHERE uniqueid="${service.uniqueid}"`, function(err, row) { if(err) throw err; });
};
});
});
};
async function sendWebhook(url, title, content, color) {
const webhookClient = new Discord.WebhookClient({ url: url });
const embed = new Discord.MessageEmbed()
.setTitle(title)
.setColor(color)
.setDescription(content)
.setThumbnail(`${config.domain}/assets/logo.png`)
.setTimestamp()
webhookClient.send({
avatarURL: `${config.domain}/assets/logo.png`,
embeds: [embed],
}).catch(e => { console.log(e); });
};
// Keeps settings updated for next render
async function resetAppLocals(app) {
dbcon.query(`SELECT * FROM sitesettings`, function(err, settings) {
if(err) throw err;
app.locals = {
config: config,
packagejson: require('./package.json'),
sitesettings: settings[0]
};
storedAppVariable = app;
});
};
// Keeps SQL connection alive
async function sqlLoop(con) {
if(con == 0) return;
await con.ping();
setTimeout(() => sqlLoop(con), 60000 * 30);
};
// Logs connection status in console
async function markSqlConnected() {
await dbcon.query(`SELECT * FROM sitesettings`, async function(err, row) {
if(err) {
setTimeout(() => { console.log(`${chalk.yellow(`[SQL Manager]`)} MySQL connection failed...`); }, 3400);
} else {
setTimeout(() => { console.log(`${chalk.yellow(`[SQL Manager]`)} MySQL successfully connected.`); }, 3400);
};
});
};
// Make sure a user is logged in to view the rendered page
async function checkAuth(req, res, next) {
if(req.isAuthenticated()){
dbcon.query(`SELECT * FROM users WHERE id="${req.user.id}"`, function(err, row) {
if(err) throw err;
if(!row[0]) {
dbcon.query(`INSERT INTO users (id, email, password) VALUES ("${req.user.id}", "${req.user.email}", "discord")`, function(err, row) {
if(err) throw err;
next();
});
} else {
next();
};
});
} else{
res.redirect("/login");
}
};
// Make sure the user is NOT logged in to view the rendered page
async function checkNotAuth(req, res, next) {
if(req.isAuthenticated()){
res.redirect("/account");
} else {
next();
};
};
// Username/Password authentication
async function authenticateUserLocal(email, password, done) {
dbcon.query(`SELECT * FROM users WHERE email="${await utils.sanitize(email)}"`, async function(err, row) {
if(err) throw err;
if(!row[0]) return done(null, false, { message: 'No user with that email' });
try {
if (await bcrypt.compare(password, row[0].password)) {
return done(null, row[0]);
} else {
return done(null, false, { message: 'Password incorrect' });
};
} catch (e) {
return done(e);
};
});
};
// Generates a user Id for non-oauth2 users
function generateUserId(length) {
let result = '';
let characters = '0123456789';
let date = Date.now();
let charactersLength = characters.length;
for ( let i = 0; i < length; i++ ) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return date + result;
};
// Module Exports
module.exports = {
init: init,
checkAuth: checkAuth,
checkNotAuth: checkNotAuth,
authenticateUserLocal: authenticateUserLocal,
generateUserId: generateUserId,
resetAppLocals: resetAppLocals,
constantPings: constantPings,
prepService: prepService
};