diff --git a/package.json b/package.json index 5eadcc363..554ad16df 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,6 @@ "safe-buffer": "^5.0.1", "scripty": "^1.5.0", "sequelize": "^3.27.0", - "ursa": "^0.9.1", "winston": "^2.1.1", "ws": "^1.1.1" }, diff --git a/server/helpers/peertube-crypto.js b/server/helpers/peertube-crypto.js index 610cb16cd..0f1e02ad6 100644 --- a/server/helpers/peertube-crypto.js +++ b/server/helpers/peertube-crypto.js @@ -1,9 +1,9 @@ 'use strict' +const crypto = require('crypto') const bcrypt = require('bcrypt') const fs = require('fs') const openssl = require('openssl-wrapper') -const ursa = require('ursa') const constants = require('../initializers/constants') const logger = require('./logger') @@ -16,12 +16,51 @@ const peertubeCrypto = { sign } -function checkSignature (publicKey, rawData, hexSignature) { - const crt = ursa.createPublicKey(publicKey) - const isValid = crt.hashAndVerify('sha256', new Buffer(rawData).toString('hex'), hexSignature, 'hex') +function checkSignature (publicKey, data, hexSignature) { + const verify = crypto.createVerify(constants.SIGNATURE_ALGORITHM) + + let dataString + if (typeof data === 'string') { + dataString = data + } else { + try { + dataString = JSON.stringify(data) + } catch (err) { + logger.error('Cannot check signature.', { error: err }) + return false + } + } + + verify.update(dataString, 'utf8') + + const isValid = verify.verify(publicKey, hexSignature, constants.SIGNATURE_ENCODING) return isValid } +function sign (data) { + const sign = crypto.createSign(constants.SIGNATURE_ALGORITHM) + + let dataString + if (typeof data === 'string') { + dataString = data + } else { + try { + dataString = JSON.stringify(data) + } catch (err) { + logger.error('Cannot sign data.', { error: err }) + return '' + } + } + + sign.update(dataString, 'utf8') + + // TODO: make async + const myKey = fs.readFileSync(constants.CONFIG.STORAGE.CERT_DIR + 'peertube.key.pem') + const signature = sign.sign(myKey, constants.SIGNATURE_ENCODING) + + return signature +} + function comparePassword (plainPassword, hashPassword, callback) { bcrypt.compare(plainPassword, hashPassword, function (err, isPasswordMatch) { if (err) return callback(err) @@ -52,13 +91,6 @@ function cryptPassword (password, callback) { }) } -function sign (data) { - const myKey = ursa.createPrivateKey(fs.readFileSync(constants.CONFIG.STORAGE.CERT_DIR + 'peertube.key.pem')) - const signature = myKey.hashAndSign('sha256', data, 'utf8', 'hex') - - return signature -} - // --------------------------------------------------------------------------- module.exports = peertubeCrypto 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) { url: constants.REMOTE_SCHEME.HTTP + '://' + params.toPod.host + params.path } - // Add data with POST requst ? - if (params.method === 'POST') { - requestParams.json = {} - - // Add signature if it is specified in the params - if (params.sign === true) { - const host = constants.CONFIG.WEBSERVER.HOST - - requestParams.json.signature = { - host, - signature: peertubeCrypto.sign(host) - } - } - - // If there are data informations - if (params.data) { - requestParams.json.data = params.data - request.post(requestParams, callback) - } else { - // No data - request.post(requestParams, callback) - } - } else { - request.get(requestParams, callback) + if (params.method !== 'POST') { + return callback(new Error('Cannot make a secure request with a non POST method.')) } + + requestParams.json = {} + + // Add signature if it is specified in the params + if (params.sign === true) { + const host = constants.CONFIG.WEBSERVER.HOST + + let dataToSign + if (params.data) { + dataToSign = dataToSign = params.data + } else { + // We do not have data to sign so we just take our host + // It is not ideal but the connection should be in HTTPS + dataToSign = host + } + + requestParams.json.signature = { + host, // Which host we pretend to be + signature: peertubeCrypto.sign(dataToSign) + } + } + + // If there are data informations + if (params.data) { + requestParams.json.data = params.data + } + + request.post(requestParams, callback) } // --------------------------------------------------------------------------- diff --git a/server/initializers/constants.js b/server/initializers/constants.js index 6ba8a9da0..a6adb75bf 100644 --- a/server/initializers/constants.js +++ b/server/initializers/constants.js @@ -118,16 +118,21 @@ const REQUEST_ENDPOINTS = { VIDEOS: 'videos' } -// --------------------------------------------------------------------------- - const REMOTE_SCHEME = { HTTP: 'https', WS: 'wss' } +// --------------------------------------------------------------------------- + +const SIGNATURE_ALGORITHM = 'RSA-SHA256' +const SIGNATURE_ENCODING = 'hex' + // Password encryption const BCRYPT_SALT_SIZE = 10 +// --------------------------------------------------------------------------- + // Express static paths (router) const STATIC_PATHS = { PREVIEWS: '/static/previews/', @@ -143,6 +148,8 @@ let STATIC_MAX_AGE = '30d' const THUMBNAILS_SIZE = '200x110' const PREVIEWS_SIZE = '640x480' +// --------------------------------------------------------------------------- + const USER_ROLES = { ADMIN: 'admin', USER: 'user' @@ -180,6 +187,8 @@ module.exports = { REQUESTS_LIMIT, RETRY_REQUESTS, SEARCHABLE_COLUMNS, + SIGNATURE_ALGORITHM, + SIGNATURE_ENCODING, SORTABLE_COLUMNS, STATIC_MAX_AGE, STATIC_PATHS, diff --git a/server/middlewares/secure.js b/server/middlewares/secure.js index 2aae715c4..b6e6d818b 100644 --- a/server/middlewares/secure.js +++ b/server/middlewares/secure.js @@ -23,7 +23,14 @@ function checkSignature (req, res, next) { logger.debug('Checking signature from %s.', host) - const signatureOk = peertubeCrypto.checkSignature(pod.publicKey, host, req.body.signature.signature) + let signatureShouldBe + if (req.body.data) { + signatureShouldBe = req.body.data + } else { + signatureShouldBe = host + } + + const signatureOk = peertubeCrypto.checkSignature(pod.publicKey, signatureShouldBe, req.body.signature.signature) if (signatureOk === true) { res.locals.secure = { diff --git a/server/middlewares/validators/remote/signature.js b/server/middlewares/validators/remote/signature.js index 5880a2c2c..002232c05 100644 --- a/server/middlewares/validators/remote/signature.js +++ b/server/middlewares/validators/remote/signature.js @@ -11,7 +11,7 @@ function signature (req, res, next) { req.checkBody('signature.host', 'Should have a signature host').isURL() req.checkBody('signature.signature', 'Should have a signature').notEmpty() - logger.debug('Checking signature parameters', { parameters: { signatureHost: req.body.signature.host } }) + logger.debug('Checking signature parameters', { parameters: { signature: req.body.signature } }) checkErrors(req, res, next) } diff --git a/server/models/request.js b/server/models/request.js index e18f8fe3d..bae227c05 100644 --- a/server/models/request.js +++ b/server/models/request.js @@ -122,7 +122,7 @@ function makeRequest (toPod, requestEndpoint, requestsToMake, callback) { 'Error sending secure request to %s pod.', toPod.host, { - error: err || new Error('Status code not 20x : ' + res.statusCode) + error: err ? err.message : 'Status code not 20x : ' + res.statusCode } )