Skip to content

Commit cb5525f

Browse files
authored
Merge pull request #45 from BitBagCommerce/UC-30-fix-cookie
[UC-30] Fix cookie handling
2 parents 3251f5e + 87d7133 commit cb5525f

10 files changed

Lines changed: 165 additions & 13 deletions

File tree

config/config.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ parameters:
88
user_com.frontend_api_key: '%env(USER_COM_FRONTEND_API_KEY)%'
99
user_com.encryption_key: '%env(USER_COM_ENCRYPTION_KEY)%'
1010
user_com.encryption_iv: '%env(USER_COM_ENCRYPTION_IV)%'
11-
11+
user_com.cookie_domain: '%env(USER_COM_COOKIE_DOMAIN)%'
12+
1213
twig:
1314
globals:
1415
user_com_frontend_api_key: '%user_com.frontend_api_key%'

config/services/cookie.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
3+
<container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
4+
<services>
5+
<defaults autowire="false" autoconfigure="false"/>
6+
<service id="bit_bag.sylius_user_com_plugin.cookie.cookie_queue" class="BitBag\SyliusUserComPlugin\Cookie\CookieQueue" />
7+
</services>
8+
</container>

config/services/event_subscriber.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,13 @@
1515
<argument type="service" id="monolog.logger.user_com"/>
1616
<tag name="kernel.event_subscriber"/>
1717
</service>
18+
19+
<service id="bit_bag.sylius_user_com_plugin.event_subscriber.cookie_flusher_subscriber" class="BitBag\SyliusUserComPlugin\EventSubscriber\CookieFlusherSubscriber">
20+
<argument type="service" id="bit_bag.sylius_user_com_plugin.cookie.cookie_queue" />
21+
<tag name="kernel.event_listener"
22+
event="kernel.response"
23+
method="onResponse"
24+
priority="0"/>
25+
</service>
1826
</services>
1927
</container>

config/services/manager.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
>
1010
<argument type="service" id="request_stack"/>
1111
<argument type="service" id="security.token_storage"/>
12+
<argument type="service" id="bit_bag.sylius_user_com_plugin.cookie.cookie_queue"/>
13+
<argument>%user_com.cookie_domain%</argument>
1214
</service>
1315

1416
<service

src/Cookie/CookieQueue.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
/*
4+
* This file has been created by developers from BitBag.
5+
* Feel free to contact us once you face any issues or want to start
6+
* You can find more information about us on https://bitbag.io and write us
7+
* an email on hello@bitbag.io.
8+
*/
9+
10+
declare(strict_types=1);
11+
12+
namespace BitBag\SyliusUserComPlugin\Cookie;
13+
14+
use Symfony\Component\HttpFoundation\Cookie;
15+
16+
final class CookieQueue implements CookieQueueInterface
17+
{
18+
private array $queued = [];
19+
20+
public function queue(Cookie $cookie): void
21+
{
22+
$this->queued[] = $cookie;
23+
}
24+
25+
/** @return Cookie[] */
26+
public function pullAll(): array
27+
{
28+
$all = $this->queued;
29+
$this->queued = [];
30+
31+
return $all;
32+
}
33+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
/*
4+
* This file has been created by developers from BitBag.
5+
* Feel free to contact us once you face any issues or want to start
6+
* You can find more information about us on https://bitbag.io and write us
7+
* an email on hello@bitbag.io.
8+
*/
9+
10+
declare(strict_types=1);
11+
12+
namespace BitBag\SyliusUserComPlugin\Cookie;
13+
14+
use Symfony\Component\HttpFoundation\Cookie;
15+
16+
interface CookieQueueInterface
17+
{
18+
public function queue(Cookie $cookie): void;
19+
20+
/** @return Cookie[] */
21+
public function pullAll(): array;
22+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
/*
4+
* This file has been created by developers from BitBag.
5+
* Feel free to contact us once you face any issues or want to start
6+
* You can find more information about us on https://bitbag.io and write us
7+
* an email on hello@bitbag.io.
8+
*/
9+
10+
declare(strict_types=1);
11+
12+
namespace BitBag\SyliusUserComPlugin\EventSubscriber;
13+
14+
use BitBag\SyliusUserComPlugin\Cookie\CookieQueueInterface;
15+
use Symfony\Component\HttpKernel\Event\ResponseEvent;
16+
17+
final class CookieFlusherSubscriber
18+
{
19+
public function __construct(private readonly CookieQueueInterface $queue)
20+
{
21+
}
22+
23+
public function onResponse(ResponseEvent $event): void
24+
{
25+
$response = $event->getResponse();
26+
27+
foreach ($this->queue->pullAll() as $cookie) {
28+
$response->headers->setCookie($cookie);
29+
}
30+
}
31+
}

src/Manager/CookieManager.php

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111

1212
namespace BitBag\SyliusUserComPlugin\Manager;
1313

14+
use BitBag\SyliusUserComPlugin\Cookie\CookieQueueInterface;
1415
use Sylius\Component\Core\Model\AdminUserInterface;
16+
use Symfony\Component\HttpFoundation\Cookie;
1517
use Symfony\Component\HttpFoundation\RequestStack;
1618
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
1719

@@ -20,6 +22,8 @@ final class CookieManager implements CookieManagerInterface
2022
public function __construct(
2123
private readonly RequestStack $requestStack,
2224
private readonly TokenStorageInterface $tokenStorage,
25+
private readonly CookieQueueInterface $queue,
26+
private readonly ?string $cookieDomain = null,
2327
) {
2428
}
2529

@@ -41,11 +45,29 @@ public function getUserComCookie(): ?string
4145

4246
public function setUserComCookie(string $value): void
4347
{
44-
$request = $this->requestStack->getCurrentRequest();
45-
if (null === $request) {
46-
return;
48+
$cookie = Cookie::create(self::CHAT_COOKIE_NAME)
49+
->withValue($value)
50+
->withPath('/')
51+
->withSecure(true)
52+
->withExpires(new \DateTimeImmutable('+1 year'))
53+
->withHttpOnly(false)
54+
->withSameSite('lax');
55+
56+
if (null !== $this->cookieDomain && '' !== $this->cookieDomain) {
57+
$cookie = $cookie->withDomain($this->cookieDomain);
58+
} else {
59+
$request = $this->requestStack->getCurrentRequest();
60+
if (null === $request) {
61+
return;
62+
}
63+
64+
$domain = $this->getBaseDomain($request->getHost());
65+
if (null !== $domain) {
66+
$cookie = $cookie->withDomain($domain);
67+
}
4768
}
48-
$request->cookies->set(self::CHAT_COOKIE_NAME, $value);
69+
70+
$this->queue->queue($cookie);
4971
}
5072

5173
private function isShopUser(): bool
@@ -59,4 +81,22 @@ private function isShopUser(): bool
5981

6082
return true;
6183
}
84+
85+
private function getBaseDomain(string $host): ?string
86+
{
87+
$host = (string) preg_replace('/:\d+$/', '', $host);
88+
89+
if ($host === 'localhost' || filter_var($host, \FILTER_VALIDATE_IP) !== false) {
90+
return null;
91+
}
92+
93+
$parts = explode('.', $host);
94+
$count = count($parts);
95+
96+
if ($count >= 2) {
97+
return '.' . $parts[$count - 2] . '.' . $parts[$count - 1];
98+
}
99+
100+
return null;
101+
}
62102
}

src/Updater/CustomerWithKeyUpdater.php

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -108,13 +108,20 @@ public function updateWithUserKey(
108108
);
109109

110110
$this->userApi->mergeUsers($apiAwareResource, $userByEmailFromForm['id'], [$userFoundByKey['id']]);
111-
$this->changeCookieWithEvent($user, $apiAwareResource, $eventName, $payload);
111+
if (is_array($user) && isset($user['email']) && is_string($user['email'])) {
112+
$this->sendEvent($apiAwareResource, $user['email'], $eventName, $payload);
113+
}
114+
$this->changeCookie($user);
112115

113116
return $user;
114117
}
115118

