mirror of
https://github.com/webmin/webmin.git
synced 2026-08-21 14:30:41 +01:00
Compare commits
15 Commits
2.650
...
dev/req-tr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
463fcea730 | ||
|
|
a94ff2c49a | ||
|
|
ec78452e7b | ||
|
|
a7325b9087 | ||
|
|
cc4bb35dee | ||
|
|
aa2282778e | ||
|
|
1c9d57f5dd | ||
|
|
4ffa02d636 | ||
|
|
57ad5fa535 | ||
|
|
a3f5ea3381 | ||
|
|
2579cf54d9 | ||
|
|
fa06c02be5 | ||
|
|
d02f0b6cb5 | ||
|
|
81d44f8491 | ||
|
|
6135c01d57 |
14
CHANGELOG.md
14
CHANGELOG.md
@@ -1,5 +1,16 @@
|
|||||||
## Changelog
|
## Changelog
|
||||||
|
|
||||||
|
#### 2.652 (July, 2026)
|
||||||
|
* Fix to recognize hex numeric HTML entities to work in various elements
|
||||||
|
|
||||||
|
#### 2.651 (June 28, 2026)
|
||||||
|
* Fix Certbot-backed certificate requests and renewals to correctly parse PEM paths after issuance
|
||||||
|
* Fix live activation of Linux bond interfaces [#2777](https://github.com/webmin/webmin/pull/2777)
|
||||||
|
* Update the Authentic theme to the latest version with various improvements and fixes:
|
||||||
|
- Fix search-result all-items delete in File Manager
|
||||||
|
- Fix search-result delete ordering in File Manager
|
||||||
|
- Fix to speed up search-result deletion cleanup in File Manager
|
||||||
|
|
||||||
#### 2.650 (June 25, 2026)
|
#### 2.650 (June 25, 2026)
|
||||||
* Add new Systemd Services and Units module
|
* Add new Systemd Services and Units module
|
||||||
* Add new GRUB 2 Boot Loader module
|
* Add new GRUB 2 Boot Loader module
|
||||||
@@ -32,8 +43,9 @@
|
|||||||
* Fix PHP-FPM monitor on EL systems when using `/etc/php.ini` as the config file
|
* Fix PHP-FPM monitor on EL systems when using `/etc/php.ini` as the config file
|
||||||
* Fix RPC-only accounts to block browser/module access before module ACL checks
|
* Fix RPC-only accounts to block browser/module access before module ACL checks
|
||||||
* Fix reflected XSS in Webmin status messages
|
* Fix reflected XSS in Webmin status messages
|
||||||
* Fix authentication state handling for SSL certificate logins and proxied keep-alive requests
|
|
||||||
* Fix path validation in File Manager, package delete helpers, and Apache virtual host files
|
* Fix path validation in File Manager, package delete helpers, and Apache virtual host files
|
||||||
|
* Fix authentication state handling for SSL certificate logins and proxied keep-alive requests
|
||||||
|
* Update session handling to improve security, which will require users to re-authenticate after upgrading
|
||||||
* Update the Authentic theme to the latest version with various improvements and fixes:
|
* Update the Authentic theme to the latest version with various improvements and fixes:
|
||||||
- Add zooming to stats history graphs by holding shift and scrolling in the dashboard
|
- Add zooming to stats history graphs by holding shift and scrolling in the dashboard
|
||||||
- Add support for saving live stats history for up to 24 hours without performance impact
|
- Add support for saving live stats history for up to 24 hours without performance impact
|
||||||
|
|||||||
2
custom/safeacl
Normal file
2
custom/safeacl
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
edit=0
|
||||||
|
cmds=*
|
||||||
BIN
gray-theme/grub2/images/icon.gif
Normal file
BIN
gray-theme/grub2/images/icon.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.0 KiB |
BIN
gray-theme/kea-dhcp/images/icon.gif
Normal file
BIN
gray-theme/kea-dhcp/images/icon.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.8 KiB |
BIN
grub2/images/icon.gif
Normal file
BIN
grub2/images/icon.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.6 KiB |
BIN
kea-dhcp/images/icon.gif
Normal file
BIN
kea-dhcp/images/icon.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 311 B |
25
miniserv.pl
25
miniserv.pl
@@ -1542,16 +1542,25 @@ if ($headerhost) {
|
|||||||
$headerhost = undef if (!&check_ipaddress($headerhost) &&
|
$headerhost = undef if (!&check_ipaddress($headerhost) &&
|
||||||
!&check_ip6address($headerhost));
|
!&check_ip6address($headerhost));
|
||||||
}
|
}
|
||||||
# If trusted_proxies is configured, header-supplied client IP and SSL
|
# If trusted_proxies is configured, header-supplied client IP is only
|
||||||
# client info are only honored when the direct TCP peer is in that list.
|
# honored when the direct TCP peer is in that list. Proxied SSL client
|
||||||
# Otherwise drop them so an attacker reaching miniserv directly cannot
|
# cert headers carry authentication identity, so only honor those from
|
||||||
# spoof X-Forwarded-For or X-SSL-Client-* to bypass auth.
|
# an explicitly trusted proxy.
|
||||||
if ($config{'trust_real_ip'} && $config{'trusted_proxies'} ne '' &&
|
my @trusted_proxies = split(/\s+/, $config{'trusted_proxies'} || "");
|
||||||
!&ip_match($acptip, $localip,
|
my $trusted_proxy = @trusted_proxies &&
|
||||||
split(/\s+/, $config{'trusted_proxies'}))) {
|
&ip_match($acptip, $localip, @trusted_proxies);
|
||||||
|
my $trust_ssl_client_headers = $config{'trust_real_ip'} &&
|
||||||
|
!$config{'no_trust_ssl'} && $trusted_proxy;
|
||||||
|
if ($config{'trust_real_ip'} && @trusted_proxies && !$trusted_proxy) {
|
||||||
print DEBUG "handle_request: peer $acptip not in trusted_proxies; ".
|
print DEBUG "handle_request: peer $acptip not in trusted_proxies; ".
|
||||||
"ignoring forwarding and SSL client headers\n";
|
"ignoring forwarding headers\n";
|
||||||
$headerhost = undef;
|
$headerhost = undef;
|
||||||
|
}
|
||||||
|
if (!$trust_ssl_client_headers) {
|
||||||
|
print DEBUG "handle_request: ignoring SSL client headers from ".
|
||||||
|
"peer $acptip\n"
|
||||||
|
if ($header{'x-ssl-client-dn'} ||
|
||||||
|
$header{'x-ssl-client-verify'});
|
||||||
delete $header{'x-ssl-client-dn'};
|
delete $header{'x-ssl-client-dn'};
|
||||||
delete $header{'x-ssl-client-verify'};
|
delete $header{'x-ssl-client-verify'};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -258,7 +258,44 @@ if (&has_command("ip") && $a->{'virtual'} ne '' && !$a->{'up'}) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!&has_command("ifconfig") && &has_command("ip")) {
|
if (&has_command("ip") && $a->{'bond'} && $a->{'up'} && !$old) {
|
||||||
|
# Create the bond before assigning addresses to it.
|
||||||
|
my $bcmd = "ip link add ".quotemeta($a->{'name'})." type bond";
|
||||||
|
if (defined($a->{'mode'}) && $a->{'mode'} ne '') {
|
||||||
|
$bcmd .= " mode ".quotemeta(&bond_mode_name($a->{'mode'}));
|
||||||
|
}
|
||||||
|
if ($a->{'miimon'}) {
|
||||||
|
$bcmd .= " miimon ".quotemeta($a->{'miimon'});
|
||||||
|
}
|
||||||
|
if ($a->{'updelay'}) {
|
||||||
|
$bcmd .= " updelay ".quotemeta($a->{'updelay'});
|
||||||
|
}
|
||||||
|
if ($a->{'downdelay'}) {
|
||||||
|
$bcmd .= " downdelay ".quotemeta($a->{'downdelay'});
|
||||||
|
}
|
||||||
|
my $out = &backquote_logged("$bcmd 2>&1");
|
||||||
|
&error("Failed to create bond device : $out") if ($?);
|
||||||
|
foreach my $slave (grep { $_ ne '' } split(/\s+/, $a->{'partner'})) {
|
||||||
|
$bcmd = "ip link set dev ".quotemeta($slave)." down";
|
||||||
|
$out = &backquote_logged("$bcmd 2>&1");
|
||||||
|
&error("Failed to bring down bond slave : $out") if ($?);
|
||||||
|
$bcmd = "ip link set dev ".quotemeta($slave)." master ".
|
||||||
|
quotemeta($a->{'name'});
|
||||||
|
$out = &backquote_logged("$bcmd 2>&1");
|
||||||
|
&error("Failed to add bond slave : $out") if ($?);
|
||||||
|
$bcmd = "ip link set dev ".quotemeta($slave)." up";
|
||||||
|
$out = &backquote_logged("$bcmd 2>&1");
|
||||||
|
&error("Failed to bring up bond slave : $out") if ($?);
|
||||||
|
}
|
||||||
|
if ($a->{'primary'}) {
|
||||||
|
$bcmd = "ip link set dev ".quotemeta($a->{'name'}).
|
||||||
|
" type bond primary ".quotemeta($a->{'primary'});
|
||||||
|
$out = &backquote_logged("$bcmd 2>&1");
|
||||||
|
&error("Failed to set bond primary interface : $out") if ($?);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (($a->{'bond'} || !&has_command("ifconfig")) && &has_command("ip")) {
|
||||||
# For a real interface, activate or de-activate the link
|
# For a real interface, activate or de-activate the link
|
||||||
if ($a->{'virtual'} eq '' && $a->{'up'} && (!$old || !$old->{'up'})) {
|
if ($a->{'virtual'} eq '' && $a->{'up'} && (!$old || !$old->{'up'})) {
|
||||||
# Bring up
|
# Bring up
|
||||||
@@ -646,6 +683,19 @@ local $out = &backquote_logged("$cmd 2>&1");
|
|||||||
&error($out) if ($?);
|
&error($out) if ($?);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# bond_mode_name(mode)
|
||||||
|
# Convert Webmin's numeric bonding mode to the name expected by ip(8).
|
||||||
|
sub bond_mode_name
|
||||||
|
{
|
||||||
|
my ($mode) = @_;
|
||||||
|
my @modes = ("balance-rr", "active-backup", "balance-xor", "broadcast",
|
||||||
|
"802.3ad", "balance-tlb", "balance-alb");
|
||||||
|
if ($mode =~ /^\d+$/ && defined($modes[$mode])) {
|
||||||
|
return $modes[$mode];
|
||||||
|
}
|
||||||
|
return $mode eq "activebackup" ? "active-backup" : $mode;
|
||||||
|
}
|
||||||
|
|
||||||
# Tries to unload the module
|
# Tries to unload the module
|
||||||
# unload_module(name)
|
# unload_module(name)
|
||||||
sub unload_module
|
sub unload_module
|
||||||
|
|||||||
@@ -377,7 +377,7 @@ else {
|
|||||||
$err && &error("<pre>$err</pre>");
|
$err && &error("<pre>$err</pre>");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if ($in{'bond'}) {
|
if ($in{'bond'} && !&has_command("ip")) {
|
||||||
if (($gconfig{'os_type'} eq 'debian-linux') &&
|
if (($gconfig{'os_type'} eq 'debian-linux') &&
|
||||||
($gconfig{'os_version'} >= 5)) {}
|
($gconfig{'os_version'} >= 5)) {}
|
||||||
else {&load_module($b);}
|
else {&load_module($b);}
|
||||||
@@ -389,4 +389,3 @@ else {
|
|||||||
"bifc", $b->{'fullname'}, $b);
|
"bifc", $b->{'fullname'}, $b);
|
||||||
}
|
}
|
||||||
&redirect("list_ifcs.cgi?mode=boot");
|
&redirect("list_ifcs.cgi?mode=boot");
|
||||||
|
|
||||||
|
|||||||
@@ -617,4 +617,47 @@ is_deeply(\@commands,
|
|||||||
[ "ip addr del 10\\.211\\.55\\.25\\/24 dev enp0s5 2>&1" ],
|
[ "ip addr del 10\\.211\\.55\\.25\\/24 dev enp0s5 2>&1" ],
|
||||||
"Linux active virtual interface is removed when saved down");
|
"Linux active virtual interface is removed when saved down");
|
||||||
|
|
||||||
|
@commands = ( );
|
||||||
|
{
|
||||||
|
no warnings 'redefine';
|
||||||
|
no warnings 'once';
|
||||||
|
local *main::has_command = sub {
|
||||||
|
return $_[0] eq "ip" ? "/sbin/ip" :
|
||||||
|
$_[0] eq "ifconfig" ? "/sbin/ifconfig" : undef;
|
||||||
|
};
|
||||||
|
local *main::active_interfaces = sub {
|
||||||
|
return ( );
|
||||||
|
};
|
||||||
|
local *main::backquote_command = sub {
|
||||||
|
return "";
|
||||||
|
};
|
||||||
|
main::activate_interface({ 'name' => 'bond0',
|
||||||
|
'fullname' => 'bond0',
|
||||||
|
'virtual' => '',
|
||||||
|
'bond' => 1,
|
||||||
|
'partner' => 'eth0 eth1',
|
||||||
|
'mode' => '1',
|
||||||
|
'primary' => 'eth0',
|
||||||
|
'miimon' => '100',
|
||||||
|
'updelay' => '200',
|
||||||
|
'downdelay' => '200',
|
||||||
|
'address' => '10.0.0.2',
|
||||||
|
'netmask' => '255.255.255.0',
|
||||||
|
'address6' => [ ],
|
||||||
|
'netmask6' => [ ],
|
||||||
|
'up' => 1 });
|
||||||
|
}
|
||||||
|
is_deeply(\@commands,
|
||||||
|
[ "ip link add bond0 type bond mode active\\-backup miimon 100 updelay 200 downdelay 200 2>&1",
|
||||||
|
"ip link set dev eth0 down 2>&1",
|
||||||
|
"ip link set dev eth0 master bond0 2>&1",
|
||||||
|
"ip link set dev eth0 up 2>&1",
|
||||||
|
"ip link set dev eth1 down 2>&1",
|
||||||
|
"ip link set dev eth1 master bond0 2>&1",
|
||||||
|
"ip link set dev eth1 up 2>&1",
|
||||||
|
"ip link set dev bond0 type bond primary eth0 2>&1",
|
||||||
|
"ip link set dev bond0 up 2>&1",
|
||||||
|
"cd / ; ip addr add 10\\.0\\.0\\.2/24 dev bond0 2>&1" ],
|
||||||
|
"Linux active bond interface is created before assigning an address");
|
||||||
|
|
||||||
done_testing();
|
done_testing();
|
||||||
|
|||||||
@@ -38,6 +38,9 @@ subtest 'html_escape' => sub {
|
|||||||
is(main::html_escape('&'), '&amp;', 'default mode double-escapes &');
|
is(main::html_escape('&'), '&amp;', 'default mode double-escapes &');
|
||||||
is(main::html_escape('&', 1), '&', 'nodblamp preserves existing &');
|
is(main::html_escape('&', 1), '&', 'nodblamp preserves existing &');
|
||||||
is(main::html_escape('A', 1), 'A', 'nodblamp preserves numeric entity');
|
is(main::html_escape('A', 1), 'A', 'nodblamp preserves numeric entity');
|
||||||
|
is(main::html_escape('◦', 1), '◦', 'nodblamp preserves hex numeric entity');
|
||||||
|
is(main::html_escape('◦', 1), '◦', 'nodblamp preserves uppercase hex numeric entity');
|
||||||
|
is(main::html_escape('&#xZZ;', 1), '&#xZZ;', 'nodblamp escapes invalid hex numeric entity');
|
||||||
# Note: nodblamp's lookahead matches any &<letters>; as an entity, so
|
# Note: nodblamp's lookahead matches any &<letters>; as an entity, so
|
||||||
# made-up names like &x; are treated as entities and not re-escaped.
|
# made-up names like &x; are treated as entities and not re-escaped.
|
||||||
is(main::html_escape('&x;', 1), '&x;', 'nodblamp preserves arbitrary &word; shape');
|
is(main::html_escape('&x;', 1), '&x;', 'nodblamp preserves arbitrary &word; shape');
|
||||||
|
|||||||
50
t/webmin-letsencrypt-paths.t
Normal file
50
t/webmin-letsencrypt-paths.t
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
#!/usr/bin/perl
|
||||||
|
# Regression tests for Certbot output path parsing used by Webmin SSL.
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use Test::More;
|
||||||
|
use File::Basename qw(dirname);
|
||||||
|
use File::Spec;
|
||||||
|
|
||||||
|
our %config;
|
||||||
|
our $module_config_directory = "/etc/webmin/webmin";
|
||||||
|
|
||||||
|
sub has_command { return undef; }
|
||||||
|
|
||||||
|
my $script = File::Spec->rel2abs(
|
||||||
|
File::Spec->catfile(dirname(__FILE__), '..',
|
||||||
|
'webmin', 'letsencrypt-lib.pl'));
|
||||||
|
do $script or die "failed to load $script: $@ $!";
|
||||||
|
|
||||||
|
my $certbot_out = <<'EOF';
|
||||||
|
Successfully received certificate.
|
||||||
|
Certificate is saved at: /etc/letsencrypt/live/test.example/fullchain.pem
|
||||||
|
Key is saved at: /etc/letsencrypt/live/test.example/privkey.pem
|
||||||
|
This certificate expires on 2026-09-25.
|
||||||
|
EOF
|
||||||
|
|
||||||
|
is(main::get_letsencrypt_output_pem_path($certbot_out),
|
||||||
|
'/etc/letsencrypt/live/test.example/fullchain.pem',
|
||||||
|
'certbot output path stops at the first PEM path');
|
||||||
|
|
||||||
|
my $ipv6_out = <<'EOF';
|
||||||
|
Successfully received certificate.
|
||||||
|
Certificate is saved at: /etc/letsencrypt/live/2001:db8::1/fullchain.pem
|
||||||
|
Key is saved at: /etc/letsencrypt/live/2001:db8::1/privkey.pem
|
||||||
|
EOF
|
||||||
|
|
||||||
|
is(main::get_letsencrypt_output_pem_path($ipv6_out),
|
||||||
|
'/etc/letsencrypt/live/2001:db8::1/fullchain.pem',
|
||||||
|
'IPv6 certificate names can still contain colons');
|
||||||
|
|
||||||
|
my $wrapped_out = <<'EOF';
|
||||||
|
Certificate is saved at: /etc/letsencrypt/live/wrapped.example/
|
||||||
|
fullchain.pem
|
||||||
|
EOF
|
||||||
|
|
||||||
|
is(main::get_letsencrypt_output_pem_path($wrapped_out),
|
||||||
|
'/etc/letsencrypt/live/wrapped.example/fullchain.pem',
|
||||||
|
'wrapped PEM paths are normalized');
|
||||||
|
|
||||||
|
done_testing();
|
||||||
@@ -302,7 +302,7 @@ if (!defined $tmp) {
|
|||||||
};
|
};
|
||||||
# Before escaping ampersand use negative lookahead to see if occurrence
|
# Before escaping ampersand use negative lookahead to see if occurrence
|
||||||
# is not an HTML entity already to prevent double escaping (optionally)
|
# is not an HTML entity already to prevent double escaping (optionally)
|
||||||
$tmp =~ s/&(?!(([a-zA-Z]+)|(#|#x)\d+);)/&/g if ($nodblamp);
|
$tmp =~ s/&(?!([a-zA-Z]+|#\d+|#[xX][0-9A-Fa-f]+);)/&/g if ($nodblamp);
|
||||||
# Always escape all ampersands by default
|
# Always escape all ampersands by default
|
||||||
# to make sure they are displayed per se
|
# to make sure they are displayed per se
|
||||||
$tmp =~ s/&/&/g if (!$nodblamp);
|
$tmp =~ s/&/&/g if (!$nodblamp);
|
||||||
|
|||||||
@@ -3,13 +3,13 @@ standard_url=URL of standard modules list,3,On webmin.com
|
|||||||
third_url=URL of third party modules list,3,On webmin.com
|
third_url=URL of third party modules list,3,On webmin.com
|
||||||
cron_mode=Show update times as,1,0-Simple interface,1-Cron time selector
|
cron_mode=Show update times as,1,0-Simple interface,1-Cron time selector
|
||||||
warn_days=Days before password expiry to warn users,0,5
|
warn_days=Days before password expiry to warn users,0,5
|
||||||
line2=Let's Encrypt configuration,11
|
line2=ACME provider configuration,11
|
||||||
letsencrypt_cmd=Full path to Let's Encrypt client command,3,Find automatically
|
letsencrypt_cmd=Full path to ACME client command,3,Find automatically
|
||||||
letsencrypt_directory_url=Custom ACME directory URL,3,Use Let's Encrypt production
|
letsencrypt_directory_url=Custom ACME directory URL,3,Use default production server
|
||||||
letsencrypt_eab_kid=External Account Binding key ID,3,None
|
letsencrypt_eab_kid=External Account Binding key ID,3,None
|
||||||
letsencrypt_eab_hmac=External Account Binding HMAC key,12
|
letsencrypt_eab_hmac=External Account Binding HMAC key,12
|
||||||
letsencrypt_algo=Encryption algorithm for Let's Encrypt private key,1,rsa-RSA,ecdsa-ECC
|
letsencrypt_algo=Encryption algorithm for certificate private key,1,rsa-RSA,ecdsa-ECC
|
||||||
letsencrypt_dns_wait=Seconds to wait for Let's Encrypt DNS propagation,0,5
|
letsencrypt_dns_wait=Seconds to wait for ACME DNS propagation,0,5
|
||||||
letsencrypt_before=Command to run before Let's Encrypt request,0,60
|
letsencrypt_before=Command to run before ACME certificate request,0,60
|
||||||
letsencrypt_after=Command to run after Let's Encrypt request,0,60
|
letsencrypt_after=Command to run after ACME certificate request,0,60
|
||||||
letsencrypt_reuse=Re-use existing Let's Encrypt keys?,1,1-Yes,0-No
|
letsencrypt_reuse=Re-use existing certificate keys?,1,1-Yes,0-No
|
||||||
|
|||||||
@@ -2,4 +2,4 @@ standard_url=URL de la llista de mòduls estàndard,3,A webmin.com
|
|||||||
third_url=URL de la llista de mòduls de tercers,3,A webmin.com
|
third_url=URL de la llista de mòduls de tercers,3,A webmin.com
|
||||||
cron_mode=Mostra els temps d'actualització com,1,0-Interfície simple,1-Selector de temps cron
|
cron_mode=Mostra els temps d'actualització com,1,0-Interfície simple,1-Selector de temps cron
|
||||||
warn_days=Dies abans de l'expiració de la contrasenya per avisar els usuaris,0,5
|
warn_days=Dies abans de l'expiració de la contrasenya per avisar els usuaris,0,5
|
||||||
letsencrypt_cmd=Camí complet de l'ordre client de Let's Encrypt,3,Troba'l automàticament
|
letsencrypt_cmd=Camí complet de l'ordre client ACME,3,Troba'l automàticament
|
||||||
|
|||||||
@@ -2,4 +2,4 @@ standard_url=URL der Standardmodul-Liste,3,Von webmin.com
|
|||||||
third_url=URL der Drittanbieter-Webmin-Modulliste,3,Von webmin.com
|
third_url=URL der Drittanbieter-Webmin-Modulliste,3,Von webmin.com
|
||||||
cron_mode=Zeige Aktualisierungszeiten als,1,0-Einfache Anzeige,1-Cron-Zeit-Auswahl
|
cron_mode=Zeige Aktualisierungszeiten als,1,0-Einfache Anzeige,1-Cron-Zeit-Auswahl
|
||||||
warn_days=Tage vor Ablauf des Passworts zu warnen an Benutzer,0,5
|
warn_days=Tage vor Ablauf des Passworts zu warnen an Benutzer,0,5
|
||||||
letsencrypt_cmd=Voller Pfad zum Let's Encrypt Client-Befehl,0
|
letsencrypt_cmd=Voller Pfad zum ACME-Client-Befehl,0
|
||||||
|
|||||||
@@ -3,6 +3,6 @@ standard_url=URL de la liste des modules standard,3,webmin.com
|
|||||||
third_url=URL de la liste des modules non-standard,3,webmin.com
|
third_url=URL de la liste des modules non-standard,3,webmin.com
|
||||||
cron_mode=Afficher les heures de mise à jour comme,1,0-Interface simple,1-Sélecteur de temps Cron
|
cron_mode=Afficher les heures de mise à jour comme,1,0-Interface simple,1-Sélecteur de temps Cron
|
||||||
warn_days=Jours avant l'expiration du mot de passe pour avertir les utilisateurs,0,5
|
warn_days=Jours avant l'expiration du mot de passe pour avertir les utilisateurs,0,5
|
||||||
line2=Let's Encrypt configuration,11
|
line2=Configuration du fournisseur ACME,11
|
||||||
letsencrypt_cmd=Chemin complet de la commande client Let's Encrypt,3,Trouver automatiquement
|
letsencrypt_cmd=Chemin complet de la commande client ACME,3,Trouver automatiquement
|
||||||
letsencrypt_dns_wait=Quelques secondes à attendre pour la propagation DNS de Let's Encrypt,0,5
|
letsencrypt_dns_wait=Quelques secondes à attendre pour la propagation DNS ACME,0,5
|
||||||
|
|||||||
@@ -3,6 +3,6 @@ standard_url=標準モジュールリストに使用する URL,3,webmin.com
|
|||||||
third_url=サードパーティ製モジュールリストに使用する URL,3,webmin.com
|
third_url=サードパーティ製モジュールリストに使用する URL,3,webmin.com
|
||||||
cron_mode=アップデート時刻の表示方法,1,0-シンプル,1-Cron 選択方式
|
cron_mode=アップデート時刻の表示方法,1,0-シンプル,1-Cron 選択方式
|
||||||
warn_days=ユーザのパスワード期限切れの通知(日前),0,5
|
warn_days=ユーザのパスワード期限切れの通知(日前),0,5
|
||||||
line2=Let's Encrypt の設定,11
|
line2=ACME プロバイダーの設定,11
|
||||||
letsencrypt_cmd=Let's Encrypt クライアントのパス,3,自動設定
|
letsencrypt_cmd=ACME クライアントのパス,3,自動設定
|
||||||
letsencrypt_dns_wait=Let's Encrypt DNS の更新待機時間(秒),0,5
|
letsencrypt_dns_wait=ACME DNS の更新待機時間(秒),0,5
|
||||||
|
|||||||
@@ -447,7 +447,7 @@ ssl_letsrenew_days=days
|
|||||||
ssl_letsnotrenew=Only renew manually
|
ssl_letsnotrenew=Only renew manually
|
||||||
ssl_staging=Provider server
|
ssl_staging=Provider server
|
||||||
ssl_staging0=Production
|
ssl_staging0=Production
|
||||||
ssl_staging1=Staging (test only)
|
ssl_staging1=Test endpoint
|
||||||
ssl_acmeopts=Provider settings
|
ssl_acmeopts=Provider settings
|
||||||
ssl_acmeextra=Show advanced settings
|
ssl_acmeextra=Show advanced settings
|
||||||
ssl_acmedir=Custom ACME directory URL
|
ssl_acmedir=Custom ACME directory URL
|
||||||
@@ -1262,13 +1262,13 @@ letsencrypt_doing=Requesting a new certificate for $1, using the website directo
|
|||||||
letsencrypt_doingdns=Requesting a new certificate for $1, using DNS validation ..
|
letsencrypt_doingdns=Requesting a new certificate for $1, using DNS validation ..
|
||||||
letsencrypt_doingcertbot=Requesting a new certificate for $1, using the Certbot webserver ..
|
letsencrypt_doingcertbot=Requesting a new certificate for $1, using the Certbot webserver ..
|
||||||
letsencrypt_failed=.. request failed : $1
|
letsencrypt_failed=.. request failed : $1
|
||||||
letsencrypt_done=.. request succeeded!
|
letsencrypt_done=.. done
|
||||||
letsencrypt_show=The new certificate and private key were written to the following files :
|
letsencrypt_show=The new certificate and private key were written to the following files:
|
||||||
letsencrypt_cert=SSL certificate
|
letsencrypt_cert=SSL certificate
|
||||||
letsencrypt_key=SSL private key
|
letsencrypt_key=SSL private key
|
||||||
letsencrypt_chain=Chained CA certificate
|
letsencrypt_chain=Chained CA certificate
|
||||||
letsencrypt_webmin=Configuring Webmin to use new cert and key ..
|
letsencrypt_webmin=Configuring Webmin to use new cert and key ..
|
||||||
letsencrypt_wdone=.. done!
|
letsencrypt_wdone=.. done
|
||||||
letsencrypt_eaccountkey=Failed to generate account key : $1
|
letsencrypt_eaccountkey=Failed to generate account key : $1
|
||||||
letsencrypt_etiny=Failed to request certificate : $1
|
letsencrypt_etiny=Failed to request certificate : $1
|
||||||
letsencrypt_echain=Failed to download chained certificate : $1
|
letsencrypt_echain=Failed to download chained certificate : $1
|
||||||
|
|||||||
@@ -131,6 +131,20 @@ return &software::missing_install_link(
|
|||||||
"certbot", $text{'letsencrypt_certbot'}, $rlink, $rmsg);
|
"certbot", $text{'letsencrypt_certbot'}, $rlink, $rmsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# get_letsencrypt_output_pem_path(output)
|
||||||
|
# Returns the first certbot PEM path from command output, or undef
|
||||||
|
sub get_letsencrypt_output_pem_path
|
||||||
|
{
|
||||||
|
my ($out) = @_;
|
||||||
|
if ($out =~ /((?:\/usr\/local)?\/etc\/letsencrypt\/(?:live|archive)\/[a-zA-Z0-9\.\_\-:\/\*]+\.pem)/ ||
|
||||||
|
$out =~ /((?:\/usr\/local)?\/etc\/letsencrypt\/(?:live|archive)\/[a-zA-Z0-9\.\_\-:\/\r\n\* ]*?\.pem)/) {
|
||||||
|
my $full = $1;
|
||||||
|
$full =~ s/\s//g;
|
||||||
|
return $full;
|
||||||
|
}
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
# request_letsencrypt_cert(domain|&domains|&ips, webroot, [email], [keysize],
|
# request_letsencrypt_cert(domain|&domains|&ips, webroot, [email], [keysize],
|
||||||
# [request-mode], [use-staging], [account-email],
|
# [request-mode], [use-staging], [account-email],
|
||||||
# [key-type], [reuse-key],
|
# [key-type], [reuse-key],
|
||||||
@@ -387,14 +401,15 @@ if ($letsencrypt_cmd) {
|
|||||||
goto FAILED;
|
goto FAILED;
|
||||||
}
|
}
|
||||||
my ($full, $cert, $key, $chain);
|
my ($full, $cert, $key, $chain);
|
||||||
if ($out =~ /((?:\/usr\/local)?\/etc\/letsencrypt\/(?:live|archive)\/[a-zA-Z0-9\.\_\-:\/\r\n\* ]*\.pem)/) {
|
if ($full = &get_letsencrypt_output_pem_path($out)) {
|
||||||
# Output contained the full path
|
# Output contained the full path
|
||||||
$full = $1;
|
|
||||||
$full =~ s/\s//g;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
# Try searching common paths
|
# Try searching common paths
|
||||||
my @fulls = (glob("/etc/letsencrypt/live/$certname-*/cert.pem"),
|
my @fulls = grep { -r $_ } (
|
||||||
|
"/etc/letsencrypt/live/$certname/cert.pem",
|
||||||
|
glob("/etc/letsencrypt/live/$certname-*/cert.pem"),
|
||||||
|
"/usr/local/etc/letsencrypt/live/$certname/cert.pem",
|
||||||
glob("/usr/local/etc/letsencrypt/live/$certname-*/cert.pem"));
|
glob("/usr/local/etc/letsencrypt/live/$certname-*/cert.pem"));
|
||||||
if (@fulls) {
|
if (@fulls) {
|
||||||
my %stats = map { $_, [ stat($_) ] } @fulls;
|
my %stats = map { $_, [ stat($_) ] } @fulls;
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ else {
|
|||||||
$mode eq 'certbot' ? 'letsencrypt_doingcertbot' :
|
$mode eq 'certbot' ? 'letsencrypt_doingcertbot' :
|
||||||
'letsencrypt_doing',
|
'letsencrypt_doing',
|
||||||
"<tt>".&html_escape(join(", ", @doms))."</tt>",
|
"<tt>".&html_escape(join(", ", @doms))."</tt>",
|
||||||
"<tt>".&html_escape($webroot)."</tt>"),"<p>\n";
|
"<tt>".&html_escape($webroot)."</tt>"),"<br>\n";
|
||||||
my ($ok, $cert, $key, $chain) = &request_letsencrypt_cert(
|
my ($ok, $cert, $key, $chain) = &request_letsencrypt_cert(
|
||||||
\@doms, $webroot, undef, $size, $mode, $in{'staging'},
|
\@doms, $webroot, undef, $size, $mode, $in{'staging'},
|
||||||
undef, undef, undef, $in{'directory_url'},
|
undef, undef, undef, $in{'directory_url'},
|
||||||
@@ -142,7 +142,20 @@ else {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
# Worked, now copy to Webmin
|
# Worked, now copy to Webmin
|
||||||
print $text{'letsencrypt_done'},"<p>\n";
|
my @grid = ( $text{'letsencrypt_cert'}, $cert,
|
||||||
|
$text{'letsencrypt_key'}, $key );
|
||||||
|
push(@grid, $text{'letsencrypt_chain'}, $chain) if ($chain);
|
||||||
|
my $details = &html_escape($text{'letsencrypt_show'})."<p>\n".
|
||||||
|
&ui_grid_table(\@grid, 2);
|
||||||
|
print &ui_details({
|
||||||
|
'html' => 1,
|
||||||
|
'title' => &ui_tag('span',
|
||||||
|
&html_escape($text{'letsencrypt_done'}),
|
||||||
|
{ 'data-second-print' => undef }),
|
||||||
|
'content' => $details,
|
||||||
|
'class' => 'inline inlined',
|
||||||
|
});
|
||||||
|
print "<div data-x-br=\"\"></div>\n";
|
||||||
|
|
||||||
# Save the renewal schedule
|
# Save the renewal schedule
|
||||||
&save_renewal_only(\@doms, $webroot, $mode,
|
&save_renewal_only(\@doms, $webroot, $mode,
|
||||||
@@ -183,15 +196,11 @@ else {
|
|||||||
|
|
||||||
&webmin_log("letsencrypt");
|
&webmin_log("letsencrypt");
|
||||||
&restart_miniserv(1);
|
&restart_miniserv(1);
|
||||||
print $text{'letsencrypt_wdone'},"<p>\n";
|
print &ui_tag('span',
|
||||||
|
&html_escape($text{'letsencrypt_wdone'}),
|
||||||
|
{ 'data-second-print' => undef });
|
||||||
|
print "<br><div data-x-br=\"\"></div>\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
# Tell the user what was done
|
|
||||||
print $text{'letsencrypt_show'},"<p>\n";
|
|
||||||
my @grid = ( $text{'letsencrypt_cert'}, $cert,
|
|
||||||
$text{'letsencrypt_key'}, $key );
|
|
||||||
push(@grid, $text{'letsencrypt_chain'}, $chain) if ($chain);
|
|
||||||
print &ui_grid_table(\@grid, 2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&ui_print_footer("", $text{'index_return'});
|
&ui_print_footer("", $text{'index_return'});
|
||||||
|
|||||||
@@ -60,8 +60,12 @@ if (!-r $first_install_file || $miniserv{'login_script'} eq $record_login_cmd) {
|
|||||||
$miniserv{'failed_script'} = $record_failed_cmd;
|
$miniserv{'failed_script'} = $record_failed_cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Disable trusting SSL certs unless already enabled
|
# Disable trusting SSL certs unless already enabled. Legacy configs with
|
||||||
if (!$miniserv{'trust_real_ip'} && !defined($miniserv{'no_trust_ssl'})) {
|
# trust_real_ip but no trusted proxy cannot safely authenticate from
|
||||||
|
# proxied SSL client cert headers.
|
||||||
|
my @trusted_proxies = split(/\s+/, $miniserv{'trusted_proxies'} || "");
|
||||||
|
if ((!$miniserv{'trust_real_ip'} || !@trusted_proxies) &&
|
||||||
|
!defined($miniserv{'no_trust_ssl'})) {
|
||||||
$miniserv{'no_trust_ssl'} = 1;
|
$miniserv{'no_trust_ssl'} = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user