Skip to content

Commit

Permalink
Fix collection deserialization errors
Browse files Browse the repository at this point in the history
  • Loading branch information
ramsey committed Mar 29, 2020
1 parent 15f777b commit ba8fff1
Show file tree
Hide file tree
Showing 6 changed files with 257 additions and 1 deletion.
12 changes: 11 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
### Security


## [4.0.1] - 2020-03-29

### Fixed

* Fix collection deserialization errors due to upstream `allowed_classes` being
set to `false`. For details, see [ramsey/uuid#303](https://github.com/ramsey/uuid/issues/303)
and [ramsey/collection#47](https://github.com/ramsey/collection/issues/47).


## [4.0.0] - 2020-03-22

### Added
Expand Down Expand Up @@ -1173,7 +1182,8 @@ versions leading up to this release.*
[ramsey/uuid-doctrine]: https://github.com/ramsey/uuid-doctrine
[ramsey/uuid-console]: https://github.com/ramsey/uuid-console

[unreleased]: https://github.com/ramsey/uuid/compare/4.0.0...HEAD
[unreleased]: https://github.com/ramsey/uuid/compare/4.0.1...HEAD
[4.0.1]: https://github.com/ramsey/uuid/compare/4.0.0...4.0.1
[4.0.0]: https://github.com/ramsey/uuid/compare/4.0.0-beta2...4.0.0
[4.0.0-beta2]: https://github.com/ramsey/uuid/compare/4.0.0-beta1...4.0.0-beta2
[4.0.0-beta1]: https://github.com/ramsey/uuid/compare/4.0.0-alpha5...4.0.0-beta1
Expand Down
33 changes: 33 additions & 0 deletions src/Builder/BuilderCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@

use Ramsey\Collection\AbstractCollection;
use Ramsey\Collection\CollectionInterface;
use Ramsey\Uuid\Converter\Number\GenericNumberConverter;
use Ramsey\Uuid\Converter\Time\GenericTimeConverter;
use Ramsey\Uuid\Converter\Time\PhpTimeConverter;
use Ramsey\Uuid\Guid\GuidBuilder;
use Ramsey\Uuid\Math\BrickMathCalculator;
use Ramsey\Uuid\Nonstandard\UuidBuilder as NonstandardUuidBuilder;
use Ramsey\Uuid\Rfc4122\UuidBuilder as Rfc4122UuidBuilder;
use Traversable;

/**
Expand All @@ -37,4 +44,30 @@ public function getIterator(): Traversable
{
return parent::getIterator();
}

/**
* Re-constructs the object from its serialized form
*
* @param string $serialized The serialized PHP string to unserialize into
* a UuidInterface instance
*
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
*/
public function unserialize($serialized): void
{
/** @var mixed[] $data */
$data = unserialize($serialized, [
'allowed_classes' => [
BrickMathCalculator::class,
GenericNumberConverter::class,
GenericTimeConverter::class,
GuidBuilder::class,
NonstandardUuidBuilder::class,
PhpTimeConverter::class,
Rfc4122UuidBuilder::class,
],
]);

$this->data = $data;
}
}
24 changes: 24 additions & 0 deletions src/Provider/Node/NodeProviderCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use Ramsey\Collection\AbstractCollection;
use Ramsey\Collection\CollectionInterface;
use Ramsey\Uuid\Provider\NodeProviderInterface;
use Ramsey\Uuid\Type\Hexadecimal;

/**
* A collection of NodeProviderInterface objects
Expand All @@ -27,4 +28,27 @@ public function getType(): string
{
return NodeProviderInterface::class;
}

/**
* Re-constructs the object from its serialized form
*
* @param string $serialized The serialized PHP string to unserialize into
* a UuidInterface instance
*
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
*/
public function unserialize($serialized): void
{
/** @var mixed[] $data */
$data = unserialize($serialized, [
'allowed_classes' => [
Hexadecimal::class,
RandomNodeProvider::class,
StaticNodeProvider::class,
SystemNodeProvider::class,
],
]);

$this->data = $data;
}
}
1 change: 1 addition & 0 deletions src/Uuid.php
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,7 @@ public function unserialize($serialized): void
$this->codec = $uuid->codec;
$this->numberConverter = $uuid->numberConverter;
$this->fields = $uuid->fields;
$this->timeConverter = $uuid->timeConverter;
}

