Skip to content

Commit

Permalink
feat: support shopware 6.6
Browse files Browse the repository at this point in the history
  • Loading branch information
tinect committed Apr 8, 2024
1 parent 26c0ea3 commit 3f9191f
Show file tree
Hide file tree
Showing 24 changed files with 111 additions and 123 deletions.
11 changes: 0 additions & 11 deletions composer-ci.json

This file was deleted.

3 changes: 1 addition & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
},
Expand Down
13 changes: 8 additions & 5 deletions src/Controller/QrCodeController.php
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
14 changes: 4 additions & 10 deletions src/Controller/StorefrontTwoFactorAuthController.php
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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;
Expand All @@ -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) {
Expand Down
14 changes: 4 additions & 10 deletions src/Controller/TwoFactorAuthenticationApiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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(
Expand All @@ -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'))) {
Expand Down
33 changes: 12 additions & 21 deletions src/Controller/TwoFactorAuthenticationController.php
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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();
}

Expand All @@ -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
);

Expand All @@ -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();
Expand All @@ -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');
Expand Down Expand Up @@ -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())) {
Expand Down
8 changes: 8 additions & 0 deletions src/Resources/app/administration/src/api/index.js
Original file line number Diff line number Diff line change
@@ -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);
});
36 changes: 36 additions & 0 deletions src/Resources/app/administration/src/api/rl-2fa.js
Original file line number Diff line number Diff line change
@@ -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);
});
}
};
22 changes: 10 additions & 12 deletions src/Resources/app/administration/src/component/rl-user-otp/index.js
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -10,6 +11,8 @@ const {Component} = Shopware;
Component.register('rl-user-otp', {
template,

inject: ['rl2faService'],

props: {
user: {
type: Object,
Expand Down Expand Up @@ -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) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@

<sw-text-field label="One-time Password"
:isInvalid="oneTimePasswordError.length > 0"
v-model="oneTimePassword"
v-model:value="oneTimePassword"
autocomplete="one-time-code"></sw-text-field>

<sw-button @click="validateAndSaveOneTimePassword">
Expand Down
1 change: 1 addition & 0 deletions src/Resources/app/administration/src/main.js
Original file line number Diff line number Diff line change
@@ -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';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

{% block sw_customer_base_metadata_2fa_content %}
<dd v-if="!customerEditMode || !twoFactorAuthenticationActive" class="sw-customer-base__label-is-active">
{{ $tc('sw-customer.baseInfo.contentActive', twoFactorAuthenticationActive) }}
{{ $tc('sw-customer.baseInfo.contentActive', twoFactorAuthenticationActive ? 1 : 2) }}
</dd>
{% endblock %}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@

<sw-text-field
v-autofocus
v-model="otp"
:label="$tc('rl-2fa.sw-login.index.labelOtp')"
v-model:value="otp"
label="One-time password"
required>
</sw-text-field>

Expand Down
5 changes: 0 additions & 5 deletions src/Resources/app/administration/src/snippet/de-DE.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
{
"rl-2fa": {
"sw-login": {
"index": {
"labelOtp": "2FA-Token"
}
},
"settings": {
"user-detail": {
"title": "Zwei-Faktor-Authentifizierung",
Expand Down
5 changes: 0 additions & 5 deletions src/Resources/app/administration/src/snippet/en-GB.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
{
"rl-2fa": {
"sw-login": {
"index": {
"labelOtp": "2FA Token"
}
},
"settings": {
"user-detail": {
"title": "Two factor authentication",
Expand Down
5 changes: 0 additions & 5 deletions src/Resources/app/administration/src/snippet/fr-FR.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
{
"rl-2fa": {
"sw-login": {
"index": {
"labelOtp": "Jeton 2FA"
}
},
"settings": {
"user-detail": {
"title": "Authentification à deux facteurs (2FA)",
Expand Down
5 changes: 0 additions & 5 deletions src/Resources/app/administration/src/snippet/nl-NL.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
{
"rl-2fa": {
"sw-login": {
"index": {
"labelOtp": "2FA Token"
}
},
"settings": {
"user-detail": {
"title": "Twee-factorauthenticatie",
Expand Down
Loading

0 comments on commit 3f9191f

Please sign in to comment.