fix(files): бот может скачивать файлы — API-ключ на /api/files и /uploads + трекинг абсолютных URL
Проблема: прямое скачивание /api/files/<key> с X-Api-Key давало 403 (файловые эндпоинты принимали только JWT), а get_task_file отвечал «не отслеживается» — 77 файлов со старыми АБСОЛЮТНЫМИ URL (https://iistwin.ru/api/files/...) не попадали в file_uploads: startup-backfill понимал только относительные ссылки. - tryPresignedOrAuth: ветка X-Api-Key — resolve ключа, req.apiKey/organizationId, tenant-контекст; владение проверяет canAccessFile, скоупы форм — новый checkApiKeyFileScope (файл привязан к задаче → форма должна быть разрешена ключом); - /api/files/:key/presigned теперь тоже через tryPresignedOrAuth (боты могут выпускать presigned-ссылки); - server/utils/file-tracking.ts: trackFileOnDemand — догрузка по требованию из task_field_values/task_messages по ссылке любого вида; используется в canAccessFile и MCP get_task_file; - startup-backfill: паттерны покрывают абсолютные URL (substring FROM regex).
This commit is contained in:
@@ -39,6 +39,7 @@ import type { Request, Response } from "express";
|
||||
import type { Task, ApiKeyScopes, OrganizationApiKey, SafeUser, Bot } from "@shared/schema";
|
||||
import { normalizeApiKeyScopes, isFormAllowedByScopes } from "./utils/api-key";
|
||||
import { createUploadTicket } from "./utils/upload-tickets";
|
||||
import { trackFileOnDemand } from "./utils/file-tracking";
|
||||
import beautify from "js-beautify";
|
||||
import {
|
||||
semanticSearch,
|
||||
@@ -4252,12 +4253,24 @@ To block task creation from task.before_create, set: ctx.result = { allow: false
|
||||
if (!task) return mcpError(`Задача ${taskId} не найдена`);
|
||||
if (!isFormAllowed(task.formId)) return formDenied(task.formId);
|
||||
|
||||
// Файл должен отслеживаться в file_uploads и принадлежать организации (как canAccessFile в index.ts)
|
||||
const [upload] = await db
|
||||
// Файл должен отслеживаться в file_uploads и принадлежать организации (как canAccessFile в index.ts).
|
||||
// Если не отслеживается — догружаем по требованию (старые абсолютные URL и прочие
|
||||
// неохваченные startup-backfill случаи, см. utils/file-tracking.ts).
|
||||
let [upload] = await db
|
||||
.select()
|
||||
.from(fileUploads)
|
||||
.where(eq(fileUploads.fileKey, fileKey))
|
||||
.limit(1);
|
||||
if (!upload) {
|
||||
const tracked = await trackFileOnDemand(fileKey);
|
||||
if (tracked) {
|
||||
[upload] = await db
|
||||
.select()
|
||||
.from(fileUploads)
|
||||
.where(eq(fileUploads.fileKey, fileKey))
|
||||
.limit(1);
|
||||
}
|
||||
}
|
||||
if (!upload) return mcpError("Файл не найден или не отслеживается");
|
||||
if (upload.organizationId !== organizationId) {
|
||||
return mcpError("Файл принадлежит другой организации");
|
||||
|
||||
Reference in New Issue
Block a user