Skip to content

Commit 0a2c477

Browse files
authored
[ReadyForReview] Exposing cart links for GUEST CARTS (magento only allows logged-in carts by default); (#747)
* creating a route that allows access to guest carts * Final tweaks to add rsa functionality * removing changes to admin urls * removing log exposure of public key * helper function for signature verification * addressing suggestions * Missing module.xml * protected usage is discouraged * modifying composer * Moving logic into Meta Sales module due to etalon-composer mismatch * fixing module.xml issue * Incorrect namespace
1 parent fcb8961 commit 0a2c477

File tree

3 files changed

+160
-0
lines changed

3 files changed

+160
-0
lines changed

app/code/Meta/BusinessExtension/Model/Api/CustomApiKey/Authenticator.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,4 +160,25 @@ private function authenticateSignature(?string $storeId = null): void
160160
throw $ex;
161161
}
162162
}
163+
164+
/**
165+
* Verify the RSA signature for an arbitrary data string.
166+
*
167+
* @param string $data
168+
* @param string $signature
169+
* @return bool
170+
* @throws LocalizedException
171+
*/
172+
public function verifySignature(string $data, string $signature): bool
173+
{
174+
// phpcs:ignore Magento2.Functions.DiscouragedFunction
175+
$publicKey = file_get_contents(__DIR__ . '/PublicKey.pem');
176+
$publicKeyResource = openssl_get_publickey($publicKey);
177+
if ($publicKeyResource === false) {
178+
throw new LocalizedException(__('Invalid Public Key'));
179+
}
180+
// phpcs:ignore Magento2.Functions.DiscouragedFunction
181+
$decodedSignature = base64_decode($signature);
182+
return openssl_verify($data, $decodedSignature, $publicKeyResource, OPENSSL_ALGO_SHA256) === 1;
183+
}
163184
}
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Meta\Sales\Controller\Checkout;
6+
7+
use Magento\Checkout\Model\Session as CheckoutSession;
8+
use Magento\Framework\App\Action\HttpGetActionInterface;
9+
use Magento\Framework\App\RequestInterface;
10+
use Magento\Framework\App\ResponseInterface;
11+
use Magento\Framework\Controller\Result\RedirectFactory;
12+
use Magento\Framework\Exception\LocalizedException;
13+
use Magento\Quote\Model\QuoteIdMaskFactory;
14+
use Magento\Quote\Model\QuoteRepository;
15+
use Meta\BusinessExtension\Helper\FBEHelper;
16+
use Meta\BusinessExtension\Model\Api\CustomApiKey\Authenticator;
17+
18+
/**
19+
* Controller for loading cart based on masked ID.
20+
*/
21+
class LoadMetaCart implements HttpGetActionInterface
22+
{
23+
/**
24+
* @var RedirectFactory
25+
*/
26+
private $resultRedirectFactory;
27+
28+
/**
29+
* @var QuoteIdMaskFactory
30+
*/
31+
private $quoteIdMaskFactory;
32+
33+
/**
34+
* @var QuoteRepository
35+
*/
36+
private $quoteRepository;
37+
38+
/**
39+
* @var CheckoutSession
40+
*/
41+
private $checkoutSession;
42+
43+
/**
44+
* @var RequestInterface
45+
*/
46+
private $request;
47+
48+
/**
49+
* @var FBEHelper
50+
*/
51+
private $fbeHelper;
52+
53+
/**
54+
* @var Authenticator
55+
*/
56+
private $authenticator;
57+
58+
/**
59+
* Constructor.
60+
*
61+
* @param RequestInterface $request
62+
* @param RedirectFactory $resultRedirectFactory
63+
* @param QuoteIdMaskFactory $quoteIdMaskFactory
64+
* @param QuoteRepository $quoteRepository
65+
* @param CheckoutSession $checkoutSession
66+
* @param FBEHelper $fbeHelper
67+
* @param Authenticator $authenticator
68+
*/
69+
public function __construct(
70+
RequestInterface $request,
71+
RedirectFactory $resultRedirectFactory,
72+
QuoteIdMaskFactory $quoteIdMaskFactory,
73+
QuoteRepository $quoteRepository,
74+
CheckoutSession $checkoutSession,
75+
FBEHelper $fbeHelper,
76+
Authenticator $authenticator
77+
) {
78+
$this->request = $request;
79+
$this->resultRedirectFactory = $resultRedirectFactory;
80+
$this->quoteIdMaskFactory = $quoteIdMaskFactory;
81+
$this->quoteRepository = $quoteRepository;
82+
$this->checkoutSession = $checkoutSession;
83+
$this->fbeHelper = $fbeHelper;
84+
$this->authenticator = $authenticator;
85+
}
86+
87+
/**
88+
* Execute action based on request.
89+
*
90+
* IMPORTANT: Signatures must be URL-Encoded after being Base64 Encoded, or verification will fail.
91+
*
92+
* @return ResponseInterface
93+
*/
94+
public function execute()
95+
{
96+
try {
97+
98+
$cartId = $this->request->getParam('cart_id');
99+
$signature = $this->request->getParam('signature');
100+
101+
if (!$this->authenticator->verifySignature($cartId, $signature)) {
102+
$this->fbeHelper->log(
103+
"RSA Verification Failed for cartId: {$cartId} with signature: {$signature}"
104+
);
105+
throw new LocalizedException(__('RSA Signature Validation Failed'));
106+
}
107+
108+
$quoteId = $this->quoteIdMaskFactory->create()->load($cartId, 'masked_id')->getQuoteId();
109+
$quote = $this->quoteRepository->get($quoteId);
110+
$this->checkoutSession->replaceQuote($quote);
111+
$resultRedirect = $this->resultRedirectFactory->create();
112+
$resultRedirect->setPath('checkout/cart');
113+
return $resultRedirect;
114+
} catch (\Exception $e) {
115+
$this->fbeHelper->logExceptionImmediatelyToMeta(
116+
$e,
117+
[
118+
'event' => 'guest_cart_link',
119+
'event_type' => 'cart_redirect',
120+
'extra_data' => [
121+
'signature' => $signature,
122+
'cart_id' => $cartId,
123+
],
124+
]
125+
);
126+
$resultRedirect = $this->resultRedirectFactory->create();
127+
$resultRedirect->setPath('checkout/cart');
128+
return $resultRedirect;
129+
}
130+
}
131+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?xml version="1.0"?>
2+
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd">
3+
<router id="standard">
4+
<route id="meta" frontName="meta">
5+
<module name="Meta_Sales"/>
6+
</route>
7+
</router>
8+
</config>

0 commit comments

Comments
 (0)