"Fossies" - the Fresh Open Source Software Archive

Member "framework-8.67.0/src/Illuminate/Broadcasting/Broadcasters/AblyBroadcaster.php" (22 Oct 2021, 5546 Bytes) of package /linux/www/laravel-framework-8.67.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) PHP source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "AblyBroadcaster.php" see the Fossies "Dox" file reference documentation.

    1 <?php
    2 
    3 namespace Illuminate\Broadcasting\Broadcasters;
    4 
    5 use Ably\AblyRest;
    6 use Illuminate\Support\Str;
    7 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
    8 
    9 /**
   10  * @author Matthew Hall (matthall28@gmail.com)
   11  * @author Taylor Otwell (taylor@laravel.com)
   12  */
   13 class AblyBroadcaster extends Broadcaster
   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 (empty($request->channel_name) ||
   46             ($this->isGuardedChannel($request->channel_name) &&
   47             ! $this->retrieveUser($request, $channelName))) {
   48             throw new AccessDeniedHttpException;
   49         }
   50 
   51         return parent::verifyUserCanAccessChannel(
   52             $request, $channelName
   53         );
   54     }
   55 
   56     /**
   57      * Return the valid authentication response.
   58      *
   59      * @param  \Illuminate\Http\Request  $request
   60      * @param  mixed  $result
   61      * @return mixed
   62      */
   63     public function validAuthenticationResponse($request, $result)
   64     {
   65         if (Str::startsWith($request->channel_name, 'private')) {
   66             $signature = $this->generateAblySignature(
   67                 $request->channel_name, $request->socket_id
   68             );
   69 
   70             return ['auth' => $this->getPublicToken().':'.$signature];
   71         }
   72 
   73         $channelName = $this->normalizeChannelName($request->channel_name);
   74 
   75         $user = $this->retrieveUser($request, $channelName);
   76 
   77         $broadcastIdentifier = method_exists($user, 'getAuthIdentifierForBroadcasting')
   78                     ? $user->getAuthIdentifierForBroadcasting()
   79                     : $user->getAuthIdentifier();
   80 
   81         $signature = $this->generateAblySignature(
   82             $request->channel_name,
   83             $request->socket_id,
   84             $userData = array_filter([
   85                 'user_id' => (string) $broadcastIdentifier,
   86                 'user_info' => $result,
   87             ])
   88         );
   89 
   90         return [
   91             'auth' => $this->getPublicToken().':'.$signature,
   92             'channel_data' => json_encode($userData),
   93         ];
   94     }
   95 
   96     /**
   97      * Generate the signature needed for Ably authentication headers.
   98      *
   99      * @param  string  $channelName
  100      * @param  string  $socketId
  101      * @param  array|null  $userData
  102      * @return string
  103      */
  104     public function generateAblySignature($channelName, $socketId, $userData = null)
  105     {
  106         return hash_hmac(
  107             'sha256',
  108             sprintf('%s:%s%s', $socketId, $channelName, $userData ? ':'.json_encode($userData) : ''),
  109             $this->getPrivateToken(),
  110         );
  111     }
  112 
  113     /**
  114      * Broadcast the given event.
  115      *
  116      * @param  array  $channels
  117      * @param  string  $event
  118      * @param  array  $payload
  119      * @return void
  120      */
  121     public function broadcast(array $channels, $event, array $payload = [])
  122     {
  123         foreach ($this->formatChannels($channels) as $channel) {
  124             $this->ably->channels->get($channel)->publish($event, $payload);
  125         }
  126     }
  127 
  128     /**
  129      * Return true if the channel is protected by authentication.
  130      *
  131      * @param  string  $channel
  132      * @return bool
  133      */
  134     public function isGuardedChannel($channel)
  135     {
  136         return Str::startsWith($channel, ['private-', 'presence-']);
  137     }
  138 
  139     /**
  140      * Remove prefix from channel name.
  141      *
  142      * @param  string  $channel
  143      * @return string
  144      */
  145     public function normalizeChannelName($channel)
  146     {
  147         if ($this->isGuardedChannel($channel)) {
  148             return Str::startsWith($channel, 'private-')
  149                         ? Str::replaceFirst('private-', '', $channel)
  150                         : Str::replaceFirst('presence-', '', $channel);
  151         }
  152 
  153         return $channel;
  154     }
  155 
  156     /**
  157      * Format the channel array into an array of strings.
  158      *
  159      * @param  array  $channels
  160      * @return array
  161      */
  162     protected function formatChannels(array $channels)
  163     {
  164         return array_map(function ($channel) {
  165             $channel = (string) $channel;
  166 
  167             if (Str::startsWith($channel, ['private-', 'presence-'])) {
  168                 return Str::startsWith($channel, 'private-')
  169                     ? Str::replaceFirst('private-', 'private:', $channel)
  170                     : Str::replaceFirst('presence-', 'presence:', $channel);
  171             }
  172 
  173             return 'public:'.$channel;
  174         }, $channels);
  175     }
  176 
  177     /**
  178      * Get the public token value from the Ably key.
  179      *
  180      * @return mixed
  181      */
  182     protected function getPublicToken()
  183     {
  184         return Str::before($this->ably->options->key, ':');
  185     }
  186 
  187     /**
  188      * Get the private token value from the Ably key.
  189      *
  190      * @return mixed
  191      */
  192     protected function getPrivateToken()
  193     {
  194         return Str::after($this->ably->options->key, ':');
  195     }
  196 
  197     /**
  198      * Get the underlying Ably SDK instance.
  199      *
  200      * @return \Ably\AblyRest
  201      */
  202     public function getAbly()
  203     {
  204         return $this->ably;
  205     }
  206 }