2020-10-01 23:10:41 +03:00
|
|
|
const config = require('./config');
|
|
|
|
|
|
|
|
const express = require('express');
|
|
|
|
const fileUpload = require('express-fileupload');
|
|
|
|
const path = require('path');
|
|
|
|
const fs = require('fs');
|
|
|
|
const mime = require('mime-types')
|
2020-10-05 00:15:13 +03:00
|
|
|
const cors = require('cors');
|
2020-10-01 23:10:41 +03:00
|
|
|
|
|
|
|
const app = express();
|
|
|
|
|
|
|
|
app.use(fileUpload());
|
|
|
|
app.set('view engine', 'ejs')
|
2020-10-02 22:46:23 +03:00
|
|
|
app.use(express.urlencoded({ extended: false }));
|
|
|
|
app.use(express.json());
|
2020-10-01 23:10:41 +03:00
|
|
|
|
|
|
|
|
|
|
|
const isPathValid = (filename, filePath) => {
|
|
|
|
if (!filename) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (filename.indexOf('\0') !== -1 || filename.indexOf('%') !== -1 || filename.indexOf('/') !== -1 || filename.indexOf('..') !== -1) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-10-03 18:53:43 +03:00
|
|
|
if (!/[A-Za-z1-9.]+/g.test(filename)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-10-01 23:10:41 +03:00
|
|
|
if (filePath.indexOf(config.storagePath) !== 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
|
2020-10-03 18:53:43 +03:00
|
|
|
const isFilenameValid = (filename) => {
|
|
|
|
if (!filename) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (filename.indexOf('\0') !== -1 || filename.indexOf('%') !== -1 || filename.indexOf('..') !== -1 || filename.indexOf('&') !== -1) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!/[A-Za-z1-9.]+/g.test(filename)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
|
2020-10-01 23:10:41 +03:00
|
|
|
const getFileType = (filename) => {
|
|
|
|
const extension = path.extname(filename).substring(1);
|
|
|
|
let type = config.files.embed[extension];
|
|
|
|
|
|
|
|
if (!type) {
|
|
|
|
type = config.files.other;
|
|
|
|
}
|
|
|
|
|
|
|
|
return type;
|
|
|
|
};
|
|
|
|
|
2020-10-05 00:15:13 +03:00
|
|
|
const allowlist = ['https://files.hippoz.xyz', 'https://hippoz.xyz']
|
|
|
|
const corsOptions = {
|
|
|
|
origin: function (origin, callback) {
|
2020-10-05 00:20:28 +03:00
|
|
|
if (allowlist.indexOf(origin) !== -1) {
|
2020-10-05 00:15:13 +03:00
|
|
|
callback(null, true)
|
|
|
|
} else {
|
|
|
|
callback(new Error('Not allowed by CORS'))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-10-03 18:53:43 +03:00
|
|
|
|
2020-10-05 00:15:13 +03:00
|
|
|
app.use('*', cors(corsOptions));
|
2020-10-03 18:53:43 +03:00
|
|
|
|
|
|
|
app.get('/', (req, res) => {
|
2020-10-05 00:15:13 +03:00
|
|
|
// res.render('upload');
|
|
|
|
res.redirect(config.url);
|
2020-10-03 18:53:43 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
2020-10-01 23:10:41 +03:00
|
|
|
app.get('/file/:filename', (req, res) => {
|
|
|
|
const filename = req.params.filename;
|
|
|
|
const filePath = path.join(config.storagePath, filename);
|
|
|
|
const isValid = isPathValid(filename, filePath);
|
|
|
|
|
|
|
|
if (!isValid) {
|
|
|
|
res.status(400).send('Invalid input.');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
fs.access(filePath, fs.F_OK, (err) => {
|
|
|
|
if (err) {
|
|
|
|
res.status(404).send('File not found or is invalid.');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const type = getFileType(filePath);
|
|
|
|
const mimeType = mime.lookup(filePath);
|
|
|
|
|
|
|
|
if (type === config.files.other) {
|
|
|
|
res.contentType('text/plain');
|
|
|
|
} else {
|
|
|
|
res.contentType(mimeType);
|
|
|
|
}
|
|
|
|
|
|
|
|
res.sendFile(filePath);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
app.post('/api/upload', (req, res) => {
|
2020-10-02 22:46:23 +03:00
|
|
|
const password = req.body.password;
|
2020-10-03 18:53:43 +03:00
|
|
|
const chosenFileName = req.body.filename;
|
2020-10-02 22:46:23 +03:00
|
|
|
|
|
|
|
if (config.passwords.indexOf(password) === -1) {
|
2020-10-02 23:12:51 +03:00
|
|
|
return res.status(401).render('uploadfailed', { message: 'The password you entered is not correct.' });
|
2020-10-02 22:46:23 +03:00
|
|
|
}
|
|
|
|
|
2020-10-01 23:10:41 +03:00
|
|
|
if (!req.files || Object.keys(req.files).length === 0) {
|
2020-10-02 23:12:51 +03:00
|
|
|
return res.status(400).render('uploadfailed', { message: 'You forgot to upload a file.' });
|
2020-10-01 23:10:41 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
const file = req.files.file;
|
2020-10-03 18:53:43 +03:00
|
|
|
|
|
|
|
if (!isFilenameValid(chosenFileName)) {
|
|
|
|
return res.status(400).render('uploadfailed', { message: 'Invalid name.' });
|
|
|
|
}
|
|
|
|
|
|
|
|
const filepath = path.join(config.storagePath, chosenFileName);
|
|
|
|
|
|
|
|
if (!isFilenameValid(file.name) || !isPathValid(chosenFileName, filepath)) {
|
|
|
|
return res.status(400).render('uploadfailed', { message: 'Invalid name.' });
|
|
|
|
}
|
2020-10-02 23:03:59 +03:00
|
|
|
|
2020-10-02 23:08:12 +03:00
|
|
|
fs.stat(filepath, (err) => {
|
|
|
|
if(err == null) {
|
2020-10-02 23:12:51 +03:00
|
|
|
return res.status(400).render('uploadfailed', { message: 'A file with that name already exists.' });
|
2020-10-02 23:08:12 +03:00
|
|
|
} else if(err.code === 'ENOENT') {
|
2020-10-02 23:03:59 +03:00
|
|
|
file.mv(filepath, (err) => {
|
2020-10-02 23:39:17 +03:00
|
|
|
if (err) return res.status(500).render('uploadfailed', { message: 'Something went wrong while uploading the file.' });
|
2020-10-03 18:53:43 +03:00
|
|
|
res.render('uploaded', { file: { name: chosenFileName } });
|
2020-10-02 23:03:59 +03:00
|
|
|
});
|
|
|
|
} else {
|
2020-10-02 23:12:51 +03:00
|
|
|
return res.status(500).render('uploadfailed', { message: 'Something went wrong.' });;
|
2020-10-02 23:03:59 +03:00
|
|
|
}
|
2020-10-01 23:10:41 +03:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2020-10-02 23:18:53 +03:00
|
|
|
app.listen(config.server.port, () => {
|
|
|
|
console.log(`Started server on port ${config.server.port}`);
|
|
|
|
});
|