]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/commitdiff
Add requests parameters validations
authorChocobozzz <florian.bigard@gmail.com>
Sat, 7 Nov 2015 13:16:26 +0000 (14:16 +0100)
committerChocobozzz <florian.bigard@gmail.com>
Sat, 7 Nov 2015 13:16:26 +0000 (14:16 +0100)
13 files changed:
middlewares/reqValidators/index.js [new file with mode: 0644]
middlewares/reqValidators/pods.js [new file with mode: 0644]
middlewares/reqValidators/remote.js [new file with mode: 0644]
middlewares/reqValidators/utils.js [new file with mode: 0644]
middlewares/reqValidators/videos.js [new file with mode: 0644]
routes/api/v1/pods.js
routes/api/v1/remoteVideos.js
routes/api/v1/videos.js
server.js
test/api/checkParams.js [new file with mode: 0644]
test/fixtures/video_short.mp4 [new file with mode: 0644]
test/fixtures/video_short.ogv [new file with mode: 0644]
test/fixtures/video_short_fake.webm [new file with mode: 0644]

diff --git a/middlewares/reqValidators/index.js b/middlewares/reqValidators/index.js
new file mode 100644 (file)
index 0000000..1ea6110
--- /dev/null
@@ -0,0 +1,11 @@
+;(function () {
+  'use strict'
+
+  var reqValidator = {
+    videos: require('./videos'),
+    pods: require('./pods'),
+    remote: require('./remote')
+  }
+
+  module.exports = reqValidator
+})()
diff --git a/middlewares/reqValidators/pods.js b/middlewares/reqValidators/pods.js
new file mode 100644 (file)
index 0000000..31eaf84
--- /dev/null
@@ -0,0 +1,19 @@
+;(function () {
+  'use strict'
+
+  var checkErrors = require('./utils').checkErrors
+  var logger = require('../../src/logger')
+
+  var pods = {}
+
+  pods.podsAdd = function (req, res, next) {
+    req.checkBody('data.url', 'Should have an url').notEmpty().isURL({ require_protocol: true })
+    req.checkBody('data.publicKey', 'Should have a public key').notEmpty()
+
+    logger.debug('Checking podsAdd parameters', { parameters: req.body })
+
+    checkErrors(req, res, next)
+  }
+
+  module.exports = pods
+})()
diff --git a/middlewares/reqValidators/remote.js b/middlewares/reqValidators/remote.js
new file mode 100644 (file)
index 0000000..e851b49
--- /dev/null
@@ -0,0 +1,40 @@
+;(function () {
+  'use strict'
+
+  var checkErrors = require('./utils').checkErrors
+  var logger = require('../../src/logger')
+
+  var remote = {}
+
+  remote.secureRequest = function (req, res, next) {
+    req.checkBody('signature.url', 'Should have a signature url').isURL()
+    req.checkBody('signature.signature', 'Should have a signature').notEmpty()
+    req.checkBody('key', 'Should have a key').notEmpty()
+    req.checkBody('data', 'Should have data').notEmpty()
+
+    logger.debug('Checking secureRequest parameters', { parameters: req.body })
+
+    checkErrors(req, res, next)
+  }
+
+  remote.remoteVideosAdd = function (req, res, next) {
+    req.checkBody('data.name', 'Should have a name').isLength(1, 50)
+    req.checkBody('data.description', 'Should have a description').isLength(1, 250)
+    req.checkBody('data.magnetUri', 'Should have a magnetUri').notEmpty()
+    req.checkBody('data.podUrl', 'Should have a podUrl').isURL()
+
+    logger.debug('Checking remoteVideosAdd parameters', { parameters: req.body })
+
+    checkErrors(req, res, next)
+  }
+
+  remote.remoteVideosRemove = function (req, res, next) {
+    req.checkBody('data.magnetUri', 'Should have a magnetUri').notEmpty()
+
+    logger.debug('Checking remoteVideosRemove parameters', { parameters: req.body })
+
+    checkErrors(req, res, next)
+  }
+
+  module.exports = remote
+})()
diff --git a/middlewares/reqValidators/utils.js b/middlewares/reqValidators/utils.js
new file mode 100644 (file)
index 0000000..91ead27
--- /dev/null
@@ -0,0 +1,22 @@
+;(function () {
+  'use strict'
+
+  var util = require('util')
+  var logger = require('../../src/logger')
+
+  var utils = {}
+
+  utils.checkErrors = function (req, res, next, status_code) {
+    if (status_code === undefined) status_code = 400
+    var errors = req.validationErrors()
+
+    if (errors) {
+      logger.warn('Incorrect request parameters', { path: req.originalUrl, err: errors })
+      return res.status(status_code).send('There have been validation errors: ' + util.inspect(errors))
+    }
+
+    return next()
+  }
+
+  module.exports = utils
+})()
diff --git a/middlewares/reqValidators/videos.js b/middlewares/reqValidators/videos.js
new file mode 100644 (file)
index 0000000..3763a65
--- /dev/null
@@ -0,0 +1,67 @@
+;(function () {
+  'use strict'
+
+  var checkErrors = require('./utils').checkErrors
+  var VideosDB = require('../../src/database').VideosDB
+  var logger = require('../../src/logger')
+
+  var videos = {}
+
+  function findVideoById (id, callback) {
+    VideosDB.findById(id, { _id: 1, namePath: 1 }).limit(1).exec(function (err, video) {
+      if (err) throw err
+
+      callback(video)
+    })
+  }
+
+  videos.videosSearch = function (req, res, next) {
+    req.checkParams('name', 'Should have a name').notEmpty()
+
+    logger.debug('Checking videosSearch parameters', { parameters: req.params })
+
+    checkErrors(req, res, next)
+  }
+
+  videos.videosAdd = function (req, res, next) {
+    req.checkFiles('input_video.originalname', 'Should have an input video').notEmpty()
+    req.checkFiles('input_video.mimetype', 'Should have a correct mime type').matches(/video\/(webm)|(mp4)|(ogg)/i)
+    req.checkBody('name', 'Should have a name').isLength(1, 50)
+    req.checkBody('description', 'Should have a description').isLength(1, 250)
+
+    logger.debug('Checking videosAdd parameters', { parameters: req.body, files: req.files })
+
+    checkErrors(req, res, next)
+  }
+
+  videos.videosGet = function (req, res, next) {
+    req.checkParams('id', 'Should have a valid id').notEmpty().isMongoId()
+
+    logger.debug('Checking videosGet parameters', { parameters: req.params })
+
+    checkErrors(req, res, function () {
+      findVideoById(req.params.id, function (video) {
+        if (!video) return res.status(404).send('Video not found')
+
+        next()
+      })
+    })
+  }
+
+  videos.videosRemove = function (req, res, next) {
+    req.checkParams('id', 'Should have a valid id').notEmpty().isMongoId()
+
+    logger.debug('Checking videosRemove parameters', { parameters: req.params })
+
+    checkErrors(req, res, function () {
+      findVideoById(req.params.id, function (video) {
+        if (!video) return res.status(404).send('Video not found')
+        else if (video.namePath === null) return res.status(403).send('Cannot remove video of another pod')
+
+        next()
+      })
+    })
+  }
+
+  module.exports = videos
+})()
index 961388fcb01029762955e06515d67d9044254a18..8ae67683438feaa8a9bfb012b289ef2176ab7e27 100644 (file)
@@ -4,6 +4,7 @@
   var express = require('express')
   var router = express.Router()
   var middleware = require('../../../middlewares')
