isMenuEnabled !== null) { return $this->isMenuEnabled; } $this->isMenuEnabled = $this->dbi->isConnected(); return $this->isMenuEnabled; } public function getScripts(): Scripts { if ($this->scripts !== null) { return $this->scripts; } $this->scripts = new Scripts($this->template); $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.min.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()); return $this->scripts; } /** * 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->config->DefaultTabDatabase), 'lang' => Current::$lang, 'server' => Current::$server, 'table' => Current::$table, 'db' => Current::$database, 'token' => Session::getToken(), 'text_dir' => LanguageManager::$textDirection->value, 'LimitChars' => $this->config->config->limitChars, 'pftext' => $pftext, 'confirm' => $this->config->config->Confirm, 'LoginCookieValidity' => $this->config->config->LoginCookieValidity, 'session_gc_maxlifetime' => (int) ini_get('session.gc_maxlifetime'), 'logged_in' => $this->dbi->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) . '));'; } public function getMenu(): Menu { if ($this->menu !== null) { return $this->menu; } $this->menu = new Menu( $this->dbi, $this->template, $this->config, $this->relation, Current::$database, Current::$table, ); 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->isMenuEnabled = false; $this->console->disable(); } /** * Disables the display of the top menu */ public function disableWarnings(): void { $this->warningsEnabled = false; } /** @return array */ public function getDisplay(ResponseRenderer $responseRenderer): array { $themeManager = ContainerBuilder::getContainer()->get(ThemeManager::class); $theme = $themeManager->theme; $scripts = $this->getScripts(); $userAgent = Core::getEnv('HTTP_USER_AGENT'); // The user preferences have been merged at this point // so we can conditionally add CodeMirror, other scripts and settings // See #20159, why we need to check for HTTP_USER_AGENT here if ($this->config->config->CodemirrorEnable && $userAgent !== '') { $scripts->addFile('vendor/codemirror/lib/codemirror.js'); $scripts->addFile('vendor/codemirror/mode/sql/sql.js'); $scripts->addFile('vendor/codemirror/addon/runmode/runmode.js'); $scripts->addFile('vendor/codemirror/addon/hint/show-hint.js'); $scripts->addFile('vendor/codemirror/addon/hint/sql-hint.js'); if ($this->config->config->LintEnable) { $scripts->addFile('vendor/codemirror/addon/lint/lint.js'); $scripts->addFile('codemirror/addon/lint/sql-lint.js'); } } if ($this->config->config->SendErrorReports !== 'never') { $scripts->addFile('vendor/tracekit.js'); $scripts->addFile('error_report.js'); } if ($this->config->config->enable_drag_drop_import) { $scripts->addFile('drag_drop_import.js'); } if (! $this->config->config->DisableShortcutKeys) { $scripts->addFile('shortcuts_handler.js'); } $scripts->addCode($this->getVariablesForJavaScript()); $scripts->addCode('ConsoleEnterExecutes=' . ($this->config->config->ConsoleEnterExecutes ? 'true' : 'false')); $scripts->addFiles($this->console->getScripts()); if ($this->isMenuEnabled() && Current::$server > 0) { $navigation = (new Navigation($this->template, $this->relation, $this->dbi, $this->config)) ->getDisplay($responseRenderer); } $customHeader = self::renderHeader(); // offer to load user preferences from localStorage if ( $this->userPreferencesHandler->storageType === 'session' && ! isset($_SESSION['userprefs_autoload']) ) { $loadUserPreferences = $this->userPreferences->autoloadGetHeader(); } $menu = ''; if ($this->isMenuEnabled() && Current::$server > 0) { $menu = $this->getMenu()->getDisplay(); } $console = $this->console->getDisplay(); $messages = $this->getMessage(); $isLoggedIn = $this->dbi->isConnected(); $scripts->addFile('datetimepicker.js'); $scripts->addFile('validator-messages.js'); return [ 'lang' => Current::$lang, 'allow_third_party_framing' => $this->config->config->AllowThirdPartyFraming, 'codemirror_enable' => $this->config->config->CodemirrorEnable, 'lint_enable' => $this->config->config->LintEnable, 'theme_path' => $theme->getPath(), 'server' => Current::$server, 'title' => $this->getPageTitle(), 'scripts' => $scripts->getDisplay(), 'body_id' => $this->bodyId, 'navigation' => $navigation ?? '', 'custom_header' => $customHeader, 'load_user_preferences' => $loadUserPreferences ?? '', 'show_hint' => $this->config->config->ShowHint, 'is_warnings_enabled' => $this->warningsEnabled, 'is_menu_enabled' => $this->isMenuEnabled(), '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' => $this->dbi->getCurrentUserAndHost(), 'is_mariadb' => $this->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(ClockInterface|null $clock = null): array { $headers = [ 'Referrer-Policy' => 'same-origin', 'Content-Security-Policy' => $this->getCspHeader(), /** * Re-enable possible disabled XSS filters. * * @see https://developer.mozilla.org/docs/Web/HTTP/Headers/X-XSS-Protection */ '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 */ 'X-Content-Type-Options' => 'nosniff', /** * Adobe cross-domain-policies. * * @see https://www.sentrium.co.uk/labs/application-security-101-http-headers */ 'X-Permitted-Cross-Domain-Policies' => 'none', /** * Robots meta tag. * * @see https://developers.google.com/search/docs/crawling-indexing/robots-meta-tag */ '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