All files / lib/resources security.js

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110                                            1x         1x 1x             1x 1x     1x 1x 1x                                           1x 1x       1x                             1x 1x                                 1x 1x              
/**
 * @name Security
 * @description This module exposes functions
 *              related to security procedures.
 *
 * @module security
 **/
import NodeRSA from 'node-rsa'
import Promise from 'bluebird'
import qs from 'qs'
import {
  toString,
  replace,
  pipe,
} from 'ramda'
import {
  verifySignature,
  calculateSignature,
} from '../postback'
 
import transactions from './transactions'
 
const cleanNumber = pipe(
  toString,
  replace(/[^0-9]/g, '')
)
 
const queryString = card =>
  qs.stringify({
    card_number: cleanNumber(card.card_number),
    card_holder_name: card.card_holder_name,
    card_expiration_date: cleanNumber(card.card_expiration_date),
    card_cvv: cleanNumber(card.card_cvv),
  })
 
const generateCardHash = ({ public_key: publicKey, id }, cardString) => {
  const key = new NodeRSA(publicKey, {
    encryptionScheme: 'pkcs1',
  })
  const encrypted = key.encrypt(cardString, 'base64')
  const cardHash = `${id}_${encrypted}`
  return cardHash
}
 
/**
 * Encrypt a card object into a card_hash
 *
 * @param {Object} opts An options params which
 *                      is usually already bound
 *                      by `connect` functions.
 *
 * @param {Object} card The card object.
 * {@link https://pagarme.readme.io/v1/reference#gerando-card_hash-manualmente|API Reference for this payload}
 *
 * @param {String} card.card_number The card's number.
 *                             Example: '4111111111111111'
 * @param {String} card.card_holder_name The card's holder name.
 *                             Example: 'Pedro Paulo'
 * @param {String} card.card_expiration_date The card's expiration date.
 *                             Example: '1225' or '12/25'
 * @param {String} card.card_cvv The card's cvv.
 *                             Example: '543'
*/
const encrypt = (opts, card) =>
  Promise.props({
    key: card.key ? card.key : transactions.cardHashKey(opts),
    cardString: queryString(card),
  })
    .then(({ key, cardString }) => generateCardHash(key, cardString))
 
/**
 * Generates a hash signed with your api_key.
 * This is used mainly to validate postbacks,
 * this functions is the same as pagarme.postback.calculatesignature
 * but it already knows your api_key.
 *
 * @param {Object} opts An options params which
 *                      is usually already bound
 *                      by `connect` functions.
 *
 * @param {String} string The string to be hashed.
 *
*/
const sign = (opts, string) =>
  calculateSignature(opts.body.api_key, string)
 
/**
 * Verifies a hash signed with your api_key.
 * This is used mainly to validate postbacks,
 * this functions is the same as pagarme.postback.validateSignature
 * but it already knows your api_key.
 *
 * @param {Object} opts An options params which
 *                      is usually already bound
 *                      by `connect` functions.
 *
 * @param {String} string The string to be hashed.
 *
 * @param {String} expected The expected result.
 *
*/
const verify = (opts, string, expected) =>
  verifySignature(opts.body.api_key, string, expected)
 
export default {
  encrypt,
  sign,
  verify,
}