+  var reqValidator = require('../../../middlewares/reqValidators').pods
   var pods = require('../../../src/pods')
 
   function listPods (req, res, next) {
@@ -32,7 +33,7 @@
 
   router.get('/', middleware.cache(false), listPods)
   router.get('/makefriends', middleware.cache(false), makeFriends)
-  router.post('/', middleware.cache(false), addPods)
+  router.post('/', reqValidator.podsAdd, middleware.cache(false), addPods)
 
   module.exports = router
 })()
index 88b8e879b9dd54ed8717747686013d6d32113052..23bdcbe243ba914dd954c6dfdfbeb2b10fd396e8 100644 (file)
@@ -4,6 +4,7 @@
   var express = require('express')
   var router = express.Router()
   var middleware = require('../../../middlewares')
+  var requestValidator = require('../../../middlewares/reqValidators').remote
   var videos = require('../../../src/videos')
 
   function addRemoteVideos (req, res, next) {
@@ -22,8 +23,8 @@
     })
   }
 
-  router.post('/add', middleware.cache(false), middleware.decryptBody, addRemoteVideos)
-  router.post('/remove', middleware.cache(false), middleware.decryptBody, removeRemoteVideo)
+  router.post('/add', requestValidator.secureRequest, middleware.decryptBody, requestValidator.remoteVideosAdd, middleware.cache(false), addRemoteVideos)
+  router.post('/remove', requestValidator.secureRequest, middleware.decryptBody, requestValidator.remoteVideosRemove, middleware.cache(false), removeRemoteVideo)
 
   module.exports = router
 })()
