aboutsummaryrefslogblamecommitdiffhomepage
path: root/server/helpers/peertube-crypto.ts
blob: 0ac87512704177f28fff94c7c90f38f6f883c4c4 (plain) (tree)
1
2
3
4



                                          










                                 
 
                                                                                 
                                                         














                                                             
                                                                            
                

 
                                     
                                                     
 
                        













                                                       
                                                                   
                                         
                                                                   



                  
                                                                                                                         






                                                                               
                                                                 


                                    





                                
      

    
 
                                                                                          
                                                         







                                                      
                                                                                 
                                                                   


                                         
                                                                               
                                                                  


                                         
                                                                              
 








                        
 
                                                                              
 
                                                                           
                                                                   



                                                         


    
                                                       


                                    
                         


                                                 


                                          
 
                                                                            

                             

                   
                                                          


                                                              
       
 
                                       
                                           
 
                                                                          

                              
                       
                             
       
                                                      
                  
                                                               

                              
 


                                          
      

    
import * as crypto from 'crypto'
import * as bcrypt from 'bcrypt'
import * as fs from 'fs'
import * as openssl from 'openssl-wrapper'
import { join } from 'path'

import {
  SIGNATURE_ALGORITHM,
  SIGNATURE_ENCODING,
  PRIVATE_CERT_NAME,
  CONFIG,
  BCRYPT_SALT_SIZE,
  PUBLIC_CERT_NAME
} from '../initializers'
import { logger } from './logger'

function checkSignature (publicKey: string, data: string, hexSignature: string) {
  const verify = crypto.createVerify(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, SIGNATURE_ENCODING)
  return isValid
}

function sign (data: string|Object) {
  const sign = crypto.createSign(SIGNATURE_ALGORITHM)

  let dataString: string
  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 certPath = join(CONFIG.STORAGE.CERT_DIR, PRIVATE_CERT_NAME)
  const myKey = fs.readFileSync(certPath)
  const signature = sign.sign(myKey.toString(), SIGNATURE_ENCODING)

  return signature
}

function comparePassword (plainPassword: string, hashPassword: string, callback: (err: Error, match?: boolean) => void) {
  bcrypt.compare(plainPassword, hashPassword, function (err, isPasswordMatch) {
    if (err) return callback(err)

    return callback(null, isPasswordMatch)
  })
}

function createCertsIfNotExist (callback: (err: Error) => void) {
  certsExist(function (err, exist) {
    if (err) return callback(err)

    if (exist === true) {
      return callback(null)
    }

    createCerts(function (err) {
      return callback(err)
    })
  })
}

function cryptPassword (password: string, callback: (err: Error, hash?: string) => void) {
  bcrypt.genSalt(BCRYPT_SALT_SIZE, function (err, salt) {
    if (err) return callback(err)

    bcrypt.hash(password, salt, function (err, hash) {
      return callback(err, hash)
    })
  })
}

function getMyPrivateCert (callback: (err: Error, privateCert: string) => void) {
  const certPath = join(CONFIG.STORAGE.CERT_DIR, PRIVATE_CERT_NAME)
  fs.readFile(certPath, 'utf8', callback)
}

function getMyPublicCert (callback: (err: Error, publicCert: string) => void) {
  const certPath = join(CONFIG.STORAGE.CERT_DIR, PUBLIC_CERT_NAME)
  fs.readFile(certPath, 'utf8', callback)
}

// ---------------------------------------------------------------------------

export {
  checkSignature,
  comparePassword,
  createCertsIfNotExist,
  cryptPassword,
  getMyPrivateCert,
  getMyPublicCert,
  sign
}

// ---------------------------------------------------------------------------

function certsExist (callback: (err: Error, certsExist: boolean) => void) {
  const certPath = join(CONFIG.STORAGE.CERT_DIR, PRIVATE_CERT_NAME)
  fs.access(certPath, function (err) {
    // If there is an error the certificates do not exist
    const exists = !err
    return callback(null, exists)
  })
}

function createCerts (callback: (err: Error) => void) {
  certsExist(function (err, exist) {
    if (err) return callback(err)

    if (exist === true) {
      const errorMessage = 'Certs already exist.'
      logger.warning(errorMessage)
      return callback(new Error(errorMessage))
    }

    logger.info('Generating a RSA key...')

    const privateCertPath = join(CONFIG.STORAGE.CERT_DIR, PRIVATE_CERT_NAME)
    const genRsaOptions = {
      'out': privateCertPath,
      '2048': false
    }
    openssl.exec('genrsa', genRsaOptions, function (err) {
      if (err) {
        logger.error('Cannot create private key on this pod.')
        return callback(err)
      }

      logger.info('RSA key generated.')
      logger.info('Managing public key...')

      const publicCertPath = join(CONFIG.STORAGE.CERT_DIR, 'peertube.pub')
      const rsaOptions = {
        'in': privateCertPath,
        'pubout': true,
        'out': publicCertPath
      }
      openssl.exec('rsa', rsaOptions, function (err) {
        if (err) {
          logger.error('Cannot create public key on this pod.')
          return callback(err)
        }

        logger.info('Public key managed.')
        return callback(null)
      })
    })
  })
}