@nka212bg/backend-utils 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/misc.js ADDED
@@ -0,0 +1,463 @@
1
+ const { existsSync, mkdirSync, readdirSync, readFileSync, readFile, statSync, copyFile, copyFileSync, unlink, unlinkSync, rmdirSync, lstatSync } = require("fs");
2
+ const sharp = require("sharp");
3
+
4
+ exports.slugFormatter = (text) => {
5
+ text = (text || "")
6
+ .toLowerCase()
7
+ .replace(/%n|%y/g, " ")
8
+ .replace(/([^\d\p{L}-]| )+/gu, " ")
9
+ .trim()
10
+ .replace(/\s+/g, "-");
11
+
12
+ return text;
13
+ };
14
+
15
+ exports.cookies = ({ cookies, ...options }) => {
16
+ return {
17
+ get(key) {
18
+ // const cookies = Object.fromEntries(new URLSearchParams(document.cookie.replace(/; /g, "&")));
19
+ const cookies = JSON.parse(`{"${req.headers?.cookie.replace(/=/g, '":"').replace(/; /g, '","')}"}`);
20
+ return key ? cookies[key] : cookies;
21
+ },
22
+ set({ key, value, domain, path, age = 99999999 }) {
23
+ let cookie = `${key}=${value}; max-age=${age};`;
24
+
25
+ path = path || options.path || "/";
26
+ cookie += ` Path=${path};`;
27
+
28
+ domain = domain || options.domain || location.hostname;
29
+ cookie += ` Domain=${domain};`;
30
+
31
+ if (options.sameSite) cookie += ` SameSite=${options.sameSite};`;
32
+ if (options.partitioned) cookie += ` Partitioned;`;
33
+ if (options.secure) cookie += ` Secure;`;
34
+
35
+ document.cookie = cookie;
36
+ },
37
+ remove({ key, domain, path = "/" }) {
38
+ let cookie = `${key}=; expires=Sat, Jan 01 2022 00:00:00 UTC;`;
39
+
40
+ path = path || options.path || "/";
41
+ cookie += ` Path=${path};`;
42
+
43
+ domain = domain || options.domain || location.hostname;
44
+ cookie += ` Domain=${domain};`;
45
+
46
+ if (options.sameSite) cookie += ` SameSite=${options.sameSite};`;
47
+ if (options.partitioned) cookie += ` Partitioned;`;
48
+ if (options.secure) cookie += ` Secure;`;
49
+
50
+ document.cookie = cookie;
51
+ },
52
+ };
53
+ };
54
+
55
+ exports.codeSnippet = (text, { color = "brown" } = {}) => {
56
+ const props = {
57
+ _sl_: { exp: "<\\/", color: null, code: "&lt;&#47;" },
58
+ _sr_: { exp: "\\/>", color: null, code: "&#47;&gt;" },
59
+ _docStart_: { exp: "<!", color: null, code: "&lt;!" },
60
+ _lt_: { exp: "<", color: null, code: "&lt;" },
61
+ _gt_: { exp: ">", color: null, code: "&gt;" },
62
+ _op_: { exp: "\\(", color: null, code: "&#40;" },
63
+ _cp_: { exp: "\\)", color: null, code: "&#41;" },
64
+ _sq_: { exp: "'", color: null, code: "&apos;" },
65
+ _dq_: { exp: '"', color: null, code: "&quot;" },
66
+ "src=": { exp: "src=", color: null, code: null },
67
+ // _eq_: { exp: "=", color: null, code: "&#61;" },
68
+ };
69
+
70
+ Object.keys(props).forEach((e) => {
71
+ text = text.replace(RegExp(props[e].exp, "g"), e);
72
+ });
73
+
74
+ Object.keys(props).forEach((e) => {
75
+ text = text.replace(RegExp(e, "g"), `<span style="color: ${props[e].color || color}">${props[e].code || e}</span>`);
76
+ });
77
+
78
+ // text = text.replace(/(<\w[^>]*>|<\/[^>]+>)/g, `<span style="color: ${color}">$1</span>`);
79
+ text = text.replace(/(\.{2,})+/g, `<span style="color: ${color}">$1</span>`);
80
+
81
+ return text;
82
+ };
83
+
84
+ exports.createToken = ({ length = 14, type } = {}) => {
85
+ const chars = "ABCDQFGHIJKLMNOPQRSTUVWXYZabcdqfghijklmnopqrstuvwxyz";
86
+ const nums = "1234567890";
87
+
88
+ if (type == "number") return mixer(nums, length);
89
+ if (type == "date") return mixer(chars, 1) + mixer(nums + chars + nums, length - 7) + parseInt(Date.now() / 100000000) + mixer(chars, 1);
90
+ return mixer(chars, 1) + mixer(nums + chars + nums, length - 2) + mixer(chars, 1);
91
+
92
+ function mixer(string, length) {
93
+ if (string.length > length) string = string + string;
94
+
95
+ return string
96
+ .split("")
97
+ .sort(() => 0.5 - Math.random())
98
+ .join("")
99
+ .substring(0, length);
100
+ }
101
+ };
102
+
103
+ exports.handlebars = ({ template, ...params } = {}) => {
104
+ const placeholders = template.match(/(\{\{)(.*?)(\}\})/g);
105
+
106
+ for (const p in params) {
107
+ const placeholder = placeholders.find((e) => e.includes(p));
108
+ if (!placeholder) continue;
109
+
110
+ template = template.replace(RegExp(placeholder, "g"), params[p]);
111
+ }
112
+
113
+ return template;
114
+ };
115
+
116
+ exports.shortCount = (value, type) => {
117
+ value = Number(value);
118
+ if (isNaN(value)) return value;
119
+
120
+ let units = {
121
+ trillion: "T",
122
+ billion: "B",
123
+ million: "M",
124
+ thousand: "K",
125
+ };
126
+
127
+ if (type == "disk") {
128
+ units = {
129
+ trillion: " tb",
130
+ billion: " gb",
131
+ million: " mb",
132
+ thousand: " kb",
133
+ };
134
+ }
135
+
136
+ if (value > 1000000000000) return (value / 1000000000000).toFixed(1) + units.trillion;
137
+ if (value > 1000000000) return (value / 1000000000).toFixed(1) + units.billion;
138
+ if (value > 1000000) return (value / 1000000).toFixed(1) + units.million;
139
+ if (value > 1000) return (value / 1000).toFixed(1) + units.thousand;
140
+ return value + (type == "disk" ? " bites" : "");
141
+ };
142
+
143
+ exports.saveFile = (file, destinationPath, callback) => {
144
+ const path = destinationPath.replace(/[^/]+$/, "");
145
+ !existsSync(path) && mkdirSync(path, { recursive: true });
146
+
147
+ copyFile(file, destinationPath, (err) => {
148
+ callback && callback(err);
149
+ setTimeout(() => unlink(file, (err) => err && console.log(err)), 10000);
150
+ });
151
+ };
152
+
153
+ exports.fileServe = ({ filePath, res, download, img } = {}) => {
154
+ readFile(filePath, (error, file) => {
155
+ if (error) return res.status(404).end();
156
+ if (img && file.includes("/svg")) res.setHeader("Content-Type", "image/svg+xml");
157
+
158
+ download ? res.download(filePath) : res.end(file);
159
+ });
160
+ };
161
+
162
+ // { file: files[file], writePath: imagePath, width: 200, height: 200, type: "jpeg" }
163
+ exports.saveImage = ({ file, writePath, width, height, loop = 0, quality = 85, maxSize = 200, type }) => {
164
+ file.sizeKb = file.size / 1000;
165
+ let animated = true;
166
+
167
+ // console.log("file.sizeKb --> ", file.sizeKb);
168
+ // console.log("file.type --> ", file.type);
169
+
170
+ if (file.sizeKb > maxSize) animated = false;
171
+
172
+ if (!type && file.mimetype.includes("svg")) {
173
+ this.saveFile(file.filepath, writePath);
174
+ return {};
175
+ }
176
+
177
+ return new Promise(async (resolve) => {
178
+ try {
179
+ const path = writePath.replace(/[^/]+$/, "");
180
+ !existsSync(path) && mkdirSync(path, { recursive: true });
181
+
182
+ const img = sharp(file.filepath, { animated });
183
+ const metaData = await img.metadata();
184
+
185
+ if (!type) type = metaData.format;
186
+ if (/jpe?g/gi.test(type)) img.flatten({ background: "#ffffff" });
187
+
188
+ // resize
189
+ if (width || height) {
190
+ if (metaData.height < height || metaData.width > metaData.height) height = undefined;
191
+ if (metaData.width < width || metaData.width < metaData.height) width = undefined;
192
+
193
+ img.resize({
194
+ width,
195
+ height,
196
+ });
197
+ }
198
+
199
+ // type
200
+ img[type]({ quality, mozjpeg: true, loop });
201
+
202
+ img.withMetadata();
203
+
204
+ img.toFile(writePath, (error) => {
205
+ resolve({ error });
206
+ setTimeout(() => unlink(file.filepath, (err) => err && console.error(err)), 10000);
207
+ });
208
+ } catch (error) {
209
+ resolve({ error });
210
+ }
211
+ });
212
+ };
213
+
214
+ // Delete files or dirs recursive
215
+ exports.deleteFolder = (path, pathTemp) => {
216
+ if (existsSync(path)) {
217
+ if (lstatSync(path).isDirectory()) {
218
+ var files = readdirSync(path);
219
+ if (!files.length) return rmdirSync(path);
220
+ for (var file in files) {
221
+ var currentPath = path + "/" + files[file];
222
+ if (!existsSync(currentPath)) continue;
223
+ if (lstatSync(currentPath).isFile()) {
224
+ unlinkSync(currentPath);
225
+ continue;
226
+ }
227
+ if (lstatSync(currentPath).isDirectory() && !readdirSync(currentPath).length) {
228
+ rmdirSync(currentPath);
229
+ } else {
230
+ this.deleteFolder(path + "/" + files[file], path);
231
+ }
232
+ }
233
+ this.deleteFolder(path);
234
+ } else {
235
+ unlinkSync(path);
236
+ }
237
+ }
238
+ if (pathTemp) this.deleteFolder(pathTemp);
239
+ };
240
+
241
+ exports.copyFolder = (source, destination) => {
242
+ if (!existsSync(destination)) mkdirSync(destination, { recursive: true });
243
+
244
+ readdirSync(source).forEach((item) => {
245
+ const sourcePath = `${source}/${item}`;
246
+ const destinationPath = `${destination}/${item}`;
247
+
248
+ if (lstatSync(sourcePath).isDirectory()) {
249
+ this.copyFolder(sourcePath, destinationPath);
250
+ } else {
251
+ copyFileSync(sourcePath, destinationPath);
252
+ }
253
+ });
254
+ };
255
+
256
+ exports.dirSize = (path) => {
257
+ let size = 0;
258
+ try {
259
+ const rootStat = statSync(path);
260
+ if (rootStat.isFile()) return rootStat.size;
261
+
262
+ const files = readdirSync(path);
263
+
264
+ for (const file of files || []) {
265
+ const filePath = path + "/" + file;
266
+ const stats = statSync(filePath);
267
+
268
+ if (stats.isFile()) {
269
+ size += stats.size;
270
+ } else if (stats.isDirectory()) {
271
+ size += this.dirSize(filePath);
272
+ }
273
+ }
274
+ } catch {}
275
+
276
+ return size;
277
+ };
278
+
279
+ exports.arrayToObject = (obj, objKey) => {
280
+ if (!Array.isArray(obj) || !objKey) return obj;
281
+
282
+ const temp = {};
283
+ obj.forEach((objectItem) => {
284
+ temp[objectItem[objKey]] = objectItem;
285
+ });
286
+ return temp;
287
+ };
288
+
289
+ exports.fileBase64 = (filePath) => {
290
+ try {
291
+ return readFileSync(filePath, { encoding: "base64" });
292
+ } catch (error) {
293
+ return "#";
294
+ }
295
+ };
296
+
297
+ exports.newURL = (url) => {
298
+ url = new URL(url);
299
+ url = {
300
+ href: url.href,
301
+ origin: url.origin,
302
+ protocol: url.protocol,
303
+ host: url.host,
304
+ hostname: url.hostname,
305
+ port: url.port,
306
+ pathname: url.pathname,
307
+ search: url.search,
308
+ hash: url.hash,
309
+ referer: url.hostname.replace(/^www\./, ""),
310
+ };
311
+
312
+ if (url.port) url.referer += `_port_${url.port}`;
313
+
314
+ return url;
315
+ };
316
+
317
+ exports.crypto = ({ salt, embedSalt } = {}) => {
318
+ salt = String(salt).trim();
319
+ const createToken = this.createToken;
320
+
321
+ return {
322
+ do(string) {
323
+ try {
324
+ string = JSON.stringify(string);
325
+ } catch {
326
+ string = String(string);
327
+ }
328
+
329
+ let encripted = encodeURIComponent(string).split("").map(textToChars).map(applySaltToChar).map(byteHex).join("");
330
+
331
+ if (embedSalt) {
332
+ const pos = Math.floor(Math.random() * encripted.length);
333
+ const embed = `hWg${createToken({ length: Math.floor(Math.random() * 40) + 10 })}rtFg${salt}gdS${createToken({ length: Math.floor(Math.random() * 40) + 10 })}Ire`;
334
+
335
+ encripted = encripted.substring(0, pos) + embed + encripted.substring(pos);
336
+ }
337
+
338
+ return encripted;
339
+ },
340
+ undo(string) {
341
+ // TODO pattern in .env
342
+ const tokenPattern = /hWg(.*)rtFg(.*)gdS(.*)Ire/;
343
+ let token;
344
+
345
+ if (tokenPattern.test(string)) {
346
+ token = string.match(tokenPattern)?.[2];
347
+ string = string.replace(tokenPattern, "");
348
+ salt = token;
349
+ }
350
+
351
+ try {
352
+ string = string.trim();
353
+
354
+ const decodedString = string
355
+ .match(/.{1,2}/g)
356
+ .map((hex) => parseInt(hex, 16))
357
+ .map(applySaltToChar)
358
+ .map((charCode) => String.fromCharCode(charCode))
359
+ .join("");
360
+
361
+ let data = decodeURIComponent(decodedString);
362
+
363
+ try {
364
+ data = JSON.parse(data);
365
+ } catch {}
366
+
367
+ return { data, token };
368
+ } catch (error) {
369
+ return { error: "wrong_salt" };
370
+ }
371
+ },
372
+ };
373
+
374
+ function textToChars(text) {
375
+ return text.split("").map((c) => c.charCodeAt(0));
376
+ }
377
+
378
+ function applySaltToChar(code) {
379
+ return textToChars(salt).reduce((a, b) => a ^ b, code);
380
+ }
381
+
382
+ function byteHex(n) {
383
+ return ("0" + Number(n).toString(16)).slice(-2);
384
+ }
385
+ };
386
+
387
+ exports.secToTime = (seconds) => {
388
+ if (!(seconds = parseInt(seconds))) return;
389
+
390
+ const years = seconds / 60 / 60 / 24 / 30.5 / 12;
391
+ const months = seconds / 60 / 60 / 24 / 30.5;
392
+ const days = seconds / 60 / 60 / 24;
393
+ const hours = seconds / 60 / 60;
394
+ const minutes = seconds / 60;
395
+ seconds = parseInt(seconds % 60);
396
+
397
+ if (years >= 1) return parseInt(years) + "y " + parseInt(months % 12) + "m " + parseInt(days % 30.5) + "d";
398
+ if (months >= 1) return parseInt(months) + "m " + parseInt(days % 30.5) + "d " + parseInt(hours % 24) + "h";
399
+ if (days >= 1) return parseInt(days) + "d " + parseInt(hours % 24) + "h";
400
+ if (hours >= 1) return parseInt(hours) + "h " + doMinutes(minutes) + "min";
401
+ return parseInt(minutes) + "min " + (seconds < 10 ? "0" + seconds : seconds) + "s";
402
+
403
+ function doMinutes(minutes) {
404
+ minutes = parseInt(minutes % 60);
405
+ return minutes < 10 ? "0" + minutes : minutes;
406
+ }
407
+ };
408
+
409
+ exports.urlMetadata = async ({ url }) => {
410
+ let fileExtension, dataType, body;
411
+
412
+ try {
413
+ const tempUrl = new URL(url);
414
+ const fxIndex = tempUrl.pathname.lastIndexOf(".");
415
+ fileExtension = fxIndex < 0 ? null : tempUrl.pathname.substring(fxIndex + 1)?.match(/\w+/)[0];
416
+
417
+ let fetchRes = await fetch(url);
418
+
419
+ const sizeKb = parseInt(Number(fetchRes.headers?.get("content-length")) / 1000);
420
+ let contentType = fetchRes.headers?.get("content-type")?.split("/") || [];
421
+ let contentGroup = contentType[0];
422
+ let fileType = contentType[1]?.match(/[\w+.-]+/)[0];
423
+
424
+ contentType = `${contentGroup}/${fileType}`;
425
+
426
+ if (/html|xhtml/.test(fileType)) {
427
+ dataType = "html";
428
+ } else if (/image|audio|video|application/.test(contentGroup) && !/^xml|json|javascript/.test(fileType)) {
429
+ dataType = "dataSrc";
430
+ } else {
431
+ dataType = "plain";
432
+ }
433
+
434
+ if (sizeKb > 2000) {
435
+ body = "";
436
+ } else if (dataType == "dataSrc") {
437
+ body = await fetchRes.arrayBuffer();
438
+
439
+ var binary = "";
440
+ var bytes = new Uint8Array(body);
441
+ var len = bytes.byteLength;
442
+ for (var i = 0; i < len; i++) {
443
+ binary += String.fromCharCode(bytes[i]);
444
+ }
445
+
446
+ body = `data:${contentType};base64,` + btoa(binary);
447
+ } else {
448
+ body = await fetchRes.text();
449
+
450
+ try {
451
+ body = JSON.parse(body);
452
+ contentType = "application/json";
453
+ contentGroup = "application";
454
+ fileType = "json";
455
+ dataType = "json";
456
+ } catch {}
457
+ }
458
+
459
+ return { data: { contentType, contentGroup, fileType, dataType, sizeKb, fileExtension, body } };
460
+ } catch (error) {
461
+ return { error: String(error) };
462
+ }
463
+ };
package/os.js ADDED
@@ -0,0 +1,53 @@
1
+ const si = require("systeminformation");
2
+ const osUtils = require("os-utils");
3
+ const os = require("os");
4
+ const { statfsSync } = require("fs");
5
+ const { shortCount, secToTime } = require("./misc");
6
+
7
+ let cpuUsage, temperature;
8
+ const serverStart = Date.now();
9
+
10
+ exports.osStatus = () => {
11
+ const now = Date.now();
12
+
13
+ try {
14
+ return {
15
+ serverUptime: secToTime((now - serverStart) / 1000),
16
+ machineUptime: secToTime(os.uptime()),
17
+ memoryUsage: shortCount(os.totalmem() - os.freemem(), "disk"),
18
+ freeMemory: shortCount(os.freemem(), "disk"),
19
+ totalMemory: shortCount(os.totalmem(), "disk"),
20
+ os: os.type(),
21
+ hostname: os.hostname(),
22
+ temperature,
23
+ cpuUsage: cpuUsage + "%",
24
+ ...diskSpace(__basedir),
25
+ };
26
+ } catch (error) {
27
+ console.log("error --> ", error);
28
+ return { error };
29
+ }
30
+ };
31
+
32
+ setInterval(handleInterval, 1000 * 30);
33
+
34
+ function handleInterval() {
35
+ osUtils.cpuUsage((v) => {
36
+ cpuUsage = Math.ceil(v * 100);
37
+ });
38
+
39
+ si.cpuTemperature().then((tmp) => {
40
+ temperature = Number(tmp.main?.toFixed(2));
41
+ });
42
+ }
43
+
44
+ function diskSpace(path = "/") {
45
+ const space = statfsSync(path);
46
+
47
+ return {
48
+ disk_user_available: shortCount(space.bsize * space.bavail, "disk"),
49
+ disk_total_available: shortCount(space.bsize * space.bfree, "disk"),
50
+ disk_capacity: shortCount(space.bsize * space.blocks, "disk"),
51
+ disk_files: shortCount(space.files),
52
+ };
53
+ }
package/package.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "@nka212bg/backend-utils",
3
+ "author": "nka212bg",
4
+ "version": "0.1.0",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://gitlab.com/nka212bg/npm-backend.git"
8
+ },
9
+ "keywords": [
10
+ "misc"
11
+ ],
12
+ "dependencies": {
13
+ "@maxmind/geoip2-node": "^5.0.0",
14
+ "systeminformation": "^5.21.24",
15
+ "nodemailer": "^6.9.14",
16
+ "os-utils": "^0.0.14",
17
+ "stripe": "^14.23.0",
18
+ "mysql2": "^3.11.0",
19
+ "sqlite3": "^5.1.7",
20
+ "sharp": "^0.33.5",
21
+ "ws": "^7.3.0"
22
+ }
23
+ }
package/session.js ADDED
@@ -0,0 +1,145 @@
1
+ const { existsSync, readFileSync, writeFileSync } = require("fs");
2
+
3
+ const sessionStateFile = `${__basedir}/state/session.json`;
4
+ const SESSION = existsSync(sessionStateFile) ? JSON.parse(readFileSync(sessionStateFile, "utf8") || "{}") : {};
5
+
6
+ setInterval(() => {
7
+ // delete expired sessions
8
+ const now = Date.now();
9
+ Object.keys(SESSION).forEach((e) => {
10
+ SESSION[e].expireTime < now && delete SESSION[e];
11
+ });
12
+
13
+ // save the sessions in file
14
+ writeFileSync(sessionStateFile, JSON.stringify(SESSION));
15
+ }, 60000);
16
+
17
+ // session C.R.U.D.
18
+ exports.session = {
19
+ set(payload = {}) {
20
+ // payload.set => {token: 23456546, whatever: 'someValue', whatever_2: 'someValue'}
21
+ if (!payload.token) return { error: "missing_token" };
22
+
23
+ const token = payload.token;
24
+ delete payload.token;
25
+
26
+ if (!Object.keys(payload).length) return { error: "empty_payload" };
27
+
28
+ const now = Date.now();
29
+
30
+ if (SESSION[token]) {
31
+ if (payload.expirePeriod) SESSION[token].expireTime = now + payload.expirePeriod;
32
+
33
+ SESSION[token] = { ...SESSION[token], ...payload };
34
+ return;
35
+ }
36
+
37
+ if (!payload.expirePeriod) payload.expirePeriod = 60000 * 60 * 24 * 7; // 7days
38
+ payload.expireTime = now + payload.expirePeriod;
39
+
40
+ SESSION[token] = payload;
41
+ return { ...payload, expireIn: payload.expirePeriod + 60000 };
42
+ },
43
+
44
+ get(payload = {}) {
45
+ if ("token" in payload) {
46
+ if (!SESSION[payload.token]) return;
47
+ return { ...SESSION[payload.token], expireIn: SESSION[payload.token].expireTime - Date.now() + 60000 };
48
+ }
49
+
50
+ // payload => {id: 23456546}
51
+ const _key = Object.keys(payload)[0];
52
+ const _value = Object.values(payload)[0];
53
+ const sessions = [];
54
+
55
+ for (let token in SESSION) {
56
+ if (SESSION[token][_key] == _value) sessions.push({ ...SESSION[token], token });
57
+ }
58
+ return sessions;
59
+ },
60
+
61
+ update(payload = {}) {
62
+ // payload => {id: 23456546, whatever: 'someValue', whatever_2: 'someValue'}
63
+ const _key = Object.keys(payload)[0];
64
+ const _value = Object.values(payload)[0];
65
+ delete payload[_key];
66
+
67
+ if (!Object.keys(payload).length) return;
68
+
69
+ if (_key == "token") {
70
+ SESSION[_value] = { ...SESSION[_value], ...payload };
71
+ return;
72
+ }
73
+
74
+ for (let token in SESSION) {
75
+ if (SESSION[token][_key] == _value) SESSION[token] = { ...SESSION[token], ...payload };
76
+ }
77
+ },
78
+
79
+ delete(payload = {}) {
80
+ if (payload.token) {
81
+ return delete SESSION[payload.token];
82
+ }
83
+
84
+ // payload => {user_id: 23456546}
85
+ const _key = Object.keys(payload)[0];
86
+ const _value = Object.values(payload)[0];
87
+
88
+ for (let s in SESSION) {
89
+ if (SESSION[s][_key] == _value) delete SESSION[s];
90
+ }
91
+ },
92
+ };
93
+
94
+ // -------- check or get ban users --------
95
+ const banListFile = `${__basedir}/state/banList.json`;
96
+ const BAN_LIST = existsSync(banListFile) ? JSON.parse(readFileSync(banListFile, "utf8") || "{}") : {};
97
+ exports.banList = {
98
+ isBanned(payload) {
99
+ // payload = {ip: 123.67.432.43}
100
+ // payload = {email: 'test@gmail.com'}
101
+
102
+ const _key = Object.keys(payload)[0];
103
+ const _value = Object.values(payload)[0];
104
+
105
+ BAN_LIST[_key]?.includes(_value);
106
+ },
107
+ banUser(payload) {
108
+ // payload = {whatever: 'someValue'}
109
+ const _key = Object.keys(payload)[0];
110
+ const _value = Object.values(payload)[0];
111
+
112
+ if (BAN_LIST[_key]?.includes(_value)) return;
113
+ if (!BAN_LIST[_key]) BAN_LIST[_key] = [];
114
+
115
+ BAN_LIST[_key].push(_value);
116
+ writeFileSync(banListFile, JSON.stringify(BAN_LIST));
117
+ },
118
+ unBanUser(payload) {
119
+ // payload = {whatever: 'someValue'}
120
+ const _key = Object.keys(payload)[0];
121
+ const _value = Object.values(payload)[0];
122
+
123
+ const index = BAN_LIST[_key]?.indexOf(_value) || -1;
124
+ if (index > -1) {
125
+ BAN_LIST[_key].splice(index, 1);
126
+ writeFileSync(banListFile, JSON.stringify(BAN_LIST));
127
+ }
128
+ },
129
+ };
130
+
131
+ // rpm -> requests per minute
132
+ let IP_REGISTER = {};
133
+ exports.firewall = (ip, { rpm = 200 } = {}) => {
134
+ if (IP_REGISTER[ip] >= rpm) return true;
135
+ IP_REGISTER[ip] = (IP_REGISTER[ip] += 1) || 1;
136
+ };
137
+ setInterval(() => (IP_REGISTER = {}), 120000);
138
+
139
+ exports.sessionStat = () => {
140
+ return {
141
+ sessions: SESSION,
142
+ firewall: IP_REGISTER,
143
+ banList: BAN_LIST,
144
+ };
145
+ };