Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
mihailivanchev committed May 13, 2024
1 parent da8a0e4 commit 23c62d2
Show file tree
Hide file tree
Showing 16 changed files with 796 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/.idea/
vendor/
composer.lock
.php-cs-fixer.cache
19 changes: 19 additions & 0 deletions .php-cs-fixer.dist.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

use PhpCsFixer\Config;
use PhpCsFixer\Finder;

$finder = Finder::create()
->in([
__DIR__ . '/src',
]);

$config = new PhpCsFixer\Config();

return (new Config())
->setFinder($finder)
->setRules([
'@PhpCsFixer' => true,
'@PSR12' => true,
'yoda_style' => false,
]);
39 changes: 39 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"name": "ampeco/omnipay-redsys",
"description": "Omnipay plugin for: https://redsys.es/en/index.html",
"type": "library",
"license": "MIT",
"version": "1.0.0",
"autoload": {
"psr-4": {
"Ampeco\\OmnipayRedsys\\": "src/"
}
},
"authors": [
{
"name": "Mihail Ivanchev",
"email": "[email protected]"
}
],
"require": {
"omnipay/common": "^3.2",
"php": ">=8.1.0",
"symfony/http-client": "^6.2",
"php-http/httplug": "^2.3",
"nyholm/psr7": "^1.5"
},
"config": {
"allow-plugins": {
"php-http/discovery": true
},
"platform": {
"php": "8.1.26"
}
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.41"
},
"scripts": {
"fix": "vendor/bin/php-cs-fixer fix"
}
}
64 changes: 64 additions & 0 deletions src/CommonParameters.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?php

namespace Ampeco\OmnipayRedsys;

trait CommonParameters
{
public function setMerchantEmv3ds($value): void
{
$this->setParameter('merchantEmv3ds', (array) $value);
}

public function getMerchantEmv3ds()
{
return $this->getParameter('merchantEmv3ds');
}

public function setMerchantCode($value): void
{
$this->setParameter('merchantCode', (string) $value);
}

public function getMerchantCode(): string
{
return $this->getParameter('merchantCode');
}

public function setMerchantTerminal($value): void
{
$this->setParameter('merchantTerminal', (string) $value);
}

public function getMerchantTerminal(): string
{
return $this->getParameter('merchantTerminal');
}
public function setApiToken($value): void
{
$this->setParameter('apiToken', (string) $value);
}

public function getApiToken(): string
{
return $this->getParameter('apiToken');
}

public function setMerchantDirectPayment($value): void
{
$this->setParameter('merchantDirectPayment', (string) $value);
}

public function getMerchantDirectPayment(): string
{
return $this->getParameter('merchantDirectPayment');
}
public function setMerchantExceptSca($value): void
{
$this->setParameter('merchantExceptSca', (string) $value);
}

public function getMerchantExceptSca(): string
{
return $this->getParameter('merchantExceptSca');
}
}
87 changes: 87 additions & 0 deletions src/Gateway.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<?php

namespace Ampeco\OmnipayRedsys;

use Ampeco\OmnipayRedsys\Message\AbstractRequest;
use Ampeco\OmnipayRedsys\Message\AuthenticationConfirmationRequest;
use Ampeco\OmnipayRedsys\Message\CreateCardRequest;
use Ampeco\OmnipayRedsys\Message\PreparePurchaseRequest;
use Ampeco\OmnipayRedsys\Message\CreatePreAuthRequest;
use Ampeco\OmnipayRedsys\Message\PurchaseRequest;
use Ampeco\OmnipayRedsys\Message\CapturePreAuthRequest;
use Ampeco\OmnipayRedsys\Message\RedsysNotification;
use Ampeco\OmnipayRedsys\Message\VoidRequest;
use Omnipay\Common\AbstractGateway;
use Omnipay\Common\Message\RequestInterface;

class Gateway extends AbstractGateway
{
public function getName(): string
{
return 'Redsys';
}

public function getBaseUrl(): string
{
return $this->getTestMode() ? AbstractRequest::API_URL_TEST : AbstractRequest::API_URL_PROD;
}

public function acceptNotification(array $options = []): RedsysNotification
{
return new RedsysNotification($options);
}

public function authorize(array $options = []): RequestInterface
{
return $this->createRequest(CreatePreAuthRequest::class, $options);
}

public function capture(array $options = []): RequestInterface
{
return $this->createRequest(CapturePreAuthRequest::class, $options);
}

public function preparePurchase(array $options = []): RequestInterface
{
return $this->createRequest(PreparePurchaseRequest::class, $options);
}

public function purchase(array $options = []): RequestInterface
{
return $this->createRequest(PurchaseRequest::class, $options);
}

public function authenticationConfirmation(array $options = []): RequestInterface
{
return $this->createRequest(AuthenticationConfirmationRequest::class, $options);
}

public function supportsDeleteCard(): bool
{
return false;
}

public function supportsAcceptNotification(): bool
{
return true;
}

public function supportsAuthorize(): bool
{
return true;
}
public function deleteCard(): array
{
return [];
}

public function void(array $options = []): RequestInterface
{
return $this->createRequest(VoidRequest::class, $options);
}

public function createCard(array $options = array()): RequestInterface
{
return $this->createRequest(CreateCardRequest::class, $options);
}
}
83 changes: 83 additions & 0 deletions src/Message/AbstractRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<?php

namespace Ampeco\OmnipayRedsys\Message;

use Ampeco\OmnipayRedsys\CommonParameters;
use Illuminate\Http\Client\PendingRequest;
use Illuminate\Support\Facades\Http;
use Omnipay\Common\Message\AbstractRequest as OmnipayAbstractRequest;

