¿Cómo funciona el proceso de firmado?

  • Para validar que la información sea enviada desde la persona que corresponda, esta se verifica a través de una firma generada por el algoritomo HMAC SHA256.
    • Para generar esta firma se necesita una Clave Electrónica Token Secret que es generada al crear el servicio en Pago Fácil.
    • Como bien dice su nombre, esta clave ES SECRETA y no debe ser compartida con nadie, ya que esto podría causar que la información del estado de la transacción no sea fidedigna hacia el comercio.
    • Este proceso no es complejo pero es importante seguir los pasos en orden para que no se vuelva frustrante.

Proceso de Firmado

  • Se debe de obtener un arreglo con todas las variables que comiencen con x_ desde el body del POST
  • Este arreglo se debe de ordenar de manera alfabética.
  • Una vez obtenido el arreglo, se crea un string con todas las variables y sus valores concatenados.
  • El string resultante se firma con el algoritmo SHA256 mencionado anteriormente.

Ejemplos de código para firmado

Los siguientes códigos no ignoran objetos;por lo que, se le deben pasar sólo los parámetros de la transacción que figuran como obligatorios.

const crypto = require('crypto');

function signPayload(payload, secret, prefix = "x_", signature = "signature") {
  
    //El arreglo SIEMPRE debe de estar ordenado antes de firmar.
    let sortedArray = Object.entries(payload).sort();
    
    let payloadFirmado = "";
    let firma = prefix + signature;
    let mensaje = "";
  
    for (let index = 0; index < sortedArray.length; index++) {
        console.log(sortedArray[index]);
        if (sortedArray[index][0] != firma) {
            mensaje += sortedArray[index][0] + sortedArray[index][1];
        }
    }
  
    let hmac = crypto.createHmac('sha256', secret);
    hmac.setEncoding('hex');
    hmac.write(mensaje);
    hmac.end();
    payloadFirmado = hmac.read();
    return payloadFirmado;
}
const crypto = require('crypto-js');

function signPayload(payload, secret, prefix = "x_", signature = "signature") {
    //El arreglo SIEMPRE debe de estar ordenado antes de firmar.
    let sortedArray = Object.entries(payload).sort();
    
    let payloadFirmado = "";
    let firma = prefix + signature;
    let mensaje = "";
  
    for (let index = 0; index < sortedArray.length; index++) {
        console.log(sortedArray[index]);
        if (sortedArray[index][0] != firma) {
            mensaje += sortedArray[index][0] + sortedArray[index][1];
        }
    }
  
    let hash = crypto.HmacSHA256(mensaje, secret);
    payloadFirmado = hash.toString(crypto.enc.Hex);
    return payloadFirmado;
}
def sign(fields, [email protected])
    Digest::HMAC.hexdigest(fields.sort.join, key, Digest::SHA256)
  end
function firmarArreglo($arreglo) {
    //Ordeno Arreglo
    ksort($arreglo);
    //Concateno Arreglo
    $mensaje = $this->concatenarArreglo($arreglo);
    //Firmo Mensaje
    $mensajeFirmado = $this->firmarMensaje($mensaje, $this->ct_token_secret);
    //Guardo y retorno el mensaje firmado
    $this->ct_firma = $mensajeFirmado;
    return $mensajeFirmado;
}
function firmarMensaje($mensaje, $claveCifrado) {
    $mensajeFirmado = hash_hmac('sha256', $mensaje, $claveCifrado);
    return $mensajeFirmado;
}
public function concatenarArreglo($arreglo) {
    $resultado = "";
    foreach ($arreglo as $field => $value) {
        $resultado .= $field . $value;
    }
    return $resultado;
}
<?php
require_once(__DIR__ . '/vendor/autoload.php');
use PSTPagoFacil\SignatureHelper; //using Pago Fácil SignatureHelper Library


$tokenService = 'TOKEN_SERVICE'; // put your Token Service here
$tokenSecret = 'TOKEN_SECRET';  // put your Token Secret here
$x_reference = (int) microtime(true); //Just a random number as an example 
$x_session_id = (int) microtime(true); //Just a random number as an example 
$sHelper = new SignatureHelper($tokenSecret);

// Building the trx

