AblyBroadcaster::generateAblySignature()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 5
c 0
b 0
f 0
nc 2
nop 3
dl 0
loc 11
rs 10
1
<?php
2
3
namespace SpringboardVR\LaravelAblyBroadcaster;
4
5
use Illuminate\Broadcasting\Broadcasters\Broadcaster;
6
use Illuminate\Support\Arr;
7
use Illuminate\Support\Str;
8
use Ably\AblyRest;
9
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
10
11
class AblyBroadcaster extends Broadcaster
12
{
13
    use UseAblyChannelConventions;
14
15
    /**
16
     * The AblyRest SDK instance.
17
     *
18
     * @var \Ably\AblyRest
19
     */
20
    protected $ably;
21
22
    /**
23
     * Create a new broadcaster instance.
24
     *
25
     * @param  \Ably\AblyRest  $ably
26
     * @return void
27
     */
28
    public function __construct(AblyRest $ably)
29
    {
30
        $this->ably = $ably;
31
    }
32
33
    /**
34
     * Authenticate the incoming request for a given channel.
35
     *
36
     * @param  \Illuminate\Http\Request  $request
37
     * @return mixed
38
     *
39
     * @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
40
     */
41
    public function auth($request)
42
    {
43
        $channelName = $this->normalizeChannelName($request->channel_name);
44
45
        if ($this->isGuardedChannel($request->channel_name) &&
46
            ! $this->retrieveUser($request, $channelName)) {
47
            throw new AccessDeniedHttpException;
48
        }
49
50
        return parent::verifyUserCanAccessChannel(
51
            $request, $channelName
52
        );
53
    }
54
55
    /**
56
     * Return the valid authentication response.
57
     *
58
     * @param  \Illuminate\Http\Request  $request
59
     * @param  mixed  $result
60
     * @return mixed
61
     */
62
    public function validAuthenticationResponse($request, $result)
63
    {
64
        if (Str::startsWith($request->channel_name, 'private')) {
65
            $signature = $this->generateAblySignature($request->channel_name, $request->socket_id);
66
            return ['auth' => $this->getPublicToken() . ':' . $signature];
67
        }
68
69
        $channelName = $this->normalizeChannelName($request->channel_name);
70
        $userId = $this->retrieveUser($request, $channelName)->getAuthIdentifier();
71
72
        $userData = [
73
            'user_id' => $userId,
74
        ];
75
76
        if ($result) {
77
            $userData['user_info'] = $result;
78
        }
79
80
        $signature = $this->generateAblySignature($request->channel_name, $request->socket_id, $userData);
81
82
        return [
83
            'auth' => $this->getPublicToken() . ':' . $signature,
84
            'channel_data' => json_encode($userData),
85
        ];
86
    }
87
88
    /**
89
     * Generate the Signature for Ably auth headers
90
     * @param $channelName
91
     * @param $socketId
92
     * @param null $userData
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $userData is correct as it would always require null to be passed?
Loading history...
93
     * @return string
94
     */
95
    public function generateAblySignature($channelName, $socketId, $userData = null)
96
    {
97
        $privateToken = $this->getPrivateToken();
98
99
        $signature = $socketId .':' . $channelName;
100
101
        if ($userData) {
0 ignored issues
show
introduced by
$userData is of type null, thus it always evaluated to false.
Loading history...
102
            $signature .= ':' . json_encode($userData);
103
        }
104
105
        return hash_hmac('sha256',$signature, $privateToken);
106
    }
107
108
    /**
109
     * Broadcast the given event.
110
     *
111
     * @param  array  $channels
112
     * @param  string  $event
113
     * @param  array  $payload
114
     * @return void
115
     */
116
    public function broadcast(array $channels, $event, array $payload = [])
117
    {;
118
        foreach (self::formatChannels($channels) as $channel) {
0 ignored issues
show
Bug Best Practice introduced by
The method SpringboardVR\LaravelAbl...aster::formatChannels() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

118
        foreach (self::/** @scrutinizer ignore-call */ formatChannels($channels) as $channel) {
Loading history...
119
            $ablyChannel = $this->ably->channels->get($channel);
120
            $ablyChannel->publish($event, $payload);
121
        }
122
    }
123
124
    /**
125
     * Get the Public Token Value out of the Ably key
126
     * @return mixed
127
     */
128
    public function getPublicToken()
129
    {
130
        return Str::before($this->ably->options->key, ':');
131
    }
132
133
    /**
134
     * Get the Private Token value out of the Ably Key
135
     * @return mixed
136
     */
137
    public function getPrivateToken()
138
    {
139
        return Str::after($this->ably->options->key, ':');
140
    }
141
142
    /**
143
     * Get the Ably SDK instance.
144
     *
145
     * @return \Ably\AblyRest
146
     */
147
    public function getAbly()
148
    {
149
        return $this->ably;
150
    }
151
}
152