index 246620ac6df1185030c18f661588393889eb6230..06b24824441c8dc7795fc15c40cbe59440750cc3 100644 (file)
@@ -4,6 +4,7 @@
   var express = require('express')
   var router = express.Router()
   var middleware = require('../../../middlewares')
+  var reqValidator = require('../../../middlewares/reqValidators').videos
   var videos = require('../../../src/videos')
 
   function listVideos (req, res, next) {
   }
 
   router.get('/', middleware.cache(false), listVideos)
-  router.post('/', middleware.cache(false), addVideos)
-  router.get('/search/:name', middleware.cache(false), searchVideos)
-  router.get('/:id', middleware.cache(false), getVideos)
-  router.delete('/:id', middleware.cache(false), removeVideo)
+  router.post('/', reqValidator.videosAdd, middleware.cache(false), addVideos)
+  router.get('/search/:name', reqValidator.videosSearch, middleware.cache(false), searchVideos)
+  router.get('/:id', reqValidator.videosGet, middleware.cache(false), getVideos)
+  router.delete('/:id', reqValidator.videosRemove, middleware.cache(false), removeVideo)
 
   module.exports = router
 })()
index d3718f8de31b59e99b6e9d98c2523376ab94ef44..317d8c3cde9568dbc79daa2e15ec7f53f4f2b02d 100644 (file)
--- a/server.js
+++ b/server.js
@@ -6,6 +6,7 @@
 
   // ----------- Node modules -----------
   var express = require('express')
+  var expressValidator = require('express-validator')
   var path = require('path')
   var morgan = require('morgan')
   var bodyParser = require('body-parser')
@@ -47,6 +48,7 @@
   app.use(bodyParser.json())
   app.use(multer({ dest: uploads }))
   app.use(bodyParser.urlencoded({ extended: false }))
+  app.use(expressValidator())
 
   // ----------- Views, routes and static files -----------
 
