Completed
Push — master ( 53691c...15e6b6 )
by Marcel
01:44
created

src/HttpApi/Controllers/Controller.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace BeyondCode\LaravelWebSockets\HttpApi\Controllers;
4
5
use Exception;
6
use Pusher\Pusher;
7
use Illuminate\Http\Request;
8
use GuzzleHttp\Psr7\Response;
9
use Ratchet\ConnectionInterface;
10
use Illuminate\Http\JsonResponse;
11
use GuzzleHttp\Psr7\ServerRequest;
12
use Ratchet\Http\HttpServerInterface;
13
use Psr\Http\Message\RequestInterface;
14
use BeyondCode\LaravelWebSockets\Apps\App;
15
use BeyondCode\LaravelWebSockets\QueryParameters;
16
use Symfony\Component\HttpKernel\Exception\HttpException;
17
use Symfony\Bridge\PsrHttpMessage\Factory\HttpFoundationFactory;
18
use BeyondCode\LaravelWebSockets\WebSockets\Channels\ChannelManager;
19
20
abstract class Controller implements HttpServerInterface
21
{
22
    /** @var \BeyondCode\LaravelWebSockets\WebSockets\Channels\ChannelManager */
23
    protected $channelManager;
24
25
    public function __construct(ChannelManager $channelManager)
26
    {
27
        $this->channelManager = $channelManager;
28
    }
29
30
    public function onOpen(ConnectionInterface $connection, RequestInterface $request = null)
31
    {
32
        $serverRequest = (new ServerRequest(
33
            $request->getMethod(),
0 ignored issues
show
It seems like $request is not always an object, but can also be of type null. Maybe add an additional type check?

If a variable is not always an object, we recommend to add an additional type check to ensure your method call is safe:

function someFunction(A $objectMaybe = null)
{
    if ($objectMaybe instanceof A) {
        $objectMaybe->doSomething();
    }
}
Loading history...
34
            $request->getUri(),
35
            $request->getHeaders(),
36
            $request->getBody(),
37
            $request->getProtocolVersion()
38
        ))->withQueryParams(QueryParameters::create($request)->all());
0 ignored issues
show
It seems like $request defined by parameter $request on line 30 can be null; however, BeyondCode\LaravelWebSoc...eryParameters::create() does not accept null, maybe add an additional type check?

It seems like you allow that null is being passed for a parameter, however the function which is called does not seem to accept null.

We recommend to add an additional type check (or disallow null for the parameter):

function notNullable(stdClass $x) { }

// Unsafe
function withoutCheck(stdClass $x = null) {
    notNullable($x);
}

// Safe - Alternative 1: Adding Additional Type-Check
function withCheck(stdClass $x = null) {
    if ($x instanceof stdClass) {
        notNullable($x);
    }
}

// Safe - Alternative 2: Changing Parameter
function withNonNullableParam(stdClass $x) {
    notNullable($x);
}
Loading history...
39
40
        $laravelRequest = Request::createFromBase((new HttpFoundationFactory)->createRequest($serverRequest));
41
42
        $this
43
            ->ensureValidAppId($laravelRequest->appId)
44
            ->ensureValidSignature($laravelRequest);
45
46
        $response = $this($laravelRequest);
47
48
        $connection->send(JsonResponse::create($response));
49
        $connection->close();
50
    }
51
52
    public function onMessage(ConnectionInterface $from, $msg)
53
    {
54
    }
55
56
    public function onClose(ConnectionInterface $connection)
57
    {
58
    }
59
60
    public function onError(ConnectionInterface $connection, Exception $exception)
61
    {
62
        if (! $exception instanceof HttpException) {
63
            return;
64
        }
65
66
        $response = new Response($exception->getStatusCode(), [
67
            'Content-Type' => 'application/json',
68
        ], json_encode([
69
            'error' => $exception->getMessage(),
70
        ]));
71
72
        $connection->send(\GuzzleHttp\Psr7\str($response));
73
74
        $connection->close();
75
    }
76
77
    public function ensureValidAppId(string $appId)
78
    {
79
        if (! App::findById($appId)) {
80
            throw new HttpException(401, "Unknown app id `{$appId}` provided.");
81
        }
82
83
        return $this;
84
    }
85
86
    protected function ensureValidSignature(Request $request)
87
    {
88
        /*
89
         * The `auth_signature` & `body_md5` parameters are not included when calculating the `auth_signature` value.
90
         *
91
         * The `appId`, `appKey` & `channelName` parameters are actually route paramaters and are never supplied by the client.
92
         */
93
        $params = array_except($request->query(), ['auth_signature', 'body_md5', 'appId', 'appKey', 'channelName']);
94
95
        if ($request->getContent() !== '') {
96
            $params['body_md5'] = md5($request->getContent());
97
        }
98
99
        ksort($params);
100
101
        $signature = "{$request->getMethod()}\n/{$request->path()}\n".Pusher::array_implode('=', '&', $params);
102
103
        $authSignature = hash_hmac('sha256', $signature, App::findById($request->get('appId'))->secret);
104
105
        if ($authSignature !== $request->get('auth_signature')) {
106
            throw new HttpException(401, 'Invalid auth signature provided.');
107
        }
108
109
        return $this;
110
    }
111
112
    abstract public function __invoke(Request $request);
113
}
114