From fc341b3f19496bc1c66cd38a665c2d2da8b8baaf Mon Sep 17 00:00:00 2001 From: therecluse26 <8239106+therecluse26@users.noreply.github.com> Date: Sun, 21 Apr 2024 15:26:25 -0400 Subject: [PATCH 1/2] Allow for encrypted command data Added a bugfix to handle fetching priority from encrypted command data if the job class implements `ShouldBeEncrypted` --- src/Queue/RabbitMQQueue.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Queue/RabbitMQQueue.php b/src/Queue/RabbitMQQueue.php index 19c4efb2..6cb2126f 100644 --- a/src/Queue/RabbitMQQueue.php +++ b/src/Queue/RabbitMQQueue.php @@ -525,6 +525,11 @@ protected function createMessage($payload, int $attempts = 0): array } if (isset($currentPayload['data']['command'])) { + // If the command data is encrypted, decrypt it first before attempting to unserialize + if (in_array(ShouldBeEncrypted::class, class_implements($currentPayload['data']['commandName']))) { + $currentPayload['data']['command'] = decrypt($currentPayload['data']['command']); + } + $commandData = unserialize($currentPayload['data']['command']); if (property_exists($commandData, 'priority')) { $properties['priority'] = $commandData->priority; From 9bd427a6d281d6e0f0fa576ae04435100380b4dd Mon Sep 17 00:00:00 2001 From: therecluse26 Date: Wed, 24 Apr 2024 17:28:09 -0400 Subject: [PATCH 2/2] Added encryption key, tests and requested updates --- phpunit.xml.dist | 1 + src/Queue/RabbitMQQueue.php | 8 ++- tests/Feature/TestCase.php | 98 ++++++++++++++++++++++++++++++++ tests/Mocks/TestEncryptedJob.php | 25 ++++++++ 4 files changed, 129 insertions(+), 3 deletions(-) create mode 100644 tests/Mocks/TestEncryptedJob.php diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 71be4e98..d213fd63 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -10,6 +10,7 @@ + diff --git a/src/Queue/RabbitMQQueue.php b/src/Queue/RabbitMQQueue.php index 6cb2126f..ce63494d 100644 --- a/src/Queue/RabbitMQQueue.php +++ b/src/Queue/RabbitMQQueue.php @@ -7,8 +7,10 @@ use ErrorException; use Exception; use Illuminate\Contracts\Queue\Queue as QueueContract; +use Illuminate\Contracts\Queue\ShouldBeEncrypted; use Illuminate\Queue\Queue; use Illuminate\Support\Arr; +use Illuminate\Support\Facades\Crypt; use Illuminate\Support\Str; use PhpAmqpLib\Channel\AMQPChannel; use PhpAmqpLib\Connection\AbstractConnection; @@ -526,10 +528,10 @@ protected function createMessage($payload, int $attempts = 0): array if (isset($currentPayload['data']['command'])) { // If the command data is encrypted, decrypt it first before attempting to unserialize - if (in_array(ShouldBeEncrypted::class, class_implements($currentPayload['data']['commandName']))) { - $currentPayload['data']['command'] = decrypt($currentPayload['data']['command']); + if (is_subclass_of($currentPayload['data']['commandName'], ShouldBeEncrypted::class)) { + $currentPayload['data']['command'] = Crypt::decrypt($currentPayload['data']['command']); } - + $commandData = unserialize($currentPayload['data']['command']); if (property_exists($commandData, 'priority')) { $properties['priority'] = $commandData->priority; diff --git a/tests/Feature/TestCase.php b/tests/Feature/TestCase.php index c49d8608..16fd5faa 100644 --- a/tests/Feature/TestCase.php +++ b/tests/Feature/TestCase.php @@ -8,6 +8,7 @@ use PhpAmqpLib\Exception\AMQPProtocolChannelException; use RuntimeException; use VladimirYuldashev\LaravelQueueRabbitMQ\Queue\Jobs\RabbitMQJob; +use VladimirYuldashev\LaravelQueueRabbitMQ\Tests\Mocks\TestEncryptedJob; use VladimirYuldashev\LaravelQueueRabbitMQ\Tests\Mocks\TestJob; use VladimirYuldashev\LaravelQueueRabbitMQ\Tests\TestCase as BaseTestCase; @@ -194,6 +195,103 @@ public function testBulk(): void $this->assertSame($count, Queue::size()); } + public function testPushEncrypted(): void + { + Queue::push(new TestEncryptedJob()); + + sleep(1); + + $this->assertSame(1, Queue::size()); + $this->assertNotNull($job = Queue::pop()); + $this->assertSame(1, $job->attempts()); + $this->assertInstanceOf(RabbitMQJob::class, $job); + $this->assertSame(TestEncryptedJob::class, $job->resolveName()); + $this->assertNotNull($job->getJobId()); + + $payload = $job->payload(); + + $this->assertSame(TestEncryptedJob::class, $payload['displayName']); + $this->assertSame('Illuminate\Queue\CallQueuedHandler@call', $payload['job']); + $this->assertNull($payload['maxTries']); + $this->assertNull($payload['backoff']); + $this->assertNull($payload['timeout']); + $this->assertNull($payload['retryUntil']); + $this->assertSame($job->getJobId(), $payload['id']); + + $job->delete(); + $this->assertSame(0, Queue::size()); + } + + public function testPushEncryptedAfterCommit(): void + { + $transaction = new DatabaseTransactionsManager; + + $this->app->singleton('db.transactions', function ($app) use ($transaction) { + $transaction->begin('FakeDBConnection', 1); + + return $transaction; + }); + + TestEncryptedJob::dispatch()->afterCommit(); + + sleep(1); + $this->assertSame(0, Queue::size()); + $this->assertNull(Queue::pop()); + + $transaction->commit('FakeDBConnection', 1, 0); + + sleep(1); + + $this->assertSame(1, Queue::size()); + $this->assertNotNull($job = Queue::pop()); + + $job->delete(); + $this->assertSame(0, Queue::size()); + } + + public function testEncryptedLater(): void + { + Queue::later(3, new TestEncryptedJob()); + + sleep(1); + + $this->assertSame(0, Queue::size()); + $this->assertNull(Queue::pop()); + + sleep(3); + + $this->assertSame(1, Queue::size()); + $this->assertNotNull($job = Queue::pop()); + + $this->assertInstanceOf(RabbitMQJob::class, $job); + + $body = json_decode($job->getRawBody(), true); + + $this->assertSame(TestEncryptedJob::class, $body['displayName']); + $this->assertSame('Illuminate\Queue\CallQueuedHandler@call', $body['job']); + $this->assertSame(TestEncryptedJob::class, $body['data']['commandName']); + $this->assertNotNull($job->getJobId()); + + $job->delete(); + $this->assertSame(0, Queue::size()); + } + + public function testEncryptedBulk(): void + { + $count = 100; + $jobs = []; + + for ($i = 0; $i < $count; $i++) { + $jobs[$i] = new TestEncryptedJob($i); + } + + Queue::bulk($jobs); + + sleep(1); + + $this->assertSame($count, Queue::size()); + } + public function testReleaseRaw(): void { Queue::pushRaw($payload = Str::random()); diff --git a/tests/Mocks/TestEncryptedJob.php b/tests/Mocks/TestEncryptedJob.php new file mode 100644 index 00000000..1c0e1762 --- /dev/null +++ b/tests/Mocks/TestEncryptedJob.php @@ -0,0 +1,25 @@ +i = $i; + } + + public function handle(): void + { + // + } +}