blockmine 1.4.3 → 1.4.6

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/backend/cli.js CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
  const fs = require('fs');
3
3
  const os = require('os');
4
4
  const path = require('path');
@@ -1,126 +1,126 @@
1
- -- CreateTable
2
- CREATE TABLE "Server" (
3
- "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
4
- "name" TEXT NOT NULL,
5
- "host" TEXT NOT NULL,
6
- "port" INTEGER NOT NULL DEFAULT 25565,
7
- "version" TEXT NOT NULL
8
- );
9
-
10
- -- CreateTable
11
- CREATE TABLE "Bot" (
12
- "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
13
- "username" TEXT NOT NULL,
14
- "password" TEXT,
15
- "prefix" TEXT DEFAULT '@',
16
- "note" TEXT,
17
- "serverId" INTEGER NOT NULL,
18
- "proxyHost" TEXT,
19
- "proxyPort" INTEGER,
20
- "proxyUsername" TEXT,
21
- "proxyPassword" TEXT,
22
- "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
23
- "updatedAt" DATETIME NOT NULL,
24
- CONSTRAINT "Bot_serverId_fkey" FOREIGN KEY ("serverId") REFERENCES "Server" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
25
- );
26
-
27
- -- CreateTable
28
- CREATE TABLE "InstalledPlugin" (
29
- "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
30
- "botId" INTEGER NOT NULL,
31
- "name" TEXT NOT NULL,
32
- "version" TEXT NOT NULL,
33
- "description" TEXT,
34
- "sourceType" TEXT NOT NULL,
35
- "sourceUri" TEXT,
36
- "path" TEXT NOT NULL,
37
- "isEnabled" BOOLEAN NOT NULL DEFAULT true,
38
- "manifest" TEXT,
39
- "settings" TEXT DEFAULT '{}',
40
- CONSTRAINT "InstalledPlugin_botId_fkey" FOREIGN KEY ("botId") REFERENCES "Bot" ("id") ON DELETE CASCADE ON UPDATE CASCADE
41
- );
42
-
43
- -- CreateTable
44
- CREATE TABLE "Command" (
45
- "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
46
- "botId" INTEGER NOT NULL,
47
- "name" TEXT NOT NULL,
48
- "isEnabled" BOOLEAN NOT NULL DEFAULT true,
49
- "cooldown" INTEGER NOT NULL DEFAULT 0,
50
- "aliases" TEXT NOT NULL DEFAULT '[]',
51
- "description" TEXT,
52
- "owner" TEXT,
53
- "permissionId" INTEGER,
54
- "allowedChatTypes" TEXT NOT NULL DEFAULT '["chat", "private"]',
55
- CONSTRAINT "Command_botId_fkey" FOREIGN KEY ("botId") REFERENCES "Bot" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
56
- CONSTRAINT "Command_permissionId_fkey" FOREIGN KEY ("permissionId") REFERENCES "Permission" ("id") ON DELETE SET NULL ON UPDATE CASCADE
57
- );
58
-
59
- -- CreateTable
60
- CREATE TABLE "User" (
61
- "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
62
- "username" TEXT NOT NULL,
63
- "isBlacklisted" BOOLEAN NOT NULL DEFAULT false,
64
- "botId" INTEGER NOT NULL,
65
- CONSTRAINT "User_botId_fkey" FOREIGN KEY ("botId") REFERENCES "Bot" ("id") ON DELETE CASCADE ON UPDATE CASCADE
66
- );
67
-
68
- -- CreateTable
69
- CREATE TABLE "Group" (
70
- "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
71
- "name" TEXT NOT NULL,
72
- "owner" TEXT NOT NULL DEFAULT 'system',
73
- "botId" INTEGER NOT NULL,
74
- CONSTRAINT "Group_botId_fkey" FOREIGN KEY ("botId") REFERENCES "Bot" ("id") ON DELETE CASCADE ON UPDATE CASCADE
75
- );
76
-
77
- -- CreateTable
78
- CREATE TABLE "Permission" (
79
- "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
80
- "name" TEXT NOT NULL,
81
- "description" TEXT,
82
- "owner" TEXT NOT NULL DEFAULT 'system',
83
- "botId" INTEGER NOT NULL,
84
- CONSTRAINT "Permission_botId_fkey" FOREIGN KEY ("botId") REFERENCES "Bot" ("id") ON DELETE CASCADE ON UPDATE CASCADE
85
- );
86
-
87
- -- CreateTable
88
- CREATE TABLE "UserGroup" (
89
- "userId" INTEGER NOT NULL,
90
- "groupId" INTEGER NOT NULL,
91
-
92
- PRIMARY KEY ("userId", "groupId"),
93
- CONSTRAINT "UserGroup_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
94
- CONSTRAINT "UserGroup_groupId_fkey" FOREIGN KEY ("groupId") REFERENCES "Group" ("id") ON DELETE CASCADE ON UPDATE CASCADE
95
- );
96
-
97
- -- CreateTable
98
- CREATE TABLE "GroupPermission" (
99
- "groupId" INTEGER NOT NULL,
100
- "permissionId" INTEGER NOT NULL,
101
-
102
- PRIMARY KEY ("groupId", "permissionId"),
103
- CONSTRAINT "GroupPermission_groupId_fkey" FOREIGN KEY ("groupId") REFERENCES "Group" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
104
- CONSTRAINT "GroupPermission_permissionId_fkey" FOREIGN KEY ("permissionId") REFERENCES "Permission" ("id") ON DELETE CASCADE ON UPDATE CASCADE
105
- );
106
-
107
- -- CreateIndex
108
- CREATE UNIQUE INDEX "Server_name_key" ON "Server"("name");
109
-
110
- -- CreateIndex
111
- CREATE UNIQUE INDEX "Bot_username_key" ON "Bot"("username");
112
-
113
- -- CreateIndex
114
- CREATE UNIQUE INDEX "InstalledPlugin_botId_name_key" ON "InstalledPlugin"("botId", "name");
115
-
116
- -- CreateIndex
117
- CREATE UNIQUE INDEX "Command_botId_name_key" ON "Command"("botId", "name");
118
-
119
- -- CreateIndex
120
- CREATE UNIQUE INDEX "User_botId_username_key" ON "User"("botId", "username");
121
-
122
- -- CreateIndex
123
- CREATE UNIQUE INDEX "Group_botId_name_key" ON "Group"("botId", "name");
124
-
125
- -- CreateIndex
126
- CREATE UNIQUE INDEX "Permission_botId_name_key" ON "Permission"("botId", "name");
1
+ -- CreateTable
2
+ CREATE TABLE "Server" (
3
+ "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
4
+ "name" TEXT NOT NULL,
5
+ "host" TEXT NOT NULL,
6
+ "port" INTEGER NOT NULL DEFAULT 25565,
7
+ "version" TEXT NOT NULL
8
+ );
9
+
10
+ -- CreateTable
11
+ CREATE TABLE "Bot" (
12
+ "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
13
+ "username" TEXT NOT NULL,
14
+ "password" TEXT,
15
+ "prefix" TEXT DEFAULT '@',
16
+ "note" TEXT,
17
+ "serverId" INTEGER NOT NULL,
18
+ "proxyHost" TEXT,
19
+ "proxyPort" INTEGER,
20
+ "proxyUsername" TEXT,
21
+ "proxyPassword" TEXT,
22
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
23
+ "updatedAt" DATETIME NOT NULL,
24
+ CONSTRAINT "Bot_serverId_fkey" FOREIGN KEY ("serverId") REFERENCES "Server" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
25
+ );
26
+
27
+ -- CreateTable
28
+ CREATE TABLE "InstalledPlugin" (
29
+ "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
30
+ "botId" INTEGER NOT NULL,
31
+ "name" TEXT NOT NULL,
32
+ "version" TEXT NOT NULL,
33
+ "description" TEXT,
34
+ "sourceType" TEXT NOT NULL,
35
+ "sourceUri" TEXT,
36
+ "path" TEXT NOT NULL,
37
+ "isEnabled" BOOLEAN NOT NULL DEFAULT true,
38
+ "manifest" TEXT,
39
+ "settings" TEXT DEFAULT '{}',
40
+ CONSTRAINT "InstalledPlugin_botId_fkey" FOREIGN KEY ("botId") REFERENCES "Bot" ("id") ON DELETE CASCADE ON UPDATE CASCADE
41
+ );
42
+
43
+ -- CreateTable
44
+ CREATE TABLE "Command" (
45
+ "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
46
+ "botId" INTEGER NOT NULL,
47
+ "name" TEXT NOT NULL,
48
+ "isEnabled" BOOLEAN NOT NULL DEFAULT true,
49
+ "cooldown" INTEGER NOT NULL DEFAULT 0,
50
+ "aliases" TEXT NOT NULL DEFAULT '[]',
51
+ "description" TEXT,
52
+ "owner" TEXT,
53
+ "permissionId" INTEGER,
54
+ "allowedChatTypes" TEXT NOT NULL DEFAULT '["chat", "private"]',
55
+ CONSTRAINT "Command_botId_fkey" FOREIGN KEY ("botId") REFERENCES "Bot" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
56
+ CONSTRAINT "Command_permissionId_fkey" FOREIGN KEY ("permissionId") REFERENCES "Permission" ("id") ON DELETE SET NULL ON UPDATE CASCADE
57
+ );
58
+
59
+ -- CreateTable
60
+ CREATE TABLE "User" (
61
+ "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
62
+ "username" TEXT NOT NULL,
63
+ "isBlacklisted" BOOLEAN NOT NULL DEFAULT false,
64
+ "botId" INTEGER NOT NULL,
65
+ CONSTRAINT "User_botId_fkey" FOREIGN KEY ("botId") REFERENCES "Bot" ("id") ON DELETE CASCADE ON UPDATE CASCADE
66
+ );
67
+
68
+ -- CreateTable
69
+ CREATE TABLE "Group" (
70
+ "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
71
+ "name" TEXT NOT NULL,
72
+ "owner" TEXT NOT NULL DEFAULT 'system',
73
+ "botId" INTEGER NOT NULL,
74
+ CONSTRAINT "Group_botId_fkey" FOREIGN KEY ("botId") REFERENCES "Bot" ("id") ON DELETE CASCADE ON UPDATE CASCADE
75
+ );
76
+
77
+ -- CreateTable
78
+ CREATE TABLE "Permission" (
79
+ "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
80
+ "name" TEXT NOT NULL,
81
+ "description" TEXT,
82
+ "owner" TEXT NOT NULL DEFAULT 'system',
83
+ "botId" INTEGER NOT NULL,
84
+ CONSTRAINT "Permission_botId_fkey" FOREIGN KEY ("botId") REFERENCES "Bot" ("id") ON DELETE CASCADE ON UPDATE CASCADE
85
+ );
86
+
87
+ -- CreateTable
88
+ CREATE TABLE "UserGroup" (
89
+ "userId" INTEGER NOT NULL,
90
+ "groupId" INTEGER NOT NULL,
91
+
92
+ PRIMARY KEY ("userId", "groupId"),
93
+ CONSTRAINT "UserGroup_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
94
+ CONSTRAINT "UserGroup_groupId_fkey" FOREIGN KEY ("groupId") REFERENCES "Group" ("id") ON DELETE CASCADE ON UPDATE CASCADE
95
+ );
96
+
97
+ -- CreateTable
98
+ CREATE TABLE "GroupPermission" (
99
+ "groupId" INTEGER NOT NULL,
100
+ "permissionId" INTEGER NOT NULL,
101
+
102
+ PRIMARY KEY ("groupId", "permissionId"),
103
+ CONSTRAINT "GroupPermission_groupId_fkey" FOREIGN KEY ("groupId") REFERENCES "Group" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
104
+ CONSTRAINT "GroupPermission_permissionId_fkey" FOREIGN KEY ("permissionId") REFERENCES "Permission" ("id") ON DELETE CASCADE ON UPDATE CASCADE
105
+ );
106
+
107
+ -- CreateIndex
108
+ CREATE UNIQUE INDEX "Server_name_key" ON "Server"("name");
109
+
110
+ -- CreateIndex
111
+ CREATE UNIQUE INDEX "Bot_username_key" ON "Bot"("username");
112
+
113
+ -- CreateIndex
114
+ CREATE UNIQUE INDEX "InstalledPlugin_botId_name_key" ON "InstalledPlugin"("botId", "name");
115
+
116
+ -- CreateIndex
117
+ CREATE UNIQUE INDEX "Command_botId_name_key" ON "Command"("botId", "name");
118
+
119
+ -- CreateIndex
120
+ CREATE UNIQUE INDEX "User_botId_username_key" ON "User"("botId", "username");
121
+
122
+ -- CreateIndex
123
+ CREATE UNIQUE INDEX "Group_botId_name_key" ON "Group"("botId", "name");
124
+
125
+ -- CreateIndex
126
+ CREATE UNIQUE INDEX "Permission_botId_name_key" ON "Permission"("botId", "name");
@@ -1,27 +1,27 @@
1
- -- AlterTable
2
- ALTER TABLE "Bot" ADD COLUMN "owners" TEXT DEFAULT '';
3
-
4
- -- RedefineTables
5
- PRAGMA defer_foreign_keys=ON;
6
- PRAGMA foreign_keys=OFF;
7
- CREATE TABLE "new_InstalledPlugin" (
8
- "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
9
- "botId" INTEGER NOT NULL,
10
- "name" TEXT NOT NULL,
11
- "version" TEXT NOT NULL,
12
- "description" TEXT,
13
- "sourceType" TEXT NOT NULL,
14
- "sourceUri" TEXT,
15
- "path" TEXT NOT NULL,
16
- "isEnabled" BOOLEAN NOT NULL DEFAULT true,
17
- "manifest" TEXT,
18
- "settings" TEXT DEFAULT '{}',
19
- "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
20
- CONSTRAINT "InstalledPlugin_botId_fkey" FOREIGN KEY ("botId") REFERENCES "Bot" ("id") ON DELETE CASCADE ON UPDATE CASCADE
21
- );
22
- INSERT INTO "new_InstalledPlugin" ("botId", "description", "id", "isEnabled", "manifest", "name", "path", "settings", "sourceType", "sourceUri", "version") SELECT "botId", "description", "id", "isEnabled", "manifest", "name", "path", "settings", "sourceType", "sourceUri", "version" FROM "InstalledPlugin";
23
- DROP TABLE "InstalledPlugin";
24
- ALTER TABLE "new_InstalledPlugin" RENAME TO "InstalledPlugin";
25
- CREATE UNIQUE INDEX "InstalledPlugin_botId_name_key" ON "InstalledPlugin"("botId", "name");
26
- PRAGMA foreign_keys=ON;
27
- PRAGMA defer_foreign_keys=OFF;
1
+ -- AlterTable
2
+ ALTER TABLE "Bot" ADD COLUMN "owners" TEXT DEFAULT '';
3
+
4
+ -- RedefineTables
5
+ PRAGMA defer_foreign_keys=ON;
6
+ PRAGMA foreign_keys=OFF;
7
+ CREATE TABLE "new_InstalledPlugin" (
8
+ "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
9
+ "botId" INTEGER NOT NULL,
10
+ "name" TEXT NOT NULL,
11
+ "version" TEXT NOT NULL,
12
+ "description" TEXT,
13
+ "sourceType" TEXT NOT NULL,
14
+ "sourceUri" TEXT,
15
+ "path" TEXT NOT NULL,
16
+ "isEnabled" BOOLEAN NOT NULL DEFAULT true,
17
+ "manifest" TEXT,
18
+ "settings" TEXT DEFAULT '{}',
19
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
20
+ CONSTRAINT "InstalledPlugin_botId_fkey" FOREIGN KEY ("botId") REFERENCES "Bot" ("id") ON DELETE CASCADE ON UPDATE CASCADE
21
+ );
22
+ INSERT INTO "new_InstalledPlugin" ("botId", "description", "id", "isEnabled", "manifest", "name", "path", "settings", "sourceType", "sourceUri", "version") SELECT "botId", "description", "id", "isEnabled", "manifest", "name", "path", "settings", "sourceType", "sourceUri", "version" FROM "InstalledPlugin";
23
+ DROP TABLE "InstalledPlugin";
24
+ ALTER TABLE "new_InstalledPlugin" RENAME TO "InstalledPlugin";
25
+ CREATE UNIQUE INDEX "InstalledPlugin_botId_name_key" ON "InstalledPlugin"("botId", "name");
26
+ PRAGMA foreign_keys=ON;
27
+ PRAGMA defer_foreign_keys=OFF;
@@ -1,13 +1,13 @@
1
- -- CreateTable
2
- CREATE TABLE "ScheduledTask" (
3
- "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
4
- "name" TEXT NOT NULL,
5
- "cronPattern" TEXT NOT NULL,
6
- "action" TEXT NOT NULL,
7
- "targetBotIds" TEXT NOT NULL,
8
- "payload" TEXT DEFAULT '{}',
9
- "isEnabled" BOOLEAN NOT NULL DEFAULT true,
10
- "lastRun" DATETIME,
11
- "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
12
- "updatedAt" DATETIME NOT NULL
13
- );
1
+ -- CreateTable
2
+ CREATE TABLE "ScheduledTask" (
3
+ "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
4
+ "name" TEXT NOT NULL,
5
+ "cronPattern" TEXT NOT NULL,
6
+ "action" TEXT NOT NULL,
7
+ "targetBotIds" TEXT NOT NULL,
8
+ "payload" TEXT DEFAULT '{}',
9
+ "isEnabled" BOOLEAN NOT NULL DEFAULT true,
10
+ "lastRun" DATETIME,
11
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
12
+ "updatedAt" DATETIME NOT NULL
13
+ );
@@ -1,26 +1,26 @@
1
- -- CreateTable
2
- CREATE TABLE "PanelUser" (
3
- "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
4
- "uuid" TEXT NOT NULL,
5
- "username" TEXT NOT NULL,
6
- "passwordHash" TEXT NOT NULL,
7
- "roleId" INTEGER NOT NULL,
8
- "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
9
- CONSTRAINT "PanelUser_roleId_fkey" FOREIGN KEY ("roleId") REFERENCES "PanelRole" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
10
- );
11
-
12
- -- CreateTable
13
- CREATE TABLE "PanelRole" (
14
- "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
15
- "name" TEXT NOT NULL,
16
- "permissions" TEXT NOT NULL DEFAULT '[]'
17
- );
18
-
19
- -- CreateIndex
20
- CREATE UNIQUE INDEX "PanelUser_uuid_key" ON "PanelUser"("uuid");
21
-
22
- -- CreateIndex
23
- CREATE UNIQUE INDEX "PanelUser_username_key" ON "PanelUser"("username");
24
-
25
- -- CreateIndex
26
- CREATE UNIQUE INDEX "PanelRole_name_key" ON "PanelRole"("name");
1
+ -- CreateTable
2
+ CREATE TABLE "PanelUser" (
3
+ "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
4
+ "uuid" TEXT NOT NULL,
5
+ "username" TEXT NOT NULL,
6
+ "passwordHash" TEXT NOT NULL,
7
+ "roleId" INTEGER NOT NULL,
8
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
9
+ CONSTRAINT "PanelUser_roleId_fkey" FOREIGN KEY ("roleId") REFERENCES "PanelRole" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
10
+ );
11
+
12
+ -- CreateTable
13
+ CREATE TABLE "PanelRole" (
14
+ "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
15
+ "name" TEXT NOT NULL,
16
+ "permissions" TEXT NOT NULL DEFAULT '[]'
17
+ );
18
+
19
+ -- CreateIndex
20
+ CREATE UNIQUE INDEX "PanelUser_uuid_key" ON "PanelUser"("uuid");
21
+
22
+ -- CreateIndex
23
+ CREATE UNIQUE INDEX "PanelUser_username_key" ON "PanelUser"("username");
24
+
25
+ -- CreateIndex
26
+ CREATE UNIQUE INDEX "PanelRole_name_key" ON "PanelRole"("name");
@@ -1,3 +1,3 @@
1
- # Please do not edit this file manually
2
- # It should be added in your version-control system (i.e. Git)
1
+ # Please do not edit this file manually
2
+ # It should be added in your version-control system (i.e. Git)
3
3
  provider = "sqlite"
