Skip to content
This repository was archived by the owner on Dec 12, 2025. It is now read-only.

Commit 94dc5cc

Browse files
committed
fix(download): remove deprecated HEAD download endpoint and sanitize filename in Content-Disposition header
1 parent 4df51b0 commit 94dc5cc

File tree

1 file changed

+3
-37
lines changed

1 file changed

+3
-37
lines changed

src/controllers/GameController.ts

Lines changed: 3 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Request, Response } from 'express';
22
import rateLimit from 'express-rate-limit';
33
import { inject } from 'inversify';
4-
import { controller, httpGet, httpPost, httpPut, httpHead } from 'inversify-express-utils';
4+
import { controller, httpGet, httpPost, httpPut } from 'inversify-express-utils';
55
import fetch from 'node-fetch';
66
import { v4 } from 'uuid';
77
import { AuthenticatedRequest, LoggedCheck } from '../middlewares/LoggedCheck';
@@ -410,16 +410,14 @@ export class Games {
410410
const headers: any = {};
411411
if (req.headers.range) {
412412
headers.Range = req.headers.range;
413-
}
413+
}
414414

415415
const fileRes = await fetch(link, { headers });
416416
if (!fileRes.ok) {
417417
return res.status(fileRes.status).send({ message: 'Error fetching file' });
418418
}
419419

420-
// Sanitize the filename to remove invalid characters
421-
const sanitizedFilename = game.name.replace(/[^a-zA-Z0-9-_\.]/g, '_');
422-
res.setHeader('Content-Disposition', `attachment; filename="${sanitizedFilename}.zip"`);
420+
res.setHeader('Content-Disposition', `attachment; filename="${game.name}.zip"`);
423421
res.setHeader('Content-Type', fileRes.headers.get('content-type') || 'application/octet-stream');
424422

425423
const contentLength = fileRes.headers.get('content-length');
@@ -445,38 +443,6 @@ export class Games {
445443
handleError(res, error, 'Error downloading game');
446444
}
447445
}
448-
449-
@httpHead('/:gameId/download', LoggedCheck.middleware)
450-
public async headDownloadGame(req: AuthenticatedRequest, res: Response) {
451-
const { gameId } = req.params;
452-
const userId = req.user.user_id;
453-
try {
454-
const game = await this.gameService.getGame(gameId);
455-
if (!game) {
456-
return res.status(404).send({ message: 'Game not found' });
457-
}
458-
const owns = (await this.gameService.userOwnsGame(gameId, userId)) || game.owner_id === userId;
459-
if (!owns) {
460-
return res.status(403).send({ message: 'Access denied' });
461-
}
462-
const link = game.download_link;
463-
if (!link) {
464-
return res.status(404).send({ message: 'Download link not available' });
465-
}
466-
467-
const fileRes = await fetch(link, { method: 'HEAD' });
468-
if (!fileRes.ok) {
469-
return res.status(fileRes.status).send({ message: 'Error fetching file metadata' });
470-
}
471-
472-
res.setHeader('Content-Length', fileRes.headers.get('content-length') || '0');
473-
res.setHeader('Accept-Ranges', fileRes.headers.get('accept-ranges') || 'none');
474-
res.setHeader('Content-Type', fileRes.headers.get('content-type') || 'application/octet-stream');
475-
res.status(200).end();
476-
} catch (error) {
477-
handleError(res, error, 'Error fetching file metadata');
478-
}
479-
}
480446
}
481447

482448

0 commit comments

Comments
 (0)