src/Controller/Plugin/PluginTokenController.php line 32

Open in your IDE?
  1. <?php
  2. namespace App\Controller\Plugin;
  3. use App\Entity\FeatureAccess;
  4. use App\Entity\User;
  5. use App\Service\Ai\FeatureAccessService;
  6. use App\Service\Ai\PluginAccessToken;
  7. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  8. use Symfony\Component\HttpFoundation\JsonResponse;
  9. use Symfony\Component\HttpFoundation\Request;
  10. use Symfony\Component\RateLimiter\RateLimiterFactory;
  11. use Symfony\Component\Routing\Annotation\Route;
  12. /**
  13.  * Endpoints utilisés par les plugins Euro-Office (cross-origin) pour
  14.  *  - obtenir un access_token court-lived (auth Symfony)
  15.  *  - récupérer la liste des features autorisées/refusées pour le user courant
  16.  *
  17.  * L'access_token /api/plugin/access-token est servi same-origin (cookie session
  18.  * de la page workroom) puis transmis en Bearer aux plugins iframe.
  19.  */
  20. class PluginTokenController extends AbstractController
  21. {
  22.     public function __construct(
  23.         private readonly PluginAccessToken $accessToken,
  24.         private readonly FeatureAccessService $featureAccess,
  25.         private readonly RateLimiterFactory $pluginTokenLimiter,
  26.     ) {}
  27.     #[Route('/api/plugin/access-token'name'plugin_access_token'methods: ['GET'], options: ['expose' => true])]
  28.     public function token(Request $request): JsonResponse
  29.     {
  30.         /** @var User|null $user */
  31.         $user $this->getUser();
  32.         if (!$user) return new JsonResponse(['error' => 'unauthorized'], 401);
  33.         // Rate-limit (cf. plugin_token in rate_limiter.yaml). Sans cette limite,
  34.         // l'endpoint pouvait servir un nombre illimité de JWTs (DoS / spam).
  35.         $limit $this->pluginTokenLimiter->create('user-'.$user->getId())->consume();
  36.         if (!$limit->isAccepted()) {
  37.             $resp = new JsonResponse(['error' => 'rate_limited''retryAfter' => $limit->getRetryAfter()->getTimestamp() - time()], 429);
  38.             $resp->headers->set('Retry-After', (string) ($limit->getRetryAfter()->getTimestamp() - time()));
  39.             return $resp;
  40.         }
  41.         return new JsonResponse([
  42.             'token' => $this->accessToken->generate($user),
  43.             'expiresIn' => $this->accessToken->getTtl(),
  44.         ]);
  45.     }
  46.     /**
  47.      * Retourne la map des features autorisées/refusées pour l'utilisateur
  48.      * courant. Utilisé par le plugin "labomega-bootstrap" (autostart) pour
  49.      * masquer les boutons des plugins désactivés dans la barre OnlyOffice.
  50.      *
  51.      * Auth : session cookie (same-origin) OU Bearer / X-Plugin-Token
  52.      * (cross-origin depuis un plugin iframe).
  53.      */
  54.     #[Route('/api/plugin/features'name'plugin_features'methods: ['GET'], options: ['expose' => true])]
  55.     public function features(Request $request): JsonResponse
  56.     {
  57.         $user $this->resolveUser($request);
  58.         if (!$user) return new JsonResponse(['error' => 'unauthorized'], 401);
  59.         $r = new JsonResponse(null);
  60.         $r->setEncodingOptions(JSON_UNESCAPED_UNICODE);
  61.         $r->setData([
  62.             'features' => $this->featureAccess->getResolvedAccessMap($user),
  63.             'disabled' => $this->featureAccess->getDisabledFeatures($user),
  64.             'available' => FeatureAccess::FEATURES,
  65.         ]);
  66.         return $r;
  67.     }
  68.     private function resolveUser(Request $request): ?User
  69.     {
  70.         $u $this->getUser();
  71.         if ($u instanceof User) return $u;
  72.         $token $request->query->get('access_token')
  73.             ?? $request->headers->get('X-Plugin-Token');
  74.         if (!$token) {
  75.             $auth $request->headers->get('Authorization''');
  76.             if (str_starts_with($auth'Bearer ')) $token substr($auth7);
  77.         }
  78.         return $token $this->accessToken->resolveUser($token) : null;
  79.     }
  80. }