diff --git a/module/oc_telegram_shop/upload/catalog/controller/extension/tgshop/handle.php b/module/oc_telegram_shop/upload/catalog/controller/extension/tgshop/handle.php index 5c98663..a629b42 100755 --- a/module/oc_telegram_shop/upload/catalog/controller/extension/tgshop/handle.php +++ b/module/oc_telegram_shop/upload/catalog/controller/extension/tgshop/handle.php @@ -48,7 +48,7 @@ class Controllerextensiontgshophandle extends Controller 'theme_dark' => $this->config->get('module_tgshop_theme_dark'), 'mainpage_products' => $this->config->get('module_tgshop_mainpage_products'), 'featured_products' => $this->config->get('module_tgshop_featured_products'), - 'ya_metrika_enabled' => !empty(trim($this->config->get('module_tgshop_yandex_metrika'))), + 'ya_metrika_enabled' => ! empty(trim($this->config->get('module_tgshop_yandex_metrika'))), 'telegram' => [ 'bot_token' => $this->config->get('module_tgshop_bot_token'), 'chat_id' => $this->config->get('module_tgshop_chat_id'), @@ -103,7 +103,8 @@ class Controllerextensiontgshophandle extends Controller $app->bootAndHandleRequest(); } - function extractPureJs($input) { + function extractPureJs($input) + { // Убираем $input = preg_replace('##is', '', $input); diff --git a/module/oc_telegram_shop/upload/oc_telegram_shop/framework/Application.php b/module/oc_telegram_shop/upload/oc_telegram_shop/framework/Application.php index ea8a3a8..bb55809 100755 --- a/module/oc_telegram_shop/upload/oc_telegram_shop/framework/Application.php +++ b/module/oc_telegram_shop/upload/oc_telegram_shop/framework/Application.php @@ -17,6 +17,7 @@ class Application extends Container private static Application $instance; private static array $events = []; private array $serviceProviders = []; + private array $middlewareStack = []; /** * @var ExecutionTimeProfiler @@ -91,9 +92,16 @@ class Application extends Container throw new InvalidArgumentException('Invalid action: ' . $controller . '->' . $method); } - $this->profiler->addCheckpoint('Handle Router.'); + $this->profiler->addCheckpoint('Handle Middlewares.'); - $response = $this->call($controller, $method); + $next = fn($req) => $this->call($controller, $method); + + foreach (array_reverse($this->middlewareStack) as $class) { + $instance = $this->get($class); + $next = static fn($req) => $instance->handle($req, $next); + } + + $response = $next($request); $this->profiler->addCheckpoint('Handle HTTP request.'); @@ -114,4 +122,11 @@ class Application extends Container return $this; } + + public function withMiddlewares(array $middlewares): Application + { + $this->middlewareStack = $middlewares; + + return $this; + } } diff --git a/module/oc_telegram_shop/upload/oc_telegram_shop/framework/Http/Request.php b/module/oc_telegram_shop/upload/oc_telegram_shop/framework/Http/Request.php index c8bc945..30344ae 100755 --- a/module/oc_telegram_shop/upload/oc_telegram_shop/framework/Http/Request.php +++ b/module/oc_telegram_shop/upload/oc_telegram_shop/framework/Http/Request.php @@ -80,4 +80,14 @@ class Request { return $_SERVER['HTTP_USER_AGENT'] ?? null; } + + public function header(string $name): ?string + { + $headers = []; + foreach (getallheaders() as $key => $value) { + $headers[mb_strtolower($key)] = trim($value); + } + + return $headers[mb_strtolower($name)] ?? null; + } } diff --git a/module/oc_telegram_shop/upload/oc_telegram_shop/framework/Telegram/SignatureValidator.php b/module/oc_telegram_shop/upload/oc_telegram_shop/framework/Telegram/SignatureValidator.php new file mode 100755 index 0000000..0805291 --- /dev/null +++ b/module/oc_telegram_shop/upload/oc_telegram_shop/framework/Telegram/SignatureValidator.php @@ -0,0 +1,81 @@ +botToken = $botToken; + } + + public function validate(Request $request): void + { + if (! $this->botToken) { + return; + } + + $initDataString = rawurldecode($request->header('X-Telegram-Initdata')); + + if (! $initDataString) { + throw new TelegramInvalidSignatureException('Invalid Telegram signature!'); + } + + $data = $this->parseInitDataStringToArray($initDataString); + + if (!isset($data['hash'])) { + throw new TelegramInvalidSignatureException('Missing hash in init data'); + } + + $checkString = $this->getCheckString($data); + + $algorithm = 'sha256'; + $secretKey = hash_hmac($algorithm, $this->botToken, 'WebAppData', true); + $calculatedHash = bin2hex(hash_hmac($algorithm, $checkString, $secretKey, true)); + + if (! hash_equals($calculatedHash, $data['hash'])) { + throw new TelegramInvalidSignatureException('Invalid Telegram signature!'); + } + } + + private function parseInitDataStringToArray(string $initData): array + { + parse_str($initData, $parsed); + + foreach ($parsed as $key => $value) { + if ($this->isValidJson($value)) { + $parsed[$key] = json_decode(urldecode($value), true); + } + } + + return $parsed; + } + + private function isValidJson(string $jsonString): bool + { + json_decode($jsonString); + + return (json_last_error() === JSON_ERROR_NONE); + } + + private function getCheckString(array $data): string + { + unset($data['hash']); + ksort($data); + + $array = []; + foreach ($data as $key => $value) { + if (is_array($value)) { + $array[] = $key . '=' . json_encode($value, JSON_UNESCAPED_UNICODE); + } else { + $array[] = $key . '=' . $value; + } + } + + return implode(PHP_EOL, $array); + } +} diff --git a/module/oc_telegram_shop/upload/oc_telegram_shop/framework/Telegram/TelegramInvalidSignatureException.php b/module/oc_telegram_shop/upload/oc_telegram_shop/framework/Telegram/TelegramInvalidSignatureException.php new file mode 100644 index 0000000..075d1e0 --- /dev/null +++ b/module/oc_telegram_shop/upload/oc_telegram_shop/framework/Telegram/TelegramInvalidSignatureException.php @@ -0,0 +1,9 @@ +logger = $logger; $this->botToken = $botToken; diff --git a/module/oc_telegram_shop/upload/oc_telegram_shop/framework/Telegram/TelegramServiceProvider.php b/module/oc_telegram_shop/upload/oc_telegram_shop/framework/Telegram/TelegramServiceProvider.php index 3a15d69..2cfcd2e 100755 --- a/module/oc_telegram_shop/upload/oc_telegram_shop/framework/Telegram/TelegramServiceProvider.php +++ b/module/oc_telegram_shop/upload/oc_telegram_shop/framework/Telegram/TelegramServiceProvider.php @@ -13,8 +13,14 @@ class TelegramServiceProvider extends ServiceProvider $this->container->singleton(TelegramService::class, function (Application $app) { $botToken = $app->getConfigValue('telegram.bot_token'); return new TelegramService( - $botToken, $app->get(Logger::class), + $botToken, + ); + }); + + $this->container->singleton(SignatureValidator::class, function (Application $app) { + return new SignatureValidator( + $app->getConfigValue('telegram.bot_token'), ); }); } diff --git a/module/oc_telegram_shop/upload/oc_telegram_shop/framework/Telegram/TelegramValidateInitDataMiddleware.php b/module/oc_telegram_shop/upload/oc_telegram_shop/framework/Telegram/TelegramValidateInitDataMiddleware.php new file mode 100644 index 0000000..95420fc --- /dev/null +++ b/module/oc_telegram_shop/upload/oc_telegram_shop/framework/Telegram/TelegramValidateInitDataMiddleware.php @@ -0,0 +1,22 @@ +signatureValidator = $signatureValidator; + } + + public function handle($request, Closure $next) + { + $this->signatureValidator->validate($request); + + return $next($request); + } +} \ No newline at end of file diff --git a/module/oc_telegram_shop/upload/oc_telegram_shop/framework/Telegram/ValidateInitDataMiddleware.php b/module/oc_telegram_shop/upload/oc_telegram_shop/framework/Telegram/ValidateInitDataMiddleware.php deleted file mode 100755 index 650c5e5..0000000 --- a/module/oc_telegram_shop/upload/oc_telegram_shop/framework/Telegram/ValidateInitDataMiddleware.php +++ /dev/null @@ -1,13 +0,0 @@ -withMiddlewares([ + TelegramValidateInitDataMiddleware::class, ]); } } diff --git a/module/oc_telegram_shop/upload/oc_telegram_shop/src/Handlers/CartHandler.php b/module/oc_telegram_shop/upload/oc_telegram_shop/src/Handlers/CartHandler.php index 6ebcb89..0a6d5cf 100755 --- a/module/oc_telegram_shop/upload/oc_telegram_shop/src/Handlers/CartHandler.php +++ b/module/oc_telegram_shop/upload/oc_telegram_shop/src/Handlers/CartHandler.php @@ -6,18 +6,15 @@ use App\Services\CartService; use Cart\Cart; use Openguru\OpenCartFramework\Http\JsonResponse; use Openguru\OpenCartFramework\Http\Request; -use Openguru\OpenCartFramework\ImageTool\ImageToolInterface; class CartHandler { private Cart $cart; - private ImageToolInterface $imageTool; private CartService $cartService; - public function __construct(Cart $cart, ImageToolInterface $imageTool, CartService $cartService) + public function __construct(Cart $cart, CartService $cartService) { $this->cart = $cart; - $this->imageTool = $imageTool; $this->cartService = $cartService; } diff --git a/spa/src/utils/ftch.js b/spa/src/utils/ftch.js index 9d5a4b0..648da3b 100644 --- a/spa/src/utils/ftch.js +++ b/spa/src/utils/ftch.js @@ -5,12 +5,12 @@ const BASE_URL = '/'; export const apiFetch = ofetch.create({ throwHttpErrors: true, onRequest({request, options}) { - const initData = window.Telegram?.WebApp?.initData + const data = window.Telegram?.WebApp?.initData; - if (initData) { + if (data) { options.headers = { ...options.headers, - 'X-Telegram-InitData': initData, + 'X-Telegram-InitData': data, } } },