cache = $cache; } /** * Generates a one-time token that is sent along in every websocket call to the Daemon. * This is a signed JWT that the Daemon then uses the verify the user's identity, and * allows us to continually renew this token and avoid users mainitaining sessions wrongly, * as well as ensure that user's only perform actions they're allowed to. * * @param \Pterodactyl\Http\Requests\Api\Client\ClientApiRequest $request * @param \Pterodactyl\Models\Server $server * @return \Illuminate\Http\JsonResponse */ public function __invoke(ClientApiRequest $request, Server $server) { if ($request->user()->cannot(Permission::ACTION_WEBSOCKET, $server)) { throw new HttpException( Response::HTTP_FORBIDDEN, 'You do not have permission to connect to this server\'s websocket.' ); } $now = Chronos::now(); $signer = new Sha256; $token = (new Builder)->issuedBy(config('app.url')) ->permittedFor($server->node->getConnectionAddress()) ->identifiedBy(hash('sha256', $request->user()->id . $server->uuid), true) ->issuedAt($now->getTimestamp()) ->canOnlyBeUsedAfter($now->getTimestamp()) ->expiresAt($now->addMinutes(15)->getTimestamp()) ->withClaim('user_id', $request->user()->id) ->withClaim('server_uuid', $server->uuid) ->withClaim('permissions', array_merge([ 'connect', 'send-command', 'send-power', ], $request->user()->root_admin ? ['receive-errors', 'receive-install'] : [])) ->getToken($signer, new Key($server->node->daemonSecret)); $socket = str_replace(['https://', 'http://'], ['wss://', 'ws://'], $server->node->getConnectionAddress()); return JsonResponse::create([ 'data' => [ 'token' => $token->__toString(), 'socket' => $socket . sprintf('/api/servers/%s/ws', $server->uuid), ], ]); } }