@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/README.md +5 -0
- package/db/dbUtils.js +36 -0
- package/db/mysql2.js +56 -0
- package/db/sqlite3.js +99 -0
- package/location/GeoLite2-City.mmdb +0 -0
- package/location/VPNs-master.zip +0 -0
- package/location/index.js +88 -0
- package/location/localelib.js +4362 -0
- package/mailSmsTools/defaultTemplate.html +21 -0
- package/mailSmsTools/index.js +162 -0
- package/markdown/index.js +24 -0
- package/markdown/markdown.js +2 -0
- package/misc.js +463 -0
- package/os.js +53 -0
- package/package.json +23 -0
- package/session.js +145 -0
- package/socket.js +157 -0
- package/stripe.js +98 -0
- package/systemLog.js +72 -0
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: "</" },
|
|
58
|
+
_sr_: { exp: "\\/>", color: null, code: "/>" },
|
|
59
|
+
_docStart_: { exp: "<!", color: null, code: "<!" },
|
|
60
|
+
_lt_: { exp: "<", color: null, code: "<" },
|
|
61
|
+
_gt_: { exp: ">", color: null, code: ">" },
|
|
62
|
+
_op_: { exp: "\\(", color: null, code: "(" },
|
|
63
|
+
_cp_: { exp: "\\)", color: null, code: ")" },
|
|
64
|
+
_sq_: { exp: "'", color: null, code: "'" },
|
|
65
|
+
_dq_: { exp: '"', color: null, code: """ },
|
|
66
|
+
"src=": { exp: "src=", color: null, code: null },
|
|
67
|
+
// _eq_: { exp: "=", color: null, code: "=" },
|
|
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
|
+
};
|