From 49f75d239ace6adfbdded4247fbe081e4db7d288 Mon Sep 17 00:00:00 2001 From: Ilia Rostovtsev Date: Fri, 26 Mar 2021 15:37:12 +0300 Subject: [PATCH 1/4] Fix bad design that I shouldn't have ever added #1466 --- miniserv.pl | 68 +++++++++++++++++++------------- unauthenticated/errors.css | 81 ++++++++++++++++++++++++++++++++++++++ web-lib-funcs.pl | 43 ++++++++++---------- 3 files changed, 141 insertions(+), 51 deletions(-) create mode 100644 unauthenticated/errors.css diff --git a/miniserv.pl b/miniserv.pl index 8f25d1c06..c4b224c03 100755 --- a/miniserv.pl +++ b/miniserv.pl @@ -2128,9 +2128,9 @@ if ($config{'userfile'}) { &write_data("\r\n"); &reset_byte_count(); &write_data("\n"); - &write_data("401 — Unauthorized\n"); - &write_data("

401 — Unauthorized

\n"); - &write_data("

A password is required to access this\n"); + &write_data("".&embed_error_styles($roots[0])."401 — Unauthorized\n"); + &write_data("

401 — Unauthorized

\n"); + &write_data("

A password is required to access this\n"); &write_data("web server. Please try again.

\n"); &write_data("\n"); &log_request($loghost, undef, $reqline, 401, &byte_count()); @@ -2389,8 +2389,8 @@ if (-d _) { &write_keep_alive(0); &write_data("\r\n"); &reset_byte_count(); - &write_data("

Index of $simple

