mirror of
https://github.com/webmin/webmin.git
synced 2026-07-26 03:10:34 +01:00
Merge branch 'master' into dev/download-target-check
This commit is contained in:
49
t/web-lib-funcs-acl.t
Normal file
49
t/web-lib-funcs-acl.t
Normal file
@@ -0,0 +1,49 @@
|
||||
#!/usr/bin/perl
|
||||
# Unit tests for ACL preservation helpers in web-lib-funcs.pl.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Test::More;
|
||||
use File::Basename qw(dirname);
|
||||
use File::Spec;
|
||||
|
||||
my $script = File::Spec->rel2abs(
|
||||
File::Spec->catfile(dirname(__FILE__), '..', 'web-lib-funcs.pl'));
|
||||
require $script;
|
||||
|
||||
subtest 'physical restore is enabled when supported' => sub {
|
||||
no warnings 'redefine';
|
||||
my $calls = 0;
|
||||
local *main::backquote_command = sub {
|
||||
$calls++;
|
||||
return "setfacl 2.4.0 -- set file access control lists\n".
|
||||
"Usage: setfacl [-bkndRLP] { -m|-M|-x|-X ... } file ...\n".
|
||||
" setfacl [-P] --restore=file\n".
|
||||
" -P, --physical physical walk, do not follow symbolic links\n".
|
||||
" --restore=file restore ACLs (inverse of `getfacl -R')\n";
|
||||
};
|
||||
|
||||
is(main::get_setfacl_restore_command('/usr/bin/setfacl'),
|
||||
'/usr/bin/setfacl -P --restore=-',
|
||||
'uses physical restore with setfacl 2.4.0 and later');
|
||||
is(main::get_setfacl_restore_command('/usr/bin/setfacl'),
|
||||
'/usr/bin/setfacl -P --restore=-',
|
||||
'keeps using physical restore on later calls');
|
||||
is($calls, 1, 'caches the capability check');
|
||||
};
|
||||
|
||||
subtest 'older setfacl remains supported' => sub {
|
||||
no warnings 'redefine';
|
||||
local *main::backquote_command = sub {
|
||||
return "setfacl 2.3.2 -- set file access control lists\n".
|
||||
"Usage: setfacl [-bkndRLP] { -m|-M|-x|-X ... } file ...\n".
|
||||
" -P, --physical physical walk, do not follow symbolic links\n".
|
||||
" --restore=file restore ACLs (inverse of `getfacl -R')\n";
|
||||
};
|
||||
|
||||
is(main::get_setfacl_restore_command('/usr/local/bin/setfacl'),
|
||||
'/usr/local/bin/setfacl --restore=-',
|
||||
'does not pass incompatible -P option to older versions');
|
||||
};
|
||||
|
||||
done_testing();
|
||||
21
t/xmlrpc.t
21
t/xmlrpc.t
@@ -110,6 +110,14 @@ subtest 'encode_xml_value type selection' => sub {
|
||||
# Plain strings.
|
||||
like(encode_xml_value('hello'), qr{^<string>hello</string>\s*$}, 'word -> string');
|
||||
like(encode_xml_value(''), qr{^<string></string>\s*$}, 'empty string -> empty <string>');
|
||||
my @warnings;
|
||||
my $undef_xml;
|
||||
{
|
||||
local $SIG{__WARN__} = sub { push(@warnings, @_); };
|
||||
$undef_xml = encode_xml_value(undef);
|
||||
}
|
||||
like($undef_xml, qr{^<string></string>\s*$}, 'undef -> empty <string>');
|
||||
is_deeply(\@warnings, [], 'undef emits no warnings');
|
||||
|
||||
# A value with control characters cannot live in a <string> (the
|
||||
# printable-range regex fails), so it must fall through to base64.
|
||||
@@ -189,6 +197,19 @@ subtest 'parse_xml_value' => sub {
|
||||
is(parse_xml_value(value_tree('<boolean>1</boolean>')),1, 'boolean parsed');
|
||||
is(parse_xml_value(value_tree('<double>2.5</double>')),'2.5', 'double parsed');
|
||||
is(parse_xml_value(value_tree('<string>hi</string>')), 'hi', 'string parsed');
|
||||
my @warnings;
|
||||
{
|
||||
local $SIG{__WARN__} = sub { push(@warnings, @_); };
|
||||
is(parse_xml_value(value_tree('<string></string>')), '',
|
||||
'empty string parsed');
|
||||
is(parse_xml_value(value_tree('')), '', 'implicit empty string parsed');
|
||||
is(parse_xml_value(value_tree('<base64></base64>')), '',
|
||||
'empty base64 parsed');
|
||||
my $empty_name = parse_xml_value(value_tree(
|
||||
'<struct><member><name></name><value><string>x</string></value></member></struct>'));
|
||||
is_deeply($empty_name, { '' => 'x' }, 'empty struct member name parsed');
|
||||
}
|
||||
is_deeply(\@warnings, [], 'empty XML values emit no warnings');
|
||||
|
||||
# base64 is decoded back to its raw bytes.
|
||||
my $b64 = encode_base64("ab\x00cd");
|
||||
|
||||
@@ -10359,16 +10359,17 @@ out progress of an HTTP request.
|
||||
=cut
|
||||
sub progress_callback
|
||||
{
|
||||
my ($mode, $arg) = @_;
|
||||
if (defined(&theme_progress_callback)) {
|
||||
# Call the theme override
|
||||
return &theme_progress_callback(@_);
|
||||
}
|
||||
if ($_[0] == 2) {
|
||||
if ($mode == 2) {
|
||||
# Got size
|
||||
print $progress_callback_prefix;
|
||||
if ($_[1]) {
|
||||
$progress_size = $_[1];
|
||||
$progress_step = int($_[1] / 10);
|
||||
if ($arg) {
|
||||
$progress_size = $arg;
|
||||
$progress_step = int($arg / 10);
|
||||
print &text('progress_size2',
|
||||
&html_escape($progress_callback_url),
|
||||
&nice_size($progress_size)),"<br>\n";
|
||||
@@ -10380,42 +10381,42 @@ if ($_[0] == 2) {
|
||||
}
|
||||
$last_progress_time = $last_progress_size = undef;
|
||||
}
|
||||
elsif ($_[0] == 3) {
|
||||
elsif ($mode == 3) {
|
||||
# Got data update
|
||||
my $sp = $progress_callback_prefix.(" " x 5);
|
||||
if ($progress_size) {
|
||||
# And we have a size to compare against
|
||||
my $st = int(($_[1] * 10) / $progress_size);
|
||||
my $st = int(($arg * 10) / $progress_size);
|
||||
my $time_now = time();
|
||||
if ($st != $progress_step ||
|
||||
$time_now - $last_progress_time > 60) {
|
||||
# Show progress every 10% or 60 seconds
|
||||
print $sp,&text('progress_datan', &nice_size($_[1]),
|
||||
int($_[1]*100/$progress_size)),"<br>\n";
|
||||
print $sp,&text('progress_datan', &nice_size($arg),
|
||||
int($arg*100/$progress_size)),"<br>\n";
|
||||
$last_progress_time = $time_now;
|
||||
}
|
||||
$progress_step = $st;
|
||||
}
|
||||
else {
|
||||
# No total size .. so only show in 1M jumps
|
||||
if ($_[1] > $last_progress_size+1024*1024) {
|
||||
if ($arg > $last_progress_size+1024*1024) {
|
||||
print $sp,&text('progress_data2n',
|
||||
&nice_size($_[1])),"<br>\n";
|
||||
$last_progress_size = $_[1];
|
||||
&nice_size($arg)),"<br>\n";
|
||||
$last_progress_size = $arg;
|
||||
}
|
||||
}
|
||||
}
|
||||
elsif ($_[0] == 4) {
|
||||
elsif ($mode == 4) {
|
||||
# All done downloading
|
||||
print $progress_callback_prefix,&text('progress_done'),"<br>\n";
|
||||
}
|
||||
elsif ($_[0] == 5) {
|
||||
elsif ($mode == 5) {
|
||||
# Got new location after redirect
|
||||
$progress_callback_url = $_[1];
|
||||
$progress_callback_url = $arg;
|
||||
}
|
||||
elsif ($_[0] == 6) {
|
||||
elsif ($mode == 6) {
|
||||
# URL is in cache
|
||||
$progress_callback_url = $_[1];
|
||||
$progress_callback_url = $arg;
|
||||
print &text('progress_incache',
|
||||
&html_escape($progress_callback_url)),"<br>\n";
|
||||
}
|
||||
@@ -11629,7 +11630,8 @@ elsif (defined($main::open_tempfiles{$_[0]})) {
|
||||
}
|
||||
if ($file_acls) {
|
||||
# Set original ACLs
|
||||
open(my $pipe, '|-', "$setfacl --restore=-");
|
||||
my $restore_command = &get_setfacl_restore_command($setfacl);
|
||||
open(my $pipe, '|-', $restore_command);
|
||||
print($pipe $file_acls);
|
||||
close($pipe);
|
||||
}
|
||||
@@ -11694,6 +11696,27 @@ if (!defined($main::selinux_enabled_cache)) {
|
||||
return $main::selinux_enabled_cache;
|
||||
}
|
||||
|
||||
=head2 get_setfacl_restore_command(setfacl-command)
|
||||
|
||||
Returns a command for restoring ACLs from standard input. Uses physical
|
||||
restore when supported by setfacl, while remaining compatible with versions
|
||||
older than 2.4.0 which reject -P together with --restore.
|
||||
|
||||
=cut
|
||||
sub get_setfacl_restore_command
|
||||
{
|
||||
my ($setfacl) = @_;
|
||||
state %physical_restore_cache;
|
||||
|
||||
if (!exists($physical_restore_cache{$setfacl})) {
|
||||
my $help = &backquote_command("$setfacl --help 2>&1 </dev/null");
|
||||
$physical_restore_cache{$setfacl} =
|
||||
$help =~ /\[-P\]\s+--restore(?:=|\b)/ ? 1 : 0;
|
||||
}
|
||||
my $physical = $physical_restore_cache{$setfacl} ? "-P " : "";
|
||||
return "$setfacl ${physical}--restore=-";
|
||||
}
|
||||
|
||||
=head2 get_clear_file_attributes(file)
|
||||
|
||||
Finds file attributes that may prevent writing, clears them and returns them
|
||||
|
||||
@@ -18,7 +18,7 @@ my ($base64) = &find_xmls("base64", $value, 1);
|
||||
my ($struct) = &find_xmls("struct", $value, 1);
|
||||
my ($array) = &find_xmls("array", $value, 1);
|
||||
if ($scalar) {
|
||||
return $scalar->[1]->[2];
|
||||
return $scalar->[1]->[2] // "";
|
||||
}
|
||||
elsif ($date) {
|
||||
# Need to decode date
|
||||
@@ -26,7 +26,7 @@ elsif ($date) {
|
||||
}
|
||||
elsif ($base64) {
|
||||
# Convert to binary
|
||||
return &decode_base64($base64->[1]->[2]);
|
||||
return &decode_base64($base64->[1]->[2] // "");
|
||||
}
|
||||
elsif ($struct) {
|
||||
# Parse member names and values
|
||||
@@ -35,7 +35,7 @@ elsif ($struct) {
|
||||
my ($name) = &find_xmls("name", $member, 1);
|
||||
my ($value) = &find_xmls("value", $member, 1);
|
||||
my $perlv = &parse_xml_value($value);
|
||||
$rv{$name->[1]->[2]} = $perlv;
|
||||
$rv{$name->[1]->[2] // ""} = $perlv;
|
||||
}
|
||||
return \%rv;
|
||||
}
|
||||
@@ -51,7 +51,7 @@ elsif ($array) {
|
||||
}
|
||||
else {
|
||||
# Fallback - just a string directly in the value
|
||||
return $value->[1]->[2];
|
||||
return $value->[1]->[2] // "";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,6 +60,7 @@ else {
|
||||
sub encode_xml_value
|
||||
{
|
||||
my ($perlv) = @_;
|
||||
$perlv = "" if (!defined($perlv));
|
||||
if (ref($perlv) eq "ARRAY") {
|
||||
# Convert to array XML format
|
||||
my $xmlrv = "<array>\n<data>\n";
|
||||
|
||||
Reference in New Issue
Block a user