Initial commit: CloudOps infrastructure platform

This commit is contained in:
root
2026-04-09 19:58:57 +02:00
commit 1166a52f26
7762 changed files with 839452 additions and 0 deletions

View File

@@ -0,0 +1,61 @@
<?php
namespace Mautic\AssetBundle\Tests\Controller\Api;
use Mautic\CoreBundle\Test\MauticMysqlTestCase;
class AssetApiControllerFunctionalTest extends MauticMysqlTestCase
{
public function testCreateNewRemoteAsset(): void
{
$payload = [
'file' => 'https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf',
'storageLocation' => 'remote',
'title' => 'title',
];
$this->client->request('POST', 'api/assets/new', $payload);
$clientResponse = $this->client->getResponse();
$this->assertResponseStatusCodeSame(201, $clientResponse->getContent());
$response = json_decode($clientResponse->getContent(), true);
$this->assertEquals($payload['title'], $response['asset']['title']);
$this->assertEquals($payload['storageLocation'], $response['asset']['storageLocation']);
$this->assertStringContainsString('application/pdf', $response['asset']['mime']);
$this->assertStringContainsString('pdf', $response['asset']['extension']);
$this->assertNotNull($response['asset']['size']);
}
public function testCreateNewRemoteAssetWithVulnerableFile(): void
{
$payload = [
'file' => 'file:///etc/passwd',
'storageLocation' => 'remote',
'title' => 'title',
];
$this->client->request('POST', 'api/assets/new', $payload);
$clientResponse = $this->client->getResponse();
$this->assertResponseStatusCodeSame(400, $clientResponse->getContent());
$this->assertEquals('{"errors":[{"code":400,"message":"remotePath: The remote should be a valid URL.","details":{"remotePath":["The remote should be a valid URL."]}}]}', $clientResponse->getContent());
}
public function testCreateNewLocalAsset(): void
{
$assetsPath = $this->client->getKernel()->getContainer()->getParameter('mautic.upload_dir');
file_put_contents($assetsPath.'/file.txt', 'test');
$payload = [
'file' => 'file.txt',
'storageLocation' => 'local',
'title' => 'title',
];
$this->client->request('POST', 'api/assets/new', $payload);
$clientResponse = $this->client->getResponse();
$this->assertResponseStatusCodeSame(201, $clientResponse->getContent());
$response = json_decode($clientResponse->getContent(), true);
$this->assertEquals($payload['title'], $response['asset']['title']);
$this->assertEquals($payload['storageLocation'], $response['asset']['storageLocation']);
$this->assertStringContainsString('text/plain', $response['asset']['mime']);
$this->assertNotNull($response['asset']['size']);
$this->assertStringContainsString('txt', $response['asset']['extension']);
unlink($assetsPath.'/file.txt');
}
}

View File

