@nka212bg/backend-utils 0.1.31 → 0.1.33

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 +1 -1
  2. package/package.json +1 -1
  3. package/session.js +120 -12
package/misc.js CHANGED
@@ -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.31",
4
+ "version": "0.1.33",
5
5
  "main": "index.js",
6
6
  "dependencies": {
7
7
  "@maxmind/geoip2-node": "^5.0.0",
package/session.js CHANGED
@@ -1,28 +1,138 @@
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) return false;
50
+
51
+ if (token === "getAll") return STATE;
52
+
53
+ if (token.includes("=")) {
54
+ const [field, value] = token.trim().split(/\s*=\s*/);
55
+ return Object.entries(STATE)
56
+ .filter(([, s]) => s[field] == value)
57
+ .map(([token, s]) => ({ ...s, token }));
58
+ }
59
+
60
+ if (!STATE[token]) return false;
61
+ return { ...STATE[token], expireIn: STATE[token].expireTime - Date.now() + 60000 };
62
+ },
63
+
64
+ // DELETE
65
+ // delete serverState["abc123"];
66
+ // delete serverState["name=alice"]; // bulk delete, removes every entry where name == "alice"
67
+ deleteProperty(_, token) {
68
+ if (!token) return false;
69
+
70
+ if (token.includes("=")) {
71
+ const [field, value] = token.trim().split(/\s*=\s*/);
72
+ let itemsCount = 0;
73
+ Object.entries(STATE).forEach(([t, s]) => {
74
+ if (s[field] == value) {
75
+ delete STATE[t];
76
+ itemsCount += 1;
77
+ }
78
+ });
79
+ return !itemsCount ? false : String(itemsCount);
80
+ }
81
+
82
+ delete STATE[token];
83
+ return true;
84
+ },
85
+
86
+ // SET / UPDATE / DELETE
87
+ // serverState["abc123"] = {name: 'alice'}; // create (stamps expirePeriod/expireTime/uuid)
88
+ // serverState["abc123"] = {name: 'alice2'}; // update (merges into existing)
89
+ // serverState["abc123"] = null; // delete, cookie-expiry trick
90
+ // serverState["name=alice"] = {name: 'john'}; // bulk update, merges into every entry where name == "alice"
91
+ set(_, token, fields) {
92
+ if (!token) return false;
93
+
94
+ if (!fields) {
95
+ delete STATE[token];
96
+ return true;
97
+ }
98
+
99
+ if (token.includes("=")) {
100
+ const [field, value] = token.trim().split(/\s*=\s*/);
101
+ let itemsCount = 0;
102
+ Object.entries(STATE).forEach(([t, s]) => {
103
+ if (s[field] == value) {
104
+ STATE[t] = { ...s, ...fields };
105
+ itemsCount += 1;
106
+ }
107
+ });
108
+ return !itemsCount ? false : String(itemsCount);
109
+ }
110
+
111
+ const now = Date.now();
112
+
113
+ if (STATE[token]) {
114
+ if (fields.expirePeriod) fields.expireTime = now + fields.expirePeriod;
115
+ STATE[token] = { ...STATE[token], ...fields };
116
+ return { ...STATE[token] };
117
+ }
118
+
119
+ fields.expirePeriod ||= 60000 * 60 * 24 * 7; // 7 days
120
+ fields.expireTime = now + fields.expirePeriod;
121
+ fields.uuid = createToken({ type: "date" });
122
+
123
+ STATE[token] = fields;
124
+ return { ...fields };
125
+ },
126
+ },
127
+ );
128
+
20
129
  // session C.R.U.D.
21
130
  exports.session = {
22
131
  set(payload = {}) {
23
132
  // payload.set => {token: 23456546, whatever: 'someValue', whatever_2: 'someValue'}
24
133
  if (!payload.token) return { error: "missing_token" };
25
134
 
135
+ payload = { ...payload };
26
136
  const token = payload.token;
27
137
  delete payload.token;
28
138
 
@@ -64,6 +174,7 @@ exports.session = {
64
174
 
65
175
  update(payload = {}) {
66
176
  // payload => {id: 23456546, whatever: 'someValue', whatever_2: 'someValue'}
177
+ payload = { ...payload };
67
178
  const _key = Object.keys(payload)[0];
68
179
  const _value = Object.values(payload)[0];
69
180
  delete payload[_key];
@@ -95,9 +206,6 @@ exports.session = {
95
206
  },
96
207
  };
97
208
 
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
209
  exports.banList = {
102
210
  isBanned(payload) {
103
211
  // payload = {ip: 123.67.432.43}
@@ -106,7 +214,7 @@ exports.banList = {
106
214
  const _key = Object.keys(payload)[0];
107
215
  const _value = Object.values(payload)[0];
108
216
 
109
- BAN_LIST[_key]?.includes(_value);
217
+ return BAN_LIST[_key]?.includes(_value);
110
218
  },
111
219
  banUser(payload) {
112
220
  // payload = {whatever: 'someValue'}
@@ -117,17 +225,17 @@ exports.banList = {
117
225
  if (!BAN_LIST[_key]) BAN_LIST[_key] = [];
118
226
 
119
227
  BAN_LIST[_key].push(_value);
120
- writeFileSync(banListFile, JSON.stringify(BAN_LIST));
228
+ writeFile(banListFile, JSON.stringify(BAN_LIST)).catch((error) => console.error("banList save failed:", error));
121
229
  },
122
230
  unBanUser(payload) {
123
231
  // payload = {whatever: 'someValue'}
124
232
  const _key = Object.keys(payload)[0];
125
233
  const _value = Object.values(payload)[0];
126
234
 
127
- const index = BAN_LIST[_key]?.indexOf(_value) || -1;
235
+ const index = BAN_LIST[_key]?.indexOf(_value) ?? -1;
128
236
  if (index > -1) {
129
237
  BAN_LIST[_key].splice(index, 1);
130
- writeFileSync(banListFile, JSON.stringify(BAN_LIST));
238
+ writeFile(banListFile, JSON.stringify(BAN_LIST)).catch((error) => console.error("banList save failed:", error));
131
239
  }
132
240
  },
133
241
  };