<?php
namespace App\Service\Authorization;
use App\Dto\Authorization\AuthorizationHeaderDto;
use App\Entity\Space;
use App\Exception\Authorization\MybizApplicationVersionNotSupportedException;
use App\Exception\Authorization\MybizAuthorizationException;
use App\Exception\Maintenance\MaintenanceException;
use App\Repository\ApplicationRepository;
use App\Repository\ApplicationVersionRepository;
use App\Repository\SpaceRepository;
use App\Service\Lock\MaintenanceLocker;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Contracts\Translation\TranslatorInterface;
class MybizRequestAuthorizationChecker
{
private ParameterBagInterface $parameter;
private TranslatorInterface $translator;
private ApplicationRepository $applicationRepository;
private ApplicationVersionRepository $applicationVersionRepository;
private SpaceRepository $spaceRepository;
private MaintenanceLocker $maintenanceLocker;
public function __construct(
ParameterBagInterface $parameter,
TranslatorInterface $translator,
ApplicationRepository $applicationRepository,
ApplicationVersionRepository $applicationVersionRepository,
SpaceRepository $spaceRepository,
MaintenanceLocker $maintenanceLocker
)
{
$this->maintenanceLocker = $maintenanceLocker;
$this->parameter = $parameter;
$this->translator = $translator;
$this->applicationRepository = $applicationRepository;
$this->applicationVersionRepository = $applicationVersionRepository;
$this->spaceRepository = $spaceRepository;
}
/**
* @param Request $request
* @return void
* @throws MybizApplicationVersionNotSupportedException
* @throws MybizAuthorizationException
*/
public function checkAuthorization(
Request $request
): void
{
$this->checkHeaderValidity(AuthorizationHeaderDto::generateFromRequest($request));
}
/**
* @param AuthorizationHeaderDto $authorizationHeaderDto
* @throws MybizApplicationVersionNotSupportedException
* @throws MybizAuthorizationException
*/
public function checkHeaderValidity(
AuthorizationHeaderDto $authorizationHeaderDto
): void
{
if ($this->maintenanceLocker->isLocked()) {
throw new MaintenanceException($this->translator->trans("authorization.maintenance", [], "authorization", $authorizationHeaderDto->getLanguage()));
}
$space = $this->spaceRepository->findOneBy([
"name" => $authorizationHeaderDto->getName()
]);
if (null === $space) {
throw new MybizAuthorizationException($this->translator->trans("authorization.space.not_found", [], "authorization", $authorizationHeaderDto->getLanguage()));
}
if (false === $space->isEnabled()) {
throw new MybizAuthorizationException($this->translator->trans("authorization.space.inactive", [], "authorization", $authorizationHeaderDto->getLanguage()));
}
// On va checker les versions (uniquement sur la partie mobile)
try{
$this->checkMobileApplicationVersion(
$space,
$authorizationHeaderDto
);
}catch (\Throwable $e){
throw new MybizAuthorizationException($e->getMessage());
}
if (true === $this->parameter->get("app_mybiz_api_check_bearer")) {
$calculatedBearer = AuthorizationHashedStringProvider::getAuthorizationHashedString($space->getToken(), $authorizationHeaderDto);
if ($calculatedBearer !== $authorizationHeaderDto->getToken()) {
throw new MybizAuthorizationException($this->translator->trans("authorization.token_invalid", [], "authorization", $authorizationHeaderDto->getLanguage()));
}
}
}
/**
* @param Space $space
* @param AuthorizationHeaderDto $authorizationHeaderDto
* @return void
*/
private function checkMobileApplicationVersion(
Space $space,
AuthorizationHeaderDto $authorizationHeaderDto
): void
{
// Si le provider contient "web" alors on ne check pas la version
if (str_contains($authorizationHeaderDto->getProvider(), "web")) {
return;
}
$application = $this->applicationRepository->findOneBy([
"space" => $space,
"name" => $authorizationHeaderDto->getProvider()
]);
if (null === $application) {
throw new MybizAuthorizationException($this->translator->trans("authorization.application.not_found", [], "authorization", $authorizationHeaderDto->getLanguage()));
}
if (false === $application->isEnabled()) {
throw new MybizAuthorizationException($this->translator->trans("authorization.application.inactive", [], "authorization", $authorizationHeaderDto->getLanguage()));
}
$applicationVersion = $this->applicationVersionRepository->findOneBy([
"application" => $application,
"versionNumber" => $authorizationHeaderDto->getVersionNumber()
]);
if (null === $applicationVersion) {
throw new MybizAuthorizationException($this->translator->trans("authorization.application_version.not_found", [], "authorization", $authorizationHeaderDto->getLanguage()));
}
if (false === $applicationVersion->isEnabled()) {
throw new MybizApplicationVersionNotSupportedException($this->translator->trans("authorization.application_version.inactive", [], "authorization", $authorizationHeaderDto->getLanguage()));
}
}
/**
* @param \Throwable $e
* @return JsonResponse
*/
public function getDefaultErrorMessage(\Throwable $e): JsonResponse
{
return new JsonResponse([
"exception" => $e->getMessage(),
"error" => $this->translator->trans("authorization.generic_error", [], "authorization") // Par défaut en anglais
], Response::HTTP_FORBIDDEN);
}
/**
* @return JsonResponse
*/
public function getUnknownJWTErrorMessage(): JsonResponse
{
return new JsonResponse([
"error" => $this->translator->trans("authorization.jwt_error", [], "authorization") // Par défaut en anglais
], Response::HTTP_UNAUTHORIZED);
}
/**
* @param \Throwable $e
* @return JsonResponse
*/
public function getParseErrorMessage(\Throwable $e): JsonResponse
{
return new JsonResponse([
"exception" => $e->getMessage(),
"error" => $this->translator->trans("authorization.generic_parse_error", [], "authorization") // Par défaut en anglais
], Response::HTTP_FORBIDDEN);
}
}