Laravel Framework Deserialization Vulnerability
Research is free — Hunters explains how the bug works, the root-cause code pattern, how the fix addresses it, and how to test whether a target is affected, in chat. Investigate & write exploit is a paid run — the engine reads the advisory and fix commits, then builds and validates a working proof-of-concept exploit with reproduction steps.
Affected versions
5.7.0 → fixed in 6.20.44
Details
The Illuminate component of Laravel Framework 5.7.x has a deserialization vulnerability that can lead to remote code execution if the content is controllable, related to the `__destruct` method of the PendingCommand class in `PendingCommand.php`.
The fix
Release delta 5.7.0 → 6.20.44 (contains the fix)
tests/Database/DatabaseEloquentModelTest.php+42 −42
@@ -227,11 +227,11 @@ public function testWithMethodCallsQueryBuilderCorrectlyWithArray()public function testUpdateProcess(){-$model = $this->getMockBuilder('Illuminate\Tests\Database\EloquentModelStub')->setMethods(['newQueryWithoutScopes', 'updateTimestamps'])->getMock();+$model = $this->getMockBuilder('Illuminate\Tests\Database\EloquentModelStub')->setMethods(['newModelQuery', 'updateTimestamps'])->getMock();$query = m::mock('Illuminate\Database\Eloquent\Builder');$query->shouldReceive('where')->once()->with('id', '=', 1);$query->shouldReceive('update')->once()->with(['name' => 'taylor'])->andReturn(1);-$model->expects($this->once())->method('newQueryWithoutScopes')->will($this->returnValue($query));+$model->expects($this->once())->method('newModelQuery')->will($this->returnValue($query));$model->expects($this->once())->method('updateTimestamps');$model->setEventDispatcher($events = m::mock('Illuminate\Contracts\Events\Dispatcher'));$events->shouldReceive('until')->once()->with('eloquent.saving: '.get_class($model), $model)->andReturn(true);@@ -250,11 +250,11 @@ public function testUpdateProcess()public function testUpdateProcessDoesntOverrideTimestamps(){-$model = $this->getMockBuilder('Illuminate\Tests\Database\EloquentModelStub')->setMethods(['newQueryWithoutScopes'])->getMock();+$model = $this->getMockBuilder('Illuminate\Tests\Database\EloquentModelStub')->setMethods(['newModelQuery'])->getMock();$query = m::mock('Illuminate\Database\Eloquent\Builder');$query->shouldReceive('where')->once()->with('id', '=', 1);$query->shouldReceive('update')->once()->with(['created_at' => 'foo', 'updated_at' => 'bar'])->andReturn(1);-$model->expects($this->once())->method('newQueryWithoutScopes')->will($this->returnValue($query));+$model->expects($this->once())->method('newModelQuery')->will($this->returnValue($query));$model->setEventDispatcher($events = m::mock('Illuminate\Contracts\Events\Dispatcher'));$events->shouldReceive('until');$events->shouldReceive('fire');@@ -269,9 +269,9 @@ public function testUpdateProcessDoesntOverrideTimestamps()public function testSaveIsCancelledIfSavingEventReturnsFalse(){-$model = $this->getMockBuilder('Illuminate\Tests\Database\EloquentModelStub')->setMethods(['newQueryWithoutScopes'])->getMock();+$model = $this->getMockBuilder('Illuminate\Tests\Database\EloquentModelStub')->setMethods(['newModelQuery'])->getMock();$query = m::mock('Illuminate\Database\Eloquent\Builder');-$model->expects($this->once())->method('newQueryWithoutScopes')->will($this->returnValue($query));+$model->expects($this->once())->method('newModelQuery')->will($this->returnValue($query));$model->setEventDispatcher($events = m::mock('Illuminate\Contracts\Events\Dispatcher'));$events->shouldReceive('until')->once()->with('eloquent.saving: '.get_class($model), $model)->andReturn(false);$model->exists = true;@@ -281,9 +281,9 @@ public function testSaveIsCancelledIfSavingEventReturnsFalse()public function testUpdateIsCancelledIfUpdatingEventReturnsFalse(){-$model = $this->getMockBuilder('Illuminate\Tests\Database\EloquentModelStub')->setMethods(['newQueryWithoutScopes'])->getMock();+$model = $this->getMockBuilder('Illuminate\Tests\Database\EloquentModelStub')->setMethods(['newModelQuery'])->getMock();$query = m::mock('Illuminate\Database\Eloquent\Builder');-$model->expects($this->once())->method('newQueryWithoutScopes')->will($this->returnValue($query));+$model->expects($this->once())->method('newModelQuery')->will($this->returnValue($query));$model->setEventDispatcher($events = m::mock('Illuminate\Contracts\Events\Dispatcher'));$events->shouldReceive('until')->once()->with('eloquent.saving: '.get_class($model), $model)->andReturn(true);$events->shouldReceive('until')->once()->with('eloquent.updating: '.get_class($model), $model)->andReturn(false);@@ -295,9 +295,9 @@ public function testUpdateIsCancelledIfUpdatingEventReturnsFalse()public function testEventsCanBeFiredWithCustomEventObjects(){-$model = $this->getMockBuilder('Illuminate\Tests\Database\EloquentModelEventObjectStub')->setMethods(['newQueryWithoutScopes'])->getMock();+$model = $this->getMockBuilder('Illuminate\Tests\Database\EloquentModelEventObjectStub')->setMethods(['newModelQuery'])->getMock();$query = m::mock('Illuminate\Database\Eloquent\Builder');-$model->expects($this->once())->method('newQueryWithoutScopes')->will($this->returnValue($query));+$model->expects($this->once())->method('newModelQuery')->will($this->returnValue($query));$model->setEventDispatcher($events = m::mock('Illuminate\Contracts\Events\Dispatcher'));$events->shouldReceive('until')->once()->with(m::type(EloquentModelSavingEventStub::class))->andReturn(false);$model->exists = true;@@ -307,12 +307,12 @@ public function testEventsCanBeFiredWithCustomEventObjects()public function testUpdateProcessWithoutTimestamps(){-$model = $this->getMockBuilder('Illuminate\Tests\Database\EloquentModelEventObjectStub')->setMethods(['newQueryWithoutScopes', 'updateTimestamps', 'fireModelEvent'])->getMock();+$model = $this->getMockBuilder('Illuminate\Tests\Database\EloquentModelEventObjectStub')->setMethods(['newModelQuery', 'updateTimestamps', 'fireModelEvent'])->getMock();$model->timestamps = false;$query = m::mock('Illuminate\Database\Eloquent\Builder');$query->shouldReceive('where')->once()->with('id', '=', 1);$query->shouldReceive('update')->once()->with(['name' => 'taylor'])->andReturn(1);-$model->expects($this->once())->method('newQueryWithoutScopes')->will($this->returnValue($query));+$model->expects($this->once())->method('newModelQuery')->will($this->returnValue($query));$model->expects($this->never())->method('updateTimestamps');$model->expects($this->any())->method('fireModelEvent')->will($this->returnValue(true));@@ -325,11 +325,11 @@ public function testUpdateProcessWithoutTimestamps()public function testUpdateUsesOldPrimaryKey(){-$model = $this->getMockBuilder('Illuminate\Tests\Database\EloquentModelStub')->setMethods(['newQueryWithoutScopes', 'updateTimestamps'])->getMock();+$model = $this->getMockBuilder('Illuminate\Tests\Database\EloquentModelStub')->setMethods(['newModelQuery', 'updateTimestamps'])->getMock();$query = m::mock('Illuminate\Database\Eloquent\Builder');$query->shouldReceive('where')->once()->with('id', '=', 1);$query->shouldReceive('update')->once()->with(['id' => 2, 'foo' => 'bar'])->andReturn(1);-$model->expects($this->once())->method('newQueryWithoutScopes')->will($this->returnValue($query));+$model->expects($this->once())->method('newModelQuery')->will($this->returnValue($query));$model->expects($this->once())->method('updateTimestamps');$model->setEventDispatcher($events = m::mock('Illuminate\Contracts\Events\Dispatcher'));$events->shouldReceive('until')->once()->with('eloquent.saving: '.get_class($model), $model)->andReturn(true);@@ -456,11 +456,11 @@ public function testFromDateTime()public function testInsertProcess(){-$model = $this->getMockBuilder('Illuminate\Tests\Database\EloquentModelStub')->setMethods(['newQueryWithoutScopes', 'updateTimestamps', 'refresh'])->getMock();+$model = $this->getMockBuilder('Illuminate\Tests\Database\EloquentModelStub')->setMethods(['newModelQuery', 'updateTimestamps', 'refresh'])->getMock();$query = m::mock('Illuminate\Database\Eloquent\Builder');$query->shouldReceive('insertGetId')->once()->with(['name' => 'taylor'], 'id')->andReturn(1);$query->shouldReceive('getConnection')->once();-$model->expects($this->once())->method('newQueryWithoutScopes')->will($this->returnValue($query));+$model->expects($this->once())->method('newModelQuery')->will($this->returnValue($query));$model->expects($this->once())->method('updateTimestamps');$model->setEventDispatcher($events = m::mock('Illuminate\Contracts\Events\Dispatcher'));@@ -475,11 +475,11 @@ public function testInsertProcess()$this->assertEquals(1, $model->id);$this->assertTrue($model->exists);-$model = $this->getMockBuilder('Illuminate\Tests\Database\EloquentModelStub')->setMethods(['newQueryWithoutScopes', 'updateTimestamps', 'refresh'])->getMock();+$model = $this->getMockBuilder('Illuminate\Tests\Database\EloquentModelStub')->setMethods(['newModelQuery', 'updateTimestamps', 'refresh'])->getMock();$query = m::mock('Illuminate\Database\Eloquent\Builder');$query->shouldReceive('insert')->once()->with(['name' => 'taylor']);$query->shouldReceive('getConnection')->once();-$model->expects($this->once())->method('newQueryWithoutScopes')->will($this->returnValue($query));+$model->expects($this->once())->method('newModelQuery')->will($this->returnValue($query));$model->expects($this->once())->method('updateTimestamps');$model->setIncrementing(false);@@ -498,10 +498,10 @@ public function testInsertProcess()public function testInsertIsCancelledIfCreatingEventReturnsFalse(){-$model = $this->getMockBuilder('Illuminate\Tests\Database\EloquentModelStub')->setMethods(['newQueryWithoutScopes'])->getMock();+$model = $this->getMockBuilder('Illuminate\Tests\Database\EloquentModelStub')->setMethods(['newModelQuery'])->getMock();$query = m::mock('Illuminate\Database\Eloquent\Builder');$query->shouldReceive('getConnection')->once();-$model->expects($this->once())->method('newQueryWithoutScopes')->will($this->returnValue($query));+$model->expects($this->once())->method('newModelQuery')->will($this->returnValue($query));$model->setEventDispatcher($events = m::mock('Illuminate\Contracts\Events\Dispatcher'));$events->shouldReceive('until')->once()->with('eloquent.saving: '.get_class($model), $model)->andReturn(true);$events->shouldReceive('until')->once()->with('eloquent.creating: '.get_class($model), $model)->andReturn(false);@@ -512,11 +512,11 @@ public function testInsertIsCancelledIfCreatingEventReturnsFalse()public function testDeleteProperlyDeletesModel(){-$model = $this->getMockBuilder('Illuminate\Database\Eloquent\Model')->setMethods(['newQueryWithoutScopes', 'updateTimestamps', 'touchOwners'])->getMock();+$model = $this->getMockBuilder('Illuminate\Database\Eloquent\Model')->setMethods(['newModelQuery', 'updateTimestamps', 'touchOwners'])->getMock();$query = m::mock('Illuminate\Database\Eloquent\Builder');$query->shouldReceive('where')->once()->with('id', '=', 1)->andReturn($query);$query->shouldReceive('delete')->once();-$model->expects($this->once())->method('newQueryWithoutScopes')->will($this->returnValue($query));+$model->expects($this->once())->method('newModelQuery')->will($this->returnValue($query));$model->expects($this->once())->method('touchOwners');$model->exists = true;$model->id = 1;@@ -525,11 +525,11 @@ public function testDeleteProperlyDeletesModel()public function testPushNoRelations(){-$model = $this->getMockBuilder('Illuminate\Tests\Database\EloquentModelStub')->setMethods(['newQueryWithoutScopes', 'updateTimestamps', 'refresh'])->getMock();+$model = $this->getMockBuilder('Illuminate\Tests\Database\EloquentModelStub')->setMethods(['newModelQuery', 'updateTimestamps', 'refresh'])->getMock();$query = m::mock('Illuminate\Database\Eloquent\Builder');$query->shouldReceive('insertGetId')->once()->with(['name' => 'taylor'], 'id')->andReturn(1);$query->shouldReceive('getConnection')->once();-$model->expects($this->once())->method('newQueryWithoutScopes')->will($this->returnValue($query));+$model->expects($this->once())->method('newModelQuery')->will($this->returnValue($query));$model->expects($this->once())->method('updateTimestamps');$model->name = 'taylor';@@ -542,11 +542,11 @@ public function testPushNoRelations()public function testPushEmptyOneRelation(){-$model = $this->getMockBuilder('Illuminate\Tests\Database\EloquentModelStub')->setMethods(['newQueryWithoutScopes', 'updateTimestamps', 'refresh'])->getMock();+$model = $this->getMockBuilder('Illuminate\Tests\Database\EloquentModelStub')->setMethods(['newModelQuery', 'updateTimestamps', 'refresh'])->getMock();$query = m::mock('Illuminate\Database\Eloquent\Builder');$query->shouldReceive('insertGetId')->once()->with(['name' => 'taylor'], 'id')->andReturn(1);$query->shouldReceive('getConnection')->once();-$model->expects($this->once())->method('newQueryWithoutScopes')->will($this->returnValue($query));+$model->expects($this->once())->method('newModelQuery')->will($this->returnValue($query));$model->expects($this->once())->method('updateTimestamps');$model->name = 'taylor';@@ -561,20 +561,20 @@ public function testPushEmptyOneRelation()public function testPushOneRelation(){-$related1 = $this->getMockBuilder('Illuminate\Tests\Database\EloquentModelStub')->setMethods(['newQueryWithoutScopes', 'updateTimestamps', 'refresh'])->getMock();+$related1 = $this->getMockBuilder('Illuminate\Tests\Database\EloquentModelStub')->setMethods(['newModelQuery', 'updateTimestamps', 'refresh'])->getMock();$query = m::mock('Illuminate\Database\Eloquent\Builder');$query->shouldReceive('insertGetId')->once()->with(['name' => 'related1'], 'id')->andReturn(2);$query->shouldReceive('getConnection')->once();-$related1->expects($this->once())->method('newQueryWithoutScopes')->will($this->returnValue($query));+$related1->expects($this->once())->method('newModelQuery')->will($this->returnValue($query));$related1->expects($this->once())->method('updateTimestamps');$related1->name = 'related1';$related1->exists = false;-$model = $this->getMockBuilder('Illuminate\Tests\Database\EloquentModelStub')->setMethods(['newQueryWithoutScopes', 'updateTimestamps', 'refresh'])->getMock();+$model = $this->getMockBuilder('Illuminate\Tests\Database\EloquentModelStub')->setMethods(['newModelQuery', 'updateTimestamps', 'refresh'])->getMock();$query = m::mock('Illuminate\Database\Eloquent\Builder');$query->shouldReceive('insertGetId')->once()->with(['name' => 'taylor'], 'id')->andReturn(1);$query->shouldReceive('getConnection')->once();-$model->expects($this->once())->method('newQueryWithoutScopes')->will($this->returnValue($query));+$model->expects($this->once())->method('newModelQuery')->will($this->returnValue($query));$model->expects($this->once())->method('updateTimestamps');$model->name = 'taylor';@@ -592,11 +592,11 @@ public function testPushOneRelation()public function testPushEmptyManyRelation(){-$model = $this->getMockBuilder('Illuminate\Tests\Database\EloquentModelStub')->setMethods(['newQueryWithoutScopes', 'updateTimestamps', 'refresh'])->getMock();+$model = $this->getMockBuilder('Illuminate\Tests\Database\EloquentModelStub')->setMethods(['newModelQuery', 'updateTimestamps', 'refresh'])->getMock();$query = m::mock('Illuminate\Database\Eloquent\Builder');$query->shouldReceive('insertGetId')->once()->with(['name' => 'taylor'], 'id')->andReturn(1);$query->shouldReceive('getConnection')->once();-$model->expects($this->once())->method('newQueryWithoutScopes')->will($this->returnValue($query));+$model->expects($this->once())->method('newModelQuery')->will($this->returnValue($query));$model->expects($this->once())->method('updateTimestamps');$model->name = 'taylor';@@ -611,29 +611,29 @@ public function testPushEmptyManyRelation()public function testPushManyRelation(){-$related1 = $this->getMockBuilder('Illuminate\Tests\Database\EloquentModelStub')->setMethods(['newQueryWithoutScopes', 'updateTimestamps', 'refresh'])->getMock();+$related1 = $this->getMockBuilder('Illuminate\Tests\Database\EloquentModelStub')->setMethods(['newModelQuery', 'updateTimestamps', 'refresh'])->getMock();$query = m::mock('Illuminate\Database\Eloquent\Builder');$query->shouldReceive('insertGetId')->once()->with(['name' => 'related1'], 'id')->andReturn(2);$query->shouldReceive('getConnection')->once();-$related1->expects($this->once())->method('newQueryWithoutScopes')->will($this->returnValue($query));+$related1->expects($this->once())->method('newModelQuery')->will($this->returnValue($query));$related1->expects($this->once())->method('updateTimestamps');$related1->name = 'related1';$related1->exists = false;-$related2 = $this->getMockBuilder('Illuminate\Tests\Database\EloquentModelStub')->setMethods(['newQueryWithoutScopes', 'updateTimestamps', 'refresh'])->getMock();+$related2 = $this->getMockBuilder('Illuminate\Tests\Database\EloquentModelStub')->setMethods(['newModelQuery', 'updateTimestamps', 'refresh'])->getMock();$query = m::mock('Illuminate\Database\Eloquent\Builder');$query->shouldReceive('insertGetId')->once()->with(['name' => 'related2'], 'id')->andReturn(3);$query->shouldReceive('getConnection')->once();-$related2->expects($this->once())->method('newQueryWithoutScopes')->will($this->returnValue($query));+$related2->expects($this->once())->method('newModelQuery')->will($this->returnValue($query));$related2->expects($this->once())->method('updateTimestamps');$related2->name = 'related2';$related2->exists = false;-$model = $this->getMockBuilder('Illuminate\Tests\Database\EloquentModelStub')->setMethods(['newQueryWithoutScopes', 'updateTimestamps', 'refresh'])->getMock();+$model = $this->getMockBuilder('Illuminate\Tests\Database\EloquentModelStub')->setMethods(['newModelQuery', 'updateTimestamps', 'refresh'])->getMock();$query = m::mock('Illuminate\Database\Eloquent\Builder');$query->shouldReceive('insertGetId')->once()->with(['name' => 'taylor'], 'id')->andReturn(1);$query->shouldReceive('getConnection')->once();-$model->expects($this->once())->method('newQueryWithoutScopes')->will($this->returnValue($query));+$model->expects($this->once())->method('newModelQuery')->will($this->returnValue($query));$model->expects($this->once())->method('updateTimestamps');$model->name = 'taylor';@@ -1619,11 +1619,11 @@ public function testNonExistingAttributeWithInternalMethodNameDoesntCallMethod()public function testIntKeyTypePreserved(){-$model = $this->getMockBuilder('Illuminate\Tests\Database\EloquentModelStub')->setMethods(['newQueryWithoutScopes', 'updateTimestamps', 'refresh'])->getMock();+$model = $this->getMockBuilder('Illuminate\Tests\Database\EloquentModelStub')->setMethods(['newModelQuery', 'updateTimestamps', 'refresh'])->getMock();$query = m::mock('Illuminate\Database\Eloquent\Builder');$query->shouldReceive('insertGetId')->once()->with([], 'id')->andReturn(1);$query->shouldReceive('getConnection')->once();-$model->expects($this->once())->method('newQueryWithoutScopes')->will($this->returnValue($query));+$model->expects($this->once())->method('newModelQuery')->will($this->returnValue($query));$this->assertTrue($model->save());$this->assertEquals(1, $model->id);@@ -1631,11 +1631,11 @@ public function testIntKeyTypePreserved()public function testStringKeyTypePreserved(){-$model = $this->getMockBuilder('Illuminate\Tests\Database\EloquentKeyTypeModelStub')->setMethods(['newQueryWithoutScopes', 'updateTimestamps', 'refresh'])->getMock();+$model = $this->getMockBuilder('Illuminate\Tests\Database\EloquentKeyTypeModelStub')->setMethods(['newModelQuery', 'updateTimestamps', 'refresh'])->getMock();$query = m::mock('Illuminate\Database\Eloquent\Builder');$query->shouldReceive('insertGetId')->once()->with([], 'id')->andReturn('string id');$query->shouldReceive('getConnection')->once();-$model->expects($this->once())->method('newQueryWithoutScopes')->will($this->returnValue($query));+$model->expects($this->once())->method('newModelQuery')->will($this->returnValue($query));$this->assertTrue($model->save());$this->assertEquals('string id', $model->id);
tests/Broadcasting/PusherBroadcasterTest.php+253 −0
@@ -0,0 +1,253 @@+<?php++namespace Illuminate\Tests\Broadcasting;++use Illuminate\Broadcasting\Broadcasters\PusherBroadcaster;+use Mockery as m;+use PHPUnit\Framework\TestCase;++class PusherBroadcasterTest extends TestCase+{+/**+* @var \Illuminate\Broadcasting\Broadcasters\PusherBroadcaster+*/+public $broadcaster;++public $pusher;++public function setUp()+{+parent::setUp();++$this->pusher = m::mock('Pusher\Pusher');+$this->broadcaster = m::mock(PusherBroadcaster::class, [$this->pusher])->makePartial();+}++/**+* @dataProvider channelsProvider+*/+public function testChannelNameNormalization($requestChannelName, $normalizedName)+{+$this->assertEquals(+$normalizedName,+$this->broadcaster->normalizeChannelName($requestChannelName)+);+}++/**+* @dataProvider channelsProvider+*/+public function testIsGuardedChannel($requestChannelName, $_, $guarded)+{+$this->assertEquals(+$guarded,+$this->broadcaster->isGuardedChannel($requestChannelName)+);+}++public function testAuthCallValidAuthenticationResponseWithPrivateChannelWhenCallbackReturnTrue()+{+$this->broadcaster->channel('test', function() {+return true;+});++$this->broadcaster->shouldReceive('validAuthenticationResponse')+->once();++$this->broadcaster->auth(+$this->getMockRequestWithUserForChannel('private-test')+);+}++/**+* @expectedException \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException+*/+public function testAuthThrowAccessDeniedHttpExceptionWithPrivateChannelWhenCallbackReturnFalse()+{+$this->broadcaster->channel('test', function() {+return false;+});++$this->broadcaster->auth(+$this->getMockRequestWithUserForChannel('private-test')+);+}++/**+* @expectedException \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException+*/+public function testAuthThrowAccessDeniedHttpExceptionWithPrivateChannelWhenRequestUserNotFound()+{+$this->broadcaster->channel('test', function() {+return true;+});++$this->broadcaster->auth(+$this->getMockRequestWithoutUserForChannel('private-test')+);+}++public function testAuthCallValidAuthenticationResponseWithPresenceChannelWhenCallbackReturnAnArray()+{+$returnData = [1, 2, 3, 4];+$this->broadcaster->channel('test', function() use ($returnData) {+return $returnData;+});++$this->broadcaster->shouldReceive('validAuthenticationResponse')+->once();++$this->broadcaster->auth(+$this->getMockRequestWithUserForChannel('presence-test')+);+}++/**+* @expectedException \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException+*/+public function testAuthThrowAccessDeniedHttpExceptionWithPresenceChannelWhenCallbackReturnNull()+{+$this->broadcaster->channel('test', function() {+return;+});++$this->broadcaster->auth(+$this->getMockRequestWithUserForChannel('presence-test')+);+}++/**+* @expectedException \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException+*/+public function testAuthThrowAccessDeniedHttpExceptionWithPresenceChannelWhenRequestUserNotFound()+{+$this->broadcaster->channel('test', function() {+return [1, 2, 3, 4];+});++$this->broadcaster->auth(+$this->getMockRequestWithoutUserForChannel('presence-test')+);+}++public function testValidAuthenticationResponseCallPusherSocketAuthMethodWithPrivateChannel()+{+$request = $this->getMockRequestWithUserForChannel('private-test');++$data = [+'auth' => 'abcd:efgh'+];++$this->pusher->shouldReceive('socket_auth')+->once()+->andReturn(json_encode($data));++$this->assertEquals(+$data,+$this->broadcaster->validAuthenticationResponse($request, true)+);+}++public function testValidAuthenticationResponseCallPusherPresenceAuthMethodWithPresenceChannel()+{+$request = $this->getMockRequestWithUserForChannel('presence-test');++$data = [+'auth' => 'abcd:efgh',+'channel_data' => [+'user_id' => 42,+'user_info' => [1, 2, 3, 4],+],+];++$this->pusher->shouldReceive('presence_auth')+->once()+->andReturn(json_encode($data));++$this->assertEquals(+$data,+$this->broadcaster->validAuthenticationResponse($request, true)+);+}++public function channelsProvider()+{+$prefixesInfos = [+['prefix' => 'private-', 'guarded' => true],+['prefix' => 'presence-', 'guarded' => true],+['prefix' => '', 'guarded' => false],+];++$channels = [+'test',+'test-channel',+'test-private-channel',+'test-presence-channel',+'abcd.efgh',+'abcd.efgh.ijkl',+'test.{param}',+'test-{param}',+'{a}.{b}',+'{a}-{b}',+'{a}-{b}.{c}',+];++$tests = [];+foreach ($prefixesInfos as $prefixInfos) {+foreach ($channels as $channel) {+$tests[] = [+$prefixInfos['prefix'] . $channel,+$channel,+$prefixInfos['guarded'],+];+}+}++$tests[] = ['private-private-test' , 'private-test', true];+$tests[] = ['private-presence-test' , 'presence-test', true];+$tests[] = ['presence-private-test' , 'private-test', true];+$tests[] = ['presence-presence-test' , 'presence-test', true];+$tests[] = ['public-test' , 'public-test', false];++return $tests;+}++/**+* @param string $channel+* @return \Illuminate\Http\Request+*/+protected function getMockRequestWithUserForChannel($channel)+{+$request = m::mock(\Illuminate\Http\Request::class);+$request->channel_name = $channel;+$request->socket_id = 'abcd.1234';++$request->shouldReceive('input')+->with('callback', false)+->andReturn(false);++$user = m::mock('User');+$user->shouldReceive('getAuthIdentifier')+->andReturn(42);++$request->shouldReceive('user')+->andReturn($user);++return $request;+}++/**+* @param string $channel+* @return \Illuminate\Http\Request+*/+protected function getMockRequestWithoutUserForChannel($channel)+{+$request = m::mock(\Illuminate\Http\Request::class);+$request->channel_name = $channel;++$request->shouldReceive('user')+->andReturn(null);++return $request;+}+}
src/Illuminate/Notifications/composer.json+10 −10
@@ -15,14 +15,14 @@],"require": {"php": "^7.1.3",-"illuminate/broadcasting": "5.7.*",-"illuminate/bus": "5.7.*",-"illuminate/container": "5.7.*",-"illuminate/contracts": "5.7.*",-"illuminate/filesystem": "5.7.*",-"illuminate/mail": "5.7.*",-"illuminate/queue": "5.7.*",-"illuminate/support": "5.7.*"+"illuminate/broadcasting": "5.8.*",+"illuminate/bus": "5.8.*",+"illuminate/container": "5.8.*",+"illuminate/contracts": "5.8.*",+"illuminate/filesystem": "5.8.*",+"illuminate/mail": "5.8.*",+"illuminate/queue": "5.8.*",+"illuminate/support": "5.8.*"},"autoload": {"psr-4": {@@ -31,12 +31,12 @@},"extra": {"branch-alias": {-"dev-master": "5.7-dev"+"dev-master": "5.8-dev"}},"suggest": {"guzzlehttp/guzzle": "Required to use the Slack transport (^6.0)",-"illuminate/database": "Required to use the database transport (5.7.*).",+"illuminate/database": "Required to use the database transport (5.8.*).","nexmo/client": "Required to use the Nexmo transport (^1.0)."},"config": {
tests/Broadcasting/RedisBroadcasterTest.php+241 −0
@@ -0,0 +1,241 @@+<?php++namespace Illuminate\Tests\Broadcasting;++use Illuminate\Broadcasting\Broadcasters\RedisBroadcaster;+use Mockery as m;+use PHPUnit\Framework\TestCase;++class RedisBroadcasterTest extends TestCase+{+/**+* @var \Illuminate\Broadcasting\Broadcasters\RedisBroadcaster+*/+public $broadcaster;++public function setUp()+{+parent::setUp();++$this->broadcaster = m::mock(RedisBroadcaster::class)->makePartial();+}++public function tearDown()+{+m::close();+}++/**+* @dataProvider channelsProvider+*/+public function testChannelNameNormalization($requestChannelName, $normalizedName)+{+$this->assertEquals(+$normalizedName,+$this->broadcaster->normalizeChannelName($requestChannelName)+);+}++/**+* @dataProvider channelsProvider+*/+public function testIsGuardedChannel($requestChannelName, $_, $guarded)+{+$this->assertEquals(+$guarded,+$this->broadcaster->isGuardedChannel($requestChannelName)+);+}++public function testAuthCallValidAuthenticationResponseWithPrivateChannelWhenCallbackReturnTrue()+{+$this->broadcaster->channel('test', function() {+return true;+});++$this->broadcaster->shouldReceive('validAuthenticationResponse')+->once();++$this->broadcaster->auth(+$this->getMockRequestWithUserForChannel('private-test')+);+}++/**+* @expectedException \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException+*/+public function testAuthThrowAccessDeniedHttpExceptionWithPrivateChannelWhenCallbackReturnFalse()+{+$this->broadcaster->channel('test', function() {+return false;+});++$this->broadcaster->auth(+$this->getMockRequestWithUserForChannel('private-test')+);+}++/**+* @expectedException \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException+*/+public function testAuthThrowAccessDeniedHttpExceptionWithPrivateChannelWhenRequestUserNotFound()+{+$this->broadcaster->channel('test', function() {+return true;+});++$this->broadcaster->auth(+$this->getMockRequestWithoutUserForChannel('private-test')+);+}++public function testAuthCallValidAuthenticationResponseWithPresenceChannelWhenCallbackReturnAnArray()+{+$returnData = [1, 2, 3, 4];+$this->broadcaster->channel('test', function() use ($returnData) {+return $returnData;+});++$this->broadcaster->shouldReceive('validAuthenticationResponse')+->once();++$this->broadcaster->auth(+$this->getMockRequestWithUserForChannel('presence-test')+);+}++/**+* @expectedException \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException+*/+public function testAuthThrowAccessDeniedHttpExceptionWithPresenceChannelWhenCallbackReturnNull()+{+$this->broadcaster->channel('test', function() {+return;+});++$this->broadcaster->auth(+$this->getMockRequestWithUserForChannel('presence-test')+);+}++/**+* @expectedException \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException+*/+public function testAuthThrowAccessDeniedHttpExceptionWithPresenceChannelWhenRequestUserNotFound()+{+$this->broadcaster->channel('test', function() {+return [1, 2, 3, 4];+});++$this->broadcaster->auth(+$this->getMockRequestWithoutUserForChannel('presence-test')+);+}++public function testValidAuthenticationResponseWithPrivateChannel()+{+$request = $this->getMockRequestWithUserForChannel('private-test');++$this->assertEquals(+json_encode(true),+$this->broadcaster->validAuthenticationResponse($request, true)+);+}++public function testValidAuthenticationResponseWithPresenceChannel()+{+$request = $this->getMockRequestWithUserForChannel('presence-test');++$this->assertEquals(+json_encode([+'channel_data' => [+'user_id' => 42,+'user_info' => [+'a' => 'b',+'c' => 'd',+],+],+]),+$this->broadcaster->validAuthenticationResponse($request, [+'a' => 'b',+'c' => 'd'+])+);+}++public function channelsProvider()+{+$prefixesInfos = [+['prefix' => 'private-', 'guarded' => true],+['prefix' => 'presence-', 'guarded' => true],+['prefix' => '', 'guarded' => false],+];++$channels = [+'test',+'test-channel',+'test-private-channel',+'test-presence-channel',+'abcd.efgh',+'abcd.efgh.ijkl',+'test.{param}',+'test-{param}',+'{a}.{b}',+'{a}-{b}',+'{a}-{b}.{c}',+];++$tests = [];+foreach ($prefixesInfos as $prefixInfos) {+foreach ($channels as $channel) {+$tests[] = [+$prefixInfos['prefix'] . $channel,+$channel,+$prefixInfos['guarded'],+];+}+}++$tests[] = ['private-private-test' , 'private-test', true];+$tests[] = ['private-presence-test' , 'presence-test', true];+$tests[] = ['presence-private-test' , 'private-test', true];+$tests[] = ['presence-presence-test' , 'presence-test', true];+$tests[] = ['public-test' , 'public-test', false];++return $tests;+}++/**+* @param string $channel+* @return \Illuminate\Http\Request+*/+protected function getMockRequestWithUserForChannel($channel)+{+$request = m::mock(\Illuminate\Http\Request::class);+$request->channel_name = $channel;++$user = m::mock('User');+$user->shouldReceive('getAuthIdentifier')+->andReturn(42);++$request->shouldReceive('user')+->andReturn($user);++return $request;+}++/**+* @param string $channel+* @return \Illuminate\Http\Request+*/+protected function getMockRequestWithoutUserForChannel($channel)+{+$request = m::mock(\Illuminate\Http\Request::class);+$request->channel_name = $channel;++$request->shouldReceive('user')+->andReturn(null);++return $request;+}+}src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php | 5 +++--1 file changed, 3 insertions(+), 2 deletions(-)
tests/Broadcasting/BroadcasterTest.php+140 −0
@@ -94,6 +94,131 @@ public function testNotFoundThrowsHttpException()};$broadcaster->extractAuthParameters('asd.{model}', 'asd.1', $callback);}++public function testCanRegisterChannelsWithoutOptions()+{+$broadcaster = new FakeBroadcaster;++$broadcaster->channel('somechannel', function () {});+}++public function testCanRegisterChannelsWithOptions()+{+$broadcaster = new FakeBroadcaster;++$options = [ 'a' => [ 'b', 'c' ] ];+$broadcaster->channel('somechannel', function () {}, $options);++$this->assertEquals(+$options,+$broadcaster->retrieveChannelOptions('somechannel')+);+}++public function testRetrieveUserWithoutGuard()+{+$broadcaster = new FakeBroadcaster;++$broadcaster->channel('somechannel', function () {});++$request = m::mock(\Illuminate\Http\Request::class);+$request->shouldReceive('user')+->once()+->withNoArgs()+->andReturn(new DummyUser);++$this->assertInstanceOf(+DummyUser::class,+$broadcaster->retrieveUser($request, 'somechannel')+);+}++public function testRetrieveUserWithOneGuardUsingAStringForSpecifyingGuard()+{+$broadcaster = new FakeBroadcaster;++$broadcaster->channel('somechannel', function () {}, ['guards' => 'myguard']);++$request = m::mock(\Illuminate\Http\Request::class);+$request->shouldReceive('user')+->once()+->with('myguard')+->andReturn(new DummyUser);++$this->assertInstanceOf(+DummyUser::class,+$broadcaster->retrieveUser($request, 'somechannel')+);+}++public function testRetrieveUserWithMultipleGuardsAndRespectGuardsOrder()+{+$broadcaster = new FakeBroadcaster;++$broadcaster->channel('somechannel', function () {}, ['guards' => ['myguard1', 'myguard2']]);+$broadcaster->channel('someotherchannel', function () {}, ['guards' => ['myguard2', 'myguard1']]);+++$request = m::mock(\Illuminate\Http\Request::class);+$request->shouldReceive('user')+->once()+->with('myguard1')+->andReturn(null);+$request->shouldReceive('user')+->twice()+->with('myguard2')+->andReturn(new DummyUser)+->ordered('user');++$this->assertInstanceOf(+DummyUser::class,+$broadcaster->retrieveUser($request, 'somechannel')+);++$this->assertInstanceOf(+DummyUser::class,+$broadcaster->retrieveUser($request, 'someotherchannel')+);+}++public function testRetrieveUserDontUseDefaultGuardWhenOneGuardSpecified()+{+$broadcaster = new FakeBroadcaster;++$broadcaster->channel('somechannel', function () {}, ['guards' => 'myguard']);++$request = m::mock(\Illuminate\Http\Request::class);+$request->shouldReceive('user')+->once()+->with('myguard')+->andReturn(null);+$request->shouldNotReceive('user')+->withNoArgs();++$broadcaster->retrieveUser($request, 'somechannel');+}++public function testRetrieveUserDontUseDefaultGuardWhenMultipleGuardsSpecified()+{+$broadcaster = new FakeBroadcaster;++$broadcaster->channel('somechannel', function () {}, ['guards' => ['myguard1', 'myguard2']]);+++$request = m::mock(\Illuminate\Http\Request::class);+$request->shouldReceive('user')+->once()+->with('myguard1')+->andReturn(null);+$request->shouldReceive('user')+->once()+->with('myguard2')+->andReturn(null);+$request->shouldNotReceive('user')+->withNoArgs();++$broadcaster->retrieveUser($request, 'somechannel');+}}class FakeBroadcaster extends Broadcaster@@ -114,6 +239,16 @@ public function extractAuthParameters($pattern, $channel, $callback){return parent::extractAuthParameters($pattern, $channel, $callback);}++public function retrieveChannelOptions($channel)+{+return parent::retrieveChannelOptions($channel);+}++public function retrieveUser($request, $channel)+{+return parent::retrieveUser($request, $channel);+}}class BroadcasterTestEloquentModelStub extends Model@@ -163,3 +298,8 @@ public function join($user, BroadcasterTestEloquentModelStub $model, $nonModel)//}}++class DummyUser+{++}
src/Illuminate/Auth/composer.json+8 −8
@@ -15,10 +15,10 @@],"require": {"php": "^7.1.3",-"illuminate/contracts": "5.7.*",-"illuminate/http": "5.7.*",-"illuminate/queue": "5.7.*",-"illuminate/support": "5.7.*"+"illuminate/contracts": "5.8.*",+"illuminate/http": "5.8.*",+"illuminate/queue": "5.8.*",+"illuminate/support": "5.8.*"},"autoload": {"psr-4": {@@ -27,13 +27,13 @@},"extra": {"branch-alias": {-"dev-master": "5.7-dev"+"dev-master": "5.8-dev"}},"suggest": {-"illuminate/console": "Required to use the auth:clear-resets command (5.7.*).",-"illuminate/queue": "Required to fire login / logout events (5.7.*).",-"illuminate/session": "Required to use the session based guard (5.7.*)."+"illuminate/console": "Required to use the auth:clear-resets command (5.8.*).",+"illuminate/queue": "Required to fire login / logout events (5.8.*).",+"illuminate/session": "Required to use the session based guard (5.8.*)."},"config": {"sort-packages": true
src/Illuminate/Database/composer.json+8 −8
@@ -16,9 +16,9 @@],"require": {"php": "^7.1.3",-"illuminate/container": "5.7.*",-"illuminate/contracts": "5.7.*",-"illuminate/support": "5.7.*"+"illuminate/container": "5.8.*",+"illuminate/contracts": "5.8.*",+"illuminate/support": "5.8.*"},"autoload": {"psr-4": {@@ -27,16 +27,16 @@},"extra": {"branch-alias": {-"dev-master": "5.7-dev"+"dev-master": "5.8-dev"}},"suggest": {"doctrine/dbal": "Required to rename columns and drop SQLite columns (^2.6).","fzaninotto/faker": "Required to use the eloquent factory builder (^1.4).",-"illuminate/console": "Required to use the database commands (5.7.*).",-"illuminate/events": "Required to use the observers with Eloquent (5.7.*).",-"illuminate/filesystem": "Required to use the migrations (5.7.*).",-"illuminate/pagination": "Required to paginate the result set (5.7.*)."+"illuminate/console": "Required to use the database commands (5.8.*).",+"illuminate/events": "Required to use the observers with Eloquent (5.8.*).",+"illuminate/filesystem": "Required to use the migrations (5.8.*).",+"illuminate/pagination": "Required to paginate the result set (5.8.*)."},"config": {"sort-packages": true
src/Illuminate/Queue/composer.json+8 −8
@@ -15,12 +15,12 @@],"require": {"php": "^7.1.3",-"illuminate/console": "5.7.*",-"illuminate/container": "5.7.*",-"illuminate/contracts": "5.7.*",-"illuminate/database": "5.7.*",-"illuminate/filesystem": "5.7.*",-"illuminate/support": "5.7.*",+"illuminate/console": "5.8.*",+"illuminate/container": "5.8.*",+"illuminate/contracts": "5.8.*",+"illuminate/database": "5.8.*",+"illuminate/filesystem": "5.8.*",+"illuminate/support": "5.8.*","symfony/debug": "^4.1","symfony/process": "^4.1"},@@ -31,14 +31,14 @@},"extra": {"branch-alias": {-"dev-master": "5.7-dev"+"dev-master": "5.8-dev"}},"suggest": {"ext-pcntl": "Required to use all features of the queue worker.","ext-posix": "Required to use all features of the queue worker.","aws/aws-sdk-php": "Required to use the SQS queue driver (^3.0).",-"illuminate/redis": "Required to use the Redis queue driver (5.7.*).",+"illuminate/redis": "Required to use the Redis queue driver (5.8.*).","pda/pheanstalk": "Required to use the Beanstalk queue driver (^3.0)."},"config": {
src/Illuminate/Routing/composer.json+8 −8
@@ -15,12 +15,12 @@],"require": {"php": "^7.1.3",-"illuminate/container": "5.7.*",-"illuminate/contracts": "5.7.*",-"illuminate/http": "5.7.*",-"illuminate/pipeline": "5.7.*",-"illuminate/session": "5.7.*",-"illuminate/support": "5.7.*",+"illuminate/container": "5.8.*",+"illuminate/contracts": "5.8.*",+"illuminate/http": "5.8.*",+"illuminate/pipeline": "5.8.*",+"illuminate/session": "5.8.*",+"illuminate/support": "5.8.*","symfony/debug": "^4.1","symfony/http-foundation": "^4.1","symfony/http-kernel": "^4.1",@@ -33,11 +33,11 @@},"extra": {"branch-alias": {-"dev-master": "5.7-dev"+"dev-master": "5.8-dev"}},"suggest": {-"illuminate/console": "Required to use the make commands (5.7.*).",+"illuminate/console": "Required to use the make commands (5.8.*).","symfony/psr-http-message-bridge": "Required to psr7 bridging features (^1.0)."},"config": {
src/Illuminate/Cache/composer.json+6 −6
@@ -15,8 +15,8 @@],"require": {"php": "^7.1.3",-"illuminate/contracts": "5.7.*",-"illuminate/support": "5.7.*"+"illuminate/contracts": "5.8.*",+"illuminate/support": "5.8.*"},"autoload": {"psr-4": {@@ -25,13 +25,13 @@},"extra": {"branch-alias": {-"dev-master": "5.7-dev"+"dev-master": "5.8-dev"}},"suggest": {-"illuminate/database": "Required to use the database cache driver (5.7.*).",-"illuminate/filesystem": "Required to use the file cache driver (5.7.*).",-"illuminate/redis": "Required to use the redis cache driver (5.7.*)."+"illuminate/database": "Required to use the database cache driver (5.8.*).",+"illuminate/filesystem": "Required to use the file cache driver (5.8.*).",+"illuminate/redis": "Required to use the redis cache driver (5.8.*)."},"config": {"sort-packages": true
src/Illuminate/Validation/composer.json+6 −6
@@ -15,10 +15,10 @@],"require": {"php": "^7.1.3",-"illuminate/container": "5.7.*",-"illuminate/contracts": "5.7.*",-"illuminate/support": "5.7.*",-"illuminate/translation": "5.7.*",+"illuminate/container": "5.8.*",+"illuminate/contracts": "5.8.*",+"illuminate/support": "5.8.*",+"illuminate/translation": "5.8.*","symfony/http-foundation": "^4.1"},"autoload": {@@ -28,11 +28,11 @@},"extra": {"branch-alias": {-"dev-master": "5.7-dev"+"dev-master": "5.8-dev"}},"suggest": {-"illuminate/database": "Required to use the database presence verifier (5.7.*)."+"illuminate/database": "Required to use the database presence verifier (5.8.*)."},"config": {"sort-packages": true
src/Illuminate/View/composer.json+6 −6
@@ -15,11 +15,11 @@],"require": {"php": "^7.1.3",-"illuminate/container": "5.7.*",-"illuminate/contracts": "5.7.*",-"illuminate/events": "5.7.*",-"illuminate/filesystem": "5.7.*",-"illuminate/support": "5.7.*",+"illuminate/container": "5.8.*",+"illuminate/contracts": "5.8.*",+"illuminate/events": "5.8.*",+"illuminate/filesystem": "5.8.*",+"illuminate/support": "5.8.*","symfony/debug": "^4.1"},"autoload": {@@ -29,7 +29,7 @@},"extra": {"branch-alias": {-"dev-master": "5.7-dev"+"dev-master": "5.8-dev"}},"config": {
tests/Integration/Database/EloquentMorphToLazyEagerLoadingTest.php+94 −0
@@ -0,0 +1,94 @@+<?php++namespace Illuminate\Tests\Integration\Database\EloquentMorphToLazyEagerLoadingTest;++use Illuminate\Support\Facades\Schema;+use Illuminate\Database\Eloquent\Model;+use Illuminate\Database\Schema\Blueprint;+use Illuminate\Tests\Integration\Database\DatabaseTestCase;++/**+* @group integration+*/+class EloquentMorphToLazyEagerLoadingTest extends DatabaseTestCase+{+public function setUp()+{+parent::setUp();++Schema::create('users', function (Blueprint $table) {+$table->increments('id');+});++Schema::create('posts', function (Blueprint $table) {+$table->increments('post_id');+$table->unsignedInteger('user_id');+});++Schema::create('videos', function (Blueprint $table) {+$table->increments('video_id');+});++Schema::create('comments', function (Blueprint $table) {+$table->increments('id');+$table->string('commentable_type');+$table->integer('commentable_id');+});++$user = User::create();++$post = tap((new Post)->user()->associate($user))->save();++$video = Video::create();++(new Comment)->commentable()->associate($post)->save();+(new Comment)->commentable()->associate($video)->save();+}++public function test_lazy_eager_loading()+{+$comments = Comment::all();++\DB::enableQueryLog();++$comments->load('commentable');++$this->assertCount(3, \DB::getQueryLog());+$this->assertTrue($comments[0]->relationLoaded('commentable'));+$this->assertTrue($comments[0]->commentable->relationLoaded('user'));+$this->assertTrue($comments[1]->relationLoaded('commentable'));+}+}++class Comment extends Model+{+public $timestamps = false;++public function commentable()+{+return $this->morphTo();+}+}++class Post extends Model+{+public $timestamps = false;+protected $primaryKey = 'post_id';+protected $with = ['user'];++public function user()+{+return $this->belongsTo(User::class);+}+}++class User extends Model+{+public $timestamps = false;+}++class Video extends Model+{+public $timestamps = false;+protected $primaryKey = 'video_id';+}src/Illuminate/Database/DetectsLostConnections.php | 1 +1 file changed, 1 insertion(+)
tests/Integration/Database/EloquentBelongsToManyTest.php+24 −0
@@ -583,6 +583,24 @@ public function can_touch_related_models()$this->assertNotEquals('2017-10-10 10:10:10', Tag::find(300)->updated_at);}++public function test_custom_related_key()+{+$post = Post::create(['title' => str_random()]);++$tag = $post->tagsWithCustomRelatedKey()->create(['name' => str_random()]);+$this->assertEquals($tag->name, $post->tagsWithCustomRelatedKey()->first()->pivot->tag_id);++$post->tagsWithCustomRelatedKey()->detach($tag);++$post->tagsWithCustomRelatedKey()->attach($tag);+$this->assertEquals($tag->name, $post->tagsWithCustomRelatedKey()->first()->pivot->tag_id);++$post->tagsWithCustomRelatedKey()->detach(new Collection([$tag]));++$post->tagsWithCustomRelatedKey()->attach(new Collection([$tag]));+$this->assertEquals($tag->name, $post->tagsWithCustomRelatedKey()->first()->pivot->tag_id);+}}class Post extends Model@@ -619,6 +637,12 @@ public function tagsWithCustomAccessor()->using(CustomPivot::class)->as('tag');}++public function tagsWithCustomRelatedKey()+{+return $this->belongsToMany(Tag::class, 'posts_tags', 'post_id', 'tag_id', 'id', 'name')+->withPivot('flag');+}}class Tag extends Modelhandlingcomposer.json | 2 +-src/Illuminate/Console/Scheduling/Event.php | 3 +-.../Console/Scheduling/ScheduleRunCommand.php | 4 +-.../Eloquent/Concerns/HasAttributes.php | 14 +-.../Eloquent/Concerns/HasTimestamps.php | 4 +-.../Exceptions/MaintenanceModeException.php | 5 +-.../Foundation/Testing/TestCase.php | 6 +-src/Illuminate/Foundation/helpers.php | 6 +-.../Failed/DatabaseFailedJobProvider.php | 4 +-.../Session/Middleware/StartSession.php | 5 +-src/Illuminate/Support/Facades/Date.php | 178 ++++++++++++++++++src/Illuminate/Support/InteractsWithTime.php | 2 +-src/Illuminate/Support/composer.json | 2 +-.../Concerns/ValidatesAttributes.php | 3 +-.../Mail/SendingMailWithLocaleTest.php | 2 +-.../SendingNotificationsWithLocaleTest.php | 2 +-tests/Support/DateFacadeTest.php | 107 +++++++++++tests/Support/fixtures/CustomDateClass.php | 21 +++18 files changed, 343 insertions(+), 27 deletions(-)create mode 100644 src/Illuminate/Support/Facades/Date.phpcreate mode 100644 tests/Support/DateFacadeTest.phpcreate mode 100644 tests/Support/fixtures/CustomDateClass.php
src/Illuminate/Broadcasting/composer.json+5 −5
@@ -16,10 +16,10 @@"require": {"php": "^7.1.3","psr/log": "^1.0",-"illuminate/bus": "5.7.*",-"illuminate/contracts": "5.7.*",-"illuminate/queue": "5.7.*",-"illuminate/support": "5.7.*"+"illuminate/bus": "5.8.*",+"illuminate/contracts": "5.8.*",+"illuminate/queue": "5.8.*",+"illuminate/support": "5.8.*"},"autoload": {"psr-4": {@@ -28,7 +28,7 @@},"extra": {"branch-alias": {-"dev-master": "5.7-dev"+"dev-master": "5.8-dev"}},"suggest": {
More files changed — see the full commit.
References
- ADVISORYhttps://nvd.nist.gov/vuln/detail/CVE-2019-9081
- WEBhttps://github.com/Laworigin/Laworigin.github.io/blob/master/2019/02/21/laravelv5-7%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96rce/index.html
- PACKAGEhttps://github.com/laravel/framework
- WEBhttps://github.com/laravel/framework/discussions/40184
- WEBhttps://laworigin.github.io/2019/02/21/laravelv5-7%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96rce