From 36d6a72317f145a90c1c00eaeecc3db37f1eea8c Mon Sep 17 00:00:00 2001 From: Yuri Kuznetsov Date: Tue, 6 Jul 2021 13:46:49 +0300 Subject: [PATCH] public folder --- .htaccess | 48 +++++++++----- Gruntfile.js | 16 ++--- application/Espo/Core/Portal/Utils/Url.php | 12 +++- application/Espo/Core/Utils/Route.php | 5 +- index.php | 62 ++++++++++++++---- install/core/tpl/index.tpl | 2 +- .../portal-access => public/api/v1}/.htaccess | 2 +- {api => public/api}/v1/index.php | 2 +- .../api/v1/portal-access}/.htaccess | 0 .../api}/v1/portal-access/index.php | 8 ++- .../api/v1/portal-access}/web.config | 6 +- .../api/v1}/web.config | 4 +- public/index.php | 46 +++++++++++++ {install => public/install}/css/install.css | 0 {install => public/install}/img/devices.png | Bin {install => public/install}/index.php | 24 +++---- {install => public/install}/js/install.js | 0 .../oauth-callback.php | 2 +- {portal => public/portal}/.htaccess | 4 +- {portal => public/portal}/index.php | 2 +- {portal => public/portal}/web.config | 10 ++- robots.txt => public/robots.txt | 0 22 files changed, 185 insertions(+), 70 deletions(-) rename {api/v1/portal-access => public/api/v1}/.htaccess (92%) rename {api => public/api}/v1/index.php (97%) rename {api/v1 => public/api/v1/portal-access}/.htaccess (100%) rename {api => public/api}/v1/portal-access/index.php (92%) rename {api/v1 => public/api/v1/portal-access}/web.config (63%) rename {api/v1/portal-access => public/api/v1}/web.config (94%) create mode 100644 public/index.php rename {install => public/install}/css/install.css (100%) rename {install => public/install}/img/devices.png (100%) rename {install => public/install}/index.php (92%) rename {install => public/install}/js/install.js (100%) rename oauth-callback.php => public/oauth-callback.php (98%) rename {portal => public/portal}/.htaccess (84%) rename {portal => public/portal}/index.php (98%) rename {portal => public/portal}/web.config (59%) rename robots.txt => public/robots.txt (100%) diff --git a/.htaccess b/.htaccess index f943999d3b..c37b5cc41f 100644 --- a/.htaccess +++ b/.htaccess @@ -1,24 +1,42 @@ - Header always set Access-Control-Allow-Methods "POST, GET, PUT, PATCH, DELETE" + Header always set Access-Control-Allow-Methods "POST, GET, PUT, PATCH, DELETE" -DirectoryIndex index.php index.html +DirectoryIndex index.php + +Options -Indexes - RewriteEngine On + RewriteEngine On - # PROTECTED DIRECTORIES - RewriteCond %{REQUEST_FILENAME} -d - RewriteRule ^/?(api|client)/ - [F] + # Forbid access. Not actual as redirect to `public` is applied. + # An extra security measure if redirect not fired. + RewriteRule ^/?data/ - [F] + RewriteRule ^/?application/ - [F] + RewriteRule ^/?custom/ - [F] + RewriteRule ^/?vendor/ - [F] + RewriteRule /?web\.config - [F] - RewriteRule ^/?data/ - [F] - RewriteRule ^/?application/ - [F] - RewriteRule ^/?custom/ - [F] - RewriteRule ^/?vendor/ - [F] - RewriteRule ^/?client/?$ - [F] - #END PROTECTED DIRECTORIES + # Forbid `public` dir. + RewriteCond %{ENV:REDIRECT_STATUS} !=200 + RewriteRule ^/?public/? - [F,L] - RewriteRule .* - [E=HTTP_ESPO_CGI_AUTH:%{HTTP:Authorization}] + # Skip redirect for `client` dir. + RewriteRule ^client/ - [L] - RewriteRule /?web\.config - [F] - \ No newline at end of file + # Skip redirect for `node_modules` dir. Actual only for dev environment. + RewriteRule ^node_modules/ - [L] + + # Store base path. + RewriteCond %{REQUEST_URI}::$1 ^(.*?/)(.*)::\2$ + RewriteRule ^(.*)$ - [E=BASE:%1] + + # Add trailing slash. + RewriteCond %{DOCUMENT_ROOT}/%{ENV:BASE}/public/$1 -d + RewriteRule ^(.*?[^/])$ %{REQUEST_URI}/ [L,R=301,NE] + + # Rewrite to `public` dir. + RewriteRule ^((?!public/).*)$ %{ENV:BASE}/public/$1 [L,NC] + + RewriteRule .* - [E=HTTP_ESPO_CGI_AUTH:%{HTTP:Authorization}] + diff --git a/Gruntfile.js b/Gruntfile.js index c63374e23e..1187fc7a90 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -177,14 +177,13 @@ module.exports = grunt => { expand: true, dot: true, src: [ - 'api/**', 'application/**', 'custom/**', 'data/.data', - 'install/**', - 'portal/**', 'vendor/**', 'html/**', + 'public/**', + 'install/**', 'bootstrap.php', 'cron.php', 'daemon.php', @@ -195,7 +194,6 @@ module.exports = grunt => { 'extension.php', 'websocket.php', 'command.php', - 'oauth-callback.php', 'index.php', 'LICENSE.txt', '.htaccess', @@ -234,11 +232,11 @@ module.exports = grunt => { mode: '755' }, src: [ - 'build/EspoCRM-<%= pkg.version %>/install', - 'build/EspoCRM-<%= pkg.version %>/portal', - 'build/EspoCRM-<%= pkg.version %>/api', - 'build/EspoCRM-<%= pkg.version %>/api/v1', - 'build/EspoCRM-<%= pkg.version %>/api/v1/portal-access', + 'build/EspoCRM-<%= pkg.version %>/public/install', + 'build/EspoCRM-<%= pkg.version %>/public/portal', + 'build/EspoCRM-<%= pkg.version %>/public/api', + 'build/EspoCRM-<%= pkg.version %>/public/api/v1', + 'build/EspoCRM-<%= pkg.version %>/public/api/v1/portal-access', 'build/EspoCRM-<%= pkg.version %>', ], }, diff --git a/application/Espo/Core/Portal/Utils/Url.php b/application/Espo/Core/Portal/Utils/Url.php index f20fbe3e4a..deaa1fb25d 100644 --- a/application/Espo/Core/Portal/Utils/Url.php +++ b/application/Espo/Core/Portal/Utils/Url.php @@ -40,8 +40,11 @@ class Url } $url = $_SERVER['REQUEST_URI']; + $scriptName = $_SERVER['SCRIPT_NAME']; - return explode('/', $url)[count(explode('/', $_SERVER['SCRIPT_NAME'])) - 1] ?? null; + $scriptNameModified = str_replace('public/api/', 'api/', $scriptName); + + return explode('/', $url)[count(explode('/', $scriptNameModified)) - 1] ?? null; } public static function detectPortalId(): ?string @@ -53,8 +56,11 @@ class Url } $url = $_SERVER['REQUEST_URI']; + $scriptName = $_SERVER['SCRIPT_NAME']; - $portalId = explode('/', $url)[count(explode('/', $_SERVER['SCRIPT_NAME'])) - 1] ?? null; + $scriptNameModified = str_replace('public/api/', 'api/', $scriptName); + + $portalId = explode('/', $url)[count(explode('/', $scriptNameModified)) - 1] ?? null; if (strpos($url, '=') !== false) { $portalId = null; @@ -70,7 +76,7 @@ class Url return null; } - $portalId = explode('/', $url)[count(explode('/', $_SERVER['SCRIPT_NAME'])) - 1] ?? null; + $portalId = explode('/', $url)[count(explode('/', $scriptNameModified)) - 1] ?? null; if ($portalId === '') { $portalId = null; diff --git a/application/Espo/Core/Utils/Route.php b/application/Espo/Core/Utils/Route.php index da6751b06d..102133b774 100644 --- a/application/Espo/Core/Utils/Route.php +++ b/application/Espo/Core/Utils/Route.php @@ -174,7 +174,10 @@ class Route public static function detectBasePath(): string { $scriptName = parse_url($_SERVER['SCRIPT_NAME'] , PHP_URL_PATH); - $scriptDir = dirname($scriptName); + + $scriptNameModified = str_replace('public/api/', 'api/', $scriptName); + + $scriptDir = dirname($scriptNameModified); $uri = parse_url('http://any.com' . $_SERVER['REQUEST_URI'], PHP_URL_PATH); diff --git a/index.php b/index.php index 8bea931e04..a7162e5ca0 100644 --- a/index.php +++ b/index.php @@ -27,20 +27,58 @@ * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. ************************************************************************/ -include "bootstrap.php"; +$path = getcwd(); -use Espo\Core\{ - Application, - ApplicationRunners\Client, - ApplicationRunners\EntryPoint, -}; +echo <<For apache webserver -$app = new Application(); +