@@ -1,17 +1,14 @@
1
-
2
1
  const jwt = require('jsonwebtoken');
3
2
  const config = require('../../config');
4
3
 
5
4
  const JWT_SECRET = config.security.jwtSecret;
6
5
 
7
- /**
8
- * Middleware для проверки JWT-токена.
9
- * Извлекает токен из заголовка Authorization, проверяет его подлинность
10
- * и добавляет расшифрованные данные (payload) в req.user.
11
- */
6
+ const tokenCache = new Map();
7
+ const CACHE_TTL = 5 * 60 * 1000;
8
+
9
+
12
10
  function authenticate(req, res, next) {
13
11
  const authHeader = req.header('Authorization');
14
-
15
12
  if (!authHeader) {
16
13
  return res.status(401).json({ error: 'Нет токена, доступ запрещен' });
17
14
  }
@@ -23,28 +20,39 @@ function authenticate(req, res, next) {
23
20
 
24
21
  const token = tokenParts[1];
25
22
 
23
+ if (tokenCache.has(token)) {
24
+ const cached = tokenCache.get(token);
25
+ if (Date.now() < cached.expires) {
26
+ req.user = cached.payload;
27
+ return next();
28
+ } else {
29
+ tokenCache.delete(token);
30
+ }
31
+ }
32
+
26
33
  try {
27
- const decoded = jwt.verify(token, JWT_SECRET);
34
+ const decoded = jwt.verify(token, JWT_SECRET, { algorithms: ['HS256'] });
28
35
  req.user = decoded;
36
+
37
+ tokenCache.set(token, {
38
+ payload: decoded,
39
+ expires: Date.now() + CACHE_TTL
40
+ });
41
+
29
42
  next();
30
43
  } catch (err) {
31
44
  res.status(401).json({ error: 'Невалидный токен' });
32
45
  }
33
46
  }
34
47
 
35
- /**
36
- * Middleware-фабрика для проверки прав доступа.
37
- * @param {string} requiredPermission - Право, необходимое для доступа к роуту (например, 'bot:delete').
38
- * @returns {function} - Express middleware.
39
- */
48
+
40
49
  function authorize(requiredPermission) {
41
50
  return (req, res, next) => {
42
- if (!req.user || !req.user.permissions) {
43
- return res.status(403).json({ error: 'Ошибка прав доступа: пользователь не аутентифицирован.' });
51
+ if (!req.user || !Array.isArray(req.user.permissions)) {
52
+ return res.status(403).json({ error: 'Ошибка прав доступа: пользователь не аутентифицирован или формат прав некорректен.' });
44
53
  }
45
54
 
46
55
  const userPermissions = req.user.permissions;
47
-
48
56
  if (userPermissions.includes('*') || userPermissions.includes(requiredPermission)) {
49
57
  next();
50
58
  } else {
@@ -5,7 +5,6 @@ const { PrismaClient } = require('@prisma/client');
5
5
  const pidusage = require('pidusage');
6
6
  const DependencyService = require('./DependencyService');
7
7
  const config = require('../config');
8
-
9
8
  const fs = require('fs');
10
9
  const os = require('os');
11
10
  const { v4: uuidv4 } = require('uuid');
@@ -25,6 +24,26 @@ const WARNING_COOLDOWN = 10 * 1000;
25
24
  const STATS_SERVER_URL = 'http://185.65.200.184:3000';
26
25
  let instanceId = null;
27
26
  const DATA_DIR = path.join(os.homedir(), '.blockmine');
27
+ const INSTANCE_ID_PATH = path.join(DATA_DIR, '.instance_id');
28
+
29
+ function getInstanceId() {
30
+ if (instanceId) return instanceId;
31
+ try {
32
+ if (fs.existsSync(INSTANCE_ID_PATH)) {
33
+ instanceId = fs.readFileSync(INSTANCE_ID_PATH, 'utf-8');
34
+ } else {
35
+ instanceId = uuidv4();
36
+ if (!fs.existsSync(DATA_DIR)) {
37
+ fs.mkdirSync(DATA_DIR, { recursive: true });
38
+ }
39
+ fs.writeFileSync(INSTANCE_ID_PATH, instanceId, 'utf-8');
40
+ }
41
+ } catch (error) {
42
+ console.error('[Telemetry] Ошибка при загрузке/создании Instance ID:', error);
43
+ return null;
44
+ }
45
+ return instanceId;
46
+ }
28
47
 
29
48
 
30
49
  class BotManager {
@@ -34,9 +53,9 @@ class BotManager {
34
53
  this.resourceUsage = new Map();
35
54
  this.botConfigs = new Map();
36
55
 
37
- setInterval(() => this.updateAllResourceUsage(), 5000);
38
-
56
+ getInstanceId();
39
57
 
58
+ setInterval(() => this.updateAllResourceUsage(), 5000);
40
59
  if (config.telemetry?.enabled) {
41
60
  setInterval(() => this.sendHeartbeat(), 5 * 60 * 1000);
42
61
  }
@@ -49,13 +68,11 @@ class BotManager {
49
68
  prisma.command.findMany({ where: { botId } }),
50
69
  prisma.permission.findMany({ where: { botId } }),
51
70
  ]);
52
-
53
71
  const config = {
54
72
  commands: new Map(commands.map(cmd => [cmd.name, cmd])),
55
73
  permissionsById: new Map(permissions.map(p => [p.id, p])),
56
74
  commandAliases: new Map()
57
75
  };
58
-
59
76
  for (const cmd of commands) {
60
77
  const aliases = JSON.parse(cmd.aliases || '[]');
61
78
  for (const alias of aliases) {
@@ -81,7 +98,6 @@ class BotManager {
81
98
 
82
99
  triggerHeartbeat() {
83
100
  if (!config.telemetry?.enabled) return;
84
-
85
101
  if (this.heartbeatDebounceTimer) {
86
102
  clearTimeout(this.heartbeatDebounceTimer);
87
103
  }
@@ -105,7 +121,6 @@ class BotManager {
105
121
 
106
122
  async sendHeartbeat() {
107
123
  if (!config.telemetry?.enabled) return;
108
-
109
124
  if (!instanceId) return;
110
125
 
111
126
  try {
@@ -131,7 +146,6 @@ class BotManager {
131
146
  return;
132
147
  }
133
148
  const { challenge, difficulty, prefix } = await challengeRes.json();
134
-
135
149
  let nonce = 0;
136
150
  let hash = '';
137
151
  do {
@@ -150,7 +164,6 @@ class BotManager {
150
164
  nonce: nonce
151
165
  })
152
166
  });
153
-
154
167
  } catch (error) {
155
168
  console.error(`[Telemetry] Не удалось отправить heartbeat: ${error.message}`);
156
169
  }
@@ -170,7 +183,6 @@ class BotManager {
170
183
  "User": ["user.say"],
171
184
  "Admin": ["admin.*", "admin.cooldown.bypass", "user.cooldown.bypass", "user.*"]
172
185
  };
173
-
174
186
  console.log(`[Permission Sync] Синхронизация системных прав для бота ID ${botId}...`);
175
187
 
176
188
  for (const perm of systemPermissions) {
@@ -218,7 +230,6 @@ class BotManager {
218
230
 
219
231
  const pids = Array.from(this.bots.values()).map(child => child.pid).filter(Boolean);
220
232
  if (pids.length === 0) return;
221
-
222
233
  try {
223
234
  const stats = await pidusage(pids);
224
235
  const usageData = [];
@@ -237,7 +248,6 @@ class BotManager {
237
248
  }
238
249
  }
239
250
  getIO().emit('bots:usage', usageData);
240
-
241
251
  } catch (error) {
242
252
  }
243
253
  }
@@ -291,18 +301,15 @@ class BotManager {
291
301
 
292
302
  await this._syncSystemPermissions(botConfig.id);
293
303
  await this.loadConfigForBot(botConfig.id);
294
-
295
304
  this.logCache.set(botConfig.id, []);
296
305
  this.emitStatusUpdate(botConfig.id, 'starting', '');
297
306
 
298
307
  const allPluginsForBot = await prisma.installedPlugin.findMany({
299
308
  where: { botId: botConfig.id },
300
309
  });
301
-
302
310
  const enabledPlugins = allPluginsForBot.filter(p => p.isEnabled);
303
311
 
304
312
  const { sortedPlugins, pluginInfo, hasCriticalIssues } = DependencyService.resolveDependencies(enabledPlugins, allPluginsForBot);
305
-
306
313
  if (hasCriticalIssues) {
307
314
  this.appendLog(botConfig.id, '[DependencyManager] Обнаружены критические проблемы с зависимостями:');
308
315
  for (const plugin of Object.values(pluginInfo)) {
@@ -328,20 +335,16 @@ class BotManager {
328
335
  }
329
336
 
330
337
  const fullBotConfig = { ...decryptedConfig, plugins: sortedPlugins };
331
-
332
338
  const botProcessPath = path.resolve(__dirname, 'BotProcess.js');
333
339
  const child = fork(botProcessPath, [], { stdio: ['pipe', 'pipe', 'pipe', 'ipc'] });
334
340
 
335
341
  child.botConfig = botConfig;
336
-
337
342
  child.on('error', (err) => {
338
343
  this.appendLog(botConfig.id, `[PROCESS FATAL] КРИТИЧЕСКАЯ ОШИБКА ПРОЦЕССА: ${err.stack}`);
339
344
  });
340
-
341
345
  child.stderr.on('data', (data) => {
342
346
  this.appendLog(botConfig.id, `[STDERR] ${data.toString()}`);
343
347
  });
344
-
345
348
  child.on('message', async (message) => {
346
349
  if (message.type === 'log') {
347
350
  this.appendLog(botConfig.id, message.content);
@@ -351,9 +354,48 @@ class BotManager {
351
354
  await this.handleCommandValidation(botConfig, message);
352
355
  } else if (message.type === 'register_command') {
353
356
  await this.handleCommandRegistration(botConfig.id, message.commandConfig);
357
+ } else if (message.type === 'request_user_action') {
358
+ const { requestId, payload } = message;
359
+ const { targetUsername, action, data } = payload;
360
+ const botId = botConfig.id;
361
+
362
+ try {
363
+ const targetUser = await RealUserService.getUser(targetUsername, botId);
364
+ let replyPayload = {};
365
+
366
+ switch (action) {
367
+ case 'toggle_blacklist': {
368
+ const isCurrentlyBlacklisted = targetUser.isBlacklisted;
369
+ await targetUser.setBlacklist(!isCurrentlyBlacklisted);
370
+ replyPayload.newStatus = !isCurrentlyBlacklisted;
371
+ break;
372
+ }
373
+
374
+ case 'toggle_group': {
375
+ if (!data.groupName) throw new Error('Название группы не указано.');
376
+ const hasGroup = targetUser.hasGroup(data.groupName);
377
+ if (hasGroup) {
378
+ await targetUser.removeGroup(data.groupName);
379
+ replyPayload.actionTaken = 'removed';
380
+ } else {
381
+ await targetUser.addGroup(data.groupName);
382
+ replyPayload.actionTaken = 'added';
383
+ }
384
+ break;
385
+ }
386
+
387
+ default:
388
+ throw new Error(`Неизвестное действие: ${action}`);
389
+ }
390
+
391
+ child.send({ type: 'user_action_response', requestId, payload: replyPayload });
392
+
393
+ } catch (error) {
394
+ console.error(`[BotManager] Ошибка выполнения действия '${action}' для пользователя '${targetUsername}':`, error);
395
+ child.send({ type: 'user_action_response', requestId, error: error.message });
396
+ }
354
397
  }
355
398
  });
356
-
357
399
  child.on('exit', (code, signal) => {
358
400
  const botId = botConfig.id;
359
401
  this.bots.delete(botId);
@@ -362,7 +404,6 @@ class BotManager {
362
404
  this.emitStatusUpdate(botId, 'stopped', `Процесс завершился с кодом ${code} (сигнал: ${signal || 'none'}).`);
363
405
  this.updateAllResourceUsage();
364
406
  });
365
-
366
407
  this.bots.set(botConfig.id, child);
367
408
  child.send({ type: 'start', config: fullBotConfig });
368
409
 
@@ -433,7 +474,6 @@ class BotManager {
433
474
  }
434
475
 
435
476
  child.send({ type: 'execute_handler', commandName: dbCommand.name, username, args, typeChat });
436
-
437
477
  } catch (error) {
438
478
  console.error(`[BotManager] Command validation error for botId: ${botId}`, {
439
479
  command: commandName,
@@ -477,18 +517,15 @@ class BotManager {
477
517
  allowedChatTypes: JSON.stringify(commandConfig.allowedChatTypes || []),
478
518
  cooldown: commandConfig.cooldown || 0,
479
519
  };
480
-
481
520
  const updateData = {
482
521
  description: commandConfig.description,
483
522
  owner: commandConfig.owner,
484
523
  };
485
-
486
524
  await prisma.command.upsert({
487
525
  where: { botId_name: { botId, name: commandConfig.name } },
488
526
  update: updateData,
489
527
  create: createData,
490
528
  });
491
-
492
529
  this.invalidateConfigCache(botId);
493
530
 
494
531
  } catch (error) {
@@ -1,7 +1,7 @@
1
-
2
1
  const mineflayer = require('mineflayer');
3
2
  const { SocksClient } = require('socks');
4
3
  const EventEmitter = require('events');
4
+ const { v4: uuidv4 } = require('uuid');
5
5
  const { loadCommands } = require('./system/CommandRegistry');
6
6
  const { initializePlugins } = require('./PluginLoader');
7
7
  const MessageQueue = require('./MessageQueue');
@@ -12,6 +12,7 @@ const UserService = require('./ipc/UserService.stub.js');
12
12
  const PermissionManager = require('./ipc/PermissionManager.stub.js');
13
13
 
14
14
  let bot = null;
15
+ const pendingRequests = new Map();
15
16
 
16
17
  function sendLog(content) {
17
18
  if (process.send) {
@@ -29,8 +30,8 @@ function handleIncomingCommand(type, username, message) {
29
30
  const commandName = commandParts.shift().toLowerCase();
30
31
  const restOfMessage = commandParts.join(' ');
31
32
 
32
- const commandInstance = bot.commands.get(commandName) ||
33
- Array.from(bot.commands.values()).find(cmd => cmd.aliases.includes(commandName));
33
+ const commandInstance = bot.commands.get(commandName) ||
34
+ Array.from(bot.commands.values()).find(cmd => cmd.aliases.includes(commandName));
34
35
 
35
36
  if (!commandInstance) return;
36
37
 
@@ -90,7 +91,17 @@ function handleIncomingCommand(type, username, message) {
90
91
  }
91
92
 
92
93
  process.on('message', async (message) => {
93
- if (message.type === 'start') {
94
+ if (message.type === 'user_action_response') {
95
+ if (pendingRequests.has(message.requestId)) {
96
+ const { resolve, reject } = pendingRequests.get(message.requestId);
97
+ if (message.error) {
98
+ reject(new Error(message.error));
99
+ } else {
100
+ resolve(message.payload);
101
+ }
102
+ pendingRequests.delete(message.requestId);
103
+ }
104
+ } else if (message.type === 'start') {
94
105
  const config = message.config;
95
106
  sendLog(`[System] Получена команда на запуск бота ${config.username}...`);
96
107
  try {
@@ -130,18 +141,17 @@ process.on('message', async (message) => {
130
141
  }
131
142
  } else {
132
143
  sendLog(`[System] Прокси не настроен, используется прямое подключение.`);
133
- }
144
+ }
134
145
 
135
146
  bot = mineflayer.createBot(botOptions);
136
147
 
137
148
  bot.events = new EventEmitter();
138
- bot.events.setMaxListeners(30);
149
+ bot.events.setMaxListeners(30);
139
150
  bot.config = config;
140
151
  bot.sendLog = sendLog;
141
152
  bot.messageQueue = new MessageQueue(bot);
142
153
 
143
154
  const installedPluginNames = config.plugins.map(p => p.name);
144
-
145
155
  bot.api = {
146
156
  Command: Command,
147
157
  events: bot.events,
@@ -172,17 +182,43 @@ process.on('message', async (message) => {
172
182
  });
173
183
  }
174
184
  sendLog(`[API] Команда "${commandInstance.name}" от плагина "${commandInstance.owner}" зарегистрирована в процессе.`);
185
+ },
186
+ performUserAction: (username, action, data = {}) => {
187
+ return new Promise((resolve, reject) => {
188
+ const requestId = uuidv4();
189
+ pendingRequests.set(requestId, { resolve, reject });
190
+
191
+ if (process.send) {
192
+ process.send({
193
+ type: 'request_user_action',
194
+ requestId,
195
+ payload: {
196
+ targetUsername: username,
197
+ action,
198
+ data
199
+ }
200
+ });
201
+ } else {
202
+ reject(new Error('IPC channel is not available.'));
203
+ }
204
+
205
+ setTimeout(() => {
206
+ if (pendingRequests.has(requestId)) {
207
+ reject(new Error('Request to main process timed out.'));
208
+ pendingRequests.delete(requestId);
209
+ }
210
+ }, 5000);
211
+ });
175
212
  }
176
213
  };
177
214
 
178
215
  bot.commands = await loadCommands();
179
-
180
216
  if (process.send) {
181
217
  for (const cmd of bot.commands.values()) {
182
218
  process.send({
183
219
  type: 'register_command',
184
220
  commandConfig: {
185
- name: cmd.name,
221
+ name: cmd.name,
186
222
  description: cmd.description,
187
223
  aliases: cmd.aliases,
188
224
  owner: cmd.owner,
@@ -207,7 +243,6 @@ process.on('message', async (message) => {
207
243
  handleIncomingCommand(type, username, message);
208
244
  }
209
245
  });
210
-
211
246
  bot.on('message', (jsonMsg) => {
212
247
  const ansiMessage = jsonMsg.toAnsi();
213
248
  if (ansiMessage.trim()) {
@@ -218,39 +253,32 @@ process.on('message', async (message) => {
218
253
  const rawMessageText = jsonMsg.toString();
219
254
  bot.events.emit('core:raw_message', rawMessageText, jsonMsg);
220
255
  });
221
-
222
256
  bot.on('chat', (username, message) => {
223
257
  if (messageHandledByCustomParser) {
224
258
  return;
225
259
  }
226
260
  handleIncomingCommand('chat', username, message);
227
261
  });
228
-
229
262
  bot.on('login', () => {
230
263
  sendLog('[Event: login] Успешно залогинился!');
231
264
  if (process.send) {
232
265
  process.send({ type: 'status', status: 'running' });
233
266
  }
234
267
  });
235
-
236
268
  bot.on('spawn', () => {
237
269
  sendLog('[Event: spawn] Бот заспавнился в мире. Полностью готов к работе!');
238
270
  });
239
-
240
271
  bot.on('kicked', (reason) => {
241
272
  let reasonText;
242
273
  try { reasonText = JSON.parse(reason).text || reason; } catch (e) { reasonText = reason; }
243
274
  sendLog(`[Event: kicked] Меня кикнули. Причина: ${reasonText}.`);
244
275
  process.exit(0);
245
276
  });
246
-
247
277
  bot.on('error', (err) => sendLog(`[Event: error] Произошла ошибка: ${err.stack || err.message}`));
248
-
249
278
  bot.on('end', (reason) => {
250
279
  sendLog(`[Event: end] Отключен от сервера. Причина: ${reason}`);
251
280
  process.exit(0);
252
281
  });
253
-
254
282
  } catch (err) {
255
283
  sendLog(`[CRITICAL] Критическая ошибка при создании бота: ${err.stack}`);
256
284
  process.exit(1);
@@ -1,24 +1,30 @@
1
-
2
1
  const crypto = require('crypto');
3
2
  const config = require('../../config');
4
-
5
3
  const ALGORITHM = 'aes-256-gcm';
6
4
  const IV_LENGTH = 16;
7
- const AUTH_TAG_LENGTH = 16;
8
- const KEY = Buffer.from(config.security.encryptionKey, 'hex');
5
+
6
+
7
+ function getEncryptionKey() {
8
+ const key = config.security.encryptionKey;
9
+ if (!key || key.length !== 64) {
10
+ throw new Error('[Crypto] Ключ шифрования не настроен или имеет неверную длину в config.json');
11
+ }
12
+ return Buffer.from(key, 'hex');
13
+ }
14
+
9
15
 
10
16
  function encrypt(text) {
11
17
  if (!text) return null;
12
18
  try {
19
+ const key = getEncryptionKey();
13
20
  const iv = crypto.randomBytes(IV_LENGTH);
14
- const cipher = crypto.createCipheriv(ALGORITHM, KEY, iv);
21
+ const cipher = crypto.createCipheriv(ALGORITHM, key, iv);
15
22
  const encrypted = Buffer.concat([cipher.update(text, 'utf8'), cipher.final()]);
16
23
  const authTag = cipher.getAuthTag();
17
24
 
18
25
  return `${iv.toString('hex')}:${authTag.toString('hex')}:${encrypted.toString('hex')}`;
19
26
  } catch (error) {
20
- console.error('[Crypto] Ошибка шифрования:', error);
21
- return null;
27
+ throw new Error(`[Crypto] Ошибка шифрования: ${error.message}`);
22
28
  }
23
29
  }
24
30
 
@@ -27,22 +33,21 @@ function decrypt(hash) {
27
33
  try {
28
34
  const parts = hash.split(':');
29
35
  if (parts.length !== 3) {
30
- console.error('[Crypto] Неверный формат зашифрованных данных. Возвращаем как есть.');
31
- return hash;
36
+ return hash;
32
37
  }
33
38
 
39
+ const key = getEncryptionKey();
34
40
  const iv = Buffer.from(parts[0], 'hex');
35
41
  const authTag = Buffer.from(parts[1], 'hex');
36
42
  const encrypted = Buffer.from(parts[2], 'hex');
37
43
 
38
- const decipher = crypto.createDecipheriv(ALGORITHM, KEY, iv);
44
+ const decipher = crypto.createDecipheriv(ALGORITHM, key, iv);
39
45
  decipher.setAuthTag(authTag);
40
46
 
41
47
  const decrypted = Buffer.concat([decipher.update(encrypted), decipher.final()]);
42
48
  return decrypted.toString('utf8');
43
49
  } catch (error) {
44
- console.error('[Crypto] Ошибка дешифрования. Возможно, ключ был изменен или данные повреждены.', error);
45
- return null;
50
+ throw new Error(`[Crypto] Ошибка дешифрования. Возможно, ключ был изменен или данные повреждены. ${error.message}`);
46
51
  }
47
52
  }
48
53
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blockmine",
3
- "version": "1.4.3",
3
+ "version": "1.4.6",
4
4
  "description": "Мощная панель управления ботами для Майнкрафта.",
5
5
  "author": "merka",
6
6
  "license": "MIT",