diff --git a/package.json b/package.json index 7486ccf4a..4c3e837f6 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,6 @@ "lodash": "^4.17.21", "maplibre-gl": "^1.15.3", "matomo-tracker": "^2.2.4", - "mime": "^3.0.0", "next": "^13.1.2", "papaparse": "^5.3.2", "prop-types": "^15.8.1", @@ -56,6 +55,7 @@ "react-dom": "^18.2.0", "react-dropzone": "^14.2.3", "react-feather": "^2.0.10", + "send": "^0.18.0", "sharp": "^0.29.3", "styled-components": "^6.0.7", "underscore.string": "^3.3.6", diff --git a/pages/data/[[...path]].js b/pages/data/[[...path]].js index 38413b7d5..19caf8773 100644 --- a/pages/data/[[...path]].js +++ b/pages/data/[[...path]].js @@ -1,6 +1,6 @@ import fs from 'node:fs' import path from 'node:path' -import mime from 'mime' +import send from 'send' import PropTypes from 'prop-types' import {Download} from 'react-feather' @@ -72,20 +72,42 @@ const getDirectories = _path => ( }) ) -export function getServerSideProps(context) { +const getFormatedDate = () => { + const date = new Date() + return new Intl.DateTimeFormat('fr', {year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit'}).format(date).replace(/,/g, '\'').replace(/ /g, ' ') +} + +const asyncSend = (req, res, filePath) => new Promise((resolve, reject) => { + const targetFileName = path.basename(filePath) + function headers(res) { + res.setHeader('Content-Disposition', `attachment; filename="${targetFileName}"`) + } + + send(req, encodeURI(filePath), {index: false}) + .on('headers', headers) + .pipe(res) + .on('error', err => { + const formattedDate = getFormatedDate() + console.warn(`[${formattedDate} - ERROR]`, 'File access error:', err) + reject(err) + }) + .on('end', () => { + resolve() + }) +}) + +export async function getServerSideProps(context) { let stat - let targetFileName + let realPath - const {params, res} = context + const {params, res, req} = context const {path: paramPath = []} = params const fileName = `${paramPath.join('/')}` const filePath = path.resolve(PATH, fileName) - const date = new Date() - const formattedDate = new Intl.DateTimeFormat('fr', {year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit'}).format(date).replace(/,/g, '\'').replace(/ /g, ' ') + const formattedDate = getFormatedDate() try { const authPath = autorizedPath(filePath) - const realPath = authPath.path if (!authPath.auth) { console.warn(`[${formattedDate} - WARNING]`, `Attempted illegal access to ${authPath.path}`) @@ -95,8 +117,8 @@ export function getServerSideProps(context) { } } + realPath = authPath.path stat = fs.lstatSync(realPath) - targetFileName = path.basename(realPath) } catch (err) { console.warn(`[${formattedDate} - ERROR]`, 'File access error:', err) res.statusCode = 404 @@ -116,20 +138,9 @@ export function getServerSideProps(context) { } try { - const fileExtension = path.extname(targetFileName) - const contentType = mime.getType(fileExtension) || 'application/octet-stream' - const fileContents = fs.readFileSync(filePath) - const lastModified = stat.mtime.toUTCString() - const fileSize = stat.size const sendToTracker = getAnalyticsPusher() - res.setHeader('Content-Type', contentType) - res.setHeader('Content-Disposition', `attachment; filename="${targetFileName}"`) - res.setHeader('Content-Length', fileSize) - res.setHeader('Last-Modified', lastModified) - res.statusCode = 200 - res.end(fileContents) - + await asyncSend(req, res, realPath) sendToTracker(getDownloadTrackData({ downloadDataType: path.dirname(fileName).split('/')[0], downloadFileName: fileName, diff --git a/yarn.lock b/yarn.lock index af5136843..01400e6dc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5500,11 +5500,6 @@ mime@1.6.0: resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== -mime@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-3.0.0.tgz#b374550dca3a0c18443b0c950a6a58f1931cf7a7" - integrity sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A== - mimic-fn@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" @@ -6702,7 +6697,7 @@ semver@^7.2.1, semver@^7.3.4, semver@^7.3.5: dependencies: lru-cache "^6.0.0" -send@0.18.0: +send@0.18.0, send@^0.18.0: version "0.18.0" resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==