]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blobdiff - server/middlewares/validators/oembed.ts
Allow oembed to fetch unlisted videos
[github/Chocobozzz/PeerTube.git] / server / middlewares / validators / oembed.ts
index 0a82e6932d77dd1b95d4c2fea4a55113705f6fe8..fc1a294e0898ef56cac18ef8970579996f9e3760 100644 (file)
@@ -1,12 +1,12 @@
-import * as express from 'express'
+import express from 'express'
 import { query } from 'express-validator'
 import { join } from 'path'
 import { loadVideo } from '@server/lib/model-loaders'
 import { VideoPlaylistModel } from '@server/models/video/video-playlist'
 import { VideoPlaylistPrivacy, VideoPrivacy } from '@shared/models'
-import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes'
+import { HttpStatusCode } from '../../../shared/models/http/http-error-codes'
 import { isTestInstance } from '../../helpers/core-utils'
-import { isIdOrUUIDValid, toCompleteUUID } from '../../helpers/custom-validators/misc'
+import { isIdOrUUIDValid, isUUIDValid, toCompleteUUID } from '../../helpers/custom-validators/misc'
 import { logger } from '../../helpers/logger'
 import { WEBSERVER } from '../../initializers/constants'
 import { areValidationErrors } from './shared'
@@ -28,7 +28,6 @@ function buildUrls (paths: string[]) {
 const startPlaylistURLs = buildUrls(playlistPaths)
 const startVideoURLs = buildUrls(videoPaths)
 
-const watchRegex = /([^/]+)$/
 const isURLOptions = {
   require_host: true,
   require_tld: true
@@ -62,14 +61,28 @@ const oembedValidator = [
 
     const url = req.query.url as string
 
+    let urlPath: string
+
+    try {
+      urlPath = new URL(url).pathname
+    } catch (err) {
+      return res.fail({
+        status: HttpStatusCode.BAD_REQUEST_400,
+        message: err.message,
+        data: {
+          url
+        }
+      })
+    }
+
     const isPlaylist = startPlaylistURLs.some(u => url.startsWith(u))
     const isVideo = isPlaylist ? false : startVideoURLs.some(u => url.startsWith(u))
 
     const startIsOk = isVideo || isPlaylist
 
-    const matches = watchRegex.exec(url)
+    const parts = urlPath.split('/')
 
-    if (startIsOk === false || matches === null) {
+    if (startIsOk === false || parts.length === 0) {
       return res.fail({
         status: HttpStatusCode.BAD_REQUEST_400,
         message: 'Invalid url.',
@@ -79,7 +92,7 @@ const oembedValidator = [
       })
     }
 
-    const elementId = toCompleteUUID(matches[1])
+    const elementId = toCompleteUUID(parts.pop())
     if (isIdOrUUIDValid(elementId) === false) {
       return res.fail({ message: 'Invalid video or playlist id.' })
     }
@@ -94,15 +107,18 @@ const oembedValidator = [
         })
       }
 
-      if (video.privacy !== VideoPrivacy.PUBLIC) {
-        return res.fail({
-          status: HttpStatusCode.FORBIDDEN_403,
-          message: 'Video is not public'
-        })
+      if (
+        video.privacy === VideoPrivacy.PUBLIC ||
+        (video.privacy === VideoPrivacy.UNLISTED && isUUIDValid(elementId) === true)
+      ) {
+        res.locals.videoAll = video
+        return next()
       }
 
-      res.locals.videoAll = video
-      return next()
+      return res.fail({
+        status: HttpStatusCode.FORBIDDEN_403,
+        message: 'Video is not publicly available'
+      })
     }
 
     // Is playlist
@@ -115,15 +131,18 @@ const oembedValidator = [
       })
     }
 
-    if (videoPlaylist.privacy !== VideoPlaylistPrivacy.PUBLIC) {
-      return res.fail({
-        status: HttpStatusCode.FORBIDDEN_403,
-        message: 'Playlist is not public'
-      })
+    if (
+      videoPlaylist.privacy === VideoPlaylistPrivacy.PUBLIC ||
+      (videoPlaylist.privacy === VideoPlaylistPrivacy.UNLISTED && isUUIDValid(elementId))
+    ) {
+      res.locals.videoPlaylistSummary = videoPlaylist
+      return next()
     }
 
-    res.locals.videoPlaylistSummary = videoPlaylist
-    return next()
+    return res.fail({
+      status: HttpStatusCode.FORBIDDEN_403,
+      message: 'Playlist is not public'
+    })
   }
 
 ]