Compare commits

...

60 Commits

Author SHA1 Message Date
Ilia Ross
0457c1d1c0 Fix not to double encode on modify 2023-10-11 16:46:44 +03:00
Ilia Ross
59b944ebff Fix to properly test unicode names 2023-10-11 16:46:26 +03:00
Ilia Ross
2e63031e22 Fix not to use bare words 2023-10-11 16:43:44 +03:00
Ilia Ross
6137f285f2 Fix not to use bare words 2023-10-11 14:46:44 +03:00
Ilia Ross
04557f6e28 Fix to check for config dir instead on systemd system 2023-10-10 23:47:05 +03:00
Ilia Ross
d7de842f45 Fix to change version in caller 2023-10-10 23:36:52 +03:00
Ilia Ross
ba1aa5a498 Add missing change 2023-10-10 18:58:48 +03:00
Ilia Ross
b70a697e66 Update CHANGELOG.md 2023-10-10 18:54:53 +03:00
Jamie Cameron
c4c2c5c38e Add a 10 second timeout to handle the case where a client connects but doesn't start a valid SSL session 2023-10-09 22:55:18 -07:00
Jamie Cameron
bbe7e78516 Log timeout to wait for 2023-10-09 21:59:50 -07:00
Jamie Cameron
e40fc5568b Merge branch 'master' of github.com:webmin/webmin 2023-10-09 20:44:31 -07:00
Jamie Cameron
71d94982df Make UI for locking page more consistent 2023-10-09 20:44:24 -07:00
Ilia Ross
d48154d6a0 Fix reading hostname from file as hostnamectl depends on it anyway #2020 2023-10-09 21:14:31 +03:00
Ilia Ross
949f6fbf8d Merge branch 'master' of github.com:webmin/webmin 2023-10-09 18:43:05 +03:00
Ilia Ross
3c97fc5a32 Fix to check if UI function exists #2021 2023-10-09 18:41:19 +03:00
Jamie Cameron
4d4468e907 Prevent password change when it makes no sense https://github.com/virtualmin/virtualmin-gpl/issues/648 2023-10-07 08:51:50 -07:00
Jamie Cameron
fc5a638e24 Merge branch 'master' of github.com:webmin/webmin 2023-10-05 21:22:33 -07:00
Jamie Cameron
cf6a14b7a6 Version bump 2023-10-05 21:22:19 -07:00
Ilia Ross
6ddde41728 Revert "Wait a bit longer for DNS propogation"
This reverts commit 45845b8ca6.
2023-10-04 13:01:43 +03:00
Ilia Ross
5114308d0d Fix to never double escape HTML in display 2023-10-04 00:51:49 +03:00
Ilia Ross
2c325b1ee4 Add support for numbered list hotkey 2023-10-03 19:04:29 +03:00
Ilia Ross
e087bb718c Add support for bullet list hotkey 2023-10-03 18:55:38 +03:00
Ilia Ross
51bdd0d07e Fix to remove old Webmin repo in sources.list file
https://github.com/webmin/webmin/issues/1969#issuecomment-1742141240
2023-10-02 21:14:18 +03:00
Jamie Cameron
74fec8b171 Merge pull request #2013 from webmin/dev/theme-switcher
Add theme switcher using hotkeys
2023-10-01 15:21:47 -07:00
Ilia Ross
9d360f1c24 Fix not to enable on error_stack option 2023-10-01 21:34:50 +03:00
Jamie Cameron
148743894f The rm command should always be available 2023-10-01 11:15:23 -07:00
Ilia Ross
6b935f980c Fix to use ACL modify_user to change theme
https://github.com/webmin/webmin/pull/2013#discussion_r1342020745
2023-10-01 14:36:56 +03:00
Jamie Cameron
e751836684 Revert "Fix to use full path [build]"
This reverts commit b9449c213b.
2023-09-30 21:40:53 -07:00
Ilia Ross
b9449c213b Fix to use full path [build] 2023-10-01 03:04:27 +03:00
Jamie Cameron
a3c9770d4f Merge branch 'master' of github.com:webmin/webmin 2023-09-29 20:43:28 -07:00
Jamie Cameron
3c971dacc1 Copy allow-transfer directives up from global, because they aren't merged 2023-09-29 20:40:31 -07:00
Ilia Ross
ac1a73c154 Update CHANGELOG.md for 2.103 2023-09-29 17:23:52 +03:00
Ilia Ross
3a099fabec Fix to consider stand alone option as well 2023-09-29 15:32:07 +03:00
Ilia Ross
9a1e869a82 Fix to only enable theme switcher in debug mode 2023-09-29 12:56:23 +03:00
Ilia Ross
5c54c614e3 Fix comments to update hotkeys 2023-09-29 03:40:32 +03:00
Ilia Ross
cbdc843500 Add theme switcher using hotkeys 2023-09-29 03:24:14 +03:00
Ilia Ross
82fbca20e4 Merge branch 'master' of github.com:webmin/webmin 2023-09-29 00:22:13 +03:00
Ilia Ross
ef7dbb1f77 Fix to support hiding dot-files in File Manager 2023-09-29 00:21:50 +03:00
Jamie Cameron
4f15106fa9 Merge branch 'master' of github.com:webmin/webmin 2023-09-27 16:45:11 -07:00
Jamie Cameron
96bfc34247 Clean up code to set per-domain allow-transfer and also-notify 2023-09-27 16:36:21 -07:00
Ilia Ross
0289ceed5b Fix indent [build] 2023-09-26 21:24:12 +03:00
Ilia Ross
4e54ce3f85 Fix to correctly cache cloned locale with military time 2023-09-26 21:22:44 +03:00
Ilia Ross
73b2322597 Add English (United States) (military time) locale
https://github.com/webmin/authentic-theme/issues/1676#issuecomment-1735466651
2023-09-26 19:19:21 +03:00
Ilia Ross
05c7b6c3a3 Fix locale as sv isn't se
https://github.com/webmin/authentic-theme/issues/1676
2023-09-26 15:22:57 +03:00
Jamie Cameron
1bb70effea Use proper page flipper API 2023-09-25 20:04:11 -07:00
Jamie Cameron
590c27d202 Make option a bit nicer 2023-09-25 19:58:09 -07:00
Jamie Cameron
846dff2636 Clean up page flipper 2023-09-25 19:56:26 -07:00
Ilia Ross
b339c76fc7 Fix to always escape & by default 2023-09-25 19:19:52 +03:00
Ilia Ross
fbabecbe9e Fix support for new ZSTD and XZ formats 2023-09-24 22:12:59 +03:00
Ilia Ross
7706c0795e Add XZ and ZSTD compression ; add plain TAR archives 2023-09-24 21:21:08 +03:00
Ilia Ross
4be368c523 Fix elements overflow in shell module [build]
https://forum.virtualmin.com/t/webmin-command-shell-module-oddity-the-text-input-field-extends-past-screens-end/122741/9?u=ilia
2023-09-23 13:08:18 +03:00
Ilia Ross
b268c1bb66 Fix to import missing $bind_version vars 2023-09-20 19:33:41 +03:00
Jamie Cameron
b2f18fb784 dnssec-enabled has been obsoleted in new version https://github.com/virtualmin/virtualmin-gpl/issues/645 2023-09-19 21:13:38 -07:00
Jamie Cameron
34e3b4c027 Fix core vs cores https://github.com/webmin/webmin/issues/2008 2023-09-19 16:15:30 -07:00
Jamie Cameron
3c5edcf184 Merge branch 'master' of github.com:webmin/webmin 2023-09-18 22:04:15 -07:00
Jamie Cameron
33f4d7a008 Re-check OS after reboot https://github.com/webmin/webmin/issues/2004 2023-09-18 22:04:04 -07:00
Ilia Ross
2d182a2eea Fix ProFTPd config path 2023-09-19 01:07:41 +03:00
Jamie Cameron
7f06ccaf53 Merge pull request #2003 from webmin/dev/die-handler
Add die handler that stores the error from eval message
2023-09-17 22:26:05 -07:00
Jamie Cameron
d8fa7f26af Use proper function to compare versions https://github.com/virtualmin/virtualmin-gpl/issues/641 2023-09-17 19:39:40 -07:00
Jamie Cameron
aa6edf6c55 Preserve original permissions, ownership and file times after gunzipping 2023-09-17 19:20:26 -07:00
52 changed files with 443 additions and 154 deletions