abstract class AbstractRequest extends OmnipayAbstractRequest
{
use CommonParameters;

public const API_URL_PROD = 'https://sis-t.redsys.es/sis/';
public const API_URL_TEST = 'https://sis-t.redsys.es:25443/sis/';

public const TIMEOUT_IN_SECONDS = 30;

abstract public function getEndpoint(): string;

protected function getClient(): PendingRequest
{
$base = self::API_URL_PROD;

if ($this->getTestMode()) {
$base = self::API_URL_TEST;
}

return Http::baseUrl($base)
->timeout(self::TIMEOUT_IN_SECONDS)
->asJson()
->acceptJson();
}

protected function getResponseClass(): string
{
return Response::class;
}

protected function createResponse(int $statusCode, ?array $data = null)
{
$responseClass = $this->getResponseClass();

return $this->response = new $responseClass($this, $statusCode, $data);
}

public function sendData($data)
{
$client = $this->getClient();
$response = $client->post($this->getEndpoint(), $data);

return $this->createResponse($response->status(), $response->json());
}

protected function generateEncodedRequestAttributes(array $requestData): array
{
$requestAttributes['Ds_SignatureVersion'] = 'HMAC_SHA256_V1';
$requestAttributes['Ds_MerchantParameters'] = base64_encode(json_encode($requestData));
$requestAttributes['Ds_Signature'] = $this->generateSignatureForTransaction($requestAttributes['Ds_MerchantParameters']);

return $requestAttributes;
}

private function generateSignatureForTransaction(string $encodedParameters): string
{
$transactionId = $this->getTransactionId();
$apiToken = $this->getApiToken();
$l = (int) ceil(strlen($transactionId) / 8) * 8;
$key = substr(
openssl_encrypt(
$transactionId . str_repeat("\0", $l - strlen($transactionId)),
'des-ede3-cbc',
base64_decode($apiToken),
OPENSSL_RAW_DATA,
"\0\0\0\0\0\0\0\0",
),
0,
$l,
);

return base64_encode(hash_hmac('sha256', $encodedParameters, $key, true));
}
}
27 changes: 27 additions & 0 deletions src/Message/AuthenticationConfirmationRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

namespace Ampeco\OmnipayRedsys\Message;

class AuthenticationConfirmationRequest extends AbstractRequest
{
public function getEndpoint(): string
{
return 'rest/trataPeticionREST';
}

public function getData()
{
$this->validate('transactionId', 'amount', 'token', 'merchantEmv3ds');

return $this->generateEncodedRequestAttributes([
'DS_MERCHANT_IDENTIFIER' => $this->getToken(),
'DS_MERCHANT_EMV3DS' => $this->getMerchantEmv3ds(),
'DS_MERCHANT_AMOUNT' => $this->getAmountInteger(),
'DS_MERCHANT_CURRENCY' => $this->getCurrencyNumeric(),
'DS_MERCHANT_MERCHANTCODE' => $this->getMerchantCode(),
'DS_MERCHANT_ORDER' => $this->getTransactionId(),
'DS_MERCHANT_TERMINAL' => $this->getMerchantTerminal(),
'DS_MERCHANT_TRANSACTIONTYPE' => '0',
]);
}
}
26 changes: 26 additions & 0 deletions src/Message/CapturePreAuthRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

namespace Ampeco\OmnipayRedsys\Message;

class CapturePreAuthRequest extends AbstractRequest
{
public function getEndpoint(): string
{
return 'rest/trataPeticionREST';
}

public function getData()
{
$this->validate('transactionId', 'amount', 'token');

return $this->generateEncodedRequestAttributes([
'DS_MERCHANT_IDENTIFIER' => $this->getToken(),
'DS_MERCHANT_AMOUNT' => $this->getAmountInteger(),
'DS_MERCHANT_CURRENCY' => $this->getCurrencyNumeric(),
'DS_MERCHANT_MERCHANTCODE' => $this->getMerchantCode(),
'DS_MERCHANT_ORDER' => $this->getTransactionId(),
'DS_MERCHANT_TERMINAL' => $this->getMerchantTerminal(),
'DS_MERCHANT_TRANSACTIONTYPE' => '2',
]);
}
}
38 changes: 38 additions & 0 deletions src/Message/CreateCardRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

namespace Ampeco\OmnipayRedsys\Message;

class CreateCardRequest extends AbstractRequest
{
/** Defines the full path as we don't send a request here, we just need the url to pass it to the form.
* @return string
*/
public function getEndpoint(): string
{
$base = self::API_URL_PROD;
if ($this->getTestMode()) {
$base = self::API_URL_TEST;
}

return $base . 'realizarPago';
}

public function getData()
{
$this->validate('transactionId', 'amount', 'currency', 'merchantTerminal', 'merchantCode', 'notifyUrl', 'returnUrl');

return $this->generateEncodedRequestAttributes([
'DS_MERCHANT_AMOUNT' => $this->getAmountInteger(),
'DS_MERCHANT_CURRENCY' => $this->getCurrencyNumeric(),
'DS_MERCHANT_MERCHANTCODE' => $this->getMerchantCode(),
'DS_MERCHANT_ORDER' => $this->getTransactionId(),
'DS_MERCHANT_TERMINAL' => $this->getMerchantTerminal(),
'DS_MERCHANT_TRANSACTIONTYPE' => '0',
//'DS_MERCHANT_COF_TYPE' => 'C', - optional. maybe we shouldn't use it at all.
'DS_MERCHANT_IDENTIFIER' => 'REQUIRED',
'DS_MERCHANT_MERCHANTURL' => $this->getNotifyUrl(),
'DS_MERCHANT_URLOK' => $this->getReturnUrl(),
'DS_MERCHANT_URLKO' => $this->getReturnUrl(),
]);
}
}
Loading

0 comments on commit 23c62d2

Please sign in to comment.