aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/helpers
diff options
context:
space:
mode:
Diffstat (limited to 'server/helpers')
-rw-r--r--server/helpers/custom-validators/index.js2
-rw-r--r--server/helpers/custom-validators/pods.js9
-rw-r--r--server/helpers/custom-validators/remote/index.js11
-rw-r--r--server/helpers/custom-validators/remote/videos.js73
-rw-r--r--server/helpers/custom-validators/videos.js71
-rw-r--r--server/helpers/logger.js6
-rw-r--r--server/helpers/peertube-crypto.js65
-rw-r--r--server/helpers/requests.js46
-rw-r--r--server/helpers/utils.js35
9 files changed, 223 insertions, 95 deletions
diff --git a/server/helpers/custom-validators/index.js b/server/helpers/custom-validators/index.js
index 96b5b20b9..9383e0304 100644
--- a/server/helpers/custom-validators/index.js
+++ b/server/helpers/custom-validators/index.js
@@ -2,12 +2,14 @@
2 2
3const miscValidators = require('./misc') 3const miscValidators = require('./misc')
4const podsValidators = require('./pods') 4const podsValidators = require('./pods')
5const remoteValidators = require('./remote')
5const usersValidators = require('./users') 6const usersValidators = require('./users')
6const videosValidators = require('./videos') 7const videosValidators = require('./videos')
7 8
8const validators = { 9const validators = {
9 misc: miscValidators, 10 misc: miscValidators,
10 pods: podsValidators, 11 pods: podsValidators,
12 remote: remoteValidators,
11 users: usersValidators, 13 users: usersValidators,
12 videos: videosValidators 14 videos: videosValidators
13} 15}
diff --git a/server/helpers/custom-validators/pods.js b/server/helpers/custom-validators/pods.js
index 0154a2424..8bb3733ff 100644
--- a/server/helpers/custom-validators/pods.js
+++ b/server/helpers/custom-validators/pods.js
@@ -5,14 +5,19 @@ const validator = require('express-validator').validator
5const miscValidators = require('./misc') 5const miscValidators = require('./misc')
6 6
7const podsValidators = { 7const podsValidators = {
8 isEachUniqueHostValid 8 isEachUniqueHostValid,
9 isHostValid
10}
11
12function isHostValid (host) {
13 return validator.isURL(host) && host.split('://').length === 1
9} 14}
10 15
11function isEachUniqueHostValid (hosts) { 16function isEachUniqueHostValid (hosts) {
12 return miscValidators.isArray(hosts) && 17 return miscValidators.isArray(hosts) &&
13 hosts.length !== 0 && 18 hosts.length !== 0 &&
14 hosts.every(function (host) { 19 hosts.every(function (host) {
15 return validator.isURL(host) && host.split('://').length === 1 && hosts.indexOf(host) === hosts.lastIndexOf(host) 20 return isHostValid(host) && hosts.indexOf(host) === hosts.lastIndexOf(host)
16 }) 21 })
17} 22}
18 23
diff --git a/server/helpers/custom-validators/remote/index.js b/server/helpers/custom-validators/remote/index.js
new file mode 100644
index 000000000..1939a95f4
--- /dev/null
+++ b/server/helpers/custom-validators/remote/index.js
@@ -0,0 +1,11 @@
1'use strict'
2
3const remoteVideosValidators = require('./videos')
4
5const validators = {
6 videos: remoteVideosValidators
7}
8
9// ---------------------------------------------------------------------------
10
11module.exports = validators
diff --git a/server/helpers/custom-validators/remote/videos.js b/server/helpers/custom-validators/remote/videos.js
new file mode 100644
index 000000000..7c27b9dbb
--- /dev/null
+++ b/server/helpers/custom-validators/remote/videos.js
@@ -0,0 +1,73 @@
1'use strict'
2
3const videosValidators = require('../videos')
4const miscValidators = require('../misc')
5
6const remoteVideosValidators = {
7 isEachRemoteRequestVideosValid
8}
9
10function isEachRemoteRequestVideosValid (requests) {
11 return miscValidators.isArray(requests) &&
12 requests.every(function (request) {
13 const video = request.data
14 return (
15 isRequestTypeAddValid(request.type) &&
16 videosValidators.isVideoAuthorValid(video.author) &&
17 videosValidators.isVideoDateValid(video.createdAt) &&
18 videosValidators.isVideoDateValid(video.updatedAt) &&
19 videosValidators.isVideoDescriptionValid(video.description) &&
20 videosValidators.isVideoDurationValid(video.duration) &&
21 videosValidators.isVideoInfoHashValid(video.infoHash) &&
22 videosValidators.isVideoNameValid(video.name) &&
23 videosValidators.isVideoTagsValid(video.tags) &&
24 videosValidators.isVideoThumbnailDataValid(video.thumbnailData) &&
25 videosValidators.isVideoRemoteIdValid(video.remoteId) &&
26 videosValidators.isVideoExtnameValid(video.extname)
27 ) ||
28 (
29 isRequestTypeUpdateValid(request.type) &&
30 videosValidators.isVideoDateValid(video.createdAt) &&
31 videosValidators.isVideoDateValid(video.updatedAt) &&
32 videosValidators.isVideoDescriptionValid(video.description) &&
33 videosValidators.isVideoDurationValid(video.duration) &&
34 videosValidators.isVideoInfoHashValid(video.infoHash) &&
35 videosValidators.isVideoNameValid(video.name) &&
36 videosValidators.isVideoTagsValid(video.tags) &&
37 videosValidators.isVideoRemoteIdValid(video.remoteId) &&
38 videosValidators.isVideoExtnameValid(video.extname)
39 ) ||
40 (
41 isRequestTypeRemoveValid(request.type) &&
42 videosValidators.isVideoRemoteIdValid(video.remoteId)
43 ) ||
44 (
45 isRequestTypeReportAbuseValid(request.type) &&
46 videosValidators.isVideoRemoteIdValid(request.data.videoRemoteId) &&
47 videosValidators.isVideoAbuseReasonValid(request.data.reportReason) &&
48 videosValidators.isVideoAbuseReporterUsernameValid(request.data.reporterUsername)
49 )
50 })
51}
52
53// ---------------------------------------------------------------------------
54
55module.exports = remoteVideosValidators
56
57// ---------------------------------------------------------------------------
58
59function isRequestTypeAddValid (value) {
60 return value === 'add'
61}
62
63function isRequestTypeUpdateValid (value) {
64 return value === 'update'
65}
66
67function isRequestTypeRemoveValid (value) {
68 return value === 'remove'
69}
70
71function isRequestTypeReportAbuseValid (value) {
72 return value === 'report-abuse'
73}
diff --git a/server/helpers/custom-validators/videos.js b/server/helpers/custom-validators/videos.js
index 1a7753265..7f727854d 100644
--- a/server/helpers/custom-validators/videos.js
+++ b/server/helpers/custom-validators/videos.js
@@ -6,43 +6,22 @@ const constants = require('../../initializers/constants')
6const usersValidators = require('./users') 6const usersValidators = require('./users')
7const miscValidators = require('./misc') 7const miscValidators = require('./misc')
8const VIDEOS_CONSTRAINTS_FIELDS = constants.CONSTRAINTS_FIELDS.VIDEOS 8const VIDEOS_CONSTRAINTS_FIELDS = constants.CONSTRAINTS_FIELDS.VIDEOS
9const VIDEO_ABUSES_CONSTRAINTS_FIELDS = constants.CONSTRAINTS_FIELDS.VIDEO_ABUSES
9 10
10const videosValidators = { 11const videosValidators = {
11 isEachRemoteVideosValid,
12 isVideoAuthorValid, 12 isVideoAuthorValid,
13 isVideoDateValid, 13 isVideoDateValid,
14 isVideoDescriptionValid, 14 isVideoDescriptionValid,
15 isVideoDurationValid, 15 isVideoDurationValid,
16 isVideoMagnetValid, 16 isVideoInfoHashValid,
17 isVideoNameValid, 17 isVideoNameValid,
18 isVideoPodHostValid,
19 isVideoTagsValid, 18 isVideoTagsValid,
20 isVideoThumbnailValid, 19 isVideoThumbnailValid,
21 isVideoThumbnail64Valid 20 isVideoThumbnailDataValid,
22} 21 isVideoExtnameValid,
23 22 isVideoRemoteIdValid,
24function isEachRemoteVideosValid (requests) { 23 isVideoAbuseReasonValid,
25 return miscValidators.isArray(requests) && 24 isVideoAbuseReporterUsernameValid
26 requests.every(function (request) {
27 const video = request.data
28 return (
29 isRequestTypeAddValid(request.type) &&
30 isVideoAuthorValid(video.author) &&
31 isVideoDateValid(video.createdDate) &&
32 isVideoDescriptionValid(video.description) &&
33 isVideoDurationValid(video.duration) &&
34 isVideoMagnetValid(video.magnet) &&
35 isVideoNameValid(video.name) &&
36 isVideoTagsValid(video.tags) &&
37 isVideoThumbnail64Valid(video.thumbnailBase64) &&
38 isVideoRemoteIdValid(video.remoteId)
39 ) ||
40 (
41 isRequestTypeRemoveValid(request.type) &&
42 isVideoNameValid(video.name) &&
43 isVideoRemoteIdValid(video.remoteId)
44 )
45 })
46} 25}
47 26
48function isVideoAuthorValid (value) { 27function isVideoAuthorValid (value) {
@@ -61,17 +40,16 @@ function isVideoDurationValid (value) {
61 return validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.DURATION) 40 return validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.DURATION)
62} 41}
63 42
64function isVideoMagnetValid (value) { 43function isVideoExtnameValid (value) {
65 return validator.isLength(value.infoHash, VIDEOS_CONSTRAINTS_FIELDS.MAGNET.INFO_HASH) 44 return VIDEOS_CONSTRAINTS_FIELDS.EXTNAME.indexOf(value) !== -1
66} 45}
67 46
68function isVideoNameValid (value) { 47function isVideoInfoHashValid (value) {
69 return validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.NAME) 48 return validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.INFO_HASH)
70} 49}
71 50
72function isVideoPodHostValid (value) { 51function isVideoNameValid (value) {
73 // TODO: set options (TLD...) 52 return validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.NAME)
74 return validator.isURL(value)
75} 53}
76 54
77function isVideoTagsValid (tags) { 55function isVideoTagsValid (tags) {
@@ -87,25 +65,22 @@ function isVideoThumbnailValid (value) {
87 return validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.THUMBNAIL) 65 return validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.THUMBNAIL)
88} 66}
89 67
90function isVideoThumbnail64Valid (value) { 68function isVideoThumbnailDataValid (value) {
91 return validator.isBase64(value) && 69 return validator.isByteLength(value, VIDEOS_CONSTRAINTS_FIELDS.THUMBNAIL_DATA)
92 validator.isByteLength(value, VIDEOS_CONSTRAINTS_FIELDS.THUMBNAIL64)
93} 70}
94 71
95function isVideoRemoteIdValid (value) { 72function isVideoRemoteIdValid (value) {
96 return validator.isMongoId(value) 73 return validator.isUUID(value, 4)
97} 74}
98 75
99// --------------------------------------------------------------------------- 76function isVideoAbuseReasonValid (value) {
77 return validator.isLength(value, VIDEO_ABUSES_CONSTRAINTS_FIELDS.REASON)
78}
100 79
101module.exports = videosValidators 80function isVideoAbuseReporterUsernameValid (value) {
81 return usersValidators.isUserUsernameValid(value)
82}
102 83
103// --------------------------------------------------------------------------- 84// ---------------------------------------------------------------------------
104 85
105function isRequestTypeAddValid (value) { 86module.exports = videosValidators
106 return value === 'add'
107}
108
109function isRequestTypeRemoveValid (value) {
110 return value === 'remove'
111}
diff --git a/server/helpers/logger.js b/server/helpers/logger.js
index fcc1789fd..281acedb8 100644
--- a/server/helpers/logger.js
+++ b/server/helpers/logger.js
@@ -22,7 +22,8 @@ const logger = new winston.Logger({
22 json: true, 22 json: true,
23 maxsize: 5242880, 23 maxsize: 5242880,
24 maxFiles: 5, 24 maxFiles: 5,
25 colorize: false 25 colorize: false,
26 prettyPrint: true
26 }), 27 }),
27 new winston.transports.Console({ 28 new winston.transports.Console({
28 level: 'debug', 29 level: 'debug',
@@ -30,7 +31,8 @@ const logger = new winston.Logger({
30 handleExceptions: true, 31 handleExceptions: true,
31 humanReadableUnhandledException: true, 32 humanReadableUnhandledException: true,
32 json: false, 33 json: false,
33 colorize: true 34 colorize: true,
35 prettyPrint: true
34 }) 36 })
35 ], 37 ],
36 exitOnError: true 38 exitOnError: true
diff --git a/server/helpers/peertube-crypto.js b/server/helpers/peertube-crypto.js
index 2e07df00e..0f1e02ad6 100644
--- a/server/helpers/peertube-crypto.js
+++ b/server/helpers/peertube-crypto.js
@@ -1,16 +1,13 @@
1'use strict' 1'use strict'
2 2
3const bcrypt = require('bcrypt')
4const crypto = require('crypto') 3const crypto = require('crypto')
4const bcrypt = require('bcrypt')
5const fs = require('fs') 5const fs = require('fs')
6const openssl = require('openssl-wrapper') 6const openssl = require('openssl-wrapper')
7const ursa = require('ursa')
8 7
9const constants = require('../initializers/constants') 8const constants = require('../initializers/constants')
10const logger = require('./logger') 9const logger = require('./logger')
11 10
12const algorithm = 'aes-256-ctr'
13
14const peertubeCrypto = { 11const peertubeCrypto = {
15 checkSignature, 12 checkSignature,
16 comparePassword, 13 comparePassword,
@@ -19,12 +16,51 @@ const peertubeCrypto = {
19 sign 16 sign
20} 17}
21 18
22function checkSignature (publicKey, rawData, hexSignature) { 19function checkSignature (publicKey, data, hexSignature) {
23 const crt = ursa.createPublicKey(publicKey) 20 const verify = crypto.createVerify(constants.SIGNATURE_ALGORITHM)
24 const isValid = crt.hashAndVerify('sha256', new Buffer(rawData).toString('hex'), hexSignature, 'hex') 21
22 let dataString
23 if (typeof data === 'string') {
24 dataString = data
25 } else {
26 try {
27 dataString = JSON.stringify(data)
28 } catch (err) {
29 logger.error('Cannot check signature.', { error: err })
30 return false
31 }
32 }
33
34 verify.update(dataString, 'utf8')
35
36 const isValid = verify.verify(publicKey, hexSignature, constants.SIGNATURE_ENCODING)
25 return isValid 37 return isValid
26} 38}
27 39
40function sign (data) {
41 const sign = crypto.createSign(constants.SIGNATURE_ALGORITHM)
42
43 let dataString
44 if (typeof data === 'string') {
45 dataString = data
46 } else {
47 try {
48 dataString = JSON.stringify(data)
49 } catch (err) {
50 logger.error('Cannot sign data.', { error: err })
51 return ''
52 }
53 }
54
55 sign.update(dataString, 'utf8')
56
57 // TODO: make async
58 const myKey = fs.readFileSync(constants.CONFIG.STORAGE.CERT_DIR + 'peertube.key.pem')
59 const signature = sign.sign(myKey, constants.SIGNATURE_ENCODING)
60
61 return signature
62}
63
28function comparePassword (plainPassword, hashPassword, callback) { 64function comparePassword (plainPassword, hashPassword, callback) {
29 bcrypt.compare(plainPassword, hashPassword, function (err, isPasswordMatch) { 65 bcrypt.compare(plainPassword, hashPassword, function (err, isPasswordMatch) {
30 if (err) return callback(err) 66 if (err) return callback(err)
@@ -55,13 +91,6 @@ function cryptPassword (password, callback) {
55 }) 91 })
56} 92}
57 93
58function sign (data) {
59 const myKey = ursa.createPrivateKey(fs.readFileSync(constants.CONFIG.STORAGE.CERT_DIR + 'peertube.key.pem'))
60 const signature = myKey.hashAndSign('sha256', data, 'utf8', 'hex')
61
62 return signature
63}
64
65// --------------------------------------------------------------------------- 94// ---------------------------------------------------------------------------
66 95
67module.exports = peertubeCrypto 96module.exports = peertubeCrypto
@@ -113,11 +142,3 @@ function createCerts (callback) {
113 }) 142 })
114 }) 143 })
115} 144}
116
117function generatePassword (callback) {
118 crypto.randomBytes(32, function (err, buf) {
119 if (err) return callback(err)
120
121 callback(null, buf.toString('utf8'))
122 })
123}
diff --git a/server/helpers/requests.js b/server/helpers/requests.js
index b0cda09fe..095b95e1c 100644
--- a/server/helpers/requests.js
+++ b/server/helpers/requests.js
@@ -28,31 +28,37 @@ function makeSecureRequest (params, callback) {
28 url: constants.REMOTE_SCHEME.HTTP + '://' + params.toPod.host + params.path 28 url: constants.REMOTE_SCHEME.HTTP + '://' + params.toPod.host + params.path
29 } 29 }
30 30
31 // Add data with POST requst ? 31 if (params.method !== 'POST') {
32 if (params.method === 'POST') { 32 return callback(new Error('Cannot make a secure request with a non POST method.'))
33 requestParams.json = {} 33 }
34 34
35 // Add signature if it is specified in the params 35 requestParams.json = {}
36 if (params.sign === true) {
37 const host = constants.CONFIG.WEBSERVER.HOST
38
39 requestParams.json.signature = {
40 host,
41 signature: peertubeCrypto.sign(host)
42 }
43 }
44 36
45 // If there are data informations 37 // Add signature if it is specified in the params
38 if (params.sign === true) {
39 const host = constants.CONFIG.WEBSERVER.HOST
40
41 let dataToSign
46 if (params.data) { 42 if (params.data) {
47 requestParams.json.data = params.data 43 dataToSign = dataToSign = params.data
48 request.post(requestParams, callback)
49 } else { 44 } else {
50 // No data 45 // We do not have data to sign so we just take our host
51 request.post(requestParams, callback) 46 // It is not ideal but the connection should be in HTTPS
47 dataToSign = host
52 } 48 }
53 } else { 49
54 request.get(requestParams, callback) 50 requestParams.json.signature = {
51 host, // Which host we pretend to be
52 signature: peertubeCrypto.sign(dataToSign)
53 }
54 }
55
56 // If there are data informations
57 if (params.data) {
58 requestParams.json.data = params.data
55 } 59 }
60
61 request.post(requestParams, callback)
56} 62}
57 63
58// --------------------------------------------------------------------------- 64// ---------------------------------------------------------------------------
diff --git a/server/helpers/utils.js b/server/helpers/utils.js
index 9f27671b6..a902850cd 100644
--- a/server/helpers/utils.js
+++ b/server/helpers/utils.js
@@ -1,13 +1,21 @@
1'use strict' 1'use strict'
2 2
3const crypto = require('crypto') 3const crypto = require('crypto')
4const retry = require('async/retry')
4 5
5const logger = require('./logger') 6const logger = require('./logger')
6 7
7const utils = { 8const utils = {
9 badRequest,
8 cleanForExit, 10 cleanForExit,
9 generateRandomString, 11 generateRandomString,
10 isTestInstance 12 isTestInstance,
13 getFormatedObjects,
14 transactionRetryer
15}
16
17function badRequest (req, res, next) {
18 res.type('json').status(400).end()
11} 19}
12 20
13function generateRandomString (size, callback) { 21function generateRandomString (size, callback) {
@@ -27,6 +35,31 @@ function isTestInstance () {
27 return (process.env.NODE_ENV === 'test') 35 return (process.env.NODE_ENV === 'test')
28} 36}
29 37
38function getFormatedObjects (objects, objectsTotal) {
39 const formatedObjects = []
40
41 objects.forEach(function (object) {
42 formatedObjects.push(object.toFormatedJSON())
43 })
44
45 return {
46 total: objectsTotal,
47 data: formatedObjects
48 }
49}
50
51function transactionRetryer (func, callback) {
52 retry({
53 times: 5,
54
55 errorFilter: function (err) {
56 const willRetry = (err.name === 'SequelizeDatabaseError')
57 logger.debug('Maybe retrying the transaction function.', { willRetry })
58 return willRetry
59 }
60 }, func, callback)
61}
62
30// --------------------------------------------------------------------------- 63// ---------------------------------------------------------------------------
31 64
32module.exports = utils 65module.exports = utils