%PDF- %PDF- 403WebShell
403Webshell
Server IP : 37.220.80.31  /  Your IP : 18.117.233.160
Web Server : Apache/2.4.52 (Ubuntu)
System : Linux 3051455-guretool.twc1.net 5.15.0-107-generic #117-Ubuntu SMP Fri Apr 26 12:26:49 UTC 2024 x86_64
User : www-root ( 1010)
PHP Version : 7.4.33
Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,
MySQL : OFF  |  cURL : ON  |  WGET : OFF  |  Perl : OFF  |  Python : OFF  |  Sudo : OFF  |  Pkexec : OFF
Directory :  /var/www/www-root/data/www/dev.artlot24.ru/bitrix/modules/sale/handlers/paysystem/uapay/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /var/www/www-root/data/www/dev.artlot24.ru/bitrix/modules/sale/handlers/paysystem/uapay/handler.php
<?php

namespace Sale\Handlers\PaySystem;

use Bitrix\Main,
	Bitrix\Main\Localization\Loc,
	Bitrix\Main\Request,
	Bitrix\Sale\Payment,
	Bitrix\Sale\PaySystem,
	Bitrix\Main\Web\HttpClient,
	Bitrix\Sale\PaymentCollection,
	Bitrix\Sale\PriceMaths;

Loc::loadMessages(__FILE__);

/**
 * Class UaPayHandler
 * @package Sale\Handlers\PaySystem
 */