public function compareTo(UuidInterface $other): int
Expand Down
158 changes: 158 additions & 0 deletions tests/Builder/FallbackBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,28 @@

namespace Ramsey\Uuid\Test\Builder;

use DateTimeInterface;
use Mockery;
use Ramsey\Uuid\Builder\BuilderCollection;
use Ramsey\Uuid\Builder\FallbackBuilder;
use Ramsey\Uuid\Builder\UuidBuilderInterface;
use Ramsey\Uuid\Codec\CodecInterface;
use Ramsey\Uuid\Codec\StringCodec;
use Ramsey\Uuid\Converter\Number\GenericNumberConverter;
use Ramsey\Uuid\Converter\Time\GenericTimeConverter;
use Ramsey\Uuid\Converter\Time\PhpTimeConverter;
use Ramsey\Uuid\Exception\BuilderNotFoundException;
use Ramsey\Uuid\Exception\UnableToBuildUuidException;
use Ramsey\Uuid\Guid\GuidBuilder;
use Ramsey\Uuid\Math\BrickMathCalculator;
use Ramsey\Uuid\Nonstandard\UuidBuilder as NonstandardUuidBuilder;
use Ramsey\Uuid\Nonstandard\UuidV6;
use Ramsey\Uuid\Rfc4122\UuidBuilder as Rfc4122UuidBuilder;
use Ramsey\Uuid\Rfc4122\UuidV1;
use Ramsey\Uuid\Rfc4122\UuidV2;
use Ramsey\Uuid\Test\TestCase;
use Ramsey\Uuid\UuidInterface;
use Ramsey\Uuid\Validator\GenericValidator;

class FallbackBuilderTest extends TestCase
{
Expand Down Expand Up @@ -50,4 +64,148 @@ public function testBuildThrowsExceptionAfterAllConfiguredBuildersHaveErrored():

$fallbackBuilder->build($codec, $bytes);
}

/**
* @dataProvider provideBytes
*/
public function testSerializationOfBuilderCollection(string $bytes): void
{
$validator = new GenericValidator();
$calculator = new BrickMathCalculator();
$genericNumberConverter = new GenericNumberConverter($calculator);
$genericTimeConverter = new GenericTimeConverter($calculator);
$phpTimeConverter = new PhpTimeConverter($calculator, $genericTimeConverter);

// Use the GenericTimeConverter.
$guidBuilder = new GuidBuilder($genericNumberConverter, $genericTimeConverter);
$rfc4122Builder = new Rfc4122UuidBuilder($genericNumberConverter, $genericTimeConverter);
$nonstandardBuilder = new NonstandardUuidBuilder($genericNumberConverter, $genericTimeConverter);

// Use the PhpTimeConverter.
$guidBuilder2 = new GuidBuilder($genericNumberConverter, $phpTimeConverter);
$rfc4122Builder2 = new Rfc4122UuidBuilder($genericNumberConverter, $phpTimeConverter);
$nonstandardBuilder2 = new NonstandardUuidBuilder($genericNumberConverter, $phpTimeConverter);

$builderCollection = new BuilderCollection(
[
$guidBuilder,
$guidBuilder2,
$rfc4122Builder,
$rfc4122Builder2,
$nonstandardBuilder,
$nonstandardBuilder2,
]
);

$serializedBuilderCollection = serialize($builderCollection);

/** @var BuilderCollection $unserializedBuilderCollection */
$unserializedBuilderCollection = unserialize($serializedBuilderCollection);

$this->assertInstanceOf(BuilderCollection::class, $unserializedBuilderCollection);

/** @var UuidBuilderInterface $builder */
foreach ($unserializedBuilderCollection as $builder) {
$codec = new StringCodec($builder);

$this->assertInstanceOf(UuidBuilderInterface::class, $builder);

try {
$uuid = $builder->build($codec, $bytes);
$this->assertInstanceOf(UuidInterface::class, $uuid);

if (($uuid instanceof UuidV1) || ($uuid instanceof UuidV2) || ($uuid instanceof UuidV6)) {
$this->assertInstanceOf(DateTimeInterface::class, $uuid->getDateTime());
}
} catch (UnableToBuildUuidException $exception) {
switch ($exception->getMessage()) {
case 'The byte string received does not contain a valid version':
case 'The byte string received does not conform to the RFC 4122 variant':
case 'The byte string received does not conform to the RFC 4122 or Microsoft Corporation variants':
// This is expected; ignoring.

break;
default:
throw $exception;
}
}
}
}