\n"); - &write_data("
\n");
+	&write_data("".&embed_error_styles($roots[0])."

Index of $simple

\n"); + &write_data("
\n");
 	&write_data(sprintf "%-35.35s %-20.20s %-10.10s\n",
 			"Name", "Last Modified", "Size");
 	&write_data("
\n"); @@ -2810,10 +2810,10 @@ else { &write_data("\r\n"); &reset_byte_count(); &write_data("\n"); - &write_data("$code — $msg\n"); - &write_data("

Error — $msg

\n"); + &write_data("".&embed_error_styles($roots[0])."$code — $msg\n"); + &write_data("

Error — $msg

\n"); if ($body) { - &write_data("

$body

\n"); + &write_data("

$body

\n"); } &write_data("\n"); } @@ -2824,6 +2824,23 @@ shutdown(SOCK, 1); exit if (!$noexit); } +# embed_error_styles() +# Returns HTML styles for nicer errors. For internal use only. +sub embed_error_styles +{ +my ($root) = @_; +if ($root) { + my $err_style = &read_any_file("$root/unauthenticated/errors.css"); + if ($err_style) { + $err_style =~ s/[\n\r]//g; + $err_style =~ s/\s+/ /g; + $err_style = ""; + return "\n$err_style\n"; + } + } +return undef; +} + sub get_type { if ($_[0] =~ /\.([A-z0-9]+)$/) { @@ -3137,7 +3154,7 @@ local($idx, $more, $rv); while(($idx = index($main::read_buffer, "\n")) < 0) { if (length($main::read_buffer) > 100000 && !$nolimit) { &http_error(414, "Request too long", - "Received excessive line
".&html_strip($main::read_buffer)."
"); + "Received excessive line
".&html_strip($main::read_buffer)."
"); } # need to read more.. @@ -4681,6 +4698,20 @@ close(CONF); return %rv; } +# read_any_file(file) +# Reads any given file and returns its content +sub read_any_file +{ +my ($realfile) = @_; +my $rv; +return $rv if (! -r $realfile); +open(my $fh, "<".$realfile); +local $/; +$rv = <$fh>; +close($fh); +return $rv; +} + # update_vital_config() # Updates %config with defaults, and dies if something vital is missing sub update_vital_config @@ -6472,22 +6503,3 @@ sub getenv my ($key) = @_; return $ENV{ uc($key) } || $ENV{ lc($key) }; } - -# get_error_style(style_for) -# Returns a style for error messages -sub get_error_style -{ -my ($type, $extra_style) = @_; -my $style = ' style="font-family:Lucida Console,Courier,monospace;'; -if ($type eq 'heading') { - $style .= 'color:#f12b2b;font-size:14px;padding:5px 2.5px 0;transform:scale(1,1.5);text-transform:uppercase;white-space:pre-wrap;font-weight:500;'; - } -if ($type eq 'content') { - $style .= 'font-size:12.5px;padding-left:2.5px;white-space:pre-wrap;'; - } -if ($type eq 'body') { - $style .= 'font-size:12.5px;'; - } -$style .= "$extra_style\""; -return $style; -} diff --git a/unauthenticated/errors.css b/unauthenticated/errors.css new file mode 100644 index 000000000..c21b48aea --- /dev/null +++ b/unauthenticated/errors.css @@ -0,0 +1,81 @@ +.err-head, +.err-content, +.err-body { + font-family: Lucida Console, Courier, monospace; +} + +.err-head { + color: #f12b2b; + font-size: 14px; + font-weight: 500; + padding: 5px 2.5px 0; + text-transform: uppercase; + transform: scale(1, 1.5); + white-space: pre-wrap; +} + +.err-content { + padding-left: 2.5px; + white-space: pre-wrap; +} + +.err-content, +.err-body { + font-size: 12.5px; +} +.err-head[data-fatal-error-text] { + padding: 0; +} + +.err-stack caption, +.err-stack > tbody > tr:first-child > td > b { + color: #151515; + font-weight: bold; + text-align: left; +} + +.err-stack > tbody > tr:first-child > td > b { + border-bottom: 1px solid #151515; +} + +.err-stack > tbody > tr:first-child>td { + font-family: unset; + font-size: 14px; + height: 25px; + text-transform: uppercase; + transform: scale(1, 1.2); + vertical-align: top; +} + +.err-stack { + border: 1px dashed #151515 +} + +.err-stack.captured { + margin-left: 12px; + width: auto +} +.err-stack tr td { + font-family: Lucida Console, Courier, monospace; + font-size: 13px; + padding: 1px 10px; + transform: scale(1, 1.15); +} + +.err-stack tr:not(:first-child) td.captured { + font-size: 90%; +} + +.err-stack > tr:first-child > td.captured { + font-size: 96%; + padding-bottom: 7px; + padding-top: 3px; +} + +.err-stack caption.err-head { + padding:0 0 10px 0; +} +.err-stack caption.err-head.captured { + color: #222; + font-size:98%; +} diff --git a/web-lib-funcs.pl b/web-lib-funcs.pl index 3b25d7370..e5de7afa0 100755 --- a/web-lib-funcs.pl +++ b/web-lib-funcs.pl @@ -1659,9 +1659,16 @@ elsif ($ENV{'REQUEST_URI'} =~ /json-error=1/) { } else { &header($text{'error'}, ""); - my $hh = $miniserv::page_capture; + my $hh = $miniserv::page_capture ? " captured" : ""; + my $err_style = &read_file_contents("$root_directory/unauthenticated/errors.css"); + if ($err_style) { + $err_style =~ s/[\n\r]//g; + $err_style =~ s/\s+/ /g; + $err_style = ""; + print "\n$err_style\n"; + } print "
\n" if ($hh); - if ($hh) { + if ($hh) { print "

",($main::whatfailed ? "$main::whatfailed : " : ""), @_,"

\n"; } @@ -1673,32 +1680,22 @@ else { $error_text = " — $error_html"; $error_html = undef; } - print "$text{'error'}

$text{'error'}$error_text

$error_html
\n"; + print "$text{'error'}

$text{'error'}$error_text

$error_html
\n"; } if ($gconfig{'error_stack'}) { # Show call stack - print "\n"; - my $caption_no_header_style = - &miniserv::get_error_style('heading', "padding:0 0 10px 0;" . ($hh ? "color: #222;font-size:98%;" : "") . ""); + my $cls_err_caption = " class=\"err-head$hh\""; + my $cls_err_td = $hh ? " class=\"@{[&trim($hh)]}\"" : ""; print "
\n" if ($hh); - print "$text{'error_stack'}\n"; - print " ", - " ", - "\n"; + print "
$text{'error_file'}$text{'error_line'}$text{'error_sub'}
$text{'error_stack'}\n"; + print "$text{'error_file'} ", + "$text{'error_line'} ", + "$text{'error_sub'} \n"; for($i=0; my @stack = caller($i); $i++) { print "\n"; - print "\n"; - print "\n"; - print "\n"; + print "$stack[1]\n"; + print "$stack[2]\n"; + print "$stack[3]\n"; print "\n"; } print "
$stack[1]$stack[2]$stack[3]
\n"; @@ -3854,7 +3851,7 @@ else { delete($ENV{'FOREIGN_ROOT_DIRECTORY'}); } @INC = @OLDINC; -if ($@) { &error("
Require $mod/$files[0] failed : $@
"); } +if ($@) { &error("
Require $mod/$files[0] failed : $@
"); } return 1; } From e54887482d1b498d8954e8fdbd393c4417b8831f Mon Sep 17 00:00:00 2001 From: Ilia Rostovtsev Date: Fri, 26 Mar 2021 15:40:43 +0300 Subject: [PATCH 2/4] Fix formatting --- unauthenticated/errors.css | 2 ++ 1 file changed, 2 insertions(+) diff --git a/unauthenticated/errors.css b/unauthenticated/errors.css index c21b48aea..9b7183f5b 100644 --- a/unauthenticated/errors.css +++ b/unauthenticated/errors.css @@ -23,6 +23,7 @@ .err-body { font-size: 12.5px; } + .err-head[data-fatal-error-text] { padding: 0; } @@ -75,6 +76,7 @@ .err-stack caption.err-head { padding:0 0 10px 0; } + .err-stack caption.err-head.captured { color: #222; font-size:98%; From e79a678a78029775de56764c2aa41e10b801d463 Mon Sep 17 00:00:00 2001 From: Ilia Rostovtsev Date: Fri, 26 Mar 2021 19:26:31 +0300 Subject: [PATCH 3/4] Don't test for file existence, just return undef https://github.com/webmin/webmin/commit/49f75d239ace6adfbdded4247fbe081e4db7d288#r48753651 --- miniserv.pl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/miniserv.pl b/miniserv.pl index c4b224c03..93164d8f5 100755 --- a/miniserv.pl +++ b/miniserv.pl @@ -4704,8 +4704,7 @@ sub read_any_file { my ($realfile) = @_; my $rv; -return $rv if (! -r $realfile); -open(my $fh, "<".$realfile); +open(my $fh, "<".$realfile) || return $rv; local $/; $rv = <$fh>; close($fh); From 1b54c49813e0dc492536ca55a0e7c75e68803718 Mon Sep 17 00:00:00 2001 From: Ilia Rostovtsev Date: Fri, 26 Mar 2021 20:40:16 +0300 Subject: [PATCH 4/4] Fix to allow limiting `list_combined_webmin_menu` to specific module --- web-lib-funcs.pl | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/web-lib-funcs.pl b/web-lib-funcs.pl index e5de7afa0..8e3a8df79 100755 --- a/web-lib-funcs.pl +++ b/web-lib-funcs.pl @@ -11037,7 +11037,7 @@ foreach my $e (@_) { return @rv; } -=head2 list_combined_webmin_menu(&data, &in) +=head2 list_combined_webmin_menu(&data, &in, [$mod]) Returns an array of objects, each representing a menu item that a theme should render such as on a left menu. Each object is a hash ref with the following @@ -11081,16 +11081,18 @@ possible keys : The &data parameter is a hash ref of additional information that the theme supplies to all modules. The &in param is the CGI inputs from the menu, for -use where the menu has a form that submits to itself. +use where the menu has a form that submits to itself, and [$mod] param binds +a function return to a given module call =cut sub list_combined_webmin_menu { -my ($data, $in) = @_; +my ($data, $in, $mod) = @_; foreach my $m (&get_available_module_infos()) { my $dir = &module_root_directory($m->{'dir'}); my $mfile = "$dir/webmin_menu.pl"; next if (!-r $mfile); + next if (defined($mod) && $mod ne $m->{'dir'}); eval { local $main::error_must_die = 1; &foreign_require($m->{'dir'}, "webmin_menu.pl");