@@ -0,0 +1,388 @@
<?php
declare(strict_types=1);
namespace Mautic\AssetBundle\Tests\Controller;
use Mautic\AssetBundle\Entity\Asset;
use Mautic\AssetBundle\Tests\Asset\AbstractAssetTestCase;
use Mautic\CoreBundle\Tests\Traits\ControllerTrait;
use Mautic\PageBundle\Tests\Controller\PageControllerTest;
use Mautic\ProjectBundle\Entity\Project;
use Mautic\UserBundle\Entity\Permission;
use Mautic\UserBundle\Entity\User;
use Mautic\UserBundle\Model\RoleModel;
use PHPUnit\Framework\Assert;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class AssetControllerFunctionalTest extends AbstractAssetTestCase
{
use ControllerTrait;
private const SALES_USER = 'sales';
private const ADMIN_USER = 'admin';
/**
* Index action should return status code 200.
*/
public function testIndexAction(): void
{
$asset = new Asset();
$asset->setTitle('test');
$asset->setAlias('test');
$asset->setDateAdded(new \DateTime('2020-02-07 20:29:02'));
$asset->setDateModified(new \DateTime('2020-03-21 20:29:02'));
$asset->setCreatedByUser('Test User');
$this->em->persist($asset);
$this->em->flush();
$this->em->detach($asset);
$urlAlias = 'assets';
$routeAlias = 'asset';
$column = 'dateModified';
$column2 = 'title';
$tableAlias = 'a.';
$this->getControllerColumnTests($urlAlias, $routeAlias, $column, $tableAlias, $column2);
}
public function testAssetSizes(): void
{
$this->client->request('GET', '/s/ajax?action=email:getAttachmentsSize&assets%5B%5D='.$this->asset->getId());
$this->assertResponseIsSuccessful();
Assert::assertSame('{"size":"178 bytes"}', $this->client->getResponse()->getContent());
}
/**
* Preview action should return the file content.
*/
public function testPreviewActionStreamByDefault(): void
{
$this->client->request('GET', '/s/assets/preview/'.$this->asset->getId());
ob_start();
$response = $this->client->getResponse();
$response->sendContent();
$content = ob_get_contents();
ob_end_clean();
$this->assertSame(Response::HTTP_OK, $response->getStatusCode());
$this->assertSame($this->expectedMimeType, $response->headers->get('Content-Type'));
$this->assertNotSame($this->expectedContentDisposition.$this->asset->getOriginalFileName(), $response->headers->get('Content-Disposition'));
$this->assertEquals($this->expectedPngContent, $content);
}
/**
* Preview action should return the file content.
*/
public function testPreviewActionStreamIsZero(): void
{
$this->client->request('GET', '/s/assets/preview/'.$this->asset->getId().'?stream=0&download=1');
ob_start();
$response = $this->client->getResponse();
$response->sendContent();
$content = ob_get_contents();
ob_end_clean();
$this->assertSame(Response::HTTP_OK, $response->getStatusCode());
$this->assertSame($this->expectedContentDisposition.$this->asset->getOriginalFileName(), $response->headers->get('Content-Disposition'));
$this->assertEquals($this->expectedPngContent, $content);
}
/**
* Preview action should return the html code.
*/
public function testPreviewActionStreamDownloadAreZero(): void
{
$this->client->request('GET', '/s/assets/preview/'.$this->asset->getId().'?stream=0&download=0');
ob_start();
$response = $this->client->getResponse();
$response->sendContent();
$content = ob_get_contents();
ob_end_clean();
$this->assertSame(Response::HTTP_OK, $response->getStatusCode(), $content);
$this->assertNotEquals($this->expectedPngContent, $content);
PageControllerTest::assertTrue($response->isOk());
$assetSlug = $this->asset->getId().':'.$this->asset->getAlias();
PageControllerTest::assertStringContainsString(
'/asset/'.$assetSlug,
$content,
'The return must contain the assert slug'
);
}
/**
* @param array<string, string[]> $permission
*/
#[\PHPUnit\Framework\Attributes\DataProvider('getValuesProvider')]
public function testEditWithPermissions(string $route, array $permission, int $expectedStatusCode, string $userCreatorUN): void
{
$userCreator = $this->getUser($userCreatorUN);
$userEditor = $this->getUser(self::SALES_USER);
$this->setPermission($userEditor, ['asset:assets' => $permission]);
$asset = new Asset();
$asset->setTitle('Asset A');
$asset->setAlias('asset-a');
$asset->setStorageLocation('local');
$asset->setPath('broken-image.jpg');
$asset->setExtension('jpg');
$asset->setCreatedByUser($userCreator->getUserIdentifier());
$asset->setCreatedBy($userCreator->getId());
$this->em->persist($asset);
$this->em->flush();
$this->em->clear();
$this->logoutUser();
$this->loginUser($userEditor);
$this->client->request(Request::METHOD_GET, "/s/assets/{$route}/{$asset->getId()}");
Assert::assertSame($expectedStatusCode, $this->client->getResponse()->getStatusCode());
}
/**
* @return \Generator<string, mixed[]>
*/
public static function getValuesProvider(): \Generator
{
yield 'The sales user with edit own permission can edits its own asset' => [
'route' => 'edit',
'permission' => ['editown'],
'expectedStatusCode' => Response::HTTP_OK,
'userCreatorUN' => self::SALES_USER,
];
yield 'The sales user with edit own permission cannot edit asset created by admin' => [
'route' => 'edit',
'permission' => ['editown'],
'expectedStatusCode' => Response::HTTP_FORBIDDEN,
'userCreatorUN' => self::ADMIN_USER,
];
yield 'The sales user with edit other permission can edit asset created by admin' => [
'route' => 'edit',
'permission' => ['editown', 'editother'],
'expectedStatusCode' => Response::HTTP_OK,
'userCreatorUN' => self::ADMIN_USER,
];
yield 'The sales user with view own permission cannot edit or asset created by admin' => [
'route' => 'edit',
'permission' => ['viewown'],
'expectedStatusCode' => Response::HTTP_FORBIDDEN,
'userCreatorUN' => self::ADMIN_USER,
];
yield 'The sales user with view other permission cannot edit asset created by admin' => [
'route' => 'edit',
'permission' => ['viewown', 'viewother'],
'expectedStatusCode' => Response::HTTP_FORBIDDEN,
'userCreatorUN' => self::ADMIN_USER,
];
yield 'The sales user with view own permission cannot view asset created by admin' => [
'route' => 'view',
'permission' => ['viewown'],
'expectedStatusCode' => Response::HTTP_FORBIDDEN,
'userCreatorUN' => self::ADMIN_USER,
];
yield 'The sales user with view others permission can view asset created by admin' => [
'route' => 'view',
'permission' => ['viewown', 'viewother'],
'expectedStatusCode' => Response::HTTP_OK,
'userCreatorUN' => self::ADMIN_USER,
];
yield 'The sales user with view own permission can view its own asset' => [
'route' => 'view',
'permission' => ['viewown'],
'expectedStatusCode' => Response::HTTP_OK,
'userCreatorUN' => self::SALES_USER,
];
}
public function testAssetUploadPathTraversal(): void
{
$client = $this->client;
$container = $this->getContainer();
// Get CSRF token
$csrfToken = $container->get('security.csrf.token_manager')->getToken('mautic_ajax_post')->getValue();
// Create a temporary file
$tempFile = tempnam(sys_get_temp_dir(), 'test_');
file_put_contents($tempFile, '111');
// Prepare the file for upload
$uploadedFile = new UploadedFile(
$tempFile,
'test.txt',
'text/plain',
null,
true
);
$tmpDir = 'tmp_'.substr(md5(uniqid()), 0, 13);
$client->request(
'POST',
'/s/_uploader/asset/upload',
['tempId' => '../../'.$tmpDir],
['file' => $uploadedFile],
[
'HTTP_X-Requested-With' => 'XMLHttpRequest',
'HTTP_X-CSRF-Token' => $csrfToken,
]
);
$response = $client->getResponse();
// Assert response is successful
$this->assertEquals(Response::HTTP_OK, $response->getStatusCode());
// Decode JSON response
$responseData = json_decode($response->getContent(), true);
// Assert the response contains expected keys
$this->assertArrayHasKey('tmpFileName', $responseData);
// Assert file was created in the correct directory
$expectedDir = $container->getParameter('mautic.upload_dir').join('/', ['', 'tmp', $tmpDir]);
$expectedFilePath = join('/', [$expectedDir, $responseData['tmpFileName']]);
$this->assertFileExists($expectedFilePath);
// Clean up
if (file_exists($expectedFilePath)) {
unlink($expectedFilePath);
}
if (is_dir($expectedDir)) {
rmdir($expectedDir);
}
if (file_exists($tempFile)) {
unlink($tempFile);
}
}
private function getUser(string $username): User
{
$repository = $this->em->getRepository(User::class);
return $repository->findOneBy(['username' => $username]);
}
/**
* @param array<string, array<string, array<string>>> $permissions
*/
private function setPermission(User $user, array $permissions): void
{
$role = $user->getRole();
// Delete previous permissions
$this->em->createQueryBuilder()
->delete(Permission::class, 'p')
->where('p.bundle = :bundle')
->andWhere('p.role = :role_id')
->setParameters(['bundle' => 'asset', 'role_id' => $role->getId()])
->getQuery()
->execute();
// Set new permissions
$role->setIsAdmin(false);
$roleModel = static::getContainer()->get('mautic.user.model.role');
\assert($roleModel instanceof RoleModel);
$roleModel->setRolePermissions($role, $permissions);
$this->em->persist($role);
$this->em->flush();
}
public function testPostRequestWithWrongTempNameAndOriginalFileNameFileExtension(): void
{
$response = $this->client->request(
Request::METHOD_GET,
'/s/assets/new',
);
$this->assertResponseStatusCodeSame(Response::HTTP_OK);
$form = $response->filter('form[name="asset"]')->form();
$data = $form->getPhpValues();
$data['asset']['tempName'] = 'image2.php';
$data['asset']['originalFileName'] = 'originalImage2.php';
$data['asset']['storageLocation'] = 'local';
$data['asset']['title'] = 'title';
$data['asset']['description'] = 'description';
$this->client->submit($form, $data);
preg_match_all('/Upload failed as the file extension, php/', $this->client->getResponse()->getContent(), $matches);
$this->assertCount(2, $matches[0]);
$this->assertStringContainsString('Upload failed as the file extension, php', $this->client->getResponse()->getContent());
}
public function testPostRequestWithWrongTempNameFileExtension(): void
{
$response = $this->client->request(
Request::METHOD_GET,
'/s/assets/new',
);
$this->assertResponseStatusCodeSame(Response::HTTP_OK);
$form = $response->filter('form[name="asset"]')->form();
$data = $form->getPhpValues();
$data['asset']['tempName'] = 'image2.php';
$data['asset']['originalFileName'] = 'originalImage2.png';
$data['asset']['storageLocation'] = 'local';
$data['asset']['title'] = 'title';
$data['asset']['description'] = 'description';
$this->client->submit($form, $data);
preg_match_all('/Upload failed as the file extension, php/', $this->client->getResponse()->getContent(), $matches);
$this->assertCount(1, $matches[0]);
$this->assertStringContainsString('Upload failed as the file extension, php', $this->client->getResponse()->getContent());
}
public function testPostResquetSuccessWithCorrectFileExtension(): void
{
$response = $this->client->request(
Request::METHOD_GET,
'/s/assets/new',
);
$this->assertResponseStatusCodeSame(Response::HTTP_OK);
$form = $response->filter('form[name="asset"]')->form();
$data = $form->getPhpValues();
$data['asset']['tempName'] = 'image.png';
$data['asset']['originalFileName'] = 'originalImage.png';
$data['asset']['storageLocation'] = 'local';
$data['asset']['title'] = 'title';
$data['asset']['description'] = 'description';
$this->client->submit($form, $data);
$this->assertResponseStatusCodeSame(Response::HTTP_OK);
$this->assertStringNotContainsString('Upload failed as the file extension, php', $this->client->getResponse()->getContent());
}
public function testAssetWithProject(): void
{
$asset = new Asset();
$asset->setTitle('test');
$asset->setAlias('test');
$this->em->persist($asset);
$project = new Project();
$project->setName('Test Project');
$this->em->persist($project);
$this->em->flush();
$this->em->clear();
$crawler = $this->client->request('GET', '/s/assets/edit/'.$asset->getId());
$form = $crawler->selectButton('Save')->form();
$form['asset[projects]']->setValue((string) $project->getId());
$this->client->submit($form);
$this->assertResponseIsSuccessful();
$savedAsset = $this->em->find(Asset::class, $asset->getId());
Assert::assertSame($project->getId(), $savedAsset->getProjects()->first()->getId());
}
}

