Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions .openapi-generator/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,33 @@ files:
destinationFilename: Transactor.php
bootstrap.php:
folder: test
RateLimiter.mustache:
folder: lib/RateLimit
destinationFilename: RateLimiter.php
RateLimitStoreInterface.mustache:
folder: lib/RateLimit
destinationFilename: RateLimitStoreInterface.php
SqlDialect.mustache:
folder: lib/RateLimit
destinationFilename: SqlDialect.php
RateLimitMode.mustache:
folder: lib/RateLimit
destinationFilename: RateLimitMode.php
RateLimitExceededException.mustache:
folder: lib/RateLimit
destinationFilename: RateLimitExceededException.php
PdoRateLimitStore.mustache:
folder: lib/RateLimit
destinationFilename: PdoRateLimitStore.php
JsonRateLimitStore.mustache:
folder: lib/RateLimit
destinationFilename: JsonRateLimitStore.php
RateLimiterTest.mustache:
folder: test/RateLimit
destinationFilename: RateLimiterTest.php
RateLimitStoreInterfaceTest.mustache:
folder: test/RateLimit
destinationFilename: RateLimitStoreInterfaceTest.php
SqlDialectTest.mustache:
folder: test/RateLimit
destinationFilename: SqlDialectTest.php
201 changes: 130 additions & 71 deletions .openapi-generator/templates/ApiClient.mustache
Original file line number Diff line number Diff line change
@@ -1,95 +1,104 @@
<?php

declare(strict_types=1);

