-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfile.controller.ts
More file actions
102 lines (92 loc) · 2.52 KB
/
file.controller.ts
File metadata and controls
102 lines (92 loc) · 2.52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
import {
Body,
Controller,
Delete,
Get,
Headers,
HttpStatus,
Logger,
Put,
Query,
Res,
} from '@nestjs/common';
import { ApiOperation, ApiTags } from '@nestjs/swagger';
import { W_OK } from 'constants';
import * as fs from 'fs';
import * as path from 'path';
import { Stream } from 'stream';
import { FileService } from './file.service';
import { FastifyReply } from 'fastify';
@Controller('/api/file')
@ApiTags('files controller')
export class FileController {
private readonly logger = new Logger(FileController.name);
constructor(private fileService: FileService) {}
@ApiOperation({
description:
'Reads the file from the provided path and the supplied content type and returns the file',
})
@Get()
async loadFile(
@Query('path') path: string,
@Query('type') contentType: string,
@Res({ passthrough: true }) res: FastifyReply,
@Headers('accept') acceptHeader: string,
) {
let type: string;
if (contentType) {
type = contentType;
} else if (acceptHeader) {
type = acceptHeader;
} else {
type = 'application/octet-stream';
}
const file: Stream = await this.fileService.getFile(path);
res.type(type);
return file;
}
@ApiOperation({
description: 'deletes file at the given path',
})
@Delete()
async deleteFile(@Query('path') path: string): Promise<void> {
await this.fileService.deleteFile(path);
}
@ApiOperation({
description: 'save raw content on server as a file',
})
@Put('raw')
async uploadFile(@Query('path') filePath: string, @Body() raw: Buffer): Promise<void> {
const SAFE_ROOT = '/safe/root/directory';
try {
if (typeof raw === 'string' || Buffer.isBuffer(raw)) {
const resolvedPath = path.resolve(SAFE_ROOT, filePath);
if (!resolvedPath.startsWith(SAFE_ROOT)) {
this.logger.error('Invalid file path');
return;
}
await fs.promises.access(path.dirname(resolvedPath), W_OK);
await fs.promises.writeFile(resolvedPath, raw);
}
} catch (err) {
this.logger.error(err.message);
}
}
@ApiOperation({
description: 'read file content content on server as a file',
})
@Get('raw')
async readFile(
@Query('path') file,
@Res({ passthrough: true }) res: FastifyReply,
) {
try {
const stream = await this.fileService.getFile(file);
res.type('application/octet-stream');
return stream;
} catch (err) {
this.logger.error(err.message);
res.status(HttpStatus.NOT_FOUND);
}
}
}