blockmine 1.22.0 → 1.23.1

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 (108) hide show
  1. package/.claude/agents/code-architect.md +34 -0
  2. package/.claude/agents/code-explorer.md +51 -0
  3. package/.claude/agents/code-reviewer.md +46 -0
  4. package/.claude/commands/feature-dev.md +125 -0
  5. package/.claude/settings.json +5 -1
  6. package/.claude/settings.local.json +12 -1
  7. package/.claude/skills/frontend-design/SKILL.md +42 -0
  8. package/CHANGELOG.md +32 -1
  9. package/README.md +302 -152
  10. package/backend/package-lock.json +681 -9
  11. package/backend/package.json +8 -0
  12. package/backend/prisma/migrations/20251116111851_add_execution_trace/migration.sql +22 -0
  13. package/backend/prisma/migrations/20251120154914_add_panel_api_keys/migration.sql +21 -0
  14. package/backend/prisma/migrations/20251121110241_add_proxy_table/migration.sql +45 -0
  15. package/backend/prisma/schema.prisma +70 -1
  16. package/backend/src/__tests__/services/BotLifecycleService.test.js +9 -4
  17. package/backend/src/ai/plugin-assistant-system-prompt.md +788 -0
  18. package/backend/src/api/middleware/auth.js +27 -0
  19. package/backend/src/api/middleware/botAccess.js +7 -3
  20. package/backend/src/api/middleware/panelApiAuth.js +135 -0
  21. package/backend/src/api/routes/aiAssistant.js +995 -0
  22. package/backend/src/api/routes/auth.js +90 -54
  23. package/backend/src/api/routes/botCommands.js +107 -0
  24. package/backend/src/api/routes/botGroups.js +165 -0
  25. package/backend/src/api/routes/botHistory.js +108 -0
  26. package/backend/src/api/routes/botPermissions.js +99 -0
  27. package/backend/src/api/routes/botStatus.js +36 -0
  28. package/backend/src/api/routes/botUsers.js +162 -0
  29. package/backend/src/api/routes/bots.js +108 -59
  30. package/backend/src/api/routes/eventGraphs.js +4 -1
  31. package/backend/src/api/routes/logs.js +13 -3
  32. package/backend/src/api/routes/panel.js +3 -3
  33. package/backend/src/api/routes/panelApiKeys.js +179 -0
  34. package/backend/src/api/routes/pluginIde.js +1715 -135
  35. package/backend/src/api/routes/plugins.js +170 -13
  36. package/backend/src/api/routes/proxies.js +130 -0
  37. package/backend/src/api/routes/search.js +4 -0
  38. package/backend/src/api/routes/servers.js +20 -3
  39. package/backend/src/api/routes/settings.js +5 -0
  40. package/backend/src/api/routes/system.js +3 -3
  41. package/backend/src/api/routes/traces.js +131 -0
  42. package/backend/src/config/debug.config.js +36 -0
  43. package/backend/src/core/BotHistoryStore.js +180 -0
  44. package/backend/src/core/BotManager.js +14 -4
  45. package/backend/src/core/BotProcess.js +1517 -1092
  46. package/backend/src/core/EventGraphManager.js +194 -280
  47. package/backend/src/core/GraphExecutionEngine.js +1004 -321
  48. package/backend/src/core/MessageQueue.js +12 -6
  49. package/backend/src/core/PluginLoader.js +99 -5
  50. package/backend/src/core/PluginManager.js +74 -13
  51. package/backend/src/core/TaskScheduler.js +1 -1
  52. package/backend/src/core/commands/whois.js +1 -1
  53. package/backend/src/core/node-registries/actions.js +72 -2
  54. package/backend/src/core/node-registries/arrays.js +18 -0
  55. package/backend/src/core/node-registries/data.js +1 -1
  56. package/backend/src/core/node-registries/events.js +14 -0
  57. package/backend/src/core/node-registries/logic.js +17 -0
  58. package/backend/src/core/node-registries/strings.js +34 -0
  59. package/backend/src/core/node-registries/type.js +25 -0
  60. package/backend/src/core/nodes/actions/bot_look_at.js +1 -1
  61. package/backend/src/core/nodes/actions/create_command.js +189 -0
  62. package/backend/src/core/nodes/actions/delete_command.js +92 -0
  63. package/backend/src/core/nodes/actions/http_request.js +23 -4
  64. package/backend/src/core/nodes/actions/send_message.js +2 -12
  65. package/backend/src/core/nodes/actions/update_command.js +133 -0
  66. package/backend/src/core/nodes/arrays/join.js +28 -0
  67. package/backend/src/core/nodes/data/cast.js +2 -1
  68. package/backend/src/core/nodes/data/string_literal.js +2 -13
  69. package/backend/src/core/nodes/logic/not.js +22 -0
  70. package/backend/src/core/nodes/strings/starts_with.js +1 -1
  71. package/backend/src/core/nodes/strings/to_lower.js +22 -0
  72. package/backend/src/core/nodes/strings/to_upper.js +22 -0
  73. package/backend/src/core/nodes/type/to_string.js +32 -0
  74. package/backend/src/core/services/BotLifecycleService.js +835 -596
  75. package/backend/src/core/services/CommandExecutionService.js +430 -351
  76. package/backend/src/core/services/DebugSessionManager.js +347 -0
  77. package/backend/src/core/services/GraphCollaborationManager.js +501 -0
  78. package/backend/src/core/services/MinecraftBotManager.js +259 -0
  79. package/backend/src/core/services/MinecraftViewerService.js +216 -0
  80. package/backend/src/core/services/TraceCollectorService.js +545 -0
  81. package/backend/src/core/system/RuntimeCommandRegistry.js +116 -0
  82. package/backend/src/core/system/Transport.js +0 -4
  83. package/backend/src/core/validation/nodeSchemas.js +6 -6
  84. package/backend/src/real-time/botApi/handlers/graphHandlers.js +2 -2
  85. package/backend/src/real-time/botApi/handlers/graphWebSocketHandlers.js +1 -1
  86. package/backend/src/real-time/botApi/utils.js +11 -0
  87. package/backend/src/real-time/panelNamespace.js +387 -0
  88. package/backend/src/real-time/presence.js +7 -2
  89. package/backend/src/real-time/socketHandler.js +395 -4
  90. package/backend/src/server.js +18 -0
  91. package/frontend/dist/assets/index-DqzDkFsP.js +11210 -0
  92. package/frontend/dist/assets/index-t6K1u4OV.css +32 -0
  93. package/frontend/dist/index.html +2 -2
  94. package/frontend/package-lock.json +9437 -0
  95. package/frontend/package.json +8 -0
  96. package/package.json +2 -2
  97. package/screen/console.png +0 -0
  98. package/screen/dashboard.png +0 -0
  99. package/screen/graph_collabe.png +0 -0
  100. package/screen/graph_live_debug.png +0 -0
  101. package/screen/management_command.png +0 -0
  102. package/screen/node_debug_trace.png +0 -0
  103. package/screen/plugin_/320/276/320/261/320/267/320/276/321/200.png +0 -0
  104. package/screen/websocket.png +0 -0
  105. 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
  106. 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
  107. package/frontend/dist/assets/index-CfTo92bP.css +0 -1
  108. 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) return next();
25
+ if (user.allBots !== false) {
26
+ return next();
27
+ }
26
28
  const allowed = user.botAccess.some((a) => a.botId === botId);
27
- if (!allowed) return res.status(403).json({ error: 'Доступ к боту запрещен' });
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
+ };