diff --git a/test/api/checkParams.js b/test/api/checkParams.js
new file mode 100644 (file)
index 0000000..a06e32b
--- /dev/null
@@ -0,0 +1,295 @@
+;(function () {
+  'use strict'
+
+  var request = require('supertest')
+  var chai = require('chai')
+  var expect = chai.expect
+
+  var utils = require('../utils')
+
+  describe('Test parameters validator', function () {
+    var app = null
+    var url = ''
+
+    before(function (done) {
+      this.timeout(20000)
+
+      utils.flushTests(function () {
+        utils.runServer(1, function (app1, url1) {
+          app = app1
+          url = url1
+          done()
+        })
+      })
+    })
+
+    function makePostRequest (path, fields, attach, done, fail) {
+      var status_code = 400
+      if (fail !== undefined && fail === false) status_code = 200
+
+      var req = request(url)
+        .post(path)
+        .set('Accept', 'application/json')
+
+      Object.keys(fields).forEach(function (field) {
+        var value = fields[field]
+        req.field(field, value)
+      })
+
+      req.expect(status_code, done)
+    }
+
+    function makePostBodyRequest (path, fields, done, fail) {
+      var status_code = 400
+      if (fail !== undefined && fail === false) status_code = 200
+
+      request(url)
+        .post(path)
+        .set('Accept', 'application/json')
+        .send(fields)
+        .expect(status_code, done)
+    }
+
+    describe('Of the pods API', function () {
+      var path = '/api/v1/pods/'
+
+      describe('When adding a pod', function () {
+        it('Should fail with nothing', function (done) {
+          var data = {}
+          makePostBodyRequest(path, data, done)
+        })
+
+        it('Should fail without public key', function (done) {
+          var data = {
+            data: {
+              url: 'http://coucou.com'
+            }
+          }
+          makePostBodyRequest(path, data, done)
+        })
+
+        it('Should fail without an url', function (done) {
+          var data = {
+            data: {
+              publicKey: 'mysuperpublickey'
+            }
+          }
+          makePostBodyRequest(path, data, done)
+        })
+
+        it('Should fail with an incorrect url', function (done) {
+          var data = {
+            data: {
+              url: 'coucou.com',
+              publicKey: 'mysuperpublickey'
+            }
+          }
+          makePostBodyRequest(path, data, function () {
+            data.data.url = 'http://coucou'
+            makePostBodyRequest(path, data, function () {
+              data.data.url = 'coucou'
+              makePostBodyRequest(path, data, done)
+            })
+          })
+        })
+
+        it('Should succeed with the correct parameters', function (done) {
+          var data = {
+            data: {
+              url: 'http://coucou.com',
+              publicKey: 'mysuperpublickey'
+            }
+          }
+          makePostBodyRequest(path, data, done, false)
+        })
+      })
+    })
+
+    describe('Of the videos API', function () {
+      var path = '/api/v1/videos/'
+
+      describe('When searching a video', function () {
+        it('Should fail with nothing', function (done) {
+          request(url)
+            .get(path + '/search/')
+            .set('Accept', 'application/json')
+            .expect(400, done)
+        })
+      })
+
+      describe('When adding a video', function () {
+        it('Should fail with nothing', function (done) {
+          var data = {}
+          var attach = {}
+          makePostRequest(path, data, attach, done)
+        })
+
+        it('Should fail without name', function (done) {
+          var data = {
+            description: 'my super description'
+          }
+          var attach = {
+            'input_video': __dirname + '/../fixtures/video_short.webm'
+          }
+          makePostRequest(path, data, attach, done)
+        })
+
+        it('Should fail with a long name', function (done) {
+          var data = {
+            name: 'My very very very very very very very very very very very very very very very very long name',
+            description: 'my super description'
+          }
+          var attach = {
+            'input_video': __dirname + '/../fixtures/video_short.webm'
+          }
+          makePostRequest(path, data, attach, done)
+        })
+
+        it('Should fail without description', function (done) {
+          var data = {
+            name: 'my super name'
+          }
+          var attach = {
+            'input_video': __dirname + '/../fixtures/video_short.webm'
+          }
+          makePostRequest(path, data, attach, done)
+        })
+
+        it('Should fail with a long description', function (done) {
+          var data = {
+            name: 'my super name',
+            description: 'my super description which is very very very very very very very very very very very very very very' +
+                         'very very very very very very very very very very very very very very very very very very very very very' +
+                         'very very very very very very very very very very very very very very very long'
+          }
+          var attach = {
+            'input_video': __dirname + '/../fixtures/video_short.webm'
+          }
+          makePostRequest(path, data, attach, done)
+        })
+
+        it('Should fail without an input file', function (done) {
+          var data = {
+            name: 'my super name',
+            description: 'my super description'
+          }
+          var attach = {}
+          makePostRequest(path, data, attach, done)
+        })
+
+        it('Should fail without an incorrect input file', function (done) {
+          var data = {
+            name: 'my super name',
+            description: 'my super description'
+          }
+          var attach = {
+            'input_video': __dirname + '/../fixtures/video_short_fake.webm'
+          }
+          makePostRequest(path, data, attach, done)
+        })
+
+        it('Should succeed with the correct parameters', function (done) {
+          var data = {
+            name: 'my super name',
+            description: 'my super description'
+          }
+          var attach = {
+            'input_video': __dirname + '/../fixtures/video_short.webm'
+          }
+          makePostRequest(path, data, attach, function () {
+            attach.input_video = __dirname + '/../fixtures/video_short.mp4'
+            makePostRequest(path, data, attach, function () {
+              attach.input_video = __dirname + '/../fixtures/video_short.ogv'
+              makePostRequest(path, data, attach, done, true)
+            }, true)
+          }, true)
+        })
+      })
+
+      describe('When getting a video', function () {
+        it('Should return the list of the videos with nothing', function (done) {
+          request(url)
+            .get(path)
+            .set('Accept', 'application/json')
+            .expect(200)
+            .expect('Content-Type', /json/)
+            .end(function (err, res) {
+              if (err) throw err
+
+              expect(res.body).to.be.an('array')
+              expect(res.body.length).to.equal(0)
+
+              done()
+            })
+        })
+
+        it('Should fail without a mongodb id', function (done) {
+          request(url)
+            .get(path + 'coucou')
+            .set('Accept', 'application/json')
+            .expect(400, done)
+        })
+
+        it('Should return 404 with an incorrect video', function (done) {
+          request(url)
+            .get(path + '123456789012345678901234')
+            .set('Accept', 'application/json')
+            .expect(404, done)
+        })
+
+        it('Should succeed with the correct parameters')
+      })
+
+      describe('When removing a video', function () {
+        it('Should have 404 with nothing', function (done) {
+          request(url)
+          .delete(path)
+          .expect(404, done)
+        })
+
+        it('Should fail without a mongodb id', function (done) {
+          request(url)
+            .delete(path + 'hello')
+            .expect(400, done)
+        })
+
+        it('Should fail with a video which does not exist', function (done) {
+          request(url)
+            .delete(path + '123456789012345678901234')
+            .expect(404, done)
+        })
+
+        it('Should fail with a video of another pod')
+
+        it('Should succeed with the correct parameters')
+      })
+    })
+
+    describe('Of the remote videos API', function () {
+      describe('When making a secure request', function () {
+        it('Should check a secure request')
+      })
+
+      describe('When adding a video', function () {
+        it('Should check when adding a video')
+      })
+
+      describe('When removing a video', function () {
+        it('Should check when removing a video')
+      })
+    })
+
+    after(function (done) {
+      process.kill(-app.pid)
+
+      // Keep the logs if the test failed
+      if (this.ok) {
+        utils.flushTests(function () {
+          done()
+        })
+      } else {
+        done()
+      }
+    })
+  })
+})()
diff --git a/test/fixtures/video_short.mp4 b/test/fixtures/video_short.mp4
new file mode 100644 (file)
index 0000000..3567836
Binary files /dev/null and b/test/fixtures/video_short.mp4 differ
diff --git a/test/fixtures/video_short.ogv b/test/fixtures/video_short.ogv
new file mode 100644 (file)
index 0000000..9e253da
Binary files /dev/null and b/test/fixtures/video_short.ogv differ
diff --git a/test/fixtures/video_short_fake.webm b/test/fixtures/video_short_fake.webm
new file mode 100644 (file)
index 0000000..d85290a
--- /dev/null
@@ -0,0 +1 @@
+this is a fake video mouahahah