@nka212bg/backend-utils 0.1.30 → 0.1.32

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.
Files changed (3) hide show
  1. package/misc.js +4 -4
  2. package/package.json +1 -1
  3. package/session.js +106 -12
package/misc.js CHANGED
@@ -86,11 +86,11 @@ exports.createToken = ({ length = 14, type } = {}) => {
86
86
  const nums = "1234567890";
87
87
 
88
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);
89
+ if (type == "date") return mixer(chars, Math.max(length - 6, 4)) + parseInt(Date.now() / 10000000);
90
+ return mixer(chars, 1) + mixer(nums + chars, length - 2) + mixer(chars, 1);
91
91
 
92
92
  function mixer(string, length) {
93
- if (string.length > length) string = string + string;
93
+ while (string.length < length) string += string;
94
94
 
95
95
  return string
96
96
  .split("")
@@ -451,7 +451,7 @@ exports.crypto = ({ salt, embedSalt } = {}) => {
451
451
  };
452
452
 
453
453
  exports.secToTime = (sec) => {
454
- sec = parseInt(sec);
454
+ sec = Math.abs(parseInt(sec));
455
455
  if (!sec) return;
456
456
 
457
457
  const SEC_IN_MIN = 60;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nka212bg/backend-utils",
3
3
  "author": "nka212bg",
4
- "version": "0.1.30",
4
+ "version": "0.1.32",
5
5
  "main": "index.js",
6
6
  "dependencies": {
7
7
  "@maxmind/geoip2-node": "^5.0.0",
package/session.js CHANGED
@@ -1,28 +1,124 @@
1
- const { existsSync, readFileSync, writeFileSync, mkdirSync } = require("fs");
1
+ const { existsSync, readFileSync, mkdirSync } = require("fs");
2
+ const { writeFile } = require("fs/promises");
2
3
  const { createToken } = require("./misc");
3
4
 
4
5
  !existsSync(`${__basedir}/state`) && mkdirSync(`${__basedir}/state`, { recursive: true });
5
- const sessionStateFile = `${__basedir}/state/session.json`;
6
6
 
7
+ /* -------------------- ban list -------------------- */
8
+ const banListFile = `${__basedir}/state/banList.json`;
9
+ const BAN_LIST = existsSync(banListFile) ? JSON.parse(readFileSync(banListFile, "utf8") || "{}") : {};
10
+
11
+ /* -------------------- session --------------------- */
12
+ const sessionStateFile = `${__basedir}/state/session.json`;
7
13
  const SESSION = existsSync(sessionStateFile) ? JSON.parse(readFileSync(sessionStateFile, "utf8") || "{}") : {};
8
14
 
15
+ /* -------------------- state --------------------- */
16
+ const serverStateFile = `${__basedir}/state/state.json`;
17
+ const STATE = existsSync(serverStateFile) ? JSON.parse(readFileSync(serverStateFile, "utf8") || "{}") : {};
18
+
9
19
  setInterval(() => {
10
- // delete expired sessions
11
20
  const now = Date.now();
21
+
22
+ // delete expired sessions
12
23
  Object.keys(SESSION).forEach((e) => {
13
24
  SESSION[e].expireTime < now && delete SESSION[e];
14
25
  });
26
+ // save the sessions in file (non-blocking write, JSON.stringify itself still runs sync)
27
+ writeFile(sessionStateFile, JSON.stringify(SESSION)).catch((error) => console.error("session save failed:", error));
15
28
 
16
- // save the sessions in file
17
- writeFileSync(sessionStateFile, JSON.stringify(SESSION));
29
+ // delete expired entries
30
+ Object.keys(STATE).forEach((e) => {
31
+ STATE[e].expireTime < now && delete STATE[e];
32
+ });
33
+ // save the state in file (non-blocking write, JSON.stringify itself still runs sync)
34
+ writeFile(serverStateFile, JSON.stringify(STATE)).catch((error) => console.error("state save failed:", error));
18
35
  }, 60000);
19
36
 
37
+ // document.cookie-style: reading serverState[token] gets it, assigning
38
+ // serverState[token] = {...} sets/updates it, assigning a falsy value
39
+ // deletes it (the same "expire it out" trick browsers use for cookies).
40
+ exports.serverState = new Proxy(
41
+ {},
42
+ {
43
+ // GET
44
+ // const s = serverState["abc123"]; // => {name: 'alice', ..., expireIn: 604859999}
45
+ // const s = serverState[req.headers.authorization];
46
+ // const all = serverState.getAll; // => whole STATE map
47
+ // const alices = serverState["name=alice"]; // => all entries where name == "alice", each with its token
48
+ get(_, token) {
49
+ if (token === "getAll") return STATE;
50
+
51
+ if (token.includes("=")) {
52
+ const [field, value] = token.trim().split(/\s*=\s*/);
53
+ return Object.entries(STATE)
54
+ .filter(([, s]) => s[field] == value)
55
+ .map(([token, s]) => ({ ...s, token }));
56
+ }
57
+
58
+ if (!STATE[token]) return undefined;
59
+ return { ...STATE[token], expireIn: STATE[token].expireTime - Date.now() + 60000 };
60
+ },
61
+
62
+ // DELETE
63
+ // delete serverState["abc123"];
64
+ // delete serverState["name=alice"]; // bulk delete, removes every entry where name == "alice"
65
+ deleteProperty(_, token) {
66
+ if (token.includes("=")) {
67
+ const [field, value] = token.trim().split(/\s*=\s*/);
68
+ Object.entries(STATE).forEach(([t, s]) => {
69
+ if (s[field] == value) delete STATE[t];
70
+ });
71
+ return true;
72
+ }
73
+
74
+ delete STATE[token];
75
+ return true;
76
+ },
77
+
78
+ // SET / UPDATE / DELETE
79
+ // serverState["abc123"] = {name: 'alice'}; // create (stamps expirePeriod/expireTime/uuid)
80
+ // serverState["abc123"] = {name: 'alice2'}; // update (merges into existing)
81
+ // serverState["abc123"] = null; // delete, cookie-expiry trick
82
+ // serverState["name=alice"] = {name: 'john'}; // bulk update, merges into every entry where name == "alice"
83
+ set(_, token, fields) {
84
+ if (token.includes("=")) {
85
+ const [field, value] = token.trim().split(/\s*=\s*/);
86
+ Object.entries(STATE).forEach(([t, s]) => {
87
+ if (s[field] == value) STATE[t] = { ...s, ...fields };
88
+ });
89
+ return true;
90
+ }
91
+
92
+ if (!fields) {
93
+ delete STATE[token];
94
+ return true;
95
+ }
96
+
97
+ const now = Date.now();
98
+
99
+ if (STATE[token]) {
100
+ if (fields.expirePeriod) fields.expireTime = now + fields.expirePeriod;
101
+ STATE[token] = { ...STATE[token], ...fields };
102
+ return true;
103
+ }
104
+
105
+ fields.expirePeriod ||= 60000 * 60 * 24 * 7; // 7 days
106
+ fields.expireTime = now + fields.expirePeriod;
107
+ fields.uuid = createToken({ type: "date" });
108
+
109
+ STATE[token] = fields;
110
+ return true;
111
+ },
112
+ },
113
+ );
114
+
20
115
  // session C.R.U.D.
21
116
  exports.session = {
22
117
  set(payload = {}) {
23
118
  // payload.set => {token: 23456546, whatever: 'someValue', whatever_2: 'someValue'}
24
119
  if (!payload.token) return { error: "missing_token" };
25
120
 
121
+ payload = { ...payload };
26
122
  const token = payload.token;
27
123
  delete payload.token;
28
124
 
@@ -64,6 +160,7 @@ exports.session = {
64
160
 
65
161
  update(payload = {}) {
66
162
  // payload => {id: 23456546, whatever: 'someValue', whatever_2: 'someValue'}
163
+ payload = { ...payload };
67
164
  const _key = Object.keys(payload)[0];
68
165
  const _value = Object.values(payload)[0];
69
166
  delete payload[_key];
@@ -95,9 +192,6 @@ exports.session = {
95
192
  },
96
193
  };
97
194
 
98
- // -------- check or get ban users --------
99
- const banListFile = `${__basedir}/state/banList.json`;
100
- const BAN_LIST = existsSync(banListFile) ? JSON.parse(readFileSync(banListFile, "utf8") || "{}") : {};
101
195
  exports.banList = {
102
196
  isBanned(payload) {
103
197
  // payload = {ip: 123.67.432.43}
@@ -106,7 +200,7 @@ exports.banList = {
106
200
  const _key = Object.keys(payload)[0];
107
201
  const _value = Object.values(payload)[0];
108
202
 
109
- BAN_LIST[_key]?.includes(_value);
203
+ return BAN_LIST[_key]?.includes(_value);
110
204
  },
111
205
  banUser(payload) {
112
206
  // payload = {whatever: 'someValue'}
@@ -117,17 +211,17 @@ exports.banList = {
117
211
  if (!BAN_LIST[_key]) BAN_LIST[_key] = [];
118
212
 
119
213
  BAN_LIST[_key].push(_value);
120
- writeFileSync(banListFile, JSON.stringify(BAN_LIST));
214
+ writeFile(banListFile, JSON.stringify(BAN_LIST)).catch((error) => console.error("banList save failed:", error));
121
215
  },
122
216
  unBanUser(payload) {
123
217
  // payload = {whatever: 'someValue'}
124
218
  const _key = Object.keys(payload)[0];
125
219
  const _value = Object.values(payload)[0];
126
220
 
127
- const index = BAN_LIST[_key]?.indexOf(_value) || -1;
221
+ const index = BAN_LIST[_key]?.indexOf(_value) ?? -1;
128
222
  if (index > -1) {
129
223
  BAN_LIST[_key].splice(index, 1);
130
- writeFileSync(banListFile, JSON.stringify(BAN_LIST));
224
+ writeFile(banListFile, JSON.stringify(BAN_LIST)).catch((error) => console.error("banList save failed:", error));
131
225
  }
132
226
  },
133
227
  };