Non-production environment

-if (filter_has_var(INPUT_GET, 'entryPoint')) { - $app->run(EntryPoint::class); +

+You need to enable `.htaccess` usage in the apache configuration. Add the code: +

- exit; -} +
+
+<Directory $path>
+  AllowOverride All
+</Directory>
+
+
-$app->run(Client::class); +

Poduction environment

+ +

+It's recommended to configure the document root to look at the `public` +directory and create an alias for the `client` directory. The code to add to the apache configuration: +

+ +
+
+DocumentRoot $path/public/
+Alias /client/ $path/client/
+
+
+ +

+And allow override for the `public` directory: +

+ +
+
+<Directory $path/public/>
+  AllowOverride All
+</Directory>
+
+
+ +

+More detals in the documentation. +

+ +

For nginx webserver

+ +

+You need to configure the document root to look at the `public` directory and create an alias for the `client` directory. More detals in the documentation. +

+EOL; diff --git a/install/core/tpl/index.tpl b/install/core/tpl/index.tpl index 1a9cbb09ca..9dd8a4ed45 100644 --- a/install/core/tpl/index.tpl +++ b/install/core/tpl/index.tpl @@ -6,7 +6,7 @@ - {if $isBuild} + {if $isBuilt} {else} {foreach from=$libFileList item=file} diff --git a/api/v1/portal-access/.htaccess b/public/api/v1/.htaccess similarity index 92% rename from api/v1/portal-access/.htaccess rename to public/api/v1/.htaccess index a9f4ca8fef..d5db689a01 100644 --- a/api/v1/portal-access/.htaccess +++ b/public/api/v1/.htaccess @@ -11,4 +11,4 @@ RewriteRule .* - [E=HTTP_ESPO_CGI_AUTH:%{HTTP:Authorization}] RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^ index.php [QSA,L] -RewriteRule /?web\.config - [F] \ No newline at end of file +RewriteRule /?web\.config - [F] diff --git a/api/v1/index.php b/public/api/v1/index.php similarity index 97% rename from api/v1/index.php rename to public/api/v1/index.php index 8fe44fa1ec..79e92ecb61 100644 --- a/api/v1/index.php +++ b/public/api/v1/index.php @@ -27,7 +27,7 @@ * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. ************************************************************************/ -require_once('../../bootstrap.php'); +require_once('../../../bootstrap.php'); use Espo\Core\{ Application, diff --git a/api/v1/.htaccess b/public/api/v1/portal-access/.htaccess similarity index 100% rename from api/v1/.htaccess rename to public/api/v1/portal-access/.htaccess diff --git a/api/v1/portal-access/index.php b/public/api/v1/portal-access/index.php similarity index 92% rename from api/v1/portal-access/index.php rename to public/api/v1/portal-access/index.php index 6d631214b1..74ade3bcb8 100644 --- a/api/v1/portal-access/index.php +++ b/public/api/v1/portal-access/index.php @@ -27,7 +27,7 @@ * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. ************************************************************************/ -require_once('../../../bootstrap.php'); +require_once('../../../../bootstrap.php'); use Espo\Core\{ Portal\Application, @@ -37,4 +37,10 @@ use Espo\Core\{ $portalId = Url::detectPortalIdForApi(); +if ($portalId === null || $portalId === '') { + echo "No portal ID"; + + exit; +} + (new Application($portalId))->run(Api::class); diff --git a/api/v1/web.config b/public/api/v1/portal-access/web.config similarity index 63% rename from api/v1/web.config rename to public/api/v1/portal-access/web.config index be763f982b..82fa8980e2 100644 --- a/api/v1/web.config +++ b/public/api/v1/portal-access/web.config @@ -5,9 +5,9 @@ - - - + + + diff --git a/api/v1/portal-access/web.config b/public/api/v1/web.config similarity index 94% rename from api/v1/portal-access/web.config rename to public/api/v1/web.config index 5f124e51e8..a1f42666b5 100644 --- a/api/v1/portal-access/web.config +++ b/public/api/v1/web.config @@ -1,15 +1,13 @@ - - + - \ No newline at end of file diff --git a/public/index.php b/public/index.php new file mode 100644 index 0000000000..18b87941d0 --- /dev/null +++ b/public/index.php @@ -0,0 +1,46 @@ +run(EntryPoint::class); + + exit; +} + +$app->run(Client::class); diff --git a/install/css/install.css b/public/install/css/install.css similarity index 100% rename from install/css/install.css rename to public/install/css/install.css diff --git a/install/img/devices.png b/public/install/img/devices.png similarity index 100% rename from install/img/devices.png rename to public/install/img/devices.png diff --git a/install/index.php b/public/install/index.php similarity index 92% rename from install/index.php rename to public/install/index.php index b858cd48d9..ad28620952 100644 --- a/install/index.php +++ b/public/install/index.php @@ -31,14 +31,14 @@ if (session_status() !== \PHP_SESSION_ACTIVE) { session_start(); } -require_once('../bootstrap.php'); +require_once('../../bootstrap.php'); use Espo\Core\Utils\Util; use Espo\Core\Utils\Client\DevModeJsFileListProvider; use Espo\Core\Utils\File\Manager as FileManager; if (!isset($postData)) { - require_once('core/PostData.php'); + require_once('install/core/PostData.php'); $postData = new PostData(); } @@ -48,7 +48,7 @@ $allPostData = $postData->getAll(); // action $action = (!empty($allPostData['action']))? $allPostData['action'] : 'main'; -require_once('core/Utils.php'); +require_once('install/core/Utils.php'); if (!Utils::checkActionExists($action)) { die('This page does not exist.'); @@ -75,7 +75,7 @@ if (!empty($allPostData)) { // get user selected language $userLang = (!empty($_SESSION['install']['user-lang']))? $_SESSION['install']['user-lang'] : 'en_US'; -require_once 'core/Language.php'; +require_once 'install/core/Language.php'; $language = new Language(); @@ -84,9 +84,9 @@ $langs = $language->get($userLang); $sanitizedLangs = Util::sanitizeHtml($langs); //END: get user selected language -$config = include('core/config.php'); +$config = include('install/core/config.php'); -require_once 'core/SystemHelper.php'; +require_once 'install/core/SystemHelper.php'; $systemHelper = new SystemHelper(); @@ -118,8 +118,8 @@ if (!$systemHelper->initWritable()) { require_once ('install/vendor/smarty/libs/Smarty.class.php'); -require_once 'core/Installer.php'; -require_once 'core/Utils.php'; +require_once 'install/core/Installer.php'; +require_once 'install/core/Utils.php'; $smarty = new Smarty(); $installer = new Installer(); @@ -185,8 +185,10 @@ switch ($action) { break; } -$actionFile = 'core/actions/'.$action.'.php'; -$tplName = $action.'.tpl'; +$actionFile = 'install/core/actions/' . $action . '.php'; + +$tplName = $action . '.tpl'; + $smarty->assign('tplName', $tplName); $smarty->assign('action', ucfirst($action)); @@ -201,7 +203,7 @@ if (!empty($actionFile) && file_exists('install/core/tpl/' . $tplName)) { /* check if EspoCRM is built */ $isBuilt = file_exists('client/espo.min.js'); - $smarty->assign('isBuilt', true); + $smarty->assign('isBuilt', $isBuilt); if (!$isBuilt) { $libListProvider = new DevModeJsFileListProvider(new FileManager()); diff --git a/install/js/install.js b/public/install/js/install.js similarity index 100% rename from install/js/install.js rename to public/install/js/install.js diff --git a/oauth-callback.php b/public/oauth-callback.php similarity index 98% rename from oauth-callback.php rename to public/oauth-callback.php index 418b68c929..1cec74f84d 100644 --- a/oauth-callback.php +++ b/public/oauth-callback.php @@ -27,7 +27,7 @@ * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. ************************************************************************/ -include "bootstrap.php"; +include "../bootstrap.php"; use Espo\Core\{ Application, diff --git a/portal/.htaccess b/public/portal/.htaccess similarity index 84% rename from portal/.htaccess rename to public/portal/.htaccess index c1d824da79..d5db689a01 100644 --- a/portal/.htaccess +++ b/public/portal/.htaccess @@ -9,4 +9,6 @@ RewriteEngine On RewriteRule .* - [E=HTTP_ESPO_CGI_AUTH:%{HTTP:Authorization}] RewriteCond %{REQUEST_FILENAME} !-f -RewriteRule ^ index.php [QSA,L] \ No newline at end of file +RewriteRule ^ index.php [QSA,L] + +RewriteRule /?web\.config - [F] diff --git a/portal/index.php b/public/portal/index.php similarity index 98% rename from portal/index.php rename to public/portal/index.php index 7a5ae89298..f135b90843 100644 --- a/portal/index.php +++ b/public/portal/index.php @@ -27,7 +27,7 @@ * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. ************************************************************************/ -include "../bootstrap.php"; +include "../../bootstrap.php"; use Espo\Core\{ Application, diff --git a/portal/web.config b/public/portal/web.config similarity index 59% rename from portal/web.config rename to public/portal/web.config index be763f982b..16d39beeb1 100644 --- a/portal/web.config +++ b/public/portal/web.config @@ -1,15 +1,13 @@ - - - - + + + - - \ No newline at end of file + diff --git a/robots.txt b/public/robots.txt similarity index 100% rename from robots.txt rename to public/robots.txt