瀏覽代碼

feat: access cached upload file + ignore common page extensions

Nick 6 年之前
父節點
當前提交
212286fc4a
共有 5 個文件被更改,包括 86 次插入34 次删除
  1. 1 1
      client/components/editor/editor-modal-media.vue
  2. 4 0
      server/app/data.yml
  3. 42 32
      server/controllers/common.js
  4. 13 1
      server/helpers/page.js
  5. 26 0
      server/models/assets.js

+ 1 - 1
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()

+ 4 - 0
server/app/data.yml

@@ -97,4 +97,8 @@ reservedPaths:
   - img
   - js
   - svg
+pageExtensions:
+  - md
+  - html
+  - txt
 # ---------------------------------

+ 42 - 32
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' })
-  }
+  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' })
+    }
 
-  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
+    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 {
+      _.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' })
+      }
     }
-    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 })
-    } else {
-      res.render('notfound', { action: 'view' })
+    if (!WIKI.auth.checkAccess(req.user, ['read:assets'], pageArgs)) {
+      return res.sendStatus(403)
     }
+
+    await WIKI.models.assets.getAsset(pageArgs.path, res)
   }
 })
 

+ 13 - 1
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
   },

+ 26 - 0
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)
+        }
+      })
+    })
+  }
 }