diff --git a/lib/models/note.js b/lib/models/note.js index ffd2a85c..8030be00 100644 --- a/lib/models/note.js +++ b/lib/models/note.js @@ -186,6 +186,16 @@ module.exports = function (sequelize, DataTypes) { var result = id.match(uuidRegex) if (result && result.length === 1) { return true } else { return false } } + Note.parseNoteIdAsync = function (noteId) { + return new Promise((resolve, reject) => { + Note.parseNoteId(noteId, (err, id) => { + if (err) { + return reject(err) + } + resolve(id) + }) + }) + } Note.parseNoteId = function (noteId, callback) { async.series({ parseNoteIdByAlias: function (_callback) { diff --git a/lib/note/index.js b/lib/note/index.js new file mode 100644 index 00000000..a53c8306 --- /dev/null +++ b/lib/note/index.js @@ -0,0 +1,63 @@ +'use strict' + +const config = require('../config') +const { Note } = require('../models') + +const { newCheckViewPermission, errorForbidden, responseCodiMD, errorNotFound } = require('../response') +const { updateHistory } = require('../history') + +async function getNoteById (noteId) { + const id = await Note.parseNoteIdAsync(noteId) + const note = await Note.findOne({ + where: { + id: id + } + }) + return note +} + +async function createNote (userId, noteAlias) { + if (!config.allowAnonymous && !!userId) { + throw new Error('can not create note') + } + + const note = await Note.create({ + ownerId: userId, + alias: noteAlias, + }) + + if (userId) { + updateHistory(userId, note) + } + + return note +} + +// controller +async function showNote (req, res) { + const noteId = req.params.noteId + const userId = req.user ? req.user.id : null + + let note = await getNoteById(noteId) + + if (!note) { + // if allow free url enable, auto create note + if (!config.allowFreeURL || config.forbiddenNoteIDs.includes(noteId)) { + return errorNotFound(res) + } + note = await createNote(userId, noteId) + } + + if (!newCheckViewPermission(note, req.isAuthenticated(), userId)) { + return errorForbidden(res) + } + + // force to use note id + const id = Note.encodeNoteId(note.id) + if ((note.alias && noteId !== note.alias) || (!note.alias && noteId !== id)) { + return res.redirect(config.serverURL + '/' + (note.alias || id)) + } + return responseCodiMD(res, note) +} + +exports.showNote = showNote diff --git a/lib/response.js b/lib/response.js index 43802baf..cff83355 100644 --- a/lib/response.js +++ b/lib/response.js @@ -25,7 +25,6 @@ exports.errorTooLong = errorTooLong exports.errorInternalError = errorInternalError exports.errorServiceUnavailable = errorServiceUnavailable exports.newNote = newNote -exports.showNote = showNote exports.showPublishNote = showPublishNote exports.showPublishSlide = showPublishSlide exports.showIndex = showIndex @@ -35,6 +34,8 @@ exports.publishSlideActions = publishSlideActions exports.githubActions = githubActions exports.gitlabActions = gitlabActions exports.checkViewPermission = checkViewPermission +exports.newCheckViewPermission = newCheckViewPermission +exports.responseCodiMD = responseCodiMD function errorForbidden (res) { const { req } = res @@ -45,20 +46,25 @@ function errorForbidden (res) { res.redirect(config.serverURL + '/') } } + function errorNotFound (res) { responseError(res, '404', 'Not Found', 'oops.') } + function errorBadRequest (res) { responseError(res, '400', 'Bad Request', 'something not right.') } + function errorTooLong (res) { responseError(res, '413', 'Payload Too Large', 'Shorten your note!') } + function errorInternalError (res) { responseError(res, '500', 'Internal Error', 'wtf.') } + function errorServiceUnavailable (res) { - res.status(503).send("I'm busy right now, try again later.") + res.status(503).send('I\'m busy right now, try again later.') } function responseError (res, code, detail, msg) { @@ -150,6 +156,16 @@ function newNote (req, res, next) { }) } +function newCheckViewPermission (note, isLogin, userId) { + if (note.permission === 'private') { + return note.ownerId === userId + } + if (note.permission === 'limited' || note.permission === 'protected') { + return isLogin + } + return true +} + function checkViewPermission (req, note) { if (note.permission === 'private') { if (!req.isAuthenticated() || note.ownerId !== req.user.id) { return false } else { return true } @@ -194,16 +210,6 @@ function findNote (req, res, callback, include) { }) } -function showNote (req, res, next) { - findNote(req, res, function (note) { - // force to use note id - var noteId = req.params.noteId - var id = models.Note.encodeNoteId(note.id) - if ((note.alias && noteId !== note.alias) || (!note.alias && noteId !== id)) { return res.redirect(config.serverURL + '/' + (note.alias || id)) } - return responseCodiMD(res, note) - }) -} - function showPublishNote (req, res, next) { var include = [{ model: models.User, diff --git a/lib/routes.js b/lib/routes.js index 0c3c9b01..1cb159e9 100644 --- a/lib/routes.js +++ b/lib/routes.js @@ -10,6 +10,7 @@ const errorPageController = require('./errorPage') const statusController = require('./status') const historyController = require('./history') const userController = require('./user') +const noteController = require('./note') const response = require('./response') const appRouter = Router() @@ -71,7 +72,7 @@ appRouter.get('/p/:shortid', response.showPublishSlide) // publish slide actions appRouter.get('/p/:shortid/:action', response.publishSlideActions) // get note by id -appRouter.get('/:noteId', response.showNote) +appRouter.get('/:noteId', wrap(noteController.showNote)) // note actions appRouter.get('/:noteId/:action', response.noteActions) // note actions with action id