Skip to content
This repository was archived by the owner on Feb 7, 2024. It is now read-only.

Commit f62ac8f

Browse files
committed
wip
1 parent b46cfad commit f62ac8f

File tree

11 files changed

+257
-35
lines changed

11 files changed

+257
-35
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ vendor
44
coverage
55
.phpunit.result.cache
66
.idea/
7+
database.sqlite

src/Contracts/PushesToPusher.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
namespace BeyondCode\LaravelWebSockets\Contracts;
4+
5+
use BeyondCode\LaravelWebSockets\PubSub\Broadcasters\RedisPusherBroadcaster;
6+
use Illuminate\Broadcasting\Broadcasters\PusherBroadcaster;
7+
use Pusher\Pusher;
8+
9+
trait PushesToPusher
10+
{
11+
/**
12+
* Get the right Pusher broadcaster for the used driver.
13+
*
14+
* @param array $app
15+
* @return \Illuminate\Broadcasting\Broadcasters\Broadcaster
16+
*/
17+
public function getPusherBroadcaster(array $app)
18+
{
19+
if (config('websockets.replication.driver') === 'redis') {
20+
return new RedisPusherBroadcaster(
21+
new Pusher($app['key'], $app['secret'], $app['id'], config('broadcasting.connections.websockets.options', [])),
22+
$app['id'],
23+
app('redis'),
24+
config('broadcasting.connections.websockets.connection', null)
25+
);
26+
}
27+
28+
return new PusherBroadcaster(
29+
new Pusher($app['key'], $app['secret'], $app['id'], config('broadcasting.connections.pusher.options', [])),
30+
);
31+
}
32+
}

src/Dashboard/Http/Controllers/AuthenticateDashboard.php

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,15 @@
33
namespace BeyondCode\LaravelWebSockets\Dashboard\Http\Controllers;
44

55
use BeyondCode\LaravelWebSockets\Apps\App;
6+
use BeyondCode\LaravelWebSockets\Contracts\PushesToPusher;
67
use Illuminate\Broadcasting\Broadcasters\PusherBroadcaster;
78
use Illuminate\Http\Request;
89
use Pusher\Pusher;
910

