menuEnabled = $dbi->isConnected(); $relation = new Relation($dbi); $this->menu = new Menu($dbi, $this->template, $this->config, $relation, Current::$database, Current::$table); $this->scripts = new Scripts($this->template); $this->addDefaultScripts(); $this->userPreferences = new UserPreferences($dbi, $relation, $this->template); } /** * Loads common scripts */ private function addDefaultScripts(): void { $this->scripts->addFile('runtime.js'); $this->scripts->addFile('vendor/jquery/jquery.min.js'); $this->scripts->addFile('vendor/jquery/jquery-migrate.min.js'); $this->scripts->addFile('vendor/sprintf.js'); $this->scripts->addFile('vendor/jquery/jquery-ui.min.js'); $this->scripts->addFile('vendor/bootstrap/bootstrap.js'); $this->scripts->addFile('vendor/js.cookie.min.js'); $this->scripts->addFile('vendor/jquery/jquery.validate.min.js'); $this->scripts->addFile('vendor/jquery/jquery-ui-timepicker-addon.js'); $this->scripts->addFile('index.php', ['route' => '/messages', 'l' => Current::$lang]); $this->scripts->addFile('shared.js'); $this->scripts->addFile('menu_resizer.js'); $this->scripts->addFile('main.js'); $this->scripts->addCode($this->getJsParamsCode()); } /** * Returns, as an array, a list of parameters * used on the client side * * @return mixed[] */ public function getJsParams(): array { $pftext = $_SESSION['tmpval']['pftext'] ?? ''; $params = [ // Do not add any separator, JS code will decide 'common_query' => Url::getCommonRaw([], ''), 'opendb_url' => Url::getFromRoute($this->config->settings['DefaultTabDatabase']), 'lang' => Current::$lang, 'server' => Current::$server, 'table' => Current::$table, 'db' => Current::$database, 'token' => $_SESSION[' PMA_token '], 'text_dir' => LanguageManager::$textDirection->value, 'LimitChars' => $this->config->settings['LimitChars'], 'pftext' => $pftext, 'confirm' => $this->config->settings['Confirm'], 'LoginCookieValidity' => $this->config->settings['LoginCookieValidity'], 'session_gc_maxlifetime' => (int) ini_get('session.gc_maxlifetime'), 'logged_in' => DatabaseInterface::getInstance()->isConnected(), 'is_https' => $this->config->isHttps(), 'rootPath' => $this->config->getRootPath(), 'arg_separator' => Url::getArgSeparator(), 'version' => Version::VERSION, ]; if ($this->config->hasSelectedServer()) { $params['auth_type'] = $this->config->selectedServer['auth_type']; if (isset($this->config->selectedServer['user'])) { $params['user'] = $this->config->selectedServer['user']; } } return $params; } /** * Returns, as a string, a list of parameters * used on the client side */ public function getJsParamsCode(): string { $params = $this->getJsParams(); return 'window.Navigation.update(window.CommonParams.setAll(' . json_encode($params, JSON_HEX_TAG) . '));'; } /** * Returns the Scripts object * * @return Scripts object */ public function getScripts(): Scripts { return $this->scripts; } /** * Returns the Menu object * * @return Menu object */ public function getMenu(): Menu { return $this->menu; } /** * Setter for the ID attribute in the BODY tag * * @param string $id Value for the ID attribute */ public function setBodyId(string $id): void { $this->bodyId = htmlspecialchars($id); } /** * Setter for the title of the page * * @param string $title New title */ public function setTitle(string $title): void { $this->title = htmlspecialchars($title); } /** * Disables the display of the top menu */ public function disableMenuAndConsole(): void { $this->menuEnabled = false; $this->console->disable(); } /** * Disables the display of the top menu */ public function disableWarnings(): void { $this->warningsEnabled = false; } /** @return mixed[] */ public function getDisplay(): array { /** @var ThemeManager $themeManager */ $themeManager = ContainerBuilder::getContainer()->get(ThemeManager::class); $theme = $themeManager->theme; // The user preferences have been merged at this point // so we can conditionally add CodeMirror, other scripts and settings if ($this->config->settings['CodemirrorEnable']) { $this->scripts->addFile('vendor/codemirror/lib/codemirror.js'); $this->scripts->addFile('vendor/codemirror/mode/sql/sql.js'); $this->scripts->addFile('vendor/codemirror/addon/runmode/runmode.js'); $this->scripts->addFile('vendor/codemirror/addon/hint/show-hint.js'); $this->scripts->addFile('vendor/codemirror/addon/hint/sql-hint.js'); if ($this->config->settings['LintEnable']) { $this->scripts->addFile('vendor/codemirror/addon/lint/lint.js'); $this->scripts->addFile('codemirror/addon/lint/sql-lint.js'); } } if ($this->config->config->SendErrorReports !== 'never') { $this->scripts->addFile('vendor/tracekit.js'); $this->scripts->addFile('error_report.js'); } if ($this->config->settings['enable_drag_drop_import'] === true) { $this->scripts->addFile('drag_drop_import.js'); } if (! $this->config->config->DisableShortcutKeys) { $this->scripts->addFile('shortcuts_handler.js'); } $this->scripts->addCode($this->getVariablesForJavaScript()); $this->scripts->addCode( 'ConsoleEnterExecutes=' . ($this->config->settings['ConsoleEnterExecutes'] ? 'true' : 'false'), ); $this->scripts->addFiles($this->console->getScripts()); $dbi = DatabaseInterface::getInstance(); if ($this->menuEnabled && Current::$server > 0) { $navigation = (new Navigation($this->template, new Relation($dbi), $dbi, $this->config))->getDisplay(); } $customHeader = self::renderHeader(); // offer to load user preferences from localStorage if ( $this->config->userPreferences === 'session' && ! isset($_SESSION['userprefs_autoload']) ) { $loadUserPreferences = $this->userPreferences->autoloadGetHeader(); } if ($this->menuEnabled && Current::$server > 0) { $menu = $this->menu->getDisplay(); } $console = $this->console->getDisplay(); $messages = $this->getMessage(); $isLoggedIn = $dbi->isConnected(); $this->scripts->addFile('datetimepicker.js'); $this->scripts->addFile('validator-messages.js'); return [ 'lang' => Current::$lang, 'allow_third_party_framing' => $this->config->settings['AllowThirdPartyFraming'], 'theme_path' => $theme->getPath(), 'server' => Current::$server, 'title' => $this->getPageTitle(), 'scripts' => $this->scripts->getDisplay(), 'body_id' => $this->bodyId, 'navigation' => $navigation ?? '', 'custom_header' => $customHeader, 'load_user_preferences' => $loadUserPreferences ?? '', 'show_hint' => $this->config->settings['ShowHint'], 'is_warnings_enabled' => $this->warningsEnabled, 'is_menu_enabled' => $this->menuEnabled, 'is_logged_in' => $isLoggedIn, 'menu' => $menu ?? '', 'console' => $console, 'messages' => $messages, 'theme_color_mode' => $theme->getColorMode(), 'theme_color_modes' => $theme->getColorModes(), 'theme_id' => $theme->getId(), 'current_user' => $dbi->getCurrentUserAndHost(), 'is_mariadb' => $dbi->isMariaDB(), ]; } /** * Returns the message to be displayed at the top of * the page, including the executed SQL query, if any. */ public function getMessage(): string { $retval = ''; $message = ''; if (Current::$message !== null) { $message = Current::$message; Current::$message = null; } elseif (! empty($_REQUEST['message'])) { $message = $_REQUEST['message']; } if ($message !== '') { $retval .= Generator::getMessage($message); } return $retval; } /** @return array */ public function getHttpHeaders(): array { $headers = []; /* Prevent against ClickJacking by disabling framing */ if (strtolower((string) $this->config->settings['AllowThirdPartyFraming']) === 'sameorigin') { $headers['X-Frame-Options'] = 'SAMEORIGIN'; } elseif ($this->config->settings['AllowThirdPartyFraming'] !== true) { $headers['X-Frame-Options'] = 'DENY'; } $headers['Referrer-Policy'] = 'same-origin'; $headers = array_merge($headers, $this->getCspHeaders()); /** * Re-enable possible disabled XSS filters. * * @see https://developer.mozilla.org/docs/Web/HTTP/Headers/X-XSS-Protection */ $headers['X-XSS-Protection'] = '1; mode=block'; /** * "nosniff", prevents Internet Explorer and Google Chrome from MIME-sniffing * a response away from the declared content-type. * * @see https://developer.mozilla.org/docs/Web/HTTP/Headers/X-Content-Type-Options */ $headers['X-Content-Type-Options'] = 'nosniff'; /** * Adobe cross-domain-policies. * * @see https://www.sentrium.co.uk/labs/application-security-101-http-headers */ $headers['X-Permitted-Cross-Domain-Policies'] = 'none'; /** * Robots meta tag. * * @see https://developers.google.com/search/docs/crawling-indexing/robots-meta-tag */ $headers['X-Robots-Tag'] = 'noindex, nofollow'; /** * The HTTP Permissions-Policy header provides a mechanism to allow and deny * the use of browser features in a document * or within any