From aab741220e0c5af2112727aedb5e74921c460cb0 Mon Sep 17 00:00:00 2001 From: "Mert E." Date: Sat, 27 Jul 2024 15:06:12 +0300 Subject: [PATCH] fix: non-ascii characters on attachment names (#9092) * fix: non-ascii characters on attachment names * chore: content-disposition library Signed-off-by: mertmit --------- Signed-off-by: mertmit --- packages/nocodb/package.json | 2 ++ .../src/controllers/attachments.controller.ts | 5 +++-- packages/nocodb/src/models/PresignedUrl.ts | 11 +++++++++-- pnpm-lock.yaml | 16 ++++++++++++++++ 4 files changed, 30 insertions(+), 4 deletions(-) diff --git a/packages/nocodb/package.json b/packages/nocodb/package.json index fbee9c5d10..f32f7af162 100644 --- a/packages/nocodb/package.json +++ b/packages/nocodb/package.json @@ -87,6 +87,7 @@ "clickhouse-migrations": "^0.1.14", "colors": "^1.4.0", "compare-versions": "^6.1.0", + "content-disposition": "^0.5.4", "cookie-parser": "^1.4.6", "cors": "^2.8.5", "cron": "^1.8.2", @@ -180,6 +181,7 @@ "@nestjs/schematics": "^10.1.1", "@nestjs/testing": "^10.3.8", "@nestjsplus/dyn-schematics": "^1.0.12", + "@types/content-disposition": "^0.5.8", "@types/ejs": "^3.1.5", "@types/express": "^4.17.21", "@types/jest": "^29.5.12", diff --git a/packages/nocodb/src/controllers/attachments.controller.ts b/packages/nocodb/src/controllers/attachments.controller.ts index e019af4fd8..5426667eff 100644 --- a/packages/nocodb/src/controllers/attachments.controller.ts +++ b/packages/nocodb/src/controllers/attachments.controller.ts @@ -16,6 +16,7 @@ import { } from '@nestjs/common'; import { AnyFilesInterceptor } from '@nestjs/platform-express'; import { Response } from 'express'; +import contentDisposition from 'content-disposition'; import type { AttachmentReqType, FileType } from 'nocodb-sdk'; import { UploadAllowedInterceptor } from '~/interceptors/is-upload-allowed/is-upload-allowed.interceptor'; import { GlobalGuard } from '~/guards/global/global.guard'; @@ -92,7 +93,7 @@ export class AttachmentsController { if (queryFilename) { res.setHeader( 'Content-Disposition', - `attachment; filename=${queryFilename}`, + contentDisposition(queryFilename, { type: 'attachment' }), ); } res.sendFile(file.path); @@ -133,7 +134,7 @@ export class AttachmentsController { if (queryFilename) { res.setHeader( 'Content-Disposition', - `attachment; filename=${queryFilename}`, + contentDisposition(queryFilename, { type: 'attachment' }), ); } res.sendFile(file.path); diff --git a/packages/nocodb/src/models/PresignedUrl.ts b/packages/nocodb/src/models/PresignedUrl.ts index f8d512f907..0692184e3d 100644 --- a/packages/nocodb/src/models/PresignedUrl.ts +++ b/packages/nocodb/src/models/PresignedUrl.ts @@ -1,4 +1,5 @@ import { nanoid } from 'nanoid'; +import contentDisposition from 'content-disposition'; import NcPluginMgrv2 from '~/helpers/NcPluginMgrv2'; import Noco from '~/Noco'; import NocoCache from '~/cache/NocoCache'; @@ -132,13 +133,19 @@ export default class PresignedUrl { pathParameters.ResponseContentDisposition = `inline;`; if (filename) { - pathParameters.ResponseContentDisposition += ` filename="${filename}"`; + pathParameters.ResponseContentDisposition = contentDisposition( + filename, + { type: 'inline' }, + ); } } else { pathParameters.ResponseContentDisposition = `attachment;`; if (filename) { - pathParameters.ResponseContentDisposition += ` filename="${filename}"`; + pathParameters.ResponseContentDisposition = contentDisposition( + filename, + { type: 'attachment' }, + ); } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 79a9d41ae7..16f1da21e7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -588,6 +588,9 @@ importers: compare-versions: specifier: ^6.1.0 version: 6.1.0 + content-disposition: + specifier: ^0.5.4 + version: 0.5.4 cookie-parser: specifier: ^1.4.6 version: 1.4.6 @@ -862,6 +865,9 @@ importers: '@nestjsplus/dyn-schematics': specifier: ^1.0.12 version: 1.0.12 + '@types/content-disposition': + specifier: ^0.5.8 + version: 0.5.8 '@types/ejs': specifier: ^3.1.5 version: 3.1.5 @@ -9596,6 +9602,10 @@ packages: '@types/node': 20.11.30 dev: true + /@types/content-disposition@0.5.8: + resolution: {integrity: sha512-QVSSvno3dE0MgO76pJhmv4Qyi/j0Yk9pBp0Y7TJ2Tlj+KCgJWY6qX7nnxCOLkZ3VYRSIk1WTxCvwUSdx6CCLdg==} + dev: true + /@types/cookie@0.4.1: resolution: {integrity: sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==} @@ -25915,6 +25925,9 @@ packages: /sqlite3@5.1.6: resolution: {integrity: sha512-olYkWoKFVNSSSQNvxVUfjiVbz3YtBwTJj+mfV5zpHmqW3sELx2Cf4QCdirMelhM5Zh+KDVaKgQHqCxrqiWHybw==} requiresBuild: true + peerDependenciesMeta: + node-gyp: + optional: true dependencies: '@mapbox/node-pre-gyp': 1.0.11 node-addon-api: 4.3.0 @@ -25929,6 +25942,9 @@ packages: /sqlite3@5.1.7: resolution: {integrity: sha512-GGIyOiFaG+TUra3JIfkI/zGP8yZYLPQ0pl1bH+ODjiX57sPhrLU5sQJn1y9bDKZUFYkX1crlrPfSYt0BKKdkog==} requiresBuild: true + peerDependenciesMeta: + node-gyp: + optional: true dependencies: bindings: 1.5.0 node-addon-api: 7.0.0