1# 2# Authentic Theme (https://github.com/authentic-theme/authentic-theme) 3# Copyright Ilia Rostovtsev <programming@rostovtsev.io> 4# Licensed under MIT (https://github.com/authentic-theme/authentic-theme/blob/master/LICENSE) 5# 6use strict; 7 8our (@theme_bundle_css, 9 @theme_bundle_js, 10 %module_text_full, 11 %theme_config, 12 %theme_text, 13 %theme_temp_data, 14 $get_user_level, 15 $theme_webprefix, 16 $theme_server_webprefix, 17 $has_cloudmin, 18 $has_usermin_conf_dir, 19 $has_usermin_root_dir, 20 $has_usermin_version, 21 $has_usermin, 22 $has_virtualmin, 23 $http_x_url, 24 $server_x_goto, 25 $xnav, 26 %config, 27 %gaccess, 28 %gconfig, 29 %in, 30 %tconfig, 31 %text, 32 $config_directory, 33 $current_lang, 34 $current_theme, 35 $remote_user, 36 $root_directory, 37 $theme_root_directory, 38 $title); 39 40do("$ENV{'THEME_ROOT'}/authentic-funcs.pl"); 41 42init_vars(); 43 44sub settings_filter 45{ 46 my (%in_data) = @_; 47 48 delete @in_data{ grep(!/^config_portable_|^settings_/, keys %in_data) }; 49 delete @in_data{ grep(!m/^\w*$/, keys %in_data) }; 50 for (values %in_data) {s/(.*)/'$1';/} 51 for (values %in_data) {s/\$|`*//g} 52 for (values %in_data) {s/<<//g} 53 for (values %in_data) {s/"/'/g} 54 for (values %in_data) {s/\/\/////g} 55 for (values %in_data) {s/'true'/true/g} 56 for (values %in_data) {s/'false'/false/g} 57 for (values %in_data) {s/'1'/1/g} 58 for (values %in_data) {s/'0'/0/g} 59 60 for (values %in_data) { 61 s/ 62 \G 63 ( 64 (?: ^ [^']* ' | (?!^) ) 65 (?: [^'\\]+ | \\. )* 66 ) 67 ' 68 (?! [^']* \z ) 69 / 70 $1 . "\\'" 71 /xseg; 72 } 73 return %in_data; 74} 75 76sub get_theme_color 77{ 78 my %theme_colors = ('blue' => '#0d5ab7', 79 'brown' => '#5d4839', 80 'gold' => '#917851', 81 'green' => '#277b4c', 82 'grey' => '#4c5250', 83 'orange' => '#946a44', 84 'purple' => '#543c53', 85 'red' => '#a02638', 86 'white' => '#ffffff'); 87 88 my $color = $theme_config{'settings_navigation_color'}; 89 return $theme_colors{$color}; 90} 91 92sub embed_favicon 93{ 94 my ($is_login_page) = @_; 95 96 return if ($theme_config{"settings_embed_favicon_privileged"} eq 'false'); 97 98 my $product = get_product_name() eq 'usermin' ? 'usermin' : 'webmin'; 99 my $product_name = $product; 100 if ($get_user_level eq '1' || $get_user_level eq '2') { 101 $product_name = 'virtualmin'; 102 } 103 if ($get_user_level eq '4') { 104 $product_name = 'cloudmin'; 105 } 106 107 my $theme_config_dir = "$config_directory/$current_theme"; 108 my $theme_user_color = get_theme_color() || "#0d5ab7"; 109 110 my $favicon_path = $theme_webprefix . '/images/favicons/' . $product_name; 111 my $ref_link = 'data-link-ref'; 112 113 my $favicon_dpath = "$root_directory/$current_theme/images/favicons/$product_name"; 114 my $favicon_cpath = "$theme_config_dir/favicons/$product_name"; 115 my $favicon_spath = -r $favicon_cpath ? $favicon_cpath : $favicon_dpath; 116 117 # Embed standard favicons using a direct link 118 if (!-r $favicon_cpath) { 119 print ' <link ' . 120 $ref_link . ' rel="apple-touch-icon" sizes="180x180" href="' . $favicon_path . '/apple-touch-icon.png">' . "\n"; 121 print ' <link ' . 122 $ref_link . ' rel="icon" type="image/png" sizes="32x32" href="' . $favicon_path . '/favicon-32x32.png">' . "\n"; 123 print ' <link ' . $ref_link . 124 ' rel="icon" type="image/png" sizes="192x192" href="' . $favicon_path . '/android-chrome-192x192.png">' . "\n"; 125 print ' <link ' . 126 $ref_link . ' rel="icon" type="image/png" sizes="16x16" href="' . $favicon_path . '/favicon-16x16.png">' . "\n"; 127 print ' <link ' . $ref_link . 128 ' rel="mask-icon" href="' . $favicon_path . '/safari-pinned-tab.svg" color="' . $theme_user_color . '">' . "\n"; 129 print ' <meta ' . 130 $ref_link . ' name="msapplication-TileImage" content="' . $favicon_path . '/mstile-150x150.png">' . "\n"; 131 } 132 133 # Embed custom favicons using base64 encoding 134 else { 135 print ' <link ' . $ref_link . ' rel="apple-touch-icon" sizes="180x180" href="data:text/css;base64,' . 136 trim_lines(trim(encode_base64(read_file_contents($favicon_spath . '/apple-touch-icon.png')))) . '">' . "\n"; 137 print ' <link ' . $ref_link . ' rel="icon" type="image/png" sizes="32x32" href="data:text/css;base64,' . 138 trim_lines(trim(encode_base64(read_file_contents($favicon_spath . '/favicon-32x32.png')))) . '">' . "\n"; 139 print ' <link ' . $ref_link . ' rel="icon" type="image/png" sizes="192x192" href="data:text/css;base64,' . 140 trim_lines(trim(encode_base64(read_file_contents($favicon_spath . '/android-chrome-192x192.png')))) . '">' . "\n"; 141 print ' <link ' . $ref_link . ' rel="icon" type="image/png" sizes="16x16" href="data:text/css;base64,' . 142 trim_lines(trim(encode_base64(read_file_contents($favicon_spath . '/favicon-16x16.png')))) . '">' . "\n"; 143 } 144 print ' <meta name="msapplication-TileColor" content="' . $theme_user_color . '">' . "\n"; 145 print ' <meta name="theme-color" content="' . $theme_user_color . '">' . "\n"; 146 if (!$is_login_page) { 147 148 # Generate manifest file from template 149 my $display_hostname = get_display_hostname(); 150 my $manifest_product_name_uc = ucfirst($product_name); 151 my $manifest_product_name_uc_with_hostname = 152 $manifest_product_name_uc . ($display_hostname ? " on " . $display_hostname : ""); 153 my %manifest_prod_descs = ('webmin' => 'Powerful and flexible web-based server management control panel', 154 'usermin' => 'Powerful and flexible web-based user management interface', 155 'virtualmin' => 'Powerful and flexible web hosting control panel', 156 'cloudmin' => 'Powerful and flexible cloud computing platform'); 157 my $manifest_desc = $manifest_prod_descs{$product_name}; 158 my $manifest_file = "$root_directory/$current_theme/manifest.template"; 159 my $manifest_contents = read_file_contents($manifest_file); 160 $manifest_contents =~ s/\%name\%/$manifest_product_name_uc_with_hostname/; 161 $manifest_contents =~ s/\%name_short\%/$manifest_product_name_uc/; 162 $manifest_contents =~ s/\%desc\%/$manifest_desc/; 163 $manifest_contents =~ s/\%prod\%/$product_name/g; 164 $manifest_contents =~ s/\%color\%/$theme_user_color/; 165 write_file_contents("$theme_config_dir/manifest-$product_name.json", $manifest_contents) if (-w $theme_config_dir); 166 167 print ' <script src="' . $theme_webprefix . '/service-worker.js" defer></script>' . "\n"; 168 print ' <link ' . $ref_link . ' crossorigin="use-credentials" rel="manifest" href="' . 169 $theme_webprefix . '/manifest-' . $product_name . '.json">' . "\n"; 170 } 171} 172 173sub embed_header 174{ 175 my (@args) = @_; 176 my $charset = defined($main::force_charset) ? $main::force_charset : get_charset(); 177 178 print "<!DOCTYPE html>\n"; 179 print '<html ' . header_html_data(undef, undef, @args) . '>', "\n"; 180 print '<head>', "\n"; 181 embed_noscript(); 182 print ' <meta charset="utf-8">', "\n"; 183 embed_favicon() if (!http_x_request()); 184 print ' <title>', 185 ( $args[4] ? 186 (get_product_name() eq 'usermin' ? $theme_text{'theme_xhred_titles_um'} : $theme_text{'theme_xhred_titles_wm'}) : 187 $args[0] 188 ), 189 '</title>', "\n"; 190 191 print ' <meta name="viewport" content="width=device-width, initial-scale=1.0">' . "\n" if (!http_x_request()); 192 193 ($args[1] && (print($args[1] . "\n"))); 194 195 if (http_x_request()) { 196 print "</head>\n"; 197 return; 198 } 199 200 # Print default options 201 print " <script src=\"$theme_webprefix/unauthenticated/js/defaults.js?" . theme_version(1) . "\"></script>\n"; 202 print ' <script>'; 203 print 'config_portable_theme_locale_languages="' . get_current_user_language(1) . '";'; 204 print "</script>\n"; 205 206 # 207 # Server statuses to JavaScript. Start. 208 # This code is only called once upon main page load 209 # and requires full page reload to have it re-applied 210 my $_sstj = sub { 211 my ($var, $sub, $mod, $jsFunc, $perlSubArgs) = @_; 212 my $quote_opening = '"'; 213 my $quote_closing = $quote_opening; 214 my $quotes_resetting = sub { 215 $quote_opening = $quote_closing = ''; 216 }; 217 if ($jsFunc) { 218 &$quotes_resetting(); 219 } 220 my $rs; 221 local $main::error_must_die = 1; 222 eval { 223 if ($mod && &foreign_available($mod)) { 224 &foreign_require($mod); 225 $rs = &foreign_call($mod, $sub); 226 } elsif (!$mod) { 227 $rs = &foreign_call('main', $sub); 228 } 229 if ($jsFunc) { 230 $rs = "$jsFunc($rs)"; 231 } else { 232 if ($rs =~ /^[-+]?([\d]+|[\d]+.[\d]+)$/) { 233 &$quotes_resetting(); 234 } 235 if ($rs =~ /^(true|false|null|undefined)$/) { 236 &$quotes_resetting(); 237 } 238 } 239 }; 240 if (!defined($rs)) { 241 $rs = "null"; 242 &$quotes_resetting(); 243 } 244 if (!length(trim($rs)) && !$quote_opening) { 245 $rs = "null"; 246 } 247 return "$var=$quote_opening$rs$quote_closing;"; 248 }; 249 print ' <script>'; 250 print &$_sstj('theme_server_data_available_acls', 'get_acls_status', 'filemin'); 251 print &$_sstj('theme_server_data_available_selinux', 'is_selinux_enabled'); 252 print "</script>\n"; 253 254 # Server statuses to JavaScript. End. 255 # 256 257 embed_settings(); 258 embed_tconfig(); 259 260 # Print object with language strings 261 print ' <script>'; 262 print 'var v___theme_language = ' . get_theme_language(); 263 print "</script>\n"; 264 265 if ($args[2]) { 266 do("$ENV{'THEME_ROOT'}/dependencies.pl"); 267 } 268 269 if ($args[3] eq '1') { 270 271 if ($args[2]) { 272 foreach my $css (@theme_bundle_css) { 273 print ' <link href="' . $theme_webprefix . 274 '/unauthenticated/css/' . $css . '.src.css?' . theme_version(1) . '" rel="stylesheet">' . "\n"; 275 } 276 embed_css_fonts(); 277 } else { 278 embed_css_bundle(); 279 } 280 281 embed_css_night_rider(); 282 283 embed_background(); 284 embed_styles(); 285 286 if ($args[2]) { 287 foreach my $js (@theme_bundle_js) { 288 if (sysstats_available() && 289 $js eq 'timeplot') 290 { 291 next; 292 } 293 294 print ' <script src="' . 295 $theme_webprefix . '/unauthenticated/js/' . $js . '.src.js?' . theme_version(1) . '"></script>' . "\n"; 296 } 297 } else { 298 embed_js_bundle(); 299 } 300 } else { 301 if ($args[2]) { 302 foreach my $css (@theme_bundle_css) { 303 print ' <link href="' . $theme_webprefix . 304 '/unauthenticated/css/' . $css . '.src.css?' . theme_version(1) . '" rel="stylesheet">' . "\n"; 305 } 306 embed_css_fonts(); 307 } else { 308 embed_css_bundle(); 309 } 310 311 embed_css_night_rider(); 312 313 if ((length $theme_config{'settings_navigation_color'} && $theme_config{'settings_navigation_color'} ne 'blue') || 314 theme_night_mode()) 315 { 316 print ' <link href="' . $theme_webprefix . '/unauthenticated/css/palettes/' . 317 (theme_night_mode() ? 'gunmetal' : lc($theme_config{'settings_navigation_color'})) . '.' . 318 ($args[2] ? 'src' : 'min') . '.css?' . theme_version(1) . '" rel="stylesheet" data-palette>' . "\n"; 319 320 } 321 322 embed_background(); 323 embed_styles(); 324 325 if ($args[2]) { 326 foreach my $js (@theme_bundle_js) { 327 328 if (sysstats_available() && 329 $js eq 'timeplot') 330 { 331 next; 332 } 333 334 print ' <script src="' . 335 $theme_webprefix . '/unauthenticated/js/' . $js . '.src.js?' . theme_version(1) . '"></script>' . "\n"; 336 } 337 } else { 338 embed_js_bundle(); 339 } 340 341 } 342 embed_js_scripts(); 343 344 # Head theme overlay 345 embed_overlay_head(); 346 347 print '</head>', "\n"; 348} 349 350sub embed_overlay_head 351{ 352 print "$tconfig{'headhtml'}\n" if ($tconfig{'headhtml'}); 353 if ($tconfig{'headinclude'}) { 354 my ($theme, $overlay) = split(' ', $gconfig{'theme'}); 355 my $file_contents = read_file_contents("$root_directory/$overlay/$tconfig{'headinclude'}"); 356 $file_contents = replace_meta($file_contents); 357 print $file_contents; 358 } 359} 360 361sub embed_overlay_prebody 362{ 363 if (defined(&theme_prebody)) { 364 &theme_prebody(@_); 365 } 366 my $prebody = $tconfig{'prebody'}; 367 if ($prebody) { 368 $prebody = replace_meta($prebody); 369 print "$prebody\n"; 370 } 371 if ($tconfig{'prebodyinclude'}) { 372 my ($theme, $overlay) = split(' ', $gconfig{'theme'}); 373 my $file_contents = read_file_contents("$root_directory/$overlay/$tconfig{'prebodyinclude'}"); 374 $file_contents = replace_meta($file_contents); 375 print $file_contents; 376 } 377} 378 379sub embed_overlay_postbody 380{ 381 my $postbody = $tconfig{'postbody'}; 382 if ($postbody) { 383 $postbody = replace_meta($postbody); 384 print "$postbody\n"; 385 } 386 if ($tconfig{'postbodyinclude'}) { 387 my ($theme, $overlay) = split(' ', $gconfig{'theme'}); 388 my $file_contents = read_file_contents("$root_directory/$overlay/$tconfig{'postbodyinclude'}"); 389 $file_contents = replace_meta($file_contents); 390 print $file_contents; 391 } 392 if (defined(&theme_postbody)) { 393 &theme_postbody(@_); 394 } 395} 396 397sub embed_settings 398{ 399 400 my $admin_def_config_file = get_taconfig_file(); 401 my $global_config_file = get_tgconfig_file(); 402 my $user_config_file = get_tuconfig_file(); 403 404 # Embed admin defaults 405 if (-r $admin_def_config_file) { 406 $admin_def_config_file = read_file_contents($admin_def_config_file); 407 $admin_def_config_file =~ tr/\r\n/;/d; 408 $admin_def_config_file =~ s/\s*(.*?=)'([\d\.]+)'(;)\s*/$1$2$3/g; 409 print ' <script>' . $admin_def_config_file . '</script>' . "\n"; 410 } 411 412 # Embed global configuration 413 if (-r $global_config_file) { 414 $global_config_file = read_file_contents($global_config_file); 415 $global_config_file =~ tr/\r\n/;/d; 416 $global_config_file =~ s/\s*(.*?=)'([\d\.]+)'(;)\s*/$1$2$3/g; 417 print ' <script>' . $global_config_file . '</script>' . "\n"; 418 } 419 420 # Embed user configuration 421 if (-r $user_config_file) { 422 $user_config_file = read_file_contents($user_config_file); 423 $user_config_file =~ tr/\r\n/;/d; 424 $user_config_file =~ s/\s*(.*?=)'([\d\.]+)'(;)\s*/$1$2$3/g; 425 print ' <script>' . $user_config_file . '</script>' . "\n"; 426 } 427} 428 429sub embed_tconfig 430{ 431 print ' <script>tconfig_beta_updates=' . ($tconfig{'beta_updates'} ne '1' ? 0 : 1) . '</script>' . "\n"; 432} 433 434sub embed_styles 435{ 436 if ($theme_config{'settings_contrast_mode'} eq 'true') { 437 print ' <link href="' . 438 $theme_webprefix . '/unauthenticated/css/high-contrast.' . (theme_debug_mode() ? 'src' : 'min') . '.css?' . 439 time() . '" rel="stylesheet" data-high-contrast>' . "\n"; 440 } 441 442 my $css = $config_directory . "/$current_theme/styles.css"; 443 if (-r $css && -s $css) { 444 print ' <link data-custom-style href="data:text/css;base64,' . 445 trim(encode_base64(read_file_contents($css))) . '" rel="stylesheet">' . "\n"; 446 } 447 448} 449 450sub embed_background 451{ 452 if ($ENV{'HTTP_X_REQUESTED_WITH'} eq "XMLHttpRequest") { 453 return; 454 } 455 456 my $background_type; 457 458 ((get_env('script_name') eq '/session_login.cgi' || get_env('script_name') eq '/pam_login.cgi') ? 459 ($background_type = 'content') : 460 ($background_type = 'aside')); 461 462 my $lnk = $config_directory . "/$current_theme/background_" . $background_type . ".png"; 463 if (-r $lnk) { 464 my $background_base64 = encode_base64(read_file_contents($lnk)); 465 my $background_css; 466 if ($background_type eq 'content') { 467 $background_css = <<EOF; 468 <style> 469 body.session_login { 470 background: url(data:image/png;base64,$background_base64) no-repeat center center fixed; 471 background-size: cover; 472 } 473 474 html.session_login .container:not(.form-signin-banner) { 475 background-color: transparent !important; 476 } 477 </style> 478EOF 479 $background_css =~ tr/\r\n//d; 480 $background_css =~ s/\s+/ /g; 481 print $background_css, "\n"; 482 } 483 } 484} 485 486sub embed_pm_scripts 487{ 488 my $scripts = "$config_directory/$current_theme/scripts.pl"; 489 if (-r $scripts && -s $scripts) { 490 do($scripts); 491 } 492} 493 494sub embed_css_fonts 495{ 496 print ' <link href="' . $theme_webprefix . '/unauthenticated/css/fonts-roboto.' . 497 (theme_debug_mode() ? 'src' : 'min') . '.css?' . theme_version(1) . '" rel="stylesheet">' . "\n"; 498} 499 500sub embed_css_bundle 501{ 502 print ' <link href="' . 503 $theme_webprefix . '/unauthenticated/css/bundle.min.css?' . theme_version(1) . '" rel="stylesheet">' . "\n"; 504 embed_css_fonts(); 505} 506 507sub embed_css_night_rider 508{ 509 if (theme_night_mode_login() || theme_night_mode()) { 510 print ' <link href="' . $theme_webprefix . '/unauthenticated/css/palettes/nightrider.' . 511 (theme_debug_mode() ? 'src' : 'min') . '.css?' . theme_version(1) . '" rel="stylesheet" data-palette>' . "\n"; 512 } 513} 514 515sub embed_js_timeplot 516{ 517 print ' <script src="' . $theme_webprefix . '/unauthenticated/js/timeplot.' . 518 (theme_debug_mode() ? 'src' : 'min') . '.js?' . theme_version(1) . '"></script>' . "\n"; 519} 520 521sub embed_js_bundle 522{ 523 print ' <script src="' . 524 $theme_webprefix . '/unauthenticated/js/bundle.min.js?' . theme_version(1) . '"></script>' . "\n"; 525} 526 527sub embed_js_scripts 528{ 529 530 return if (http_x_request()); 531 532 my $js = $config_directory . "/$current_theme/scripts.js"; 533 if (-r $js && -s $js) { 534 $js = read_file_contents($js); 535 print ' <script data-custom-script>' . $js . '</script>' . "\n"; 536 } 537} 538 539sub embed_noscript 540{ 541 return if (http_x_request()); 542 my $noscript = <<EOF; 543 <noscript> 544 <style> 545 html[data-bgs="gainsboro"] 546 { 547 background-color: #d6d6d6; 548 } 549 html[data-bgs="nightRider"] 550 { 551 background-color: #1a1c20; 552 } 553 html[data-bgs="nightRider"] div[data-noscript] 554 { 555 color: #979ba080; 556 } 557 html[data-slider-fixed='1'] 558 { 559 margin-right: 0 !important; 560 } 561 body > div[data-noscript] ~ * 562 { 563 display: none !important; 564 } 565 div[data-noscript] 566 { 567 visibility: hidden; 568 569 animation: 2s noscript-fadein; 570 animation-delay: 1s; 571 text-align: center; 572 573 animation-fill-mode: forwards; 574 } 575 \@keyframes noscript-fadein 576 { 577 0% 578 { 579 opacity: 0; 580 } 581 100% 582 { 583 visibility: visible; 584 585 opacity: 1; 586 } 587 } 588 </style> 589 <div data-noscript> 590 <div class="fa fa-3x fa-exclamation-triangle margined-top-20 text-danger"></div> 591 <h2>$theme_text{'body_no_javascript_title'}</h2> 592 <p>$theme_text{'body_no_javascript_message'}</p> 593 </div> 594 </noscript> 595EOF 596 597 $noscript =~ tr/\r\n//d; 598 $noscript =~ s/\s+/ /g; 599 print $noscript, "\n"; 600} 601 602sub embed_port_shell 603{ 604 if (!@_ && 605 get_env('script_name') ne '/session_login.cgi' && 606 get_env('script_name') ne '/pam_login.cgi' && 607 get_env('script_name') ne '/401.cgi' && 608 get_env('script_name') ne '/403.cgi' && 609 get_env('script_name') ne '/404.cgi') 610 { 611 my $prefix; 612 my $hostname = ($prefix) = split(/\./, get_display_hostname()); 613 my $host = ($prefix ? $prefix : get_display_hostname()); 614 print '<div data-autocomplete="' . (has_command('bash') ? 1 : 0) . '" class="-shell-port-"> 615 <div class="-shell-port-container"> 616 <div data-shell-config><i aria-label="' . 617 $theme_text{'theme_xhred_global_configuration'} . '" class="fa fa-lg fa-cogs"></i></div> 618 <div aria-label="' . $theme_text{'theme_xhred_global_close'} . '" class="-shell-port-close"></div> 619 <div data-output="true"><pre data-xconsole></pre></div> 620 <div class="-shell-port-cmd"> 621 <span class="-shell-port-prompt"><span class="-shell-port-type">[' 622 . $remote_user . 623 '@<span data-shell-host="' . $host . '">' . $host . '</span> <span class="-shell-port-pwd" data-home="' . 624 get_user_home() . '" data-pwd="' . get_user_home() . '">~</span>]' . ($get_user_level eq '0' ? '#' : '$') . 625'</span></span><input type="text" data-command="true" autocomplete="off" autocorrect="off" autocapitalize="none" spellcheck="false"><span class="-shell-port-cursor"> </span> 626 </div> 627 </div> 628</div>', "\n"; 629 } 630} 631 632sub embed_footer 633{ 634 my (@args) = @_; 635 if (get_env('script_name') !~ /session_login.cgi/ && 636 get_env('script_name') !~ /pam_login.cgi/ && 637 get_env('script_name') !~ /password_form.cgi/ && 638 get_env('script_name') !~ /password_change.cgi/) 639 { 640 641 # Load `MySQL/PostgreSQL` specific scripts 642 if (get_module_name() =~ /mysql/ || 643 get_module_name() =~ /postgresql/) 644 { 645 print ' <script src="' . $theme_webprefix . '/extensions/sql.' . 646 ($args[0] ? 'src' : 'min') . '.js?' . theme_version(1) . '"></script>' . "\n"; 647 } 648 649 # Load `File Manager` specific scripts 650 if (get_module_name() =~ /file-manager/ || 651 get_module_name() =~ /filemin/) 652 { 653 print ' <script src="' . $theme_webprefix . '/extensions/file-manager/file-manager.' . 654 ($args[0] ? 'src' : 'min') . '.js?' . theme_version(1) . '"></script>' . "\n"; 655 } 656 657 } 658} 659 660sub sysstats_available 661{ 662 return ($http_x_url !~ /\/virtual-server\/pro\/history.cgi/ && 663 $http_x_url !~ /\/server-manager\/bwgraph.cgi/ && 664 $http_x_url !~ /\/server-manager\/history.cgi/ && 665 $http_x_url !~ /\/server-manager\/one_history.cgi/) ? 666 1 : 667 0; 668} 669 670sub theme_text 671{ 672 673 my $rv = $theme_text{ $_[0] }; 674 $rv =~ s/\$(\d+)/$1 < @_ ? $_[$1] : '$'.$1/ge; 675 return $rv; 676} 677 678sub init_vars 679{ 680 if (theme_debug_mode()) { 681 do("$root_directory/$current_theme/.debug.pl"); 682 } 683 684 our %theme_config = (settings(get_tdconfig_file()), 685 settings(get_taconfig_file()), 686 settings(get_tgconfig_file(), "settings_"), 687 settings(get_tuconfig_file(), "settings_")); 688 our $http_x_url = 689 (get_env('http_x_pjax_url') || get_env('http_x_progressive_url')); 690 691 # Load theme language 692 our %theme_text = (load_language($current_theme), %text); 693 694 # Load other modules language strings conditionally 695 if (!http_x_request() || 696 ($http_x_url =~ /sysinfo\.cgi/ || grep {/xhr-info/} keys %in)) 697 { 698 my @text_mods = ("virtual-server", "server-manager"); 699 foreach my $mod (@text_mods) { 700 if (foreign_available($mod)) { 701 %theme_text = (load_language($mod), %theme_text); 702 } 703 } 704 } 705 706 our ($get_user_level, $has_virtualmin, $has_cloudmin) = get_user_level(); 707 our ($has_usermin, $has_usermin_version, $has_usermin_root_dir, $has_usermin_conf_dir) = get_usermin_vars(); 708 709 # Set webprefix that should be used by the theme 710 $theme_webprefix = $gconfig{'webprefix'}; 711 my ($server_webprefix) = parse_remote_server_webprefix(); 712 if ($server_webprefix) { 713 $theme_webprefix = $server_webprefix; 714 $theme_server_webprefix = 1; 715 } 716 717 our $xnav = "xnavigation=1"; 718 719 our %gaccess = &get_module_acl(); 720 our $title = &get_html_framed_title(); 721 our %cookies = get_cookies(); 722 723 $server_x_goto = get_theme_temp_data('goto'); 724 725} 726 727sub check_pro_package 728{ 729 my ($id) = @_; 730 if (&foreign_available("virtual-server") && $id eq "vm") { 731 my %virtualmin = &get_module_info("virtual-server"); 732 if ($virtualmin{'version'} =~ /pro/is) { 733 return 1; 734 } elsif ($virtualmin{'version'} =~ /gpl/is) { 735 return 0; 736 } else { 737 return 1; 738 } 739 } elsif (&foreign_available("server-manager") && $id eq "cm") { 740 my %cloudmin = &get_module_info("server-manager"); 741 if ($cloudmin{'version'} =~ /pro/is || $cloudmin{'version'} =~ /real/is) { 742 return 1; 743 } elsif ($cloudmin{'version'} =~ /\..*?\./is) { 744 return 0; 745 } else { 746 return 1; 747 } 748 } else { 749 return 0; 750 } 751} 752 753sub get_usermin_vars 754{ 755 my ($has_usermin, $has_usermin_version, $has_usermin_root_dir, $has_usermin_conf_dir); 756 eval { 757 if (&foreign_exists("usermin")) { 758 &foreign_require("usermin"); 759 my %uminiserv; 760 &usermin::get_usermin_miniserv_config(\%uminiserv); 761 762 # Usermin config dir 763 $has_usermin_conf_dir = $uminiserv{'env_WEBMIN_CONFIG'}; 764 765 # Usermin root dir 766 $has_usermin_root_dir = $uminiserv{'root'}; 767 768 # Usermin version 769 $has_usermin_version = $uminiserv{'server'}; 770 $has_usermin_version =~ /\/([\d\.]+)/; 771 $has_usermin_version = "$1"; 772 if (length($has_usermin_version) > 6) { 773 $has_usermin_version = 774 substr($has_usermin_version, 0, 5) . "." . 775 substr($has_usermin_version, 5, 5 - 1) . "." . 776 substr($has_usermin_version, 5 * 2 - 1); 777 } 778 779 # Usermin installed 780 $has_usermin = -r $has_usermin_root_dir; 781 782 # Usermin Authentic Theme config dir exists 783 my $theme_conf_usermin = "$has_usermin_conf_dir/$current_theme"; 784 if ($has_usermin && 785 $has_usermin_conf_dir && 786 !-d $theme_conf_usermin) 787 { 788 mkdir($theme_conf_usermin, 0755); 789 } 790 } 791 }; 792 return ($has_usermin, $has_usermin_version, $has_usermin_root_dir, $has_usermin_conf_dir); 793} 794 795sub get_current_user_language 796{ 797 my ($full) = @_; 798 my $language; 799 my @languages; 800 my $language_browser = $gconfig{'acceptlang'}; 801 802 if ($language_browser) { 803 $language = $ENV{'HTTP_ACCEPT_LANGUAGE'}; 804 $language =~ s/;.*//; 805 @languages = split /,/, $language; 806 $language = $languages[0]; 807 } 808 809 if (($language_browser && !$language) || !$language_browser) { 810 $language = $gconfig{ 'lang' . '_' . $remote_user }; 811 $language = ($language ? $language : $gconfig{'lang'}); 812 } 813 814 $language = substr($language, 0, ($full ? 5 : 2)); 815 $language =~ s/\..*//; 816 $language =~ s/_/-/; 817 return lc($language); 818} 819 820sub get_filters 821{ 822 return 'filter: grayscale(' . $theme_config{'settings_grayscale_level_navigation'} . 823 ') ' . 'sepia(' . $theme_config{'settings_sepia_level_navigation'} . 824 ')' . ' saturate(' . $theme_config{'settings_saturation_level_navigation'} . 825 ') hue-rotate(' . $theme_config{'settings_hue_level_navigation'} . 826 'deg)' . ' invert(' . $theme_config{'settings_invert_level_navigation'} . 827 ') brightness(' . $theme_config{'settings_brightness_level_navigation'} . 828 ') contrast(' . $theme_config{'settings_contrast_level_navigation'} . ')' . ';'; 829} 830 831sub get_user_level 832{ 833 my ($level, $has_virtualmin, $has_cloudmin); 834 $has_cloudmin = &foreign_available("server-manager"); 835 $has_virtualmin = &foreign_available("virtual-server"); 836 if ($has_cloudmin) { 837 &foreign_require("server-manager", "server-manager-lib.pl"); 838 } 839 if ($has_virtualmin) { 840 &foreign_require("virtual-server", "virtual-server-lib.pl"); 841 } 842 if ($has_cloudmin) { 843 no warnings 'once'; 844 $level = $server_manager::access{'owner'} ? 4 : 0; 845 } elsif ($has_virtualmin) { 846 $level = 847 &virtual_server::master_admin() ? 0 : 848 &virtual_server::reseller_admin() ? 1 : 849 2; 850 } elsif (&get_product_name() eq "usermin") { 851 $level = 3; 852 } else { 853 $level = 0; 854 } 855 return ($level, $has_virtualmin, $has_cloudmin); 856} 857 858sub get_user_icon 859{ 860 my $user_icon = 'fa2-user-cog'; 861 if ($get_user_level eq '1') { 862 $user_icon = 'fa2-user-plus'; 863 } elsif ($get_user_level eq '2') { 864 $user_icon = 'fa2-user-check'; 865 } elsif ($get_user_level eq '3') { 866 $user_icon = 'fa2-user'; 867 } elsif ($get_user_level eq '4') { 868 $user_icon = 'fa2-user-friends'; 869 } 870 return $user_icon; 871} 872 873sub set_user_level 874{ 875 if ($get_user_level ne '0' && $get_user_level ne '1') { 876 switch_to_remote_user(); 877 } 878} 879 880sub get_initial_wizard 881{ 882 # Prevent running Virtualmin post installation wizard 883 my $mod_vm = 'virtual-server'; 884 if ($get_user_level eq '0' && foreign_exists($mod_vm)) { 885 my %virtualmin_config = foreign_config($mod_vm); 886 return $virtualmin_config{'wizard_run'}; 887 } 888 return 1; 889} 890 891sub get_button_style 892{ 893 894 my $label = quote_escape(@_); 895 896 my %module_text = module_text_full(); 897 my (@keys) = grep {$module_text{$_} eq $label} keys %module_text; 898 899 my $keys = "@keys"; 900 my $icon; 901 my $class = "default"; 902 903 if (string_contains($keys, 'mail_fchange')) { 904 $class = "default"; 905 } elsif (string_contains($keys, 'sform_ok')) { 906 $icon = "search"; 907 $class = "info"; 908 } elsif (string_contains($keys, 'edit_createnow') || string_contains($keys, 'edit_savenow')) { 909 $icon = "backup fa-1_25x"; 910 } elsif (string_contains($keys, "pass_ok")) { 911 $icon = " fa2 fa2-key"; 912 $class = "warning "; 913 } elsif (string_contains($keys, "newips")) { 914 $icon = "pencil-square-o"; 915 } elsif (string_contains($keys, "docker_reg")) { 916 $class = "success "; 917 $icon = "server-add"; 918 } elsif (string_contains($keys, "save") || 919 string_contains($keys, "backup_ok2") || 920 string_contains($keys, "sharedips_ok") || 921 string_contains($keys, "categories_ok") || 922 string_contains($keys, "frame_ok") || 923 string_contains($keys, "newquotas_ok") || 924 string_contains($keys, "newdynip_ok")) 925 { 926 $class = "success "; 927 $icon = "check-circle"; 928 } elsif (string_contains($keys, "form_ok")) { 929 $class = "success "; 930 $icon = "check-circle"; 931 } elsif (string_contains($keys, "apply")) { 932 $class = "info "; 933 $icon = "check-circle-o"; 934 } elsif (string_contains($keys, "migrate_show") || string_contains($keys, "import_show")) { 935 $class = "success "; 936 $icon = " fa2 fa2-import"; 937 } elsif (string_contains($keys, "update") || 938 string_contains($keys, "index_sync")) 939 { 940 $class = "info "; 941 $icon = "refresh"; 942 } elsif ((string_contains($keys, "delete") && !string_contains($keys, "users_delete")) || 943 string_contains($keys, "wipe") || 944 string_contains($keys, "ddrop_ok") || 945 string_contains($keys, "dbs_dok") || 946 string_contains($keys, "tprivs_dok") || 947 string_contains($keys, "hosts_dok") || 948 string_contains($keys, "cprivs_dok") || 949 string_contains($keys, "dbase_drop") || 950 string_contains($keys, "ddrop_title") || 951 string_contains($keys, "dbase_delete2") || 952 string_contains($keys, "table_drop") || 953 string_contains($keys, "tdrop_title") || 954 string_contains($keys, "tdrop_ok") || 955 string_contains($keys, "index_drops") || 956 string_contains($keys, "delq_confirm") || 957 string_contains($keys, "umass_del2") || 958 string_contains($keys, "index_gmass") || 959 string_contains($keys, "master_del") || 960 string_contains($keys, "newstyles_del") || 961 string_contains($keys, "html_dtitle")) 962 { 963 $class = "danger "; 964 965 $icon = "times-circle"; 966 } elsif (string_contains($keys, "disable_ok")) { 967 $class = "warning "; 968 $icon = "lock"; 969 } elsif (string_contains($keys, "enable_ok")) { 970 $class = "success "; 971 $icon = "unlock"; 972 } elsif (string_contains($keys, "twofactor_enable")) { 973 $class = "info "; 974 $icon = "lock"; 975 } elsif (string_contains($keys, "twofactor_disable")) { 976 $class = "warning "; 977 $icon = "unlock"; 978 } elsif (string_contains($keys, "zonekey")) { 979 if ($keys eq "zonekey_disable") { 980 $class = "danger "; 981 $icon = " fa2 fa2-key-minus fa-1_15x"; 982 } else { 983 $icon = " fa2 fa2-key"; 984 } 985 } elsif ( 986 (string_contains($keys, "install") || 987 string_contains($keys, "recsok") || 988 string_contains($keys, "scripts_iok") || 989 string_contains($keys, "missing_now") || 990 string_contains($keys, "right_upok") 991 ) && 992 !string_contains($keys, "uninstall")) 993 { 994 $class = "success "; 995 $icon = "package-install fa-1_25x"; 996 } elsif (string_contains($keys, "uninstall") || 997 string_contains($keys, "edit_uninst") || 998 string_contains($keys, "scripts_uok") || 999 string_contains($keys, "drecs_ok")) 1000 { 1001 $class = "danger "; 1002 $icon = "times-circle-o"; 1003 } elsif (string_contains($keys, "cert_remove")) { 1004 $class = "warning "; 1005 $icon = " fa2 fa2-certificate-delete"; 1006 } elsif (string_contains($keys, "cert_copyall2")) { 1007 $class = "info "; 1008 $icon = " fa2 fa2-certificate-global"; 1009 } elsif (string_contains($keys, "cert_copyall")) { 1010 $class = "info "; 1011 $icon = " fa2 fa2-certificate-add"; 1012 } elsif (string_contains($keys, "upgrade") || 1013 string_contains($keys, "massg_ok") || 1014 string_contains($keys, "massscript_ok")) 1015 { 1016 $class = "info "; 1017 $icon = "update"; 1018 } elsif (string_contains($keys, "index_srefresh")) { 1019 $icon = "user-md"; 1020 } elsif (string_contains($keys, "quota")) { 1021 $icon = "pie-chart"; 1022 } elsif (string_contains($keys, "addboot") || 1023 string_contains($keys, "enable") || 1024 string_contains($keys, "massdomains_enaok")) 1025 { 1026 $icon = "toggle-switch fa-1_25x"; 1027 } elsif (string_contains($keys, "shutdown")) { 1028 $icon = "power-off"; 1029 } elsif (string_contains($keys, "index_shut")) { 1030 $icon = "power-off"; 1031 $class = "danger "; 1032 } elsif (string_contains($keys, "index_reboot reboot_title")) { 1033 $icon = "refresh-mdi fa-1_25x"; 1034 $class = "warning "; 1035 } elsif (string_contains($keys, "docker_reg")) { 1036 $icon = "check-circle-o"; 1037 } elsif (string_contains($keys, "tmpl_nprev") || string_contains($keys, "wizard_prev")) { 1038 $icon = "arrow-circle-o-left"; 1039 } elsif (string_contains($keys, "tmpl_nnext") || 1040 string_contains($keys, "wizard_next") || 1041 string_contains($keys, "tmpl_cnext") || 1042 string_contains($keys, "tmpl_snext") || 1043 string_contains($keys, "continue") || 1044 string_contains($keys, "download_cont")) 1045 { 1046 $icon = "arrow-circle-o-right"; 1047 if (string_contains($keys, "continue")) { 1048 $class = "success "; 1049 } 1050 } elsif (string_contains($keys, "cancel")) { 1051 $icon = "times-circle-o"; 1052 } elsif (string_contains($keys, "ticket_submit")) { 1053 $icon = "question-circle"; 1054 } elsif (string_contains($keys, "trace_change")) { 1055 $icon = " fa2 fa2-toggle-off fa-0_90x"; 1056 $class = "warning "; 1057 } elsif (string_contains($keys, "passwd_change")) { 1058 $icon = "key-li"; 1059 $class = "warning "; 1060 } elsif (string_contains($keys, "nf_seen")) { 1061 $icon = "clear-all fa-1_25x"; 1062 } elsif (string_contains($keys, "history_ok")) { 1063 $icon = "area-chart"; 1064 } elsif (string_contains($keys, "edit_open") || string_contains($keys, "edit_list")) { 1065 $icon = "files-o"; 1066 } elsif (string_contains($keys, "reboot") || 1067 string_contains($keys, "view_refresh") || 1068 string_contains($keys, "refreshmods") || 1069 string_contains($keys, "index_buttinit")) 1070 { 1071 if (string_contains($keys, "refreshmods")) { 1072 $class = "primary "; 1073 } elsif (!string_contains($keys, "reboot_ok") && !string_contains($keys, "index_reboot") || 1074 string_contains($keys, "index_buttinit")) 1075 { 1076 $class = "warning "; 1077 } 1078 1079 if (string_contains($keys, "view_refresh")) { 1080 $icon = "refresh-fi fa-1_25x"; 1081 } else { 1082 $icon = "refresh-mdi fa-1_25x"; 1083 } 1084 } elsif (string_contains($keys, "search") || 1085 string_contains($keys, "index_broad") || 1086 string_contains($keys, "scripts_findok") || 1087 string_contains($keys, "kill_title")) 1088 { 1089 $class = "info "; 1090 $icon = "search"; 1091 } elsif (string_contains($keys, "dmass_move") || string_contains($keys, "domains_move")) { 1092 $class = "warning "; 1093 $icon = " fa2 fa2-transfer"; 1094 } elsif (string_contains($keys, "restart") || string_contains($keys, "edit_kill")) { 1095 $class = "warning "; 1096 $icon = "refresh"; 1097 } elsif (string_contains($keys, "ddrop_empty")) { 1098 $class = "warning "; 1099 $icon = "times-circle-o"; 1100 } elsif (string_contains($keys, "start") || string_contains($keys, "index_run")) { 1101 $class = "success "; 1102 $icon = "play"; 1103 } elsif (string_contains($keys, "index_stop") || 1104 string_contains($keys, "edit_stopnow")) 1105 { 1106 $class = "danger "; 1107 $icon = "stop"; 1108 } elsif (string_contains($keys, "ok_ok")) { 1109 $icon = "check-square-o"; 1110 $class = "success "; 1111 } elsif (string_contains($keys, "index_delboot")) { 1112 $class = "grey "; 1113 $icon = "toggle-switch-off fa-1_25x"; 1114 } elsif (string_contains($keys, "index_refsel") || 1115 string_contains($keys, "index_reset") || 1116 string_contains($keys, "index_regen") || 1117 string_contains($keys, "index_reload")) 1118 { 1119 $class = "warning "; 1120 $icon = "refresh"; 1121 } elsif (string_contains($keys, "scripts_ustop")) { 1122 $icon = "stop"; 1123 } elsif (string_contains($keys, "index_script")) { 1124 $icon = "update"; 1125 } elsif (string_contains($keys, "cron_ok")) { 1126 $icon = "check-circle-o"; 1127 $class = "success "; 1128 } elsif (string_contains($keys, "status")) { 1129 $icon = "info-circle"; 1130 } elsif (string_contains($keys, "warnok")) { 1131 $icon = "check-circle-o"; 1132 $class = "warning "; 1133 } elsif (string_contains($keys, "index_clear") || string_contains($keys, "shell_clear")) { 1134 $icon = "history"; 1135 } elsif (string_contains($keys, "index_clearcmds") || string_contains($keys, "shell_clearcmds")) { 1136 $icon = "broom fa-1_25x"; 1137 } elsif (string_contains($keys, "index_boot") || 1138 string_contains($keys, "index_bootup") || 1139 string_contains($keys, "index_atboot") || 1140 string_contains($keys, "massdomains_disok") || 1141 string_contains($keys, "disable")) 1142 { 1143 $icon = "toggle-switch-off fa-1_25x"; 1144 } elsif (string_contains($keys, "index_global") || 1145 string_contains($keys, "umass_ok") || 1146 string_contains($keys, "vars_edit") || 1147 string_contains($keys, "lusers_mass") || 1148 string_contains($keys, "root_ok") || 1149 string_contains($keys, "index_edit")) 1150 { 1151 $class = "primary "; 1152 $icon = "pencil-square-o"; 1153 } elsif (string_contains($keys, "clone")) { 1154 $icon = "clone"; 1155 } elsif (string_contains($keys, "index_tmpls")) { 1156 $icon = "table-edit fa-1_25x"; 1157 } elsif (string_contains($keys, "index_sched") || 1158 string_contains($keys, "sched_title")) 1159 { 1160 if (string_contains($keys, "sched_title")) { 1161 $class = "primary "; 1162 } 1163 $icon = "clock"; 1164 } elsif (string_contains($keys, "uedit_mail") || string_contains($keys, "newnotify_ok")) { 1165 $icon = "envelope-o"; 1166 } elsif (string_contains($keys, "reply_send")) { 1167 $icon = "send"; 1168 $class = "success "; 1169 } elsif (string_contains($keys, "sendmail")) { 1170 $icon = "envelope-o"; 1171 $class = "info "; 1172 } elsif (string_contains($keys, "uedit_swit") || string_contains($keys, "user_switch")) { 1173 $icon = "webmin"; 1174 } elsif (string_contains($keys, "uedit_logins") || 1175 string_contains($keys, "index_logins") || 1176 string_contains($keys, "login_enable")) 1177 { 1178 $icon = "key"; 1179 } elsif (string_contains($keys, "index_who")) { 1180 $icon = "sign-in"; 1181 } elsif (string_contains($keys, "dbase_add") || string_contains($keys, "databases_import")) { 1182 $class = "success "; 1183 $icon = "database-plus fa-1_25x"; 1184 } elsif ( 1185 (string_contains($keys, "add") && !string_contains($keys, "dbase_addview") && !string_contains($keys, "edit_addinc")) 1186 || 1187 (string_contains($keys, "create") && 1188 !string_contains($keys, "user_priv_create_view")) || 1189 string_contains($keys, "index_crnow") || 1190 string_contains($keys, "view_new") || 1191 string_contains($keys, "mass_ok") || 1192 string_contains($keys, "rmass_ok")) 1193 { 1194 $class = "success "; 1195 $icon = "plus-circle"; 1196 } elsif (string_contains($keys, "force_title") || 1197 string_contains($keys, "index_force")) 1198 { 1199 $class = "warning "; 1200 $icon = "rotate-3d fa-1_25x margined-left--3 margined-right--3"; 1201 } elsif (string_contains($keys, "csv")) { 1202 $icon = "export"; 1203 } elsif (string_contains($keys, "restore")) { 1204 $icon = "restore fa-1_25x"; 1205 } elsif (string_contains($keys, "backup_title") || 1206 string_contains($keys, "dbase_backup") || 1207 string_contains($keys, "index_dump") || 1208 string_contains($keys, "backup_ok") || 1209 string_contains($keys, "export") || 1210 string_contains($keys, "backup_now")) 1211 { 1212 $icon = "backup fa-1_25x"; 1213 } elsif (string_contains($keys, "dbase_exec") || 1214 string_contains($keys, "exec_exec") || 1215 string_contains($keys, "user_priv_execute") || 1216 string_contains($keys, "exec_title") || 1217 string_contains($keys, "exec_tabexec")) 1218 { 1219 $icon = "database"; 1220 } elsif (string_contains($keys, "create_view") || 1221 string_contains($keys, "addview") || 1222 string_contains($keys, "view_title1")) 1223 { 1224 $icon = "list"; 1225 } elsif (string_contains($keys, "table_data")) { 1226 $icon = "database-outline"; 1227 } elsif (string_contains($keys, "index_title1") || string_contains($keys, "table_index")) { 1228 $icon = "key-plus fa-1_25x"; 1229 } elsif (string_contains($keys, "transfer_transferok")) { 1230 $icon = "transform fa-1_25x"; 1231 } elsif (string_contains($keys, "transfer_uploadok") || 1232 string_contains($keys, "transfer_tabupload") || 1233 string_contains($keys, "html_uploadok")) 1234 { 1235 $class = "primary "; 1236 $icon = "upload"; 1237 } elsif (string_contains($keys, "index_down") || 1238 string_contains($keys, "transfer_downloadok") || 1239 string_contains($keys, "index_up") || 1240 string_contains($keys, "download_need")) 1241 { 1242 $class = "primary "; 1243 $icon = "download"; 1244 } elsif (string_contains($keys, "images_get")) { 1245 $class = "success "; 1246 $icon = "download"; 1247 } elsif (string_contains($keys, "umass_del1") || 1248 string_contains($keys, "gdel_del") || 1249 string_contains($keys, "gdel_title") || 1250 string_contains($keys, "drecs_title") || 1251 string_contains($keys, "rdmass_ok")) 1252 { 1253 $icon = "times-circle-o"; 1254 } elsif (string_contains($keys, "users_dok") || 1255 string_contains($keys, "users_delete") || 1256 string_contains($keys, "users_dconfirm")) 1257 { 1258 $class = "danger "; 1259 $icon = "user-times"; 1260 } elsif (string_contains($keys, "index_mass2")) { 1261 $class = "warning "; 1262 $icon = "toggle-switch fa-1_25x"; 1263 } elsif (string_contains($keys, "index_mass3")) { 1264 $class = "success "; 1265 $icon = "toggle-switch-off fa-1_25x"; 1266 } elsif (string_contains($keys, "lang")) { 1267 $icon = "globe"; 1268 $class = "warning "; 1269 } elsif (string_contains($keys, "_ok")) { 1270 $icon = "check-circle-o"; 1271 $class = "success "; 1272 } elsif (string_contains($keys, "_change") && 1273 !string_contains($keys, "edit_change") && 1274 !string_contains($keys, "trace_change")) 1275 { 1276 $class = "warning "; 1277 $icon = "pencil-square-o"; 1278 } elsif (string_contains($keys, "lkeys_sok2") || 1279 string_contains($keys, "mail_login")) 1280 { 1281 $class = "success "; 1282 $icon = "key"; 1283 } elsif (string_contains($keys, "letsencrypt_title") || 1284 string_contains($keys, "ssl_copycert")) 1285 { 1286 $class = "success "; 1287 $icon = " fa2 fa2-certificate-request"; 1288 } elsif (string_contains($keys, "cert_letsonly")) { 1289 $icon = " fa2 fa2-certificate-update-time"; 1290 $class = "info "; 1291 } elsif (string_contains($keys, "index_tree")) { 1292 $icon = "tree"; 1293 } 1294 1295 if ($icon) { 1296 $icon = "<i class=\"fa fa-fw fa-$icon\"></i>"; 1297 } 1298 1299 return ($keys, $class, $icon); 1300} 1301 1302sub theme_night_mode 1303{ 1304 if ($theme_config{'settings_force_night_mode'} eq '1') { 1305 return 1; 1306 } else { 1307 return 0; 1308 } 1309} 1310 1311sub theme_night_mode_login 1312{ 1313 if ($theme_config{'settings_global_palette_unauthenticated'} eq 'dark') { 1314 return 1; 1315 } else { 1316 return 0; 1317 } 1318} 1319 1320sub theme_version 1321{ 1322 my ($string, $minor) = @_; 1323 my %tinfo = get_theme_info($current_theme); 1324 my $version = $tinfo{'version'}; 1325 my $mversion = $tinfo{'mversion'}; 1326 my $is_alpha = string_contains($version, 'alpha'); 1327 my $is_beta = string_contains($version, 'beta'); 1328 my $is_rc = string_contains($version, 'RC'); 1329 my $is_devel_ver = $is_alpha || $is_beta || $is_rc; 1330 1331 # Return minor version only 1332 if ($minor) { 1333 1334 # Format minor version suffix 1335 if ($string) { 1336 $mversion = int($mversion); 1337 if ($mversion > 1) { 1338 $mversion = "-$mversion"; 1339 } else { 1340 $mversion = undef; 1341 } 1342 } 1343 return $mversion; 1344 } 1345 1346 # Return theme version as timestamp 1347 if ($string) { 1348 $version =~ s/(alpha|beta|RC)\d*|\.|-//ig; 1349 if (theme_debug_mode() || $is_devel_ver) { 1350 $version .= ("9" . time() . "$mversion"); 1351 } else { 1352 $version .= ('99999999999' . $mversion); 1353 } 1354 } 1355 return $version; 1356} 1357 1358sub theme_debug_mode 1359{ 1360 if (-r "$ENV{'THEME_ROOT'}/dependencies.pl") { 1361 return 1; 1362 } else { 1363 return 0; 1364 } 1365} 1366 1367sub theme_post_update 1368{ 1369 my $update = $root_directory . "/$current_theme/update"; 1370 1371 if (-f $update && $get_user_level eq '0') { 1372 unlink $update; 1373 return '1'; 1374 } else { 1375 return '0'; 1376 } 1377} 1378 1379sub header_html_data 1380{ 1381 my ($module, $skip, @args) = @_; 1382 return 'data-redirect="' . get_theme_temp_data('redirected') . 1383 '" data-host="' . get_env('http_host') . '" data-hostname="' . get_display_hostname() . '" data-title-initial="' . 1384 format_document_title($args[0]) . '" data-debug="' . theme_debug_mode() . '" data-session="' . 1385 ($remote_user ? '1' : '0') . '" data-script-name="' . ($module ? "/$module/" : get_env('script_name')) . 1386 '"' . ($skip ? '' : ' data-bgs="' . (theme_night_mode() ? 'nightRider' : 'gainsboro') . '"') . 1387 '' . ($skip ? '' : ' data-night-mode="' . theme_night_mode() . '"') . 1388 ' data-high-contrast="' . ($theme_config{'settings_contrast_mode'} eq 'true' ? '1' : '0') . 1389 '" data-navigation-collapsed="' . ($theme_config{'settings_navigation_always_collapse'} eq 'true' ? '1' : '0') . 1390 '" data-slider-fixed="' . ($theme_config{'settings_side_slider_fixed'} eq "true" && 1391 $get_user_level eq '0' && 1392 $theme_config{'settings_side_slider_enabled'} ne "false" ? '1' : '0') . 1393 '" data-shell="' . 1394 foreign_available("shell") . '" data-webmin="' . foreign_available("webmin") . '" data-usermin="' . $has_usermin . 1395 '" data-navigation="' . ($args[3] eq '1' ? '0' : '1') . '" data-status="' . foreign_available("system-status") . 1396 '" data-package-updates="' . foreign_available("package-updates") . '" data-csf="' . foreign_available("csf") . '"' . 1397 ($skip ? '' : ' data-theme="' . (theme_night_mode() ? 'gunmetal' : $theme_config{'settings_navigation_color'}) . '"') 1398 . '' . ($skip ? '' : ' data-default-theme="' . $theme_config{'settings_navigation_color'} . '"') . 1399 ' data-editor-palette="' . $theme_config{'settings_cm_editor_palette'} . 1400 '" data-theme-version="' . theme_version(0) . '" data-theme-mversion="' . theme_version(0, 1) . 1401 '" data-level="' . $get_user_level . '" data-user-home="' . get_user_home() . '" data-user-id="' . get_user_id() . 1402 '" data-user="' . $remote_user . '" data-ltr="' . get_text_ltr() . '" data-language="' . get_current_user_language() . 1403 '" data-language-full="' . get_current_user_language(1) . '" data-charset="' . get_charset() . '" data-notice="' . 1404 theme_post_update() . '" data-initial-wizard="' . get_initial_wizard() . '" data-webprefix="' . $theme_webprefix . 1405 '" data-current-product="' . get_product_name() . '" data-module="' . ($module ? "$module" : get_module_name()) . 1406 '" data-uri="' . ($module ? "/$module/" : html_escape(un_urlize(get_env('request_uri'), 1))) . 1407 '" data-progress="' . ($theme_config{'settings_hide_top_loader'} ne 'true' ? '1' : '0') . '" data-product="' . 1408 get_product_name() . '" data-access-level="' . $get_user_level . '" data-time-offset="' . get_time_offset() . '"'; 1409} 1410 1411sub header_body_data 1412{ 1413 my ($module) = @_; 1414 return 'data-uri="' . ($module ? "/$module/" : html_escape(get_env('request_uri'))) . '"' 1415 . 1416 ( (get_module_name() || $module) ? 1417 ' class="' . 1418 ($module ? $module : get_module_name()) . '" data-module="' . ($module ? $module : get_module_name()) . '"' : 1419 undef 1420 ) . 1421 '' . 1422 (get_env('request_uri') =~ /\/config.cgi\?/ ? ' id="configCGI"' : '') . ''; 1423} 1424 1425sub get_version 1426{ 1427 my ($version) = @_; 1428 return $version =~ /([0-9]+[.][0-9]+)/; 1429} 1430 1431sub get_version_range 1432{ 1433 my ($start, $end, $step) = @_; 1434 $step ||= 1; 1435 return map {sprintf("%.2f", $_ * $step)} (sprintf("%.2f", $start / $step) .. sprintf("%.2f", $end / $step)); 1436 1437} 1438 1439sub get_version_link 1440{ 1441 my ($version, $type) = @_; 1442 1443 if ($version =~ /\.\.\./) { 1444 ($version) = $version =~ /([0-9]+[.][0-9]+\.\.\.[0-9]+[.][0-9]+)/; 1445 my $links_start = '<div class="pull-right versionSeparatorContainer">'; 1446 my $links_end = '</div>'; 1447 my @versions = split(/\.\.\./, $version); 1448 1449 if ($type eq '1' || $type eq '2') { 1450 return "$links_start <span class=\"versionSeparator\">$version</span> $links_end"; 1451 } 1452 1453 @versions = get_version_range($versions[0], $versions[1], 0.01); 1454 foreach my $version (@versions) { 1455 $links_start .= get_version_link($version) . " "; 1456 } 1457 $links_start .= $links_end; 1458 return $links_start; 1459 } 1460 1461 if ($type eq '2') { 1462 return "<span class=\"versionSeparator\">" . get_version_full($version, 1) . "</span>"; 1463 } else { 1464 return '<a href="https://github.com/authentic-theme/authentic-theme/releases/tag/' . 1465 get_version_full($version) . '" class="versionSeparator">' . get_version_full($version, 1) . '</a>'; 1466 } 1467 1468} 1469 1470sub get_version_full 1471{ 1472 my ($version, $beta) = @_; 1473 ($version) = $version =~ /([0-9]+[.][0-9]+(?:.\d+|-alpha[\d]+|-beta[\d]+|-RC[\d]+|))/; 1474 1475 if ($version =~ /alpha|beta|RC/ && $beta) { 1476 return undef; 1477 } 1478 1479 return $version; 1480} 1481 1482sub get_env 1483{ 1484 my ($key) = @_; 1485 return $ENV{ uc($key) }; 1486} 1487 1488sub set_theme_temp_data 1489{ 1490 my ($key, $value) = @_; 1491 my $salt = substr(encode_base64($main::session_id), 0, 16); 1492 my %var; 1493 1494 $salt =~ tr/A-Za-z0-9//cd; 1495 $key =~ tr/A-Za-z0-9//cd; 1496 1497 $value =~ s/[?|&]$xnav//g; 1498 $value =~ s/[?|&]randomized=[\d]+//g; 1499 $value =~ s/.cgi&/.cgi?/g; 1500 $value =~ s/[^\p{L}\p{N},;:.%&#=_@\+\?\-\/]//g; 1501 1502 $var{$key} = $value; 1503 1504 write_file(tempname('.theme_' . $salt . '_' . get_product_name() . '_' . $key . '_' . $remote_user), \%var); 1505} 1506 1507sub get_theme_temp_data 1508{ 1509 my ($key, $keep) = @_; 1510 my $salt = substr(encode_base64($main::session_id), 0, 16); 1511 my $data; 1512 my %theme_temp_data; 1513 1514 $salt =~ tr/A-Za-z0-9//cd; 1515 1516 my $tmp_file = tempname('.theme_' . $salt . '_' . get_product_name() . '_' . $key . '_' . $remote_user); 1517 1518 # Process multiple goto requests 1519 if ($key eq 'goto') { 1520 my (%theme_goto_temp); 1521 my $tmp_dir = tempname_dir(); 1522 my @gotos; 1523 opendir(my $dir, $tmp_dir); 1524 @gotos = grep {/^\.theme/ && $_ =~ /$salt/ && $_ =~ /goto/ && -f "$tmp_dir/$_"} readdir($dir); 1525 closedir $dir; 1526 foreach (@gotos) { 1527 $tmp_file = "$tmp_dir/$_"; 1528 if (-r $tmp_file) { 1529 my $tmp_file_mod = (stat($tmp_file))[9]; 1530 my $tmp_file_age = time() - $tmp_file_mod; 1531 if ($tmp_file_age >= 15) { 1532 unlink_file($tmp_file); 1533 next; 1534 } 1535 read_file($tmp_file, \%theme_temp_data); 1536 last; 1537 } 1538 } 1539 } else { 1540 read_file($tmp_file, \%theme_temp_data); 1541 } 1542 1543 if (!$keep && -r $tmp_file) { 1544 unlink_file($tmp_file); 1545 } 1546 1547 $data = $theme_temp_data{$key}; 1548 $data =~ s/[?|&]$xnav//g; 1549 $data =~ s/[?|&]randomized=[\d]+//g; 1550 $data =~ s/.cgi&/.cgi?/g; 1551 1552 return $data; 1553} 1554 1555sub get_user_home 1556{ 1557 if (!supports_users()) { 1558 return undef; 1559 } 1560 my @my_user_info = $remote_user ? getpwnam($remote_user) : getpwuid($<); 1561 return $my_user_info[7]; 1562} 1563 1564sub get_user_id 1565{ 1566 if (!supports_users()) { 1567 return undef; 1568 } 1569 my @my_user_info = $remote_user ? getpwnam($remote_user) : getpwuid($<); 1570 return $my_user_info[2]; 1571} 1572 1573sub get_fm_jailed_user 1574{ 1575 if (!supports_users()) { 1576 return undef; 1577 } 1578 my $jailed_user = 0; 1579 my %fmaccess = get_module_acl(undef, $_[0]); 1580 if ($get_user_level eq '0' && %fmaccess && $fmaccess{'work_as_user'} && $fmaccess{'work_as_user'} ne $remote_user) { 1581 my @user_info = getpwnam($fmaccess{'work_as_user'}); 1582 $jailed_user = $_[1] ? $user_info[0] : $user_info[7]; 1583 } 1584 return $jailed_user; 1585} 1586 1587sub get_tdconfig_file 1588{ 1589 return "$root_directory/$current_theme/unauthenticated/js/defaults.js"; 1590} 1591 1592sub get_taconfig_file 1593{ 1594 return "$config_directory/$current_theme/defaults.js"; 1595} 1596 1597sub get_tgconfig_file 1598{ 1599 return "$config_directory/$current_theme/settings.js"; 1600} 1601 1602sub get_tuconfig_file 1603{ 1604 my $oconfig = "$config_directory/$current_theme/settings-$remote_user"; 1605 return -r $oconfig ? $oconfig : "$oconfig.js"; 1606} 1607 1608sub http_x_request 1609{ 1610 if (get_env('http_x_requested_with') eq "XMLHttpRequest") { 1611 return 1; 1612 } else { 1613 return 0; 1614 } 1615} 1616 1617sub fetch_content 1618{ 1619 if (get_env('request_uri') =~ /fetch-content=1/ || 1620 get_module_name() eq "file") 1621 { 1622 return 1; 1623 } else { 1624 return 0; 1625 } 1626} 1627 1628sub get_link 1629{ 1630 my ($string, $type) = @_; 1631 my $url; 1632 1633 if ($type eq 'ugly') { 1634 $string =~ /<a.*href=([\s\S]+?)>/; 1635 $url = $1; 1636 } elsif ($type eq 'bad') { 1637 $string =~ /<a.*href='([\s\S]+?)'.*>/; 1638 $url = $1; 1639 } else { 1640 $string =~ /<a.*href="([\s\S]+?)".*>/; 1641 $url = $1; 1642 } 1643 $string =~ /<a.*href.*>([\s\S]+?)<\/a>/; 1644 1645 return [$url, $1]; 1646} 1647 1648sub get_button_tooltip 1649{ 1650 my ($label, $key, $placement, $html, $force, $container, $br_label_on) = @_; 1651 1652 my $mod_key = $theme_config{'settings_hotkey_toggle_modifier'}; 1653 my $hot_key = ($key ? ucfirst($theme_config{$key}) : undef); 1654 if (!$container) { 1655 $container = '#content'; 1656 } 1657 my $tooltip_text = ($theme_text{$label} ? $theme_text{$label} : ($text{$label} ? $text{$label} : $label)); 1658 if ($br_label_on) { 1659 my @tooltip_text = split(/\Q$br_label_on\E/, $tooltip_text, 2); 1660 $tooltip_text = join('<br>' . $br_label_on, @tooltip_text); 1661 } 1662 1663 return ( 1664 ' aria-label="' . strip_html($tooltip_text) . '" data-container="' . $container . '" data-placement="' . 1665 $placement . '" data-toggle="tooltip" data-html="' . ($html ? 'true' : 'false') . '" data-title="' 1666 . 1667 ($tooltip_text 1668 . 1669 (length $theme_config{'settings_hotkeys_active'} && 1670 $theme_config{'settings_hotkeys_active'} ne 'false' && 1671 $hot_key ? 1672 " (" . ($mod_key eq "altKey" ? "Alt" : $mod_key eq "ctrlKey" ? "Ctrl" : "Meta") . '+' . $hot_key . ")" : 1673 '') 1674 ) . 1675 '"'); 1676} 1677 1678sub error_40x_handler 1679{ 1680 my %miniserv; 1681 get_miniserv_config(\%miniserv); 1682 if ($_[0]) { 1683 if ($miniserv{'error_handler_403'}) { 1684 $miniserv{'error_handler_401'} = undef; 1685 $miniserv{'error_handler_403'} = undef; 1686 $miniserv{'error_handler_404'} = undef; 1687 put_miniserv_config(\%miniserv); 1688 reload_miniserv(); 1689 } 1690 } else { 1691 if (!$miniserv{'error_handler_403'}) { 1692 $miniserv{'error_handler_401'} = "401.cgi"; 1693 $miniserv{'error_handler_403'} = "403.cgi"; 1694 $miniserv{'error_handler_404'} = "404.cgi"; 1695 put_miniserv_config(\%miniserv); 1696 reload_miniserv(); 1697 } 1698 } 1699} 1700 1701sub lib_csf_control 1702{ 1703 my ($action) = @_; 1704 if (foreign_check("csf") && foreign_available("csf") && has_command("csf") && $current_theme =~ /authentic-theme/) { 1705 do("$root_directory/$current_theme/extensions/csf/csf-lib.pl"); 1706 if ($action eq 'load') { 1707 csf_mod(); 1708 } elsif ($action eq 'unload') { 1709 csf_clear(); 1710 } elsif ($action eq 'strings') { 1711 return csf_strings(); 1712 } 1713 } 1714} 1715 1716sub embed_product_branding 1717{ 1718 return if ($theme_config{"settings_embed_product_branding_privileged"} eq 'false'); 1719 return &custom_embed_product_branding(@_) 1720 if (defined(&custom_embed_product_branding)); 1721 1722 my ($brand, 1723 $brand_name, 1724 $brand_dir_default, 1725 $brand_dir_custom, 1726 $brand_dir, 1727 $loader, 1728 $request_uri, 1729 $vm_mod_name, 1730 $vm_available, 1731 $cm_mod_name, 1732 $cm_available); 1733 1734 # Set brand directory 1735 $brand_name; 1736 $brand_dir_default = "$root_directory/$current_theme/images/brand"; 1737 $brand_dir_custom = "$config_directory/$current_theme/brand"; 1738 $brand_dir = -r $brand_dir_custom ? $brand_dir_custom : $brand_dir_default; 1739 $loader = read_file_contents("$brand_dir/loader.html"); 1740 $request_uri = get_theme_temp_data('goto', 1); 1741 1742 # Virtualmin available 1743 $vm_mod_name = "virtual-server"; 1744 $vm_available = foreign_available($vm_mod_name); 1745 1746 # Cloudmin available and requested 1747 $cm_mod_name = "server-manager"; 1748 $cm_available = foreign_available($cm_mod_name); 1749 1750 # Define brand image for Virtualmin 1751 if ($vm_available && !$cm_available) { 1752 $brand = read_file_contents("$brand_dir/virtualmin.html"); 1753 $brand_name = "brand-virtualmin"; 1754 } 1755 1756 # Define brand image for Cloudmin 1757 elsif ($cm_available) { 1758 $brand = read_file_contents("$brand_dir/cloudmin.html"); 1759 $brand_name = "brand-cloudmin"; 1760 } 1761 1762 # Webmin/Usermin brand image 1763 else { 1764 my $prod = get_product_name(); 1765 $brand = read_file_contents("$brand_dir/$prod.html"); 1766 $brand_name = "brand-$prod"; 1767 } 1768 $brand = 1769"<div tabindex=\"1\" class=\"branding-backdrop $brand_name\"><div class=\"centered\">$brand<br><div class=\"branding-loader\">$loader</div></div></div>"; 1770 $brand .= "<script>page.branding.process()</script>"; 1771 print $brand; 1772} 1773 17741; 1775