View File

@@ -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

View File

@@ -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;

View File

@@ -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,

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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();

View File

@@ -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

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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')))

Binary file not shown.

After

Width:  |  Height:  |  Size: 764 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 764 B

View File

@@ -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

View File

@@ -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

View File

@@ -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) {

View File

@@ -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>

View File

@@ -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>

View File

@@ -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-&#45;&#45;comment option

View File

@@ -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

View File

@@ -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.

View File

@@ -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';

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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>";

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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

View File

@@ -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;

View File

@@ -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'});

View File

@@ -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

View File

@@ -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

View File

@@ -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("");

View File

@@ -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("");

View File

@@ -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

View 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
View 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() . "/");

View File

@@ -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

View File

@@ -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) });
}
}
}

View File

@@ -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=\"@{[&quote_escape($c->{'class'})]}\"" if($c->{'class'});
$o = ' open' if ($o);

View 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 + "";
}
});
})();

View File

@@ -1 +1 @@
2.102
2.103

View File

@@ -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+);)/&amp;/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+);)/&amp;/g if ($nodblamp);
# Always escape all ampersands by default
# to make sure they are displayed per se
$tmp =~ s/&/&amp;/g if ($editor_mode);
$tmp =~ s/&/&amp;/g if (!$nodblamp);
# Just always escape the following
$tmp =~ s/</&lt;/g;
$tmp =~ s/>/&gt;/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)',

View File

@@ -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

View File

@@ -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'} ] ]);

View File

@@ -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 ..

View File

@@ -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

View File

@@ -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] };