Атрибуция от бота в MCP/REST + REST API по ключу (этап 2)
- MCP: getActor (владелец ключа + бот), аудит changedByName=бот/label ключа, botId, metadata.source='mcp'; аудит для update_task/update_task_status - sendTaskMessage: botId (messageType 'bot'), починен путь isBotToken без req.user - authenticateTokenOrApiKey: JWT или X-Api-Key с белым списком endpoint'ов (/api/upload, messages, field-values, create task), проверки скоупов, аудит source='api' - Лимиты файлов через env: UPLOAD_IMAGE_MAX_MB=25, UPLOAD_DOC_MAX_MB=100, UPLOAD_MAX_MB=100 - MCP upload-инструменты: параметр fileUrl для привязки уже загруженного файла; новый инструмент get_api_guide
This commit is contained in:
@@ -1,12 +1,13 @@
|
||||
import { Router } from "express";
|
||||
import { z } from 'zod';
|
||||
import { storage } from "../storage";
|
||||
import { authenticateToken, tryBotServiceToken, type AuthenticatedRequest } from "../middleware/auth.middleware";
|
||||
import { authenticateToken, authenticateTokenOrApiKey, tryBotServiceToken, type AuthenticatedRequest } from "../middleware/auth.middleware";
|
||||
import { tenantIsolation } from "../middleware/tenant.middleware";
|
||||
import { validateRequest } from "../middleware/validation.middleware";
|
||||
import { createTaskMessageSchema } from "@shared/schema";
|
||||
import { eventBus } from "./shared";
|
||||
import { sendTaskMessage, SendTaskMessageError } from "../services/task-message.service";
|
||||
import { isFormAllowedByScopes } from "../utils/api-key";
|
||||
|
||||
export function registerChatMessageRoutes(router: Router): void {
|
||||
// Get task messages
|
||||
@@ -40,10 +41,10 @@ export function registerChatMessageRoutes(router: Router): void {
|
||||
}
|
||||
);
|
||||
|
||||
// Create task message
|
||||
// Create task message (JWT пользователя или API-ключ организации)
|
||||
router.post('/api/tasks/:id/messages',
|
||||
tryBotServiceToken,
|
||||
authenticateToken,
|
||||
authenticateTokenOrApiKey,
|
||||
tenantIsolation,
|
||||
validateRequest(createTaskMessageSchema.omit({ taskId: true })),
|
||||
async (req: AuthenticatedRequest, res) => {
|
||||
@@ -65,9 +66,9 @@ export function registerChatMessageRoutes(router: Router): void {
|
||||
|
||||
{
|
||||
const taskRolesForGuard = await storage.getTaskRoles(taskId, req.organizationId!);
|
||||
if (taskRolesForGuard.length > 0) {
|
||||
if (req.user && taskRolesForGuard.length > 0) {
|
||||
const hasAccess = await storage.canUserAccessTask(
|
||||
taskId, req.user!.id, req.organizationId!, req.user!.appRole
|
||||
taskId, req.user.id, req.organizationId!, req.user.appRole
|
||||
);
|
||||
if (!hasAccess) {
|
||||
return res.status(403).json({ success: false, error: 'Нет доступа к этой задаче' });
|
||||
@@ -75,12 +76,38 @@ export function registerChatMessageRoutes(router: Router): void {
|
||||
}
|
||||
}
|
||||
|
||||
// Проверки для авторизации по API-ключу (JWT-путь не меняется)
|
||||
if (req.apiKey) {
|
||||
if (req.apiKey.scopes.mode === 'read') {
|
||||
return res.status(403).json({ success: false, error: 'API-ключ в режиме read не может отправлять сообщения' });
|
||||
}
|
||||
if (!isFormAllowedByScopes(req.apiKey.scopes, task.formId)) {
|
||||
return res.status(403).json({ success: false, error: 'Доступ к форме этой задачи запрещён правами API-ключа' });
|
||||
}
|
||||
}
|
||||
|
||||
// Автор сообщения: пользователь (JWT); по ключу бота — сам бот;
|
||||
// по ключу без бота — владелец ключа
|
||||
let messageUser = req.user ?? null;
|
||||
let messageBotId: number | null = null;
|
||||
if (!messageUser && req.apiKey) {
|
||||
if (req.apiKey.botId) {
|
||||
messageBotId = req.apiKey.botId;
|
||||
} else {
|
||||
messageUser = await storage.getUser(req.apiKey.createdBy);
|
||||
}
|
||||
}
|
||||
if (!messageUser && !messageBotId) {
|
||||
return res.status(401).json({ success: false, error: 'Не удалось определить автора сообщения' });
|
||||
}
|
||||
|
||||
// Основная логика (сообщение + side-эффекты) вынесена в сервис —
|
||||
// переиспользуется также MCP-сервером (инструмент send_task_message).
|
||||
try {
|
||||
const createdMessage = await sendTaskMessage({
|
||||
task,
|
||||
user: req.user!,
|
||||
user: messageUser ?? undefined,
|
||||
botId: messageBotId,
|
||||
organizationId: req.organizationId!,
|
||||
message: req.body.message || '',
|
||||
messageType: req.body.messageType,
|
||||
|
||||
Reference in New Issue
Block a user