mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
Implements StoredObjectManager for local storage
This commit is contained in:
parent
1f6de3cb11
commit
c1e449f48e
@ -11,49 +11,200 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Chill\DocStoreBundle\AsyncUpload\Driver\LocalStorage;
|
namespace Chill\DocStoreBundle\AsyncUpload\Driver\LocalStorage;
|
||||||
|
|
||||||
|
use Base64Url\Base64Url;
|
||||||
use Chill\DocStoreBundle\Entity\StoredObject;
|
use Chill\DocStoreBundle\Entity\StoredObject;
|
||||||
use Chill\DocStoreBundle\Entity\StoredObjectVersion;
|
use Chill\DocStoreBundle\Entity\StoredObjectVersion;
|
||||||
|
use Chill\DocStoreBundle\Exception\StoredObjectManagerException;
|
||||||
|
use Chill\DocStoreBundle\Service\Cryptography\KeyGenerator;
|
||||||
use Chill\DocStoreBundle\Service\StoredObjectManagerInterface;
|
use Chill\DocStoreBundle\Service\StoredObjectManagerInterface;
|
||||||
|
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
||||||
|
use Symfony\Component\Filesystem\Filesystem;
|
||||||
|
use Symfony\Component\Filesystem\Path;
|
||||||
|
|
||||||
class StoredObjectManager implements StoredObjectManagerInterface
|
class StoredObjectManager implements StoredObjectManagerInterface
|
||||||
{
|
{
|
||||||
|
private readonly string $baseDir;
|
||||||
|
|
||||||
|
private readonly Filesystem $filesystem;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
ParameterBagInterface $parameterBag,
|
||||||
|
private readonly KeyGenerator $keyGenerator,
|
||||||
|
) {
|
||||||
|
$this->baseDir = $parameterBag->get('chill_doc_store')['local_storage']['base_dir'];
|
||||||
|
$this->filesystem = new Filesystem();
|
||||||
|
}
|
||||||
|
|
||||||
public function getLastModified(StoredObject|StoredObjectVersion $document): \DateTimeInterface
|
public function getLastModified(StoredObject|StoredObjectVersion $document): \DateTimeInterface
|
||||||
{
|
{
|
||||||
// TODO: Implement getLastModified() method.
|
$version = $document instanceof StoredObject ? $document->getCurrentVersion() : $document;
|
||||||
|
|
||||||
|
if (null === $version) {
|
||||||
|
throw StoredObjectManagerException::storedObjectDoesNotContainsVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
$path = $this->buildPath($version->getFilename());
|
||||||
|
|
||||||
|
if (false === $ts = filemtime($path)) {
|
||||||
|
throw StoredObjectManagerException::unableToReadDocumentOnDisk($path);
|
||||||
|
}
|
||||||
|
|
||||||
|
return \DateTimeImmutable::createFromFormat('U', (string) $ts);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getContentLength(StoredObject|StoredObjectVersion $document): int
|
public function getContentLength(StoredObject|StoredObjectVersion $document): int
|
||||||
{
|
{
|
||||||
// TODO: Implement getContentLength() method.
|
return strlen($this->read($document));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function exists(StoredObject|StoredObjectVersion $document): bool
|
public function exists(StoredObject|StoredObjectVersion $document): bool
|
||||||
{
|
{
|
||||||
// TODO: Implement exists() method.
|
$version = $document instanceof StoredObject ? $document->getCurrentVersion() : $document;
|
||||||
|
|
||||||
|
if (null === $version) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$path = $this->buildPath($version->getFilename());
|
||||||
|
|
||||||
|
return $this->filesystem->exists($path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function read(StoredObject|StoredObjectVersion $document): string
|
public function read(StoredObject|StoredObjectVersion $document): string
|
||||||
{
|
{
|
||||||
// TODO: Implement read() method.
|
$version = $document instanceof StoredObject ? $document->getCurrentVersion() : $document;
|
||||||
|
|
||||||
|
if (null === $version) {
|
||||||
|
throw StoredObjectManagerException::storedObjectDoesNotContainsVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
$path = $this->buildPath($version->getFilename());
|
||||||
|
|
||||||
|
if (!file_exists($path)) {
|
||||||
|
throw StoredObjectManagerException::unableToFindDocumentOnDisk($path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false === $content = file_get_contents($path)) {
|
||||||
|
throw StoredObjectManagerException::unableToReadDocumentOnDisk($path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->isVersionEncrypted($version)) {
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
$clearData = openssl_decrypt(
|
||||||
|
$content,
|
||||||
|
self::ALGORITHM,
|
||||||
|
// TODO: Why using this library and not use base64_decode() ?
|
||||||
|
Base64Url::decode($version->getKeyInfos()['k']),
|
||||||
|
\OPENSSL_RAW_DATA,
|
||||||
|
pack('C*', ...$version->getIv())
|
||||||
|
);
|
||||||
|
|
||||||
|
if (false === $clearData) {
|
||||||
|
throw StoredObjectManagerException::unableToDecrypt(openssl_error_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $clearData;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function write(StoredObject $document, string $clearContent, ?string $contentType = null): StoredObjectVersion
|
public function write(StoredObject $document, string $clearContent, ?string $contentType = null): StoredObjectVersion
|
||||||
{
|
{
|
||||||
// TODO: Implement write() method.
|
$newIv = $document->isEncrypted() ? $document->getIv() : $this->keyGenerator->generateIv();
|
||||||
|
$newKey = $document->isEncrypted() ? $document->getKeyInfos() : $this->keyGenerator->generateKey(self::ALGORITHM);
|
||||||
|
$newType = $contentType ?? $document->getType();
|
||||||
|
$version = $document->registerVersion(
|
||||||
|
$newIv,
|
||||||
|
$newKey,
|
||||||
|
$newType
|
||||||
|
);
|
||||||
|
|
||||||
|
$encryptedContent = $this->isVersionEncrypted($version)
|
||||||
|
? openssl_encrypt(
|
||||||
|
$clearContent,
|
||||||
|
self::ALGORITHM,
|
||||||
|
// TODO: Why using this library and not use base64_decode() ?
|
||||||
|
Base64Url::decode($version->getKeyInfos()['k']),
|
||||||
|
\OPENSSL_RAW_DATA,
|
||||||
|
pack('C*', ...$version->getIv())
|
||||||
|
)
|
||||||
|
: $clearContent;
|
||||||
|
|
||||||
|
if (false === $encryptedContent) {
|
||||||
|
throw StoredObjectManagerException::unableToEncryptDocument((string) openssl_error_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
$fullPath = $this->buildPath($version->getFilename());
|
||||||
|
$dir = Path::getDirectory($fullPath);
|
||||||
|
|
||||||
|
if (!$this->filesystem->exists($dir)) {
|
||||||
|
$this->filesystem->mkdir($dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = file_put_contents($fullPath, $encryptedContent);
|
||||||
|
|
||||||
|
if (false === $result) {
|
||||||
|
throw StoredObjectManagerException::unableToStoreDocumentOnDisk();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $version;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildPath(string $filename): string
|
||||||
|
{
|
||||||
|
$dirs = [$this->baseDir];
|
||||||
|
|
||||||
|
for ($i = 0; $i < min(strlen($filename), 8); ++$i) {
|
||||||
|
$dirs[] = $filename[$i];
|
||||||
|
}
|
||||||
|
|
||||||
|
$dirs[] = $filename;
|
||||||
|
|
||||||
|
return Path::canonicalize(implode(DIRECTORY_SEPARATOR, $dirs));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function delete(StoredObjectVersion $storedObjectVersion): void
|
public function delete(StoredObjectVersion $storedObjectVersion): void
|
||||||
{
|
{
|
||||||
// TODO: Implement delete() method.
|
if (!$this->exists($storedObjectVersion)) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$path = $this->buildPath($storedObjectVersion->getFilename());
|
||||||
|
|
||||||
|
$this->filesystem->remove($path);
|
||||||
|
$this->removeDirectoriesRecursively(Path::getDirectory($path));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function removeDirectoriesRecursively(string $path): void
|
||||||
|
{
|
||||||
|
if ($path === $this->baseDir) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$files = scandir($path);
|
||||||
|
|
||||||
|
// if it does contains only "." and "..", we can remove the directory
|
||||||
|
if (2 === count($files) && in_array('.', $files, true) && in_array('..', $files, true)) {
|
||||||
|
$this->filesystem->remove($path);
|
||||||
|
$this->removeDirectoriesRecursively(Path::getDirectory($path));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws StoredObjectManagerException
|
||||||
|
*/
|
||||||
public function etag(StoredObject|StoredObjectVersion $document): string
|
public function etag(StoredObject|StoredObjectVersion $document): string
|
||||||
{
|
{
|
||||||
// TODO: Implement etag() method.
|
return md5($this->read($document));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function clearCache(): void
|
public function clearCache(): void
|
||||||
{
|
{
|
||||||
// TODO: Implement clearCache() method.
|
// there is no cache: nothing to do here !
|
||||||
|
}
|
||||||
|
|
||||||
|
private function isVersionEncrypted(StoredObjectVersion $storedObjectVersion): bool
|
||||||
|
{
|
||||||
|
return $storedObjectVersion->isEncrypted();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,8 +25,6 @@ use Symfony\Contracts\HttpClient\ResponseInterface;
|
|||||||
|
|
||||||
final class StoredObjectManager implements StoredObjectManagerInterface
|
final class StoredObjectManager implements StoredObjectManagerInterface
|
||||||
{
|
{
|
||||||
private const ALGORITHM = 'AES-256-CBC';
|
|
||||||
|
|
||||||
private array $inMemory = [];
|
private array $inMemory = [];
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
@ -362,6 +360,6 @@ final class StoredObjectManager implements StoredObjectManagerInterface
|
|||||||
|
|
||||||
private function isVersionEncrypted(StoredObjectVersion $storedObjectVersion): bool
|
private function isVersionEncrypted(StoredObjectVersion $storedObjectVersion): bool
|
||||||
{
|
{
|
||||||
return ([] !== $storedObjectVersion->getKeyInfos()) && ([] !== $storedObjectVersion->getIv());
|
return $storedObjectVersion->isEncrypted();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -448,4 +448,12 @@ class StoredObject implements Document, TrackCreationInterface
|
|||||||
{
|
{
|
||||||
return $storedObject->getDeleteAt() < $now && $storedObject->getVersions()->isEmpty();
|
return $storedObject->getDeleteAt() < $now && $storedObject->getVersions()->isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if it has a current version, and if the current version is encrypted.
|
||||||
|
*/
|
||||||
|
public function isEncrypted(): bool
|
||||||
|
{
|
||||||
|
return $this->hasCurrentVersion() && $this->getCurrentVersion()->isEncrypted();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -226,4 +226,9 @@ class StoredObjectVersion implements TrackCreationInterface
|
|||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isEncrypted(): bool
|
||||||
|
{
|
||||||
|
return ([] !== $this->getKeyInfos()) && ([] !== $this->getIv());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,4 +34,29 @@ final class StoredObjectManagerException extends \Exception
|
|||||||
{
|
{
|
||||||
return new self('Unable to get content from response.', 500, $exception);
|
return new self('Unable to get content from response.', 500, $exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function unableToStoreDocumentOnDisk(?\Throwable $exception = null): self
|
||||||
|
{
|
||||||
|
return new self('Unable to store document on disk.', previous: $exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function unableToFindDocumentOnDisk(string $path): self
|
||||||
|
{
|
||||||
|
return new self('Unable to find document on disk at path "'.$path.'".');
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function unableToReadDocumentOnDisk(string $path): self
|
||||||
|
{
|
||||||
|
return new self('Unable to read document on disk at path "'.$path.'".');
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function unableToEncryptDocument(string $errors): self
|
||||||
|
{
|
||||||
|
return new self('Unable to encrypt document: '.$errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function storedObjectDoesNotContainsVersion(): self
|
||||||
|
{
|
||||||
|
return new self('Stored object does not contains any version');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\DocStoreBundle\Service\Cryptography;
|
||||||
|
|
||||||
|
use Base64Url\Base64Url;
|
||||||
|
use Chill\DocStoreBundle\Service\StoredObjectManagerInterface;
|
||||||
|
use Random\Randomizer;
|
||||||
|
|
||||||
|
class KeyGenerator
|
||||||
|
{
|
||||||
|
private readonly Randomizer $randomizer;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->randomizer = new Randomizer();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array{alg: string, ext: bool, k: string, key_ops: list<string>, kty: string}
|
||||||
|
*/
|
||||||
|
public function generateKey(string $algo = StoredObjectManagerInterface::ALGORITHM): array
|
||||||
|
{
|
||||||
|
if (StoredObjectManagerInterface::ALGORITHM !== $algo) {
|
||||||
|
throw new \LogicException(sprintf("Algorithm '%s' is not supported.", $algo));
|
||||||
|
}
|
||||||
|
|
||||||
|
$key = $this->randomizer->getBytes(128);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'alg' => 'A256CBC',
|
||||||
|
'ext' => true,
|
||||||
|
'k' => Base64Url::encode($key),
|
||||||
|
'key_ops' => ['encrypt', 'decrypt'],
|
||||||
|
'kty' => 'oct',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return list<int<0, 255>>
|
||||||
|
*/
|
||||||
|
public function generateIv(): array
|
||||||
|
{
|
||||||
|
$iv = [];
|
||||||
|
for ($i = 0; $i < 16; ++$i) {
|
||||||
|
$iv[] = unpack('C', $this->randomizer->getBytes(8))[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $iv;
|
||||||
|
}
|
||||||
|
}
|
@ -18,6 +18,8 @@ use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
|
|||||||
|
|
||||||
interface StoredObjectManagerInterface
|
interface StoredObjectManagerInterface
|
||||||
{
|
{
|
||||||
|
public const ALGORITHM = 'AES-256-CBC';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param StoredObject|StoredObjectVersion $document if a StoredObject is given, the last version will be used
|
* @param StoredObject|StoredObjectVersion $document if a StoredObject is given, the last version will be used
|
||||||
*/
|
*/
|
||||||
|
@ -0,0 +1,160 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\DocStoreBundle\Tests\AsyncUpload\Driver\LocalStorage;
|
||||||
|
|
||||||
|
use Chill\DocStoreBundle\AsyncUpload\Driver\LocalStorage\StoredObjectManager;
|
||||||
|
use Chill\DocStoreBundle\Entity\StoredObject;
|
||||||
|
use Chill\DocStoreBundle\Entity\StoredObjectVersion;
|
||||||
|
use Chill\DocStoreBundle\Service\Cryptography\KeyGenerator;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
|
* @coversNothing
|
||||||
|
*/
|
||||||
|
class StoredObjectManagerTest extends TestCase
|
||||||
|
{
|
||||||
|
private const CONTENT = 'abcde';
|
||||||
|
|
||||||
|
public function testWrite(): StoredObjectVersion
|
||||||
|
{
|
||||||
|
$storedObject = new StoredObject();
|
||||||
|
|
||||||
|
$manager = $this->buildStoredObjectManager();
|
||||||
|
$version = $manager->write($storedObject, self::CONTENT);
|
||||||
|
|
||||||
|
self::assertSame($storedObject, $version->getStoredObject());
|
||||||
|
|
||||||
|
return $version;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @depends testWrite
|
||||||
|
*/
|
||||||
|
public function testRead(StoredObjectVersion $version): StoredObjectVersion
|
||||||
|
{
|
||||||
|
$manager = $this->buildStoredObjectManager();
|
||||||
|
$content = $manager->read($version);
|
||||||
|
|
||||||
|
self::assertEquals(self::CONTENT, $content);
|
||||||
|
|
||||||
|
return $version;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @depends testRead
|
||||||
|
*/
|
||||||
|
public function testExists(StoredObjectVersion $version): StoredObjectVersion
|
||||||
|
{
|
||||||
|
$manager = $this->buildStoredObjectManager();
|
||||||
|
$notExisting = new StoredObject();
|
||||||
|
$versionNotPersisted = $notExisting->registerVersion();
|
||||||
|
|
||||||
|
self::assertTrue($manager->exists($version));
|
||||||
|
self::assertFalse($manager->exists($versionNotPersisted));
|
||||||
|
self::assertFalse($manager->exists(new StoredObject()));
|
||||||
|
|
||||||
|
return $version;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws \Chill\DocStoreBundle\Exception\StoredObjectManagerException
|
||||||
|
*
|
||||||
|
* @depends testExists
|
||||||
|
*/
|
||||||
|
public function testEtag(StoredObjectVersion $version): StoredObjectVersion
|
||||||
|
{
|
||||||
|
$manager = $this->buildStoredObjectManager();
|
||||||
|
$actual = $manager->etag($version);
|
||||||
|
|
||||||
|
self::assertEquals(md5(self::CONTENT), $actual);
|
||||||
|
|
||||||
|
return $version;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @depends testEtag
|
||||||
|
*/
|
||||||
|
public function testGetContentLength(StoredObjectVersion $version): StoredObjectVersion
|
||||||
|
{
|
||||||
|
$manager = $this->buildStoredObjectManager();
|
||||||
|
|
||||||
|
$actual = $manager->getContentLength($version);
|
||||||
|
|
||||||
|
self::assertSame(5, $actual);
|
||||||
|
|
||||||
|
return $version;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws \Chill\DocStoreBundle\Exception\StoredObjectManagerException
|
||||||
|
*
|
||||||
|
* @depends testGetContentLength
|
||||||
|
*/
|
||||||
|
public function testGetLastModified(StoredObjectVersion $version): StoredObjectVersion
|
||||||
|
{
|
||||||
|
$manager = $this->buildStoredObjectManager();
|
||||||
|
$actual = $manager->getLastModified($version);
|
||||||
|
|
||||||
|
self::assertInstanceOf(\DateTimeImmutable::class, $actual);
|
||||||
|
self::assertGreaterThan((new \DateTimeImmutable('now'))->getTimestamp() - 10, $actual->getTimestamp());
|
||||||
|
|
||||||
|
return $version;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @depends testGetLastModified
|
||||||
|
*/
|
||||||
|
public function testDelete(StoredObjectVersion $version): void
|
||||||
|
{
|
||||||
|
$manager = $this->buildStoredObjectManager();
|
||||||
|
$manager->delete($version);
|
||||||
|
|
||||||
|
self::assertFalse($manager->exists($version));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDeleteDoesNotRemoveOlderVersion(): void
|
||||||
|
{
|
||||||
|
$storedObject = new StoredObject();
|
||||||
|
$manager = $this->buildStoredObjectManager();
|
||||||
|
$version1 = $manager->write($storedObject, 'version1');
|
||||||
|
$version2 = $manager->write($storedObject, 'version2');
|
||||||
|
$version3 = $manager->write($storedObject, 'version3');
|
||||||
|
|
||||||
|
self::assertTrue($manager->exists($version1));
|
||||||
|
self::assertEquals('version1', $manager->read($version1));
|
||||||
|
self::assertTrue($manager->exists($version2));
|
||||||
|
self::assertEquals('version2', $manager->read($version2));
|
||||||
|
self::assertTrue($manager->exists($version3));
|
||||||
|
self::assertEquals('version3', $manager->read($version3));
|
||||||
|
|
||||||
|
// we delete the intermediate version
|
||||||
|
$manager->delete($version2);
|
||||||
|
|
||||||
|
self::assertFalse($manager->exists($version2));
|
||||||
|
// we check that we are still able to download the other versions
|
||||||
|
self::assertTrue($manager->exists($version1));
|
||||||
|
self::assertEquals('version1', $manager->read($version1));
|
||||||
|
self::assertTrue($manager->exists($version3));
|
||||||
|
self::assertEquals('version3', $manager->read($version3));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildStoredObjectManager(): StoredObjectManager
|
||||||
|
{
|
||||||
|
return new StoredObjectManager(
|
||||||
|
new ParameterBag(['chill_doc_store' => ['local_storage' => ['base_dir' => '/tmp/chill-local-storage-test']]]),
|
||||||
|
new KeyGenerator(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\DocStoreBundle\Tests\Service\Cryptography;
|
||||||
|
|
||||||
|
use Chill\DocStoreBundle\Service\Cryptography\KeyGenerator;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
|
* @coversNothing
|
||||||
|
*/
|
||||||
|
class KeyGeneratorTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testGenerateKey(): void
|
||||||
|
{
|
||||||
|
$keyGenerator = new KeyGenerator();
|
||||||
|
|
||||||
|
$key = $keyGenerator->generateKey();
|
||||||
|
|
||||||
|
self::assertNotEmpty($key['k']);
|
||||||
|
self::assertEquals('A256CBC', $key['alg']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGenerateIv(): void
|
||||||
|
{
|
||||||
|
$keyGenerator = new KeyGenerator();
|
||||||
|
|
||||||
|
$actual = $keyGenerator->generateIv();
|
||||||
|
|
||||||
|
self::assertCount(16, $actual);
|
||||||
|
foreach ($actual as $value) {
|
||||||
|
self::assertIsInt($value);
|
||||||
|
self::assertGreaterThanOrEqual(0, $value);
|
||||||
|
self::assertLessThan(256, $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user