From 3f9191fca8bb8663ad34ea945c0dfca4a20735ba Mon Sep 17 00:00:00 2001 From: tinect Date: Mon, 8 Apr 2024 22:30:16 +0200 Subject: [PATCH] feat: support shopware 6.6 --- composer-ci.json | 11 ------ composer.json | 3 +- src/Controller/QrCodeController.php | 13 ++++--- .../StorefrontTwoFactorAuthController.php | 14 +++----- .../TwoFactorAuthenticationApiController.php | 14 +++----- .../TwoFactorAuthenticationController.php | 33 +++++++---------- .../app/administration/src/api/index.js | 8 +++++ .../app/administration/src/api/rl-2fa.js | 36 +++++++++++++++++++ .../src/component/rl-user-otp/index.js | 22 ++++++------ .../rl-user-otp/rl-user-otp.html.twig | 2 +- src/Resources/app/administration/src/main.js | 1 + .../component/sw-customer-base-info/index.js | 6 +--- .../sw-customer-base-info.twig | 2 +- .../sw-login-login/sw-login-login.html.twig | 4 +-- .../app/administration/src/snippet/de-DE.json | 5 --- .../app/administration/src/snippet/en-GB.json | 5 --- .../app/administration/src/snippet/fr-FR.json | 5 --- .../app/administration/src/snippet/nl-NL.json | 5 --- src/Resources/app/storefront/src/main.js | 4 +-- .../src/plugin/rl2fa-verification.plugin.js | 3 +- src/Resources/config/routes.xml | 2 +- .../page/account/profile/index.html.twig | 4 +-- src/Service/ConfigurationService.php | 21 +++++------ src/Subscriber/ApiOauthTokenSubscriber.php | 11 +++--- 24 files changed, 111 insertions(+), 123 deletions(-) delete mode 100644 composer-ci.json create mode 100644 src/Resources/app/administration/src/api/index.js create mode 100644 src/Resources/app/administration/src/api/rl-2fa.js diff --git a/composer-ci.json b/composer-ci.json deleted file mode 100644 index 86cab47..0000000 --- a/composer-ci.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "autoload": { - "psr-4": { - "RuneLaenen\\TwoFactorAuth\\": "src/" - } - }, - "require": { - "pragmarx/google2fa": "^8.0", - "bacon/bacon-qr-code": "^2.0" - } -} diff --git a/composer.json b/composer.json index b34918c..f7ccf2f 100644 --- a/composer.json +++ b/composer.json @@ -18,8 +18,7 @@ } }, "require": { - "php": "^8.1", - "shopware/core": "^6.5", + "shopware/core": "~6.6", "pragmarx/google2fa": "^8.0", "bacon/bacon-qr-code": "^2.0" }, diff --git a/src/Controller/QrCodeController.php b/src/Controller/QrCodeController.php index 3c0254e..8303068 100644 --- a/src/Controller/QrCodeController.php +++ b/src/Controller/QrCodeController.php @@ -10,16 +10,19 @@ use BaconQrCode\Writer; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Routing\Attribute\Route; class QrCodeController { - /** - * @Route("admin/rl-2fa/qr-code/secret.png", name="rl-2fa.qr-code.secret", methods={"GET"}, defaults={"auth_required"=false, "_routeScope"={"administration"}}) - */ + #[Route( + path: 'admin/rl-2fa/qr-code/secret.png', + name: 'rl-2fa.qr-code.secret', + defaults: ['auth_required' => false, '_routeScope' => ['administration']], + methods: ['GET']) + ] public function qrCode(Request $request): Response { - $qrUrl = $request->get('qrUrl', ''); + $qrUrl = $request->query->getString('qrUrl'); $renderer = new ImageRenderer( new RendererStyle(400), diff --git a/src/Controller/StorefrontTwoFactorAuthController.php b/src/Controller/StorefrontTwoFactorAuthController.php index 6143767..3032be0 100644 --- a/src/Controller/StorefrontTwoFactorAuthController.php +++ b/src/Controller/StorefrontTwoFactorAuthController.php @@ -15,11 +15,9 @@ use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Routing\Attribute\Route; -/** - * @Route(defaults={"_routeScope"={"storefront"}}) - */ +#[Route(defaults: ['_routeScope' => ['storefront']])] class StorefrontTwoFactorAuthController extends StorefrontController { public function __construct( @@ -29,9 +27,7 @@ public function __construct( ) { } - /** - * @Route("/rl-2fa/verification", name="frontend.rl2fa.verification", methods={"GET", "POST"}) - */ + #[Route(path: '/rl-2fa/verification', name: 'frontend.rl2fa.verification', methods: ['GET', 'POST'])] public function verification(Request $request, SalesChannelContext $context): Response { $twoFactorSecret = $context->getCustomer()?->getCustomFields()['rl_2fa_secret'] ?? null; @@ -58,9 +54,7 @@ public function verification(Request $request, SalesChannelContext $context): Re return $this->render('@RuneLaenenTwoFactorAuth/storefront/page/2fa/verification.html.twig'); } - /** - * @Route("/rl-2fa/verification/cancel", name="frontend.rl2fa.verification.cancel", methods={"GET"}) - */ + #[Route(path: '/rl-2fa/verification/cancel', name: 'frontend.rl2fa.verification.cancel', methods: ['GET'])] public function cancelVerification(SalesChannelContext $context, RequestDataBag $dataBag): RedirectResponse { if ($context->getCustomer() !== null) { diff --git a/src/Controller/TwoFactorAuthenticationApiController.php b/src/Controller/TwoFactorAuthenticationApiController.php index 62cd034..9bb5a9c 100644 --- a/src/Controller/TwoFactorAuthenticationApiController.php +++ b/src/Controller/TwoFactorAuthenticationApiController.php @@ -11,13 +11,11 @@ use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Routing\RouterInterface; -/** - * @Route(defaults={"_routeScope"={"api"}}) - */ +#[Route(path: '/api/_action/rl-2fa', defaults: ['_routeScope' => ['api']])] class TwoFactorAuthenticationApiController extends AbstractController { public function __construct( @@ -27,9 +25,7 @@ public function __construct( ) { } - /** - * @Route("/api/rl-2fa/generate-secret", name="api.action.rl-2fa.generate-secret", methods={"GET"}) - */ + #[Route(path: '/generate-secret', name: 'api.action.rl-2fa.generate-secret', methods: ['GET'])] public function generateSecret(Request $request): JsonResponse { $company = $this->configurationService->getAdministrationCompany( @@ -55,9 +51,7 @@ public function generateSecret(Request $request): JsonResponse ]); } - /** - * @Route("/api/rl-2fa/validate-secret", name="api.action.rl-2fa.validate-secret", methods={"POST"}) - */ + #[Route(path: '/validate-secret', name: 'api.action.rl-2fa.validate-secret', methods: ['POST'])] public function validateSecret(Request $request): JsonResponse { if (empty($request->get('secret')) || empty($request->get('code'))) { diff --git a/src/Controller/TwoFactorAuthenticationController.php b/src/Controller/TwoFactorAuthenticationController.php index 9392c09..b19e634 100644 --- a/src/Controller/TwoFactorAuthenticationController.php +++ b/src/Controller/TwoFactorAuthenticationController.php @@ -11,13 +11,11 @@ use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Routing\RouterInterface; -/** - * @Route(defaults={"_routeScope"={"storefront"}}) - */ +#[Route(defaults: ['_routeScope' => ['storefront']])] class TwoFactorAuthenticationController extends StorefrontController { public function __construct( @@ -29,14 +27,13 @@ public function __construct( ) { } - /** - * @Route("/rl-2fa/profile/setup", name="widgets.rl-2fa.profile.setup", methods={"GET"}, defaults={"XmlHttpRequest"=true})) - */ + #[Route(path: '/rl-2fa/profile/setup', name: 'widgets.rl-2fa.profile.setup', defaults: ['XmlHttpRequest' => true], methods: ['GET'])] public function profileSetup(SalesChannelContext $salesChannelContext): Response { - $salesChannelId = $salesChannelContext->getSalesChannel()->getId(); + $customer = $salesChannelContext->getCustomer(); + $salesChannelId = $salesChannelContext->getSalesChannelId(); - if (!$salesChannelContext->getCustomer() || !$this->configurationService->isStorefrontEnabled($salesChannelId)) { + if ($customer === null || !$this->configurationService->isStorefrontEnabled($salesChannelId)) { return new Response(); } @@ -48,7 +45,7 @@ public function profileSetup(SalesChannelContext $salesChannelContext): Response $qrUrl = $this->totpService->getQrCodeUrl( $company, - $salesChannelContext->getCustomer()->getFirstName() . ' ' . $salesChannelContext->getCustomer()->getLastName(), + $customer->getFirstName() . ' ' . $customer->getLastName(), $secret ); @@ -64,12 +61,10 @@ public function profileSetup(SalesChannelContext $salesChannelContext): Response ]); } - /** - * @Route("/rl-2fa/profile/disable", name="widgets.rl-2fa.profile.disable", methods={"GET"}, defaults={"XmlHttpRequest"=true})) - */ + #[Route(path: '/rl-2fa/profile/disable', name: 'widgets.rl-2fa.profile.disable', defaults: ['XmlHttpRequest' => true], methods: ['GET'])] public function profileDisable(SalesChannelContext $salesChannelContext): Response { - $salesChannelId = $salesChannelContext->getSalesChannel()->getId(); + $salesChannelId = $salesChannelContext->getSalesChannelId(); if (!$this->configurationService->isStorefrontEnabled($salesChannelId)) { return new Response(); @@ -78,12 +73,10 @@ public function profileDisable(SalesChannelContext $salesChannelContext): Respon return $this->renderStorefront('@Storefront/storefront/page/account/profile/2fa/disable.html.twig'); } - /** - * @Route("/rl-2fa/profile/disable", name="widgets.rl-2fa.profile.disable.post", methods={"POST"}, defaults={"XmlHttpRequest"=true})) - */ + #[Route(path: '/rl-2fa/profile/disable', name: 'widgets.rl-2fa.profile.disable.post', defaults: ['XmlHttpRequest' => true], methods: ['POST'])] public function profileDisablePost(Request $request, SalesChannelContext $salesChannelContext): Response { - if (!$this->configurationService->isStorefrontEnabled($salesChannelContext->getSalesChannel()->getId())) { + if (!$this->configurationService->isStorefrontEnabled($salesChannelContext->getSalesChannelId())) { $this->addFlash('danger', $this->trans('rl-2fa.account.error.not-enabled')); return $this->redirectToRoute('frontend.account.profile.page'); @@ -125,9 +118,7 @@ public function profileDisablePost(Request $request, SalesChannelContext $salesC return $this->redirectToRoute('frontend.account.profile.page'); } - /** - * @Route("/rl-2fa/profile/validate", name="widgets.rl-2fa.profile.validate", methods={"POST"}, defaults={"XmlHttpRequest"=true})) - */ + #[Route(path: '/rl-2fa/profile/validate', name: 'widgets.rl-2fa.profile.validate', methods: ['POST'], defaults: ['XmlHttpRequest' => true])] public function validateSecret(Request $request, SalesChannelContext $salesChannelContext): Response { if (!$this->configurationService->isStorefrontEnabled($salesChannelContext->getSalesChannel()->getId())) { diff --git a/src/Resources/app/administration/src/api/index.js b/src/Resources/app/administration/src/api/index.js new file mode 100644 index 0000000..a4598b2 --- /dev/null +++ b/src/Resources/app/administration/src/api/index.js @@ -0,0 +1,8 @@ +import Rl2faService from "./rl-2fa"; +const { Application } = Shopware; + +Application.addServiceProvider('rl2faService', (container) => { + const initContainer = Application.getContainer('init'); + + return new Rl2faService(initContainer.httpClient, container.loginService); +}); \ No newline at end of file diff --git a/src/Resources/app/administration/src/api/rl-2fa.js b/src/Resources/app/administration/src/api/rl-2fa.js new file mode 100644 index 0000000..1ed7b90 --- /dev/null +++ b/src/Resources/app/administration/src/api/rl-2fa.js @@ -0,0 +1,36 @@ +const { ApiService } = Shopware.Classes; + +export default class Rl2fa extends ApiService { + constructor(httpClient, loginService, apiEndpoint = '_action/rl-2fa') { + super(httpClient, loginService, apiEndpoint); + } + + getSecret(holder) { + const apiRoute = `${this.getApiBasePath()}/generate-secret`; + return this.httpClient.get( + apiRoute, + { + params: { holder }, + headers: this.getBasicHeaders() + } + ).then((response) => { + return ApiService.handleResponse(response); + }); + } + + validateSecret(secret, code) { + const apiRoute = `${this.getApiBasePath()}/validate-secret`; + return this.httpClient.post( + apiRoute, + { + secret, + code, + }, + { + headers: this.getBasicHeaders() + } + ).then((response) => { + return ApiService.handleResponse(response); + }); + } +}; \ No newline at end of file diff --git a/src/Resources/app/administration/src/component/rl-user-otp/index.js b/src/Resources/app/administration/src/component/rl-user-otp/index.js index 38b84f7..543ba4d 100644 --- a/src/Resources/app/administration/src/component/rl-user-otp/index.js +++ b/src/Resources/app/administration/src/component/rl-user-otp/index.js @@ -1,5 +1,6 @@ import template from './rl-user-otp.html.twig'; import './rl-user-otp.scss'; +import Rl2faService from "../../api/rl-2fa"; const {Component} = Shopware; @@ -10,6 +11,8 @@ const {Component} = Shopware; Component.register('rl-user-otp', { template, + inject: ['rl2faService'], + props: { user: { type: Object, @@ -44,25 +47,20 @@ Component.register('rl-user-otp', { methods: { generateSecret() { this.isLoading2Fa = true; - this.httpClient.get('rl-2fa/generate-secret', { - params: { - holder: this.user.username, - }, - }).then((response) => { + + this.rl2faService.getSecret(this.user.username).then((response) => { this.isLoading2Fa = false; - this.generatedSecret = response.data.secret; - this.generatedSecretUrl = response.data.qrUrl; + this.generatedSecret = response.secret; + this.generatedSecretUrl = response.qrUrl; }); }, validateAndSaveOneTimePassword() { this.isLoading2Fa = true; - this.httpClient.post('rl-2fa/validate-secret', { - secret: this.generatedSecret, - code: this.oneTimePassword, - }).then((response) => { + + this.rl2faService.validateSecret(this.generatedSecret, this.oneTimePassword).then((response) => { this.isLoading2Fa = false; - if (response.data.status === 'OK') { + if (response.status === 'OK') { this.saveOneTimePassword(); } }).catch((error) => { diff --git a/src/Resources/app/administration/src/component/rl-user-otp/rl-user-otp.html.twig b/src/Resources/app/administration/src/component/rl-user-otp/rl-user-otp.html.twig index 1faa76c..0c56760 100644 --- a/src/Resources/app/administration/src/component/rl-user-otp/rl-user-otp.html.twig +++ b/src/Resources/app/administration/src/component/rl-user-otp/rl-user-otp.html.twig @@ -48,7 +48,7 @@ diff --git a/src/Resources/app/administration/src/main.js b/src/Resources/app/administration/src/main.js index 99e6685..7d988ed 100644 --- a/src/Resources/app/administration/src/main.js +++ b/src/Resources/app/administration/src/main.js @@ -1,6 +1,7 @@ import enGB from './snippet/en-GB.json'; import nlNL from './snippet/nl-NL.json'; +import './api/index'; import './component/rl-user-otp'; import './override/sw-login/view/sw-login-login'; import './override/sw-profile/page/sw-profile-index'; diff --git a/src/Resources/app/administration/src/override/sw-customer/component/sw-customer-base-info/index.js b/src/Resources/app/administration/src/override/sw-customer/component/sw-customer-base-info/index.js index 2aac17b..8c94a6c 100644 --- a/src/Resources/app/administration/src/override/sw-customer/component/sw-customer-base-info/index.js +++ b/src/Resources/app/administration/src/override/sw-customer/component/sw-customer-base-info/index.js @@ -8,11 +8,7 @@ if (Component.getComponentRegistry().has('sw-customer-base-info')) { computed: { twoFactorAuthenticationActive() { - if (!this.customer.customFields) { - return false; - } - - if (this.customer.customFields.rl_2fa_secret) { + if (this.customer.customFields?.rl_2fa_secret) { return true; } diff --git a/src/Resources/app/administration/src/override/sw-customer/component/sw-customer-base-info/sw-customer-base-info.twig b/src/Resources/app/administration/src/override/sw-customer/component/sw-customer-base-info/sw-customer-base-info.twig index 7339b8e..f5444ed 100644 --- a/src/Resources/app/administration/src/override/sw-customer/component/sw-customer-base-info/sw-customer-base-info.twig +++ b/src/Resources/app/administration/src/override/sw-customer/component/sw-customer-base-info/sw-customer-base-info.twig @@ -8,7 +8,7 @@ {% block sw_customer_base_metadata_2fa_content %}
- {{ $tc('sw-customer.baseInfo.contentActive', twoFactorAuthenticationActive) }} + {{ $tc('sw-customer.baseInfo.contentActive', twoFactorAuthenticationActive ? 1 : 2) }}
{% endblock %} diff --git a/src/Resources/app/administration/src/override/sw-login/view/sw-login-login/sw-login-login.html.twig b/src/Resources/app/administration/src/override/sw-login/view/sw-login-login/sw-login-login.html.twig index fc53802..2d80494 100644 --- a/src/Resources/app/administration/src/override/sw-login/view/sw-login-login/sw-login-login.html.twig +++ b/src/Resources/app/administration/src/override/sw-login/view/sw-login-login/sw-login-login.html.twig @@ -9,8 +9,8 @@ diff --git a/src/Resources/app/administration/src/snippet/de-DE.json b/src/Resources/app/administration/src/snippet/de-DE.json index 39a5b4b..dcb7d2f 100644 --- a/src/Resources/app/administration/src/snippet/de-DE.json +++ b/src/Resources/app/administration/src/snippet/de-DE.json @@ -1,10 +1,5 @@ { "rl-2fa": { - "sw-login": { - "index": { - "labelOtp": "2FA-Token" - } - }, "settings": { "user-detail": { "title": "Zwei-Faktor-Authentifizierung", diff --git a/src/Resources/app/administration/src/snippet/en-GB.json b/src/Resources/app/administration/src/snippet/en-GB.json index 7313132..f6c9d70 100644 --- a/src/Resources/app/administration/src/snippet/en-GB.json +++ b/src/Resources/app/administration/src/snippet/en-GB.json @@ -1,10 +1,5 @@ { "rl-2fa": { - "sw-login": { - "index": { - "labelOtp": "2FA Token" - } - }, "settings": { "user-detail": { "title": "Two factor authentication", diff --git a/src/Resources/app/administration/src/snippet/fr-FR.json b/src/Resources/app/administration/src/snippet/fr-FR.json index e42e094..c8b6556 100644 --- a/src/Resources/app/administration/src/snippet/fr-FR.json +++ b/src/Resources/app/administration/src/snippet/fr-FR.json @@ -1,10 +1,5 @@ { "rl-2fa": { - "sw-login": { - "index": { - "labelOtp": "Jeton 2FA" - } - }, "settings": { "user-detail": { "title": "Authentification à deux facteurs (2FA)", diff --git a/src/Resources/app/administration/src/snippet/nl-NL.json b/src/Resources/app/administration/src/snippet/nl-NL.json index 79f56ef..c327415 100644 --- a/src/Resources/app/administration/src/snippet/nl-NL.json +++ b/src/Resources/app/administration/src/snippet/nl-NL.json @@ -1,10 +1,5 @@ { "rl-2fa": { - "sw-login": { - "index": { - "labelOtp": "2FA Token" - } - }, "settings": { "user-detail": { "title": "Twee-factorauthenticatie", diff --git a/src/Resources/app/storefront/src/main.js b/src/Resources/app/storefront/src/main.js index eb25dbf..6ca9ffa 100644 --- a/src/Resources/app/storefront/src/main.js +++ b/src/Resources/app/storefront/src/main.js @@ -1,3 +1 @@ -import Rl2faVerificationPlugin from './plugin/rl2fa-verification.plugin'; - -window.PluginManager.register('Rl2faVerificationPlugin', Rl2faVerificationPlugin, '[data-rl2fa-verification-plugin]'); +window.PluginManager.register('Rl2faVerificationPlugin', () => import('./plugin/rl2fa-verification.plugin'), '[data-rl2fa-verification-plugin]'); diff --git a/src/Resources/app/storefront/src/plugin/rl2fa-verification.plugin.js b/src/Resources/app/storefront/src/plugin/rl2fa-verification.plugin.js index eff1726..5fc02e8 100644 --- a/src/Resources/app/storefront/src/plugin/rl2fa-verification.plugin.js +++ b/src/Resources/app/storefront/src/plugin/rl2fa-verification.plugin.js @@ -1,9 +1,8 @@ -import Plugin from 'src/plugin-system/plugin.class'; import DomAccess from 'src/helper/dom-access.helper'; import HttpClient from 'src/service/http-client.service'; import ElementLoadingIndicatorUtil from 'src/utility/loading-indicator/element-loading-indicator.util'; -export default class Rl2faVerificationPlugin extends Plugin { +export default class Rl2faVerificationPlugin extends window.PluginBaseClass { static options = { /** Selector for the submit button of the verification step */ buttonSelector: '.account-profile-2fa-setup-verify', diff --git a/src/Resources/config/routes.xml b/src/Resources/config/routes.xml index 400db73..b79d6e2 100644 --- a/src/Resources/config/routes.xml +++ b/src/Resources/config/routes.xml @@ -5,5 +5,5 @@ xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd"> - + diff --git a/src/Resources/views/storefront/page/account/profile/index.html.twig b/src/Resources/views/storefront/page/account/profile/index.html.twig index fd6a37f..1a8c99a 100644 --- a/src/Resources/views/storefront/page/account/profile/index.html.twig +++ b/src/Resources/views/storefront/page/account/profile/index.html.twig @@ -22,7 +22,7 @@

{{ "rl-2fa.account.description"|trans|sw_sanitize }}