@@ -5,6 +5,7 @@ const router = express.Router(); | |||
const User = require('../models/User.js'); | |||
const Invite = require('../models/Invite.js'); | |||
const passport = require('passport'); | |||
const config = require('config'); | |||
const canonicalizeRequest = require('../util/canonicalize').canonicalizeRequest; | |||
const requireAuth = require('../util/requireAuth').requireAuth; | |||
@@ -29,10 +30,11 @@ function login(user, req) { | |||
// Check if a canonical name is valid | |||
async function validateUsername(username, canonicalName, sanitize) { | |||
if (canonicalName.length > 36) | |||
if (canonicalName.length > config.get('User.Username.maxLength')) | |||
return {valid: false, message: 'Username too long.'}; | |||
if (canonicalName !== sanitize(canonicalName).replace(/\s/g, '')) | |||
const restrictedRegex = new RegExp(config.get('User.Username.restrictedChars'), 'g'); | |||
if (canonicalName !== sanitize(canonicalName).replace(restrictedRegex, '')) | |||
return {valid: false, message: 'Username contains invalid characters.'}; | |||
const count = await User.countDocuments({canonicalname: canonicalName}); | |||
@@ -7,7 +7,7 @@ const Upload = require('../models/Upload.js'); | |||
const Key = require('../models/Key.js'); | |||
const multer = require('multer'); | |||
const fileUpload = multer({dest: config.uploadPath}).single('file'); | |||
const fileUpload = multer({dest: config.get('Upload.path')}).single('file'); | |||
const fsPromises = require('fs').promises; | |||
const requireAuth = require('../util/requireAuth').requireAuth; | |||
@@ -17,8 +17,8 @@ const generatedIdExists = async id => | |||
await Upload.countDocuments({id: id}) === 1; | |||
const generateId = async () => { | |||
const charset = "abcdefghijklmnopqrstuvwxyz"; | |||
const len = 6; | |||
const charset = config.get('Upload.charset'); | |||
const len = config.get('Upload.idLength'); | |||
const id = [...Array(len)] | |||
.map(() => charset.charAt(Math.floor(Math.random() * charset.length))) | |||
@@ -42,8 +42,7 @@ router.post('/', requireAuth('file.upload'), fileUpload, wrap(async (req, res, n | |||
if (!req.file) | |||
return res.status(400).json({message: 'No file specified.'}); | |||
// Max file size is 128 MiB | |||
if (req.file.size > 1024 * 1024 * 128) { | |||
if (req.file.size > config.get('Upload.maxSize')) { | |||
await fsPromises.unlink(req.file.path); | |||
return res.status(413).json({message: 'File too large.'}); | |||
} | |||
@@ -63,7 +62,7 @@ router.post('/', requireAuth('file.upload'), fileUpload, wrap(async (req, res, n | |||
res.status(200).json({ | |||
id: upload.id, | |||
url: 'https://shimapan.rocks/v/' + upload.id | |||
url: config.get('Server.hostname') + '/v/' + upload.id | |||
}); | |||
})); | |||
@@ -1,5 +1,24 @@ | |||
{ | |||
"dbHost": "mongodb://localhost:27017/shimapan", | |||
"uploadPath": "uploads", | |||
"httpLogLevel": "dev" | |||
"Server": { | |||
"port": 443, | |||
"hostname": "https://shimapan.rocks" | |||
}, | |||
"Database": { | |||
"host": "mongodb://localhost:27017/shimapan" | |||
}, | |||
"Upload": { | |||
"path": "uploads", | |||
"maxSize": 134217728, | |||
"charset": "abcdefghijklmnopqrstuvwxyz", | |||
"idLength": 6 | |||
}, | |||
"User": { | |||
"Username": { | |||
"maxLength": 36, | |||
"restrictedChars": "\\s" | |||
} | |||
}, | |||
"Log": { | |||
"httpLevel": "combined" | |||
} | |||
} |
@@ -1,5 +1,15 @@ | |||
{ | |||
"dbHost": "mongodb://localhost:27017/shimapan", | |||
"uploadPath": "uploads", | |||
"httpLogLevel": "dev" | |||
"Server": { | |||
"port": 8080, | |||
"hostname": "http://localhost:8080" | |||
}, | |||
"Database": { | |||
"host": "mongodb://localhost:27017/shimapan-dev" | |||
}, | |||
"Uploads": { | |||
"path": "uploads-dev" | |||
}, | |||
"Log": { | |||
"httpLevel": "dev" | |||
} | |||
} |
@@ -1,5 +1,15 @@ | |||
{ | |||
"dbHost": "mongodb://localhost:27017/shimapan-test", | |||
"uploadPath": "uploads-test", | |||
"httpLogLevel": "dev" | |||
"Server": { | |||
"port": 8080, | |||
"hostname": "http://localhost:8080" | |||
}, | |||
"Database": { | |||
"host": "mongodb://localhost:27017/shimapan-test" | |||
}, | |||
"Upload": { | |||
"path": "uploads-test" | |||
}, | |||
"Log": { | |||
"httpLevel": "dev" | |||
} | |||
} |
@@ -12,13 +12,19 @@ const app = express(); | |||
const config = require('config'); | |||
// MongoDB | |||
mongoose.connect(config.dbHost, {useNewUrlParser: true}); | |||
const db = mongoose.connection; | |||
const dbHost = config.get('Database.host'); | |||
let db; | |||
mongoose.connect(dbHost, {useNewUrlParser: true}) | |||
.then(() => { | |||
console.log('Connected to mongodb server ' + dbHost); | |||
db = mongoose.connection; | |||
}); | |||
const MongoStore = require('connect-mongo')(session); | |||
const mongoStore = new MongoStore({url: config.dbHost}); | |||
const mongoStore = new MongoStore({url: dbHost}); | |||
// HTTP Request Logging | |||
app.use(morgan(config.httpLogLevel)); | |||
app.use(morgan(config.get('Log.httpLevel'))); | |||
// Session setup | |||
app.use(helmet()); | |||
@@ -62,7 +68,7 @@ app.use((err, req, res, next) => { | |||
}); | |||
// Start app | |||
const port = process.env.PORT || 8080; | |||
const port = config.get('Server.port'); | |||
const server = app.listen(port, () => { | |||
console.log('Listening on port ' + port + '...\n'); | |||
}); | |||
@@ -12,6 +12,8 @@ const Key = require('../app/models/Key.js'); | |||
const util = require('./testUtil.js'); | |||
const canonicalize = require('../app/util/canonicalize').canonicalize; | |||
const config = require('config'); | |||
let app; | |||
let server; | |||
let agent; | |||
@@ -225,7 +227,7 @@ describe('Uploads', () => { | |||
} | |||
async function verifyFailedUpload(file, status, message) { | |||
const fileCountBefore = await util.directoryFileCount('uploads'); | |||
const fileCountBefore = await util.directoryFileCount(config.get('Upload.path')); | |||
const uploadCountBefore = await Upload.countDocuments({}); | |||
const res = await util.upload(file, agent); | |||
@@ -233,7 +235,7 @@ describe('Uploads', () => { | |||
res.body.should.be.a('object'); | |||
res.body.should.have.property('message').equal(message); | |||
const fileCountAfter = await util.directoryFileCount('uploads'); | |||
const fileCountAfter = await util.directoryFileCount(config.get('Upload.path')); | |||
fileCountAfter.should.equal(fileCountBefore, 'File should not have been written to disk'); | |||
const uploadCountAfter = await Upload.countDocuments({}); | |||
@@ -281,7 +283,7 @@ describe('Uploads', () => { | |||
it('SHOULD NOT accept a too large file', async () => { | |||
await Promise.all([ | |||
util.createTestSession(agent), | |||
util.createTestFile(1024 * 1024 * 129, 'large.bin') // 129 MiB, limit is 128 MiB | |||
util.createTestFile(config.get('Upload.maxSize') + 1, 'large.bin') | |||
]); | |||
await verifyFailedUpload('large.bin', 413, 'File too large.'); | |||