mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-28 07:51:02 +00:00
fix issue
This commit is contained in:
@@ -6,22 +6,24 @@ import {
|
||||
Query,
|
||||
Res,
|
||||
} from "@nestjs/common";
|
||||
import { ApiOperation, ApiQuery, ApiTags } from "@nestjs/swagger";
|
||||
import { Public } from "@edr/api-common";
|
||||
import { ApiBearerAuth, ApiOperation, ApiQuery, ApiTags } from "@nestjs/swagger";
|
||||
import { Response } from "express";
|
||||
|
||||
import { FilesService } from "./files.service";
|
||||
|
||||
@ApiTags("files")
|
||||
@ApiBearerAuth()
|
||||
@Controller("files")
|
||||
export class FilesController {
|
||||
constructor(private readonly filesService: FilesService) {}
|
||||
|
||||
@Get(":fileId")
|
||||
// Public so the browser can load the bytes directly via <img>/<iframe>/<a> —
|
||||
// those requests can't carry the Bearer token the axios client injects, so a
|
||||
// guarded route 401s. File UUIDs are unguessable; same tradeoff as webhooks.
|
||||
@Public()
|
||||
// Authenticated: no @Public, so the global JwtGuard applies. Unguessable file
|
||||
// UUIDs are obscurity, not authorization — raw byte streams must require auth.
|
||||
// Browser inline previews (<img>/<iframe>/<a>) that can't carry the Bearer
|
||||
// token should use a short-lived signed URL instead (FilesService.signUrl).
|
||||
// TODO: enforce ownership-by-resource here next (scope the file to the
|
||||
// caller's booking/company before streaming).
|
||||
@ApiOperation({
|
||||
summary: "Stream a file by ID",
|
||||
description:
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import { Injectable, NotFoundException } from "@nestjs/common";
|
||||
import {
|
||||
BadRequestException,
|
||||
Injectable,
|
||||
NotFoundException,
|
||||
} from "@nestjs/common";
|
||||
import { Readable } from "stream";
|
||||
|
||||
import { MinioService } from "../minio/minio.service";
|
||||
@@ -28,6 +32,31 @@ function sanitizeObjectName(name: string): string {
|
||||
|
||||
@Injectable()
|
||||
export class FilesService {
|
||||
// Defense-in-depth for ANY caller of upload() (not just the driver-docs
|
||||
// route). This is deliberately BROADER than the driver controller's strict
|
||||
// images+pdf Multer filter, because the same method also stores generated
|
||||
// PDFs, PNG signatures, and customer/customs booking documents (scans, office
|
||||
// docs). It rejects the actual attack surface (executables/scripts/HTML) while
|
||||
// permitting every business-document type these flows legitimately upload.
|
||||
// No file-upload-settings row governs raw byte size, so the cap is a sane,
|
||||
// generous default that won't reject large scanned documents.
|
||||
private static readonly MAX_UPLOAD_BYTES = 25 * 1024 * 1024;
|
||||
private static readonly ALLOWED_UPLOAD_MIME = new Set([
|
||||
"image/jpeg",
|
||||
"image/png",
|
||||
"image/webp",
|
||||
"image/gif",
|
||||
"image/heic",
|
||||
"image/tiff",
|
||||
"application/pdf",
|
||||
"application/msword",
|
||||
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||
"application/vnd.ms-excel",
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
"text/csv",
|
||||
"text/plain",
|
||||
]);
|
||||
|
||||
constructor(
|
||||
private readonly filesRepository: FilesRepository,
|
||||
private readonly minioService: MinioService,
|
||||
@@ -35,6 +64,15 @@ export class FilesService {
|
||||
|
||||
async upload(input: CreateFileInput): Promise<FileRecord> {
|
||||
const { resourceId, resource, code, file } = input;
|
||||
|
||||
if (!FilesService.ALLOWED_UPLOAD_MIME.has(file.mimetype)) {
|
||||
throw new BadRequestException(`Unsupported file type: ${file.mimetype}`);
|
||||
}
|
||||
if (file.size > FilesService.MAX_UPLOAD_BYTES) {
|
||||
throw new BadRequestException(
|
||||
`File exceeds the ${FilesService.MAX_UPLOAD_BYTES / (1024 * 1024)}MB upload limit`,
|
||||
);
|
||||
}
|
||||
// Keep the object key URL-safe so it survives the round-trip through the
|
||||
// stored URL (spaces/unicode in the original name would otherwise be
|
||||
// percent-encoded in the URL and no longer match the MinIO key). The
|
||||
|
||||
Reference in New Issue
Block a user