class UaPayHandler
	extends PaySystem\ServiceHandler
	implements PaySystem\IRefund
{
	const PAYMENT_STATUS_FINISHED = "FINISHED";

	const INVOICE_ID_DELIMITER = "#";

	/**
	 * @param Payment $payment
	 * @param Request|null $request
	 * @return PaySystem\ServiceResult
	 * @throws Main\ArgumentException
	 * @throws Main\ArgumentNullException
	 * @throws Main\ArgumentOutOfRangeException
	 * @throws Main\ArgumentTypeException
	 * @throws Main\NotImplementedException
	 * @throws Main\ObjectException
	 */
	public function initiatePay(Payment $payment, Request $request = null)
	{
		$result = new PaySystem\ServiceResult();

		$invoiceResult = $this->createInvoice($payment);
		if ($invoiceResult->isSuccess())
		{
			$result->setPsData($invoiceResult->getPsData());

			$invoiceData = $invoiceResult->getData();
			$params = [
				"CURRENCY" => $payment->getField("CURRENCY"),
				"SUM" => PriceMaths::roundPrecision($payment->getSum()),
				"URL" => $invoiceData["paymentPageUrl"],
			];
			$this->setExtraParams($params);

			$showTemplateResult = $this->showTemplate($payment, "template");
			if ($showTemplateResult->isSuccess())
			{
				$result->setTemplate($showTemplateResult->getTemplate());
			}
			else
			{
				$result->addErrors($showTemplateResult->getErrors());
			}

			if ($params["URL"])
			{
				$result->setPaymentUrl($params["URL"]);
			}
		}
		else
		{
			$result->addErrors($invoiceResult->getErrors());
		}

		return $result;
	}

	/**
	 * @param Payment $payment
	 * @return PaySystem\ServiceResult
	 * @throws Main\ArgumentException
	 * @throws Main\ArgumentNullException
	 * @throws Main\ArgumentOutOfRangeException
	 * @throws Main\ArgumentTypeException
	 * @throws Main\ObjectException
	 */
	private function createSession(Payment $payment)
	{
		$result = new PaySystem\ServiceResult();

		$clientId = $this->getBusinessValue($payment, "UAPAY_CLIENT_ID");
		if (!$clientId)
		{
			$result->addError(new Main\Error(Loc::getMessage("SALE_HPS_UAPAY_ERROR_CLIENT_ID")));
			return $result;
		}

		$url = $this->getUrl($payment, "sessionCreate");
		$requestParams = [
			"params" => [
				"clientId" => $this->getBusinessValue($payment, "UAPAY_CLIENT_ID")
			]
		];

		$sendResult = $this->send($payment, $url, $requestParams);
		if (!$sendResult->isSuccess())
		{
			$result->addErrors($sendResult->getErrors());
			return $result;
		}

		$sendData = $sendResult->getData();

		$validationResult = $this->validationResponse($payment, $sendData);
		if (!$validationResult->isSuccess())
		{
			$result->addErrors($validationResult->getErrors());
			return $result;
		}

		$payloadData = self::getPayload($sendData["data"]["token"]);
		if (!$payloadData)
		{
			$result->addError(new Main\Error(Loc::getMessage("SALE_HPS_UAPAY_ERROR_PARSE_JWT")));
			return $result;
		}

		PaySystem\Logger::addDebugInfo(__CLASS__.": createSession payload: ".self::encode($payloadData));

		$result->setData(["id" => $payloadData["id"]]);
		return $result;
	}

	/**
	 * @param Payment $payment
	 * @return PaySystem\ServiceResult
	 * @throws Main\ArgumentException
	 * @throws Main\ArgumentNullException
	 * @throws Main\ArgumentOutOfRangeException
	 * @throws Main\ArgumentTypeException
	 * @throws Main\NotImplementedException
	 * @throws Main\ObjectException
	 */
	private function createInvoice(Payment $payment)
	{
		$result = new PaySystem\ServiceResult();

		$sessionResult = $this->createSession($payment);
		if (!$sessionResult->isSuccess())
		{
			$result->addErrors($sessionResult->getErrors());
			return $result;
		}

		$sessionData = $sessionResult->getData();

		$url = $this->getUrl($payment, "invoicesCreate");
		$extraInfo = [
			"paySystemId" => $this->service->getField("ID"),
		];
		$requestParams = [
			"params" => [
				"sessionId" => $sessionData["id"],
				"systemType" => "ECOM"
			],
			"data" => [
				"externalId" => $payment->getField("ACCOUNT_NUMBER"),
				"reusability" => false,
				"type" => "PAY",
				"callbackUrl" => $this->getBusinessValue($payment, "UAPAY_CALLBACK_URL"),
				"description" => $this->getPaymentDescription($payment),
				"amount" => (int)PriceMaths::roundPrecision($payment->getSum() * 100),
				"redirectUrl" => $this->getRedirectUrl($payment),
				"extraInfo" => self::encode($extraInfo),
			],
		];

		if ($userEmail = $payment->getOrder()->getPropertyCollection()->getUserEmail())
		{
			$requestParams["data"]["email"] = $userEmail->getValue();
		}

		$sendResult = $this->send($payment, $url, $requestParams);
		if (!$sendResult->isSuccess())
		{
			$result->addErrors($sendResult->getErrors());
			return $result;
		}

		$sendData = $sendResult->getData();

		$validationResult = $this->validationResponse($payment, $sendData);
		if (!$validationResult->isSuccess())
		{
			$result->addErrors($validationResult->getErrors());
			return $result;
		}

		$payloadData = self::getPayload($sendData["data"]["token"]);
		if (!$payloadData)
		{
			$result->addError(new Main\Error(Loc::getMessage("SALE_HPS_UAPAY_ERROR_PARSE_JWT")));
			return $result;
		}

		PaySystem\Logger::addDebugInfo(__CLASS__.": createInvoice payload: ".self::encode($payloadData));

		$result->setPsData(["PS_INVOICE_ID" => $payloadData["id"]]);
		$result->setData($payloadData);
		return $result;
	}

	/**
	 * @param Payment $payment
	 * @return mixed|string
	 */
	private function getRedirectUrl(Payment $payment)
	{
		return $this->getBusinessValue($payment, 'UAPAY_REDIRECT_URL') ?: $this->service->getContext()->getUrl();
	}

	/**
	 * @param Payment $payment
	 * @param $refundableSum
	 * @return PaySystem\ServiceResult
	 * @throws Main\ArgumentException
	 * @throws Main\ArgumentNullException
	 * @throws Main\ArgumentOutOfRangeException
	 * @throws Main\ArgumentTypeException
	 * @throws Main\ObjectException
	 */
	public function refund(Payment $payment, $refundableSum)
	{
		$result = new PaySystem\ServiceResult();

		$sessionResult = $this->createSession($payment);
		if ($sessionResult->isSuccess())
		{
			$sessionData = $sessionResult->getData();

			$psInvoiceId = $payment->getField("PS_INVOICE_ID");
			$psInvoiceIdList = explode(self::INVOICE_ID_DELIMITER, $psInvoiceId);
			if (count($psInvoiceIdList) == 2)
			{
				$url = $this->getUrl($payment, "paymentReverse");
				$requestParams = [
					"params" => [
						"sessionId" => $sessionData["id"],
						"invoiceId" => $psInvoiceIdList[0],
						"paymentId" => $psInvoiceIdList[1],
					],
				];

				$sendResult = $this->send($payment, $url, $requestParams);
				if (!$sendResult->isSuccess())
				{
					$result->addErrors($sendResult->getErrors());
				}

				if ($sendResult->isSuccess())
				{
					$sendData = $sendResult->getData();
					$validationResult = $this->validationResponse($payment, $sendData);
					if (!$validationResult->isSuccess())
					{
						$result->addErrors($validationResult->getErrors());
					}

					if ($validationResult->isSuccess())
					{
						$payloadData = self::getPayload($sendData["data"]["token"]);
						if ($payloadData)
						{
							PaySystem\Logger::addDebugInfo(__CLASS__.": refund payload: ".self::encode($payloadData));
						}
						else
						{
							$result->addError(new Main\Error(Loc::getMessage("SALE_HPS_UAPAY_ERROR_PARSE_JWT")));
						}
					}
				}
			}
			else
			{
				$result->addError(new Main\Error(Loc::getMessage("SALE_HPS_UAPAY_ERROR_PAYMENT_ID")));
			}
		}
		else
		{
			$result->addErrors($sessionResult->getErrors());
		}

		if ($result->isSuccess())
		{
			$result->setOperationType(PaySystem\ServiceResult::MONEY_LEAVING);
		}
		else
		{
			PaySystem\Logger::addError(__CLASS__.": refund: ".join("\n", $result->getErrorMessages()));
		}

		return $result;
	}

	/**
	 * @param Payment $payment
	 * @param $url
	 * @param array $params
	 * @return PaySystem\ServiceResult
	 * @throws Main\ArgumentException
	 * @throws Main\ArgumentNullException
	 * @throws Main\ArgumentOutOfRangeException
	 * @throws Main\ArgumentTypeException
	 * @throws Main\ObjectException
	 */
	private function send(Payment $payment, $url, array $params)
	{
		$result = new PaySystem\ServiceResult();
		$httpClient = new HttpClient();

		$headers = $this->getHeaders();
		foreach ($headers as $name => $value)
		{
			$httpClient->setHeader($name, $value);
		}

		$params["iat"] = time();
		$params["token"] = $this->getJwt($payment, $params);
		$postData = self::encode($params);

		PaySystem\Logger::addDebugInfo(__CLASS__.": request data: ".$postData);

		$response = $httpClient->post($url, $postData);
		if ($response === false)
		{
			$errors = $httpClient->getError();
			foreach ($errors as $code =>$message)
			{
				$result->addError(new Main\Error($message, $code));
			}

			return $result;
		}

		PaySystem\Logger::addDebugInfo(__CLASS__.": response data: ".$response);

		$httpStatus = $httpClient->getStatus();
		if ($httpStatus !== 200)
		{
			$result->addError(new Main\Error(Loc::getMessage("SALE_HPS_UAPAY_ERROR_HTTP_STATUS", [
				"#STATUS_CODE#" => $httpStatus
			])));
			return $result;
		}

		$response = self::decode($response);
		if ($response)
		{
			$result->setData($response);
		}

		return $result;
	}

	/**
	 * @param Payment $payment
	 * @param $response
	 * @return PaySystem\ServiceResult
	 */
	private function validationResponse(Payment $payment, $response)
	{
		$result = new PaySystem\ServiceResult();

		if (!is_array($response))
		{
			$result->addError(new Main\Error(Loc::getMessage("SALE_HPS_UAPAY_ERROR_RESPONSE")));
			return $result;
		}

		if (isset($response["status"]) && !$response["status"])
		{
			$result->addError(new Main\Error(Loc::getMessage("SALE_HPS_UAPAY_ERROR_RESPONSE_STATUS")));
			return $result;
		}

		if (isset($response["error"]))
		{
			$result->addError(new Main\Error($response["error"]["message"], $response["error"]["code"]));
			return $result;
		}

		if (!$this->isTokenCorrect($response["data"]["token"], $payment))
		{
			$result->addError(new Main\Error(Loc::getMessage("SALE_HPS_UAPAY_ERROR_CHECK_SUM")));
			return $result;
		}

		return $result;
	}

	/**
	 * @return array
	 */
	private function getHeaders()
	{
		$headers = [
			"Content-Type" => "application/json",
		];

		return $headers;
	}

	/**
	 * @param $token
	 * @return mixed|null
	 */
	private static function getPayload($token)
	{
		$tokenPathList = explode(".", $token);
		if (count($tokenPathList) != 3)
		{
			return null;
		}

		$payload = self::decode(self::urlSafeBase64Decode($tokenPathList[1]));
		return $payload;
	}

	/**
	 * @param $token
	 * @param Payment $payment
	 * @return bool
	 */
	private function isTokenCorrect($token, Payment $payment)
	{
		$signKey = (string)$this->getBusinessValue($payment, "UAPAY_SIGN_KEY");

		$tokenPathList = explode(".", $token);
		if (count($tokenPathList) != 3)
		{
			return false;
		}

		list($headBase64, $bodyBase64, $cryptoBase64) = $tokenPathList;
		$signature = self::urlSafeBase64Decode($cryptoBase64);

		$hash = hash_hmac("sha256", $headBase64.".".$bodyBase64, $signKey, true);
		if ($hash)
		{
			return hash_equals($signature, $hash);
		}

		return false;
	}

	/**
	 * @param Payment $payment
	 * @param array $payload
	 * @return string
	 * @throws Main\ArgumentException
	 */
	private function getJwt(Payment $payment, array $payload)
	{
		$signKey = (string)$this->getBusinessValue($payment, "UAPAY_SIGN_KEY");

		$search = ["+", "/", "="];
		$replace = ["-", "_", ""];

		$header = self::encode(["alg" => "HS256", "typ" => "JWT"]);
		$base64UrlHeader = str_replace($search, $replace, base64_encode($header));

		$payload = self::encode($payload);
		$base64UrlPayload = str_replace($search, $replace, base64_encode($payload));

		$signature = hash_hmac("sha256", $base64UrlHeader.".".$base64UrlPayload, $signKey, true);
		$base64UrlSignature = str_replace($search, $replace, base64_encode($signature));
		$jwt = $base64UrlHeader.".".$base64UrlPayload.".".$base64UrlSignature;
		return $jwt;
	}

	/**
	 * @return array
	 */
	public function getCurrencyList()
	{
		return ["UAH"];
	}

	/**
	 * @param Payment $payment
	 * @param Request $request
	 * @return PaySystem\ServiceResult
	 * @throws Main\ArgumentException
	 * @throws Main\ArgumentNullException
	 * @throws Main\ArgumentOutOfRangeException
	 * @throws Main\ArgumentTypeException
	 * @throws Main\ObjectException
	 */
	public function processRequest(Payment $payment, Request $request)
	{
		$result = new PaySystem\ServiceResult();

		$inputStream = self::readFromStream();
		$data = self::decode($inputStream);
		if ($payloadData = self::getPayload($data["token"]))
		{
			PaySystem\Logger::addDebugInfo(__CLASS__.": processRequest payloadData: ".self::encode($payloadData));
			if ($this->isTokenCorrect($data["token"], $payment))
			{
				$paymentId = $payloadData["paymentId"] ?? $payloadData["id"];
				if ($payloadData["paymentStatus"] === self::PAYMENT_STATUS_FINISHED && $paymentId)
				{
					$description = Loc::getMessage("SALE_HPS_UAPAY_TRANSACTION", [
						"#ID#" => $payloadData["id"],
						"#PAYMENT_NUMBER#" => $payloadData["paymentNumber"]
					]);
					$invoiceId = $payloadData["invoiceId"] ?? $payloadData["orderId"];
					$fields = array(
						"PS_INVOICE_ID" => $invoiceId.self::INVOICE_ID_DELIMITER.$paymentId,
						"PS_STATUS_CODE" => $payloadData["paymentStatus"],
						"PS_STATUS_DESCRIPTION" => $description,
						"PS_SUM" => $payloadData["amount"] / 100,
						"PS_STATUS" => "N",
						"PS_RESPONSE_DATE" => new Main\Type\DateTime()
					);

					if ($this->isSumCorrect($payment, $payloadData["amount"] / 100))
					{
						$fields["PS_STATUS"] = "Y";

						PaySystem\Logger::addDebugInfo(
							__CLASS__.": PS_CHANGE_STATUS_PAY=".$this->getBusinessValue($payment, "PS_CHANGE_STATUS_PAY")
						);

						if ($this->getBusinessValue($payment, "PS_CHANGE_STATUS_PAY") === "Y")
						{
							$result->setOperationType(PaySystem\ServiceResult::MONEY_COMING);
						}
					}
					else
					{
						$error = Loc::getMessage("SALE_HPS_UAPAY_ERROR_SUM");
						$fields["PS_STATUS_DESCRIPTION"] .= " ".$error;
						$result->addError(new Main\Error($error));
					}

					$result->setPsData($fields);
				}
			}
			else
			{
				$result->addError(new Main\Error(Loc::getMessage("SALE_HPS_UAPAY_ERROR_CHECK_SUM")));
			}
		}
		else
		{
			$result->addError(new Main\Error(Loc::getMessage("SALE_HPS_UAPAY_ERROR_PARSE_JWT")));
		}

		if (!$result->isSuccess())
		{
			$error = __CLASS__.": processRequest: ".join("\n", $result->getErrorMessages());
			PaySystem\Logger::addError($error);
		}

		return $result;
	}

	/**
	 * @param Payment $payment
	 * @param $amount
	 * @return bool
	 * @throws Main\ArgumentNullException
	 * @throws Main\ArgumentOutOfRangeException
	 * @throws Main\ArgumentTypeException
	 * @throws Main\ObjectException
	 */
	private function isSumCorrect(Payment $payment, $amount)
	{
		PaySystem\Logger::addDebugInfo(
			__CLASS__.": sum=".PriceMaths::roundPrecision($amount)."; paymentSum=".PriceMaths::roundPrecision($payment->getSum())
		);

		return PriceMaths::roundPrecision($amount) === PriceMaths::roundPrecision($payment->getSum());
	}

	/**
	 * @param Request $request
	 * @param int $paySystemId
	 * @return bool
	 */
	public static function isMyResponse(Request $request, $paySystemId)
	{
		$inputStream = self::readFromStream();
		if ($inputStream)
		{
			$data = self::decode($inputStream);
			if ($data !== false && isset($data["token"]))
			{
				$payloadData = self::getPayload($data["token"]);
				if (!$payloadData)
				{
					return false;
				}

				if (isset($payloadData["extraInfo"]) && !is_array($payloadData["extraInfo"]))
				{
					$payloadData["extraInfo"] = self::decode($payloadData["extraInfo"]);
				}

				if (isset($payloadData["extraInfo"]["paySystemId"]) && ((int)$payloadData["extraInfo"]["paySystemId"] === (int)$paySystemId))
				{
					return true;
				}
			}
		}

		return false;
	}

	/**
	 * @param Request $request
	 * @return mixed
	 */
	public function getPaymentIdFromRequest(Request $request)
	{
		$inputStream = self::readFromStream();
		$data = self::decode($inputStream);
		$payloadData = self::getPayload($data["token"]);
		if (!$payloadData)
		{
			return false;
		}

		if (isset($payloadData["externalId"]))
		{
			return $payloadData["externalId"];
		}

		return false;
	}

	/**
	 * @return array
	 */
	protected function getUrlList()
	{
		$testUrl = "https://api.demo.uapay.ua/api/";
		$activeUrl = "https://api.uapay.ua/api/";

		return [
			"sessionCreate" => [
				self::TEST_URL => $testUrl."sessions/create",
				self::ACTIVE_URL => $activeUrl."sessions/create",
			],
			"invoicesCreate" => [
				self::TEST_URL => $testUrl."invoicer/invoices/create",
				self::ACTIVE_URL => $activeUrl."invoicer/invoices/create",
			],
			"paymentReverse" => [
				self::TEST_URL => $testUrl."invoicer/payments/reverse",
				self::ACTIVE_URL => $activeUrl."invoicer/payments/reverse",
			]
		];
	}

	/**
	 * @param Payment $payment
	 * @return bool
	 */
	protected function isTestMode(Payment $payment = null)
	{
		return ($this->getBusinessValue($payment, "UAPAY_TEST_MODE") === "Y");
	}

	/**
	 * @param Payment $payment
	 * @return mixed
	 * @throws Main\ArgumentException
	 * @throws Main\ArgumentOutOfRangeException
	 * @throws Main\NotImplementedException
	 */
	private function getPaymentDescription(Payment $payment)
	{
		/** @var PaymentCollection $collection */
		$collection = $payment->getCollection();
		$order = $collection->getOrder();
		$userEmail = $order->getPropertyCollection()->getUserEmail();

		$description =  str_replace(
			[
				"#PAYMENT_NUMBER#",
				"#ORDER_NUMBER#",
				"#PAYMENT_ID#",
				"#ORDER_ID#",
				"#USER_EMAIL#"
			],
			[
				$payment->getField("ACCOUNT_NUMBER"),
				$order->getField("ACCOUNT_NUMBER"),
				$payment->getId(),
				$order->getId(),
				($userEmail) ? $userEmail->getValue() : ""
			],
			$this->getBusinessValue($payment, "UAPAY_INVOICE_DESCRIPTION")
		);

		return $description;
	}

	/**
	 * @param array $data
	 * @return mixed
	 * @throws Main\ArgumentException
	 */
	private static function encode(array $data)
	{
		return Main\Web\Json::encode($data, JSON_UNESCAPED_UNICODE);
	}

	/**
	 * @param string $data
	 * @return mixed
	 */
	private static function decode($data)
	{
		try
		{
			return Main\Web\Json::decode($data);
		}
		catch (Main\ArgumentException $exception)
		{
			return false;
		}
	}

	/**
	 * @param $input
	 * @return bool|string
	 */
	private static function urlSafeBase64Decode($input)
	{
		$remainder = mb_strlen($input) % 4;
		if ($remainder)
		{
			$padLength = 4 - $remainder;
			$input .= str_repeat("=", $padLength);
		}
		return base64_decode(strtr($input, "-_", "+/"));
	}

	/**
	 * @return bool|string
	 */
	private static function readFromStream()
	{
		return file_get_contents("php://input");
	}
}

Youez - 2016 - github.com/yon3zu
LinuXploit