View File

@@ -0,0 +1,33 @@
<?php
namespace Mautic\AssetBundle\Tests\Controller;
use Mautic\AssetBundle\Entity\Asset;
use Mautic\CoreBundle\Test\MauticMysqlTestCase;
use PHPUnit\Framework\Assert;
class AssetDetailFunctionalTest extends MauticMysqlTestCase
{
public function testLeadViewPreventsXSS(): void
{
$title = 'aaa" onerror=alert(1) a="';
$asset = new Asset();
$asset->setTitle($title);
$asset->setAlias('dummy-alias');
$asset->setStorageLocation('local');
$asset->setPath('broken-image.jpg');
$asset->setExtension('jpg');
$this->em->persist($asset);
$this->em->flush();
$this->em->detach($asset);
$crawler = $this->client->request('GET', sprintf('/s/assets/view/%d', $asset->getId()));
$imageTag = $crawler->filter('.img-thumbnail');
$onError = $imageTag->attr('onerror');
$altProp = $imageTag->attr('alt');
Assert::assertNull($onError);
Assert::assertSame($title, $altProp);
}
}

View File

@@ -0,0 +1,25 @@
<?php
declare(strict_types=1);
namespace Mautic\AssetBundle\Tests\Controller;
use Mautic\CoreBundle\Test\MauticMysqlTestCase;
use PHPUnit\Framework\Assert;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
final class AssetDownloadFunctionalTest extends MauticMysqlTestCase
{
public function testDownloadOfNotFoundAsset(): void
{
$this->client->request(Request::METHOD_GET, '/s/logout');
// The 500 error happened only on the second request.
// It happened only if the device was already tracked.
$this->client->request(Request::METHOD_GET, '/asset/unicorn'); // returns 404 correctly
$this->client->request(Request::METHOD_GET, '/asset/unicorn'); // returned 500 but it should return 404
Assert::assertSame(Response::HTTP_NOT_FOUND, $this->client->getResponse()->getStatusCode());
}
}