/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ReturnTypeHint.MissingTraversableTypeHintSpecification
*/
public function provideBytes(): array
{
return [
[
// GUID bytes
'bytes' => hex2bin('b08c6fff7dc5e1110b210800200c9a66'),
],
[
// GUID bytes
'bytes' => hex2bin('b08c6fff7dc5e1111b210800200c9a66'),
],
[
// GUID bytes
'bytes' => hex2bin('b08c6fff7dc5e1112b210800200c9a66'),
],
[
// GUID bytes
'bytes' => hex2bin('b08c6fff7dc5e1113b210800200c9a66'),
],
[
// GUID bytes
'bytes' => hex2bin('b08c6fff7dc5e1114b210800200c9a66'),
],
[
// GUID bytes
'bytes' => hex2bin('b08c6fff7dc5e1115b210800200c9a66'),
],
[
// GUID bytes
'bytes' => hex2bin('b08c6fff7dc5e1116b210800200c9a66'),
],
[
// GUID bytes
'bytes' => hex2bin('b08c6fff7dc5e1117b210800200c9a66'),
],
[
// GUID bytes
'bytes' => hex2bin('b08c6fff7dc5e111eb210800200c9a66'),
],
[
// GUID bytes
'bytes' => hex2bin('b08c6fff7dc5e111fb210800200c9a66'),
],
[
// Version 1 bytes
'bytes' => hex2bin('ff6f8cb0c57d11e19b210800200c9a66'),
],
[
// Version 2 bytes
'bytes' => hex2bin('000001f55cde21ea84000242ac130003'),
],
[
// Version 3 bytes
'bytes' => hex2bin('ff6f8cb0c57d31e1bb210800200c9a66'),
],
[
// Version 4 bytes
'bytes' => hex2bin('ff6f8cb0c57d41e1ab210800200c9a66'),
],
[
// Version 5 bytes
'bytes' => hex2bin('ff6f8cb0c57d51e18b210800200c9a66'),
],
[
// Version 6 bytes
'bytes' => hex2bin('ff6f8cb0c57d61e18b210800200c9a66'),
],
[
// NIL bytes
'bytes' => hex2bin('00000000000000000000000000000000'),
],
];
}
}
30 changes: 30 additions & 0 deletions tests/Provider/Node/FallbackNodeProviderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
use Ramsey\Uuid\Exception\NodeException;
use Ramsey\Uuid\Provider\Node\FallbackNodeProvider;
use Ramsey\Uuid\Provider\Node\NodeProviderCollection;
use Ramsey\Uuid\Provider\Node\RandomNodeProvider;
use Ramsey\Uuid\Provider\Node\StaticNodeProvider;
use Ramsey\Uuid\Provider\Node\SystemNodeProvider;
use Ramsey\Uuid\Provider\NodeProviderInterface;
use Ramsey\Uuid\Test\TestCase;
use Ramsey\Uuid\Type\Hexadecimal;
Expand Down Expand Up @@ -65,4 +68,31 @@ public function testGetNodeThrowsExceptionWhenNoNodesFound(): void

$provider->getNode();
}

public function testSerializationOfNodeProviderCollection(): void
{
$staticNodeProvider = new StaticNodeProvider(new Hexadecimal('aabbccddeeff'));
$randomNodeProvider = new RandomNodeProvider();
$systemNodeProvider = new SystemNodeProvider();

$nodeProviderCollection = new NodeProviderCollection(
[
$staticNodeProvider,
$randomNodeProvider,
$systemNodeProvider,
]
);

$serializedNodeProviderCollection = serialize($nodeProviderCollection);

/** @var NodeProviderCollection $unserializedNodeProviderCollection */
$unserializedNodeProviderCollection = unserialize($serializedNodeProviderCollection);

$this->assertInstanceOf(NodeProviderCollection::class, $unserializedNodeProviderCollection);

foreach ($unserializedNodeProviderCollection as $nodeProvider) {
$this->assertInstanceOf(NodeProviderInterface::class, $nodeProvider);
$this->assertInstanceOf(Hexadecimal::class, $nodeProvider->getNode());
}
}
}

0 comments on commit ba8fff1

Please sign in to comment.