mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-13 05:44:24 +00:00
Apply new CS rules on the webdav feature
This commit is contained in:
parent
813a80d6f9
commit
a0328b9d68
@ -19,6 +19,7 @@ use Symfony\Component\Security\Core\Authentication\Token\AbstractToken;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
|
*
|
||||||
* @coversNothing
|
* @coversNothing
|
||||||
*/
|
*/
|
||||||
class DavTokenAuthenticationEventSubscriberTest extends TestCase
|
class DavTokenAuthenticationEventSubscriberTest extends TestCase
|
||||||
|
@ -16,7 +16,6 @@ use Chill\DocStoreBundle\Dav\Response\DavResponse;
|
|||||||
use Chill\DocStoreBundle\Entity\StoredObject;
|
use Chill\DocStoreBundle\Entity\StoredObject;
|
||||||
use Chill\DocStoreBundle\Security\Authorization\StoredObjectRoleEnum;
|
use Chill\DocStoreBundle\Security\Authorization\StoredObjectRoleEnum;
|
||||||
use Chill\DocStoreBundle\Service\StoredObjectManagerInterface;
|
use Chill\DocStoreBundle\Service\StoredObjectManagerInterface;
|
||||||
use DateTimeInterface;
|
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
||||||
@ -42,7 +41,7 @@ final readonly class WebdavController
|
|||||||
public function __construct(
|
public function __construct(
|
||||||
private \Twig\Environment $engine,
|
private \Twig\Environment $engine,
|
||||||
private StoredObjectManagerInterface $storedObjectManager,
|
private StoredObjectManagerInterface $storedObjectManager,
|
||||||
private Security $security,
|
private Security $security,
|
||||||
) {
|
) {
|
||||||
$this->requestAnalyzer = new PropfindRequestAnalyzer();
|
$this->requestAnalyzer = new PropfindRequestAnalyzer();
|
||||||
}
|
}
|
||||||
@ -73,11 +72,11 @@ final readonly class WebdavController
|
|||||||
throw new AccessDeniedHttpException();
|
throw new AccessDeniedHttpException();
|
||||||
}
|
}
|
||||||
|
|
||||||
$response = (new DavResponse(""))
|
$response = (new DavResponse(''))
|
||||||
->setEtag($this->storedObjectManager->etag($storedObject))
|
->setEtag($this->storedObjectManager->etag($storedObject))
|
||||||
;
|
;
|
||||||
|
|
||||||
//$response->headers->add(['Allow' => 'OPTIONS,GET,HEAD,DELETE,PROPFIND,PUT,PROPPATCH,COPY,MOVE,REPORT,PATCH,POST,TRACE']);
|
// $response->headers->add(['Allow' => 'OPTIONS,GET,HEAD,DELETE,PROPFIND,PUT,PROPPATCH,COPY,MOVE,REPORT,PATCH,POST,TRACE']);
|
||||||
$response->headers->add(['Allow' => 'OPTIONS,GET,HEAD,DELETE,PROPFIND,PUT']);
|
$response->headers->add(['Allow' => 'OPTIONS,GET,HEAD,DELETE,PROPFIND,PUT']);
|
||||||
|
|
||||||
return $response;
|
return $response;
|
||||||
@ -94,8 +93,8 @@ final readonly class WebdavController
|
|||||||
|
|
||||||
$depth = $request->headers->get('depth');
|
$depth = $request->headers->get('depth');
|
||||||
|
|
||||||
if ("0" !== $depth && "1" !== $depth) {
|
if ('0' !== $depth && '1' !== $depth) {
|
||||||
throw new BadRequestHttpException("only 1 and 0 are accepted for Depth header");
|
throw new BadRequestHttpException('only 1 and 0 are accepted for Depth header');
|
||||||
}
|
}
|
||||||
|
|
||||||
[$properties, $lastModified, $etag, $length] = $this->parseDavRequest($request->getContent(), $storedObject);
|
[$properties, $lastModified, $etag, $length] = $this->parseDavRequest($request->getContent(), $storedObject);
|
||||||
@ -104,7 +103,7 @@ final readonly class WebdavController
|
|||||||
$this->engine->render('@ChillDocStore/Webdav/directory_propfind.xml.twig', [
|
$this->engine->render('@ChillDocStore/Webdav/directory_propfind.xml.twig', [
|
||||||
'stored_object' => $storedObject,
|
'stored_object' => $storedObject,
|
||||||
'properties' => $properties,
|
'properties' => $properties,
|
||||||
'last_modified' => $lastModified ,
|
'last_modified' => $lastModified,
|
||||||
'etag' => $etag,
|
'etag' => $etag,
|
||||||
'content_length' => $length,
|
'content_length' => $length,
|
||||||
'depth' => (int) $depth,
|
'depth' => (int) $depth,
|
||||||
@ -114,7 +113,7 @@ final readonly class WebdavController
|
|||||||
);
|
);
|
||||||
|
|
||||||
$response->headers->add([
|
$response->headers->add([
|
||||||
'Content-Type' => 'text/xml'
|
'Content-Type' => 'text/xml',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return $response;
|
return $response;
|
||||||
@ -142,13 +141,13 @@ final readonly class WebdavController
|
|||||||
throw new AccessDeniedHttpException();
|
throw new AccessDeniedHttpException();
|
||||||
}
|
}
|
||||||
|
|
||||||
$response = new DavResponse("");
|
$response = new DavResponse('');
|
||||||
|
|
||||||
$response->headers->add(
|
$response->headers->add(
|
||||||
[
|
[
|
||||||
'Content-Length' => $this->storedObjectManager->getContentLength($storedObject),
|
'Content-Length' => $this->storedObjectManager->getContentLength($storedObject),
|
||||||
'Content-Type' => $storedObject->getType(),
|
'Content-Type' => $storedObject->getType(),
|
||||||
'Etag' => $this->storedObjectManager->etag($storedObject)
|
'Etag' => $this->storedObjectManager->etag($storedObject),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -164,7 +163,7 @@ final readonly class WebdavController
|
|||||||
throw new AccessDeniedHttpException();
|
throw new AccessDeniedHttpException();
|
||||||
}
|
}
|
||||||
|
|
||||||
$response = (new DavResponse(""))
|
$response = (new DavResponse(''))
|
||||||
->setEtag($this->storedObjectManager->etag($storedObject))
|
->setEtag($this->storedObjectManager->etag($storedObject))
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -201,7 +200,7 @@ final readonly class WebdavController
|
|||||||
|
|
||||||
$response
|
$response
|
||||||
->headers->add([
|
->headers->add([
|
||||||
'Content-Type' => 'text/xml'
|
'Content-Type' => 'text/xml',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return $response;
|
return $response;
|
||||||
@ -218,11 +217,11 @@ final readonly class WebdavController
|
|||||||
|
|
||||||
$this->storedObjectManager->write($storedObject, $request->getContent());
|
$this->storedObjectManager->write($storedObject, $request->getContent());
|
||||||
|
|
||||||
return (new DavResponse("", Response::HTTP_NO_CONTENT));
|
return new DavResponse('', Response::HTTP_NO_CONTENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array{0: array, 1: DateTimeInterface, 2: string, 3: int} properties, lastModified, etag, length
|
* @return array{0: array, 1: \DateTimeInterface, 2: string, 3: int} properties, lastModified, etag, length
|
||||||
*/
|
*/
|
||||||
private function parseDavRequest(string $content, StoredObject $storedObject): array
|
private function parseDavRequest(string $content, StoredObject $storedObject): array
|
||||||
{
|
{
|
||||||
@ -247,7 +246,7 @@ final readonly class WebdavController
|
|||||||
$properties,
|
$properties,
|
||||||
$lastModified ?? null,
|
$lastModified ?? null,
|
||||||
$etag ?? null,
|
$etag ?? null,
|
||||||
$length ?? null
|
$length ?? null,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,4 +11,6 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Chill\DocStoreBundle\Dav\Exception;
|
namespace Chill\DocStoreBundle\Dav\Exception;
|
||||||
|
|
||||||
class ParseRequestException extends \UnexpectedValueException {}
|
class ParseRequestException extends \UnexpectedValueException
|
||||||
|
{
|
||||||
|
}
|
||||||
|
@ -36,17 +36,17 @@ class PropfindRequestAnalyzer
|
|||||||
$propfinds = $request->getElementsByTagNameNS('DAV:', 'propfind');
|
$propfinds = $request->getElementsByTagNameNS('DAV:', 'propfind');
|
||||||
|
|
||||||
if (0 === $propfinds->count()) {
|
if (0 === $propfinds->count()) {
|
||||||
throw new ParseRequestException("any propfind element found");
|
throw new ParseRequestException('any propfind element found');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (1 < $propfinds->count()) {
|
if (1 < $propfinds->count()) {
|
||||||
throw new ParseRequestException("too much propfind element found");
|
throw new ParseRequestException('too much propfind element found');
|
||||||
}
|
}
|
||||||
|
|
||||||
$propfind = $propfinds->item(0);
|
$propfind = $propfinds->item(0);
|
||||||
|
|
||||||
if (0 === $propfind->childNodes->count()) {
|
if (0 === $propfind->childNodes->count()) {
|
||||||
throw new ParseRequestException("no element under propfind");
|
throw new ParseRequestException('no element under propfind');
|
||||||
}
|
}
|
||||||
|
|
||||||
$unknows = [];
|
$unknows = [];
|
||||||
@ -79,7 +79,6 @@ class PropfindRequestAnalyzer
|
|||||||
default => '',
|
default => '',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$props = array_filter(array_values($props), fn (string $item) => '' !== $item);
|
$props = array_filter(array_values($props), fn (string $item) => '' !== $item);
|
||||||
@ -98,7 +97,7 @@ class PropfindRequestAnalyzer
|
|||||||
self::KNOWN_PROPS,
|
self::KNOWN_PROPS,
|
||||||
array_fill(0, count(self::KNOWN_PROPS), $default)
|
array_fill(0, count(self::KNOWN_PROPS), $default)
|
||||||
),
|
),
|
||||||
'unknowns' => []
|
'unknowns' => [],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,8 +34,7 @@ class StoredObjectVoter extends Voter
|
|||||||
/** @var StoredObject $subject */
|
/** @var StoredObject $subject */
|
||||||
if (
|
if (
|
||||||
!$token->hasAttribute(DavTokenAuthenticationEventSubscriber::STORED_OBJECT)
|
!$token->hasAttribute(DavTokenAuthenticationEventSubscriber::STORED_OBJECT)
|
||||||
||
|
|| $subject->getUuid()->toString() !== $token->getAttribute(DavTokenAuthenticationEventSubscriber::STORED_OBJECT)
|
||||||
$subject->getUuid()->toString() !== $token->getAttribute(DavTokenAuthenticationEventSubscriber::STORED_OBJECT)
|
|
||||||
) {
|
) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -49,9 +48,8 @@ class StoredObjectVoter extends Voter
|
|||||||
$token->getAttribute(DavTokenAuthenticationEventSubscriber::ACTIONS);
|
$token->getAttribute(DavTokenAuthenticationEventSubscriber::ACTIONS);
|
||||||
|
|
||||||
return match ($askedRole) {
|
return match ($askedRole) {
|
||||||
StoredObjectRoleEnum::SEE =>
|
StoredObjectRoleEnum::SEE => StoredObjectRoleEnum::EDIT === $tokenRoleAuthorization || StoredObjectRoleEnum::SEE === $tokenRoleAuthorization,
|
||||||
$tokenRoleAuthorization === StoredObjectRoleEnum::EDIT || $tokenRoleAuthorization === StoredObjectRoleEnum::SEE,
|
StoredObjectRoleEnum::EDIT => StoredObjectRoleEnum::EDIT === $tokenRoleAuthorization
|
||||||
StoredObjectRoleEnum::EDIT => $tokenRoleAuthorization === StoredObjectRoleEnum::EDIT
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,9 +27,10 @@ final readonly class DavOnUrlTokenExtractor implements TokenExtractorInterface
|
|||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private LoggerInterface $logger,
|
private LoggerInterface $logger,
|
||||||
) {}
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
public function extract(Request $request): string|false
|
public function extract(Request $request): false|string
|
||||||
{
|
{
|
||||||
$uri = $request->getRequestUri();
|
$uri = $request->getRequestUri();
|
||||||
|
|
||||||
@ -41,13 +42,13 @@ final readonly class DavOnUrlTokenExtractor implements TokenExtractorInterface
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (2 > count($segments)) {
|
if (2 > count($segments)) {
|
||||||
$this->logger->info("not enough segment for parsing URL");
|
$this->logger->info('not enough segment for parsing URL');
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ('dav' !== $segments[0]) {
|
if ('dav' !== $segments[0]) {
|
||||||
$this->logger->info("the first segment of the url must be DAV");
|
$this->logger->info('the first segment of the url must be DAV');
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -43,11 +43,9 @@ class DavTokenAuthenticationEventSubscriber implements EventSubscriberInterface
|
|||||||
$token->setAttribute(self::ACTIONS, match ($payload['e']) {
|
$token->setAttribute(self::ACTIONS, match ($payload['e']) {
|
||||||
0 => StoredObjectRoleEnum::SEE,
|
0 => StoredObjectRoleEnum::SEE,
|
||||||
1 => StoredObjectRoleEnum::EDIT,
|
1 => StoredObjectRoleEnum::EDIT,
|
||||||
default => throw new \UnexpectedValueException("unsupported value for e parameter")
|
default => throw new \UnexpectedValueException('unsupported value for e parameter')
|
||||||
});
|
});
|
||||||
|
|
||||||
$token->setAttribute(self::STORED_OBJECT, $payload['so']);
|
$token->setAttribute(self::STORED_OBJECT, $payload['so']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -17,14 +17,15 @@ use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface;
|
|||||||
use Symfony\Component\Security\Core\Security;
|
use Symfony\Component\Security\Core\Security;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provide a JWT Token which will be valid for viewing or editing a document
|
* Provide a JWT Token which will be valid for viewing or editing a document.
|
||||||
*/
|
*/
|
||||||
final readonly class JWTDavTokenProvider implements JWTDavTokenProviderInterface
|
final readonly class JWTDavTokenProvider implements JWTDavTokenProviderInterface
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private JWTTokenManagerInterface $JWTTokenManager,
|
private JWTTokenManagerInterface $JWTTokenManager,
|
||||||
private Security $security,
|
private Security $security,
|
||||||
) {}
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
public function createToken(StoredObject $storedObject, StoredObjectRoleEnum $roleEnum): string
|
public function createToken(StoredObject $storedObject, StoredObjectRoleEnum $roleEnum): string
|
||||||
{
|
{
|
||||||
@ -44,5 +45,4 @@ final readonly class JWTDavTokenProvider implements JWTDavTokenProviderInterface
|
|||||||
|
|
||||||
return \DateTimeImmutable::createFromFormat('U', (string) $jwt['exp']);
|
return \DateTimeImmutable::createFromFormat('U', (string) $jwt['exp']);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ use Chill\DocStoreBundle\Entity\StoredObject;
|
|||||||
use Chill\DocStoreBundle\Security\Authorization\StoredObjectRoleEnum;
|
use Chill\DocStoreBundle\Security\Authorization\StoredObjectRoleEnum;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provide a JWT Token which will be valid for viewing or editing a document
|
* Provide a JWT Token which will be valid for viewing or editing a document.
|
||||||
*/
|
*/
|
||||||
interface JWTDavTokenProviderInterface
|
interface JWTDavTokenProviderInterface
|
||||||
{
|
{
|
||||||
|
@ -15,7 +15,6 @@ use ChampsLibres\WopiLib\Contract\Service\Discovery\DiscoveryInterface;
|
|||||||
use Chill\DocStoreBundle\Entity\StoredObject;
|
use Chill\DocStoreBundle\Entity\StoredObject;
|
||||||
use Chill\DocStoreBundle\Security\Authorization\StoredObjectRoleEnum;
|
use Chill\DocStoreBundle\Security\Authorization\StoredObjectRoleEnum;
|
||||||
use Chill\DocStoreBundle\Security\Guard\JWTDavTokenProviderInterface;
|
use Chill\DocStoreBundle\Security\Guard\JWTDavTokenProviderInterface;
|
||||||
use Namshi\JOSE\JWS;
|
|
||||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||||
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
|
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
|
||||||
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
||||||
@ -129,7 +128,8 @@ final readonly class WopiEditTwigExtensionRuntime implements RuntimeExtensionInt
|
|||||||
private NormalizerInterface $normalizer,
|
private NormalizerInterface $normalizer,
|
||||||
private JWTDavTokenProviderInterface $davTokenProvider,
|
private JWTDavTokenProviderInterface $davTokenProvider,
|
||||||
private UrlGeneratorInterface $urlGenerator,
|
private UrlGeneratorInterface $urlGenerator,
|
||||||
) {}
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* return true if the document is editable.
|
* return true if the document is editable.
|
||||||
@ -149,7 +149,7 @@ final readonly class WopiEditTwigExtensionRuntime implements RuntimeExtensionInt
|
|||||||
* @throws \Twig\Error\RuntimeError
|
* @throws \Twig\Error\RuntimeError
|
||||||
* @throws \Twig\Error\SyntaxError
|
* @throws \Twig\Error\SyntaxError
|
||||||
*/
|
*/
|
||||||
public function renderButtonGroup(Environment $environment, StoredObject $document, ?string $title = null, bool $canEdit = true, array $options = []): string
|
public function renderButtonGroup(Environment $environment, StoredObject $document, string $title = null, bool $canEdit = true, array $options = []): string
|
||||||
{
|
{
|
||||||
$accessToken = $this->davTokenProvider->createToken(
|
$accessToken = $this->davTokenProvider->createToken(
|
||||||
$document,
|
$document,
|
||||||
@ -174,7 +174,7 @@ final readonly class WopiEditTwigExtensionRuntime implements RuntimeExtensionInt
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function renderEditButton(Environment $environment, StoredObject $document, ?array $options = null): string
|
public function renderEditButton(Environment $environment, StoredObject $document, array $options = null): string
|
||||||
{
|
{
|
||||||
return $environment->render(self::TEMPLATE, [
|
return $environment->render(self::TEMPLATE, [
|
||||||
'document' => $document,
|
'document' => $document,
|
||||||
|
@ -14,18 +14,16 @@ namespace Chill\DocStoreBundle\Tests\Controller;
|
|||||||
use Chill\DocStoreBundle\Controller\WebdavController;
|
use Chill\DocStoreBundle\Controller\WebdavController;
|
||||||
use Chill\DocStoreBundle\Entity\StoredObject;
|
use Chill\DocStoreBundle\Entity\StoredObject;
|
||||||
use Chill\DocStoreBundle\Service\StoredObjectManagerInterface;
|
use Chill\DocStoreBundle\Service\StoredObjectManagerInterface;
|
||||||
use DateTimeInterface;
|
|
||||||
use PHPUnit\Framework\TestCase;
|
|
||||||
use Prophecy\Argument;
|
use Prophecy\Argument;
|
||||||
use Prophecy\PhpUnit\ProphecyTrait;
|
use Prophecy\PhpUnit\ProphecyTrait;
|
||||||
use Ramsey\Uuid\Uuid;
|
use Ramsey\Uuid\Uuid;
|
||||||
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\Security\Core\Security;
|
use Symfony\Component\Security\Core\Security;
|
||||||
use Symfony\Component\Templating\EngineInterface;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
|
*
|
||||||
* @coversNothing
|
* @coversNothing
|
||||||
*/
|
*/
|
||||||
class WebdavControllerTest extends KernelTestCase
|
class WebdavControllerTest extends KernelTestCase
|
||||||
@ -124,7 +122,7 @@ class WebdavControllerTest extends KernelTestCase
|
|||||||
self::assertEquals($expectedStatusCode, $response->getStatusCode());
|
self::assertEquals($expectedStatusCode, $response->getStatusCode());
|
||||||
self::assertContains('content-type', $response->headers->keys());
|
self::assertContains('content-type', $response->headers->keys());
|
||||||
self::assertStringContainsString('text/xml', $response->headers->get('content-type'));
|
self::assertStringContainsString('text/xml', $response->headers->get('content-type'));
|
||||||
self::assertTrue((new \DOMDocument())->loadXML($response->getContent()), $message . " test that the xml response is a valid xml");
|
self::assertTrue((new \DOMDocument())->loadXML($response->getContent()), $message.' test that the xml response is a valid xml');
|
||||||
self::assertXmlStringEqualsXmlString($expectedXmlResponse, $response->getContent(), $message);
|
self::assertXmlStringEqualsXmlString($expectedXmlResponse, $response->getContent(), $message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,13 +135,13 @@ class WebdavControllerTest extends KernelTestCase
|
|||||||
|
|
||||||
$request = new Request([], [], [], [], [], [], $requestContent);
|
$request = new Request([], [], [], [], [], [], $requestContent);
|
||||||
$request->setMethod('PROPFIND');
|
$request->setMethod('PROPFIND');
|
||||||
$request->headers->add(["Depth" => "0"]);
|
$request->headers->add(['Depth' => '0']);
|
||||||
$response = $controller->propfindDirectory($this->buildDocument(), '1234', $request);
|
$response = $controller->propfindDirectory($this->buildDocument(), '1234', $request);
|
||||||
|
|
||||||
self::assertEquals($expectedStatusCode, $response->getStatusCode());
|
self::assertEquals($expectedStatusCode, $response->getStatusCode());
|
||||||
self::assertContains('content-type', $response->headers->keys());
|
self::assertContains('content-type', $response->headers->keys());
|
||||||
self::assertStringContainsString('text/xml', $response->headers->get('content-type'));
|
self::assertStringContainsString('text/xml', $response->headers->get('content-type'));
|
||||||
self::assertTrue((new \DOMDocument())->loadXML($response->getContent()), $message . " test that the xml response is a valid xml");
|
self::assertTrue((new \DOMDocument())->loadXML($response->getContent()), $message.' test that the xml response is a valid xml');
|
||||||
self::assertXmlStringEqualsXmlString($expectedXmlResponse, $response->getContent(), $message);
|
self::assertXmlStringEqualsXmlString($expectedXmlResponse, $response->getContent(), $message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,7 +190,7 @@ class WebdavControllerTest extends KernelTestCase
|
|||||||
</d:multistatus>
|
</d:multistatus>
|
||||||
XML;
|
XML;
|
||||||
|
|
||||||
yield [$content, 207, $response, "get IsReadOnly and contenttype from server"];
|
yield [$content, 207, $response, 'get IsReadOnly and contenttype from server'];
|
||||||
|
|
||||||
$content =
|
$content =
|
||||||
<<<'XML'
|
<<<'XML'
|
||||||
@ -220,7 +218,7 @@ class WebdavControllerTest extends KernelTestCase
|
|||||||
</d:multistatus>
|
</d:multistatus>
|
||||||
XML;
|
XML;
|
||||||
|
|
||||||
yield [$content, 207, $response, "get property IsReadOnly"];
|
yield [$content, 207, $response, 'get property IsReadOnly'];
|
||||||
|
|
||||||
yield [
|
yield [
|
||||||
<<<'XML'
|
<<<'XML'
|
||||||
@ -246,7 +244,7 @@ class WebdavControllerTest extends KernelTestCase
|
|||||||
</d:response>
|
</d:response>
|
||||||
</d:multistatus>
|
</d:multistatus>
|
||||||
XML,
|
XML,
|
||||||
"Test requesting an unknow property"
|
'Test requesting an unknow property',
|
||||||
];
|
];
|
||||||
|
|
||||||
yield [
|
yield [
|
||||||
@ -274,7 +272,7 @@ class WebdavControllerTest extends KernelTestCase
|
|||||||
</d:response>
|
</d:response>
|
||||||
</d:multistatus>
|
</d:multistatus>
|
||||||
XML,
|
XML,
|
||||||
"test getting the last modified date"
|
'test getting the last modified date',
|
||||||
];
|
];
|
||||||
|
|
||||||
yield [
|
yield [
|
||||||
@ -311,7 +309,7 @@ class WebdavControllerTest extends KernelTestCase
|
|||||||
</d:response>
|
</d:response>
|
||||||
</d:multistatus>
|
</d:multistatus>
|
||||||
XML,
|
XML,
|
||||||
"test finding all properties"
|
'test finding all properties',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -356,7 +354,7 @@ class WebdavControllerTest extends KernelTestCase
|
|||||||
</d:response>
|
</d:response>
|
||||||
</d:multistatus>
|
</d:multistatus>
|
||||||
XML,
|
XML,
|
||||||
"test resourceType and IsReadOnly "
|
'test resourceType and IsReadOnly ',
|
||||||
];
|
];
|
||||||
|
|
||||||
yield [
|
yield [
|
||||||
@ -379,15 +377,14 @@ class WebdavControllerTest extends KernelTestCase
|
|||||||
</d:response>
|
</d:response>
|
||||||
</d:multistatus>
|
</d:multistatus>
|
||||||
XML,
|
XML,
|
||||||
"test creatableContentsInfo"
|
'test creatableContentsInfo',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class MockedStoredObjectManager implements StoredObjectManagerInterface
|
class MockedStoredObjectManager implements StoredObjectManagerInterface
|
||||||
{
|
{
|
||||||
public function getLastModified(StoredObject $document): DateTimeInterface
|
public function getLastModified(StoredObject $document): \DateTimeInterface
|
||||||
{
|
{
|
||||||
return new \DateTimeImmutable('2023-09-13T14:15');
|
return new \DateTimeImmutable('2023-09-13T14:15');
|
||||||
}
|
}
|
||||||
@ -402,11 +399,12 @@ class MockedStoredObjectManager implements StoredObjectManagerInterface
|
|||||||
return 'abcde';
|
return 'abcde';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function write(StoredObject $document, string $clearContent): void {}
|
public function write(StoredObject $document, string $clearContent): void
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public function etag(StoredObject $document): string
|
public function etag(StoredObject $document): string
|
||||||
{
|
{
|
||||||
return 'ab56b4d92b40713acc5af89985d4b786';
|
return 'ab56b4d92b40713acc5af89985d4b786';
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -12,11 +12,11 @@ declare(strict_types=1);
|
|||||||
namespace Chill\DocStoreBundle\Tests\Dav\Request;
|
namespace Chill\DocStoreBundle\Tests\Dav\Request;
|
||||||
|
|
||||||
use Chill\DocStoreBundle\Dav\Request\PropfindRequestAnalyzer;
|
use Chill\DocStoreBundle\Dav\Request\PropfindRequestAnalyzer;
|
||||||
use phpseclib3\Crypt\DSA\Formats\Keys\XML;
|
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
|
*
|
||||||
* @coversNothing
|
* @coversNothing
|
||||||
*/
|
*/
|
||||||
class PropfindRequestAnalyzerTest extends TestCase
|
class PropfindRequestAnalyzerTest extends TestCase
|
||||||
@ -33,7 +33,7 @@ class PropfindRequestAnalyzerTest extends TestCase
|
|||||||
$actual = $analyzer->getRequestedProperties($request);
|
$actual = $analyzer->getRequestedProperties($request);
|
||||||
|
|
||||||
foreach ($expected as $key => $value) {
|
foreach ($expected as $key => $value) {
|
||||||
if ($key === 'unknowns') {
|
if ('unknowns' === $key) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,17 +59,17 @@ class PropfindRequestAnalyzerTest extends TestCase
|
|||||||
</propfind>
|
</propfind>
|
||||||
XML,
|
XML,
|
||||||
[
|
[
|
||||||
"resourceType" => false,
|
'resourceType' => false,
|
||||||
"contentType" => false,
|
'contentType' => false,
|
||||||
"lastModified" => false,
|
'lastModified' => false,
|
||||||
"creationDate" => false,
|
'creationDate' => false,
|
||||||
"contentLength" => false,
|
'contentLength' => false,
|
||||||
"etag" => false,
|
'etag' => false,
|
||||||
"supportedLock" => false,
|
'supportedLock' => false,
|
||||||
'unknowns' => [
|
'unknowns' => [
|
||||||
['xmlns' => 'http://ucb.openoffice.org/dav/props/', 'prop' => 'BaseURI']
|
['xmlns' => 'http://ucb.openoffice.org/dav/props/', 'prop' => 'BaseURI'],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
yield [
|
yield [
|
||||||
@ -80,15 +80,15 @@ class PropfindRequestAnalyzerTest extends TestCase
|
|||||||
</propfind>
|
</propfind>
|
||||||
XML,
|
XML,
|
||||||
[
|
[
|
||||||
"resourceType" => true,
|
'resourceType' => true,
|
||||||
"contentType" => true,
|
'contentType' => true,
|
||||||
"lastModified" => true,
|
'lastModified' => true,
|
||||||
"creationDate" => true,
|
'creationDate' => true,
|
||||||
"contentLength" => true,
|
'contentLength' => true,
|
||||||
"etag" => true,
|
'etag' => true,
|
||||||
"supportedLock" => true,
|
'supportedLock' => true,
|
||||||
"unknowns" => [],
|
'unknowns' => [],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
yield [
|
yield [
|
||||||
@ -101,15 +101,15 @@ class PropfindRequestAnalyzerTest extends TestCase
|
|||||||
</propfind>
|
</propfind>
|
||||||
XML,
|
XML,
|
||||||
[
|
[
|
||||||
"resourceType" => false,
|
'resourceType' => false,
|
||||||
"contentType" => false,
|
'contentType' => false,
|
||||||
"lastModified" => true,
|
'lastModified' => true,
|
||||||
"creationDate" => false,
|
'creationDate' => false,
|
||||||
"contentLength" => false,
|
'contentLength' => false,
|
||||||
"etag" => false,
|
'etag' => false,
|
||||||
"supportedLock" => false,
|
'supportedLock' => false,
|
||||||
'unknowns' => []
|
'unknowns' => [],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
yield [
|
yield [
|
||||||
@ -118,17 +118,17 @@ class PropfindRequestAnalyzerTest extends TestCase
|
|||||||
<propfind xmlns="DAV:"><prop><resourcetype xmlns="DAV:"/><IsReadOnly xmlns="http://ucb.openoffice.org/dav/props/"/><getcontenttype xmlns="DAV:"/><supportedlock xmlns="DAV:"/></prop></propfind>
|
<propfind xmlns="DAV:"><prop><resourcetype xmlns="DAV:"/><IsReadOnly xmlns="http://ucb.openoffice.org/dav/props/"/><getcontenttype xmlns="DAV:"/><supportedlock xmlns="DAV:"/></prop></propfind>
|
||||||
XML,
|
XML,
|
||||||
[
|
[
|
||||||
"resourceType" => true,
|
'resourceType' => true,
|
||||||
"contentType" => true,
|
'contentType' => true,
|
||||||
"lastModified" => false,
|
'lastModified' => false,
|
||||||
"creationDate" => false,
|
'creationDate' => false,
|
||||||
"contentLength" => false,
|
'contentLength' => false,
|
||||||
"etag" => false,
|
'etag' => false,
|
||||||
"supportedLock" => false,
|
'supportedLock' => false,
|
||||||
'unknowns' => [
|
'unknowns' => [
|
||||||
['xmlns' => 'http://ucb.openoffice.org/dav/props/', 'prop' => 'IsReadOnly']
|
['xmlns' => 'http://ucb.openoffice.org/dav/props/', 'prop' => 'IsReadOnly'],
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
|
*
|
||||||
* @coversNothing
|
* @coversNothing
|
||||||
*/
|
*/
|
||||||
class StoredObjectVoterTest extends TestCase
|
class StoredObjectVoterTest extends TestCase
|
||||||
@ -31,7 +32,7 @@ class StoredObjectVoterTest extends TestCase
|
|||||||
/**
|
/**
|
||||||
* @dataProvider provideDataVote
|
* @dataProvider provideDataVote
|
||||||
*/
|
*/
|
||||||
public function testVote(TokenInterface $token, object|null $subject, string $attribute, mixed $expected): void
|
public function testVote(TokenInterface $token, null|object $subject, string $attribute, mixed $expected): void
|
||||||
{
|
{
|
||||||
$voter = new StoredObjectVoter();
|
$voter = new StoredObjectVoter();
|
||||||
|
|
||||||
@ -44,28 +45,28 @@ class StoredObjectVoterTest extends TestCase
|
|||||||
$this->buildToken(StoredObjectRoleEnum::EDIT, new StoredObject()),
|
$this->buildToken(StoredObjectRoleEnum::EDIT, new StoredObject()),
|
||||||
new \stdClass(),
|
new \stdClass(),
|
||||||
'SOMETHING',
|
'SOMETHING',
|
||||||
VoterInterface::ACCESS_ABSTAIN
|
VoterInterface::ACCESS_ABSTAIN,
|
||||||
];
|
];
|
||||||
|
|
||||||
yield [
|
yield [
|
||||||
$this->buildToken(StoredObjectRoleEnum::EDIT, $so = new StoredObject()),
|
$this->buildToken(StoredObjectRoleEnum::EDIT, $so = new StoredObject()),
|
||||||
$so,
|
$so,
|
||||||
'SOMETHING',
|
'SOMETHING',
|
||||||
VoterInterface::ACCESS_ABSTAIN
|
VoterInterface::ACCESS_ABSTAIN,
|
||||||
];
|
];
|
||||||
|
|
||||||
yield [
|
yield [
|
||||||
$this->buildToken(StoredObjectRoleEnum::EDIT, $so = new StoredObject()),
|
$this->buildToken(StoredObjectRoleEnum::EDIT, $so = new StoredObject()),
|
||||||
$so,
|
$so,
|
||||||
StoredObjectRoleEnum::SEE->value,
|
StoredObjectRoleEnum::SEE->value,
|
||||||
VoterInterface::ACCESS_GRANTED
|
VoterInterface::ACCESS_GRANTED,
|
||||||
];
|
];
|
||||||
|
|
||||||
yield [
|
yield [
|
||||||
$this->buildToken(StoredObjectRoleEnum::EDIT, $so = new StoredObject()),
|
$this->buildToken(StoredObjectRoleEnum::EDIT, $so = new StoredObject()),
|
||||||
$so,
|
$so,
|
||||||
StoredObjectRoleEnum::EDIT->value,
|
StoredObjectRoleEnum::EDIT->value,
|
||||||
VoterInterface::ACCESS_GRANTED
|
VoterInterface::ACCESS_GRANTED,
|
||||||
];
|
];
|
||||||
|
|
||||||
yield [
|
yield [
|
||||||
@ -79,7 +80,7 @@ class StoredObjectVoterTest extends TestCase
|
|||||||
$this->buildToken(StoredObjectRoleEnum::SEE, $so = new StoredObject()),
|
$this->buildToken(StoredObjectRoleEnum::SEE, $so = new StoredObject()),
|
||||||
$so,
|
$so,
|
||||||
StoredObjectRoleEnum::SEE->value,
|
StoredObjectRoleEnum::SEE->value,
|
||||||
VoterInterface::ACCESS_GRANTED
|
VoterInterface::ACCESS_GRANTED,
|
||||||
];
|
];
|
||||||
|
|
||||||
yield [
|
yield [
|
||||||
@ -97,8 +98,7 @@ class StoredObjectVoterTest extends TestCase
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function buildToken(StoredObjectRoleEnum $storedObjectRoleEnum = null, StoredObject $storedObject = null): TokenInterface
|
||||||
private function buildToken(?StoredObjectRoleEnum $storedObjectRoleEnum = null, ?StoredObject $storedObject = null): TokenInterface
|
|
||||||
{
|
{
|
||||||
$token = $this->prophesize(TokenInterface::class);
|
$token = $this->prophesize(TokenInterface::class);
|
||||||
|
|
||||||
@ -110,7 +110,6 @@ class StoredObjectVoterTest extends TestCase
|
|||||||
$token->getAttribute(DavTokenAuthenticationEventSubscriber::ACTIONS)->willThrow(new \InvalidArgumentException());
|
$token->getAttribute(DavTokenAuthenticationEventSubscriber::ACTIONS)->willThrow(new \InvalidArgumentException());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (null !== $storedObject) {
|
if (null !== $storedObject) {
|
||||||
$token->hasAttribute(DavTokenAuthenticationEventSubscriber::STORED_OBJECT)->willReturn(true);
|
$token->hasAttribute(DavTokenAuthenticationEventSubscriber::STORED_OBJECT)->willReturn(true);
|
||||||
$token->getAttribute(DavTokenAuthenticationEventSubscriber::STORED_OBJECT)->willReturn($storedObject->getUuid()->toString());
|
$token->getAttribute(DavTokenAuthenticationEventSubscriber::STORED_OBJECT)->willReturn($storedObject->getUuid()->toString());
|
||||||
|
@ -19,6 +19,7 @@ use Symfony\Component\HttpFoundation\Request;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
|
*
|
||||||
* @coversNothing
|
* @coversNothing
|
||||||
*/
|
*/
|
||||||
class DavOnUrlTokenExtractorTest extends TestCase
|
class DavOnUrlTokenExtractorTest extends TestCase
|
||||||
@ -28,7 +29,7 @@ class DavOnUrlTokenExtractorTest extends TestCase
|
|||||||
/**
|
/**
|
||||||
* @dataProvider provideDataUri
|
* @dataProvider provideDataUri
|
||||||
*/
|
*/
|
||||||
public function testExtract(string $uri, string|false $expected): void
|
public function testExtract(string $uri, false|string $expected): void
|
||||||
{
|
{
|
||||||
$request = $this->prophesize(Request::class);
|
$request = $this->prophesize(Request::class);
|
||||||
$request->getRequestUri()->willReturn($uri);
|
$request->getRequestUri()->willReturn($uri);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user