View File

@@ -0,0 +1,98 @@
<?php
declare(strict_types=1);
namespace Mautic\AssetBundle\Tests\Controller;
use Mautic\AssetBundle\Entity\Asset;
use Mautic\ProjectBundle\Tests\Functional\AbstractProjectSearchTestCase;
final class AssetProjectSearchFunctionalTest extends AbstractProjectSearchTestCase
{
#[\PHPUnit\Framework\Attributes\DataProvider('searchDataProvider')]
public function testProjectSearch(string $searchTerm, array $expectedEntities, array $unexpectedEntities): void
{
$projectOne = $this->createProject('Project One');
$projectTwo = $this->createProject('Project Two');
$projectThree = $this->createProject('Project Three');
$assetAlpha = $this->createAsset('Asset Alpha');
$assetBeta = $this->createAsset('Asset Beta');
$this->createAsset('Asset Gamma');
$this->createAsset('Asset Delta');
$assetAlpha->addProject($projectOne);
$assetAlpha->addProject($projectTwo);
$assetBeta->addProject($projectTwo);
$assetBeta->addProject($projectThree);
$this->em->flush();
$this->em->clear();
$this->searchAndAssert($searchTerm, $expectedEntities, $unexpectedEntities, ['/api/assets', '/s/assets']);
}
/**
* @return \Generator<string, array{searchTerm: string, expectedEntities: array<string>, unexpectedEntities: array<string>}>
*/
public static function searchDataProvider(): \Generator
{
yield 'search by one project' => [
'searchTerm' => 'project:"Project Two"',
'expectedEntities' => ['Asset Alpha', 'Asset Beta'],
'unexpectedEntities' => ['Asset Gamma', 'Asset Delta'],
];
yield 'search by one project AND asset name' => [
'searchTerm' => 'project:"Project Two" AND Beta',
'expectedEntities' => ['Asset Beta'],
'unexpectedEntities' => ['Asset Alpha', 'Asset Gamma', 'Asset Delta'],
];
yield 'search by one project OR asset name' => [
'searchTerm' => 'project:"Project Two" OR Gamma',
'expectedEntities' => ['Asset Alpha', 'Asset Beta', 'Asset Gamma'],
'unexpectedEntities' => ['Asset Delta'],
];
yield 'search by NOT one project' => [
'searchTerm' => '!project:"Project Two"',
'expectedEntities' => ['Asset Gamma', 'Asset Delta'],
'unexpectedEntities' => ['Asset Alpha', 'Asset Beta'],
];
yield 'search by two projects with AND' => [
'searchTerm' => 'project:"Project Two" AND project:"Project Three"',
'expectedEntities' => ['Asset Beta'],
'unexpectedEntities' => ['Asset Alpha', 'Asset Gamma', 'Asset Delta'],
];
yield 'search by two projects with NOT AND' => [
'searchTerm' => '!project:"Project Two" AND !project:"Project Three"',
'expectedEntities' => ['Asset Gamma', 'Asset Delta'],
'unexpectedEntities' => ['Asset Alpha', 'Asset Beta'],
];
yield 'search by two projects with OR' => [
'searchTerm' => 'project:"Project Two" OR project:"Project Three"',
'expectedEntities' => ['Asset Alpha', 'Asset Beta'],
'unexpectedEntities' => ['Asset Gamma', 'Asset Delta'],
];
yield 'search by two projects with NOT OR' => [
'searchTerm' => '!project:"Project Two" OR !project:"Project Three"',
'expectedEntities' => ['Asset Alpha', 'Asset Gamma', 'Asset Delta'],
'unexpectedEntities' => ['Asset Beta'],
];
}
private function createAsset(string $name): Asset
{
$asset = new Asset();
$asset->setTitle($name);
$asset->setAlias($name);
$this->em->persist($asset);
return $asset;
}
}

