Живой тест показал: presigned-ссылка формировалась против внутреннего хоста (http://minio:9000/...) — снаружи docker-сети недоступна, для ботов бесполезна. - presigned-токены вынесены в server/utils/presigned-tokens.ts (общие для index.ts и mcp.ts); - MCP get_task_file возвращает /api/files/<key>?presigned=<token> — работает через https://iistwin.ru без авторизации ~5 минут, в S3 и локальном режимах.
44 lines
1.7 KiB
TypeScript
44 lines
1.7 KiB
TypeScript
import crypto from 'crypto';
|
|
|
|
// ── Presigned-токены для временного доступа к файлам без авторизации ─────────
|
|
// Вынесено из index.ts: используется и файловыми маршрутами (/api/files/:key/presigned),
|
|
// и MCP get_task_file — последний отдаёт внешний прокси-URL приложения
|
|
// (/api/files/<key>?presigned=<token>) вместо внутреннего хоста MinIO
|
|
// (http://minio:9000/...), который снаружи docker-сети недоступен.
|
|
// Токены in-memory: при multi-instance понадобится Redis (как upload-тикеты).
|
|
|
|
interface PresignedToken {
|
|
fileKey: string;
|
|
organizationId: number;
|
|
expiresAt: number;
|
|
}
|
|
|
|
const presignedTokens = new Map<string, PresignedToken>();
|
|
export const PRESIGNED_TTL_MS = 5 * 60 * 1000; // 5 minutes
|
|
|
|
export function generatePresignedToken(fileKey: string, organizationId: number): string {
|
|
const token = crypto.randomBytes(32).toString('hex');
|
|
presignedTokens.set(token, { fileKey, organizationId, expiresAt: Date.now() + PRESIGNED_TTL_MS });
|
|
return token;
|
|
}
|
|
|
|
export function validatePresignedToken(token: string, fileKey: string): number | null {
|
|
const entry = presignedTokens.get(token);
|
|
if (!entry) return null;
|
|
if (entry.fileKey !== fileKey) return null;
|
|
if (entry.expiresAt <= Date.now()) {
|
|
presignedTokens.delete(token);
|
|
return null;
|
|
}
|
|
return entry.organizationId;
|
|
}
|
|
|
|
export function sweepPresignedTokens(): void {
|
|
const now = Date.now();
|
|
for (const [token, entry] of presignedTokens.entries()) {
|
|
if (entry.expiresAt <= now) {
|
|
presignedTokens.delete(token);
|
|
}
|
|
}
|
|
}
|