From 7a472d7295988ced67146ebb102c4150f98900c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20D?= Date: Fri, 30 Aug 2024 08:39:51 +0200 Subject: [PATCH] test(IT): Test Config Backup use cases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rubén D --- .../DownloadBackupDbController.php | 98 +++++++--------- .../ConfigBackup/DownloadExportController.php | 97 +++++++--------- .../ConfigBackup/FileBackupController.php | 58 +++------- .../ConfigBackup/XmlExportController.php | 101 ++++++++-------- lib/SP/Core/Definitions/DomainDefinitions.php | 8 +- .../Export/Services/XmlAccountExport.php | 3 +- .../Export/Services/XmlCategoryExport.php | 4 +- .../Export/Services/XmlClientExport.php | 4 +- lib/SP/Domain/Export/Services/XmlExport.php | 23 ++-- .../Domain/Export/Services/XmlTagExport.php | 6 +- lib/SP/Domain/Export/Services/XmlVerify.php | 4 +- lib/SP/Domain/Http/Ports/RequestService.php | 2 +- lib/SP/Domain/Http/Services/Request.php | 8 +- lib/SP/Infrastructure/File/ArchiveHandler.php | 10 +- tests/SP/IntegrationTestCase.php | 13 ++- .../ConfigBackupControllerTest.php | 108 +++++++++++++++++- 16 files changed, 308 insertions(+), 239 deletions(-) diff --git a/app/modules/web/Controllers/ConfigBackup/DownloadBackupDbController.php b/app/modules/web/Controllers/ConfigBackup/DownloadBackupDbController.php index 26abd0e9..fec36426 100644 --- a/app/modules/web/Controllers/ConfigBackup/DownloadBackupDbController.php +++ b/app/modules/web/Controllers/ConfigBackup/DownloadBackupDbController.php @@ -24,26 +24,29 @@ namespace SP\Modules\Web\Controllers\ConfigBackup; -use Exception; +use Klein\Response; use SP\Core\Application; use SP\Core\Bootstrap\Path; use SP\Core\Bootstrap\PathsContext; use SP\Core\Context\Session; use SP\Core\Events\Event; use SP\Core\Events\EventMessage; +use SP\Domain\Common\Attributes\Action; +use SP\Domain\Common\Dtos\ActionResponse; +use SP\Domain\Common\Enums\ResponseStatus; +use SP\Domain\Common\Enums\ResponseType; use SP\Domain\Core\Acl\AclActionsInterface; -use SP\Domain\Core\Acl\UnauthorizedPageException; use SP\Domain\Core\Exceptions\SessionTimeout; use SP\Domain\Core\Exceptions\SPException; use SP\Domain\Export\Dtos\BackupFile; use SP\Domain\Export\Dtos\BackupType; +use SP\Infrastructure\File\FileException; use SP\Infrastructure\File\FileHandler; use SP\Modules\Web\Controllers\SimpleControllerBase; -use SP\Modules\Web\Controllers\Traits\JsonTrait; use SP\Mvc\Controller\SimpleControllerHelper; +use function SP\__; use function SP\__u; -use function SP\processException; /** * Class ConfigBackupController @@ -52,8 +55,6 @@ use function SP\processException; */ final class DownloadBackupDbController extends SimpleControllerBase { - use JsonTrait; - public function __construct( Application $application, SimpleControllerHelper $simpleControllerHelper, @@ -63,56 +64,51 @@ final class DownloadBackupDbController extends SimpleControllerBase } /** - * @return string + * @return ActionResponse + * @throws FileException */ - public function downloadBackupDbAction(): string + #[Action(ResponseType::CALLBACK)] + public function downloadBackupDbAction(): ActionResponse { if ($this->configData->isDemoEnabled()) { - return __('Ey, this is a DEMO!!'); + return ActionResponse::warning(__('Ey, this is a DEMO!!')); } - try { - Session::close(); + Session::close(); - $filePath = new BackupFile( - BackupType::db, - $this->configData->getBackupHash(), - $this->pathsContext[Path::BACKUP], - 'gz' - ); + $filePath = new BackupFile( + BackupType::db, + $this->configData->getBackupHash(), + $this->pathsContext[Path::BACKUP], + 'gz' + ); - $file = new FileHandler((string)$filePath); - $file->checkFileExists(); + $file = new FileHandler((string)$filePath); - $this->eventDispatcher->notify( - 'download.backupDbFile', - new Event( - $this, - EventMessage::build() - ->addDescription(__u('File downloaded')) - ->addDetail(__u('File'), str_replace(APP_ROOT, '', $file->getFile())) - ) - ); + $this->eventDispatcher->notify( + 'download.backupDbFile', + new Event( + $this, + EventMessage::build(__u('File downloaded')) + ->addDetail(__u('File'), str_replace(APP_ROOT, '', $file->getFile())) + ) + ); - $this->router - ->response() - ->header('Cache-Control', 'max-age=60, must-revalidate') - ->header('Content-length', $file->getFileSize()) - ->header('Content-type', $file->getFileType()) - ->header('Content-Description', ' sysPass file') - ->header('Content-transfer-encoding', 'chunked') - ->header('Content-Disposition', 'attachment; filename="' . basename($file->getFile()) . '"') - ->header('Set-Cookie', 'fileDownload=true; path=/') - ->send(); + return new ActionResponse( + ResponseStatus::OK, + function (Response $response) use ($file) { + $response->header('Cache-Control', 'max-age=60, must-revalidate') + ->header('Content-length', $file->getFileSize()) + ->header('Content-type', $file->getFileType()) + ->header('Content-Description', ' sysPass file') + ->header('Content-transfer-encoding', 'chunked') + ->header('Content-Disposition', 'attachment; filename="' . basename($file->getFile()) . '"') + ->header('Set-Cookie', 'fileDownload=true; path=/') + ->send(); - $file->readChunked(); - } catch (Exception $e) { - processException($e); - - $this->eventDispatcher->notify('exception', new Event($e)); - } - - return ''; + $file->readChunked(); + } + ); } /** @@ -123,13 +119,7 @@ final class DownloadBackupDbController extends SimpleControllerBase */ protected function initialize(): void { - try { - $this->checks(); - $this->checkAccess(AclActionsInterface::CONFIG_BACKUP); - } catch (UnauthorizedPageException $e) { - $this->eventDispatcher->notify('exception', new Event($e)); - - $this->returnJsonResponseException($e); - } + $this->checks(); + $this->checkAccess(AclActionsInterface::CONFIG_BACKUP); } } diff --git a/app/modules/web/Controllers/ConfigBackup/DownloadExportController.php b/app/modules/web/Controllers/ConfigBackup/DownloadExportController.php index c67e410c..3c7a0817 100644 --- a/app/modules/web/Controllers/ConfigBackup/DownloadExportController.php +++ b/app/modules/web/Controllers/ConfigBackup/DownloadExportController.php @@ -25,34 +25,33 @@ namespace SP\Modules\Web\Controllers\ConfigBackup; -use Exception; +use Klein\Response; use SP\Core\Application; use SP\Core\Bootstrap\Path; use SP\Core\Bootstrap\PathsContext; use SP\Core\Context\Session; use SP\Core\Events\Event; use SP\Core\Events\EventMessage; +use SP\Domain\Common\Attributes\Action; +use SP\Domain\Common\Dtos\ActionResponse; +use SP\Domain\Common\Enums\ResponseStatus; +use SP\Domain\Common\Enums\ResponseType; use SP\Domain\Core\Acl\AclActionsInterface; -use SP\Domain\Core\Acl\UnauthorizedPageException; use SP\Domain\Core\Exceptions\SessionTimeout; use SP\Domain\Core\Exceptions\SPException; use SP\Domain\Export\Dtos\BackupFile as BackupFileDto; use SP\Domain\Export\Dtos\BackupType; use SP\Infrastructure\File\FileHandler; use SP\Modules\Web\Controllers\SimpleControllerBase; -use SP\Modules\Web\Controllers\Traits\JsonTrait; use SP\Mvc\Controller\SimpleControllerHelper; use function SP\__u; -use function SP\processException; /** * Class DownloadExportController */ final class DownloadExportController extends SimpleControllerBase { - use JsonTrait; - public function __construct( Application $application, SimpleControllerHelper $simpleControllerHelper, @@ -61,56 +60,44 @@ final class DownloadExportController extends SimpleControllerBase parent::__construct($application, $simpleControllerHelper); } - /** - * @return string - */ - public function downloadExportAction(): string + #[Action(ResponseType::CALLBACK)] + public function downloadExportAction(): ActionResponse { - try { - Session::close(); + Session::close(); - $filePath = (string)new BackupFileDto( - BackupType::export, - $this->configData->getExportHash() ?: '', - $this->pathsContext[Path::BACKUP], - 'gz' - ); + $filePath = (string)new BackupFileDto( + BackupType::export, + $this->configData->getExportHash() ?: '', + $this->pathsContext[Path::BACKUP], + 'gz' + ); - $file = new FileHandler($filePath); - $file->checkFileExists(); + $file = new FileHandler($filePath); - $this->eventDispatcher->notify( - 'download.exportFile', - new Event( - $this, - EventMessage::build() - ->addDescription(__u('File downloaded')) - ->addDetail(__u('File'), str_replace(APP_ROOT, '', $file->getFile())) - ) - ); + $this->eventDispatcher->notify( + 'download.exportFile', + new Event( + $this, + EventMessage::build(__u('File downloaded')) + ->addDetail(__u('File'), str_replace(APP_ROOT, '', $file->getFile())) + ) + ); - $this->router - ->response() - ->header('Cache-Control', 'max-age=60, must-revalidate') - ->header('Content-length', $file->getFileSize()) - ->header('Content-type', $file->getFileType()) - ->header('Content-Description', ' sysPass file') - ->header('Content-transfer-encoding', 'chunked') - ->header('Content-Disposition', 'attachment; filename="' . basename($file->getFile()) . '"') - ->header('Set-Cookie', 'fileDownload=true; path=/') - ->send(); + return new ActionResponse( + ResponseStatus::OK, + function (Response $response) use ($file) { + $response->header('Cache-Control', 'max-age=60, must-revalidate') + ->header('Content-length', $file->getFileSize()) + ->header('Content-type', $file->getFileType()) + ->header('Content-Description', ' sysPass file') + ->header('Content-transfer-encoding', 'chunked') + ->header('Content-Disposition', 'attachment; filename="' . basename($file->getFile()) . '"') + ->header('Set-Cookie', 'fileDownload=true; path=/') + ->send(); - $file->readChunked(); - } catch (Exception $e) { - processException($e); - - $this->eventDispatcher->notify( - 'exception', - new Event($e) - ); - } - - return ''; + $file->readChunked(); + } + ); } /** @@ -121,13 +108,7 @@ final class DownloadExportController extends SimpleControllerBase */ protected function initialize(): void { - try { - $this->checks(); - $this->checkAccess(AclActionsInterface::CONFIG_BACKUP); - } catch (UnauthorizedPageException $e) { - $this->eventDispatcher->notify('exception', new Event($e)); - - $this->returnJsonResponseException($e); - } + $this->checks(); + $this->checkAccess(AclActionsInterface::CONFIG_BACKUP); } } diff --git a/app/modules/web/Controllers/ConfigBackup/FileBackupController.php b/app/modules/web/Controllers/ConfigBackup/FileBackupController.php index 157b0eab..7c9726f2 100644 --- a/app/modules/web/Controllers/ConfigBackup/FileBackupController.php +++ b/app/modules/web/Controllers/ConfigBackup/FileBackupController.php @@ -24,34 +24,29 @@ namespace SP\Modules\Web\Controllers\ConfigBackup; - -use Exception; use SP\Core\Application; use SP\Core\Bootstrap\Path; use SP\Core\Bootstrap\PathsContext; use SP\Core\Context\Session; use SP\Core\Events\Event; use SP\Core\Events\EventMessage; +use SP\Domain\Common\Attributes\Action; +use SP\Domain\Common\Dtos\ActionResponse; +use SP\Domain\Common\Enums\ResponseType; use SP\Domain\Core\Acl\AclActionsInterface; -use SP\Domain\Core\Acl\UnauthorizedPageException; use SP\Domain\Core\Exceptions\SessionTimeout; use SP\Domain\Core\Exceptions\SPException; use SP\Domain\Export\Ports\BackupFileService; -use SP\Domain\Http\Dtos\JsonMessage; use SP\Modules\Web\Controllers\SimpleControllerBase; -use SP\Modules\Web\Controllers\Traits\ConfigTrait; use SP\Mvc\Controller\SimpleControllerHelper; use function SP\__u; -use function SP\processException; /** * Class FileBackupController */ final class FileBackupController extends SimpleControllerBase { - use ConfigTrait; - public function __construct( Application $application, SimpleControllerHelper $simpleControllerHelper, @@ -62,38 +57,29 @@ final class FileBackupController extends SimpleControllerBase } /** - * @return bool + * @return ActionResponse * @throws SPException */ - public function fileBackupAction(): bool + #[Action(ResponseType::JSON)] + public function fileBackupAction(): ActionResponse { if ($this->config->getConfigData()->isDemoEnabled()) { - return $this->returnJsonResponse(JsonMessage::JSON_WARNING, __u('Ey, this is a DEMO!!')); + return ActionResponse::warning(__u('Ey, this is a DEMO!!')); } - try { - Session::close(); + Session::close(); - $this->fileBackupService->doBackup($this->pathsContext[Path::BACKUP], $this->pathsContext[Path::APP]); + $this->fileBackupService->doBackup($this->pathsContext[Path::BACKUP], $this->pathsContext[Path::APP]); - $this->eventDispatcher->notify( - 'run.backup.end', - new Event( - $this, - EventMessage::build()->addDescription( - __u('Application and database backup completed successfully') - ) - ) - ); + $this->eventDispatcher->notify( + 'run.backup.end', + new Event( + $this, + EventMessage::build(__u('Application and database backup completed successfully')) + ) + ); - return $this->returnJsonResponse(JsonMessage::JSON_SUCCESS, __u('Backup process finished')); - } catch (Exception $e) { - processException($e); - - $this->eventDispatcher->notify('exception', new Event($e)); - - return $this->returnJsonResponseException($e); - } + return ActionResponse::ok(__u('Backup process finished')); } /** @@ -104,13 +90,7 @@ final class FileBackupController extends SimpleControllerBase */ protected function initialize(): void { - try { - $this->checks(); - $this->checkAccess(AclActionsInterface::CONFIG_BACKUP); - } catch (UnauthorizedPageException $e) { - $this->eventDispatcher->notify('exception', new Event($e)); - - $this->returnJsonResponseException($e); - } + $this->checks(); + $this->checkAccess(AclActionsInterface::CONFIG_BACKUP); } } diff --git a/app/modules/web/Controllers/ConfigBackup/XmlExportController.php b/app/modules/web/Controllers/ConfigBackup/XmlExportController.php index 5534f881..8af3466f 100644 --- a/app/modules/web/Controllers/ConfigBackup/XmlExportController.php +++ b/app/modules/web/Controllers/ConfigBackup/XmlExportController.php @@ -24,36 +24,36 @@ namespace SP\Modules\Web\Controllers\ConfigBackup; -use Exception; use SP\Core\Application; use SP\Core\Bootstrap\Path; use SP\Core\Bootstrap\PathsContext; use SP\Core\Context\Session; use SP\Core\Events\Event; use SP\Core\Events\EventMessage; +use SP\Domain\Common\Attributes\Action; +use SP\Domain\Common\Dtos\ActionResponse; +use SP\Domain\Common\Enums\ResponseType; +use SP\Domain\Common\Services\ServiceException; use SP\Domain\Core\Acl\AclActionsInterface; use SP\Domain\Core\Acl\UnauthorizedPageException; use SP\Domain\Core\Exceptions\SessionTimeout; use SP\Domain\Core\Exceptions\SPException; use SP\Domain\Export\Ports\XmlExportService; use SP\Domain\Export\Ports\XmlVerifyService; -use SP\Domain\Http\Dtos\JsonMessage; +use SP\Domain\Import\Services\ImportException; use SP\Infrastructure\File\ArchiveHandler; use SP\Infrastructure\File\DirectoryHandler; +use SP\Infrastructure\File\FileException; use SP\Modules\Web\Controllers\SimpleControllerBase; -use SP\Modules\Web\Controllers\Traits\JsonTrait; use SP\Mvc\Controller\SimpleControllerHelper; use function SP\__u; -use function SP\processException; /** * Class XmlExportController */ final class XmlExportController extends SimpleControllerBase { - use JsonTrait; - /** * @throws SessionTimeout * @throws SPException @@ -73,71 +73,60 @@ final class XmlExportController extends SimpleControllerBase } /** - * @return bool - * @throws SPException + * @return ActionResponse + * @throws ServiceException + * @throws ImportException + * @throws FileException */ - public function xmlExportAction(): bool + #[Action(ResponseType::JSON)] + public function xmlExportAction(): ActionResponse { $exportPassword = $this->request->analyzeEncrypted('exportPwd'); $exportPasswordR = $this->request->analyzeEncrypted('exportPwdR'); if (!empty($exportPassword) && $exportPassword !== $exportPasswordR) { - return $this->returnJsonResponse(JsonMessage::JSON_ERROR, __u('Passwords do not match')); + return ActionResponse::error(__u('Passwords do not match')); } - try { - $this->eventDispatcher->notify( - 'run.export.start', - new Event($this, EventMessage::build()->addDescription(__u('sysPass XML export'))) - ); + $this->eventDispatcher->notify( + 'run.export.start', + new Event($this, EventMessage::build(__u('sysPass XML export'))) + ); - Session::close(); + Session::close(); - $file = $this->xmlExportService->export( - new DirectoryHandler($this->pathsContext[Path::BACKUP]), - $exportPassword - ); + $file = $this->xmlExportService->export( + new DirectoryHandler($this->pathsContext[Path::BACKUP]), + $exportPassword + ); - $this->eventDispatcher->notify( - 'run.export.end', - new Event($this, EventMessage::build()->addDescription(__u('Export process finished'))) - ); + $this->eventDispatcher->notify( + 'run.export.end', + new Event($this, EventMessage::build(__u('Export process finished'))) + ); - if (!empty($exportPassword)) { - $verifyResult = - $this->xmlVerifyService->verify($file, $exportPassword); - } else { - $verifyResult = $this->xmlVerifyService->verify($file); - } + $verifyResult = $this->xmlVerifyService->verify($file, $exportPassword); - $nodes = $verifyResult->getNodes(); + $nodes = $verifyResult->getNodes(); - $this->eventDispatcher->notify( - 'run.export.verify', - new Event( - $this, - EventMessage::build() - ->addDescription(__u('Verification of exported data finished')) - ->addDetail(__u('Version'), $verifyResult->getVersion()) - ->addDetail(__u('Encrypted'), $verifyResult->isEncrypted() ? __u('Yes') : __u('No')) - ->addDetail(__u('Accounts'), $nodes['Account']) - ->addDetail(__u('Clients'), $nodes['Client']) - ->addDetail(__u('Categories'), $nodes['Category']) - ->addDetail(__u('Tags'), $nodes['Tag']) - ) - ); + $this->eventDispatcher->notify( + 'run.export.verify', + new Event( + $this, + EventMessage::build(__u('Verification of exported data finished')) + ->addDetail(__u('Version'), $verifyResult->getVersion()) + ->addDetail(__u('Encrypted'), $verifyResult->isEncrypted() ? __u('Yes') : __u('No')) + ->addDetail(__u('Accounts'), $nodes['Account']) + ->addDetail(__u('Clients'), $nodes['Client']) + ->addDetail(__u('Categories'), $nodes['Category']) + ->addDetail(__u('Tags'), $nodes['Tag']) + ) + ); - // Create the XML archive after verifying the export integrity - $archive = new ArchiveHandler($file, $this->extensionChecker); - $archive->compressFile($file); + // Create the XML archive after verifying the export integrity + $archive = new ArchiveHandler($file, $this->extensionChecker); + $archive->compressFile($file); - return $this->returnJsonResponse(JsonMessage::JSON_SUCCESS, __u('Export process finished')); - } catch (Exception $e) { - processException($e); - - $this->eventDispatcher->notify('exception', new Event($e)); - - return $this->returnJsonResponseException($e); - } + return ActionResponse::ok(__u('Export process finished')); } } diff --git a/lib/SP/Core/Definitions/DomainDefinitions.php b/lib/SP/Core/Definitions/DomainDefinitions.php index 5cbed166..4a49fa9f 100644 --- a/lib/SP/Core/Definitions/DomainDefinitions.php +++ b/lib/SP/Core/Definitions/DomainDefinitions.php @@ -30,6 +30,8 @@ use SP\Core\Bootstrap\Path; use SP\Core\Bootstrap\PathsContext; use SP\Domain\Common\Ports\Repository; use SP\Domain\Common\Providers\Image; +use SP\Domain\Export\Ports\XmlVerifyService; +use SP\Domain\Export\Services\XmlVerify; use SP\Domain\Image\Ports\ImageService; use SP\Infrastructure\Common\Repositories\SimpleRepository; use SP\Infrastructure\File\FileSystem; @@ -88,7 +90,11 @@ final class DomainDefinitions 'tempPath', factory(static fn(PathsContext $p) => $p[Path::TMP]) ), - Repository::class => autowire(SimpleRepository::class) + Repository::class => autowire(SimpleRepository::class), + XmlVerifyService::class => autowire(XmlVerify::class)->constructorParameter( + 'schema', + factory(static fn(PathsContext $p) => $p[Path::XML_SCHEMA]) + ) ]; foreach (self::DOMAINS as $domain) { diff --git a/lib/SP/Domain/Export/Services/XmlAccountExport.php b/lib/SP/Domain/Export/Services/XmlAccountExport.php index 6342e35b..65bb1b1b 100644 --- a/lib/SP/Domain/Export/Services/XmlAccountExport.php +++ b/lib/SP/Domain/Export/Services/XmlAccountExport.php @@ -34,13 +34,14 @@ use SP\Core\Events\EventMessage; use SP\Domain\Account\Ports\AccountService; use SP\Domain\Account\Ports\AccountToTagService; use SP\Domain\Common\Services\ServiceException; +use SP\Domain\Export\Ports\XmlAccountExportService; use function SP\__u; /** * Class XmlAccountExport */ -final class XmlAccountExport extends XmlExportEntityBase +final class XmlAccountExport extends XmlExportEntityBase implements XmlAccountExportService { public function __construct( diff --git a/lib/SP/Domain/Export/Services/XmlCategoryExport.php b/lib/SP/Domain/Export/Services/XmlCategoryExport.php index c207cfb6..ba2b09f2 100644 --- a/lib/SP/Domain/Export/Services/XmlCategoryExport.php +++ b/lib/SP/Domain/Export/Services/XmlCategoryExport.php @@ -1,4 +1,5 @@ context->getUserData(); + $nodeUser = $this->document->createElement( + 'User', + $this->document->createTextNode($userDto->login)->nodeValue + ); + $nodeUser->setAttribute('id', (string)$userDto->id); + + $nodeUserGroup = $this->document->createElement( + 'Group', + $this->document->createTextNode($userDto->userGroupName)->nodeValue + ); + $nodeUserGroup->setAttribute('id', (string)$userDto->userGroupId); + + $nodeMeta = $this->document->createElement('Meta'); $nodeMeta->append( $this->document->createElement('Generator', 'sysPass'), $this->document->createElement('Version', Version::getVersionStringNormalized()), $this->document->createElement('Time', (string)time()), - $this->document->createElement( - 'User', - $this->document->createTextNode($userDto->login)->nodeValue - ), - $this->document->createElement( - 'Group', - $this->document->createTextNode($userDto->userGroupName)->nodeValue - ) + $nodeUser, + $nodeUserGroup ); $this->document->documentElement->appendChild($nodeMeta); diff --git a/lib/SP/Domain/Export/Services/XmlTagExport.php b/lib/SP/Domain/Export/Services/XmlTagExport.php index 6b2694ab..8f60489a 100644 --- a/lib/SP/Domain/Export/Services/XmlTagExport.php +++ b/lib/SP/Domain/Export/Services/XmlTagExport.php @@ -1,4 +1,5 @@ document, $password ?? $self->config->getConfigData()->getPasswordSalt())) { + $key = $password ?: sha1($self->config->getConfigData()->getPasswordSalt()); + + if (!self::checkXmlHash($self->document, $key)) { throw ServiceException::error(__u('Error while checking integrity hash')); } diff --git a/lib/SP/Domain/Http/Ports/RequestService.php b/lib/SP/Domain/Http/Ports/RequestService.php index f18cc3aa..e7da6ef5 100644 --- a/lib/SP/Domain/Http/Ports/RequestService.php +++ b/lib/SP/Domain/Http/Ports/RequestService.php @@ -51,7 +51,7 @@ interface RequestService /** * Analizar un valor encriptado y devolverlo desencriptado */ - public function analyzeEncrypted(string $param): string; + public function analyzeEncrypted(string $param): ?string; public function analyzeString(string $param, ?string $default = null): ?string; diff --git a/lib/SP/Domain/Http/Services/Request.php b/lib/SP/Domain/Http/Services/Request.php index 37665b25..3d9acccb 100644 --- a/lib/SP/Domain/Http/Services/Request.php +++ b/lib/SP/Domain/Http/Services/Request.php @@ -189,19 +189,17 @@ class Request implements RequestService /** * Analizar un valor encriptado y devolverlo desencriptado */ - public function analyzeEncrypted(string $param): string + public function analyzeEncrypted(string $param): ?string { $encryptedData = $this->analyzeString($param); if ($encryptedData === null) { - return ''; + return null; } try { - // Desencriptar con la clave RSA $clearData = $this->cryptPKI->decryptRSA(base64_decode($encryptedData)); - // Desencriptar con la clave RSA if ($clearData === null) { logger('No RSA encrypted data from request'); @@ -244,7 +242,7 @@ class Request implements RequestService public function analyzeArray( string $param, ?callable $mapper = null, - mixed $default = null + mixed $default = null ): ?array { $requestValue = $this->params->get($param); diff --git a/lib/SP/Infrastructure/File/ArchiveHandler.php b/lib/SP/Infrastructure/File/ArchiveHandler.php index 32b73202..2f3e3f9b 100644 --- a/lib/SP/Infrastructure/File/ArchiveHandler.php +++ b/lib/SP/Infrastructure/File/ArchiveHandler.php @@ -47,7 +47,8 @@ class ArchiveHandler implements ArchiveHandlerInterface private static function makeArchiveName(string $archive): string { - return preg_replace('/\.gz$/', '', $archive); + // return preg_replace('/\.gz$/', '', $archive); + return sprintf('%s.tar', $archive); } /** @@ -76,9 +77,10 @@ class ArchiveHandler implements ArchiveHandlerInterface $this->archive->addFile($file, basename($file)); $packed = $this->archive->compress(Phar::GZ); - // Delete the non-compressed archive - (new FileHandler($this->archive->getPathname()))->delete(); + // Delete the non-compressed files + (new FileHandler($file))->delete(); + (new FileHandler($this->archive->getPath()))->delete(); - return $packed->getFileInfo()->getPathname(); + return $packed->getFileInfo()->getPath(); } } diff --git a/tests/SP/IntegrationTestCase.php b/tests/SP/IntegrationTestCase.php index 4b8505e5..5681f3fe 100644 --- a/tests/SP/IntegrationTestCase.php +++ b/tests/SP/IntegrationTestCase.php @@ -66,7 +66,6 @@ use SP\Domain\Database\Ports\DbStorageHandler; use SP\Domain\Notification\Ports\MailService; use SP\Domain\User\Dtos\UserDto; use SP\Domain\User\Models\ProfileData; -use SP\Domain\User\Models\User; use SP\Domain\User\Models\UserPreferences; use SP\Infrastructure\Database\QueryData; use SP\Infrastructure\Database\QueryResult; @@ -252,10 +251,16 @@ abstract class IntegrationTestCase extends TestCase */ protected function getUserDataDto(): UserDto { - $user = UserDataGenerator::factory()->buildUserData()->mutate(['isAdminApp' => false, 'isAdminAcc' => false]); + $user = UserDataGenerator::factory()->buildUserData(); - return UserDto::fromModel($user, User::class) - ->mutate(['preferences', $user->hydrate(UserPreferences::class)]); + $properties = [ + 'isAdminApp' => false, + 'isAdminAcc' => false, + 'userGroupName' => self::$faker->colorName(), + 'preferences' => $user->hydrate(UserPreferences::class) + ]; + + return UserDto::fromModel($user)->mutate($properties); } /** diff --git a/tests/SP/Modules/Web/Controllers/ConfigBackup/ConfigBackupControllerTest.php b/tests/SP/Modules/Web/Controllers/ConfigBackup/ConfigBackupControllerTest.php index beb7ce95..f73ace9c 100644 --- a/tests/SP/Modules/Web/Controllers/ConfigBackup/ConfigBackupControllerTest.php +++ b/tests/SP/Modules/Web/Controllers/ConfigBackup/ConfigBackupControllerTest.php @@ -63,16 +63,118 @@ class ConfigBackupControllerTest extends IntegrationTestCase $this->passwordSalt . '.gz'; - file_put_contents($filename, 'test_data'); + file_put_contents($filename, 'test_data_app'); $container = $this->buildContainer( $this->definitions, $this->buildRequest('get', 'index.php', ['r' => 'configBackup/downloadBackupApp']) ); + $this->expectOutputString('test_data_app'); + $this->runApp($container); - $this->expectOutputString('test_data'); + unlink($filename); + } + + /** + * @throws ContainerExceptionInterface + * @throws Exception + * @throws NotFoundExceptionInterface + */ + #[Test] + public function downloadBackupDb() + { + $filename = REAL_APP_ROOT . + DIRECTORY_SEPARATOR . + 'app' . + DIRECTORY_SEPARATOR . + 'backup' . + DIRECTORY_SEPARATOR . + 'sysPass_db-' . + $this->passwordSalt . + '.gz'; + + file_put_contents($filename, 'test_data_db'); + + $container = $this->buildContainer( + $this->definitions, + $this->buildRequest('get', 'index.php', ['r' => 'configBackup/downloadBackupDb']) + ); + + $this->expectOutputString('test_data_db'); + + $this->runApp($container); + + unlink($filename); + } + + /** + * @throws ContainerExceptionInterface + * @throws Exception + * @throws NotFoundExceptionInterface + */ + #[Test] + public function downloadBackupExport() + { + $filename = REAL_APP_ROOT . + DIRECTORY_SEPARATOR . + 'app' . + DIRECTORY_SEPARATOR . + 'backup' . + DIRECTORY_SEPARATOR . + 'sysPass_export-' . + $this->passwordSalt . + '.gz'; + + file_put_contents($filename, 'test_data_export'); + + $container = $this->buildContainer( + $this->definitions, + $this->buildRequest('get', 'index.php', ['r' => 'configBackup/downloadExport']) + ); + + $this->expectOutputString('test_data_export'); + + $this->runApp($container); + + unlink($filename); + } + + /** + * @throws ContainerExceptionInterface + * @throws Exception + * @throws NotFoundExceptionInterface + */ + #[Test] + public function fileBackup() + { + $container = $this->buildContainer( + $this->definitions, + $this->buildRequest('get', 'index.php', ['r' => 'configBackup/fileBackup']) + ); + + $this->expectOutputString('{"status":"OK","description":"Backup process finished","data":null}'); + + $this->runApp($container); + } + + /** + * @throws ContainerExceptionInterface + * @throws Exception + * @throws NotFoundExceptionInterface + */ + #[Test] + public function xmlExport() + { + $container = $this->buildContainer( + $this->definitions, + $this->buildRequest('get', 'index.php', ['r' => 'configBackup/xmlExport']) + ); + + $this->expectOutputString('{"status":"OK","description":"Export process finished","data":null}'); + + $this->runApp($container); } /** @@ -90,8 +192,8 @@ class ConfigBackupControllerTest extends IntegrationTestCase { $configData = parent::getConfigData(); $configData->method('getBackupHash')->willReturn($this->passwordSalt); + $configData->method('getExportHash')->willReturn($this->passwordSalt); return $configData; } - }