View File

@@ -0,0 +1,79 @@
<?php
namespace Mautic\AssetBundle\Tests\Controller;
use Mautic\AssetBundle\Entity\Download;
use Mautic\AssetBundle\Tests\Asset\AbstractAssetTestCase;
class PublicControllerFunctionalTest extends AbstractAssetTestCase
{
/**
* Download action should return the file content.
*/
public function testDownloadActionStreamByDefault(): void
{
$assetSlug = $this->asset->getId().':'.$this->asset->getAlias();
$this->client->request('GET', '/asset/'.$assetSlug);
ob_start();
$response = $this->client->getResponse();
$response->sendContent();
$content = ob_get_contents();
ob_end_clean();
$this->assertResponseIsSuccessful();
$this->assertSame($this->expectedMimeType, $response->headers->get('Content-Type'));
$this->assertNotSame($this->expectedContentDisposition.$this->asset->getOriginalFileName(), $response->headers->get('Content-Disposition'));
$this->assertEquals($this->expectedPngContent, $content);
}
/**
* Download action should return the file content.
*/
public function testDownloadActionStreamIsZero(): void
{
$assetSlug = $this->asset->getId().':'.$this->asset->getAlias();
$this->client->request('GET', '/asset/'.$assetSlug.'?stream=0');
ob_start();
$response = $this->client->getResponse();
$response->sendContent();
$content = ob_get_contents();
ob_end_clean();
$this->assertResponseIsSuccessful();
$this->assertSame($this->expectedContentDisposition.$this->asset->getOriginalFileName(), $response->headers->get('Content-Disposition'));
$this->assertEquals($this->expectedPngContent, $content);
}
/**
* Download action with UTM should return the file content.
*/
public function testDownloadActionWithUTM(): void
{
$this->logoutUser();
$assetSlug = $this->asset->getId().':'.$this->asset->getAlias().'?utm_source=test2&utm_medium=test3&utm_campaign=test6&utm_term=test4&utm_content=test5';
$this->client->request('GET', '/asset/'.$assetSlug);
ob_start();
$response = $this->client->getResponse();
$response->sendContent();
$content = ob_get_contents();
ob_end_clean();
$this->assertResponseIsSuccessful();
$this->assertSame($this->expectedMimeType, $response->headers->get('Content-Type'));
$this->assertNotSame($this->expectedContentDisposition.$this->asset->getOriginalFileName(), $response->headers->get('Content-Disposition'));
$this->assertEquals($this->expectedPngContent, $content);
$downloadRepo = $this->em->getRepository(Download::class);
$download = $downloadRepo->findOneBy(['asset' => $this->asset]);
\assert($download instanceof Download);
$this->assertSame('test2', $download->getUtmSource());
$this->assertSame('test3', $download->getUtmMedium());
$this->assertSame('test4', $download->getUtmTerm());
$this->assertSame('test5', $download->getUtmContent());
$this->assertSame('test6', $download->getUtmCampaign());
}
}

