mirror of
https://github.com/webmin/webmin.git
synced 2026-02-06 15:32:20 +00:00
Compare commits
60 Commits
dev/die-ha
...
dev/samba-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0457c1d1c0 | ||
|
|
59b944ebff | ||
|
|
2e63031e22 | ||
|
|
6137f285f2 | ||
|
|
04557f6e28 | ||
|
|
d7de842f45 | ||
|
|
ba1aa5a498 | ||
|
|
b70a697e66 | ||
|
|
c4c2c5c38e | ||
|
|
bbe7e78516 | ||
|
|
e40fc5568b | ||
|
|
71d94982df | ||
|
|
d48154d6a0 | ||
|
|
949f6fbf8d | ||
|
|
3c97fc5a32 | ||
|
|
4d4468e907 | ||
|
|
fc5a638e24 | ||
|
|
cf6a14b7a6 | ||
|
|
6ddde41728 | ||
|
|
5114308d0d | ||
|
|
2c325b1ee4 | ||
|
|
e087bb718c | ||
|
|
51bdd0d07e | ||
|
|
74fec8b171 | ||
|
|
9d360f1c24 | ||
|
|
148743894f | ||
|
|
6b935f980c | ||
|
|
e751836684 | ||
|
|
b9449c213b | ||
|
|
a3c9770d4f | ||
|
|
3c971dacc1 | ||
|
|
ac1a73c154 | ||
|
|
3a099fabec | ||
|
|
9a1e869a82 | ||
|
|
5c54c614e3 | ||
|
|
cbdc843500 | ||
|
|
82fbca20e4 | ||
|
|
ef7dbb1f77 | ||
|
|
4f15106fa9 | ||
|
|
96bfc34247 | ||
|
|
0289ceed5b | ||
|
|
4e54ce3f85 | ||
|
|
73b2322597 | ||
|
|
05c7b6c3a3 | ||
|
|
1bb70effea | ||
|
|
590c27d202 | ||
|
|
846dff2636 | ||
|
|
b339c76fc7 | ||
|
|
fbabecbe9e | ||
|
|
7706c0795e | ||
|
|
4be368c523 | ||
|
|
b268c1bb66 | ||
|
|
b2f18fb784 | ||
|
|
34e3b4c027 | ||
|
|
3c5edcf184 | ||
|
|
33f4d7a008 | ||
|
|
2d182a2eea | ||
|
|
7f06ccaf53 | ||
|
|
d8fa7f26af | ||
|
|
aa6edf6c55 |
11
CHANGELOG.md
11
CHANGELOG.md
@@ -1,8 +1,17 @@
|
||||
## Changelog
|
||||
|
||||
#### 2.103 (September 18, 2023)
|
||||
#### 2.104 (October 12, 2023)
|
||||
* Add support for numbered and bulleted lists in mail HTML editor
|
||||
* Fix Webmin version display [#2023](https://github.com/webmin/webmin/issues/2023)
|
||||
* Fix hostname detection on `systemd` systems to avoid excessive logging [#2020](https://github.com/webmin/webmin/issues/2020)
|
||||
* Fix to check if UI library is loaded before using it [#2021](https://github.com/webmin/webmin/issues/2021)
|
||||
|
||||
#### 2.103 (October 08, 2023)
|
||||
* Add support for hostname detection using `hostnamectl` command
|
||||
* Add support for other ACME services
|
||||
* Add ability to hide dotfiles in File Manager [#1578](https://github.com/webmin/authentic-theme/issues/1578)
|
||||
* Add `xz`, `zstd` and plain `tar` support when creating archives in File Manager [#2009](https://github.com/webmin/webmin/issues/2009)
|
||||
* Add support for English (United States) (military time) locale
|
||||
* Fix to correctly switch key hash type with ACME services
|
||||
* Fix bug when `backend` wasn't saved correctly in Fail2Ban module [#1992](https://github.com/webmin/webmin/issues/1992)
|
||||
* Fix large files download in Upload and Download module
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1976,22 +1976,32 @@ if (!$file) {
|
||||
push(@{$dir->{'members'}}, { 'name' => 'file',
|
||||
'values' => [ $file ] } );
|
||||
|
||||
# Add slave IPs
|
||||
if (@$slaves) {
|
||||
# Allow transfer from slave IPs
|
||||
my (@notify, @transfer);
|
||||
foreach my $s (@$slaves) {
|
||||
push(@notify, { 'name' => $s });
|
||||
push(@transfer, { 'name' => $s });
|
||||
}
|
||||
if (@transfer) {
|
||||
my $gat = &find("allow-transfer", $opts->{'members'});
|
||||
if ($gat) {
|
||||
push(@transfer, @{$gat->{'members'}});
|
||||
}
|
||||
}
|
||||
if (@notify) {
|
||||
my $also = { 'name' => 'also-notify',
|
||||
'type' => 1,
|
||||
'members' => [ ] };
|
||||
my $allow = { 'name' => 'allow-transfer',
|
||||
'type' => 1,
|
||||
'members' => [ ] };
|
||||
foreach my $s (@$slaves) {
|
||||
push(@{$also->{'members'}}, { 'name' => $s });
|
||||
push(@{$allow->{'members'}}, { 'name' => $s });
|
||||
}
|
||||
push(@{$dir->{'members'}}, $also, $allow);
|
||||
'members' => \@notify};
|
||||
push(@{$dir->{'members'}}, $also);
|
||||
push(@{$dir->{'members'}}, { 'name' => 'notify',
|
||||
'values' => [ 'yes' ] });
|
||||
}
|
||||
if (@transfer) {
|
||||
my $allow = { 'name' => 'allow-transfer',
|
||||
'type' => 1,
|
||||
'members' => \@transfer };
|
||||
push(@{$dir->{'members'}}, $allow);
|
||||
}
|
||||
|
||||
# Create the zone file, with records
|
||||
my $ZONE;
|
||||
|
||||
@@ -5,7 +5,7 @@ use warnings;
|
||||
no warnings 'redefine';
|
||||
no warnings 'uninitialized';
|
||||
# Globals
|
||||
our (%access, %text);
|
||||
our (%access, %text, $bind_version);
|
||||
our $dnssec_dlv_zone;
|
||||
|
||||
require './bind8-lib.pl';
|
||||
@@ -24,10 +24,12 @@ $tkeys ||= { 'members' => [ ] };
|
||||
print &ui_form_start("save_trusted.cgi", "post");
|
||||
print &ui_table_start($text{'trusted_header'}, undef, 2);
|
||||
|
||||
# DNSSEC enabled?
|
||||
print &choice_input($text{'trusted_dnssec'}, 'dnssec-enable', $mems,
|
||||
$text{'yes'}, 'yes', $text{'no'}, 'no',
|
||||
$text{'default'}, undef);
|
||||
if (&compare_version_numbers($bind_version, '<', '9.16.0')) {
|
||||
# DNSSEC enabled?
|
||||
print &choice_input($text{'trusted_dnssec'}, 'dnssec-enable', $mems,
|
||||
$text{'yes'}, 'yes', $text{'no'}, 'no',
|
||||
$text{'default'}, undef);
|
||||
}
|
||||
if (&supports_dnssec_client() == 2) {
|
||||
print &choice_input($text{'trusted_validation'},
|
||||
'dnssec-validation', $mems,
|
||||
|
||||
@@ -4,7 +4,7 @@ use strict;
|
||||
use warnings;
|
||||
no warnings 'redefine';
|
||||
no warnings 'uninitialized';
|
||||
our (%access, %text, %in, %config);
|
||||
our (%access, %text, %in, %config, $bind_version);
|
||||
|
||||
require './bind8-lib.pl';
|
||||
$access{'defaults'} || &error($text{'trusted_ecannot'});
|
||||
@@ -17,7 +17,9 @@ my $conf = $parent->{'members'};
|
||||
my $options = &find("options", $conf);
|
||||
|
||||
# DNSSEC enabled
|
||||
&save_choice("dnssec-enable", $options, 1);
|
||||
if (&compare_version_numbers($bind_version, '<', '9.16.0')) {
|
||||
&save_choice("dnssec-enable", $options, 1);
|
||||
}
|
||||
if (&supports_dnssec_client() == 2) {
|
||||
&save_choice("dnssec-validation", $options, 1);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,19 @@ if(!$in{'arch'}) {
|
||||
|
||||
my $command;
|
||||
|
||||
if ($in{'method'} eq 'tar') {
|
||||
if ($in{'method'} eq 'plain-tar') {
|
||||
$full = "$cwd/$in{'arch'}.tar";
|
||||
$command = "tar cf ".quotemeta($full)." -C ".quotemeta($cwd);
|
||||
}
|
||||
elsif ($in{'method'} eq 'xz-tar') {
|
||||
$full = "$cwd/$in{'arch'}.tar.xz";
|
||||
$command = "tar cJf ".quotemeta($full)." -C ".quotemeta($cwd);
|
||||
}
|
||||
elsif ($in{'method'} eq 'zstd-tar') {
|
||||
$full = "$cwd/$in{'arch'}.zst";
|
||||
$command = "ZSTD_CLEVEL=19 tar --zstd -cf ".quotemeta($full)." -C ".quotemeta($cwd);
|
||||
}
|
||||
elsif ($in{'method'} eq 'tar') {
|
||||
$full = "$cwd/$in{'arch'}.tar.gz";
|
||||
$command = "tar czf ".quotemeta($full)." -C ".quotemeta($cwd);
|
||||
}
|
||||
|
||||
@@ -41,7 +41,8 @@ print &ui_table_row($text{'config_columns_to_display'},
|
||||
&ui_checkbox('columns', 'last_mod_time', $text{'last_mod_time'}, $config{'columns'} =~ /last_mod_time/)
|
||||
);
|
||||
print &ui_table_row($text{'config_per_page'}, ui_textbox("per_page", $config{'per_page'}, 80));
|
||||
print &ui_table_row($text{'file_detect_encoding'}, &ui_yesno_radio('config_portable_module_filemanager_editor_detect_encoding', $config{'config_portable_module_filemanager_editor_detect_encoding'}, 'true', 'false'));
|
||||
print &ui_table_row($text{'file_detect_encoding'}, &ui_yesno_radio('config_portable_module_filemanager_editor_detect_encoding', $config{'config_portable_module_filemanager_editor_detect_encoding'} ne 'false' ? 'true' : 'false', 'true', 'false'));
|
||||
print &ui_table_row($text{'file_showhiddenfiles'}, &ui_yesno_radio('config_portable_module_filemanager_show_dot_files', $config{'config_portable_module_filemanager_show_dot_files'} ne 'false' ? 'true' : 'false', 'true', 'false'));
|
||||
print &ui_table_row($text{'config_bookmarks'}, &ui_textarea("bookmarks", $bookmarks, 5, 40));
|
||||
|
||||
print &ui_table_end();
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
max=Maximum size for uploaded files,3,Unlimited
|
||||
config_portable_module_filemanager_editor_detect_encoding=Fix to prevent encoding detection if forbidden,1,true-Yes,false-No
|
||||
config_portable_module_filemanager_editor_detect_encoding=Fix to prevent encoding detection if forbidden,1,true-Yes,false-No
|
||||
config_portable_module_filemanager_show_dot_files=Show hidden files,1,true-Yes,false-No
|
||||
@@ -1,3 +1,4 @@
|
||||
columns=size,owner_user,permissions,last_mod_time
|
||||
per_page=50
|
||||
config_portable_module_filemanager_editor_detect_encoding=true
|
||||
config_portable_module_filemanager_editor_detect_encoding=true
|
||||
config_portable_module_filemanager_show_dot_files=true
|
||||
|
||||
@@ -12,7 +12,7 @@ if ($archive_type =~ /x-bzip/) {
|
||||
$cmd = "tar xvjfp ".quotemeta("$cwd/$in{'file'}").
|
||||
" -C ".quotemeta($cwd);
|
||||
}
|
||||
elsif ($archive_type =~ /x-tar|\/gzip|x-xz|x-compressed-tar/) {
|
||||
elsif ($archive_type =~ /x-tar|\/gzip|x-xz|zstd|x-compressed-tar/) {
|
||||
$cmd = "tar xfp ".quotemeta("$cwd/$in{'file'}").
|
||||
" -C ".quotemeta($cwd);
|
||||
}
|
||||
|
||||
@@ -397,6 +397,7 @@ sub print_interface {
|
||||
index($type, "-x-tar") != -1 ||
|
||||
(index($type, "-x-bzip") != -1 && has_command('bzip2')) ||
|
||||
(index($type, "-gzip") != -1 && has_command('gzip')) ||
|
||||
(index($type, "zstd") != -1 && has_command('zstd')) ||
|
||||
(index($type, "-x-xz") != -1 && has_command('xz'))
|
||||
) &&
|
||||
has_command('tar')))
|
||||
|
||||
BIN
filemin/images/icons/mime/application-x-xz-compressed-tar.png
Normal file
BIN
filemin/images/icons/mime/application-x-xz-compressed-tar.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 764 B |
BIN
filemin/images/icons/mime/application-zstd.png
Normal file
BIN
filemin/images/icons/mime/application-zstd.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 764 B |
@@ -18,7 +18,8 @@ unless (opendir ( DIR, $cwd )) {
|
||||
my %secontext;
|
||||
|
||||
# Push file names with full paths to array, filtering out "." and ".."
|
||||
@list = map { &simplify_path("$cwd/$_") } grep { $_ ne '.' && $_ ne '..' } readdir(DIR);
|
||||
my $show_dot_files = $userconfig{'config_portable_module_filemanager_show_dot_files'} ne 'false';
|
||||
@list = map { &simplify_path("$cwd/$_") } grep { $_ ne '.' && $_ ne '..' && ($show_dot_files || ($_ !~ /^\./ && $_ !~ /\/\./)) } readdir(DIR);
|
||||
closedir(DIR);
|
||||
|
||||
# Filter out not allowed paths
|
||||
|
||||
@@ -173,6 +173,7 @@ acls_action=Action
|
||||
acls_manual=Manual params
|
||||
acls_error=<tt>setfacl</tt> command is not found on your system
|
||||
file_detect_encoding=Automatically detect file encoding
|
||||
file_showhiddenfiles=Show hidden files
|
||||
index_return=file listing
|
||||
upload_dirs=Directory Upload
|
||||
extract_uploaded=Extract Compressed
|
||||
|
||||
@@ -13,6 +13,7 @@ $columns =~ s/\0/,/g;
|
||||
'columns' => $columns,
|
||||
'per_page' => $in{'per_page'},
|
||||
'config_portable_module_filemanager_editor_detect_encoding' => $in{'config_portable_module_filemanager_editor_detect_encoding'},
|
||||
'config_portable_module_filemanager_show_dot_files' => $in{'config_portable_module_filemanager_show_dot_files'},
|
||||
);
|
||||
my $max_allowed = $in{'max_allowed'};
|
||||
if($max_allowed) {
|
||||
|
||||
@@ -102,7 +102,10 @@
|
||||
<input name="filename" type="text" class="form-control" data-placement="right" data-content="$text{'provide_file_name'}" data-trigger="manual">
|
||||
</div>
|
||||
<select name="method">
|
||||
<option value="tar">.tar.gz</option>
|
||||
<option value="plain-tar">.tar</option>
|
||||
<option value="xz-tar">.tar.xz</option>
|
||||
<option selected value="tar">.tar.gz</option>
|
||||
<option value="zstd-tar">.zstd</option>
|
||||
<option value="zip">.zip</option>
|
||||
</select>
|
||||
</form>
|
||||
|
||||
@@ -39,7 +39,10 @@
|
||||
<label>$text{'archive_name'}</label>
|
||||
<input name="filename" type="text">
|
||||
<select name="method">
|
||||
<option value="tar">.tar.gz</option>
|
||||
<option value="plain-tar">.tar</option>
|
||||
<option value="xz-tar">.tar.xz</option>
|
||||
<option selected value="tar">.tar.gz</option>
|
||||
<option value="zstd-tar">.zstd</option>
|
||||
<option value="zip">.zip</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
line0=Configurable global options,11
|
||||
perpage=Number of rules to display per page,3,50
|
||||
perpage=Number of rules to display per page,3,Default (50)
|
||||
view_condition=Display condition in rules list?,1,1-Yes,0-No
|
||||
view_comment=Display comment in rules list?,1,1-Yes,0-No
|
||||
comment_mod=Store comments as,1,0-# comments in save file,1---comment option
|
||||
|
||||
@@ -225,25 +225,17 @@ else {
|
||||
print &ui_hidden("table", $in{'table'});
|
||||
print &ui_hidden("chain", $c);
|
||||
|
||||
if (@rules > $config{'perpage'}) {
|
||||
my $pp = $config{'perpage'};
|
||||
if (@rules > $pp) {
|
||||
# Need to show arrows
|
||||
print "<center>\n";
|
||||
$s = int($in{'start'});
|
||||
$e = $in{'start'} + $config{'perpage'} - 1;
|
||||
$e = $in{'start'} + $pp - 1;
|
||||
$e = @rules-1 if ($e >= @rules);
|
||||
if ($s) {
|
||||
print &ui_link("?start=".
|
||||
($s - $config{'perpage'}),
|
||||
"<img src=/images/left.gif border=0 align=middle>");
|
||||
}
|
||||
print "<font size=+1>",&text('index_position', $s+1, $e+1,
|
||||
scalar(@rules)),"</font>\n";
|
||||
if ($e < @rules-1) {
|
||||
print &ui_link("?start=".
|
||||
($s + $config{'perpage'}),
|
||||
"<img src=/images/right.gif border=0 align=middle>");
|
||||
}
|
||||
print "</center>\n";
|
||||
print &ui_page_flipper(
|
||||
&text('index_position', $s+1, $e+1, scalar(@rules)),
|
||||
undef, undef,
|
||||
$s ? "?start=".($s - $pp) : "",
|
||||
$e < @rules-1 ? "?start=".($s + $pp) : "");
|
||||
}
|
||||
else {
|
||||
# Can show them all
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
index_title=Linux IPTables Firewall
|
||||
index_title_v=IPv4 Firewall
|
||||
index_title_v6=IPv6 Firewall
|
||||
index_position=Showing rules $1 to $2 of $3
|
||||
index_editing=rules file $1
|
||||
index_ecommand=The command $1 was not found on your system. Webmin needs this command to configure IPtables.
|
||||
index_ekernel=An error occured when checking your current IPtables configuration : $1 This may indicate that your kernel does not support IPtables.
|
||||
|
||||
@@ -96,6 +96,7 @@ if ($current_lang_info->{'rtl'} || $current_lang eq "ar") {
|
||||
# Page header
|
||||
print "<html>\n";
|
||||
print "<head>\n";
|
||||
print &ui_switch_theme_javascript();
|
||||
print "<title>$title</title>\n";
|
||||
my $imgdir = "@{[&get_webprefix()]}/images";
|
||||
my $prod = 'webmin';
|
||||
|
||||
@@ -84,7 +84,7 @@ if (@has > 1) {
|
||||
}
|
||||
print "</div>";
|
||||
}
|
||||
|
||||
print &ui_switch_theme_javascript();
|
||||
print "<div class='wrapper leftmenu'>\n";
|
||||
print "<table id='main' width='100%'><tbody><tr><td>\n";
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -22,6 +22,23 @@ our $ui_formcount;
|
||||
$main::WRAPPER_OPEN = 0;
|
||||
$main::COLUMNS_WRAPPER_OPEN = 0;
|
||||
|
||||
sub theme_ui_print_header
|
||||
{
|
||||
my ($text, @args) = @_;
|
||||
&header(@args);
|
||||
print <<EOL;
|
||||
<script>
|
||||
(function () {
|
||||
const body = document.querySelector('body');
|
||||
try {
|
||||
body && body.classList.add('$module_name');
|
||||
} catch (e) {}
|
||||
})();
|
||||
</script>
|
||||
EOL
|
||||
print &ui_post_header($text);
|
||||
}
|
||||
|
||||
# theme_ui_post_header([subtext])
|
||||
# Returns HTML to appear directly after a standard header() call
|
||||
sub theme_ui_post_header
|
||||
|
||||
@@ -697,4 +697,16 @@ body > .mode > b[data-mode="server-manager"] > a > .ff-cloudmin {
|
||||
}
|
||||
.ql-compose-container .ql-snow .ql-tooltip {
|
||||
z-index: 99;
|
||||
}
|
||||
}
|
||||
|
||||
/* Shell module tweaks */
|
||||
.shell pre {
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
.shell input[name="cmd"] {
|
||||
max-width: 64.5vw;
|
||||
}
|
||||
.shell select[name="pcmd"] {
|
||||
max-width: 65vw;
|
||||
}
|
||||
|
||||
@@ -277,24 +277,51 @@ my $html_editor_init_script =
|
||||
theme: 'snow'
|
||||
});
|
||||
|
||||
// Google Mail editor like keybind for quoting
|
||||
// Google Mail like key bind for creating numbered list (Ctrl+Shift+7)
|
||||
editor.keyboard.addBinding({
|
||||
key: '9',
|
||||
shiftKey: true,
|
||||
ctrlKey: !isMac,
|
||||
metaKey: isMac,
|
||||
format: ['blockquote'],
|
||||
key: '7',
|
||||
shiftKey: true,
|
||||
ctrlKey: !isMac,
|
||||
metaKey: isMac,
|
||||
}, function(range, context) {
|
||||
this.quill.format('blockquote', false);
|
||||
const currentFormat = this.quill.getFormat(range.index);
|
||||
if (currentFormat.list === 'ordered') {
|
||||
this.quill.format('list', false);
|
||||
} else {
|
||||
this.quill.format('list', 'ordered');
|
||||
}
|
||||
});
|
||||
|
||||
// Google Mail like key bind for creating bullet list (Ctrl+Shift+8)
|
||||
editor.keyboard.addBinding({
|
||||
key: '9',
|
||||
shiftKey: true,
|
||||
ctrlKey: !isMac,
|
||||
metaKey: isMac,
|
||||
key: '8',
|
||||
shiftKey: true,
|
||||
ctrlKey: !isMac,
|
||||
metaKey: isMac,
|
||||
}, function(range, context) {
|
||||
this.quill.format('blockquote', true);
|
||||
const currentFormat = this.quill.getFormat(range.index);
|
||||
if (currentFormat.list === 'bullet') {
|
||||
this.quill.format('list', false);
|
||||
} else {
|
||||
this.quill.format('list', 'bullet');
|
||||
}
|
||||
});
|
||||
|
||||
// Google Mail like key bind for creating blockquote (Ctrl+Shift+9)
|
||||
editor.keyboard.addBinding({
|
||||
key: '9',
|
||||
shiftKey: true,
|
||||
ctrlKey: !isMac,
|
||||
metaKey: isMac,
|
||||
}, function(range, context) {
|
||||
const currentFormat = this.quill.getFormat(range.index);
|
||||
if (currentFormat.blockquote) {
|
||||
this.quill.format('blockquote', false);
|
||||
} else {
|
||||
this.quill.format('blockquote', true);
|
||||
}
|
||||
});
|
||||
|
||||
editor.on('text-change', function() {
|
||||
// This should most probably go to onSubmit event
|
||||
targ.value = editor.root.innerHTML + "<br>";
|
||||
|
||||
@@ -3027,12 +3027,15 @@ sub gunzip_mail_file
|
||||
my ($file) = @_;
|
||||
my $switched = &switch_to_mail_user();
|
||||
my $outfile = $file.".$$.uncompressed";
|
||||
my @st = stat($file);
|
||||
my $ex = system("gunzip -c ".quotemeta($file)."> ".quotemeta($outfile)." 2>/dev/null");
|
||||
if ($ex) {
|
||||
unlink($outfile);
|
||||
}
|
||||
else {
|
||||
rename($outfile, $file);
|
||||
&set_ownership_permissions($st[4], $st[5], $st[2], $file);
|
||||
utime($st[8], $st[9], $file);
|
||||
}
|
||||
if ($switched) {
|
||||
$) = 0;
|
||||
|
||||
@@ -60,6 +60,7 @@ $vers || usage();
|
||||
"webmin-search-lib.pl", "WebminCore.pm",
|
||||
"record-login.pl", "record-logout.pl", "record-failed.pl",
|
||||
"robots.txt", "unauthenticated", "bin", "html-editor-lib.pl",
|
||||
"switch_theme.cgi",
|
||||
);
|
||||
if ($min) {
|
||||
# Only those required by others
|
||||
|
||||
@@ -86,7 +86,7 @@ Version: $ver
|
||||
Release: $rel
|
||||
Provides: %{name}-%{version} perl(WebminCore)
|
||||
Requires(pre): /usr/bin/perl
|
||||
Requires: /bin/sh /usr/bin/perl /bin/rm perl(lib) perl(open) perl(Net::SSLeay) perl(Time::Local) perl(Data::Dumper) perl(File::Path) perl(File::Basename) perl(Digest::SHA) perl(Digest::MD5) openssl unzip tar gzip
|
||||
Requires: /bin/sh /usr/bin/perl perl(lib) perl(open) perl(Net::SSLeay) perl(Time::Local) perl(Data::Dumper) perl(File::Path) perl(File::Basename) perl(Digest::SHA) perl(Digest::MD5) openssl unzip tar gzip
|
||||
Recommends: perl(DateTime) perl(DateTime::TimeZone) perl(DateTime::Locale) perl(Time::Piece) perl(Encode::Detect) lynx
|
||||
AutoReq: 0
|
||||
License: BSD-3-clause
|
||||
|
||||
14
miniserv.pl
14
miniserv.pl
@@ -1303,11 +1303,10 @@ if ($header_timeout > 10*60) {
|
||||
$header_timeout = 10*60;
|
||||
}
|
||||
|
||||
# Wait at most 60 secs for start of headers for initial requests, or
|
||||
# 10 minutes for kept-alive connections
|
||||
local $rmask;
|
||||
vec($rmask, fileno(SOCK), 1) = 1;
|
||||
local $to = $checked_timeout ? 10*60 : $header_timeout;
|
||||
print DEBUG "handle_request: waiting for $to seconds\n";
|
||||
local $sel = select($rmask, undef, undef, $to);
|
||||
if (!$sel) {
|
||||
if ($checked_timeout) {
|
||||
@@ -4749,10 +4748,15 @@ if ($config{'ssl_cipher_list'}) {
|
||||
"$@\n";
|
||||
}
|
||||
}
|
||||
|
||||
# Accept the SSL connection
|
||||
Net::SSLeay::set_fd($ssl_con, fileno($sock));
|
||||
if (!Net::SSLeay::accept($ssl_con)) {
|
||||
return undef;
|
||||
}
|
||||
alarm(10);
|
||||
$SIG{'ALRM'} = sub { die "timeout" };
|
||||
my $ok = Net::SSLeay::accept($ssl_con);
|
||||
alarm(0);
|
||||
return undef if (!$ok);
|
||||
|
||||
# Check for a per-hostname SSL context and use that instead
|
||||
if (defined(&Net::SSLeay::get_servername)) {
|
||||
my $h = Net::SSLeay::get_servername($ssl_con);
|
||||
|
||||
@@ -865,6 +865,7 @@ root_epass1=No new password entered
|
||||
root_epass2=Passwords do not match
|
||||
root_none=No password!
|
||||
root_auto=Automatic (typically <tt>root</tt>)
|
||||
root_socket=The MySQL <tt>$1</tt> user is using Unix socket authentication, so no password is needed and the password cannot be changed.
|
||||
|
||||
mysqlpass_err=MySQL safe mode
|
||||
mysqlpass_esafecmd=The command $1 needed to start MySQL with authentication disabled was not found
|
||||
|
||||
@@ -2005,5 +2005,19 @@ if ($mysql_module_version =~ /mariadb/i) {
|
||||
return $htext;
|
||||
}
|
||||
|
||||
# mysql_login_type(user)
|
||||
# Returns one of 'password' or 'socket'
|
||||
sub mysql_login_type
|
||||
{
|
||||
my ($user) = @_;
|
||||
my $rv;
|
||||
eval {
|
||||
local $main::error_must_die = 1;
|
||||
$rv = &execute_sql_safe($master_db, "select plugin from user where user = ?", $user);
|
||||
};
|
||||
return 'password' if ($@); # Old version without plugins
|
||||
return $rv->{'data'}->[0]->[0] =~ /unix_socket/i ? 'socket' : 'password';
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
|
||||
@@ -6,19 +6,27 @@ require './mysql-lib.pl';
|
||||
$access{'perms'} == 1 || &error($text{'perms_ecannot'});
|
||||
&ui_print_header(undef, $text{'root_title'}, "");
|
||||
|
||||
print &ui_form_start("save_root.cgi", "post");
|
||||
print &ui_table_start($text{'root_header'}, undef, 2);
|
||||
$mode = &mysql_login_type($mysql_login || 'root');
|
||||
if ($mode eq 'socket') {
|
||||
print &ui_alert_box(&text('root_socket', $mysql_login), 'warn');
|
||||
}
|
||||
else {
|
||||
print &ui_form_start("save_root.cgi", "post");
|
||||
print &ui_table_start($text{'root_header'}, undef, 2);
|
||||
|
||||
print &ui_table_row($text{'root_user'},
|
||||
$mysql_login ? "<tt>$mysql_login</tt>" : "<label>$text{'root_auto'}</label>");
|
||||
print &ui_table_row($text{'root_pass'},
|
||||
$mysql_pass ? "<tt>$mysql_pass</tt>" : &ui_text_color($text{'root_none'}, 'danger'));
|
||||
print &ui_table_row($text{'root_newpass1'},
|
||||
&ui_password("newpass1", undef, 20));
|
||||
print &ui_table_row($text{'root_newpass2'},
|
||||
&ui_password("newpass2", undef, 20));
|
||||
print &ui_table_row($text{'root_user'},
|
||||
$mysql_login ? "<tt>$mysql_login</tt>"
|
||||
: "<label>$text{'root_auto'}</label>");
|
||||
print &ui_table_row($text{'root_pass'},
|
||||
$mysql_pass ? "<tt>$mysql_pass</tt>"
|
||||
: &ui_text_color($text{'root_none'}, 'danger'));
|
||||
print &ui_table_row($text{'root_newpass1'},
|
||||
&ui_password("newpass1", undef, 20));
|
||||
print &ui_table_row($text{'root_newpass2'},
|
||||
&ui_password("newpass2", undef, 20));
|
||||
|
||||
print &ui_table_end();
|
||||
print &ui_form_end([ [ undef, $text{'root_ok'} ] ]);
|
||||
print &ui_table_end();
|
||||
print &ui_form_end([ [ undef, $text{'root_ok'} ] ]);
|
||||
}
|
||||
|
||||
&ui_print_footer("", $text{'index_return'});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
proftpd_path=/usr/sbin/proftpd
|
||||
proftpd_conf=/etc/proftpd.conf
|
||||
proftpd_conf=/etc/proftpd/proftpd.conf
|
||||
pid_file=/var/run/proftpd.pid
|
||||
start_cmd=systemctl start proftpd
|
||||
stop_cmd=systemctl stop proftpd
|
||||
|
||||
@@ -119,8 +119,7 @@ for($i=0; $i<@conf; $i++) {
|
||||
elsif ($1 eq $_[0]) {
|
||||
&print_tempfile(CONF, "[$_[1]]\n");
|
||||
foreach $k (grep {!/share_name/} (keys %share)) {
|
||||
&print_tempfile(CONF, "\t$k = ",
|
||||
&to_utf8($share{$k}),"\n");
|
||||
&print_tempfile(CONF, "\t$k = ", $share{$k},"\n");
|
||||
}
|
||||
#&print_tempfile(CONF, "\n");
|
||||
$replacing = 1;
|
||||
@@ -131,8 +130,7 @@ for($i=0; $i<@conf; $i++) {
|
||||
$first = 1;
|
||||
&print_tempfile(CONF, "[$_[1]]\n");
|
||||
foreach $k (grep {!/share_name/} (keys %share)) {
|
||||
&print_tempfile(CONF, "\t$k = ",
|
||||
&to_utf8($share{$k}),"\n");
|
||||
&print_tempfile(CONF, "\t$k = ", $share{$k},"\n");
|
||||
}
|
||||
&print_tempfile(CONF, "\n");
|
||||
$replacing = 1;
|
||||
@@ -209,6 +207,17 @@ else {
|
||||
}
|
||||
}
|
||||
|
||||
# decode_unicode_string(string)
|
||||
# Decodes a string from UTF-8 if needed
|
||||
sub decode_unicode_string
|
||||
{
|
||||
my ($str) = @_;
|
||||
eval "use Encode";
|
||||
if ($@) {
|
||||
return $str;
|
||||
}
|
||||
return decode('utf8', $str);
|
||||
}
|
||||
|
||||
# list_connections([share])
|
||||
# Uses the smbstatus program to return a list of connections a share. Each
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
require './samba-lib.pl';
|
||||
&ReadParse();
|
||||
&lock_file($config{'smb_conf'});
|
||||
&get_share($in{old_name}) if $in{old_name};
|
||||
&get_share($in{'old_name'}) if $in{'old_name'};
|
||||
|
||||
if ($in{'view'}) {
|
||||
# Redirect to view connections page
|
||||
@@ -22,9 +22,9 @@ elsif ($in{'delete'}) {
|
||||
# check acls
|
||||
|
||||
&error_setup("$text{'eacl_aviol'}ask_epass.cgi");
|
||||
if ($in{old_name}) {
|
||||
if ($in{'old_name'}) {
|
||||
&error("$text{'eacl_np'} $text{'eacl_pus'}")
|
||||
unless &can('rw', \%access, $in{old_name});
|
||||
unless &can('rw', \%access, $in{'old_name'});
|
||||
}
|
||||
else {
|
||||
&error("$text{'eacl_np'} $text{'eacl_pcrs'}") unless $access{'c_fs'};
|
||||
@@ -32,7 +32,7 @@ else {
|
||||
|
||||
&error_setup($text{'savefshare_fail'});
|
||||
# store share options
|
||||
if ($in{old_name} eq "global") {
|
||||
if ($in{'old_name'} eq "global") {
|
||||
$name = "global";
|
||||
}
|
||||
else {
|
||||
@@ -51,13 +51,13 @@ if ($name ne "global") {
|
||||
foreach (&list_shares()) {
|
||||
$exists{$_}++;
|
||||
}
|
||||
if (!$in{old_name} && $exists{$name}) {
|
||||
if (!$in{'old_name'} && $exists{$name}) {
|
||||
&error(&text('savefshare_exist', $name));
|
||||
}
|
||||
elsif ($in{old_name} ne $name && $exists{$name}) {
|
||||
elsif ($in{'old_name'} ne $name && $exists{$name}) {
|
||||
&error(&text('savefshare_exist', $name));
|
||||
}
|
||||
elsif ($name !~ /^[A-Za-z0-9_\$\-\. ]+$/) {
|
||||
elsif (&decode_unicode_string($name) !~ /^[\p{L}\p{N}_\$\-\.\s]+$/) {
|
||||
&error(&text('savefshare_mode', $name));
|
||||
}
|
||||
elsif ($name eq "global") { # unreachable code ? EB
|
||||
@@ -76,12 +76,12 @@ if ($in{'create'} eq "yes") {
|
||||
}
|
||||
|
||||
# Update config file
|
||||
if ($in{old_name}) {
|
||||
if ($in{'old_name'}) {
|
||||
# Changing an existing share
|
||||
&modify_share($in{old_name}, $name);
|
||||
if ($name ne $in{old_name}) {
|
||||
local $oldacl=$access{'ACLfs_' . $in{old_name}};
|
||||
&drop_samba_acl(\%access, $in{old_name});
|
||||
&modify_share($in{'old_name'}, $name);
|
||||
if ($name ne $in{'old_name'}) {
|
||||
local $oldacl=$access{'ACLfs_' . $in{'old_name'}};
|
||||
&drop_samba_acl(\%access, $in{'old_name'});
|
||||
&save_samba_acl($oldacl, \%access, $name);
|
||||
}
|
||||
}
|
||||
@@ -99,5 +99,5 @@ else {
|
||||
&save_samba_acl('rwvVsSpPnNoO', \%access, $name);
|
||||
}
|
||||
&unlock_file($config{'smb_conf'});
|
||||
&webmin_log($in{old_name} ? "save" : "create", "fshare", $name, \%in);
|
||||
&webmin_log($in{'old_name'} ? "save" : "create", "fshare", $name, \%in);
|
||||
&redirect("");
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
require './samba-lib.pl';
|
||||
&ReadParse();
|
||||
&lock_file($config{'smb_conf'});
|
||||
&get_share($in{old_name}) if $in{old_name};
|
||||
&get_share($in{'old_name'}) if $in{'old_name'};
|
||||
|
||||
if ($in{'view'}) {
|
||||
# Redirect to view connections page
|
||||
@@ -22,16 +22,16 @@ elsif ($in{'delete'}) {
|
||||
# check acls
|
||||
|
||||
&error_setup("$text{'eacl_aviol'}ask_epass.cgi");
|
||||
if ($in{old_name}) {
|
||||
if ($in{'old_name'}) {
|
||||
&error("$text{'eacl_np'} $text{'eacl_pus'}")
|
||||
unless &can('rw', \%access, $in{old_name});
|
||||
unless &can('rw', \%access, $in{'old_name'});
|
||||
}
|
||||
else {
|
||||
&error("$text{'eacl_np'} $text{'eacl_pcrs'}") unless $access{'c_ps'};
|
||||
}
|
||||
|
||||
&error_setup($text{'savepshare_fail'});
|
||||
if ($in{old_name} eq "global") {
|
||||
if ($in{'old_name'} eq "global") {
|
||||
$name = "global";
|
||||
}
|
||||
else {
|
||||
@@ -53,13 +53,13 @@ if ($name ne "global") {
|
||||
foreach (&list_shares()) {
|
||||
$exists{$_}++;
|
||||
}
|
||||
if (!$in{old_name} && $exists{$name}) {
|
||||
if (!$in{'old_name'} && $exists{$name}) {
|
||||
&error(&text('savepshare_exist', $name));
|
||||
}
|
||||
elsif ($in{old_name} ne $name && $exists{$name}) {
|
||||
elsif ($in{'old_name'} ne $name && $exists{$name}) {
|
||||
&error(&text('savepshare_exist', $name));
|
||||
}
|
||||
elsif ($name !~ /^[A-Za-z0-9_\$\-\. ]+$/) {
|
||||
elsif (&decode_unicode_string($name) !~ /^[\p{L}\p{N}_\$\-\.\s]+$/) {
|
||||
&error(&text('savepshare_name', $name));
|
||||
}
|
||||
elsif ($name eq "global") {
|
||||
@@ -68,12 +68,12 @@ if ($name ne "global") {
|
||||
}
|
||||
|
||||
# Update config file
|
||||
if ($in{old_name}) {
|
||||
if ($in{'old_name'}) {
|
||||
# Changing an existing share
|
||||
&modify_share($in{old_name}, $name);
|
||||
if ($name ne $in{old_name}) {
|
||||
local $oldacl=$access{'ACLps_' . $in{old_name}};
|
||||
&drop_samba_acl(\%access, $in{old_name});
|
||||
&modify_share($in{'old_name'}, $name);
|
||||
if ($name ne $in{'old_name'}) {
|
||||
local $oldacl=$access{'ACLps_' . $in{'old_name'}};
|
||||
&drop_samba_acl(\%access, $in{'old_name'});
|
||||
&save_samba_acl($oldacl, \%access, $name);
|
||||
}
|
||||
}
|
||||
@@ -83,6 +83,6 @@ else {
|
||||
&save_samba_acl('rwvVsSoO', \%access, $name);
|
||||
}
|
||||
&unlock_file($config{'smb_conf'});
|
||||
&webmin_log($in{old_name} ? "save" : "create", "pshare", $name, \%in);
|
||||
&webmin_log($in{'old_name'} ? "save" : "create", "pshare", $name, \%in);
|
||||
&redirect("");
|
||||
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
# setup-repos-nightly.sh
|
||||
# Configures Webmin development repository for RHEL and Debian systems (derivatives)
|
||||
|
||||
webmin_download="https://download.webmin.com"
|
||||
webmin_host="download.webmin.com"
|
||||
webmin_download="https://$webmin_host"
|
||||
webmin_download_nightly="https://builds.webmin.dev"
|
||||
webmin_key="developers-key.asc"
|
||||
webmin_key_download="$webmin_download/$webmin_key"
|
||||
@@ -163,11 +164,16 @@ rpm)
|
||||
echo " .. done"
|
||||
;;
|
||||
deb)
|
||||
# Remove our keys
|
||||
rm -f "/usr/share/keyrings/debian-$webmin_key_suffix.gpg" "/usr/share/keyrings/$repoid_debian_like-$webmin_key_suffix.gpg"
|
||||
# Install our keys
|
||||
echo " Installing Webmin key .."
|
||||
gpg --import $webmin_key 1>/dev/null 2>&1
|
||||
cat $webmin_key | gpg --dearmor > "/usr/share/keyrings/$repoid_debian_like-$webmin_key_suffix.gpg"
|
||||
echo " .. done"
|
||||
# Remove Webmin repo from sources.list
|
||||
sources_list=$(grep -v "$webmin_host" /etc/apt/sources.list)
|
||||
echo "$sources_list" > /etc/apt/sources.list
|
||||
# Create repo file
|
||||
echo " Setting up Webmin development repository .."
|
||||
echo "deb [signed-by=/usr/share/keyrings/$repoid_debian_like-$webmin_key_suffix.gpg] $webmin_download_nightly ./" >$debian_repo_file
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
# setup-repos.sh
|
||||
# Configures Webmin repository for RHEL and Debian systems (derivatives)
|
||||
|
||||
webmin_download="https://download.webmin.com"
|
||||
webmin_host="download.webmin.com"
|
||||
webmin_download="https://$webmin_host"
|
||||
webmin_key="developers-key.asc"
|
||||
webmin_key_download="$webmin_download/$webmin_key"
|
||||
webmin_key_suffix="webmin-developers"
|
||||
@@ -159,11 +160,16 @@ rpm)
|
||||
echo " .. done"
|
||||
;;
|
||||
deb)
|
||||
# Remove our keys
|
||||
rm -f "/usr/share/keyrings/debian-$webmin_key_suffix.gpg" "/usr/share/keyrings/$repoid_debian_like-$webmin_key_suffix.gpg"
|
||||
# Install our keys
|
||||
echo " Installing Webmin key .."
|
||||
gpg --import $webmin_key 1>/dev/null 2>&1
|
||||
cat $webmin_key | gpg --dearmor > "/usr/share/keyrings/$repoid_debian_like-$webmin_key_suffix.gpg"
|
||||
echo " .. done"
|
||||
# Remove Webmin repo from sources.list
|
||||
sources_list=$(grep -v "$webmin_host" /etc/apt/sources.list)
|
||||
echo "$sources_list" > /etc/apt/sources.list
|
||||
# Create repo file
|
||||
echo " Setting up Webmin repository .."
|
||||
echo "deb [signed-by=/usr/share/keyrings/$repoid_debian_like-$webmin_key_suffix.gpg] $webmin_download/download/newkey/repository stable contrib" >$debian_repo_file
|
||||
|
||||
45
switch_theme.cgi
Executable file
45
switch_theme.cgi
Executable file
@@ -0,0 +1,45 @@
|
||||
#!/usr/local/bin/perl
|
||||
# switch_theme.cgi
|
||||
# Change the theme for the current user if allowed
|
||||
|
||||
BEGIN { push(@INC, "."); };
|
||||
use WebminCore;
|
||||
|
||||
&init_config();
|
||||
&ReadParse();
|
||||
my $err = sub {
|
||||
&PrintHeader();
|
||||
print("<tt>Cannot change theme : $_[0]</tt>\n");
|
||||
exit(1);
|
||||
};
|
||||
# Check if in debug mode
|
||||
&$err("Debug mode is not enabled!")
|
||||
if (!$gconfig{'debug_enabled'} &&
|
||||
!$gconfig{'debug_theme_switcher'});
|
||||
# Check if allowed to change theme,
|
||||
# otherwise throw an error
|
||||
if (!&foreign_available('theme') &&
|
||||
!&foreign_available('change-user') &&
|
||||
!&foreign_available('webmin') &&
|
||||
!&foreign_available('acl')) {
|
||||
&$err("You are not allowed to change themes!");
|
||||
}
|
||||
# Check if the theme is known
|
||||
&$err("Theme identification is not known!")
|
||||
if (!$in{'theme'} || $in{'theme'} !~ /^[123]$/);
|
||||
# Check if the remote user is known
|
||||
&$err("Remote user is not known!") if (!$remote_user);
|
||||
# Define the theme
|
||||
my $themes = {
|
||||
'1' => 'authentic-theme',
|
||||
'2' => 'gray-theme',
|
||||
'3' => '' };
|
||||
my $theme = $themes->{$in{'theme'}};
|
||||
# Change the theme
|
||||
&foreign_require('acl');
|
||||
my @users = &acl::list_users();
|
||||
my ($user) = grep { $_->{'name'} eq $remote_user } @users;
|
||||
$user->{'theme'} = $theme;
|
||||
&acl::modify_user($user->{'name'}, $user);
|
||||
&restart_miniserv();
|
||||
&redirect(&get_webprefix() . "/");
|
||||
@@ -15,6 +15,7 @@ right_drivetemps=Drive temperatures
|
||||
right_driveerr=$1 errors!
|
||||
right_drivefailed=SMART check failed!
|
||||
right_cputype=$5, $8 cores
|
||||
right_cputype1=$5, $8 core
|
||||
right_load=$1 (1 min) $2 (5 mins) $3 (15 mins)
|
||||
right_cpuuse=CPU usage
|
||||
right_cpustats=$1% user, $2% kernel, $4% IO, $3% idle
|
||||
|
||||
@@ -107,8 +107,10 @@ if (&show_section('cpu')) {
|
||||
if ($info->{'load'}) {
|
||||
my @c = @{$info->{'load'}};
|
||||
if (@c > 3) {
|
||||
my $msg = $c[7] == 1 ? 'right_cputype1'
|
||||
: 'right_cputype';
|
||||
push(@table, { 'desc' => $text{'right_cpuinfo'},
|
||||
'value' => &text('right_cputype', @c) });
|
||||
'value' => &text($msg, @c) });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
33
ui-lib.pl
33
ui-lib.pl
@@ -1305,7 +1305,7 @@ return "<textarea class='ui_textarea' ".
|
||||
"rows='$rows' cols='$cols'".($wrap ? " wrap='$wrap'" : "").
|
||||
($dis ? " disabled='true'" : "").
|
||||
($tags ? " $tags" : "").">".
|
||||
&html_escape($value, 1).
|
||||
&html_escape($value).
|
||||
"</textarea>";
|
||||
}
|
||||
|
||||
@@ -2280,6 +2280,33 @@ for(var i=0; i<values.length; i++) {
|
||||
EOF
|
||||
}
|
||||
|
||||
=head2 ui_switch_theme_javascript()
|
||||
|
||||
The subroutine is designed to load JavaScript
|
||||
for switching themes using hotkeys.
|
||||
|
||||
Hotkeys are:
|
||||
To activate theme switch mode:
|
||||
Use: `Ctrl+Alt+T` (or `Control+Option+T` on Mac).
|
||||
|
||||
Immediately after, within 1 second, select your desired theme by pressing:
|
||||
- `Shift + A`: Authentic theme
|
||||
- `Shift + G`: Gray theme
|
||||
- `Shift + L`: Legacy theme.
|
||||
|
||||
=cut
|
||||
|
||||
sub ui_switch_theme_javascript
|
||||
{
|
||||
return &theme_ui_switch_theme_javascript(@_) if (defined(&theme_ui_switch_theme_javascript));
|
||||
return "" if (!$gconfig{'debug_enabled'} && !$gconfig{'debug_theme_switcher'});
|
||||
my $switch_script = "<script>const __webmin_webprefix__ = '@{[&get_webprefix()]}';</script>\n";
|
||||
my $webmin_version = &get_webmin_version();
|
||||
$webmin_version =~ s/\.//g;
|
||||
$switch_script .= "<script type=\"text/javascript\" src=\"@{[&get_webprefix()]}/unauthenticated/switch_theme.js?$webmin_version\"></script>\n";
|
||||
return $switch_script;
|
||||
}
|
||||
|
||||
####################### grid layout functions
|
||||
|
||||
=head2 ui_grid_table(&elements, columns, [width-percent], [&tds], [tabletags], [title])
|
||||
@@ -2779,8 +2806,8 @@ if (defined(&theme_ui_details)) {
|
||||
|
||||
my $rv;
|
||||
if (!$c->{'html'}) {
|
||||
$c->{'title'} = &html_escape($c->{'title'});
|
||||
$c->{'content'} = &html_escape($c->{'content'});
|
||||
$c->{'title'} = &html_escape($c->{'title'}, 1);
|
||||
$c->{'content'} = &html_escape($c->{'content'}, 1);
|
||||
}
|
||||
$c->{'class'} = " class=\"@{["e_escape($c->{'class'})]}\"" if($c->{'class'});
|
||||
$o = ' open' if ($o);
|
||||
|
||||
31
unauthenticated/switch_theme.js
Normal file
31
unauthenticated/switch_theme.js
Normal file
@@ -0,0 +1,31 @@
|
||||
(function () {
|
||||
let firstCombinationPressed = false;
|
||||
document.addEventListener("keydown", function (event) {
|
||||
// Check for Ctrl+Alt+T or Control+Option+T
|
||||
if (event.ctrlKey && event.altKey && event.keyCode === 84) {
|
||||
firstCombinationPressed = true;
|
||||
|
||||
// Set a timeout to reset the state after a short period (e.g., 1 seconds)
|
||||
setTimeout(() => {
|
||||
firstCombinationPressed = false;
|
||||
}, 1000);
|
||||
}
|
||||
if (firstCombinationPressed && event.shiftKey &&
|
||||
(event.keyCode === 65 || event.keyCode === 71 || event.keyCode === 76)) {
|
||||
const theme =
|
||||
// Shift + A : Authentic theme
|
||||
event.keyCode === 65 ? 1 :
|
||||
// Shift + G : Gray theme
|
||||
event.keyCode === 71 ? 2 :
|
||||
// Shift + L : Legacy theme.
|
||||
event.keyCode === 76 ? 3 : null;
|
||||
firstCombinationPressed = false;
|
||||
try {
|
||||
top.document.documentElement.style.filter = 'grayscale(100%) blur(0.5px) brightness(0.75) opacity(0.5)';
|
||||
top.document.documentElement.style.cursor = 'wait';
|
||||
top.document.documentElement.style.pointerEvents = 'none';
|
||||
} catch (error) {}
|
||||
top.location.href = __webmin_webprefix__ + "/switch_theme.cgi?theme=" + theme + "";
|
||||
}
|
||||
});
|
||||
})();
|
||||
@@ -242,7 +242,7 @@ if ($sorted_by && $sorted_by_sectioning_preserved) {
|
||||
}
|
||||
}
|
||||
|
||||
=head2 html_escape(string, [editor-mode])
|
||||
=head2 html_escape(string, [no-double-amp-escape])
|
||||
|
||||
Converts &, < and > codes in text to HTML entities, and returns the new string.
|
||||
This should be used when including data read from other sources in HTML pages.
|
||||
@@ -250,16 +250,16 @@ This should be used when including data read from other sources in HTML pages.
|
||||
=cut
|
||||
sub html_escape
|
||||
{
|
||||
my ($tmp, $editor_mode) = @_;
|
||||
my ($tmp, $nodblamp) = @_;
|
||||
if (!defined $tmp) {
|
||||
return ''; # empty string
|
||||
};
|
||||
# Before escaping ampersand use negative lookahead to see if occurrence
|
||||
# is not an HTML entity already to prevent double escaping
|
||||
$tmp =~ s/&(?!(([a-zA-Z]+)|(#|#x)\d+);)/&/g if (!$editor_mode);
|
||||
# In editor mode always escape all ampersands
|
||||
# is not an HTML entity already to prevent double escaping (optionally)
|
||||
$tmp =~ s/&(?!(([a-zA-Z]+)|(#|#x)\d+);)/&/g if ($nodblamp);
|
||||
# Always escape all ampersands by default
|
||||
# to make sure they are displayed per se
|
||||
$tmp =~ s/&/&/g if ($editor_mode);
|
||||
$tmp =~ s/&/&/g if (!$nodblamp);
|
||||
# Just always escape the following
|
||||
$tmp =~ s/</</g;
|
||||
$tmp =~ s/>/>/g;
|
||||
@@ -1119,6 +1119,8 @@ my $text = defined($tconfig{'cs_text'}) ? $tconfig{'cs_text'} :
|
||||
my $bgimage = defined($tconfig{'bgimage'}) ? "background=$tconfig{'bgimage'}" : "";
|
||||
my $dir = $current_lang_info->{'dir'} ? "dir=\"$current_lang_info->{'dir'}\"" : "";
|
||||
my $html_body = "<body bgcolor=\"#$bgcolor\" link=\"#$link\" vlink=\"#$link\" text=\"#$text\" style=\"height:100%\" $bgimage $tconfig{'inbody'} $dir $_[8]>\n";
|
||||
print &ui_switch_theme_javascript()
|
||||
if (defined(&ui_switch_theme_javascript));
|
||||
$html_body =~ s/\s+\>/>/g;
|
||||
print $html_body;
|
||||
print "<script>function _document_cookie_set_client_height(){document.cookie='client_height='+document.documentElement.clientHeight+'';}_document_cookie_set_client_height();window.onresize=_document_cookie_set_client_height</script>\n";
|
||||
@@ -2091,6 +2093,7 @@ code or preserve the original, old logic
|
||||
sub make_date
|
||||
{
|
||||
my ($secs, $only, $fmt) = @_;
|
||||
state $locale_military_name;
|
||||
$secs ||= 0;
|
||||
eval "use DateTime; use DateTime::Locale; use DateTime::TimeZone;";
|
||||
if (!$@ && $] > 5.011) {
|
||||
@@ -2115,7 +2118,35 @@ if (!$@ && $] > 5.011) {
|
||||
}
|
||||
}
|
||||
}
|
||||
my $locale = DateTime::Locale->load($locale_name);
|
||||
# Pre-process time locale
|
||||
my $locale_military_status = sub {
|
||||
return ($locale_military_name && $locale_military_name =~ /[a-z]/i) ? 2 :
|
||||
($locale_military_name == 1) ? 1 : 0;
|
||||
};
|
||||
# Allow locales with military time (in 24h format)
|
||||
my $locale_name_loaded = &$locale_military_status() == 2 ?
|
||||
$locale_military_name : $locale_name;
|
||||
my $locale_name_initial = $locale_name;
|
||||
if ($locale_name =~ /[a-z]{2}24$/i && &$locale_military_status() == 0) {
|
||||
$locale_name =~ s/^(.*?)24$/$1/;
|
||||
$locale_name_loaded = $locale_name;
|
||||
$locale_military_name = 1;
|
||||
}
|
||||
# Load given locale
|
||||
my $locale = DateTime::Locale->load($locale_name_loaded);
|
||||
# Create a new locale out of base locale
|
||||
if (&$locale_military_status() == 1) {
|
||||
my %locale_data = $locale->locale_data;
|
||||
$locale_data{'code'} = $locale_name_initial;
|
||||
# Force 24h time
|
||||
$locale_data{'glibc_date_1_format'} = '%a %b %e %H:%M:%S %Z %Y';
|
||||
$locale_data{'glibc_datetime_format'} = '%a %d %b %Y %T %Z';
|
||||
$locale_data{'glibc_time_format'} = '%T';
|
||||
DateTime::Locale->register_from_data(%locale_data);
|
||||
# Load newly cloned locale in 24h time format
|
||||
$locale_military_name = $locale_name_loaded = $locale_name_initial;
|
||||
$locale = DateTime::Locale->load($locale_name_loaded);
|
||||
}
|
||||
my $locale_format_full_tz = $locale->glibc_date_1_format; # Sat 20 Nov 2286 17:46:39 UTC
|
||||
my $locale_format_full = $locale->glibc_datetime_format; # Sat 20 Nov 2286 17:46:39
|
||||
my $locale_format_short = $locale->glibc_date_format; # 20/11/86
|
||||
@@ -2150,15 +2181,15 @@ if (!$@ && $] > 5.011) {
|
||||
# my $xxxx = $locale->full_date_format;
|
||||
my $data = {
|
||||
# Wed Feb 8 05:09:39 PM UTC 2023
|
||||
'full-tz-utc' => DateTime->from_epoch(locale => $locale_name, epoch => $secs)->strftime($locale_format_full_tz),
|
||||
'full-tz-utc' => DateTime->from_epoch(locale => $locale_name_loaded, epoch => $secs)->strftime($locale_format_full_tz),
|
||||
# Wed Feb 8 07:10:01 PM EET 2023
|
||||
'full-tz' => DateTime->from_epoch(locale => $locale_name, epoch => $secs, time_zone => $tz)->strftime($locale_format_full_tz),
|
||||
'full-tz' => DateTime->from_epoch(locale => $locale_name_loaded, epoch => $secs, time_zone => $tz)->strftime($locale_format_full_tz),
|
||||
# Wed 08 Feb 2023 07:11:26 PM EET
|
||||
'full' => DateTime->from_epoch(locale => $locale_name, epoch => $secs, time_zone => $tz)->strftime($locale_format_full),
|
||||
'full' => DateTime->from_epoch(locale => $locale_name_loaded, epoch => $secs, time_zone => $tz)->strftime($locale_format_full),
|
||||
# 02/08/2023
|
||||
'short' => DateTime->from_epoch(locale => $locale_name, epoch => $secs, time_zone => $tz)->strftime($locale_format_short),
|
||||
'short' => DateTime->from_epoch(locale => $locale_name_loaded, epoch => $secs, time_zone => $tz)->strftime($locale_format_short),
|
||||
# 07:12:07 PM
|
||||
'time' => DateTime->from_epoch(locale => $locale_name, epoch => $secs, time_zone => $tz)->strftime($locale_format_time),
|
||||
'time' => DateTime->from_epoch(locale => $locale_name_loaded, epoch => $secs, time_zone => $tz)->strftime($locale_format_time),
|
||||
'ago' => $ago,
|
||||
'tz' => $tz,
|
||||
'delimiter' => $locale_format_delimiter,
|
||||
@@ -2171,8 +2202,8 @@ if (!$@ && $] > 5.011) {
|
||||
|
||||
# %c alternative with full week and month and no seconds in time (complete)
|
||||
# Wednesday, February 8, 2023, 8:18 PM or 星期三, 2023年2月8日 20:18 or miércoles, 8 febrero 2023, 20:28
|
||||
$data->{'monthfull'} = DateTime->from_epoch(locale => $locale_name, epoch => $secs, time_zone => $tz)->strftime("%B");
|
||||
foreach (split(/\s+/, DateTime->from_epoch(locale => $locale_name, epoch => $secs, time_zone => $tz)->strftime("%A, %c"))) {
|
||||
$data->{'monthfull'} = DateTime->from_epoch(locale => $locale_name_loaded, epoch => $secs, time_zone => $tz)->strftime("%B");
|
||||
foreach (split(/\s+/, DateTime->from_epoch(locale => $locale_name_loaded, epoch => $secs, time_zone => $tz)->strftime("%A, %c"))) {
|
||||
if ($data->{'monthfull'} =~ /^$_/) {
|
||||
$data->{'complete'} .= "$data->{'monthfull'} "
|
||||
}
|
||||
@@ -2207,12 +2238,12 @@ if (!$@ && $] > 5.011) {
|
||||
@date = grep { /\%/ } @date;
|
||||
$locale_format_short = join($locale_format_delimiter, @date);
|
||||
}
|
||||
my $date_format_short = DateTime->from_epoch(locale => $locale_name, epoch => $secs, time_zone => $tz)->strftime($locale_format_short);
|
||||
my $date_format_short = DateTime->from_epoch(locale => $locale_name_loaded, epoch => $secs, time_zone => $tz)->strftime($locale_format_short);
|
||||
if (!ref($only) && $only) {
|
||||
return $date_format_short;
|
||||
}
|
||||
else {
|
||||
my $date_format_time = DateTime->from_epoch(locale => $locale_name, epoch => $secs, time_zone => $tz)->strftime($locale_format_time);
|
||||
my $date_format_time = DateTime->from_epoch(locale => $locale_name_loaded, epoch => $secs, time_zone => $tz)->strftime($locale_format_time);
|
||||
$date_format_time = $date_format_time;
|
||||
$date_format_time =~ s/(\d+):(\d+):(\d+)(.*?)/$1:$2$4/;
|
||||
if ($main::webmin_script_type eq 'web') {
|
||||
@@ -4274,12 +4305,11 @@ undef(@system_hostname) if ($nocache);
|
||||
return if ($nocache == 2);
|
||||
if (!$system_hostname[$m]) {
|
||||
if ($gconfig{'os_type'} ne 'windows') {
|
||||
# Try hostnamectl command on Linux
|
||||
if (&has_command("hostnamectl")) {
|
||||
my $hostname =
|
||||
&backquote_command("hostnamectl --static");
|
||||
chop($hostname);
|
||||
if ($? == 0 && $hostname =~ /\./) {
|
||||
# If systemd system try /etc/hostname straight away
|
||||
if (-d "/etc/systemd") {
|
||||
my $hostname = &read_file_contents("/etc/hostname");
|
||||
if ($hostname) {
|
||||
$hostname =~ s/\r|\n//g;
|
||||
$hostname =~ s/\..*$// if ($m);
|
||||
$system_hostname[$m] = $hostname;
|
||||
return $hostname;
|
||||
@@ -6272,7 +6302,8 @@ return { 'af' => 'Afrikaans',
|
||||
'en-SB' => 'English (Solomon Islands)',
|
||||
'en-SC' => 'English (Seychelles)',
|
||||
'en-SD' => 'English (Sudan)',
|
||||
'en-SE' => 'English (Sweden)',
|
||||
'en-SV' => 'English (Sweden)',
|
||||
'en-SE' => 'English (Northern Sami)',
|
||||
'en-SG' => 'English (Singapore)',
|
||||
'en-SH' => 'English (St Helena)',
|
||||
'en-SI' => 'English (Slovenia)',
|
||||
@@ -6289,6 +6320,7 @@ return { 'af' => 'Afrikaans',
|
||||
'en-UG' => 'English (Uganda)',
|
||||
'en-UM' => 'English (U.S. Outlying Islands)',
|
||||
'en-US' => 'English (United States)',
|
||||
'en-US24' => 'English (United States) (military time)',
|
||||
'en-VC' => 'English (St Vincent & the Grenadines)',
|
||||
'en-VG' => 'English (British Virgin Islands)',
|
||||
'en-VI' => 'English (U.S. Virgin Islands)',
|
||||
|
||||
@@ -5,6 +5,6 @@ updays=1
|
||||
cron_mode=0
|
||||
osdn=1
|
||||
warn_days=7
|
||||
letsencrypt_dns_wait=30
|
||||
letsencrypt_dns_wait=10
|
||||
letsencrypt_algo=rsa
|
||||
letsencrypt_reuse=1
|
||||
@@ -9,15 +9,14 @@ print $text{'lock_desc'},"<p>\n";
|
||||
print &ui_form_start("change_lock.cgi", "post");
|
||||
print &ui_table_start($text{'lock_header'}, undef, 2);
|
||||
|
||||
@grid = ( );
|
||||
push(@grid, &ui_radio("lockmode", int($gconfig{'lockmode'}),
|
||||
[ [ 0, $text{'lock_all'}."<br>" ],
|
||||
[ 1, $text{'lock_none'}."<br>" ],
|
||||
[ 2, $text{'lock_only'}."<br>" ],
|
||||
[ 3, $text{'lock_except'} ] ]));
|
||||
push(@grid, &ui_textarea("lockdirs",
|
||||
print &ui_table_row($text{'lock_mode'},
|
||||
&ui_radio("lockmode", int($gconfig{'lockmode'}),
|
||||
[ [ 0, $text{'lock_all'} ],
|
||||
[ 1, $text{'lock_none'} ],
|
||||
[ 2, $text{'lock_only'} ],
|
||||
[ 3, $text{'lock_except'} ] ])."<br>\n".
|
||||
&ui_textarea("lockdirs",
|
||||
join("\n", split(/\t+/, $gconfig{'lockdirs'})), 10, 60));
|
||||
print &ui_table_row(undef, &ui_grid_table(\@grid, 2), 2);
|
||||
|
||||
print &ui_table_end();
|
||||
print &ui_form_end([ [ "save", $text{'save'} ] ]);
|
||||
|
||||
@@ -832,6 +832,7 @@ third_title=Select Third Party Module
|
||||
lock_title=File Locking
|
||||
lock_desc=By default, Webmin will obtain a lock on any file that it modifies in order to prevent concurrent modification by multiple processes, which could lead to file corruption. This page allows you to selectively or totally disable locking if it is causing problems.
|
||||
lock_header=File locking settings
|
||||
lock_mode=Files for Webmin to lock
|
||||
lock_all=Lock all files
|
||||
lock_none=Never lock files
|
||||
lock_only=Only lock files and directories ..
|
||||
|
||||
@@ -35,7 +35,7 @@ foreach $url (@urls) {
|
||||
my $nver = $u->[1];
|
||||
$nver =~ s/^(\d+\.\d+)\..*$/$1/;
|
||||
next if (%info && $info{'version'} &&
|
||||
$info{'version'} >= $nver);
|
||||
&compare_version_numbers($info{'version'}, $nver) >= 0);
|
||||
|
||||
if ($in{'show'}) {
|
||||
# Just tell the user what would be done
|
||||
|
||||
@@ -1169,13 +1169,14 @@ my %miniserv;
|
||||
&get_miniserv_config(\%miniserv);
|
||||
&load_theme_library(); # So that UI functions work
|
||||
|
||||
# Need OS upgrade, but only once per day
|
||||
# XXX use a cache
|
||||
# Need OS upgrade, but only once per day or if the system was rebooted
|
||||
my $now = time();
|
||||
my $uptime = &get_system_uptime();
|
||||
if (&foreign_available("webmin")) {
|
||||
my %realos;
|
||||
my @st = stat($realos_cache_file);
|
||||
if (!@st || $now - $st[9] > 24*60*60) {
|
||||
if (!@st || $now - $st[9] > 24*60*60 ||
|
||||
$uptime && $now - $st[9] > $uptime) {
|
||||
%realos = &detect_operating_system(undef, 1);
|
||||
&write_file($realos_cache_file, \%realos);
|
||||
}
|
||||
@@ -1187,7 +1188,6 @@ if (&foreign_available("webmin")) {
|
||||
$realos{'os_type'} ne $gconfig{'os_type'}) &&
|
||||
$realos{'os_version'} && $realos{'os_type'} &&
|
||||
&foreign_available("webmin")) {
|
||||
|
||||
# Tell the user that OS version was updated
|
||||
push(@notifs,
|
||||
&ui_form_start("@{[&get_webprefix()]}/webmin/fix_os.cgi").
|
||||
@@ -2458,7 +2458,8 @@ foreach my $u (@$allupdates) {
|
||||
next if (!%info && !$missing);
|
||||
|
||||
# Skip if module has a version, and we already have it
|
||||
next if (%info && $info{'version'} && $info{'version'} >= $nver);
|
||||
next if (%info && $info{'version'} &&
|
||||
&compare_version_numbers($info{'version'}, $nver) >= 0);
|
||||
|
||||
# Skip if not supported on this OS
|
||||
my $osinfo = { 'os_support' => $u->[3] };
|
||||
|
||||
Reference in New Issue
Block a user