- validate all file-upload via clamdscan (clamav), throw ValidationException in case of an error

- add @types/clamscan and clamscan for node
- package clamav-daemon and clamav-frehshclam for docker
- add API Controller: HomeController.ts for /api/years and /api/sitelinks/{year}
 change root path of file storage from '/storage/app/public/files' to '/storage/app/public'
 - adapt dockerfile to use node:18-bookworm-slim
This commit is contained in:
Kaimbacher 2023-09-04 13:24:58 +02:00
parent 5f8fe1c16d
commit b6b1c90ff8
20 changed files with 941 additions and 278 deletions

View file

@ -12,6 +12,10 @@ Route.group(() => {
// Route.get("author/:id", "TodosController.show");
// Route.put("author/update", "TodosController.update");
// Route.post("author", "TodosController.store");
Route.get('/dataset', 'DatasetController.findAll').as('dataset.findAll');
Route.get('/dataset/:publish_id', 'DatasetController.findOne').as('dataset.findOne');
Route.get('/sitelinks/:year', 'HomeController.findDocumentsPerYear');
Route.get('/years', 'HomeController.findYears');
});
// .middleware("auth:api");
})

View file

@ -72,3 +72,69 @@ validator.rule(
// }
},
);
validator.rule('fileExtension', async (value, [extensions], { pointer, arrayExpressionPointer, errorReporter }) => {
const allowedExtensions = extensions.map((ext: string) => ext.toLowerCase());
const uploadedFile = value;
if (!uploadedFile) {
return;
}
const extension = uploadedFile.extname.toLowerCase().replace('.', '');
if (!allowedExtensions.includes(extension)) {
errorReporter.report(
pointer,
'fileExtension',
'Invalid file extension. Only {{ extensions }} files are allowed.',
arrayExpressionPointer,
);
}
});
// validator.rule(
// 'clamavScan',
// (value, [field], { root, tip, pointer, arrayExpressionPointer, errorReporter }) => {
// if (typeof value !== 'object') {
// return;
// }
// const uploadedFile = validator.helpers.getFieldValue(field, root, tip);
// // return rules.file({}, [
// // async (file) => {
// // const clamdhost = process.env['CLAMD_HOST'] ?? '127.0.0.1';
// // const clamdport = Number(process.env['CLAMD_PORT']) ?? '3310';
// // try {
// // var isInfected = await scanFileForViruses(file.tmpPath, clamdhost, clamdport);
// // } catch (error) {
// // throw new Error(`${pointer}: ${error.message}`);
// // }
// // },
// // ]);
// });
// async function scanFileForViruses(filePath, host, port): Promise<boolean> {
// // const clamscan = await (new ClamScan().init());
// const opts: ClamScan.Options = {
// preference: 'clamdscan',
// clamdscan: {
// active: true,
// host,
// port,
// multiscan: true,
// },
// };
// const clamscan = await new ClamScan().init(opts);
// return new Promise((resolve, reject) => {
// clamscan.isInfected(filePath, (err, file, isInfected: boolean) => {
// if (err) {
// reject(err);
// } else if (isInfected) {
// reject(new Error(`File ${file} is infected!`));
// } else {
// resolve(isInfected);
// }
// });
// });
// }