1011
class AuthenticateDashboard
1112
{
13+
use PushesToPusher;
14+
1215
/**
1316
* Find the app by using the header
1417
* and then reconstruct the PusherBroadcaster
@@ -21,12 +24,11 @@ public function __invoke(Request $request)
2124
{
2225
$app = App::findById($request->header('x-app-id'));
2326

24-
$broadcaster = new PusherBroadcaster(new Pusher(
25-
$app->key,
26-
$app->secret,
27-
$app->id,
28-
[]
29-
));
27+
$broadcaster = $this->getPusherBroadcaster([
28+
'key' => $app->key,
29+
'secret' => $app->secret,
30+
'id' =>$app->id,
31+
]);
3032

3133
/*
3234
* Since the dashboard itself is already secured by the

src/Dashboard/Http/Controllers/SendMessage.php

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,15 @@
33
namespace BeyondCode\LaravelWebSockets\Dashboard\Http\Controllers;
44

55
use BeyondCode\LaravelWebSockets\Statistics\Rules\AppId;
6+
use BeyondCode\LaravelWebSockets\Contracts\PushesToPusher;
67
use Illuminate\Broadcasting\Broadcasters\PusherBroadcaster;
78
use Illuminate\Http\Request;
89
use Pusher\Pusher;
910

1011
class SendMessage
1112
{
13+
use PushesToPusher;
14+
1215
/**
1316
* Send the message to the requested channel.
1417
*
@@ -17,7 +20,7 @@ class SendMessage
1720
*/
1821
public function __invoke(Request $request)
1922
{
20-
$validated = $request->validate([
23+
$request->validate([
2124
'appId' => ['required', new AppId],
2225
'key' => 'required|string',
2326
'secret' => 'required|string',
@@ -26,30 +29,18 @@ public function __invoke(Request $request)
2629
'data' => 'required|json',
2730
]);
2831

29-
$this->getPusherBroadcaster($validated)->broadcast(
30-
[$validated['channel']],
31-
$validated['event'],
32-
json_decode($validated['data'], true)
33-
);
34-
35-
return 'ok';
36-
}
32+
$broadcaster = $this->getPusherBroadcaster([
33+
'key' => $request->key,
34+
'secret' => $request->secret,
35+
'id' => $request->appId,
36+
]);
3737

38-
/**
39-
* Get the pusher broadcaster for the current request.
40-
*
41-
* @param array $validated
42-
* @return \Illuminate\Broadcasting\Broadcasters\PusherBroadcaster
43-
*/
44-
protected function getPusherBroadcaster(array $validated): PusherBroadcaster
45-
{
46-
$pusher = new Pusher(
47-
$validated['key'],
48-
$validated['secret'],
49-
$validated['appId'],
50-
config('broadcasting.connections.pusher.options', [])
38+
$broadcaster->broadcast(
39+
[$request->channel],
40+
$request->event,
41+
json_decode($request->data, true)
5142
);
5243

53-
return new PusherBroadcaster($pusher);
44+
return 'ok';
5445
}
5546
}

src/WebSocketsServiceProvider.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,8 @@ protected function registerDashboardRoutes()
125125
], function () {
126126
Route::get('/', ShowDashboard::class)->name('dashboard');
127127
Route::get('/api/{appId}/statistics', [DashboardApiController::class, 'getStatistics'])->name('statistics');
128-
Route::post('auth', AuthenticateDashboard::class)->name('auth');
129-
Route::post('event', SendMessage::class)->name('send');
128+
Route::post('/auth', AuthenticateDashboard::class)->name('auth');
129+
Route::post('/event', SendMessage::class)->name('send');
130130
});
131131

132132
return $this;
@@ -140,7 +140,7 @@ protected function registerDashboardRoutes()
140140
protected function registerDashboardGate()
141141
{
142142
Gate::define('viewWebSocketsDashboard', function ($user = null) {
143-
return $this->app->environment(['local', 'testing']);
143+
return $this->app->environment('local');
144144
});
145145

146146
return $this;

tests/Dashboard/AuthTest.php

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
<?php
2+
3+
namespace BeyondCode\LaravelWebSockets\Tests\Dashboard;
4+
5+
use BeyondCode\LaravelWebSockets\Tests\TestCase;
6+
use BeyondCode\LaravelWebSockets\Tests\Models\User;
7+
use BeyondCode\LaravelWebSockets\Tests\Mocks\Message;
8+
9+
class AuthTest extends TestCase
10+
{
11+
/** @test */
12+
public function can_authenticate_dashboard_over_channel()
13+
{
14+
$connection = $this->getConnectedWebSocketConnection(['test-channel']);
15+
16+
$this->pusherServer->onOpen($connection);
17+
18+
$this->actingAs(factory(User::class)->create())
19+
->json('POST', route('laravel-websockets.auth'), [
20+
'socket_id' => $connection->socketId,
21+
'channel_name' => 'test-channel',
22+
], ['x-app-id' => '1234'])
23+
->seeJsonStructure([
24+
'auth',
25+
'channel_data',
26+
]);
27+
}
28+
29+
/** @test */
30+
public function can_authenticate_dashboard_over_private_channel()
31+
{
32+
$connection = $this->getWebSocketConnection();
33+
34+
$this->pusherServer->onOpen($connection);
35+
36+
$signature = "{$connection->socketId}:private-channel";
37+
38+
$hashedAppSecret = hash_hmac('sha256', $signature, $connection->app->secret);
39+
40+
$message = new Message([
41+
'event' => 'pusher:subscribe',
42+
'data' => [
43+
'auth' => "{$connection->app->key}:{$hashedAppSecret}",
44+
'channel' => 'private-channel',
45+
],
46+
]);
47+
48+
$this->pusherServer->onMessage($connection, $message);
49+
50+
$connection->assertSentEvent('pusher_internal:subscription_succeeded', [
51+
'channel' => 'private-channel',
52+
]);
53+
54+
$this->actingAs(factory(User::class)->create())
55+
->json('POST', route('laravel-websockets.auth'), [
56+
'socket_id' => $connection->socketId,
57+
'channel_name' => 'private-test-channel',
58+
], ['x-app-id' => '1234'])
59+
->seeJsonStructure([
60+
'auth',
61+
]);
62+
}
63+
64+
/** @test */
65+
public function can_authenticate_dashboard_over_presence_channel()
66+
{
67+
$connection = $this->getWebSocketConnection();
68+
69+
$this->pusherServer->onOpen($connection);
70+
71+
$channelData = [
72+
'user_id' => 1,
73+
'user_info' => [
74+
'name' => 'Marcel',
75+
],
76+
];
77+
78+
$signature = "{$connection->socketId}:presence-channel:".json_encode($channelData);
79+
80+
$message = new Message([
81+
'event' => 'pusher:subscribe',
82+
'data' => [
83+
'auth' => $connection->app->key.':'.hash_hmac('sha256', $signature, $connection->app->secret),
84+
'channel' => 'presence-channel',
85+
'channel_data' => json_encode($channelData),
86+
],
87+
]);
88+
89+
$this->pusherServer->onMessage($connection, $message);
90+
91+
$this->actingAs(factory(User::class)->create())
92+
->json('POST', route('laravel-websockets.auth'), [
93+
'socket_id' => $connection->socketId,
94+
'channel_name' => 'presence-channel',
95+
], ['x-app-id' => '1234'])
96+
->seeJsonStructure([
97+
'auth',
98+
]);
99+
}
100+
}

tests/Dashboard/DashboardTest.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,22 @@
33
namespace BeyondCode\LaravelWebSockets\Tests\Dashboard;
44

55
use BeyondCode\LaravelWebSockets\Tests\TestCase;
6+
use BeyondCode\LaravelWebSockets\Tests\Models\User;
67

78
class DashboardTest extends TestCase
89
{
910
/** @test */
1011
public function cant_see_dashboard_without_authorization()
1112
{
12-
config(['app.env' => 'production']);
13-
1413
$this->get(route('laravel-websockets.dashboard'))
1514
->assertResponseStatus(403);
1615
}
1716

1817
/** @test */
1918
public function can_see_dashboard()
2019
{
21-
$this->get(route('laravel-websockets.dashboard'))
20+
$this->actingAs(factory(User::class)->create())
21+
->get(route('laravel-websockets.dashboard'))
2222
->assertResponseOk()
2323
->see('WebSockets Dashboard');
2424
}

tests/Models/User.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
namespace BeyondCode\LaravelWebSockets\Tests\Models;
4+
5+
use Illuminate\Foundation\Auth\User as Authenticatable;
6+
7+
class User extends Authenticatable
8+
{
9+
protected $fillable = [
10+
'name', 'email', 'password',
11+
];
12+
13+
protected $hidden = [
14+
'password', 'remember_token',
15+
];
16+
}

tests/TestCase.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,12 @@ public function setUp(): void
4646
{
4747
parent::setUp();
4848

49+
$this->resetDatabase();
50+
51+
$this->loadLaravelMigrations(['--database' => 'sqlite']);
52+
53+
$this->withFactories(__DIR__.'/database/factories');
54+
4955
$this->pusherServer = $this->app->make(config('websockets.handlers.websocket'));
5056

5157
$this->channelManager = $this->app->make(ChannelManager::class);
@@ -69,6 +75,7 @@ protected function getPackageProviders($app)
6975
{
7076
return [
7177
\BeyondCode\LaravelWebSockets\WebSocketsServiceProvider::class,
78+
TestServiceProvider::class,
7279
];
7380
}
7481

@@ -79,6 +86,16 @@ protected function getEnvironmentSetUp($app)
7986
{
8087
$app['config']->set('app.key', 'wslxrEFGWY6GfGhvN9L3wH3KSRJQQpBD');
8188

89+
$app['config']->set('auth.providers.users.model', Models\User::class);
90+
91+
$app['config']->set('database.default', 'sqlite');
92+
93+
$app['config']->set('database.connections.sqlite', [
94+
'driver' => 'sqlite',
95+
'database' => __DIR__.'/database.sqlite',
96+
'prefix' => '',
97+
]);
98+
8299
$app['config']->set('websockets.apps', [
83100
[
84101
'name' => 'Test App',
@@ -307,4 +324,14 @@ protected function getPublishClient()
307324
->make(ReplicationInterface::class)
308325
->getPublishClient();
309326
}
327+
328+
/**
329+
* Reset the database.
330+
*
331+
* @return void
332+
*/
333+
protected function resetDatabase()
334+
{
335+
file_put_contents(__DIR__.'/database.sqlite', null);
336+
}
310337
}

tests/TestServiceProvider.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
namespace BeyondCode\LaravelWebSockets\Tests;
4+
5+
use Illuminate\Support\Facades\Gate;
6+
use Illuminate\Support\ServiceProvider;
7+
8+
class TestServiceProvider extends ServiceProvider
9+
{
10+
/**
11+
* Boot the service provider.
12+
*
13+
* @return void
14+
*/
15+
public function boot()
16+
{
17+
Gate::define('viewWebSocketsDashboard', function ($user = null) {
18+
return ! is_null($user);
19+
});
20+
}
21+
22+
/**
23+
* Register the service provider.
24+
*
25+
* @return void
26+
*/
27+
public function register()
28+
{
29+
//
30+
}
31+
}

0 commit comments

Comments
 (0)