/**
*
* This file is part of the MultiFlexi package
*
* https://github.com/VitexSoftware/php-vitexsoftware-rbczpremiumapi
*
* (c) Vítězslav Dvořák <http://vitexsoftware.com>
*
* @author Vitex <vitex@hippy.cz>
* @copyright 2023 Vitex@hippy.cz (G)
*
* PHP 8
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace VitexSoftware\Raiffeisenbank;

use VitexSoftware\Raiffeisenbank\RateLimit\RateLimiter;
use VitexSoftware\Raiffeisenbank\RateLimit\RateLimitExceededException;
use GuzzleHttp\Exception\GuzzleException;

Comment thread
coderabbitai[bot] marked this conversation as resolved.
/**
* Description of ApiClient
* Description of ApiClient.
*
* @author vitex
*/
class ApiClient extends \GuzzleHttp\Client
{

/**
* ClientID obtained from Developer Portal - when you registered your app with us.
* @var string
*/
protected string $xIBMClientId = '';

/**
* the end IP address of the client application (no server) in IPv4 or IPv6
* format. If the bank client (your user) uses a browser by which he
* accesses your server app, we need to know the IP address of his browser.
* Always provide the closest IP address to the real end-user possible.
* (optional)
*
* @var string
* the end IP address of the client application (no server) in IPv4 or IPv6
* format. If the bank client (your user) uses a browser by which he
* accesses your server app, we need to know the IP address of his browser.
* Always provide the closest IP address to the real end-user possible.
* (optional).
*/
protected string $pSUIPAddress = '';

/**
* Use mocking for api calls ?
* @var boolean
*/
protected bool $mockMode = false;
private RateLimiter $rateLimiter;

/**
* @inheritDoc
*
* {@inheritDoc}
*
* $config['clientid'] - obtained from Developer Portal - when you registered your app with us.
* $config['cert'] = ['/path/to/cert.p12','certificat password']
* $config['clientpubip'] = the closest IP address to the real end-user
* $config['mocking'] = true to use /rbcz/premium/mock/* endpoints
*
* @param array $config
*
* @throws \Exception CERT_FILE is not set
* @throws \Exception CERT_PASS is not set
*/
public function __construct(array $config = [])
{
if (array_key_exists('clientid', $config) === false) {
if (\array_key_exists('clientid', $config) === false) {
$this->xIBMClientId = \Ease\Shared::cfg('XIBMCLIENTID');
} else {
$this->xIBMClientId = $config['clientid'];
}

if (array_key_exists('cert', $config) === false) {
if (\array_key_exists('cert', $config) === false) {
$config['cert'] = [\Ease\Shared::cfg('CERT_FILE'), \Ease\Shared::cfg('CERT_PASS')];

if (empty($config['cert'][0])) {
throw new \Exception('Certificate (CERT_FILE) not specified');
}

if (empty($config['cert'][1])) {
throw new \Exception('Certificate password (CERT_PASS) not specified');
}
}

if (array_key_exists('debug', $config) === false) {
if (\array_key_exists('debug', $config) === false) {
$config['debug'] = \Ease\Shared::cfg('API_DEBUG', false);
}
if (array_key_exists('clientpubip', $config)){
}

if (\array_key_exists('clientpubip', $config)) {
$this->pSUIPAddress = $config['clientpubip'];
}

if (array_key_exists('mocking', $config)){
$this->mockMode = boolval($config['mocking']);
if (\array_key_exists('mocking', $config)) {
$this->mockMode = (bool) $config['mocking'];
}


$limitStore = new RateLimit\JsonRateLimitStore(sys_get_temp_dir().'/rbczpremiumapi_rates.json');

$this->rateLimiter = new RateLimiter($limitStore);

parent::__construct($config);
}

/**
* ClientID obtained from Developer Portal
*
* ClientID obtained from Developer Portal.
*
* @return string
*/
public function getXIBMClientId()
Expand All @@ -98,102 +107,152 @@ class ApiClient extends \GuzzleHttp\Client
}

/**
* Keep user public IP here
*
* Keep user public IP here.
*
* @return string
*/
public function getpSUIPAddress()
{
return $this->pSUIPAddress;
}
}

/**
* Use mocking uri for api calls ?
*
* @return boolean
*
* @return bool
*/
public function getMockMode()
{
return $this->mockMode;
}

/**
* Obtain Your current Public IP
*
* Obtain Your current Public IP.
*
* @deprecated since version 0.1 - Do not use in production Environment!
*
*
* @return string
*/
public static function getPublicIP()
{
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, "http://httpbin.org/ip");
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, \CURLOPT_URL, 'http://httpbin.org/ip');
curl_setopt($curl, \CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($curl);
curl_close($curl);
$ip = json_decode($output, true);

return $ip['origin'];
}

/**
* Source Identifier
*
* Source Identifier.
*
* @deprecated since version 0.1 - Do not use in production Environment!
*
*
* @return string
*/
public static function sourceString()
{
return substr(__FILE__ . '@' . gethostname(), -50);
return substr(__FILE__.'@'.gethostname(), -50);
}

/**
* Try to check certificate readibilty
*
* @throws Exception - Certificate file not found
*
* @param string $certFile path to certificate
* @param boolean $die throw exception or return false ?
*
* @return boolean certificate file
* Try to check certificate readibilty.
*
* @param string $certFile path to certificate
* @param bool $die throw exception or return false ?
*
* @throws \Exception - Certificate file not found
*
* @return bool certificate file
*/
public static function checkCertificatePresence(string $certFile, bool $die = false): bool
{
$found = false;

if ((file_exists($certFile) === false) || (is_readable($certFile) === false)) {
$errMsg = 'Cannot read specified certificate file: ' . $certFile;
fwrite(STDERR, $errMsg . PHP_EOL);
if ($die){
$errMsg = 'Cannot read specified certificate file: '.$certFile;
fwrite(\STDERR, $errMsg.\PHP_EOL);

if ($die) {
throw new \Exception($errMsg);
}
} else {
$found = true;
}
return $found;

return $found;
}

public static function checkCertificate($certFile,$password): bool {
return self::checkCertificatePresence($certFile) && self::checkCertificatePassword($certFile,$password);

public static function checkCertificate($certFile, $password): bool
{
return self::checkCertificatePresence($certFile) && self::checkCertificatePassword($certFile, $password);
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
}

public static function checkCertificatePassword(string $certFile, string $password): bool {

public static function checkCertificatePassword(string $certFile, string $password): bool
{
$certContent = file_get_contents($certFile);

if (openssl_pkcs12_read($certContent, $certs, $password) === false) {
fwrite(\STDERR, 'Cannot read PKCS12 certificate file: '.$certFile.\PHP_EOL);

exit(1);
}

return true;
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.



/**
* Request Identifier
*
* Request Identifier.
*
* @todo Obtain using RateLimiter
*
* @deprecated since version 0.1 - Do not use in production Environment!
*
*
* @return string
*/
public static function getxRequestId() {
return substr(self::sourceString() . '#' . time(),-59);
public static function getxRequestId()
{
return substr(self::sourceString().'#'.time(), -59);
}

/**
* Send an HTTP request.
*
* @param array $options Request options to apply to the given
* request and to the transfer. See \GuzzleHttp\RequestOptions.
*
* @throws GuzzleException
* @throws RateLimitExceededException
*/
public function send(\Psr\Http\Message\RequestInterface $request, array $options = []): \Psr\Http\Message\ResponseInterface
{
$this->rateLimiter->checkBeforeRequest($this->xIBMClientId);

$response = parent::send($request, $options);

$statusCode = $response->getStatusCode();
$responseHeaders = $response->getHeaders();

if (isset($responseHeaders['x-ratelimit-remaining-second'])) {
$remainingSecond = (int) $responseHeaders['x-ratelimit-remaining-second'][0];
$remainingDay = (int) $responseHeaders['x-ratelimit-remaining-day'][0];

$timestamp = time();

$this->rateLimiter->handleRateLimits($this->xIBMClientId, $remainingSecond, $remainingDay, $timestamp);
}

if ($statusCode === 429) { // 429 Too Many Requests
if ($this->rateLimiter->isWaitMode()) {
$this->rateLimiter->checkBeforeRequest($this->xIBMClientId);
$response = parent::send($request, $options);
} else {
throw new RateLimitExceededException('Rate limit exceeded (HTTP 429)');
}
}

return $response;
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
Loading