$trxBody = [
    "x_account_id"=> $tokenService,
    "x_amount"=> 1000,
    "x_currency"=> "CLP",
    "x_reference"=> $x_reference,
    "x_customer_email"=> "[email protected]",
     "x_url_complete"=> "https://postman-echo.com/post",
    "x_url_cancel"=> "https://postman-echo.com/post",
    "x_url_callback"=> "https://postman-echo.com/post",
     "x_shop_country"=> "CL",
    "x_session_id"=> "$x_session_id"
];

// Signing trx with 

$firma = $sHelper->signPayload($trxBody);
$x_signature = $sHelper->signPayload($trxBody);
$trxBody["x_signature"] = $x_signature;

// Posting Signed trx with Pago Fácil SignatureHelper Library
$payload = json_encode($trxBody);
// print_r($payload); //payload ready to be sent

$curl = curl_init();

curl_setopt_array($curl, [
  CURLOPT_URL => "https://apis-dev.pgf.cl/trxs",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => "",
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "POST",
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_HTTPHEADER => [
    "Accept: application/json",
    "Content-Type: application/json"
  ],
]);

// Requesting the Response
$response = curl_exec($curl);

$err = curl_error($curl);

curl_close($curl);

if ($err) {
  echo "cURL Error #:" . $err;
} else {
    $jsonResponse = json_decode($response);

    print_r ($jsonResponse); //here you can see the JSON Response Object

/*  0 gateway
    1 webpay
    2 khipu max 5mm
    3 multicaja error
    4 pago 46
    5 mach
*/

    // $url = $jsonResponse->data->payUrl[0]->url; // here you choose your payUrl
    // echo $url,"\n\n";
}
import requests
import hashlib
import hmac
import json
import time
import webbrowser
import tokens
import pprint


encoding = 'utf-8'
x_account_id = tokens.tokenServiceDev #Put your Token Service
x_amount = str(b'1000', encoding)
x_currency = str(b'CLP', encoding)
x_reference = str(time.time()) #Just a random number as an example 
x_customer_email = str(b'[email protected]', encoding)
x_url_complete = str(b'https://www.pagofacil.cl', encoding)
x_url_cancel = str(b'https://www.pagofacil.cl', encoding)
x_url_callback = str(b'https://callback.domain.com', encoding)
x_shop_country = str(b'CL', encoding)
x_session_id = str(b'1', encoding) #Just a random number as an example 



object='x_account_id'+x_account_id+'x_amount'+x_amount+'x_currency'+x_currency+'x_customer_email'+x_customer_email+'x_reference'+x_reference+'x_session_id'+x_session_id+'x_shop_country'+x_shop_country+'x_url_callback'+x_url_callback+'x_url_cancel'+x_url_cancel+'x_url_complete'+x_url_complete
payload = object.encode('utf-8')
key = tokens.tokenSecretDev #Put your Token Secret


# Generate the hash.
signature = hmac.new(key,payload,hashlib.sha256).hexdigest()
x_signature =  signature
url = tokens.dev # Put the Enviroment Endpoint (dev or Prod)
payload = {
  'x_account_id' : x_account_id ,
  'x_amount' : int(x_amount), 
  'x_currency' : x_currency, 
  'x_reference' : x_reference , 
  'x_customer_email' : x_customer_email, 
  'x_url_complete' : x_url_complete, 
  'x_url_cancel' : x_url_cancel, 
  'x_url_callback' : x_url_callback ,
  'x_shop_country' : x_shop_country, 
  'x_session_id' : x_session_id, 
  'x_signature' : x_signature 
}

jpayload = json.dumps(payload)
headers = {
    'accept': "application/json",
    'content-type': "application/json"
    }

response = requests.request("POST", url, data=jpayload, headers=headers)
"""
0 gateway
1 webpay
2 khipu max 5mm
3 multicaja
4 pago 46
5 mach
"""
chosenPayUrl = response.json()['data']['payUrl'][0]['url']  # here you choose your payUrl
pprint.pprint(response.json())#Here you can see the response
webbrowser.open(chosenPayUrl)

Author

  • Cristian Tala Sánchez
  • Luis Marcelo Poblete Sandoval (Collaborator)