Return filename validation messages
This commit is contained in:
parent
41d427f4a8
commit
795ca2247b
|
@ -12,31 +12,39 @@ const VALID_CATEGORIES = ['bgm', 'ambient', 'blip', 'live2d'];
|
||||||
/**
|
/**
|
||||||
* Validates the input filename for the asset.
|
* Validates the input filename for the asset.
|
||||||
* @param {string} inputFilename Input filename
|
* @param {string} inputFilename Input filename
|
||||||
* @returns {string} Normalized or empty path if invalid
|
* @returns {{error: boolean, message?: string}} Whether validation failed, and why if so
|
||||||
*/
|
*/
|
||||||
function validateAssetFileName(inputFilename) {
|
function validateAssetFileName(inputFilename) {
|
||||||
if (!/^[a-zA-Z0-9_\-.]+$/.test(inputFilename)) {
|
if (!/^[a-zA-Z0-9_\-.]+$/.test(inputFilename)) {
|
||||||
console.debug('Bad request: illegal character in filename, only alphanumeric, \'_\', \'-\' are accepted.');
|
return {
|
||||||
return '';
|
error: true,
|
||||||
|
message: 'Illegal character in filename; only alphanumeric, \'_\', \'-\' are accepted.',
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const inputExtension = path.extname(inputFilename).toLowerCase();
|
const inputExtension = path.extname(inputFilename).toLowerCase();
|
||||||
if (UNSAFE_EXTENSIONS.some(ext => ext === inputExtension)) {
|
if (UNSAFE_EXTENSIONS.some(ext => ext === inputExtension)) {
|
||||||
console.debug('Bad request: forbidden file extension.');
|
return {
|
||||||
return '';
|
error: true,
|
||||||
|
message: 'Forbidden file extension.',
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inputFilename.startsWith('.')) {
|
if (inputFilename.startsWith('.')) {
|
||||||
console.debug('Bad request: filename cannot start with \'.\'');
|
return {
|
||||||
return '';
|
error: true,
|
||||||
|
message: 'Filename cannot start with \'.\'',
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sanitize(inputFilename) !== inputFilename) {
|
if (sanitize(inputFilename) !== inputFilename) {
|
||||||
console.debug('Bad request: reserved or long filename');
|
return {
|
||||||
return '';
|
error: true,
|
||||||
|
message: 'Reserved or long filename.',
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return inputFilename;
|
return { error: false };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recursive function to get files
|
// Recursive function to get files
|
||||||
|
@ -141,13 +149,13 @@ router.post('/download', jsonParser, async (request, response) => {
|
||||||
return response.sendStatus(400);
|
return response.sendStatus(400);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sanitize filename
|
// Validate filename
|
||||||
const safe_input = validateAssetFileName(request.body.filename);
|
const validation = validateAssetFileName(request.body.filename);
|
||||||
if (safe_input == '')
|
if (validation.error)
|
||||||
return response.sendStatus(400);
|
return response.status(400).send(validation.message);
|
||||||
|
|
||||||
const temp_path = path.join(DIRECTORIES.assets, 'temp', safe_input);
|
const temp_path = path.join(DIRECTORIES.assets, 'temp', request.body.filename);
|
||||||
const file_path = path.join(DIRECTORIES.assets, category, safe_input);
|
const file_path = path.join(DIRECTORIES.assets, category, request.body.filename);
|
||||||
console.debug('Request received to download', url, 'to', file_path);
|
console.debug('Request received to download', url, 'to', file_path);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -199,12 +207,12 @@ router.post('/delete', jsonParser, async (request, response) => {
|
||||||
return response.sendStatus(400);
|
return response.sendStatus(400);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sanitize filename
|
// Validate filename
|
||||||
const safe_input = validateAssetFileName(request.body.filename);
|
const validation = validateAssetFileName(request.body.filename);
|
||||||
if (safe_input == '')
|
if (validation.error)
|
||||||
return response.sendStatus(400);
|
return response.status(400).send(validation.message);
|
||||||
|
|
||||||
const file_path = path.join(DIRECTORIES.assets, category, safe_input);
|
const file_path = path.join(DIRECTORIES.assets, category, request.body.filename);
|
||||||
console.debug('Request received to delete', category, file_path);
|
console.debug('Request received to delete', category, file_path);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -16,13 +16,12 @@ router.post('/upload', jsonParser, async (request, response) => {
|
||||||
return response.status(400).send('No upload data specified');
|
return response.status(400).send('No upload data specified');
|
||||||
}
|
}
|
||||||
|
|
||||||
const safeInput = validateAssetFileName(request.body.name);
|
// Validate filename
|
||||||
|
const validation = validateAssetFileName(request.body.name);
|
||||||
|
if (validation.error)
|
||||||
|
return response.status(400).send(validation.message);
|
||||||
|
|
||||||
if (!safeInput) {
|
const pathToUpload = path.join(DIRECTORIES.files, request.body.name);
|
||||||
return response.status(400).send('Invalid upload name');
|
|
||||||
}
|
|
||||||
|
|
||||||
const pathToUpload = path.join(DIRECTORIES.files, safeInput);
|
|
||||||
writeFileSyncAtomic(pathToUpload, request.body.data, 'base64');
|
writeFileSyncAtomic(pathToUpload, request.body.data, 'base64');
|
||||||
const url = path.normalize(pathToUpload.replace('public' + path.sep, ''));
|
const url = path.normalize(pathToUpload.replace('public' + path.sep, ''));
|
||||||
return response.send({ path: url });
|
return response.send({ path: url });
|
||||||
|
|
Loading…
Reference in New Issue