<?php
namespace App\Controller\Api;
use App\Entity\Gos\PortalSettings;
use App\Entity\Gos\User;
use App\Utils\Api\ApiRegistrationService;
use App\Utils\OrderFreeAccessService;
use App\Utils\PasswordResetService;
use App\Utils\RegistrationUtils;
use App\Utils\UserServices;
use Doctrine\ORM\EntityManagerInterface;
use FOS\UserBundle\Model\UserManagerInterface;
use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\Routing\Annotation\Route;
use OpenApi\Annotations as OA;
/** @Route("/apiv2") */
class SecurityController extends AbstractController
{
use JsonNotSerializedTrait;
private $em;
private $userServices;
private $registrationUtils;
public function __construct(
EntityManagerInterface $em,
UserServices $userServices,
RegistrationUtils $registrationUtils
) {
$this->em = $em;
$this->userServices = $userServices;
$this->registrationUtils = $registrationUtils;
}
/**
* @Route("/facebook_login")
*/
public function facebookLogin(Request $request, UserManagerInterface $userManager, JWTTokenManagerInterface $JWTTokenManager)
{
$token = $request->get('access_token');
$tokenResponse = @file_get_contents("https://graph.facebook.com/app/?access_token=${token}");
if (!$tokenResponse)
{
throw new AccessDeniedHttpException();
}
$tokenApp = json_decode($tokenResponse, true);
if (!isset($tokenApp['id']) || $tokenApp['id'] !== $_ENV['FB_ID'])
{
throw new AccessDeniedHttpException();
}
$userTokenResponse = @file_get_contents("https://graph.facebook.com/me/?access_token=${token}&fields=email,first_name,last_name");
if (!$userTokenResponse)
{
throw new AccessDeniedHttpException();
}
$userToken = json_decode($userTokenResponse, true);
if (!isset($userToken['id']) || !isset($userToken['email']))
{
throw new AccessDeniedHttpException();
}
$user = $userManager->findUserBy(['facebook_id' => $userToken['id']]);
if ($user === null)
{
$user = $userManager->findUserByEmail($userToken['email']);
}
if ($user === null)
{
/** @var User $user */
$user = $userManager->createUser();
$user->setUsername($userToken['email']);
$user->setUsernameCanonical($userToken['email']);
$user->setEmail($userToken['email']);
$user->setEmailCanonical($userToken['email']);
if (isset($userToken['first_name']))
{
$user->setFirstName($userToken['first_name']);
}
if (isset($userToken['last_name']))
{
$user->setLastName($userToken['last_name']);
}
$user->setEnabled(true);
$user->setPlainPassword(random_bytes(8));
if ($request->get('hash'))
{
$portal = $this->em->getRepository(PortalSettings::class)->findOneByHash($request->get('hash'));
$user->setRegisteredFrom($portal);
}
}
$user->setFacebookId($userToken['id']);
$user->setFacebookAccessToken($token);
$userManager->updateUser($user);
$this->registrationUtils->createLeadFormCompleted($user, $portal ?? null, $request, null);
$token = $JWTTokenManager->create($user);
return $this->json(['token' => $token]);
}
/**
* @Route("/google_login")
*/
public function googleLogin(Request $request, UserManagerInterface $userManager, JWTTokenManagerInterface $JWTTokenManager)
{
$token = $request->get('id_token');
$client = new \Google_Client(['client_id' => $_ENV['GOOGLE_ID']]);
$client->addScope('email');
$payload = $client->verifyIdToken($token);
if (!$payload)
{
throw new AccessDeniedHttpException();
}
$user = $userManager->findUserBy(['google_id' => $payload['sub']]);
if ($user === null)
{
$user = $userManager->findUserByEmail($payload['email']);
}
if ($user === null)
{
/** @var User $user */
$user = $userManager->createUser();
$user->setUsername($payload['email']);
$user->setUsernameCanonical($payload['email']);
$user->setEmail($payload['email']);
$user->setEmailCanonical($payload['email']);
if (isset($payload['given_name']))
{
$user->setFirstName($payload['given_name']);
}
if (isset($payload['family_name']))
{
$user->setLastName($payload['family_name']);
}
$user->setEnabled(true);
$user->setPlainPassword(random_bytes(8));
if ($request->get('hash'))
{
$portal = $this->em->getRepository(PortalSettings::class)->findOneByHash($request->get('hash'));
$user->setRegisteredFrom($portal);
}
}
$accessToken = $client->getAccessToken();
$user->setGoogleId($payload['sub']);
$user->setGoogleAccessToken($accessToken['access_token'] ?? '');
$userManager->updateUser($user);
$this->registrationUtils->createLeadFormCompleted($user, $portal ?? null, $request, null);
$token = $JWTTokenManager->create($user);
return $this->json(['token' => $token]);
}
/**
* @Route("/otp_login")
*/
public function otpLogin(Request $request, UserManagerInterface $userManager, JWTTokenManagerInterface $JWTTokenManager): JsonResponse
{
$otpCode = $request->get('code');
$user = $userManager->findUserByEmail($request->get('email'));
if ($user instanceof User && $user->getOtpLoginCode() === $otpCode
&& $user->getOtpLoginCreatedAt() instanceof \DateTime && (strtotime((new \DateTime())->format('Y-m-d H:i:s'))
- strtotime($user->getOtpLoginCreatedAt()->format('Y-m-d H:i:s'))) / 60 < 60)
{
$token = $JWTTokenManager->create($user);
$user->setOtpLoginCode(null);
$user->setOtpLoginCreatedAt(null);
$user->setOtpLoginToken(null);
$userManager->updateUser($user);
return $this->json(['token' => $token]);
}
return $this->json(false);
}
/**
* @Route("/register", name="newApiRegister", methods={"POST"})
*
* @OA\Tag(name="Security")
* @OA\Post(summary="Register new user")
*
* @OA\RequestBody(
* required=true,
* @OA\JsonContent(
* required={"email", "hash", "firstName", "country"},
* @OA\Property(property="email", type="string"),
* @OA\Property(property="password", type="string"),
* @OA\Property(property="hash", type="string", description="Hash portalu"),
* @OA\Property(property="firstName", type="string"),
* @OA\Property(property="lastName", type="string"),
* @OA\Property(property="phoneNumber", type="string"),
* @OA\Property(property="position", type="string"),
* @OA\Property(property="npwz", type="string"),
* @OA\Property(property="language", type="string"),
* @OA\Property(property="lead", type="int", description="Id leada, odpowiedzialny np. za wysłanie OTP"),
* @OA\Property(property="country", type="integer", default="153", description="Id kraju"),
* ),
* )
*
* @OA\Response(
* response=201,
* description="Success",
* @OA\JsonContent(
* required={"token"},
* @OA\Property(property="otpToken", type="string", description="Jeśli rejestracja z OTP"),
* @OA\Property(property="token", type="string", description="JSON Web Token, patrz lexik/jwt-authentication-bundle"),
* )
* )
*
* @OA\Response(
* response=403,
* description="Error",
* @OA\JsonContent(
* required={"status", "errors"},
* @OA\Property(property="status", type="string", default="error"),
* @OA\Property(property="errors", type="object"),
* )
* )
*
* Accepts fields from RegistrationType form
* Returns json status
*/
public function register(ApiRegistrationService $apiRegistrationService, Request $request)
{
$data = $request->request->all();
$portal = $this->em->getRepository(PortalSettings::class)->findOneByHash($data['hash']);
return $this->json(...$apiRegistrationService->register($data, $portal));
}
/**
* @Route("/resend-registration-email", name="resendRegistrationEmail", methods={"POST"})
*
* Accepts ['email'] - user email
* Accepts ['hash'] - portal settings hash
* Returns json status
*/
public function resendRegistrationEmail(Request $request, UserManagerInterface $userManager): Response
{
$user = $userManager->findUserByEmail($request->get('email'));
$portal = $this->em->getRepository(PortalSettings::class)->findOneByHash($request->get('hash'));
if (!$user instanceof User || !$portal instanceof PortalSettings)
{
return $this->json([
'status' => 'error',
'message' => 'User found: ' . var_export($user instanceof User) . '. Portal found: ' . var_export($portal instanceof PortalSettings),
]);
}
$this->userServices->sendRegisterConfirmationMail($portal, $user);
return $this->json(['status' => 'success']);
}
/**
* @Route("/forgot-password", name="newApiForgotPassword", methods={"POST"})
*
* @OA\Tag(name="Security")
* @OA\Post(summary="Send email to change password")
*
* @OA\RequestBody(
* required=true,
* @OA\JsonContent(
* required={"hash", "username"},
* @OA\Property(property="hash", type="string", description="Hash portalu"),
* @OA\Property(property="username", type="string", description="Email"),
* @OA\Property(property="sendActivationMail", type="boolean", description="Wysyła maila z potwierdzeniem rejestracji", default="false"),
* ),
* )
*
* @OA\Response(
* response=200,
* description="Success",
* @OA\JsonContent(
* @OA\Property(property="success", type="string", default="ok"),
* )
* )
*
* @OA\Response(
* response=403,
* description="Error",
* @OA\JsonContent(
* @OA\Property(property="error", type="string", default="Nieprawidłowy token"),
* )
* )
*
* Accepts ['username'] - user email
* Accepts ['hash'] - portal settings hash
* Returns json status
*/
public function forgotPassword(Request $request, PasswordResetService $passwordReset)
{
$request->getSession()->set('portalSettingsHash', $request->request->get('hash'));
try
{
$username = $request->request->get('username');
$sendActivationMail = $request->request->getBoolean('sendActivationMail');
$locale = $request->request->get('language');
$portalHash = $request->request->get('hash');
return $this->json($passwordReset->confirm(
$username,
$sendActivationMail,
$locale,
$portalHash
));
}
catch (\Exception $e)
{
return $this->json(['error' => $e->getMessage()]);
}
}
/**
* @Route("/reset-password", name="newApiResetPassword", methods={"POST"})
*
* @OA\Tag(name="Security")
* @OA\Post(summary="Reset password")
*
* @OA\RequestBody(
* required=true,
* @OA\JsonContent(
* required={"token", "new"},
* @OA\Property(property="token", type="string", description="Confirmation token (z prośby o zmiane hasła lub walidacji OTP)"),
* @OA\Property(property="new", type="string", description="Nowe hasło"),
* @OA\Property(property="current", type="string", description="Aktualne hasło"),
* ),
* )
*
* @OA\Response(
* response=200,
* description="Success",
* @OA\JsonContent(
* @OA\Property(property="success", type="string", default="ok"),
* )
* )
*
* @OA\Response(
* response=403,
* description="Error",
* @OA\JsonContent(
* @OA\Property(property="error", type="string", default="Nieprawidłowy token"),
* )
* )
*
* Accepts ['current'] - current password
* Accepts ['new'] - new password
* Accepts ['token'] - user resetting token
* Returns json status
*/
public function resetPassword(PasswordResetService $passwordReset): JsonResponse
{
return $this->json($passwordReset->reset());
}
/**
* @Route("/validate-otp-code", name="newApiValidateOtpCode", methods={"POST"})
*
* @OA\Tag(name="Security")
* @OA\Post(summary="Validate otp code")
*
* @OA\RequestBody(
* required=true,
* @OA\JsonContent(
* required={"email", "hash", "otpToken", "otpCode", "lead"},
* @OA\Property(property="hash", type="string"),
* @OA\Property(property="email", type="string"),
* @OA\Property(property="otpToken", type="string", description="Hash portalu"),
* @OA\Property(property="otpCode", type="string"),
* @OA\Property(property="lead", type="string"),
* ),
* )
*
* @OA\Response(
* response=200,
* description="Success",
* @OA\JsonContent(
* required={"token"},
* @OA\Property(property="status", type="string", description="Jeśli rejestracja z OTP"),
* @OA\Property(property="success", type="boolean"),
* @OA\Property(property="confirmationToken", type="string", description="Dla resetowania hasła"),
* )
* )
*
* @OA\Response(
* response=403,
* description="Error",
* @OA\JsonContent(
* required={"success", "errors"},
* @OA\Property(property="success", type="boolean", default="false"),
* @OA\Property(property="errors", type="string"),
* )
* )
* Accepts ['email'] - user email
* Accepts ['otpToken'] - user otp token
* Accepts ['otpCode'] - user otp code
* Returns json status
*/
public function validateOtpCode(
Request $request
): Response {
$request->getSession()->set('portalSettingsHash', $request->request->get('hash'));
$data = $request->request->all();
return $this->forward('App\Controller\Frontend\OneTimePasswordController::activate', $data);
}
/**
* @Route("/resend-otp-code", name="newApiResendOtpCode")
* @Method("POST")
*
* Accepts ['hash'] - portal hash
* Accepts ['email'] - user email
* Accepts ['token'] - user otp token
* Accepts ['templateType'] - leadTemplate
* Accepts ['templateId'] - gosLeadId
* Returns json status
*/
public function resendOtpCode(Request $request): Response
{
$request->getSession()->set('portalSettingsHash', $request->request->get('hash'));
$data = $request->request->all();
$response = $this->forward('App\Controller\Frontend\OneTimePasswordController::sendEmailWithCode', $data);
return $response;
}
/**
* @Route("/send-otp-code-by-sms", name="newApiSendOtpCodeBySMS")
* @Method("POST")
*
* Accepts ['hash'] - portal hash
* Accepts ['email'] - user email
* Accepts ['token'] - user otp token
* Returns json status
*/
public function sendOtpCodeBySms(Request $request): Response
{
$request->getSession()->set('portalSettingsHash', $request->request->get('hash'));
$data = $request->request->all();
$response = $this->forward('App\Controller\Frontend\OneTimePasswordController::sendSMSWithCode', $data);
return $response;
}
/**
* @Route("/autologin", name="autologin", methods={"POST"})
*/
public function autologin(): Response
{
return new Response(null);
}
}