src/Controller/ApiClientController.php line 389

  1. <?php
  2. namespace App\Controller;
  3. use App\AppHelper\Helper;
  4. use App\AppHelper\Settings;
  5. use App\Entity\Fonts;
  6. use App\Entity\Licences;
  7. use App\Entity\OAuth2UserConsent;
  8. use App\Entity\Product;
  9. use App\Entity\ProductLicense;
  10. use App\Entity\SystemSettings;
  11. use App\Entity\User;
  12. use App\Products\FlxZip;
  13. use DateTimeImmutable;
  14. use Doctrine\ORM\EntityManagerInterface;
  15. use Doctrine\ORM\Query\Expr\Join;
  16. use Exception;
  17. use Firebase\JWT\JWK;
  18. use Firebase\JWT\JWT;
  19. use League\Bundle\OAuth2ServerBundle\Model\Client;
  20. use League\Bundle\OAuth2ServerBundle\Model\Client as clientModel;
  21. use League\OAuth2\Server\AuthorizationServer;
  22. use League\OAuth2\Server\Exception\OAuthServerException;
  23. use Psr\Http\Message\ServerRequestInterface;
  24. use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
  25. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  26. use Symfony\Component\HttpFoundation\BinaryFileResponse;
  27. use Symfony\Component\HttpFoundation\JsonResponse;
  28. use Symfony\Component\HttpFoundation\RedirectResponse;
  29. use Symfony\Component\HttpFoundation\Response;
  30. use Symfony\Component\HttpFoundation\ResponseHeaderBag;
  31. use Symfony\Component\Routing\Annotation\Route;
  32. use Symfony\Component\Security\Core\User\UserInterface;
  33. use Symfony\Component\HttpFoundation\Request;
  34. use Symfony\Component\Serializer\SerializerInterface;
  35. use ZipArchive;
  36. class ApiClientController extends AbstractController
  37. {
  38.     use Settings;
  39.     public function __construct(
  40.         private readonly EntityManagerInterface $em,
  41.         private readonly SerializerInterface    $serializer
  42.     )
  43.     {
  44.     }
  45.     #[Route('/api/license/{license}'name'app_get_license_by_id')]
  46.     public function apiGetLicenseById(Request $request): JsonResponse
  47.     {
  48.         $license $request->get('license');
  49.         $referer $request->headers->get('X-Origin-URL');
  50.         $query $this->em->createQueryBuilder()
  51.             ->from(ProductLicense::class, 'l')
  52.             ->select('l, u, ud')
  53.             ->leftJoin('l.user''u')
  54.             ->leftJoin('u.userdetails''ud')
  55.             ->andWhere('l.product_license =:product_license')
  56.             ->setParameter('product_license'$license);
  57.         $result $query->getQuery()->getArrayResult();
  58.         $data $result[0] ?? null;
  59.         $apiRedirect = [];
  60.         if($data){
  61.             $email =  $data['user']['email'];
  62.             $client $this->em->getRepository(Client::class)->findOneBy(['name' => $email]);
  63.             $urls $client->getRedirectUris();
  64.             $apiRedirect implode(','$urls);
  65.             $apiRedirect explode(','$apiRedirect);
  66.         }
  67.         $helper Helper::instance();
  68.         $redirectArr = [];
  69.         foreach ($apiRedirect as $tmp) {
  70.             $redirectArr[] = $helper->removeTrailingSlash($tmp);
  71.         }
  72.         $referer $helper->removeTrailingSlash($referer);
  73.         $license_status false;
  74.         if(in_array($referer$redirectArr)) {
  75.             $license_status true;
  76.         }
  77.         $object = [
  78.             'id' => $license,
  79.             'license' => $license_status,
  80.             'urls' => $apiRedirect,
  81.             'referer' => $referer,
  82.             'cronjob' => $data['user']['userdetails']['cronjob'],
  83.             'user_active' => $data['user']['userdetails']['aktiv']
  84.         ];
  85.       //  return $this->json($object);
  86.         $json $this->serializer->serialize($object'json');
  87.         return new JsonResponse($json200, [], true);
  88.     }
  89.     #[Route('/api/test'name'app_api_test')]
  90.     #[IsGranted('ROLE_OAUTH2_BASIC')]
  91.     public function apiTest(Request $request): Response
  92.     {
  93.         /** @var User $user */
  94.         $user $this->getUser();
  95.         if ($user) {
  96.             $loggedInEmail $user->getEmail();
  97.         } else {
  98.             $loggedInEmail 'empty';
  99.         }
  100.         $callValidate $this->validate_client($request);
  101.         $client $callValidate['client'];
  102.         $clientUser $callValidate['user'];
  103.         if (!$callValidate['status']) {
  104.             return $this->json([
  105.                 'error' => $callValidate['msg'],
  106.                 'error_description' => 'Client authentication failed',
  107.                 'message' => 'Client authentication failed'
  108.             ], 403);
  109.         }
  110.         return $this->json([
  111.             'message' => 'You successfully authenticated!',
  112.             'email' => $client->getName(),
  113.             'loggend_in_user' => $loggedInEmail,
  114.             'vorname' => $clientUser->getUserdetails()->getFirstName(),
  115.             'nachname' => $clientUser->getUserdetails()->getLastName(),
  116.             'scope' => explode(','$callValidate['scopes']),
  117.         ], 200);
  118.     }
  119.     /**
  120.      * @param Fonts $fonts
  121.      * @return BinaryFileResponse|void
  122.      */
  123.     #[Route('/api/fonts/{id}/download'name'_api_download_font')]
  124.     #[IsGranted('ROLE_OAUTH2_BASIC')]
  125.     public function api_font_download(Fonts $fonts)
  126.     {
  127.         $helper Helper::instance();
  128.         $fontDir $this->getParameter('fonts_dir');
  129.         $zipDir $fontDir 'zip';
  130.         $tmpDir $fontDir 'tmp';
  131.         $fileDir $fontDir 'fonts' DIRECTORY_SEPARATOR $fonts->getBezeichnung();
  132.         if (is_dir($zipDir)) {
  133.             $helper->recursive_destroy_dir($zipDir);
  134.         }
  135.         try {
  136.             $helper->make_is_dir($tmpDir);
  137.         } catch (Exception $e) {
  138.             dd($e->getMessage());
  139.         }
  140.         try {
  141.             $helper->make_is_dir($zipDir);
  142.         } catch (Exception $e) {
  143.             dd($e->getMessage());
  144.         }
  145.         try {
  146.             $helper->recursive_copy($fileDir$tmpDir DIRECTORY_SEPARATOR $fonts->getBezeichnung());
  147.         } catch (Exception $e) {
  148.             dd($e->getMessage());
  149.         }
  150.         $srcCss $fontDir 'fonts' DIRECTORY_SEPARATOR $fonts->getBezeichnung() . '.css';
  151.         $destCss $tmpDir DIRECTORY_SEPARATOR 'stylesheet.css';
  152.         try {
  153.             $helper->move_file($srcCss$destCss);
  154.         } catch (Exception $e) {
  155.             dd($e->getMessage());
  156.         }
  157.         $zipFile $zipDir DIRECTORY_SEPARATOR $fonts->getBezeichnung() . '.zip';
  158.         $za = new FlxZip;
  159.         $res $za->open($zipFileZipArchive::CREATE);
  160.         if ($res === true) {
  161.             $za->addDir($tmpDir'');
  162.             $za->close();
  163.         }
  164.         $helper->recursive_destroy_dir($tmpDir);
  165.         if (is_file($zipFile)) {
  166.             $response = new BinaryFileResponse($zipFile);
  167.             $response->setContentDisposition(
  168.                 ResponseHeaderBag::DISPOSITION_ATTACHMENT,
  169.                 $fonts->getBezeichnung() . '.zip'
  170.             );
  171.             return $response;
  172.         }
  173.     }
  174.     #[Route('/api/get-client'name'app_get_client')]
  175.     #[IsGranted('ROLE_OAUTH2_BASIC')]
  176.     public function api_get_client(Request $request): Response
  177.     {
  178.         $callValidate $this->validate_client($request);
  179.         if (!$callValidate['status']) {
  180.             return $this->json([
  181.                 'error' => $callValidate['msg'],
  182.                 'error_description' => 'Client authentication failed',
  183.                 'message' => 'Client authentication failed'
  184.             ], 403);
  185.         }
  186.         $client $callValidate['client'];
  187.         $valUser $callValidate['user'];
  188.         $loggedInEmail '';
  189.         /** @var User $user */
  190.         if ($this->getUser() !== null) {
  191.             $user $this->getUser();
  192.             if ($user) {
  193.                 if ($user->getRoles()) {
  194.                     $loggedInEmail $user->getEmail();
  195.                 }
  196.             }
  197.         }
  198.         //$lizenz = $this->em->getRepository(ProductLicense::class)->get_lizenz($valUser->getId(), $callValidate['redirect_uri']);
  199.         $client $this->em->getRepository(Client::class)->find($request->get('client_id'));
  200.         if (!in_array($callValidate['redirect_uri'], $client->getRedirectUris())) {
  201.             return $this->json([
  202.                 'error' => $callValidate['msg'],
  203.                 'error_description' => 'Client authentication failed',
  204.                 'message' => 'Client authentication failed (URL)'
  205.             ], 403);
  206.         }
  207.         $lizenz $this->em->getRepository(ProductLicense::class)->get_lizenz_not_check_uri($valUser->getId());
  208.         //dd($lizenz);
  209.         // $lizenz = $this->em->getRepository(ProductLicense::class)->get_others_uri_lizenz($valUser->getId());
  210.         if (!$lizenz->status) {
  211.             return $this->json([
  212.                 'error' => 'error',
  213.                 'error_description' => 'Client authentication failed',
  214.                 'message' => 'Client authentication failed'
  215.             ], 403);
  216.         }
  217.         $lizenzData $lizenz->record;
  218.         $lizenzDaten = [];
  219.         foreach ($lizenzData as $tmp) {
  220.             if (!$tmp['activatedAt']) {
  221.                 $activatedAt = new DateTimeImmutable();
  222.                 $activatedAtLizenz $this->em->getRepository(ProductLicense::class)->find($tmp['id']);
  223.                 $activatedAtLizenz->setActivatedAt($activatedAt);
  224.                 $this->em->persist($activatedAtLizenz);
  225.                 $this->em->flush();
  226.             }
  227.             $produkt $this->em->getRepository(Product::class)->find($tmp['product_id']);
  228.             unset($tmp['upload_token']);
  229.             $tmp['version'] = $produkt->getVersion();
  230.             $tmp['description'] = $produkt->getBeschreibung();
  231.             $tmp['redirect_uri'] = $callValidate['redirect_uri'];
  232.             $lizenzDaten[] = $tmp;
  233.         }
  234.         $lsP = [];
  235.         $licenseProducts $this->em->getRepository(Product::class)->findBy(['is_license' => true'is_show_api' => true]);
  236.         if ($licenseProducts) {
  237.             foreach ($licenseProducts as $tmp) {
  238.                 $s $this->get_product_type($tmp->getType());
  239.                 $item = [
  240.                     'basename' => $tmp->getSlug(),
  241.                     'bezeichnung' => $tmp->getBezeichnung(),
  242.                     'type' => $tmp->getType(),
  243.                     'raw_type' => $s['type']
  244.                 ];
  245.                 $lsP[] = $item;
  246.             }
  247.         }
  248.         return $this->json([
  249.             'email' => $client->getName(),
  250.             'logged_in_email' => $loggedInEmail,
  251.             'vorname' => $valUser->getUserdetails()->getFirstName(),
  252.             'nachname' => $valUser->getUserdetails()->getLastName(),
  253.             'lizenz_data' => $lizenzDaten,
  254.             'lizenz_products' => $lsP,
  255.             'cronjob' => $valUser->getUserdetails()->getCronjob(),
  256.             'scope' => explode(','$callValidate['scopes']),
  257.         ], 200);
  258.     }
  259.     #[Route('/api/{product_license}/wp-cron'name'app_wp_cron_check')]
  260.     public function wp_cron_check(Request $request): Response
  261.     {
  262.         $product_license $request->get('product_license');
  263.         $redirectUri $request->query->get('redirect_uri');
  264.         $redirect_uri filter_var($redirectUriFILTER_VALIDATE_URL);
  265.         if (!$product_license || !$redirect_uri) {
  266.             return $this->json([
  267.                 'error' => 'not-found',
  268.                 'error_description' => 'Product not found',
  269.                 'message' => 'Product not found',
  270.             ], 401);
  271.         }
  272.         $productLicense $this->em->getRepository(ProductLicense::class)->get_license_cron($product_license);
  273.         if (!$productLicense) {
  274.             return $this->json([
  275.                 'error' => 'not-found',
  276.                 'error_description' => 'Product not found',
  277.                 'message' => 'Product not found or not active',
  278.                 'delete_file' => 1
  279.             ], 401);
  280.         }
  281.         if (!$productLicense['aktiv']) {
  282.             return $this->json([
  283.                 'error' => 'not-active (' __LINE__ ')',
  284.                 'error_description' => 'License not active',
  285.                 'message' => 'License not active',
  286.                 'delete_file' => 0
  287.             ], 401);
  288.         }
  289.         if (!in_array($redirect_uri$productLicense['redirectUris'])) {
  290.             return $this->json([
  291.                 'error' => 'error',
  292.                 'error_description' => 'Client authentication failed',
  293.                 'message' => 'Client authentication failed (URL)'
  294.             ], 403);
  295.         }
  296.         $dateTime date('Y-m-d H:i:s'strtotime($productLicense['activatedAt']->format('Y-m-d H:i:s')));
  297.         $lizenz $this->em->getRepository(Licences::class)->find($productLicense['licenseId']);
  298.         $days $lizenz->getTimeLimit();
  299.         $rest strtotime("$dateTime +$days days");
  300.         if ($lizenz->getTimeLimit() && $rest time() <= 0) {
  301.             return $this->json([
  302.                 'error' => 'not-active (' __LINE__ ')',
  303.                 'error_description' => 'License not active',
  304.                 'message' => 'License not active',
  305.                 'delete_file' => 0
  306.             ], 401);
  307.         }
  308.         return $this->json([
  309.             'license' => $product_license,
  310.         ], 200);
  311.     }
  312.     #[Route('/api/{product_license}/token'name'app_get_download_code')]
  313.     public function get_download_code(Request $request): RedirectResponse
  314.     {
  315.         $redirect urldecode($request->get('redirect'));
  316.         $license $this->em->getRepository(ProductLicense::class)->get_license_by_product_license(['product_license' => $request->get('product_license')]);
  317.         if ($license && $license['redirectUris'] && in_array($redirect$license['redirectUris'])) {
  318.             return $this->redirect($redirect '?upload_code=' $license['upload_token'] . '&type=' $license['product_type'] . '&slug=' $license['product_slug']);
  319.         }
  320.         return $this->redirect($redirect '?error=URL nicht gefunden.');
  321.     }
  322.     #[Route('/api/download-free'name'app_download_free')]
  323.     #[IsGranted('ROLE_OAUTH2_PRODUCT')]
  324.     public function api_download_free(Request $request): Response
  325.     {
  326.         $body json_decode($request->getContent(), true);
  327.         $product $this->em->getRepository(Product::class)->find($body['product_id']);
  328.         if (!$product) {
  329.             return $this->json([
  330.                 'error' => 'not found db',
  331.                 'error_description' => 'Product not found',
  332.                 'message' => 'Product not found',
  333.             ], 401);
  334.         }
  335.         if (!in_array($product->getType(), $this->free_products)) {
  336.             return $this->json([
  337.                 'error' => 'not free',
  338.                 'error_description' => 'No free product',
  339.                 'message' => 'No free product'
  340.             ], 403);
  341.         }
  342.         return $this->json([
  343.             'slug' => $product->getSlug(),
  344.             'type' => $product->getType(),
  345.             'download' => '/api/' $product->getId() . '/download'
  346.         ], 200);
  347.     }
  348.     #[Route('/api/{slug}/{type}/update-options'name'_api_product_update_options')]
  349.     public function update_options(Request $request): Response
  350.     {
  351.         $slug $request->get('slug');
  352.         $type $request->get('type');
  353.         $product $this->em->getRepository(Product::class)->findOneBy(['slug' => $slug]);
  354.         if (!$product) {
  355.             return $this->json([
  356.                 'error' => 'not found db',
  357.                 'error_description' => 'Product not found',
  358.                 'message' => 'Product not found',
  359.             ], 401);
  360.         }
  361.         if ($product->getUpdateChecker()) {
  362.             $update json_decode($product->getUpdateChecker()->getUpdateData(), true);
  363.             $gitData json_decode($product->getUpdateChecker()->getGitData(), true);
  364.         } else {
  365.             return $this->json([
  366.                 'error' => 'not found db',
  367.                 'error_description' => 'Product not found',
  368.                 'message' => 'Product not found',
  369.             ], 401);
  370.         }
  371.         $selfUrl $request->getSchemeAndHttpHost();
  372.         if ($type == 'conf') {
  373.             return $this->json([
  374.                 'is_git' => $product->isIsGit(),
  375.                 'is_aktive' => $product->getUpdateChecker()->isAktive(),
  376.                 'self' => $selfUrl,
  377.                 'git_data' => $gitData,
  378.                 'update_url' => $selfUrl '/api/' $slug '/update/update-options'
  379.             ], 200);
  380.         }
  381.         if ($product->getUpdateChecker()->getType() == 'plugin') {
  382.             if (!$product->getUpdateChecker()->isRatingAktiv()) {
  383.                 unset($update['rating']);
  384.                 unset($update['num_ratings']);
  385.                 unset($update['downloaded']);
  386.                 unset($update['active_installs']);
  387.             }
  388.             if (!$product->getUpdateChecker()->isLanguageAktiv()) {
  389.                 unset($update['translations']);
  390.             }
  391.         }
  392.         return $this->json(
  393.             $update
  394.             200);
  395.     }
  396.     /**
  397.      * @param Product $product
  398.      * @return BinaryFileResponse|void
  399.      */
  400.     #[IsGranted('ROLE_OAUTH2_PRODUCT')]
  401.     #[Route('/api/{id}/download'name'_download_api_product')]
  402.     public function download_product(Product $product)
  403.     {
  404.         $file $this->getParameter('product_dir') . '/' $product->getSlug() . '/' $product->getSlug() . '.zip';
  405.         if (is_file($file)) {
  406.             $response = new BinaryFileResponse($file);
  407.             $response->setContentDisposition(
  408.                 ResponseHeaderBag::DISPOSITION_ATTACHMENT,
  409.                 $product->getSlug() . '.zip'
  410.             );
  411.             return $response;
  412.         }
  413.     }
  414.     /**
  415.      * @param Request $request
  416.      * @return BinaryFileResponse|JsonResponse
  417.      */
  418.     #[IsGranted('ROLE_OAUTH2_PRODUCT')]
  419.     #[Route('/api/{upload_token}/lizenz-product-download'name'_download_api_lizenz_product')]
  420.     public function download_lizenz_product(Request $request): BinaryFileResponse|JsonResponse
  421.     {
  422.         /* if(!$this->isGranted('ROLE_OAUTH2_PRODUCT')) {
  423.              return $this->json([
  424.                  'error' => 'ungültiger access token',
  425.                  'error_description' => 'ungültiger access token',
  426.                  'message' => 'ungültiger access token',
  427.              ], 403);
  428.          }*/
  429.         $productLicense $this->em->getRepository(ProductLicense::class)->findOneBy(['upload_token' => $request->get('upload_token')]);
  430.         if (!$productLicense) {
  431.             return $this->json([
  432.                 'error' => 'not found product license',
  433.                 'error_description' => 'Product not found',
  434.                 'message' => 'Product not found',
  435.             ], 401);
  436.         }
  437.         // dd($productLicense, $request->get('upload_token'));
  438.         //ProductLicense $productLicense
  439.         $product $this->em->getRepository(Product::class)->find($productLicense->getProductId());
  440.         if (!$product) {
  441.             return $this->json([
  442.                 'error' => 'not found product',
  443.                 'error_description' => 'Product not found',
  444.                 'message' => 'Product not found',
  445.             ], 401);
  446.         }
  447.         $file $this->getParameter('product_dir') . '/' $product->getSlug() . '/' $product->getSlug() . '.zip';
  448.         if (is_file($file)) {
  449.             $helper Helper::instance();
  450.             $newToken $helper->generate_callback_pw(2000100);
  451.             $productLicense->setUploadToken($newToken);
  452.             $productLicense->setAktiv(true);
  453.             $this->em->persist($productLicense);
  454.             $this->em->flush();
  455.             $response = new BinaryFileResponse($file);
  456.             $response->setContentDisposition(
  457.                 ResponseHeaderBag::DISPOSITION_ATTACHMENT,
  458.                 $product->getSlug() . '.zip'
  459.             );
  460.             return $response;
  461.         }
  462.         return $this->json([
  463.             'error' => 'not found file',
  464.             'error_description' => 'Product not found',
  465.             'message' => 'Product not found',
  466.         ], 401);
  467.     }
  468.     /**
  469.      * @param Request $request
  470.      * @return BinaryFileResponse|Response
  471.      */
  472.     #[Route('/api/{product_license}/aktivierungs-file'name'_download_api_lizenz_file')]
  473.     #[IsGranted('ROLE_OAUTH2_PRODUCT')]
  474.     public function aktivierungs_file_data(Request $request): BinaryFileResponse|Response
  475.     {
  476.         $productLicense $this->em->getRepository(ProductLicense::class)->findOneBy(['product_license' => $request->get('product_license')]);
  477.         //ProductLicense $productLicense
  478.         $produkt $this->em->getRepository(Product::class)->find($productLicense->getProductId());
  479.         $version str_replace(['v'], '-'$produkt->getVersion());
  480.         $filePath $this->getParameter('product_dir') . '/' $produkt->getSlug() . '/' $produkt->getSlug() . $version '/' $produkt->getAktivierungsPath();
  481.         if (is_file($filePath) && $productLicense->isAktiv()) {
  482.             $response = new BinaryFileResponse($filePath);
  483.             $response->setContentDisposition(
  484.                 ResponseHeaderBag::DISPOSITION_ATTACHMENT,
  485.                 basename($filePath)
  486.             );
  487.             return $response;
  488.         }
  489.         return $this->json([
  490.             'error' => 'not found',
  491.             'error_description' => 'Not found product',
  492.             'message' => 'Not found product',
  493.             'file' => $filePath
  494.         ], 403);
  495.     }
  496.     #[Route('/api/remove-consent'name'app_remove_consent')]
  497.     #[IsGranted('ROLE_OAUTH2_BASIC')]
  498.     public function remove_consent(Request $request): Response
  499.     {
  500.         $callValidate $this->validate_client($request);
  501.         if (!$callValidate['status']) {
  502.             return $this->json([
  503.                 'error' => $callValidate['msg'],
  504.                 'error_description' => 'Client authentication failed',
  505.                 'message' => 'Client authentication failed'
  506.             ], 403);
  507.         }
  508.         $client $callValidate['client'];
  509.         $valUser $callValidate['user'];
  510.         $consent $this->em->getRepository(OAuth2UserConsent::class)->findOneBy(['user' => $valUser]);
  511.         if (!$consent) {
  512.             return $this->json([
  513.                 'error' => $callValidate['msg'],
  514.                 'error_description' => 'Not found',
  515.                 'message' => 'Consent not found'
  516.             ], 403);
  517.         }
  518.         $this->em->remove($consent);
  519.         $this->em->flush();
  520.         return $this->json([
  521.             'email' => $client->getName(),
  522.             'vorname' => $valUser->getUserdetails()->getFirstName(),
  523.             'nachname' => $valUser->getUserdetails()->getLastName(),
  524.             'scope' => explode(','$callValidate['scopes']),
  525.         ], 200);
  526.     }
  527.     private function validate_client($request): array
  528.     {
  529.         $client $this->em->getRepository(Client::class)->findOneBy(['identifier' => $request->request->get('client_id')]);
  530.         $user $this->em->getRepository(User::class)->findOneBy(['email' => $client->getName()]);
  531.         $scopes implode(','$client->getScopes());
  532.         $user_active $user->getUserdetails()->isAktiv();
  533.         if (!$client->isActive() || !$user_active) {
  534.             return [
  535.                 'status' => false,
  536.                 'msg' => 'User not active',
  537.             ];
  538.         }
  539.         $urlError false;
  540.         $redirect_uri filter_var($request->request->get('redirect_uri'), FILTER_VALIDATE_URL);
  541.         if (!$redirect_uri) {
  542.             $urlError true;
  543.         }
  544.         $apiRedirect $client->getRedirectUris();
  545.         $apiRedirect implode(','$apiRedirect);
  546.         $apiRedirect explode(','$apiRedirect);
  547.         if (!in_array($redirect_uri$apiRedirect)) {
  548.             $urlError true;
  549.         }
  550.         if ($urlError) {
  551.             return [
  552.                 'status' => false,
  553.                 'msg' => sprintf('User not active for this URL: %s'$redirect_uri),
  554.             ];
  555.         }
  556.         return [
  557.             'status' => true,
  558.             'client' => $client,
  559.             'user' => $user,
  560.             'scopes' => $scopes,
  561.             'redirect_uri' => $redirect_uri
  562.         ];
  563.     }
  564. }