22
33namespace Pterodactyl \Http \Controllers \Api \Client \Servers ;
44
5- use Cake \Chronos \Chronos ;
6- use Lcobucci \JWT \Builder ;
7- use Lcobucci \JWT \Signer \Key ;
5+ use Carbon \CarbonImmutable ;
86use Illuminate \Http \Response ;
97use Pterodactyl \Models \Server ;
8+ use Pterodactyl \Models \Subuser ;
109use Illuminate \Http \JsonResponse ;
1110use Pterodactyl \Models \Permission ;
12- use Lcobucci \JWT \Signer \Hmac \Sha256 ;
1311use Illuminate \Contracts \Cache \Repository ;
12+ use Pterodactyl \Services \Nodes \NodeJWTService ;
1413use Symfony \Component \HttpKernel \Exception \HttpException ;
1514use Pterodactyl \Http \Requests \Api \Client \ClientApiRequest ;
1615use Pterodactyl \Http \Controllers \Api \Client \ClientApiController ;
@@ -22,16 +21,23 @@ class WebsocketController extends ClientApiController
2221 */
2322 private $ cache ;
2423
24+ /**
25+ * @var \Pterodactyl\Services\Nodes\NodeJWTService
26+ */
27+ private $ jwtService ;
28+
2529 /**
2630 * WebsocketController constructor.
2731 *
32+ * @param \Pterodactyl\Services\Nodes\NodeJWTService $jwtService
2833 * @param \Illuminate\Contracts\Cache\Repository $cache
2934 */
30- public function __construct (Repository $ cache )
35+ public function __construct (NodeJWTService $ jwtService , Repository $ cache )
3136 {
3237 parent ::__construct ();
3338
3439 $ this ->cache = $ cache ;
40+ $ this ->jwtService = $ jwtService ;
3541 }
3642
3743 /**
@@ -46,30 +52,35 @@ public function __construct(Repository $cache)
4652 */
4753 public function __invoke (ClientApiRequest $ request , Server $ server )
4854 {
49- if ($ request ->user ()->cannot (Permission::ACTION_WEBSOCKET , $ server )) {
50- throw new HttpException (
51- Response::HTTP_FORBIDDEN , 'You do not have permission to connect to this server \'s websocket. '
52- );
55+ $ user = $ request ->user ();
56+ if ($ user ->cannot (Permission::ACTION_WEBSOCKET , $ server )) {
57+ throw new HttpException (Response::HTTP_FORBIDDEN , 'You do not have permission to connect to this server \'s websocket. ' );
5358 }
5459
55- $ now = Chronos::now ();
60+ if ($ user ->root_admin || $ user ->id === $ server ->owner_id ) {
61+ $ permissions = ['* ' ];
5662
57- $ signer = new Sha256 ;
63+ if ($ user ->root_admin ) {
64+ $ permissions [] = 'admin.errors ' ;
65+ $ permissions [] = 'admin.install ' ;
66+ }
67+ } else {
68+ /** @var \Pterodactyl\Models\Subuser|null $subuserPermissions */
69+ $ subuserPermissions = $ server ->subusers ->first (function (Subuser $ subuser ) use ($ user ) {
70+ return $ subuser ->user_id === $ user ->id ;
71+ });
72+
73+ $ permissions = $ subuserPermissions ? $ subuserPermissions ->permissions : [];
74+ }
5875
59- $ token = (new Builder )->issuedBy (config ('app.url ' ))
60- ->permittedFor ($ server ->node ->getConnectionAddress ())
61- ->identifiedBy (hash ('sha256 ' , $ request ->user ()->id . $ server ->uuid ), true )
62- ->issuedAt ($ now ->getTimestamp ())
63- ->canOnlyBeUsedAfter ($ now ->getTimestamp ())
64- ->expiresAt ($ now ->addMinutes (15 )->getTimestamp ())
65- ->withClaim ('user_id ' , $ request ->user ()->id )
66- ->withClaim ('server_uuid ' , $ server ->uuid )
67- ->withClaim ('permissions ' , array_merge ([
68- 'connect ' ,
69- 'send-command ' ,
70- 'send-power ' ,
71- ], $ request ->user ()->root_admin ? ['receive-errors ' , 'receive-install ' ] : []))
72- ->getToken ($ signer , new Key ($ server ->node ->daemonSecret ));
76+ $ token = $ this ->jwtService
77+ ->setExpiresAt (CarbonImmutable::now ()->addMinutes (15 ))
78+ ->setClaims ([
79+ 'user_id ' => $ request ->user ()->id ,
80+ 'server_uuid ' => $ server ->uuid ,
81+ 'permissions ' => $ permissions ?? [],
82+ ])
83+ ->handle ($ server ->node , $ user ->id . $ server ->uuid );
7384
7485 $ socket = str_replace (['https:// ' , 'http:// ' ], ['wss:// ' , 'ws:// ' ], $ server ->node ->getConnectionAddress ());
7586
0 commit comments