blockmine 1.22.0 → 1.23.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/.claude/settings.json +5 -1
- package/.claude/settings.local.json +10 -1
- package/CHANGELOG.md +27 -3
- package/CLAUDE.md +284 -0
- package/README.md +302 -152
- package/backend/package-lock.json +681 -9
- package/backend/package.json +8 -0
- package/backend/prisma/migrations/20251116111851_add_execution_trace/migration.sql +22 -0
- package/backend/prisma/migrations/20251120154914_add_panel_api_keys/migration.sql +21 -0
- package/backend/prisma/migrations/20251121110241_add_proxy_table/migration.sql +45 -0
- package/backend/prisma/migrations/migration_lock.toml +2 -2
- package/backend/prisma/schema.prisma +70 -1
- package/backend/src/__tests__/services/BotLifecycleService.test.js +9 -4
- package/backend/src/ai/plugin-assistant-system-prompt.md +788 -0
- package/backend/src/api/middleware/auth.js +27 -0
- package/backend/src/api/middleware/botAccess.js +7 -3
- package/backend/src/api/middleware/panelApiAuth.js +135 -0
- package/backend/src/api/routes/aiAssistant.js +995 -0
- package/backend/src/api/routes/auth.js +669 -633
- package/backend/src/api/routes/botCommands.js +107 -0
- package/backend/src/api/routes/botGroups.js +165 -0
- package/backend/src/api/routes/botHistory.js +108 -0
- package/backend/src/api/routes/botPermissions.js +99 -0
- package/backend/src/api/routes/botStatus.js +36 -0
- package/backend/src/api/routes/botUsers.js +162 -0
- package/backend/src/api/routes/bots.js +2451 -2402
- package/backend/src/api/routes/eventGraphs.js +4 -1
- package/backend/src/api/routes/logs.js +13 -3
- package/backend/src/api/routes/panel.js +66 -66
- package/backend/src/api/routes/panelApiKeys.js +179 -0
- package/backend/src/api/routes/pluginIde.js +1715 -135
- package/backend/src/api/routes/plugins.js +376 -219
- package/backend/src/api/routes/proxies.js +130 -0
- package/backend/src/api/routes/search.js +4 -0
- package/backend/src/api/routes/servers.js +20 -3
- package/backend/src/api/routes/settings.js +5 -0
- package/backend/src/api/routes/system.js +174 -174
- package/backend/src/api/routes/traces.js +131 -0
- package/backend/src/config/debug.config.js +36 -0
- package/backend/src/core/BotHistoryStore.js +180 -0
- package/backend/src/core/BotManager.js +14 -4
- package/backend/src/core/BotProcess.js +1517 -1092
- package/backend/src/core/EventGraphManager.js +37 -123
- package/backend/src/core/GraphExecutionEngine.js +977 -321
- package/backend/src/core/MessageQueue.js +12 -6
- package/backend/src/core/PluginLoader.js +99 -5
- package/backend/src/core/PluginManager.js +74 -13
- package/backend/src/core/TaskScheduler.js +1 -1
- package/backend/src/core/commands/whois.js +1 -1
- package/backend/src/core/node-registries/actions.js +70 -0
- package/backend/src/core/node-registries/arrays.js +18 -0
- package/backend/src/core/node-registries/data.js +1 -1
- package/backend/src/core/node-registries/events.js +14 -0
- package/backend/src/core/node-registries/logic.js +17 -0
- package/backend/src/core/node-registries/strings.js +34 -0
- package/backend/src/core/node-registries/type.js +25 -0
- package/backend/src/core/nodes/actions/bot_look_at.js +1 -1
- package/backend/src/core/nodes/actions/create_command.js +189 -0
- package/backend/src/core/nodes/actions/delete_command.js +92 -0
- package/backend/src/core/nodes/actions/update_command.js +133 -0
- package/backend/src/core/nodes/arrays/join.js +28 -0
- package/backend/src/core/nodes/data/cast.js +2 -1
- package/backend/src/core/nodes/logic/not.js +22 -0
- package/backend/src/core/nodes/strings/starts_with.js +1 -1
- package/backend/src/core/nodes/strings/to_lower.js +22 -0
- package/backend/src/core/nodes/strings/to_upper.js +22 -0
- package/backend/src/core/nodes/type/to_string.js +32 -0
- package/backend/src/core/services/BotLifecycleService.js +255 -16
- package/backend/src/core/services/CommandExecutionService.js +430 -351
- package/backend/src/core/services/DebugSessionManager.js +347 -0
- package/backend/src/core/services/GraphCollaborationManager.js +501 -0
- package/backend/src/core/services/MinecraftBotManager.js +259 -0
- package/backend/src/core/services/MinecraftViewerService.js +216 -0
- package/backend/src/core/services/TraceCollectorService.js +545 -0
- package/backend/src/core/system/RuntimeCommandRegistry.js +116 -0
- package/backend/src/core/system/Transport.js +0 -4
- package/backend/src/core/validation/nodeSchemas.js +6 -6
- package/backend/src/real-time/botApi/handlers/graphHandlers.js +2 -2
- package/backend/src/real-time/botApi/handlers/graphWebSocketHandlers.js +1 -1
- package/backend/src/real-time/botApi/utils.js +11 -0
- package/backend/src/real-time/panelNamespace.js +387 -0
- package/backend/src/real-time/presence.js +7 -2
- package/backend/src/real-time/socketHandler.js +395 -4
- package/backend/src/server.js +18 -0
- package/frontend/dist/assets/index-B1serztM.js +11210 -0
- package/frontend/dist/assets/index-t6K1u4OV.css +32 -0
- package/frontend/dist/index.html +2 -2
- package/frontend/package-lock.json +9437 -0
- package/frontend/package.json +8 -0
- package/package.json +2 -2
- package/screen/console.png +0 -0
- package/screen/dashboard.png +0 -0
- package/screen/graph_collabe.png +0 -0
- package/screen/graph_live_debug.png +0 -0
- package/screen/management_command.png +0 -0
- package/screen/node_debug_trace.png +0 -0
- package/screen/plugin_/320/276/320/261/320/267/320/276/321/200.png +0 -0
- package/screen/websocket.png +0 -0
- package/screen//320/275/320/260/321/201/321/202/321/200/320/276/320/271/320/272/320/270_/320/276/321/202/320/264/320/265/320/273/321/214/320/275/321/213/321/205_/320/272/320/276/320/274/320/260/320/275/320/264_/320/272/320/260/320/266/320/264/321/203_/320/272/320/276/320/274/320/260/320/275/320/273/320/264/321/203_/320/274/320/276/320/266/320/275/320/276_/320/275/320/260/321/201/321/202/321/200/320/260/320/270/320/262/320/260/321/202/321/214.png +0 -0
- package/screen//320/277/320/273/320/260/320/275/320/270/321/200/320/276/320/262/321/211/320/270/320/272_/320/274/320/276/320/266/320/275/320/276_/320/267/320/260/320/264/320/260/320/262/320/260/321/202/321/214_/320/264/320/265/320/271/321/201/321/202/320/262/320/270/321/217_/320/277/320/276_/320/262/321/200/320/265/320/274/320/265/320/275/320/270.png +0 -0
- package/frontend/dist/assets/index-CfTo92bP.css +0 -1
- package/frontend/dist/assets/index-CiFD5X9Z.js +0 -8344
|
@@ -1,11 +1,37 @@
|
|
|
1
1
|
const jwt = require('jsonwebtoken');
|
|
2
2
|
const config = require('../../config');
|
|
3
|
+
const { authenticatePanelApiKey } = require('./panelApiAuth');
|
|
3
4
|
|
|
4
5
|
const JWT_SECRET = config.security.jwtSecret;
|
|
5
6
|
|
|
6
7
|
const tokenCache = new Map();
|
|
7
8
|
const CACHE_TTL = 5 * 60 * 1000;
|
|
8
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Универсальный middleware аутентификации
|
|
12
|
+
* Поддерживает Panel API Keys и JWT токены
|
|
13
|
+
*/
|
|
14
|
+
function authenticateUniversal(req, res, next) {
|
|
15
|
+
const authHeader = req.header('Authorization');
|
|
16
|
+
if (!authHeader) {
|
|
17
|
+
return res.status(401).json({ error: 'Нет токена, доступ запрещен' });
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const tokenParts = authHeader.split(' ');
|
|
21
|
+
if (tokenParts.length !== 2 || tokenParts[0] !== 'Bearer') {
|
|
22
|
+
return res.status(401).json({ error: 'Неверный формат токена' });
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const token = tokenParts[1];
|
|
26
|
+
|
|
27
|
+
// Если токен начинается с pk_ - это Panel API Key
|
|
28
|
+
if (token.startsWith('pk_')) {
|
|
29
|
+
return authenticatePanelApiKey(req, res, next);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Иначе это JWT токен
|
|
33
|
+
return authenticate(req, res, next);
|
|
34
|
+
}
|
|
9
35
|
|
|
10
36
|
function authenticate(req, res, next) {
|
|
11
37
|
const authHeader = req.header('Authorization');
|
|
@@ -63,5 +89,6 @@ function authorize(requiredPermission) {
|
|
|
63
89
|
|
|
64
90
|
module.exports = {
|
|
65
91
|
authenticate,
|
|
92
|
+
authenticateUniversal,
|
|
66
93
|
authorize,
|
|
67
94
|
};
|
|
@@ -22,9 +22,13 @@ async function checkBotAccess(req, res, next) {
|
|
|
22
22
|
if (!user) return res.status(401).json({ error: 'Пользователь не найден' });
|
|
23
23
|
|
|
24
24
|
// Если поле allBots отсутствует (старый клиент) — считаем true
|
|
25
|
-
if (user.allBots !== false)
|
|
25
|
+
if (user.allBots !== false) {
|
|
26
|
+
return next();
|
|
27
|
+
}
|
|
26
28
|
const allowed = user.botAccess.some((a) => a.botId === botId);
|
|
27
|
-
if (!allowed)
|
|
29
|
+
if (!allowed) {
|
|
30
|
+
return res.status(403).json({ error: 'Доступ к боту запрещен' });
|
|
31
|
+
}
|
|
28
32
|
return next();
|
|
29
33
|
} catch (e) {
|
|
30
34
|
console.error('[checkBotAccess] error', e);
|
|
@@ -32,4 +36,4 @@ async function checkBotAccess(req, res, next) {
|
|
|
32
36
|
}
|
|
33
37
|
}
|
|
34
38
|
|
|
35
|
-
module.exports = { checkBotAccess };
|
|
39
|
+
module.exports = { checkBotAccess };
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
const bcrypt = require('bcryptjs');
|
|
2
|
+
const prisma = require('../../lib/prisma');
|
|
3
|
+
|
|
4
|
+
const keyCache = new Map();
|
|
5
|
+
const CACHE_TTL = 5 * 60 * 1000;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Аутентификация запросов Panel API с использованием API ключей
|
|
9
|
+
*/
|
|
10
|
+
async function authenticatePanelApiKey(req, res, next) {
|
|
11
|
+
const authHeader = req.header('Authorization');
|
|
12
|
+
if (!authHeader) {
|
|
13
|
+
return res.status(401).json({ error: 'API ключ не предоставлен' });
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const keyParts = authHeader.split(' ');
|
|
17
|
+
if (keyParts.length !== 2 || keyParts[0] !== 'Bearer') {
|
|
18
|
+
return res.status(401).json({ error: 'Неверный формат API ключа' });
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const apiKey = keyParts[1];
|
|
22
|
+
|
|
23
|
+
if (keyCache.has(apiKey)) {
|
|
24
|
+
const cached = keyCache.get(apiKey);
|
|
25
|
+
if (Date.now() < cached.expires) {
|
|
26
|
+
req.user = cached.user;
|
|
27
|
+
req.apiKey = cached.keyData;
|
|
28
|
+
return next();
|
|
29
|
+
} else {
|
|
30
|
+
keyCache.delete(apiKey);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
const allKeys = await prisma.panelApiKey.findMany({
|
|
36
|
+
where: {
|
|
37
|
+
isActive: true,
|
|
38
|
+
OR: [
|
|
39
|
+
{ expiresAt: null },
|
|
40
|
+
{ expiresAt: { gt: new Date() } }
|
|
41
|
+
]
|
|
42
|
+
},
|
|
43
|
+
include: {
|
|
44
|
+
user: {
|
|
45
|
+
include: {
|
|
46
|
+
role: true
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
let matchedKey = null;
|
|
53
|
+
for (const keyRecord of allKeys) {
|
|
54
|
+
if (await bcrypt.compare(apiKey, keyRecord.keyHash)) {
|
|
55
|
+
matchedKey = keyRecord;
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (!matchedKey) {
|
|
61
|
+
return res.status(401).json({ error: 'Неверный API ключ' });
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
await prisma.panelApiKey.update({
|
|
65
|
+
where: { id: matchedKey.id },
|
|
66
|
+
data: { lastUsedAt: new Date() }
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
let permissions;
|
|
70
|
+
try {
|
|
71
|
+
if (matchedKey.customScopes) {
|
|
72
|
+
permissions = JSON.parse(matchedKey.customScopes);
|
|
73
|
+
} else {
|
|
74
|
+
permissions = JSON.parse(matchedKey.user.role.permissions);
|
|
75
|
+
}
|
|
76
|
+
} catch (parseError) {
|
|
77
|
+
console.error('Ошибка парсинга прав доступа:', parseError);
|
|
78
|
+
return res.status(500).json({ error: 'Ошибка обработки прав доступа' });
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
console.log(`[Panel API Key] User: ${matchedKey.user.username}, Key: ${matchedKey.name}, Permissions:`, permissions);
|
|
82
|
+
|
|
83
|
+
const user = {
|
|
84
|
+
id: matchedKey.user.id,
|
|
85
|
+
userId: matchedKey.user.id, // для совместимости с JWT
|
|
86
|
+
uuid: matchedKey.user.uuid,
|
|
87
|
+
username: matchedKey.user.username,
|
|
88
|
+
roleId: matchedKey.user.roleId,
|
|
89
|
+
roleName: matchedKey.user.role.name,
|
|
90
|
+
permissions,
|
|
91
|
+
allBots: matchedKey.user.allBots
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
req.user = user;
|
|
95
|
+
req.apiKey = {
|
|
96
|
+
id: matchedKey.id,
|
|
97
|
+
name: matchedKey.name,
|
|
98
|
+
prefix: matchedKey.prefix
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
keyCache.set(apiKey, {
|
|
102
|
+
user,
|
|
103
|
+
keyData: req.apiKey,
|
|
104
|
+
expires: Date.now() + CACHE_TTL
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
next();
|
|
108
|
+
} catch (err) {
|
|
109
|
+
console.error('Ошибка аутентификации Panel API ключа:', err);
|
|
110
|
+
res.status(500).json({ error: 'Ошибка аутентификации' });
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Авторизация запросов Panel API на основе прав доступа
|
|
116
|
+
*/
|
|
117
|
+
function authorizePanelApi(requiredPermission) {
|
|
118
|
+
return (req, res, next) => {
|
|
119
|
+
if (!req.user || !Array.isArray(req.user.permissions)) {
|
|
120
|
+
return res.status(403).json({ error: 'Доступ запрещён: пользователь не аутентифицирован или неверный формат прав' });
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const userPermissions = req.user.permissions;
|
|
124
|
+
if (userPermissions.includes('*') || userPermissions.includes(requiredPermission)) {
|
|
125
|
+
next();
|
|
126
|
+
} else {
|
|
127
|
+
res.status(403).json({ error: 'Доступ запрещён: недостаточно прав' });
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
module.exports = {
|
|
133
|
+
authenticatePanelApiKey,
|
|
134
|
+
authorizePanelApi
|
|
135
|
+
};
|