mirror of
https://github.com/BobbyWibowo/lolisafe.git
synced 2025-01-19 01:31:34 +00:00
refactor: HUGE REFACTOR for hyper-express
This commit is contained in:
parent
b89945d693
commit
38d86779ae
@ -70,8 +70,7 @@ self.getUniqueRandomName = async () => {
|
|||||||
throw new ServerError('Failed to allocate a unique identifier for the album. Try again?')
|
throw new ServerError('Failed to allocate a unique identifier for the album. Try again?')
|
||||||
}
|
}
|
||||||
|
|
||||||
self.list = (req, res, next) => {
|
self.list = async (req, res) => {
|
||||||
Promise.resolve().then(async () => {
|
|
||||||
const user = await utils.authorize(req)
|
const user = await utils.authorize(req)
|
||||||
|
|
||||||
const all = req.headers.all === '1'
|
const all = req.headers.all === '1'
|
||||||
@ -93,7 +92,9 @@ self.list = (req, res, next) => {
|
|||||||
.where(filter)
|
.where(filter)
|
||||||
.count('id as count')
|
.count('id as count')
|
||||||
.then(rows => rows[0].count)
|
.then(rows => rows[0].count)
|
||||||
if (!count) return res.json({ success: true, albums: [], count })
|
if (!count) {
|
||||||
|
return res.json({ success: true, albums: [], count })
|
||||||
|
}
|
||||||
|
|
||||||
const fields = ['id', 'name']
|
const fields = ['id', 'name']
|
||||||
|
|
||||||
@ -159,7 +160,9 @@ self.list = (req, res, next) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If we are not listing all albums, send response
|
// If we are not listing all albums, send response
|
||||||
if (!all) return res.json({ success: true, albums, count, homeDomain })
|
if (!all) {
|
||||||
|
return res.json({ success: true, albums, count, homeDomain })
|
||||||
|
}
|
||||||
|
|
||||||
// Otherwise proceed to querying usernames
|
// Otherwise proceed to querying usernames
|
||||||
const userids = albums
|
const userids = albums
|
||||||
@ -169,7 +172,9 @@ self.list = (req, res, next) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// If there are no albums attached to a registered user, send response
|
// If there are no albums attached to a registered user, send response
|
||||||
if (!userids.length) return res.json({ success: true, albums, count, homeDomain })
|
if (!userids.length) {
|
||||||
|
return res.json({ success: true, albums, count, homeDomain })
|
||||||
|
}
|
||||||
|
|
||||||
// Query usernames of user IDs from currently selected files
|
// Query usernames of user IDs from currently selected files
|
||||||
const usersTable = await utils.db.table('users')
|
const usersTable = await utils.db.table('users')
|
||||||
@ -181,14 +186,15 @@ self.list = (req, res, next) => {
|
|||||||
users[user.id] = user.username
|
users[user.id] = user.username
|
||||||
}
|
}
|
||||||
|
|
||||||
await res.json({ success: true, albums, count, users, homeDomain })
|
return res.json({ success: true, albums, count, users, homeDomain })
|
||||||
}).catch(next)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.create = (req, res, next) => {
|
self.create = async (req, res) => {
|
||||||
Promise.resolve().then(async resolve => {
|
|
||||||
const user = await utils.authorize(req)
|
const user = await utils.authorize(req)
|
||||||
|
|
||||||
|
// Parse POST body
|
||||||
|
req.body = await req.json()
|
||||||
|
|
||||||
const name = typeof req.body.name === 'string'
|
const name = typeof req.body.name === 'string'
|
||||||
? utils.escape(req.body.name.trim().substring(0, self.titleMaxLength))
|
? utils.escape(req.body.name.trim().substring(0, self.titleMaxLength))
|
||||||
: ''
|
: ''
|
||||||
@ -224,22 +230,26 @@ self.create = (req, res, next) => {
|
|||||||
utils.invalidateStatsCache('albums')
|
utils.invalidateStatsCache('albums')
|
||||||
self.onHold.delete(identifier)
|
self.onHold.delete(identifier)
|
||||||
|
|
||||||
await res.json({ success: true, id: ids[0] })
|
return res.json({ success: true, id: ids[0] })
|
||||||
}).catch(next)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.delete = (req, res, next) => {
|
self.delete = async (req, res) => {
|
||||||
// Map /delete requests to /disable route
|
// Parse POST body and re-map for .disable()
|
||||||
req.body.del = true
|
req.body = await req.json()
|
||||||
return self.disable(req, res, next)
|
.then(obj => {
|
||||||
|
obj.del = true
|
||||||
|
return obj
|
||||||
|
})
|
||||||
|
return self.disable(req, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.disable = (req, res, next) => {
|
self.disable = async (req, res) => {
|
||||||
Promise.resolve().then(async () => {
|
|
||||||
const user = await utils.authorize(req)
|
const user = await utils.authorize(req)
|
||||||
|
|
||||||
const ismoderator = perms.is(user, 'moderator')
|
const ismoderator = perms.is(user, 'moderator')
|
||||||
|
|
||||||
|
// Parse POST body, if required
|
||||||
|
req.body = req.body || await req.json()
|
||||||
|
|
||||||
const id = parseInt(req.body.id)
|
const id = parseInt(req.body.id)
|
||||||
if (isNaN(id)) throw new ClientError('No album specified.')
|
if (isNaN(id)) throw new ClientError('No album specified.')
|
||||||
|
|
||||||
@ -275,7 +285,9 @@ self.disable = (req, res, next) => {
|
|||||||
if (files.length) {
|
if (files.length) {
|
||||||
const ids = files.map(file => file.id)
|
const ids = files.map(file => file.id)
|
||||||
const failed = await utils.bulkDeleteFromDb('id', ids, user)
|
const failed = await utils.bulkDeleteFromDb('id', ids, user)
|
||||||
if (failed.length) return res.json({ success: false, failed })
|
if (failed.length) {
|
||||||
|
return res.json({ success: false, failed })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
utils.invalidateStatsCache('uploads')
|
utils.invalidateStatsCache('uploads')
|
||||||
}
|
}
|
||||||
@ -300,16 +312,17 @@ self.disable = (req, res, next) => {
|
|||||||
// Re-throw non-ENOENT error
|
// Re-throw non-ENOENT error
|
||||||
if (error.code !== 'ENOENT') throw error
|
if (error.code !== 'ENOENT') throw error
|
||||||
}
|
}
|
||||||
await res.json({ success: true })
|
|
||||||
}).catch(next)
|
return res.json({ success: true })
|
||||||
}
|
}
|
||||||
|
|
||||||
self.edit = (req, res, next) => {
|
self.edit = async (req, res) => {
|
||||||
Promise.resolve().then(async () => {
|
|
||||||
const user = await utils.authorize(req)
|
const user = await utils.authorize(req)
|
||||||
|
|
||||||
const ismoderator = perms.is(user, 'moderator')
|
const ismoderator = perms.is(user, 'moderator')
|
||||||
|
|
||||||
|
// Parse POST body, if required
|
||||||
|
req.body = req.body || await req.json()
|
||||||
|
|
||||||
const id = parseInt(req.body.id)
|
const id = parseInt(req.body.id)
|
||||||
if (isNaN(id)) throw new ClientError('No album specified.')
|
if (isNaN(id)) throw new ClientError('No album specified.')
|
||||||
|
|
||||||
@ -396,24 +409,28 @@ self.edit = (req, res, next) => {
|
|||||||
if (error.code !== 'ENOENT') throw error
|
if (error.code !== 'ENOENT') throw error
|
||||||
}
|
}
|
||||||
|
|
||||||
await res.json({
|
return res.json({
|
||||||
success: true,
|
success: true,
|
||||||
identifier: update.identifier
|
identifier: update.identifier
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
await res.json({ success: true, name })
|
return res.json({ success: true, name })
|
||||||
}
|
}
|
||||||
}).catch(next)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.rename = (req, res, next) => {
|
self.rename = async (req, res) => {
|
||||||
req._old = true
|
// Parse POST body and re-map for .edit()
|
||||||
req.body = { name: req.body.name }
|
req.body = await req.json()
|
||||||
return self.edit(req, res, next)
|
.then(obj => {
|
||||||
|
return {
|
||||||
|
_old: true,
|
||||||
|
name: obj.name
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return self.edit(req, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.get = (req, res, next) => {
|
self.get = async (req, res) => {
|
||||||
Promise.resolve().then(async () => {
|
|
||||||
const identifier = req.params.identifier
|
const identifier = req.params.identifier
|
||||||
if (identifier === undefined) {
|
if (identifier === undefined) {
|
||||||
throw new ClientError('No identifier provided.')
|
throw new ClientError('No identifier provided.')
|
||||||
@ -450,7 +467,7 @@ self.get = (req, res, next) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await res.json({
|
return res.json({
|
||||||
success: true,
|
success: true,
|
||||||
description: 'Successfully retrieved files.',
|
description: 'Successfully retrieved files.',
|
||||||
title,
|
title,
|
||||||
@ -458,11 +475,9 @@ self.get = (req, res, next) => {
|
|||||||
count: files.length,
|
count: files.length,
|
||||||
files
|
files
|
||||||
})
|
})
|
||||||
}).catch(next)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.generateZip = (req, res, next) => {
|
self.generateZip = async (req, res) => {
|
||||||
Promise.resolve().then(async () => {
|
|
||||||
const versionString = parseInt(req.query.v)
|
const versionString = parseInt(req.query.v)
|
||||||
|
|
||||||
const identifier = req.params.identifier
|
const identifier = req.params.identifier
|
||||||
@ -575,11 +590,10 @@ self.generateZip = (req, res, next) => {
|
|||||||
const fileName = `${album.name}.zip`
|
const fileName = `${album.name}.zip`
|
||||||
|
|
||||||
self.zipEmitters.get(identifier).emit('done', filePath, fileName)
|
self.zipEmitters.get(identifier).emit('done', filePath, fileName)
|
||||||
await res.download(filePath, fileName)
|
return res.download(filePath, fileName)
|
||||||
}).catch(next)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.listFiles = (req, res, next) => {
|
self.listFiles = async (req, res) => {
|
||||||
if (req.params.page === undefined) {
|
if (req.params.page === undefined) {
|
||||||
// Map to /api/album/get, but with lolisafe upstream compatibility, when accessed with this API route
|
// Map to /api/album/get, but with lolisafe upstream compatibility, when accessed with this API route
|
||||||
req.params.identifier = req.params.id
|
req.params.identifier = req.params.id
|
||||||
@ -609,27 +623,29 @@ self.listFiles = (req, res, next) => {
|
|||||||
if (rebuild.message) rebuild.message = rebuild.message.replace(/\.$/, '')
|
if (rebuild.message) rebuild.message = rebuild.message.replace(/\.$/, '')
|
||||||
return res._json(rebuild)
|
return res._json(rebuild)
|
||||||
}
|
}
|
||||||
return self.get(req, res, next)
|
return self.get(req, res)
|
||||||
} else {
|
} else {
|
||||||
return uploadController.list(req, res, next)
|
return uploadController.list(req, res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.addFiles = (req, res, next) => {
|
self.addFiles = async (req, res) => {
|
||||||
let ids, albumid, failed, albumids
|
|
||||||
return Promise.resolve().then(async () => {
|
|
||||||
const user = await utils.authorize(req)
|
const user = await utils.authorize(req)
|
||||||
|
|
||||||
ids = req.body.ids
|
// Parse POST body
|
||||||
|
req.body = await req.json()
|
||||||
|
|
||||||
|
const ids = req.body.ids
|
||||||
if (!Array.isArray(ids) || !ids.length) {
|
if (!Array.isArray(ids) || !ids.length) {
|
||||||
throw new ClientError('No files specified.')
|
throw new ClientError('No files specified.')
|
||||||
}
|
}
|
||||||
|
|
||||||
albumid = parseInt(req.body.albumid)
|
let albumid = parseInt(req.body.albumid)
|
||||||
if (isNaN(albumid) || albumid < 0) albumid = null
|
if (isNaN(albumid) || albumid < 0) albumid = null
|
||||||
|
|
||||||
failed = []
|
const failed = []
|
||||||
albumids = []
|
const albumids = []
|
||||||
|
return Promise.resolve().then(async () => {
|
||||||
if (albumid !== null) {
|
if (albumid !== null) {
|
||||||
const album = await utils.db.table('albums')
|
const album = await utils.db.table('albums')
|
||||||
.where('id', albumid)
|
.where('id', albumid)
|
||||||
@ -651,7 +667,7 @@ self.addFiles = (req, res, next) => {
|
|||||||
.whereIn('id', ids)
|
.whereIn('id', ids)
|
||||||
.where('userid', user.id)
|
.where('userid', user.id)
|
||||||
|
|
||||||
failed = ids.filter(id => !files.find(file => file.id === id))
|
failed.push(...ids.filter(id => !files.find(file => file.id === id)))
|
||||||
|
|
||||||
await utils.db.table('files')
|
await utils.db.table('files')
|
||||||
.whereIn('id', files.map(file => file.id))
|
.whereIn('id', files.map(file => file.id))
|
||||||
@ -669,13 +685,12 @@ self.addFiles = (req, res, next) => {
|
|||||||
.update('editedAt', Math.floor(Date.now() / 1000))
|
.update('editedAt', Math.floor(Date.now() / 1000))
|
||||||
utils.deleteStoredAlbumRenders(albumids)
|
utils.deleteStoredAlbumRenders(albumids)
|
||||||
|
|
||||||
await res.json({ success: true, failed })
|
return res.json({ success: true, failed })
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
if (Array.isArray(failed) && (failed.length === ids.length)) {
|
if (Array.isArray(failed) && (failed.length === ids.length)) {
|
||||||
return next(new ServerError(`Could not ${albumid === null ? 'add' : 'remove'} any files ${albumid === null ? 'to' : 'from'} the album.`))
|
throw new ServerError(`Could not ${albumid === null ? 'add' : 'remove'} any files ${albumid === null ? 'to' : 'from'} the album.`)
|
||||||
} else {
|
|
||||||
return next(error)
|
|
||||||
}
|
}
|
||||||
|
throw error
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,8 +30,10 @@ const self = {
|
|||||||
// https://github.com/kelektiv/node.bcrypt.js/tree/v5.0.1#a-note-on-rounds
|
// https://github.com/kelektiv/node.bcrypt.js/tree/v5.0.1#a-note-on-rounds
|
||||||
const saltRounds = 10
|
const saltRounds = 10
|
||||||
|
|
||||||
self.verify = (req, res, next) => {
|
self.verify = async (req, res) => {
|
||||||
Promise.resolve().then(async () => {
|
// Parse POST body
|
||||||
|
req.body = await req.json()
|
||||||
|
|
||||||
const username = typeof req.body.username === 'string'
|
const username = typeof req.body.username === 'string'
|
||||||
? req.body.username.trim()
|
? req.body.username.trim()
|
||||||
: ''
|
: ''
|
||||||
@ -56,13 +58,14 @@ self.verify = (req, res, next) => {
|
|||||||
if (result === false) {
|
if (result === false) {
|
||||||
throw new ClientError('Wrong credentials.', { statusCode: 403 })
|
throw new ClientError('Wrong credentials.', { statusCode: 403 })
|
||||||
} else {
|
} else {
|
||||||
await res.json({ success: true, token: user.token })
|
return res.json({ success: true, token: user.token })
|
||||||
}
|
}
|
||||||
}).catch(next)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.register = (req, res, next) => {
|
self.register = async (req, res) => {
|
||||||
Promise.resolve().then(async () => {
|
// Parse POST body
|
||||||
|
req.body = await req.json()
|
||||||
|
|
||||||
if (config.enableUserAccounts === false) {
|
if (config.enableUserAccounts === false) {
|
||||||
throw new ClientError('Registration is currently disabled.', { statusCode: 403 })
|
throw new ClientError('Registration is currently disabled.', { statusCode: 403 })
|
||||||
}
|
}
|
||||||
@ -106,14 +109,15 @@ self.register = (req, res, next) => {
|
|||||||
utils.invalidateStatsCache('users')
|
utils.invalidateStatsCache('users')
|
||||||
tokens.onHold.delete(token)
|
tokens.onHold.delete(token)
|
||||||
|
|
||||||
await res.json({ success: true, token })
|
return res.json({ success: true, token })
|
||||||
}).catch(next)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.changePassword = (req, res, next) => {
|
self.changePassword = async (req, res) => {
|
||||||
Promise.resolve().then(async () => {
|
|
||||||
const user = await utils.authorize(req)
|
const user = await utils.authorize(req)
|
||||||
|
|
||||||
|
// Parse POST body
|
||||||
|
req.body = await req.json()
|
||||||
|
|
||||||
const password = typeof req.body.password === 'string'
|
const password = typeof req.body.password === 'string'
|
||||||
? req.body.password.trim()
|
? req.body.password.trim()
|
||||||
: ''
|
: ''
|
||||||
@ -127,8 +131,7 @@ self.changePassword = (req, res, next) => {
|
|||||||
.where('id', user.id)
|
.where('id', user.id)
|
||||||
.update('password', hash)
|
.update('password', hash)
|
||||||
|
|
||||||
await res.json({ success: true })
|
return res.json({ success: true })
|
||||||
}).catch(next)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.assertPermission = (user, target) => {
|
self.assertPermission = (user, target) => {
|
||||||
@ -141,10 +144,12 @@ self.assertPermission = (user, target) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.createUser = (req, res, next) => {
|
self.createUser = async (req, res) => {
|
||||||
Promise.resolve().then(async () => {
|
|
||||||
const user = await utils.authorize(req)
|
const user = await utils.authorize(req)
|
||||||
|
|
||||||
|
// Parse POST body
|
||||||
|
req.body = await req.json()
|
||||||
|
|
||||||
const isadmin = perms.is(user, 'admin')
|
const isadmin = perms.is(user, 'admin')
|
||||||
if (!isadmin) return res.status(403).end()
|
if (!isadmin) return res.status(403).end()
|
||||||
|
|
||||||
@ -201,14 +206,15 @@ self.createUser = (req, res, next) => {
|
|||||||
utils.invalidateStatsCache('users')
|
utils.invalidateStatsCache('users')
|
||||||
tokens.onHold.delete(token)
|
tokens.onHold.delete(token)
|
||||||
|
|
||||||
await res.json({ success: true, username, password, group })
|
return res.json({ success: true, username, password, group })
|
||||||
}).catch(next)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.editUser = (req, res, next) => {
|
self.editUser = async (req, res) => {
|
||||||
Promise.resolve().then(async () => {
|
|
||||||
const user = await utils.authorize(req)
|
const user = await utils.authorize(req)
|
||||||
|
|
||||||
|
// Parse POST body, if required
|
||||||
|
req.body = req.body || await req.json()
|
||||||
|
|
||||||
const isadmin = perms.is(user, 'admin')
|
const isadmin = perms.is(user, 'admin')
|
||||||
if (!isadmin) throw new ClientError('', { statusCode: 403 })
|
if (!isadmin) throw new ClientError('', { statusCode: 403 })
|
||||||
|
|
||||||
@ -252,20 +258,31 @@ self.editUser = (req, res, next) => {
|
|||||||
utils.invalidateStatsCache('users')
|
utils.invalidateStatsCache('users')
|
||||||
|
|
||||||
const response = { success: true, update }
|
const response = { success: true, update }
|
||||||
if (password) response.update.password = password
|
if (password) {
|
||||||
await res.json(response)
|
response.update.password = password
|
||||||
}).catch(next)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.disableUser = (req, res, next) => {
|
return res.json(response)
|
||||||
req.body = { id: req.body.id, enabled: false }
|
|
||||||
return self.editUser(req, res, next)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.deleteUser = (req, res, next) => {
|
self.disableUser = async (req, res) => {
|
||||||
Promise.resolve().then(async () => {
|
// Parse POST body and re-map for .editUser()
|
||||||
|
req.body = await req.json()
|
||||||
|
.then(obj => {
|
||||||
|
return {
|
||||||
|
id: obj.id,
|
||||||
|
enabled: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return self.editUser(req, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.deleteUser = async (req, res) => {
|
||||||
const user = await utils.authorize(req)
|
const user = await utils.authorize(req)
|
||||||
|
|
||||||
|
// Parse POST body
|
||||||
|
req.body = await req.json()
|
||||||
|
|
||||||
const isadmin = perms.is(user, 'admin')
|
const isadmin = perms.is(user, 'admin')
|
||||||
if (!isadmin) throw new ClientError('', { statusCode: 403 })
|
if (!isadmin) throw new ClientError('', { statusCode: 403 })
|
||||||
|
|
||||||
@ -286,8 +303,10 @@ self.deleteUser = (req, res, next) => {
|
|||||||
const fileids = files.map(file => file.id)
|
const fileids = files.map(file => file.id)
|
||||||
if (purge) {
|
if (purge) {
|
||||||
const failed = await utils.bulkDeleteFromDb('id', fileids, user)
|
const failed = await utils.bulkDeleteFromDb('id', fileids, user)
|
||||||
if (failed.length) return res.json({ success: false, failed })
|
|
||||||
utils.invalidateStatsCache('uploads')
|
utils.invalidateStatsCache('uploads')
|
||||||
|
if (failed.length) {
|
||||||
|
return res.json({ success: false, failed })
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Clear out userid attribute from the files
|
// Clear out userid attribute from the files
|
||||||
await utils.db.table('files')
|
await utils.db.table('files')
|
||||||
@ -324,16 +343,14 @@ self.deleteUser = (req, res, next) => {
|
|||||||
.del()
|
.del()
|
||||||
utils.invalidateStatsCache('users')
|
utils.invalidateStatsCache('users')
|
||||||
|
|
||||||
await res.json({ success: true })
|
return res.json({ success: true })
|
||||||
}).catch(next)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.bulkDeleteUsers = (req, res, next) => {
|
self.bulkDeleteUsers = async (req, res) => {
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
self.listUsers = (req, res, next) => {
|
self.listUsers = async (req, res) => {
|
||||||
Promise.resolve().then(async () => {
|
|
||||||
const user = await utils.authorize(req)
|
const user = await utils.authorize(req)
|
||||||
|
|
||||||
const isadmin = perms.is(user, 'admin')
|
const isadmin = perms.is(user, 'admin')
|
||||||
@ -342,7 +359,9 @@ self.listUsers = (req, res, next) => {
|
|||||||
const count = await utils.db.table('users')
|
const count = await utils.db.table('users')
|
||||||
.count('id as count')
|
.count('id as count')
|
||||||
.then(rows => rows[0].count)
|
.then(rows => rows[0].count)
|
||||||
if (!count) return res.json({ success: true, users: [], count })
|
if (!count) {
|
||||||
|
return res.json({ success: true, users: [], count })
|
||||||
|
}
|
||||||
|
|
||||||
let offset = Number(req.params.page)
|
let offset = Number(req.params.page)
|
||||||
if (isNaN(offset)) offset = 0
|
if (isNaN(offset)) offset = 0
|
||||||
@ -371,8 +390,7 @@ self.listUsers = (req, res, next) => {
|
|||||||
pointers[upload.userid].usage += parseInt(upload.size)
|
pointers[upload.userid].usage += parseInt(upload.size)
|
||||||
}
|
}
|
||||||
|
|
||||||
await res.json({ success: true, users, count })
|
return res.json({ success: true, users, count })
|
||||||
}).catch(next)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = self
|
module.exports = self
|
||||||
|
@ -2,8 +2,8 @@ const path = require('path')
|
|||||||
const paths = require('./pathsController')
|
const paths = require('./pathsController')
|
||||||
const ClientError = require('./utils/ClientError')
|
const ClientError = require('./utils/ClientError')
|
||||||
const ServerError = require('./utils/ServerError')
|
const ServerError = require('./utils/ServerError')
|
||||||
const config = require('./../config')
|
const config = require('../config')
|
||||||
const logger = require('./../logger')
|
const logger = require('../logger')
|
||||||
|
|
||||||
const self = {
|
const self = {
|
||||||
errorPagesCodes: Object.keys(config.errorPages)
|
errorPagesCodes: Object.keys(config.errorPages)
|
||||||
@ -11,7 +11,7 @@ const self = {
|
|||||||
.map(key => Number(key))
|
.map(key => Number(key))
|
||||||
}
|
}
|
||||||
|
|
||||||
self.handle = (error, req, res, next) => {
|
self.handlerError = (req, res, error) => {
|
||||||
if (!res || res.headersSent) {
|
if (!res || res.headersSent) {
|
||||||
console.error('Unexpected missing "res" object or headers alredy sent.')
|
console.error('Unexpected missing "res" object or headers alredy sent.')
|
||||||
return console.trace()
|
return console.trace()
|
||||||
@ -58,7 +58,7 @@ self.handle = (error, req, res, next) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.handleMissing = (req, res, next) => {
|
self.handlerNotFound = (req, res) => {
|
||||||
res.setHeader('Cache-Control', 'no-store')
|
res.setHeader('Cache-Control', 'no-store')
|
||||||
return res.status(404).sendFile(path.join(paths.errorRoot, config.errorPages[404]))
|
return res.status(404).sendFile(path.join(paths.errorRoot, config.errorPages[404]))
|
||||||
}
|
}
|
||||||
|
@ -33,8 +33,10 @@ self.generateUniqueToken = async () => {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
self.verify = (req, res, next) => {
|
self.verify = async (req, res) => {
|
||||||
Promise.resolve().then(async () => {
|
// Parse POST body
|
||||||
|
req.body = await req.json()
|
||||||
|
|
||||||
const token = typeof req.body.token === 'string'
|
const token = typeof req.body.token === 'string'
|
||||||
? req.body.token.trim()
|
? req.body.token.trim()
|
||||||
: ''
|
: ''
|
||||||
@ -69,19 +71,15 @@ self.verify = (req, res, next) => {
|
|||||||
obj.version = utils.clientVersion
|
obj.version = utils.clientVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
await res.json(obj)
|
return res.json(obj)
|
||||||
}).catch(next)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.list = (req, res, next) => {
|
self.list = async (req, res) => {
|
||||||
Promise.resolve().then(async () => {
|
|
||||||
const user = await utils.authorize(req)
|
const user = await utils.authorize(req)
|
||||||
await res.json({ success: true, token: user.token })
|
return res.json({ success: true, token: user.token })
|
||||||
}).catch(next)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.change = (req, res, next) => {
|
self.change = async (req, res) => {
|
||||||
Promise.resolve().then(async () => {
|
|
||||||
const user = await utils.authorize(req, 'token')
|
const user = await utils.authorize(req, 'token')
|
||||||
|
|
||||||
const newToken = await self.generateUniqueToken()
|
const newToken = await self.generateUniqueToken()
|
||||||
@ -97,8 +95,7 @@ self.change = (req, res, next) => {
|
|||||||
})
|
})
|
||||||
self.onHold.delete(newToken)
|
self.onHold.delete(newToken)
|
||||||
|
|
||||||
await res.json({ success: true, token: newToken })
|
return res.json({ success: true, token: newToken })
|
||||||
}).catch(next)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = self
|
module.exports = self
|
||||||
|
@ -108,6 +108,7 @@ const executeMulter = multer({
|
|||||||
// and that will also be as a chunk.
|
// and that will also be as a chunk.
|
||||||
files: maxFilesPerUpload
|
files: maxFilesPerUpload
|
||||||
},
|
},
|
||||||
|
|
||||||
fileFilter (req, file, cb) {
|
fileFilter (req, file, cb) {
|
||||||
// BUG: Since multer@1.4.5-lts.1, UTF-8 filenames are not handled properly, so we force it
|
// BUG: Since multer@1.4.5-lts.1, UTF-8 filenames are not handled properly, so we force it
|
||||||
file.originalname = file.originalname &&
|
file.originalname = file.originalname &&
|
||||||
@ -120,7 +121,7 @@ const executeMulter = multer({
|
|||||||
|
|
||||||
// Re-map Dropzone chunked uploads keys so people can manually use the API without prepending 'dz'
|
// Re-map Dropzone chunked uploads keys so people can manually use the API without prepending 'dz'
|
||||||
for (const key in req.body) {
|
for (const key in req.body) {
|
||||||
if (!/^dz/.test(key)) continue
|
if (!key.startsWith('dz')) continue
|
||||||
req.body[key.replace(/^dz/, '')] = req.body[key]
|
req.body[key.replace(/^dz/, '')] = req.body[key]
|
||||||
delete req.body[key]
|
delete req.body[key]
|
||||||
}
|
}
|
||||||
@ -131,6 +132,7 @@ const executeMulter = multer({
|
|||||||
return cb(null, true)
|
return cb(null, true)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
storage: multerStorage({
|
storage: multerStorage({
|
||||||
destination (req, file, cb) {
|
destination (req, file, cb) {
|
||||||
// Is file a chunk!?
|
// Is file a chunk!?
|
||||||
@ -272,10 +274,9 @@ self.parseStripTags = stripTags => {
|
|||||||
return Boolean(parseInt(stripTags))
|
return Boolean(parseInt(stripTags))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Uploads */
|
/** File uploads */
|
||||||
|
|
||||||
self.upload = (req, res, next) => {
|
self.upload = async (req, res) => {
|
||||||
Promise.resolve().then(async () => {
|
|
||||||
let user
|
let user
|
||||||
if (config.private === true) {
|
if (config.private === true) {
|
||||||
user = await utils.authorize(req)
|
user = await utils.authorize(req)
|
||||||
@ -294,29 +295,34 @@ self.upload = (req, res, next) => {
|
|||||||
|
|
||||||
const age = self.assertRetentionPeriod(user, req.headers.age)
|
const age = self.assertRetentionPeriod(user, req.headers.age)
|
||||||
|
|
||||||
const func = req.body.urls ? self.actuallyUploadUrls : self.actuallyUploadFiles
|
const multerError = await new Promise(resolve => {
|
||||||
await func(req, res, user, albumid, age)
|
|
||||||
}).catch(next)
|
|
||||||
}
|
|
||||||
|
|
||||||
self.actuallyUploadFiles = async (req, res, user, albumid, age) => {
|
|
||||||
const error = await new Promise(resolve => {
|
|
||||||
req._user = user
|
req._user = user
|
||||||
return executeMulter(req, res, err => resolve(err))
|
return executeMulter(req, res, err => resolve(err))
|
||||||
}).finally(() => delete req._user)
|
}).finally(() => delete req._user)
|
||||||
|
|
||||||
if (error) {
|
if (multerError) {
|
||||||
const suppress = [
|
const suppress = [
|
||||||
'LIMIT_FILE_SIZE',
|
'LIMIT_FILE_SIZE',
|
||||||
'LIMIT_UNEXPECTED_FILE'
|
'LIMIT_UNEXPECTED_FILE'
|
||||||
]
|
]
|
||||||
if (suppress.includes(error.code)) {
|
if (suppress.includes(multerError.code)) {
|
||||||
throw new ClientError(error.toString())
|
throw new ClientError(multerError.toString())
|
||||||
} else {
|
} else {
|
||||||
throw error
|
throw multerError
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If req.files is unset, then Multer did not encounter any files
|
||||||
|
if (req.files === undefined) {
|
||||||
|
// Parse POST body
|
||||||
|
req.body = await req.json()
|
||||||
|
return self.actuallyUploadUrls(req, res, user, albumid, age)
|
||||||
|
} else {
|
||||||
|
return self.actuallyUpload(req, res, user, albumid, age)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.actuallyUpload = async (req, res, user, albumid, age) => {
|
||||||
if (!req.files || !req.files.length) {
|
if (!req.files || !req.files.length) {
|
||||||
throw new ClientError('No files.')
|
throw new ClientError('No files.')
|
||||||
}
|
}
|
||||||
@ -397,11 +403,7 @@ self.actuallyUploadUrls = async (req, res, user, albumid, age) => {
|
|||||||
|
|
||||||
const downloaded = []
|
const downloaded = []
|
||||||
const infoMap = []
|
const infoMap = []
|
||||||
try {
|
|
||||||
await Promise.all(urls.map(async url => {
|
await Promise.all(urls.map(async url => {
|
||||||
let outStream
|
|
||||||
let hasher
|
|
||||||
try {
|
|
||||||
const original = path.basename(url).split(/[?#]/)[0]
|
const original = path.basename(url).split(/[?#]/)[0]
|
||||||
const extname = utils.extname(original)
|
const extname = utils.extname(original)
|
||||||
|
|
||||||
@ -446,6 +448,10 @@ self.actuallyUploadUrls = async (req, res, user, albumid, age) => {
|
|||||||
const name = await self.getUniqueRandomName(length, extname)
|
const name = await self.getUniqueRandomName(length, extname)
|
||||||
|
|
||||||
const destination = path.join(paths.uploads, name)
|
const destination = path.join(paths.uploads, name)
|
||||||
|
|
||||||
|
let outStream
|
||||||
|
let hasher
|
||||||
|
return Promise.resolve().then(async () => {
|
||||||
outStream = fs.createWriteStream(destination)
|
outStream = fs.createWriteStream(destination)
|
||||||
hasher = blake3.createHash()
|
hasher = blake3.createHash()
|
||||||
|
|
||||||
@ -488,7 +494,7 @@ self.actuallyUploadUrls = async (req, res, user, albumid, age) => {
|
|||||||
age
|
age
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} catch (err) {
|
}).catch(err => {
|
||||||
// Dispose of unfinished write & hasher streams
|
// Dispose of unfinished write & hasher streams
|
||||||
if (outStream && !outStream.destroyed) {
|
if (outStream && !outStream.destroyed) {
|
||||||
outStream.destroy()
|
outStream.destroy()
|
||||||
@ -501,20 +507,8 @@ self.actuallyUploadUrls = async (req, res, user, albumid, age) => {
|
|||||||
|
|
||||||
// Re-throw errors
|
// Re-throw errors
|
||||||
throw err
|
throw err
|
||||||
}
|
})
|
||||||
}))
|
})).catch(async error => {
|
||||||
|
|
||||||
// If no errors encountered, clear cache of downloaded files
|
|
||||||
downloaded.length = 0
|
|
||||||
|
|
||||||
if (utils.scan.instance) {
|
|
||||||
const scanResult = await self.scanFiles(req, user, infoMap)
|
|
||||||
if (scanResult) throw new ClientError(scanResult)
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await self.storeFilesToDb(req, res, user, infoMap)
|
|
||||||
await self.sendUploadResponse(req, res, user, result)
|
|
||||||
} catch (error) {
|
|
||||||
// Unlink all downloaded files when at least one file threw an error from the for-loop
|
// Unlink all downloaded files when at least one file threw an error from the for-loop
|
||||||
// Should continue even when encountering errors
|
// Should continue even when encountering errors
|
||||||
if (downloaded.length) {
|
if (downloaded.length) {
|
||||||
@ -523,6 +517,7 @@ self.actuallyUploadUrls = async (req, res, user, albumid, age) => {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Re-throw suppressed errors as ClientError, otherwise as-is
|
||||||
const errorString = error.toString()
|
const errorString = error.toString()
|
||||||
const suppress = [
|
const suppress = [
|
||||||
/ over limit:/
|
/ over limit:/
|
||||||
@ -532,13 +527,20 @@ self.actuallyUploadUrls = async (req, res, user, albumid, age) => {
|
|||||||
} else {
|
} else {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (utils.scan.instance) {
|
||||||
|
const scanResult = await self.scanFiles(req, user, infoMap)
|
||||||
|
if (scanResult) throw new ClientError(scanResult)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const result = await self.storeFilesToDb(req, res, user, infoMap)
|
||||||
|
return self.sendUploadResponse(req, res, user, result)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Chunk uploads */
|
/** Chunk uploads */
|
||||||
|
|
||||||
self.finishChunks = (req, res, next) => {
|
self.finishChunks = async (req, res) => {
|
||||||
Promise.resolve().then(async () => {
|
|
||||||
if (!chunkedUploads) {
|
if (!chunkedUploads) {
|
||||||
throw new ClientError('Chunked upload is disabled.', { statusCode: 403 })
|
throw new ClientError('Chunked upload is disabled.', { statusCode: 403 })
|
||||||
}
|
}
|
||||||
@ -551,18 +553,29 @@ self.finishChunks = (req, res, next) => {
|
|||||||
user = await utils.assertUser(req.headers.token)
|
user = await utils.assertUser(req.headers.token)
|
||||||
}
|
}
|
||||||
|
|
||||||
await self.actuallyFinishChunks(req, res, user)
|
// Parse POST body
|
||||||
}).catch(next)
|
req.body = await req.json()
|
||||||
}
|
|
||||||
|
|
||||||
self.actuallyFinishChunks = async (req, res, user) => {
|
|
||||||
const files = req.body.files
|
const files = req.body.files
|
||||||
if (!Array.isArray(files) || !files.length) {
|
if (!Array.isArray(files) || !files.length) {
|
||||||
throw new ClientError('Bad request.')
|
throw new ClientError('Bad request.')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return self.actuallyFinishChunks(req, res, user, files)
|
||||||
|
.catch(error => {
|
||||||
|
// Should continue even when encountering errors
|
||||||
|
files.forEach(file => {
|
||||||
|
if (file.uuid && chunksData[file.uuid]) {
|
||||||
|
self.cleanUpChunks(file.uuid).catch(logger.error)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// Re-throw errors
|
||||||
|
throw error
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
self.actuallyFinishChunks = async (req, res, user, files) => {
|
||||||
const infoMap = []
|
const infoMap = []
|
||||||
try {
|
|
||||||
await Promise.all(files.map(async file => {
|
await Promise.all(files.map(async file => {
|
||||||
if (!file.uuid || typeof chunksData[file.uuid] === 'undefined') {
|
if (!file.uuid || typeof chunksData[file.uuid] === 'undefined') {
|
||||||
throw new ClientError('Invalid file UUID, or chunks data had already timed out. Try again?')
|
throw new ClientError('Invalid file UUID, or chunks data had already timed out. Try again?')
|
||||||
@ -642,18 +655,7 @@ self.actuallyFinishChunks = async (req, res, user) => {
|
|||||||
await self.stripTags(req, infoMap)
|
await self.stripTags(req, infoMap)
|
||||||
|
|
||||||
const result = await self.storeFilesToDb(req, res, user, infoMap)
|
const result = await self.storeFilesToDb(req, res, user, infoMap)
|
||||||
await self.sendUploadResponse(req, res, user, result)
|
return self.sendUploadResponse(req, res, user, result)
|
||||||
} catch (error) {
|
|
||||||
// Should continue even when encountering errors
|
|
||||||
files.forEach(file => {
|
|
||||||
if (file.uuid && chunksData[file.uuid]) {
|
|
||||||
self.cleanUpChunks(file.uuid).catch(logger.error)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Re-throw error
|
|
||||||
throw error
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.cleanUpChunks = async uuid => {
|
self.cleanUpChunks = async uuid => {
|
||||||
@ -963,26 +965,27 @@ self.sendUploadResponse = async (req, res, user, result) => {
|
|||||||
|
|
||||||
/** Delete uploads */
|
/** Delete uploads */
|
||||||
|
|
||||||
self.delete = async (req, res, next) => {
|
self.delete = async (req, res) => {
|
||||||
// Map /api/delete requests to /api/bulkdelete
|
// Parse POST body and re-map for .bulkDelete()
|
||||||
let body
|
// Original API used by lolisafe v3's frontend
|
||||||
if (req.method === 'POST') {
|
// Meanwhile this fork's frontend uses .bulkDelete() straight away
|
||||||
// Original lolisafe API (this fork uses /api/bulkdelete immediately)
|
req.body = await req.json()
|
||||||
const id = parseInt(req.body.id)
|
.then(obj => {
|
||||||
body = {
|
const id = parseInt(obj.id)
|
||||||
|
return {
|
||||||
field: 'id',
|
field: 'id',
|
||||||
values: isNaN(id) ? undefined : [id]
|
values: isNaN(id) ? undefined : [id]
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
return self.bulkDelete(req, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
req.body = body
|
self.bulkDelete = async (req, res) => {
|
||||||
return self.bulkDelete(req, res, next)
|
|
||||||
}
|
|
||||||
|
|
||||||
self.bulkDelete = (req, res, next) => {
|
|
||||||
Promise.resolve().then(async () => {
|
|
||||||
const user = await utils.authorize(req)
|
const user = await utils.authorize(req)
|
||||||
|
|
||||||
|
// Parse POST body, if required
|
||||||
|
req.body = req.body || await req.json()
|
||||||
|
|
||||||
const field = req.body.field || 'id'
|
const field = req.body.field || 'id'
|
||||||
const values = req.body.values
|
const values = req.body.values
|
||||||
|
|
||||||
@ -991,14 +994,13 @@ self.bulkDelete = (req, res, next) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const failed = await utils.bulkDeleteFromDb(field, values, user)
|
const failed = await utils.bulkDeleteFromDb(field, values, user)
|
||||||
await res.json({ success: true, failed })
|
|
||||||
}).catch(next)
|
return res.json({ success: true, failed })
|
||||||
}
|
}
|
||||||
|
|
||||||
/** List uploads */
|
/** List uploads */
|
||||||
|
|
||||||
self.list = (req, res, next) => {
|
self.list = async (req, res) => {
|
||||||
Promise.resolve().then(async () => {
|
|
||||||
const user = await utils.authorize(req)
|
const user = await utils.authorize(req)
|
||||||
|
|
||||||
const all = req.headers.all === '1'
|
const all = req.headers.all === '1'
|
||||||
@ -1479,7 +1481,9 @@ self.list = (req, res, next) => {
|
|||||||
.where(filter)
|
.where(filter)
|
||||||
.count('id as count')
|
.count('id as count')
|
||||||
.then(rows => rows[0].count)
|
.then(rows => rows[0].count)
|
||||||
if (!count) return res.json({ success: true, files: [], count })
|
if (!count) {
|
||||||
|
return res.json({ success: true, files: [], count })
|
||||||
|
}
|
||||||
|
|
||||||
let offset = Number(req.params.page)
|
let offset = Number(req.params.page)
|
||||||
if (isNaN(offset)) offset = 0
|
if (isNaN(offset)) offset = 0
|
||||||
@ -1517,7 +1521,9 @@ self.list = (req, res, next) => {
|
|||||||
.offset(25 * offset)
|
.offset(25 * offset)
|
||||||
.select(columns)
|
.select(columns)
|
||||||
|
|
||||||
if (!files.length) return res.json({ success: true, files, count, basedomain })
|
if (!files.length) {
|
||||||
|
return res.json({ success: true, files, count, basedomain })
|
||||||
|
}
|
||||||
|
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
file.extname = utils.extname(file.name)
|
file.extname = utils.extname(file.name)
|
||||||
@ -1549,7 +1555,9 @@ self.list = (req, res, next) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If we are not listing all uploads, send response
|
// If we are not listing all uploads, send response
|
||||||
if (!all) return res.json({ success: true, files, count, albums, basedomain })
|
if (!all) {
|
||||||
|
return res.json({ success: true, files, count, albums, basedomain })
|
||||||
|
}
|
||||||
|
|
||||||
// Otherwise proceed to querying usernames
|
// Otherwise proceed to querying usernames
|
||||||
let usersTable = filterObj.uploaders
|
let usersTable = filterObj.uploaders
|
||||||
@ -1561,7 +1569,9 @@ self.list = (req, res, next) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// If there are no uploads attached to a registered user, send response
|
// If there are no uploads attached to a registered user, send response
|
||||||
if (!userids.length) return res.json({ success: true, files, count, albums, basedomain })
|
if (!userids.length) {
|
||||||
|
return res.json({ success: true, files, count, albums, basedomain })
|
||||||
|
}
|
||||||
|
|
||||||
// Query usernames of user IDs from currently selected files
|
// Query usernames of user IDs from currently selected files
|
||||||
usersTable = await utils.db.table('users')
|
usersTable = await utils.db.table('users')
|
||||||
@ -1574,14 +1584,12 @@ self.list = (req, res, next) => {
|
|||||||
users[user.id] = user.username
|
users[user.id] = user.username
|
||||||
}
|
}
|
||||||
|
|
||||||
await res.json({ success: true, files, count, users, albums, basedomain })
|
return res.json({ success: true, files, count, users, albums, basedomain })
|
||||||
}).catch(next)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get file info */
|
/** Get file info */
|
||||||
|
|
||||||
self.get = (req, res, next) => {
|
self.get = async (req, res) => {
|
||||||
Promise.resolve().then(async () => {
|
|
||||||
const user = await utils.authorize(req)
|
const user = await utils.authorize(req)
|
||||||
const ismoderator = perms.is(user, 'moderator')
|
const ismoderator = perms.is(user, 'moderator')
|
||||||
|
|
||||||
@ -1603,8 +1611,7 @@ self.get = (req, res, next) => {
|
|||||||
throw new ClientError('File not found.', { statusCode: 404 })
|
throw new ClientError('File not found.', { statusCode: 404 })
|
||||||
}
|
}
|
||||||
|
|
||||||
await res.json({ success: true, file })
|
return res.json({ success: true, file })
|
||||||
}).catch(next)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = self
|
module.exports = self
|
||||||
|
@ -784,8 +784,7 @@ self.invalidateStatsCache = type => {
|
|||||||
statsData[type].cache = null
|
statsData[type].cache = null
|
||||||
}
|
}
|
||||||
|
|
||||||
self.stats = (req, res, next) => {
|
const generateStats = async (req, res) => {
|
||||||
Promise.resolve().then(async () => {
|
|
||||||
const user = await self.authorize(req)
|
const user = await self.authorize(req)
|
||||||
|
|
||||||
const isadmin = perms.is(user, 'admin')
|
const isadmin = perms.is(user, 'admin')
|
||||||
@ -1091,12 +1090,17 @@ self.stats = (req, res, next) => {
|
|||||||
])
|
])
|
||||||
|
|
||||||
return res.json({ success: true, stats, hrtime: process.hrtime(hrstart) })
|
return res.json({ success: true, stats, hrtime: process.hrtime(hrstart) })
|
||||||
}).catch(error => {
|
}
|
||||||
|
|
||||||
|
self.stats = async (req, res) => {
|
||||||
|
return generateStats(req, res)
|
||||||
|
.catch(error => {
|
||||||
|
logger.debug('caught generateStats() errors')
|
||||||
// Reset generating state when encountering any errors
|
// Reset generating state when encountering any errors
|
||||||
Object.keys(statsData).forEach(key => {
|
Object.keys(statsData).forEach(key => {
|
||||||
statsData[key].generating = false
|
statsData[key].generating = false
|
||||||
})
|
})
|
||||||
return next(error)
|
throw error
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
115
lolisafe.js
115
lolisafe.js
@ -10,14 +10,13 @@ process.on('unhandledRejection', error => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// Require libraries
|
// Require libraries
|
||||||
const bodyParser = require('body-parser')
|
|
||||||
const contentDisposition = require('content-disposition')
|
const contentDisposition = require('content-disposition')
|
||||||
const express = require('express')
|
|
||||||
const helmet = require('helmet')
|
const helmet = require('helmet')
|
||||||
|
const HyperExpress = require('hyper-express')
|
||||||
|
const LiveDirectory = require('live-directory')
|
||||||
const NodeClam = require('clamscan')
|
const NodeClam = require('clamscan')
|
||||||
const nunjucks = require('nunjucks')
|
const nunjucks = require('nunjucks')
|
||||||
const path = require('path')
|
// const rateLimit = require('express-rate-limit') // FIXME: Find alternative
|
||||||
const rateLimit = require('express-rate-limit')
|
|
||||||
const { accessSync, constants } = require('fs')
|
const { accessSync, constants } = require('fs')
|
||||||
|
|
||||||
// Check required config files
|
// Check required config files
|
||||||
@ -38,9 +37,10 @@ const versions = require('./src/versions')
|
|||||||
|
|
||||||
// lolisafe
|
// lolisafe
|
||||||
logger.log('Starting lolisafe\u2026')
|
logger.log('Starting lolisafe\u2026')
|
||||||
const safe = express()
|
const safe = new HyperExpress.Server({
|
||||||
|
trust_proxy: Boolean(config.trustProxy)
|
||||||
|
})
|
||||||
|
|
||||||
const errors = require('./controllers/errorsController')
|
|
||||||
const paths = require('./controllers/pathsController')
|
const paths = require('./controllers/pathsController')
|
||||||
paths.initSync()
|
paths.initSync()
|
||||||
const utils = require('./controllers/utilsController')
|
const utils = require('./controllers/utilsController')
|
||||||
@ -91,21 +91,44 @@ if (config.accessControlAllowOrigin) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.trustProxy) {
|
const initLiveDirectory = (options = {}) => {
|
||||||
safe.set('trust proxy', 1)
|
if (!options.ignore) {
|
||||||
|
options.ignore = path => {
|
||||||
|
// ignore dot files
|
||||||
|
return path.startsWith('.')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new LiveDirectory(options)
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://mozilla.github.io/nunjucks/api.html#configure
|
// https://mozilla.github.io/nunjucks/api.html#configure
|
||||||
nunjucks.configure('views', {
|
const nunjucksEnv = nunjucks.configure('views', {
|
||||||
autoescape: true,
|
autoescape: true,
|
||||||
express: safe,
|
|
||||||
watch: isDevMode
|
watch: isDevMode
|
||||||
// noCache: isDevMode
|
// noCache: isDevMode
|
||||||
})
|
})
|
||||||
safe.set('view engine', 'njk')
|
|
||||||
safe.enable('view cache')
|
const renderNunjucks = (res, path, params) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
nunjucksEnv.render(`${path}.njk`, params, (err, html) => {
|
||||||
|
if (err) return reject(err)
|
||||||
|
resolve(html)
|
||||||
|
})
|
||||||
|
}).then(html => {
|
||||||
|
return res.type('html').send(html)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind a global middleware which will attach to our helper method into all incoming requests
|
||||||
|
safe.use((req, res, next) => {
|
||||||
|
// Inject the render method onto the response object on each requet
|
||||||
|
res.render = (path, params) => renderNunjucks(res, path, params)
|
||||||
|
next()
|
||||||
|
})
|
||||||
|
|
||||||
// Configure rate limits (disabled during development)
|
// Configure rate limits (disabled during development)
|
||||||
|
// FIXME: express-rate-limit does not work with hyper-express, find alternative
|
||||||
|
/*
|
||||||
if (!isDevMode && Array.isArray(config.rateLimits) && config.rateLimits.length) {
|
if (!isDevMode && Array.isArray(config.rateLimits) && config.rateLimits.length) {
|
||||||
for (const _rateLimit of config.rateLimits) {
|
for (const _rateLimit of config.rateLimits) {
|
||||||
const limiter = rateLimit(_rateLimit.config)
|
const limiter = rateLimit(_rateLimit.config)
|
||||||
@ -114,9 +137,7 @@ if (!isDevMode && Array.isArray(config.rateLimits) && config.rateLimits.length)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
safe.use(bodyParser.urlencoded({ extended: true }))
|
|
||||||
safe.use(bodyParser.json())
|
|
||||||
|
|
||||||
const cdnPages = [...config.pages]
|
const cdnPages = [...config.pages]
|
||||||
let setHeaders
|
let setHeaders
|
||||||
@ -179,15 +200,17 @@ const initServeStaticUploads = (opts = {}) => {
|
|||||||
// which it will await before creating 'send' stream to client.
|
// which it will await before creating 'send' stream to client.
|
||||||
// This is necessary due to database queries being async tasks,
|
// This is necessary due to database queries being async tasks,
|
||||||
// and express/serve-static not having the functionality by default.
|
// and express/serve-static not having the functionality by default.
|
||||||
safe.use('/', require('@bobbywibowo/serve-static')(paths.uploads, opts))
|
// safe.use('/', require('@bobbywibowo/serve-static')(paths.uploads, opts))
|
||||||
logger.debug('Inititated SimpleDataStore for Content-Disposition: ' +
|
// logger.debug('Inititated SimpleDataStore for Content-Disposition: ' +
|
||||||
`{ limit: ${utils.contentDispositionStore.limit}, strategy: "${utils.contentDispositionStore.strategy}" }`)
|
// `{ limit: ${utils.contentDispositionStore.limit}, strategy: "${utils.contentDispositionStore.strategy}" }`)
|
||||||
|
logger.error('initServeStaticUploads() was called, but still WIP')
|
||||||
} else {
|
} else {
|
||||||
safe.use('/', express.static(paths.uploads, opts))
|
// safe.use('/', express.static(paths.uploads, opts))
|
||||||
|
logger.error('initServeStaticUploads() was called, but still WIP')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cache control (safe.fiery.me)
|
// Cache control
|
||||||
if (config.cacheControl) {
|
if (config.cacheControl) {
|
||||||
const cacheControls = {
|
const cacheControls = {
|
||||||
// max-age: 6 months
|
// max-age: 6 months
|
||||||
@ -212,9 +235,8 @@ if (config.cacheControl) {
|
|||||||
// If using CDN, cache public pages in CDN
|
// If using CDN, cache public pages in CDN
|
||||||
cdnPages.push('api/check')
|
cdnPages.push('api/check')
|
||||||
for (const page of cdnPages) {
|
for (const page of cdnPages) {
|
||||||
safe.get(`/${page === 'home' ? '' : page}`, (req, res, next) => {
|
safe.get(`/${page === 'home' ? '' : page}`, async (req, res) => {
|
||||||
res.set('Cache-Control', cacheControls.cdn)
|
res.set('Cache-Control', cacheControls.cdn)
|
||||||
next()
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
@ -264,9 +286,25 @@ if (config.cacheControl) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Static assets
|
// Static assets
|
||||||
safe.use('/', express.static(paths.public, { setHeaders }))
|
const liveDirectoryPublic = initLiveDirectory({ path: paths.public })
|
||||||
safe.use('/', express.static(paths.dist, { setHeaders }))
|
const liveDirectoryDist = initLiveDirectory({ path: paths.dist })
|
||||||
|
safe.use('/', (req, res, next) => {
|
||||||
|
// Only process GET and HEAD requests
|
||||||
|
if (req.method !== 'GET' && req.method !== 'HEAD') {
|
||||||
|
return next()
|
||||||
|
}
|
||||||
|
// Try to find asset from public directory, then dist directory
|
||||||
|
const file = liveDirectoryPublic.get(req.path) || liveDirectoryDist.get(req.path)
|
||||||
|
if (file === undefined) {
|
||||||
|
return next()
|
||||||
|
}
|
||||||
|
if (typeof setHeaders === 'function') {
|
||||||
|
setHeaders(res)
|
||||||
|
}
|
||||||
|
return res.type(file.extension).send(file.buffer)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Routes
|
||||||
safe.use('/', album)
|
safe.use('/', album)
|
||||||
safe.use('/', file)
|
safe.use('/', file)
|
||||||
safe.use('/', nojs)
|
safe.use('/', nojs)
|
||||||
@ -276,7 +314,7 @@ safe.use('/api', api)
|
|||||||
;(async () => {
|
;(async () => {
|
||||||
try {
|
try {
|
||||||
// Init database
|
// Init database
|
||||||
await require('./controllers/utils/initDatabase.js')(utils.db)
|
await require('./controllers/utils/initDatabase')(utils.db)
|
||||||
|
|
||||||
// Purge any leftover in chunks directory, do not wait
|
// Purge any leftover in chunks directory, do not wait
|
||||||
paths.purgeChunks()
|
paths.purgeChunks()
|
||||||
@ -297,6 +335,11 @@ safe.use('/api', api)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const liveDirectoryCustomPages = initLiveDirectory({
|
||||||
|
path: paths.customPages,
|
||||||
|
keep: ['.html']
|
||||||
|
})
|
||||||
|
|
||||||
// Cookie Policy
|
// Cookie Policy
|
||||||
if (config.cookiePolicy) {
|
if (config.cookiePolicy) {
|
||||||
config.pages.push('cookiepolicy')
|
config.pages.push('cookiepolicy')
|
||||||
@ -304,23 +347,27 @@ safe.use('/api', api)
|
|||||||
|
|
||||||
// Check for custom pages, otherwise fallback to Nunjucks templates
|
// Check for custom pages, otherwise fallback to Nunjucks templates
|
||||||
for (const page of config.pages) {
|
for (const page of config.pages) {
|
||||||
const customPage = path.join(paths.customPages, `${page}.html`)
|
// FIXME: Have this update on-the-fly or don't use LiveDirectory
|
||||||
if (!await paths.access(customPage).catch(() => true)) {
|
const customPage = liveDirectoryCustomPages.get(`${page}.html`)
|
||||||
safe.get(`/${page === 'home' ? '' : page}`, (req, res, next) => res.sendFile(customPage))
|
if (customPage) {
|
||||||
|
safe.get(`/${page === 'home' ? '' : page}`, (req, res) => {
|
||||||
|
res.type('html').send(customPage.buffer)
|
||||||
|
})
|
||||||
} else if (page === 'home') {
|
} else if (page === 'home') {
|
||||||
safe.get('/', (req, res, next) => res.render(page, {
|
safe.get('/', (req, res) => res.render(page, {
|
||||||
config, utils, versions: utils.versionStrings
|
config, utils, versions: utils.versionStrings
|
||||||
}))
|
}))
|
||||||
} else {
|
} else {
|
||||||
safe.get(`/${page}`, (req, res, next) => res.render(page, {
|
safe.get(`/${page}`, (req, res) => res.render(page, {
|
||||||
config, utils, versions: utils.versionStrings
|
config, utils, versions: utils.versionStrings
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Express error handlers
|
// Web server error handlers (must always be set after all routes/routers)
|
||||||
safe.use(errors.handleMissing)
|
const errorsController = require('./controllers/errorsController')
|
||||||
safe.use(errors.handle)
|
safe.set_not_found_handler(errorsController.handlerNotFound)
|
||||||
|
safe.set_error_handler(errorsController.handlerError)
|
||||||
|
|
||||||
// Git hash
|
// Git hash
|
||||||
if (config.showGitHash) {
|
if (config.showGitHash) {
|
||||||
@ -355,7 +402,7 @@ safe.use('/api', api)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Binds Express to port
|
// Binds Express to port
|
||||||
await new Promise(resolve => safe.listen(utils.conf.port, () => resolve()))
|
await safe.listen(utils.conf.port)
|
||||||
logger.log(`lolisafe started on port ${utils.conf.port}`)
|
logger.log(`lolisafe started on port ${utils.conf.port}`)
|
||||||
|
|
||||||
// Cache control (safe.fiery.me)
|
// Cache control (safe.fiery.me)
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
const routes = require('express').Router()
|
const { Router } = require('hyper-express')
|
||||||
|
const routes = new Router()
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const paths = require('./../controllers/pathsController')
|
const errors = require('../controllers/errorsController')
|
||||||
const utils = require('./../controllers/utilsController')
|
const utils = require('./../controllers/utilsController')
|
||||||
const config = require('./../config')
|
const config = require('./../config')
|
||||||
|
|
||||||
routes.get('/a/:identifier', async (req, res, next) => {
|
routes.get('/a/:identifier', async (req, res) => {
|
||||||
const identifier = req.params.identifier
|
const identifier = req.params.identifier
|
||||||
if (identifier === undefined) {
|
if (identifier === undefined) {
|
||||||
res.status(404).sendFile(path.join(paths.errorRoot, config.errorPages[404]))
|
return errors.handlerNotFound(req, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
const album = await utils.db.table('albums')
|
const album = await utils.db.table('albums')
|
||||||
@ -19,7 +20,7 @@ routes.get('/a/:identifier', async (req, res, next) => {
|
|||||||
.first()
|
.first()
|
||||||
|
|
||||||
if (!album || album.public === 0) {
|
if (!album || album.public === 0) {
|
||||||
return res.status(404).sendFile(path.join(paths.errorRoot, config.errorPages[404]))
|
return errors.handlerNotFound(req, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
const nojs = req.query.nojs !== undefined
|
const nojs = req.query.nojs !== undefined
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
const routes = require('express').Router()
|
const { Router } = require('hyper-express')
|
||||||
|
const routes = new Router()
|
||||||
const albumsController = require('./../controllers/albumsController')
|
const albumsController = require('./../controllers/albumsController')
|
||||||
const authController = require('./../controllers/authController')
|
const authController = require('./../controllers/authController')
|
||||||
const tokenController = require('./../controllers/tokenController')
|
const tokenController = require('./../controllers/tokenController')
|
||||||
@ -6,7 +7,7 @@ const uploadController = require('./../controllers/uploadController')
|
|||||||
const utilsController = require('./../controllers/utilsController')
|
const utilsController = require('./../controllers/utilsController')
|
||||||
const config = require('./../config')
|
const config = require('./../config')
|
||||||
|
|
||||||
routes.get('/check', (req, res, next) => {
|
routes.get('/check', async (req, res) => {
|
||||||
const obj = {
|
const obj = {
|
||||||
private: config.private,
|
private: config.private,
|
||||||
enableUserAccounts: config.enableUserAccounts,
|
enableUserAccounts: config.enableUserAccounts,
|
||||||
@ -22,44 +23,51 @@ routes.get('/check', (req, res, next) => {
|
|||||||
if (utilsController.clientVersion) {
|
if (utilsController.clientVersion) {
|
||||||
obj.version = utilsController.clientVersion
|
obj.version = utilsController.clientVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.json(obj)
|
return res.json(obj)
|
||||||
})
|
})
|
||||||
|
|
||||||
routes.post('/login', (req, res, next) => authController.verify(req, res, next))
|
routes.post('/login', authController.verify)
|
||||||
routes.post('/register', (req, res, next) => authController.register(req, res, next))
|
routes.post('/register', authController.register)
|
||||||
routes.post('/password/change', (req, res, next) => authController.changePassword(req, res, next))
|
routes.post('/password/change', authController.changePassword)
|
||||||
routes.get('/uploads', (req, res, next) => uploadController.list(req, res, next))
|
routes.get('/uploads', uploadController.list)
|
||||||
routes.get('/uploads/:page', (req, res, next) => uploadController.list(req, res, next))
|
routes.get('/uploads/:page', uploadController.list)
|
||||||
routes.post('/upload', (req, res, next) => uploadController.upload(req, res, next))
|
routes.post('/upload', uploadController.upload, {
|
||||||
routes.post('/upload/delete', (req, res, next) => uploadController.delete(req, res, next))
|
// HyperExpress defaults to 250kb
|
||||||
routes.post('/upload/bulkdelete', (req, res, next) => uploadController.bulkDelete(req, res, next))
|
// https://github.com/kartikk221/hyper-express/blob/6.2.4/docs/Server.md#server-constructor-options
|
||||||
routes.post('/upload/finishchunks', (req, res, next) => uploadController.finishChunks(req, res, next))
|
max_body_length: parseInt(config.uploads.maxSize) * 1e6
|
||||||
routes.get('/upload/get/:identifier', (req, res, next) => uploadController.get(req, res, next))
|
})
|
||||||
routes.post('/upload/:albumid', (req, res, next) => uploadController.upload(req, res, next))
|
routes.post('/uploadurls', uploadController.uploadUrls)
|
||||||
routes.get('/album/get/:identifier', (req, res, next) => albumsController.get(req, res, next))
|
routes.post('/upload/delete', uploadController.delete)
|
||||||
routes.get('/album/zip/:identifier', (req, res, next) => albumsController.generateZip(req, res, next))
|
routes.post('/upload/bulkdelete', uploadController.bulkDelete)
|
||||||
routes.get('/album/:id', (req, res, next) => albumsController.listFiles(req, res, next))
|
routes.post('/upload/finishchunks', uploadController.finishChunks)
|
||||||
routes.get('/album/:id/:page', (req, res, next) => albumsController.listFiles(req, res, next))
|
routes.get('/upload/get/:identifier', uploadController.get)
|
||||||
routes.get('/albums', (req, res, next) => albumsController.list(req, res, next))
|
routes.post('/upload/:albumid', uploadController.upload)
|
||||||
routes.get('/albums/:page', (req, res, next) => albumsController.list(req, res, next))
|
routes.post('/uploadurls/:albumid', uploadController.uploadUrls)
|
||||||
routes.post('/albums', (req, res, next) => albumsController.create(req, res, next))
|
routes.get('/album/get/:identifier', albumsController.get)
|
||||||
routes.post('/albums/addfiles', (req, res, next) => albumsController.addFiles(req, res, next))
|
routes.get('/album/zip/:identifier', albumsController.generateZip)
|
||||||
routes.post('/albums/delete', (req, res, next) => albumsController.delete(req, res, next))
|
routes.get('/album/:id', albumsController.listFiles)
|
||||||
routes.post('/albums/disable', (req, res, next) => albumsController.disable(req, res, next))
|
routes.get('/album/:id/:page', albumsController.listFiles)
|
||||||
routes.post('/albums/edit', (req, res, next) => albumsController.edit(req, res, next))
|
routes.get('/albums', albumsController.list)
|
||||||
routes.post('/albums/rename', (req, res, next) => albumsController.rename(req, res, next))
|
routes.get('/albums/:page', albumsController.list)
|
||||||
routes.get('/albums/test', (req, res, next) => albumsController.test(req, res, next))
|
routes.post('/albums', albumsController.create)
|
||||||
routes.get('/tokens', (req, res, next) => tokenController.list(req, res, next))
|
routes.post('/albums/addfiles', albumsController.addFiles)
|
||||||
routes.post('/tokens/verify', (req, res, next) => tokenController.verify(req, res, next))
|
routes.post('/albums/delete', albumsController.delete)
|
||||||
routes.post('/tokens/change', (req, res, next) => tokenController.change(req, res, next))
|
routes.post('/albums/disable', albumsController.disable)
|
||||||
routes.get('/filelength/config', (req, res, next) => authController.getFileLengthConfig(req, res, next))
|
routes.post('/albums/edit', albumsController.edit)
|
||||||
routes.post('/filelength/change', (req, res, next) => authController.changeFileLength(req, res, next))
|
routes.post('/albums/rename', albumsController.rename)
|
||||||
routes.get('/users', (req, res, next) => authController.listUsers(req, res, next))
|
routes.get('/albums/test', albumsController.test)
|
||||||
routes.get('/users/:page', (req, res, next) => authController.listUsers(req, res, next))
|
routes.get('/tokens', tokenController.list)
|
||||||
routes.post('/users/create', (req, res, next) => authController.createUser(req, res, next))
|
routes.post('/tokens/verify', tokenController.verify)
|
||||||
routes.post('/users/edit', (req, res, next) => authController.editUser(req, res, next))
|
routes.post('/tokens/change', tokenController.change)
|
||||||
routes.post('/users/disable', (req, res, next) => authController.disableUser(req, res, next))
|
routes.get('/filelength/config', authController.getFileLengthConfig)
|
||||||
routes.post('/users/delete', (req, res, next) => authController.deleteUser(req, res, next))
|
routes.post('/filelength/change', authController.changeFileLength)
|
||||||
routes.get('/stats', (req, res, next) => utilsController.stats(req, res, next))
|
routes.get('/users', authController.listUsers)
|
||||||
|
routes.get('/users/:page', authController.listUsers)
|
||||||
|
routes.post('/users/create', authController.createUser)
|
||||||
|
routes.post('/users/edit', authController.editUser)
|
||||||
|
routes.post('/users/disable', authController.disableUser)
|
||||||
|
routes.post('/users/delete', authController.deleteUser)
|
||||||
|
routes.get('/stats', utilsController.stats)
|
||||||
|
|
||||||
module.exports = routes
|
module.exports = routes
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
const routes = require('express').Router()
|
const { Router } = require('hyper-express')
|
||||||
|
const routes = new Router()
|
||||||
const utils = require('../controllers/utilsController')
|
const utils = require('../controllers/utilsController')
|
||||||
const config = require('../config')
|
const config = require('../config')
|
||||||
|
|
||||||
routes.get([
|
routes.get('/file/:identifier', async (req, res) => {
|
||||||
'/file/:identifier'
|
|
||||||
], async (req, res, next) => {
|
|
||||||
// Uploads identifiers parsing, etc., are strictly handled by client-side JS at src/js/file.js
|
// Uploads identifiers parsing, etc., are strictly handled by client-side JS at src/js/file.js
|
||||||
return res.render('file', {
|
return res.render('file', {
|
||||||
config, utils, versions: utils.versionStrings
|
config, utils, versions: utils.versionStrings
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
const routes = require('express').Router()
|
const { Router } = require('hyper-express')
|
||||||
|
const routes = new Router()
|
||||||
const uploadController = require('./../controllers/uploadController')
|
const uploadController = require('./../controllers/uploadController')
|
||||||
const utils = require('./../controllers/utilsController')
|
const utils = require('./../controllers/utilsController')
|
||||||
const config = require('./../config')
|
const config = require('./../config')
|
||||||
|
|
||||||
routes.get('/nojs', async (req, res, next) => {
|
routes.get('/nojs', async (req, res) => {
|
||||||
return res.render('nojs', {
|
return res.render('nojs', {
|
||||||
config,
|
config,
|
||||||
utils,
|
utils,
|
||||||
@ -11,7 +12,7 @@ routes.get('/nojs', async (req, res, next) => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
routes.post('/nojs', (req, res, next) => {
|
routes.post('/nojs', async (req, res) => {
|
||||||
res._json = res.json
|
res._json = res.json
|
||||||
res.json = (...args) => {
|
res.json = (...args) => {
|
||||||
const result = args[0]
|
const result = args[0]
|
||||||
@ -23,7 +24,11 @@ routes.post('/nojs', (req, res, next) => {
|
|||||||
files: result.files || [{}]
|
files: result.files || [{}]
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return uploadController.upload(req, res, next)
|
return uploadController.upload(req, res)
|
||||||
|
}, {
|
||||||
|
// HyperExpress defaults to 250kb
|
||||||
|
// https://github.com/kartikk221/hyper-express/blob/6.2.4/docs/Server.md#server-constructor-options
|
||||||
|
max_body_length: parseInt(config.uploads.maxSize) * 1e6
|
||||||
})
|
})
|
||||||
|
|
||||||
module.exports = routes
|
module.exports = routes
|
||||||
|
@ -1,15 +1,16 @@
|
|||||||
const routes = require('express').Router()
|
const { Router } = require('hyper-express')
|
||||||
|
const routes = new Router()
|
||||||
const utils = require('./../controllers/utilsController')
|
const utils = require('./../controllers/utilsController')
|
||||||
const config = require('./../config')
|
const config = require('./../config')
|
||||||
|
|
||||||
routes.get([
|
const playerHandler = async (req, res) => {
|
||||||
'/player/:identifier',
|
|
||||||
'/v/:identifier'
|
|
||||||
], async (req, res, next) => {
|
|
||||||
// Uploads identifiers parsing, etc., are strictly handled by client-side JS at src/js/player.js
|
// Uploads identifiers parsing, etc., are strictly handled by client-side JS at src/js/player.js
|
||||||
return res.render('player', {
|
return res.render('player', {
|
||||||
config, utils, versions: utils.versionStrings
|
config, utils, versions: utils.versionStrings
|
||||||
})
|
})
|
||||||
})
|
}
|
||||||
|
|
||||||
|
routes.get('/player/:identifier', playerHandler)
|
||||||
|
routes.get('/v/:identifier', playerHandler)
|
||||||
|
|
||||||
module.exports = routes
|
module.exports = routes
|
||||||
|
Loading…
Reference in New Issue
Block a user