Press n or j to go to the next uncovered block, b, p or k for the previous block.
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 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x | import {inject} from '@loopback/core'; import {get, oas, param, post, Request, requestBody, Response, RestBindings} from '@loopback/rest'; import fs from 'fs'; import path from 'path'; import {promisify} from 'util'; import {ASSETS_DIRECTORY, FILE_UPLOAD_SERVICE, STORAGE_DIRECTORY} from '../keys'; import {FileUploadHandler} from '../types'; import {getFilesAndFields} from './components'; import {baseResponse} from './requestSpecs'; const readdir = promisify(fs.readdir); export class FilesController { constructor( @inject(FILE_UPLOAD_SERVICE) private handler: FileUploadHandler, @inject(STORAGE_DIRECTORY) private storageDirectory: string, @inject(ASSETS_DIRECTORY) private assetsDirectory: string, @inject(RestBindings.Http.RESPONSE) private res: Response, ) { } @post('/files', baseResponse) async fileUpload(@requestBody.file() request: Request): Promise<object> { return new Promise<object>((resolve, reject) => { this.handler(request, this.res, (err: unknown) => { if (err) { reject(err) } else { resolve(getFilesAndFields(request)); } }); }); } @get('/files', baseResponse) async listFiles() { let methodName = "listFiles" try { const files = await readdir(this.storageDirectory); return files; } catch (error) { throw {code: 422, message: error, methodName, className: FilesController.name} } } @get('/files/{filename}') @oas.response.file() downloadFile( @param.path.string('filename') fileName: string, @inject(RestBindings.Http.RESPONSE) response: Response, ) { let methodName = "downloadFile" try { const file = this.validateFileName(fileName); response.download(file, fileName); return response; } catch (error) { throw {code: 422, message: error, methodName, className: FilesController.name} } } @get('/assets/{filename}') @oas.response.file() downloadAssets( @param.path.string('filename') fileName: string, @inject(RestBindings.Http.RESPONSE) response: Response, ) { let methodName = "downloadAssets" try { const file = this.validateAssetsFileName(fileName); response.download(file, fileName); return response; } catch (error) { throw {code: 422, message: error, methodName, className: FilesController.name} } } private validateAssetsFileName(fileName: string) { let methodName = "validateAssetsFileName" const resolved = path.resolve(this.assetsDirectory, fileName); if (resolved.startsWith(this.assetsDirectory)) return resolved; // The resolved file is outside sandbox throw {code: 406, message: `Invalid file name: ${fileName}`, methodName, className: FilesController.name} } private validateFileName(fileName: string) { const resolved = path.resolve(this.storageDirectory, fileName); const validFile = fs.existsSync(resolved) let methodName = "validateFileName" if (validFile) if (resolved.startsWith(this.storageDirectory)) return resolved; // The resolved file is outside sandbox throw {code: 406, message: `Invalid file name: ${fileName}`, methodName, className: FilesController.name} } } |