This commit is contained in:
Marcel Pociot 2018-11-22 21:36:25 +01:00
parent 07046c1fdd
commit abeef421b5
5 changed files with 91 additions and 12 deletions

View File

@ -29,6 +29,7 @@
"illuminate/http": "5.6.*|5.7.*",
"illuminate/routing": "5.6.*|5.7.*",
"illuminate/support": "5.6.*|5.7.*",
"symfony/http-kernel": "~4.0",
"symfony/psr-http-message-bridge": "^1.1"
},
"require-dev": {

View File

@ -2,17 +2,21 @@
namespace BeyondCode\LaravelWebSockets\LaravelEcho\Http\Controllers;
use Exception;
use Illuminate\Http\Request;
use GuzzleHttp\Psr7 as gPsr;
use GuzzleHttp\Psr7\Response;
use Ratchet\ConnectionInterface;
use Illuminate\Http\JsonResponse;
use GuzzleHttp\Psr7\ServerRequest;
use Ratchet\Http\HttpServerInterface;
use Psr\Http\Message\RequestInterface;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Bridge\PsrHttpMessage\Factory\HttpFoundationFactory;
abstract class EchoController implements HttpServerInterface
{
public function onOpen(ConnectionInterface $conn, RequestInterface $request = null)
public function onOpen(ConnectionInterface $connection, RequestInterface $request = null)
{
$queryParameters = [];
parse_str($request->getUri()->getQuery(), $queryParameters);
@ -25,22 +29,42 @@ abstract class EchoController implements HttpServerInterface
$request->getProtocolVersion()
))->withQueryParams($queryParameters);
$response = $this(Request::createFromBase((new HttpFoundationFactory)->createRequest($serverRequest)));
$conn->send(JsonResponse::create($response)->send());
$conn->close();
$laravelRequest = Request::createFromBase((new HttpFoundationFactory)->createRequest($serverRequest));
// Always verify the app id
$this->verifyAppId($laravelRequest->appId);
$response = $this($laravelRequest);
$connection->send(JsonResponse::create($response)->send());
$connection->close();
}
function onMessage(ConnectionInterface $from, $msg)
{
}
function onClose(ConnectionInterface $conn)
function onClose(ConnectionInterface $connection)
{
}
function onError(ConnectionInterface $conn, \Exception $e)
function onError(ConnectionInterface $connection, Exception $exception)
{
if ($exception instanceof HttpException)
{
$response = new Response($exception->getStatusCode(), $exception->getHeaders(), $exception->getMessage());
$connection->send(gPsr\str($response));
$connection->close();
}
}
public function verifyAppId(string $appId)
{
if ($appId !== config('broadcasting.connections.pusher.app_id')) {
throw new HttpException(401, 'Invalid App ID provided.');
}
}
abstract public function __invoke(Request $request);

View File

@ -0,0 +1,54 @@
<?php
namespace BeyondCode\LaravelWebSockets\LaravelEcho\Http\Controllers;
use BeyondCode\LaravelWebSockets\LaravelEcho\Pusher\Channels\ChannelManager;
use BeyondCode\LaravelWebSockets\LaravelEcho\Pusher\Exceptions\InvalidSignatureException;
use Illuminate\Http\Request;
use Symfony\Component\HttpKernel\Exception\HttpException;
class FetchChannel extends EchoController
{
/** @var \BeyondCode\LaravelWebSockets\LaravelEcho\Pusher\Channels\ChannelManager */
protected $channelManager;
public function __construct(ChannelManager $channelManager)
{
$this->channelManager = $channelManager;
}
public function __invoke(Request $request)
{
$this->verifySignature($request);
foreach ($request->json()->get('channels', []) as $channelId) {
$channel = $this->channelManager->find($request->appId, $channelId);
optional($channel)->broadcast([
'channel' => $channelId,
'event' => $request->json()->get('name'),
'data' => $request->json()->get('data'),
]);
}
return $request->json()->all();
}
protected function verifySignature(Request $request)
{
$bodyMd5 = md5($request->getContent());
$signature =
"POST\n/apps/{$request->appId}/events\n".
"auth_key={$request->auth_key}".
"&auth_timestamp={$request->auth_timestamp}".
"&auth_version={$request->auth_version}".
"&body_md5={$bodyMd5}";
$authSignature = hash_hmac('sha256', $signature, config('broadcasting.connections.pusher.secret'));
if ($authSignature !== $request->get('auth_signature')) {
throw new HttpException(401, 'Invalid authentication signature.');
}
}
}

View File

@ -2,11 +2,11 @@
namespace BeyondCode\LaravelWebSockets\LaravelEcho\Http\Controllers;
use BeyondCode\LaravelWebSockets\LaravelEcho\Pusher\Channels\ChannelManager;
use BeyondCode\LaravelWebSockets\LaravelEcho\Pusher\Exceptions\InvalidSignatureException;
use Illuminate\Http\Request;
use Symfony\Component\HttpKernel\Exception\HttpException;
use BeyondCode\LaravelWebSockets\LaravelEcho\Pusher\Channels\ChannelManager;
class EventController extends EchoController
class TriggerEvent extends EchoController
{
/** @var \BeyondCode\LaravelWebSockets\LaravelEcho\Pusher\Channels\ChannelManager */
protected $channelManager;
@ -47,7 +47,7 @@ class EventController extends EchoController
$authSignature = hash_hmac('sha256', $signature, config('broadcasting.connections.pusher.secret'));
if ($authSignature !== $request->get('auth_signature')) {
throw new InvalidSignatureException();
throw new HttpException(401, 'Invalid auth signature provided.');
}
}
}

View File

@ -71,10 +71,10 @@ class Router
// TODO: fleshen out http API
$this->get('/apps/{appId}/status', LaravelEcho\Http\Controllers\StatusController::class);
$this->get('/apps/{appId}/channels', LaravelEcho\Http\Controllers\StatusController::class);
$this->get('/apps/{appId}/channels/{channelName}', LaravelEcho\Http\Controllers\StatusController::class);
$this->get('/apps/{appId}/channels/{channelName}', LaravelEcho\Http\Controllers\FetchChannel::class);
$this->get('/apps/{appId}/channels/{channelName}/users', LaravelEcho\Http\Controllers\StatusController::class);
$this->post('/apps/{appId}/events', LaravelEcho\Http\Controllers\EventController::class);
$this->post('/apps/{appId}/events', LaravelEcho\Http\Controllers\TriggerEvent::class);
}
/**