View File

@@ -0,0 +1,114 @@
<?php
namespace Mautic\AssetBundle\Tests\Controller;
use Mautic\AssetBundle\Tests\Asset\AbstractAssetTestCase;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class UploadControllerFunctionalTest extends AbstractAssetTestCase
{
public function testUploadWithWrongMimetype(): void
{
// Create a php file with the content of phpinfo
$assetsPath = $this->client->getKernel()->getContainer()->getParameter('mautic.upload_dir');
$fileName = 'image2.png';
$filePath = $assetsPath.'/'.$fileName;
if (file_exists($filePath)) {
unlink($filePath);
}
copy('index.php', $filePath);
$binaryFile = new UploadedFile($filePath, $fileName, 'application/x-httpd-php', null, true);
$tmpId = 'tempId_'.time();
// Upload the file
$this->client->request(
Request::METHOD_POST,
'/s/_uploader/asset/upload',
[
'tempId' => $tmpId,
],
[
'file' => $binaryFile,
]
);
$response = $this->client->getResponse();
$this->assertStringContainsString('Upload failed as the file mimetype', $response->getContent());
$this->assertStringContainsString('text\/x-php is not allowed', $response->getContent());
unlink($filePath);
}
public function testSuccessUploadWithPng(): void
{
// Create a temporary PNG file
// Create a php file with the content of phpinfo
$assetsPath = $this->client->getKernel()->getContainer()->getParameter('mautic.upload_dir');
$assetsPathFrom = $this->client->getKernel()->getContainer()->getParameter('mautic.application_dir').'/app/assets/images/mautic_logo_db64.png';
$fileName = 'image3.png';
$filePath = $assetsPath.'/'.$fileName;
copy($assetsPathFrom, $filePath);
// Create an UploadedFile instance with the correct MIME type
$uploadedFile = new UploadedFile($filePath, $fileName, 'image/png', null, true);
$tmpId = 'tempId_'.time();
// Perform the request with the file
$this->client->request(
'POST',
'/s/_uploader/asset/upload',
['tempId' => $tmpId],
['file' => $uploadedFile]
);
$this->assertResponseStatusCodeSame(Response::HTTP_OK);
$this->assertStringContainsString('state":1', $this->client->getResponse()->getContent());
if (file_exists($filePath)) {
unlink($filePath);
}
$data = json_decode($this->client->getResponse()->getContent(), true);
unlink($assetsPath.'/tmp/'.$tmpId.'/'.$data['tmpFileName']);
rmdir($assetsPath.'/tmp/'.$tmpId);
}
public function testUploadWithWrongExtension(): void
{
// Create a php file with the content of phpinfo
$assetsPath = $this->client->getKernel()->getContainer()->getParameter('mautic.upload_dir');
$assetsPathFrom = $this->client->getKernel()->getContainer()->getParameter('mautic.application_dir').'/app/assets/images/mautic_logo_db64.png';
$fileName = 'image2.php';
$filePath = $assetsPath.'/'.$fileName;
if (file_exists($filePath)) {
unlink($filePath);
}
copy($assetsPathFrom, $filePath);
$binaryFile = new UploadedFile($filePath, $fileName, 'image/png', null, true);
$tmpId = 'tempId_'.time();
// Upload the file
$this->client->request(
Request::METHOD_POST,
'/s/_uploader/asset/upload',
[
'tempId' => $tmpId,
],
[
'file' => $binaryFile,
]
);
$response = $this->client->getResponse();
$this->assertStringContainsString('Upload failed as the file extension', $response->getContent());
$this->assertStringContainsString('Upload failed as the file extension, php,', $response->getContent());
unlink($filePath);
}
}