diff --git a/client/components/editor/editor-modal-media.vue b/client/components/editor/editor-modal-media.vue index d314ce1a..9b85cb1e 100644 --- a/client/components/editor/editor-modal-media.vue +++ b/client/components/editor/editor-modal-media.vue @@ -213,7 +213,7 @@ export default { } for (let file of files) { file.setMetadata({ - path: '/universe' + path: 'test' }) } await this.$refs.pond.processFiles() diff --git a/server/app/data.yml b/server/app/data.yml index 383c78b4..05d21645 100644 --- a/server/app/data.yml +++ b/server/app/data.yml @@ -97,4 +97,8 @@ reservedPaths: - img - js - svg +pageExtensions: + - md + - html + - txt # --------------------------------- diff --git a/server/controllers/common.js b/server/controllers/common.js index 6de24eda..3abc52c0 100644 --- a/server/controllers/common.js +++ b/server/controllers/common.js @@ -32,7 +32,7 @@ router.get('/healthz', (req, res, next) => { * Create/Edit document */ router.get(['/e', '/e/*'], async (req, res, next) => { - const pageArgs = pageHelper.parsePath(req.path) + const pageArgs = pageHelper.parsePath(req.path, { stripExt: true }) if (pageHelper.isReservedPath(pageArgs.path)) { return next(new Error('Cannot create this page because it starts with a system reserved path.')) @@ -93,7 +93,7 @@ router.get(['/p', '/p/*'], (req, res, next) => { * History */ router.get(['/h', '/h/*'], async (req, res, next) => { - const pageArgs = pageHelper.parsePath(req.path) + const pageArgs = pageHelper.parsePath(req.path, { stripExt: true }) if (!WIKI.auth.checkAccess(req.user, ['read:pages'], pageArgs)) { _.set(res.locals, 'pageMeta.title', 'Unauthorized') @@ -119,7 +119,7 @@ router.get(['/h', '/h/*'], async (req, res, next) => { * Source */ router.get(['/s', '/s/*'], async (req, res, next) => { - const pageArgs = pageHelper.parsePath(req.path) + const pageArgs = pageHelper.parsePath(req.path, { stripExt: true }) if (!WIKI.auth.checkAccess(req.user, ['read:pages'], pageArgs)) { return res.render('unauthorized', { action: 'source' }) @@ -141,42 +141,52 @@ router.get(['/s', '/s/*'], async (req, res, next) => { }) /** - * View document + * View document / asset */ router.get('/*', async (req, res, next) => { - const pageArgs = pageHelper.parsePath(req.path) + const stripExt = _.some(WIKI.data.pageExtensions, ext => _.endsWith(req.path, `.${ext}`)) + const pageArgs = pageHelper.parsePath(req.path, { stripExt }) + const isPage = (stripExt || pageArgs.path.indexOf('.') === -1) - if (!WIKI.auth.checkAccess(req.user, ['read:pages'], pageArgs)) { - _.set(res.locals, 'pageMeta.title', 'Unauthorized') - return res.render('unauthorized', { action: 'view' }) - } - - const page = await WIKI.models.pages.getPage({ - path: pageArgs.path, - locale: pageArgs.locale, - userId: req.user.id, - isPrivate: false - }) - if (page) { - _.set(res.locals, 'pageMeta.title', page.title) - _.set(res.locals, 'pageMeta.description', page.description) - const sidebar = await WIKI.models.navigation.getTree({ cache: true }) - const injectCode = { - css: WIKI.config.theming.injectCSS, - head: WIKI.config.theming.injectHead, - body: WIKI.config.theming.injectBody + if (isPage) { + if (!WIKI.auth.checkAccess(req.user, ['read:pages'], pageArgs)) { + _.set(res.locals, 'pageMeta.title', 'Unauthorized') + return res.status(403).render('unauthorized', { action: 'view' }) } - res.render('page', { page, sidebar, injectCode }) - } else if (pageArgs.path === 'home') { - _.set(res.locals, 'pageMeta.title', 'Welcome') - res.render('welcome') - } else { - _.set(res.locals, 'pageMeta.title', 'Page Not Found') - if (WIKI.auth.checkAccess(req.user, ['write:pages'], pageArgs)) { - res.status(404).render('new', { pagePath: req.path }) + + const page = await WIKI.models.pages.getPage({ + path: pageArgs.path, + locale: pageArgs.locale, + userId: req.user.id, + isPrivate: false + }) + if (page) { + _.set(res.locals, 'pageMeta.title', page.title) + _.set(res.locals, 'pageMeta.description', page.description) + const sidebar = await WIKI.models.navigation.getTree({ cache: true }) + const injectCode = { + css: WIKI.config.theming.injectCSS, + head: WIKI.config.theming.injectHead, + body: WIKI.config.theming.injectBody + } + res.render('page', { page, sidebar, injectCode }) + } else if (pageArgs.path === 'home') { + _.set(res.locals, 'pageMeta.title', 'Welcome') + res.render('welcome') } else { - res.render('notfound', { action: 'view' }) + _.set(res.locals, 'pageMeta.title', 'Page Not Found') + if (WIKI.auth.checkAccess(req.user, ['write:pages'], pageArgs)) { + res.status(404).render('new', { pagePath: req.path }) + } else { + res.status(404).render('notfound', { action: 'view' }) + } } + } else { + if (!WIKI.auth.checkAccess(req.user, ['read:assets'], pageArgs)) { + return res.sendStatus(403) + } + + await WIKI.models.assets.getAsset(pageArgs.path, res) } }) diff --git a/server/helpers/page.js b/server/helpers/page.js index b53969fe..1a134ae5 100644 --- a/server/helpers/page.js +++ b/server/helpers/page.js @@ -1,6 +1,7 @@ const qs = require('querystring') const _ = require('lodash') const crypto = require('crypto') +const path = require('path') const localeSegmentRegex = /^[A-Z]{2}(-[A-Z]{2})?$/i @@ -10,7 +11,7 @@ module.exports = { /** * Parse raw url path and make it safe */ - parsePath (rawPath) { + parsePath (rawPath, opts = {}) { let pathObj = { locale: 'en', path: 'home', @@ -32,6 +33,17 @@ module.exports = { pathObj.locale = pathParts[0] pathParts.shift() } + + // Strip extension + if (opts.stripExt) { + const lastPart = _.last(pathParts) + if (lastPart.indexOf('.') > 0) { + pathParts.pop() + const lastPartMeta = path.parse(lastPart) + pathParts.push(lastPartMeta.name) + } + } + pathObj.path = _.join(pathParts, '/') return pathObj }, diff --git a/server/models/assets.js b/server/models/assets.js index df059b10..3ab58176 100644 --- a/server/models/assets.js +++ b/server/models/assets.js @@ -94,4 +94,30 @@ module.exports = class Asset extends Model { // Move temp upload to cache await fs.move(opts.path, path.join(process.cwd(), `data/cache/${fileHash}.dat`)) } + + static async getAsset(assetPath, res) { + let asset = await WIKI.models.assets.getAssetFromCache(assetPath, res) + if (!asset) { + // asset = await WIKI.models.assets.getAssetFromDb(assetPath, res) + // if (asset) { + // await WIKI.models.assets.saveAssetToCache(asset) + // } + res.sendStatus(404) + } + } + + static async getAssetFromCache(assetPath, res) { + const fileHash = assetHelper.generateHash(assetPath) + const cachePath = path.join(process.cwd(), `data/cache/${fileHash}.dat`) + + return new Promise((resolve, reject) => { + res.sendFile(cachePath, { dotfiles: 'deny' }, err => { + if (err) { + resolve(false) + } else { + resolve(true) + } + }) + }) + } }