var friends = require('../../../lib/friends')
var middleware = require('../../../middlewares')
var cacheMiddleware = middleware.cache
+ var peertubeCrypto = require('../../../helpers/peertubeCrypto')
var Pods = require('../../../models/pods')
var reqValidator = middleware.reqValidators.pods
var secureMiddleware = middleware.secure
var secureRequest = middleware.reqValidators.remote.secureRequest
- var utils = require('../../../helpers/utils')
var Videos = require('../../../models/videos')
var router = express.Router()
Videos.addRemotes(informations.videos)
- fs.readFile(utils.getCertDir() + 'peertube.pub', 'utf8', function (err, cert) {
+ fs.readFile(peertubeCrypto.getCertDir() + 'peertube.pub', 'utf8', function (err, cert) {
if (err) {
logger.error('Cannot read cert file.', { error: err })
return next(err)
--- /dev/null
+;(function () {
+ 'use strict'
+
+ var config = require('config')
+ var crypto = require('crypto')
+ var fs = require('fs')
+ var openssl = require('openssl-wrapper')
+ var ursa = require('ursa')
+
+ var logger = require('./logger')
+
+ var certDir = __dirname + '/../' + config.get('storage.certs')
+ var algorithm = 'aes-256-ctr'
+
+ var peertubeCrypto = {
+ checkSignature: checkSignature,
+ createCertsIfNotExist: createCertsIfNotExist,
+ decrypt: decrypt,
+ encrypt: encrypt,
+ getCertDir: getCertDir,
+ sign: sign
+ }
+
+ function checkSignature (public_key, raw_data, hex_signature) {
+ var crt = ursa.createPublicKey(public_key)
+ var is_valid = crt.hashAndVerify('sha256', new Buffer(raw_data).toString('hex'), hex_signature, 'hex')
+ return is_valid
+ }
+
+ function createCertsIfNotExist (callback) {
+ certsExist(function (exist) {
+ if (exist === true) {
+ return callback(null)
+ }
+
+ createCerts(function (err) {
+ return callback(err)
+ })
+ })
+ }
+
+ function decrypt (key, data, callback) {
+ fs.readFile(getCertDir() + 'peertube.key.pem', function (err, file) {
+ if (err) return callback(err)
+
+ var my_private_key = ursa.createPrivateKey(file)
+ var decrypted_key = my_private_key.decrypt(key, 'hex', 'utf8')
+ var decrypted_data = symetricDecrypt(data, decrypted_key)
+
+ return callback(null, decrypted_data)
+ })
+ }
+
+ function encrypt (public_key, data, callback) {
+ var crt = ursa.createPublicKey(public_key)
+
+ symetricEncrypt(data, function (err, dataEncrypted) {
+ if (err) return callback(err)
+
+ var key = crt.encrypt(dataEncrypted.password, 'utf8', 'hex')
+ var encrypted = {
+ data: dataEncrypted.crypted,
+ key: key
+ }
+
+ callback(null, encrypted)
+ })
+ }
+
+ function getCertDir () {
+ return certDir
+ }
+
+ function sign (data) {
+ var myKey = ursa.createPrivateKey(fs.readFileSync(certDir + 'peertube.key.pem'))
+ var signature = myKey.hashAndSign('sha256', data, 'utf8', 'hex')
+
+ return signature
+ }
+
+ // ---------------------------------------------------------------------------
+
+ module.exports = peertubeCrypto
+
+ // ---------------------------------------------------------------------------
+
+ function certsExist (callback) {
+ fs.exists(certDir + 'peertube.key.pem', function (exists) {
+ return callback(exists)
+ })
+ }
+
+ function createCerts (callback) {
+ certsExist(function (exist) {
+ if (exist === true) {
+ var string = 'Certs already exist.'
+ logger.warning(string)
+ return callback(new Error(string))
+ }
+
+ logger.info('Generating a RSA key...')
+ openssl.exec('genrsa', { 'out': certDir + 'peertube.key.pem', '2048': false }, function (err) {
+ if (err) {
+ logger.error('Cannot create private key on this pod.', { error: err })
+ return callback(err)
+ }
+ logger.info('RSA key generated.')
+
+ logger.info('Manage public key...')
+ openssl.exec('rsa', { 'in': certDir + 'peertube.key.pem', 'pubout': true, 'out': certDir + 'peertube.pub' }, function (err) {
+ if (err) {
+ logger.error('Cannot create public key on this pod .', { error: err })
+ return callback(err)
+ }
+
+ logger.info('Public key managed.')
+ return callback(null)
+ })
+ })
+ })
+ }
+
+ function generatePassword (callback) {
+ crypto.randomBytes(32, function (err, buf) {
+ if (err) {
+ return callback(err)
+ }
+
+ callback(null, buf.toString('utf8'))
+ })
+ }
+
+ function symetricDecrypt (text, password) {
+ var decipher = crypto.createDecipher(algorithm, password)
+ var dec = decipher.update(text, 'hex', 'utf8')
+ dec += decipher.final('utf8')
+ return dec
+ }
+
+ function symetricEncrypt (text, callback) {
+ generatePassword(function (err, password) {
+ if (err) {
+ return callback(err)
+ }
+
+ var cipher = crypto.createCipher(algorithm, password)
+ var crypted = cipher.update(text, 'utf8', 'hex')
+ crypted += cipher.final('hex')
+ callback(null, { crypted: crypted, password: password })
+ })
+ }
+})()
--- /dev/null
+;(function () {
+ 'use strict'
+
+ var async = require('async')
+ var config = require('config')
+ var request = require('request')
+ var replay = require('request-replay')
+
+ var constants = require('../initializers/constants')
+ var logger = require('./logger')
+ var peertubeCrypto = require('./peertubeCrypto')
+
+ var http = config.get('webserver.https') ? 'https' : 'http'
+ var host = config.get('webserver.host')
+ var port = config.get('webserver.port')
+
+ var requests = {
+ makeMultipleRetryRequest: makeMultipleRetryRequest
+ }
+
+ function makeMultipleRetryRequest (all_data, pods, callbackEach, callback) {
+ if (!callback) {
+ callback = callbackEach
+ callbackEach = null
+ }
+
+ var url = http + '://' + host + ':' + port
+ var signature
+
+ // Add signature if it is specified in the params
+ if (all_data.method === 'POST' && all_data.data && all_data.sign === true) {
+ signature = peertubeCrypto.sign(url)
+ }
+
+ // Make a request for each pod
+ async.each(pods, function (pod, callback_each_async) {
+ function callbackEachRetryRequest (err, response, body, url, pod) {
+ if (callbackEach !== null) {
+ callbackEach(err, response, body, url, pod, function () {
+ callback_each_async()
+ })
+ } else {
+ callback_each_async()
+ }
+ }
+
+ var params = {
+ url: pod.url + all_data.path,
+ method: all_data.method
+ }
+
+ // Add data with POST requst ?
+ if (all_data.method === 'POST' && all_data.data) {
+ // Encrypt data ?
+ if (all_data.encrypt === true) {
+ // TODO: ES6 with let
+ ;(function (copy_params, copy_url, copy_pod, copy_signature) {
+ peertubeCrypto.encrypt(pod.publicKey, JSON.stringify(all_data.data), function (err, encrypted) {
+ if (err) return callback(err)
+
+ copy_params.json = {
+ data: encrypted.data,
+ key: encrypted.key
+ }
+
+ makeRetryRequest(copy_params, copy_url, copy_pod, copy_signature, callbackEachRetryRequest)
+ })
+ })(params, url, pod, signature)
+ } else {
+ params.json = { data: all_data.data }
+ makeRetryRequest(params, url, pod, signature, callbackEachRetryRequest)
+ }
+ } else {
+ makeRetryRequest(params, url, pod, signature, callbackEachRetryRequest)
+ }
+ }, callback)
+ }
+
+ // ---------------------------------------------------------------------------
+
+ module.exports = requests
+
+ // ---------------------------------------------------------------------------
+
+ function makeRetryRequest (params, from_url, to_pod, signature, callbackEach) {
+ // Append the signature
+ if (signature) {
+ params.json.signature = {
+ url: from_url,
+ signature: signature
+ }
+ }
+
+ logger.debug('Make retry requests to %s.', to_pod.url)
+
+ replay(
+ request.post(params, function (err, response, body) {
+ callbackEach(err, response, body, params.url, to_pod)
+ }),
+ {
+ retries: constants.REQUEST_RETRIES,
+ factor: 3,
+ maxTimeout: Infinity,
+ errorCodes: [ 'EADDRINFO', 'ETIMEDOUT', 'ECONNRESET', 'ESOCKETTIMEDOUT', 'ENOTFOUND', 'ECONNREFUSED' ]
+ }
+ ).on('replay', function (replay) {
+ logger.info('Replaying request to %s. Request failed: %d %s. Replay number: #%d. Will retry in: %d ms.',
+ params.url, replay.error.code, replay.error.message, replay.number, replay.delay)
+ })
+ }
+})()
;(function () {
'use strict'
- var async = require('async')
- var config = require('config')
- var crypto = require('crypto')
- var fs = require('fs')
- var openssl = require('openssl-wrapper')
- var request = require('request')
- var replay = require('request-replay')
- var ursa = require('ursa')
-
- var constants = require('../initializers/constants')
var logger = require('./logger')
- var certDir = __dirname + '/../' + config.get('storage.certs')
- var http = config.get('webserver.https') ? 'https' : 'http'
- var host = config.get('webserver.host')
- var port = config.get('webserver.port')
- var algorithm = 'aes-256-ctr'
-
var utils = {
- getCertDir: getCertDir,
- certsExist: certsExist,
- cleanForExit: cleanForExit,
- createCerts: createCerts,
- createCertsIfNotExist: createCertsIfNotExist,
- generatePassword: generatePassword,
- makeMultipleRetryRequest: makeMultipleRetryRequest,
- symetricEncrypt: symetricEncrypt,
- symetricDecrypt: symetricDecrypt
- }
-
- function getCertDir () {
- return certDir
- }
-
- function makeMultipleRetryRequest (all_data, pods, callbackEach, callback) {
- if (!callback) {
- callback = callbackEach
- callbackEach = null
- }
-
- var url = http + '://' + host + ':' + port
- var signature
-
- // Add signature if it is specified in the params
- if (all_data.method === 'POST' && all_data.data && all_data.sign === true) {
- var myKey = ursa.createPrivateKey(fs.readFileSync(certDir + 'peertube.key.pem'))
- signature = myKey.hashAndSign('sha256', url, 'utf8', 'hex')
- }
-
- // Make a request for each pod
- async.each(pods, function (pod, callback_each_async) {
- function callbackEachRetryRequest (err, response, body, url, pod) {
- if (callbackEach !== null) {
- callbackEach(err, response, body, url, pod, function () {
- callback_each_async()
- })
- } else {
- callback_each_async()
- }
- }
-
- var params = {
- url: pod.url + all_data.path,
- method: all_data.method
- }
-
- // Add data with POST requst ?
- if (all_data.method === 'POST' && all_data.data) {
- // Encrypt data ?
- if (all_data.encrypt === true) {
- var crt = ursa.createPublicKey(pod.publicKey)
-
- // TODO: ES6 with let
- ;(function (crt_copy, copy_params, copy_url, copy_pod, copy_signature) {
- symetricEncrypt(JSON.stringify(all_data.data), function (err, dataEncrypted) {
- if (err) throw err
-
- var passwordEncrypted = crt_copy.encrypt(dataEncrypted.password, 'utf8', 'hex')
- copy_params.json = {
- data: dataEncrypted.crypted,
- key: passwordEncrypted
- }
-
- makeRetryRequest(copy_params, copy_url, copy_pod, copy_signature, callbackEachRetryRequest)
- })
- })(crt, params, url, pod, signature)
- } else {
- params.json = { data: all_data.data }
- makeRetryRequest(params, url, pod, signature, callbackEachRetryRequest)
- }
- } else {
- makeRetryRequest(params, url, pod, signature, callbackEachRetryRequest)
- }
- }, callback)
- }
-
- function certsExist (callback) {
- fs.exists(certDir + 'peertube.key.pem', function (exists) {
- return callback(exists)
- })
- }
-
- function createCerts (callback) {
- certsExist(function (exist) {
- if (exist === true) {
- var string = 'Certs already exist.'
- logger.warning(string)
- return callback(new Error(string))
- }
-
- logger.info('Generating a RSA key...')
- openssl.exec('genrsa', { 'out': certDir + 'peertube.key.pem', '2048': false }, function (err) {
- if (err) {
- logger.error('Cannot create private key on this pod.', { error: err })
- return callback(err)
- }
- logger.info('RSA key generated.')
-
- logger.info('Manage public key...')
- openssl.exec('rsa', { 'in': certDir + 'peertube.key.pem', 'pubout': true, 'out': certDir + 'peertube.pub' }, function (err) {
- if (err) {
- logger.error('Cannot create public key on this pod .', { error: err })
- return callback(err)
- }
-
- logger.info('Public key managed.')
- return callback(null)
- })
- })
- })
- }
-
- function createCertsIfNotExist (callback) {
- certsExist(function (exist) {
- if (exist === true) {
- return callback(null)
- }
-
- createCerts(function (err) {
- return callback(err)
- })
- })
- }
-
- function generatePassword (callback) {
- crypto.randomBytes(32, function (err, buf) {
- if (err) {
- return callback(err)
- }
-
- callback(null, buf.toString('utf8'))
- })
- }
-
- function symetricEncrypt (text, callback) {
- generatePassword(function (err, password) {
- if (err) {
- return callback(err)
- }
-
- var cipher = crypto.createCipher(algorithm, password)
- var crypted = cipher.update(text, 'utf8', 'hex')
- crypted += cipher.final('hex')
- callback(null, { crypted: crypted, password: password })
- })
- }
-
- function symetricDecrypt (text, password) {
- var decipher = crypto.createDecipher(algorithm, password)
- var dec = decipher.update(text, 'hex', 'utf8')
- dec += decipher.final('utf8')
- return dec
+ cleanForExit: cleanForExit
}
function cleanForExit (webtorrent_process) {
// ---------------------------------------------------------------------------
module.exports = utils
-
- // ---------------------------------------------------------------------------
-
- function makeRetryRequest (params, from_url, to_pod, signature, callbackEach) {
- // Append the signature
- if (signature) {
- params.json.signature = {
- url: from_url,
- signature: signature
- }
- }
-
- logger.debug('Make retry requests to %s.', to_pod.url)
-
- replay(
- request.post(params, function (err, response, body) {
- callbackEach(err, response, body, params.url, to_pod)
- }),
- {
- retries: constants.REQUEST_RETRIES,
- factor: 3,
- maxTimeout: Infinity,
- errorCodes: [ 'EADDRINFO', 'ETIMEDOUT', 'ECONNRESET', 'ESOCKETTIMEDOUT', 'ENOTFOUND', 'ECONNREFUSED' ]
- }
- ).on('replay', function (replay) {
- logger.info('Replaying request to %s. Request failed: %d %s. Replay number: #%d. Will retry in: %d ms.',
- params.url, replay.error.code, replay.error.message, replay.number, replay.delay)
- })
- }
})()
var constants = require('../initializers/constants')
var logger = require('../helpers/logger')
+ var peertubeCrypto = require('../helpers/peertubeCrypto')
var Pods = require('../models/pods')
var PoolRequests = require('../models/poolRequests')
var poolRequests = require('../lib/poolRequests')
- var utils = require('../helpers/utils')
+ var requests = require('../helpers/requests')
var Videos = require('../models/videos')
var http = config.get('webserver.https') ? 'https' : 'http'
var pods_score = {}
logger.info('Make friends!')
- fs.readFile(utils.getCertDir() + 'peertube.pub', 'utf8', function (err, cert) {
+ fs.readFile(peertubeCrypto.getCertDir() + 'peertube.pub', 'utf8', function (err, cert) {
if (err) {
logger.error('Cannot read public cert.', { error: err })
return callback(err)
videos: videos_list
}
- utils.makeMultipleRetryRequest(
+ requests.makeMultipleRetryRequest(
{ method: 'POST', path: '/api/' + constants.API_VERSION + '/pods/', data: data },
pods_list,
}
// Announce we quit them
- utils.makeMultipleRetryRequest(request, pods, function () {
+ requests.makeMultipleRetryRequest(request, pods, function () {
Pods.removeAll(function (err) {
poolRequests.activate()
var logger = require('../helpers/logger')
var Pods = require('../models/pods')
var PoolRequests = require('../models/poolRequests')
- var utils = require('../helpers/utils')
+ var requests = require('../helpers/requests')
var Videos = require('../models/videos')
var timer = null
// ---------------------------------------------------------------------------
- function makePoolRequest (type, requests, callback) {
+ function makePoolRequest (type, requests_to_make, callback) {
if (!callback) callback = function () {}
Pods.list(function (err, pods) {
sign: true,
method: 'POST',
path: null,
- data: requests
+ data: requests_to_make
}
if (type === 'add') {
var bad_pods = []
var good_pods = []
- utils.makeMultipleRetryRequest(params, pods, callbackEachPodFinished, callbackAllPodsFinished)
+ requests.makeMultipleRetryRequest(params, pods, callbackEachPodFinished, callbackAllPodsFinished)
function callbackEachPodFinished (err, response, body, url, pod, callback_each_pod_finished) {
if (err || (response.statusCode !== 200 && response.statusCode !== 204)) {
if (pool_requests.length === 0) return
- var requests = {
+ var requests_to_make = {
add: {
ids: [],
requests: []
async.each(pool_requests, function (pool_request, callback_each) {
if (pool_request.type === 'add') {
- requests.add.requests.push(pool_request.request)
- requests.add.ids.push(pool_request._id)
+ requests_to_make.add.requests.push(pool_request.request)
+ requests_to_make.add.ids.push(pool_request._id)
} else if (pool_request.type === 'remove') {
- requests.remove.requests.push(pool_request.request)
- requests.remove.ids.push(pool_request._id)
+ requests_to_make.remove.requests.push(pool_request.request)
+ requests_to_make.remove.ids.push(pool_request._id)
} else {
throw new Error('Unkown pool request type.')
}
callback_each()
}, function () {
// Send the add requests
- if (requests.add.requests.length !== 0) {
- makePoolRequest('add', requests.add.requests, function (err) {
+ if (requests_to_make.add.requests.length !== 0) {
+ makePoolRequest('add', requests_to_make.add.requests, function (err) {
if (err) logger.error('Errors when sent add pool requests.', { error: err })
- PoolRequests.removeRequests(requests.add.ids)
+ PoolRequests.removeRequests(requests_to_make.add.ids)
})
}
// Send the remove requests
- if (requests.remove.requests.length !== 0) {
- makePoolRequest('remove', requests.remove.requests, function (err) {
+ if (requests_to_make.remove.requests.length !== 0) {
+ makePoolRequest('remove', requests_to_make.remove.requests, function (err) {
if (err) logger.error('Errors when sent remove pool requests.', { error: err })
- PoolRequests.removeRequests(requests.remove.ids)
+ PoolRequests.removeRequests(requests_to_make.remove.ids)
})
}
})
;(function () {
'use strict'
- var fs = require('fs')
- var ursa = require('ursa')
-
var logger = require('../helpers/logger')
+ var peertubeCrypto = require('../helpers/peertubeCrypto')
var Pods = require('../models/pods')
- var utils = require('../helpers/utils')
var secureMiddleware = {
decryptBody: decryptBody
logger.debug('Decrypting body from %s.', url)
- var crt = ursa.createPublicKey(pod.publicKey)
- var signature_ok = crt.hashAndVerify('sha256', new Buffer(req.body.signature.url).toString('hex'), req.body.signature.signature, 'hex')
+ var signature_ok = peertubeCrypto.checkSignature(pod.publicKey, url, req.body.signature.signature)
if (signature_ok === true) {
- var myKey = ursa.createPrivateKey(fs.readFileSync(utils.getCertDir() + 'peertube.key.pem'))
- var decryptedKey = myKey.decrypt(req.body.key, 'hex', 'utf8')
- req.body.data = JSON.parse(utils.symetricDecrypt(req.body.data, decryptedKey))
- delete req.body.key
+ peertubeCrypto.decrypt(req.body.key, req.body.data, function (err, decrypted) {
+ if (err) {
+ logger.error('Cannot decrypt data.', { error: err })
+ return res.sendStatus(500)
+ }
+
+ req.body.data = JSON.parse(decrypted)
+ delete req.body.key
+
+ next()
+ })
} else {
logger.error('Signature is not okay in decryptBody for %s.', req.body.signature.url)
return res.sendStatus(403)
}
-
- next()
})
}
var customValidators = require('./helpers/customValidators')
var database = require('./initializers/database')
var logger = require('./helpers/logger')
+ var peertubeCrypto = require('./helpers/peertubeCrypto')
var poolRequests = require('./lib/poolRequests')
var routes = require('./controllers')
var utils = require('./helpers/utils')
// Prod : no stacktraces leaked to user
if (process.env.NODE_ENV === 'production') {
app.use(function (err, req, res, next) {
- logger.error('Error : ' + err.message, { error: err })
+ logger.error(err)
res.status(err.status || 500)
res.render('error', {
message: err.message,
})
} else {
app.use(function (err, req, res, next) {
- logger.error('Error : ' + err.message, { error: err })
+ logger.error(err)
res.status(err.status || 500)
res.render('error', {
message: err.message,
}
// ----------- Create the certificates if they don't already exist -----------
- utils.createCertsIfNotExist(function (err) {
+ peertubeCrypto.createCertsIfNotExist(function (err) {
if (err) throw err
// Create/activate the webtorrent module
webtorrent.create(function () {