From 185e8d5ea894f3c355e1fedddbe02df3ddb5bae0 Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Mon, 7 Dec 2020 19:51:25 +0200 Subject: [PATCH 1/3] allow encrypting jobs --- .../Contracts/Queue/UsesEncryption.php | 8 ++++++ src/Illuminate/Queue/CallQueuedHandler.php | 25 +++++++++++++++++-- src/Illuminate/Queue/Queue.php | 7 +++++- 3 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 src/Illuminate/Contracts/Queue/UsesEncryption.php diff --git a/src/Illuminate/Contracts/Queue/UsesEncryption.php b/src/Illuminate/Contracts/Queue/UsesEncryption.php new file mode 100644 index 000000000000..2e3a6560b1cd --- /dev/null +++ b/src/Illuminate/Contracts/Queue/UsesEncryption.php @@ -0,0 +1,8 @@ +setJobInstanceIfNecessary( - $job, unserialize($data['command']) + $job, $this->getCommand($data) ); } catch (ModelNotFoundException $e) { return $this->handleModelNotFound($job, $e); @@ -226,7 +228,7 @@ protected function handleModelNotFound(Job $job, $e) */ public function failed(array $data, $e, string $uuid) { - $command = unserialize($data['command']); + $command = $this->getCommand($data); if (! $command instanceof ShouldBeUniqueUntilProcessing) { $this->ensureUniqueJobLockIsReleased($command); @@ -272,4 +274,23 @@ protected function ensureChainCatchCallbacksAreInvoked(string $uuid, $command, $ $command->invokeChainCatchCallbacks($e); } } + + /** + * Get the command from the given payload. + * + * @param array $data + * @return mixed + */ + protected function getCommand(array $data) + { + if (Str::startsWith($data['command'], 'O:')) { + return unserialize($data['command']); + } + + if ($this->container->bound('encrypter')) { + return unserialize($this->container['encrypter']->decrypt($data['command'])); + } + + throw new RuntimeException('Unable to extract job payload.'); + } } diff --git a/src/Illuminate/Queue/Queue.php b/src/Illuminate/Queue/Queue.php index 40023ae34e3d..4a319ace4d64 100755 --- a/src/Illuminate/Queue/Queue.php +++ b/src/Illuminate/Queue/Queue.php @@ -5,6 +5,7 @@ use Closure; use DateTimeInterface; use Illuminate\Container\Container; +use Illuminate\Contracts\Queue\UsesEncryption; use Illuminate\Support\Arr; use Illuminate\Support\InteractsWithTime; use Illuminate\Support\Str; @@ -142,10 +143,14 @@ protected function createObjectPayload($job, $queue) ], ]); + $command = $job instanceof UsesEncryption && $this->container->bound('encrypter') + ? $this->container['encrypter']->encrypt(serialize(clone $job)) + : serialize(clone $job); + return array_merge($payload, [ 'data' => [ 'commandName' => get_class($job), - 'command' => serialize(clone $job), + 'command' => $command, ], ]); } From 9849131d13cdac73df6f1d9161462ea988242df4 Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Thu, 10 Dec 2020 18:02:23 +0200 Subject: [PATCH 2/3] add integration tests --- tests/Integration/Queue/JobEncryptionTest.php | 126 ++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 tests/Integration/Queue/JobEncryptionTest.php diff --git a/tests/Integration/Queue/JobEncryptionTest.php b/tests/Integration/Queue/JobEncryptionTest.php new file mode 100644 index 000000000000..7160e0c3b97d --- /dev/null +++ b/tests/Integration/Queue/JobEncryptionTest.php @@ -0,0 +1,126 @@ +set('app.key', Str::random(32)); + $app['config']->set('app.debug', 'true'); + $app['config']->set('queue.default', 'database'); + } + + protected function setUp(): void + { + parent::setUp(); + + Schema::create('jobs', function (Blueprint $table) { + $table->bigIncrements('id'); + $table->string('queue')->index(); + $table->longText('payload'); + $table->unsignedTinyInteger('attempts'); + $table->unsignedInteger('reserved_at')->nullable(); + $table->unsignedInteger('available_at'); + $table->unsignedInteger('created_at'); + }); + } + + protected function tearDown(): void + { + JobEncryptionTestEncryptedJob::$ran = false; + JobEncryptionTestNonEncryptedJob::$ran = false; + + m::close(); + } + + public function testEncryptedJobPayloadIsStoredEncrypted() + { + Bus::dispatch(new JobEncryptionTestEncryptedJob); + + $this->assertNotEmpty( + decrypt(json_decode(DB::table('jobs')->first()->payload)->data->command) + ); + } + + public function testNonEncryptedJobPayloadIsStoredRaw() + { + Bus::dispatch(new JobEncryptionTestNonEncryptedJob); + + $this->expectExceptionMessage('The payload is invalid'); + + $this->assertInstanceOf(JobEncryptionTestNonEncryptedJob::class, + unserialize(json_decode(DB::table('jobs')->first()->payload)->data->command) + ); + + decrypt(json_decode(DB::table('jobs')->first()->payload)->data->command); + } + + public function testQueueCanProcessEncryptedJob() + { + Bus::dispatch(new JobEncryptionTestEncryptedJob); + + Queue::pop()->fire(); + + $this->assertTrue(JobEncryptionTestEncryptedJob::$ran); + } + + public function testQueueCanProcessUnEncryptedJob() + { + Bus::dispatch(new JobEncryptionTestNonEncryptedJob); + + Queue::pop()->fire(); + + $this->assertTrue(JobEncryptionTestNonEncryptedJob::$ran); + } +} + +class JobEncryptionTestEncryptedJob implements ShouldQueue, UsesEncryption +{ + use Dispatchable, Queueable; + + public static $ran = false; + + public function handle() + { + static::$ran = true; + } +} + + +class JobEncryptionTestNonEncryptedJob implements ShouldQueue +{ + use Dispatchable, Queueable; + + public static $ran = false; + + public function handle() + { + static::$ran = true; + } +} From 2b566a5d5b4b68fff6a49ee8ae6cfb341b422611 Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Thu, 10 Dec 2020 18:03:00 +0200 Subject: [PATCH 3/3] fix style --- tests/Integration/Queue/JobEncryptionTest.php | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tests/Integration/Queue/JobEncryptionTest.php b/tests/Integration/Queue/JobEncryptionTest.php index 7160e0c3b97d..fb331e7394ff 100644 --- a/tests/Integration/Queue/JobEncryptionTest.php +++ b/tests/Integration/Queue/JobEncryptionTest.php @@ -3,10 +3,8 @@ namespace Illuminate\Tests\Integration\Queue; use Illuminate\Bus\Queueable; -use Illuminate\Contracts\Encryption\Encrypter; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Contracts\Queue\UsesEncryption; -use Illuminate\Database\DatabaseTransactionsManager; use Illuminate\Database\Schema\Blueprint; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Support\Facades\Bus; @@ -15,12 +13,7 @@ use Illuminate\Support\Facades\Schema; use Illuminate\Support\Str; use Illuminate\Tests\Integration\Database\DatabaseTestCase; -use Illuminate\Tests\Integration\Database\EloquentCollectionLoadMissingTest\Comment; -use Illuminate\Tests\Integration\Database\EloquentCollectionLoadMissingTest\Post; -use Illuminate\Tests\Integration\Database\EloquentCollectionLoadMissingTest\Revision; -use Illuminate\Tests\Integration\Database\EloquentCollectionLoadMissingTest\User; use Mockery as m; -use Orchestra\Testbench\TestCase; /** * @group integration