import { Request, Response } from 'express' import fs from 'fs' import path from 'path' import { config } from '../../config' import { errors } from '../../errors' import { logger } from '../../logger' import { Note } from '../../models' import { PhotoProfile } from '../../utils/PhotoProfile' export function newNote (req, res: Response, body: string | null): void { let owner = null const noteId = req.params.noteId ? req.params.noteId : null if (req.isAuthenticated()) { owner = req.user.id } else if (!config.allowAnonymous) { return errors.errorForbidden(res) } if (config.allowFreeURL && noteId && !config.forbiddenNoteIDs.includes(noteId)) { req.alias = noteId } else if (noteId) { return req.method === 'POST' ? errors.errorForbidden(res) : errors.errorNotFound(res) } Note.create({ ownerId: owner, alias: req.alias ? req.alias : null, content: body }).then(function (note) { return res.redirect(config.serverURL + '/' + (note.alias ? note.alias : Note.encodeNoteId(note.id))) }).catch(function (err) { logger.error(err) return errors.errorInternalError(res) }) } export enum Permission { None, Read, Write, Owner } interface NoteObject { ownerId?: string; permission: string; } export function getPermission (user, note: NoteObject): Permission { // There are two possible User objects we get passed. One is from socket.io // and the other is from passport directly. The former sets the logged_in // parameter to either true or false, whereas for the latter, the logged_in // parameter is always undefined, and the existence of user itself means the // user is logged in. if (!user || user.logged_in === false) { // Anonymous switch (note.permission) { case 'freely': return Permission.Write case 'editable': case 'locked': return Permission.Read default: return Permission.None } } else if (note.ownerId === user.id) { // Owner return Permission.Owner } else { // Registered user switch (note.permission) { case 'editable': case 'limited': case 'freely': return Permission.Write case 'locked': case 'protected': return Permission.Read default: return Permission.None } } } export function findNoteOrCreate (req: Request, res: Response, callback: (note: Note) => void): void { const id = req.params.noteId || req.params.shortid Note.parseNoteId(id, function (err, _id) { if (err) { logger.error(err) return errors.errorInternalError(res) } Note.findOne({ where: { id: _id } }).then(function (note) { if (!note) { return newNote(req, res, '') } if (getPermission(req.user, note) === Permission.None) { return errors.errorForbidden(res) } else { return callback(note) } }).catch(function (err) { logger.error(err) return errors.errorInternalError(res) }) }) } function isRevealTheme (theme: string): string | undefined { if (fs.existsSync(path.join(__dirname, '..', '..', '..', '..', 'public', 'build', 'reveal.js', 'css', 'theme', theme + '.css'))) { return theme } return undefined } export function getPublishData (req: Request, res: Response, note, callback: (data) => void): void { const body = note.content const extracted = Note.extractMeta(body) const markdown = extracted.markdown const meta = Note.parseMeta(extracted.meta) const createtime = note.createdAt const updatetime = note.lastchangeAt let title = Note.decodeTitle(note.title) title = Note.generateWebTitle(meta.title || title) const ogdata = Note.parseOpengraph(meta, title) const data = { title: title, description: meta.description || (markdown ? Note.generateDescription(markdown) : null), viewcount: note.viewcount, createtime: createtime, updatetime: updatetime, body: markdown, theme: meta.slideOptions && isRevealTheme(meta.slideOptions.theme), meta: JSON.stringify(extracted.meta), owner: note.owner ? note.owner.id : null, ownerprofile: note.owner ? PhotoProfile.fromUser(note.owner) : null, lastchangeuser: note.lastchangeuser ? note.lastchangeuser.id : null, lastchangeuserprofile: note.lastchangeuser ? PhotoProfile.fromUser(note.lastchangeuser) : null, robots: meta.robots || false, // default allow robots GA: meta.GA, disqus: meta.disqus, cspNonce: res.locals.nonce, dnt: req.headers.dnt, opengraph: ogdata } callback(data) }