116119
$user = $this->userApi->createUser($apiAwareResource, $payload);
117-
$this->changeCookieWithEvent($user, $apiAwareResource, $eventName, $payload);
120+
121+
if (is_array($user) && isset($user['email']) && is_string($user['email'])) {
122+
$this->sendEvent($apiAwareResource, $user['email'], $eventName, $payload);
123+
}
124+
$this->changeCookie($user);
118125

119126
return $user;
120127
}
@@ -154,16 +161,16 @@ private function updateForUserWithoutEmail(
154161
$this->userApi->mergeUsers($apiAwareResource, $customerFoundByEmail['id'], [$userFromUserKey['id']]);
155162
}
156163

157-
$this->sendEvent($apiAwareResource, $email, $eventName, $payload);
164+
if (is_array($user) && isset($user['email']) && is_string($user['email'])) {
165+
$this->sendEvent($apiAwareResource, $user['email'], $eventName, $payload);
166+
}
167+
$this->changeCookie($user);
158168

159169
return $user;
160170
}
161171

162-
public function changeCookieWithEvent(
172+
public function changeCookie(
163173
?array $user,
164-
UserComApiAwareInterface $apiAwareResource,
165-
string $eventName,
166-
?array $payload = null,
167174
): void {
168175
if (false === is_array($user) ||
169176
false === array_key_exists('id', $user) ||
@@ -173,6 +180,5 @@ public function changeCookieWithEvent(
173180
}
174181

175182
$this->cookieManager->setUserComCookie($user['user_key']);
176-
$this->sendEvent($apiAwareResource, $user['email'], $eventName, $payload);
177183
}
178184
}

tests/Application/.env

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,6 @@ SYLIUS_MESSENGER_TRANSPORT_CATALOG_PROMOTION_REMOVAL_FAILED_DSN=doctrine://defau
3636
USER_COM_FRONTEND_API_KEY=""
3737
USER_COM_ENCRYPTION_KEY=your-32-character-long-key
3838
USER_COM_ENCRYPTION_IV=your-16-character-long-
39+
USER_COM_COOKIE_DOMAIN=""
3940
MESSENGER_USER_COM_ASYNCHRONOUS_DSN="doctrine://default"
4041
###< UserCom

0 commit comments

Comments
 (0)