diff --git a/config/core_services.yaml b/config/core_services.yaml index 4d860eda2..e5adeeda7 100644 --- a/config/core_services.yaml +++ b/config/core_services.yaml @@ -20,6 +20,7 @@ services: $copyLegacyAssetPaths: '%legacy.copy_asset_paths%' $legacyApiPaths: '%legacy.api_paths%' $legacyApiPathFiles: '%legacy.api_path_files%' + $legacyEntrypointPaths: '%legacy.entrypoint_paths%' $legacyEntrypointFiles: '%legacy.entrypoint_files%' $exposedUserPreferences: '%legacy.exposed_user_preferences%' $userPreferencesKeyMap: '%legacy.user_preferences_key_map%' diff --git a/config/packages/security.php b/config/packages/security.php index 2e2f422c1..55c7664f0 100644 --- a/config/packages/security.php +++ b/config/packages/security.php @@ -99,6 +99,7 @@ return static function (ContainerConfigurator $containerConfig) { ['path' => '^/api', 'roles' => 'PUBLIC_ACCESS'], ['path' => '^/api/graphql', 'roles' => 'PUBLIC_ACCESS'], ['path' => '^/api/graphql/graphiql*', 'roles' => 'PUBLIC_ACCESS'], + ['path' => '^/ep', 'roles' => 'PUBLIC_ACCESS'], ['path' => '^/', 'roles' => 'PUBLIC_ACCESS'] ]; diff --git a/config/routes.yaml b/config/routes.yaml index 4fb920cb7..82bedba68 100644 --- a/config/routes.yaml +++ b/config/routes.yaml @@ -16,3 +16,8 @@ engine_controllers: namespace: App\Engine\Controller type: attribute +entrypoint_controllers: + resource: + path: ../core/backend/EntryPoint/Controller/ + namespace: App\EntryPoint\Controller + type: attribute diff --git a/config/services/legacy/entrypoint_files.yaml b/config/services/legacy/entrypoint_files.yaml index 9a391c885..2868a7c8c 100644 --- a/config/services/legacy/entrypoint_files.yaml +++ b/config/services/legacy/entrypoint_files.yaml @@ -1,4 +1,7 @@ parameters: + legacy.entrypoint_paths: + ep: index.php + legacy.entrypoint_files: 'campaign_tracker.php': file: campaign_tracker.php diff --git a/core/backend/Engine/LegacyHandler/LegacyHandler.php b/core/backend/Engine/LegacyHandler/LegacyHandler.php index 42f710259..01349bff2 100644 --- a/core/backend/Engine/LegacyHandler/LegacyHandler.php +++ b/core/backend/Engine/LegacyHandler/LegacyHandler.php @@ -153,6 +153,16 @@ abstract class LegacyHandler return true; } + public function getProjectDir(): string + { + return $this->projectDir; + } + + public function setProjectDir(string $projectDir): void + { + $this->projectDir = $projectDir; + } + /** * Swap symfony session with legacy suite session * @param string $sessionName diff --git a/core/backend/EntryPoint/Controller/EntryPointController.php b/core/backend/EntryPoint/Controller/EntryPointController.php new file mode 100644 index 000000000..583883056 --- /dev/null +++ b/core/backend/EntryPoint/Controller/EntryPointController.php @@ -0,0 +1,58 @@ +. + * + * In accordance with Section 7(b) of the GNU Affero General Public License + * version 3, these Appropriate Legal Notices must retain the display of the + * "Supercharged by SuiteCRM" logo. If the display of the logos is not reasonably + * feasible for technical reasons, the Appropriate Legal Notices must display + * the words "Supercharged by SuiteCRM". + */ + +namespace App\EntryPoint\Controller; + +use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Routing\Annotation\Route; + +/** + * Class IndexController + * @package App\Controller + */ +class EntryPointController extends AbstractController +{ + + #[Route('/ep/{name}', name: 'generic_ep_route', methods: ["GET", "POST"], stateless: false)] + public function genericEntryPoint(): Response + { + $response = new Response(); + $response->setStatusCode(Response::HTTP_NOT_FOUND); + + return $response; + } + + #[Route('/ep', name: 'empty_ep_route', methods: ["GET", "POST"], stateless: false)] + public function emptyEntryPoint(): Response + { + $response = new Response(); + $response->setStatusCode(Response::HTTP_NOT_FOUND); + + return $response; + } +} diff --git a/core/backend/EntryPoint/LegacyHandler/EntryPointHandler.php b/core/backend/EntryPoint/LegacyHandler/EntryPointHandler.php new file mode 100644 index 000000000..c35bbfbc0 --- /dev/null +++ b/core/backend/EntryPoint/LegacyHandler/EntryPointHandler.php @@ -0,0 +1,79 @@ +. + * + * In accordance with Section 7(b) of the GNU Affero General Public License + * version 3, these Appropriate Legal Notices must retain the display of the + * "Supercharged by SuiteCRM" logo. If the display of the logos is not reasonably + * feasible for technical reasons, the Appropriate Legal Notices must display + * the words "Supercharged by SuiteCRM". + */ + +namespace App\EntryPoint\LegacyHandler; + +use App\Engine\LegacyHandler\LegacyHandler; +use ControllerFactory; +use SugarController; + +class EntryPointHandler extends LegacyHandler +{ + public const HANDLER_KEY = 'entrypoint'; + + /** + * @inheritDoc + */ + public function getHandlerKey(): string + { + return self::HANDLER_KEY; + } + + /** + * Get currency info array + * @param string $entryPoint + * @return array + */ + public function validateEntryPoint(string $entryPoint): array + { + $this->init(); + + /** @var SugarController $controller */ + $controller = ControllerFactory::getController('home'); + + $valid = false; + $auth = true; + + $authRequired = $controller->checkEntryPointRequiresAuth($entryPoint); + + if ($authRequired && get_authenticated_user() === NULL) { + $auth = false; + } + + if (!empty($controller->entry_point_registry[$entryPoint])) { + $valid = true; + } + + $this->close(); + + return [ + 'valid' => $valid, + 'auth' => $auth, + ]; + } + +} diff --git a/core/backend/Kernel.php b/core/backend/Kernel.php index dc1d75173..fae527a20 100644 --- a/core/backend/Kernel.php +++ b/core/backend/Kernel.php @@ -127,7 +127,10 @@ class Kernel extends BaseKernel public function getLegacyRoute(Request $request): array { if ($this->container->has('legacy.route.handler')) { - return $this->container->get('legacy.route.handler')->getLegacyRoute($request); + $legacyRouteHandler = $this->container->get('legacy.route.handler'); + $legacyRouteHandler->setCurrentDir(getcwd()); + + return $legacyRouteHandler->getLegacyRoute($request); } return []; diff --git a/core/backend/Routes/Service/LegacyEntryPointRedirectHandler.php b/core/backend/Routes/Service/LegacyEntryPointRedirectHandler.php new file mode 100644 index 000000000..79712b013 --- /dev/null +++ b/core/backend/Routes/Service/LegacyEntryPointRedirectHandler.php @@ -0,0 +1,159 @@ +. + * + * In accordance with Section 7(b) of the GNU Affero General Public License + * version 3, these Appropriate Legal Notices must retain the display of the + * "Supercharged by SuiteCRM" logo. If the display of the logos is not reasonably + * feasible for technical reasons, the Appropriate Legal Notices must display + * the words "Supercharged by SuiteCRM". + */ + + +namespace App\Routes\Service; + +use App\EntryPoint\LegacyHandler\EntryPointHandler; +use Symfony\Component\HttpFoundation\Request; + +class LegacyEntryPointRedirectHandler extends LegacyRedirectHandler +{ + private array $legacyEntrypointPaths; + private EntryPointHandler $entryPointHandler; + private string $currentDir; + + /** + * LegacyEntryPointRedirectHandler constructor. + * @param array $legacyEntrypointPaths + * @param String $legacyPath + */ + public function __construct(EntryPointHandler $entryPointHandler, array $legacyEntrypointPaths, string $legacyPath) + { + parent::__construct($legacyPath); + $this->entryPointHandler = $entryPointHandler; + $this->legacyEntrypointPaths = $legacyEntrypointPaths; + } + + /** + * Check if the given $request is a legacy entryPoint request + * + * @param Request $request + * @return bool + */ + public function isEntryPointRequest(Request $request): bool + { + return $this->inPathList($request, array_keys($this->legacyEntrypointPaths)); + } + + public function setCurrentDir(string $dir): void + { + $this->currentDir = $dir; + } + + /** + * Check if the given $request is a valid legacy entryPoint + * + * @param Request $request + * @return array + */ + public function isValidEntryPoint(Request $request): array + { + $entryPoint = $this->getEntryPoint($request); + if (!empty($entryPoint)) { + $this->entryPointHandler->setProjectDir($this->currentDir); + return $this->entryPointHandler->validateEntryPoint($entryPoint['name']); + } + + return ['valid' => false]; + } + + /** + * Convert given $request route + * + * @param Request $request + * @return string + */ + public function convert(Request $request): string + { + $legacyPath = parent::convert($request); + + foreach ($this->legacyEntrypointPaths as $path => $replace) { + if ($this->inPath($request, $path)) { + return str_replace($path, $replace, $legacyPath); + } + } + + return $legacyPath; + } + + /** + * Convert given $request route + * + * @param Request $request + * @return array + */ + public function getIncludeFile(Request $request): array + { + $entryPoint = $this->getEntryPoint($request); + if (!empty($entryPoint)) { + + $base = $_SERVER['BASE'] ?? $_SERVER['REDIRECT_BASE'] ?? ''; + + $scriptName = $base . '/legacy/' . $entryPoint['file']; + $requestUri = $base . '/legacy/' . $entryPoint['file'] . $entryPoint['params']; + + $_REQUEST['entryPoint'] = $entryPoint['name']; + + $info['dir'] = ''; + $info['file'] = $entryPoint['file']; + $info['script-name'] = $scriptName; + $info['request-uri'] = $requestUri; + $info['access'] = true; + + return $info; + } + + return [ + 'dir' => '', + 'file' => './index.php', + 'access' => false + ]; + } + + protected function getEntryPoint(Request $request): array + { + foreach ($this->legacyEntrypointPaths as $path => $file) { + if ($this->inPath($request, $path)) { + $epCheck = explode('/' . $path . '/', $request->getRequestUri()); + if (!empty($epCheck[1])) { + $entryPoint = explode('?', $epCheck[1]); + + return [ + 'name' => $entryPoint[0], + 'params' => !empty($entryPoint[1]) ? '?' . $entryPoint[1] : '', + 'path' => $path, + 'file' => $file, + ]; + } + } + } + + return []; + } + +} diff --git a/core/backend/Routes/Service/LegacyRouteHandler.php b/core/backend/Routes/Service/LegacyRouteHandler.php index 41efb2d9c..0b8330ca0 100644 --- a/core/backend/Routes/Service/LegacyRouteHandler.php +++ b/core/backend/Routes/Service/LegacyRouteHandler.php @@ -46,20 +46,26 @@ class LegacyRouteHandler */ private $legacyAssetRedirectHandler; + private LegacyEntryPointRedirectHandler $legacyEntryPointRedirectHandler; + private string $currentDir; + /** * LegacyRedirectListener constructor. * @param LegacyApiRedirectHandler $legacyApiRedirectHandler * @param LegacyNonViewActionRedirectHandler $legacyNonViewActionRedirectHandler * @param LegacyAssetRedirectHandler $legacyAssetRedirectHandler + * @param LegacyEntryPointRedirectHandler $legacyEntryPointRedirectHandler */ public function __construct( LegacyApiRedirectHandler $legacyApiRedirectHandler, LegacyNonViewActionRedirectHandler $legacyNonViewActionRedirectHandler, - LegacyAssetRedirectHandler $legacyAssetRedirectHandler + LegacyAssetRedirectHandler $legacyAssetRedirectHandler, + LegacyEntryPointRedirectHandler $legacyEntryPointRedirectHandler ) { $this->legacyApiRedirectHandler = $legacyApiRedirectHandler; $this->legacyNonViewActionRedirectHandler = $legacyNonViewActionRedirectHandler; $this->legacyAssetRedirectHandler = $legacyAssetRedirectHandler; + $this->legacyEntryPointRedirectHandler = $legacyEntryPointRedirectHandler; } /** @@ -79,6 +85,21 @@ class LegacyRouteHandler return $this->legacyNonViewActionRedirectHandler->getIncludeFile($request); } + if ($this->isLegacyEntryPointPath($request)) { + $entryPoint = $this->isValidLegacyEntryPoint($request); + if ($entryPoint['valid']) { + if ($entryPoint['auth']) { + return $this->legacyEntryPointRedirectHandler->getIncludeFile($request); + } + + return [ + 'access' => false + ]; + } + + return []; + } + if ($this->isLegacyApi($request)) { return $this->legacyApiRedirectHandler->getIncludeFile($request); } @@ -99,6 +120,11 @@ class LegacyRouteHandler return []; } + public function setCurrentDir($dir) : void + { + $this->currentDir = $dir; + } + /** * Check if it is legacy entry point * @param Request $request @@ -159,4 +185,26 @@ class LegacyRouteHandler return $this->legacyNonViewActionRedirectHandler->isMatch($request); } + /** + * Check if it is EntryPoint Path view request + * @param Request $request + * @return bool + */ + protected function isLegacyEntryPointPath(Request $request): bool + { + return $this->legacyEntryPointRedirectHandler->isEntryPointRequest($request); + } + + /** + * Check if it is EntryPoint Path view request + * @param Request $request + * @return array + */ + protected function isValidLegacyEntryPoint(Request $request): array + { + $this->legacyEntryPointRedirectHandler->setCurrentDir($this->currentDir); + return $this->legacyEntryPointRedirectHandler->isValidEntryPoint($request); + } + + }