Merge pull request #897 from bergware/master

Bug fixes and enhancements
This commit is contained in:
tom mortensen
2021-07-16 09:44:23 -07:00
committed by GitHub
10 changed files with 86 additions and 91 deletions
+10 -3
View File
@@ -1,6 +1,13 @@
<?php
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
require_once "$docroot/webGui/include/Helpers.php";
// add translations
extract(parse_plugin_cfg('dynamix',true));
$login_locale = $display['locale'];
require_once "$docroot/webGui/include/Translations.php";
$var = parse_ini_file('state/var.ini');
$error = '';
@@ -16,12 +23,12 @@ if ($_SERVER['REQUEST_URI'] == '/logout') {
$params = session_get_cookie_params();
setcookie(session_name(), '', 0, '/', $params['domain'], $params['secure'], isset($params['httponly']));
}
$error = 'Successfully logged out';
$error = _('Successfully logged out');
}
$result = exec( "/usr/bin/passwd --status root");
if (($result === false) || (substr($result, 0, 6) !== "root P"))
include("$docroot/webGui/include/set-password.php");
include "$docroot/webGui/include/set-password.php";
else
include("$docroot/webGui/include/login.php");
include "$docroot/webGui/include/login.php";
?>
@@ -239,8 +239,8 @@ _(Template Authoring Mode)_:
:docker_authoring_mode_help:
_(Host access to custom networks)_:
: <select name="DOCKER_ALLOW_ACCESS" disabled>
<?=mk_option($dockercfg['DOCKER_ALLOW_ACCESS'], '', _('Disabled'),'selected')?>
: <select name="DOCKER_ALLOW_ACCESS">
<?=mk_option($dockercfg['DOCKER_ALLOW_ACCESS'], '', _('Disabled'))?>
<?=mk_option($dockercfg['DOCKER_ALLOW_ACCESS'], 'yes', _('Enabled'))?>
</select>
@@ -437,7 +437,7 @@ _(Docker LOG rotation)_:
:docker_log_rotation_active_help:
_(Host access to custom networks)_:
: <?=($dockercfg['DOCKER_ALLOW_ACCESS']||1) ? _('Disabled') : _('Enabled')?>
: <?=$dockercfg['DOCKER_ALLOW_ACCESS']=='yes' ? _('Enabled') : _('Disabled')?>
:docker_custom_network_active_help:
@@ -1001,7 +1001,7 @@ class DockerUtil {
}
public static function custom() {
return static::docker("network ls --filter driver='bridge' --filter driver='ipvlan' --format='{{.Name}}'|grep -v '^bridge$'",true);
return static::docker("network ls --filter driver='bridge' --filter driver='macvlan' --filter driver='ipvlan' --format='{{.Name}}' 2>/dev/null|grep -v '^bridge$'",true);
}
public static function network($custom) {
@@ -292,8 +292,9 @@ function xmlToCommand($xml, $create_paths=false) {
} elseif ($confType == 'port') {
switch ($driver[$xml['Network']]) {
case 'host':
case 'macvlan':
case 'ipvlan':
// Export ports as variable if network is set to host or ipvlan
// Export ports as variable if network is set to host or macvlan or ipvlan
$Variables[] = strtoupper(escapeshellarg($Mode.'_PORT_'.$containerConfig).'='.escapeshellarg($hostConfig));
break;
case 'bridge':
+2 -2
View File
@@ -316,8 +316,8 @@ foreach ($cpus as $pair) {
<?=mk_option("", "2", _("Errors info"))?>
<?=mk_option("", "3", _("Network traffic"))?>
</select></td>
<td><i class='view1'>_(Mode of operation)_</i><i class='view2'>_(Received packets)_</i><i class='view3'>_(Receive counters)_</i><i class='fa fa-fw fa-arrow-down red-text'></i>&nbsp;<i class='view4 red-text'>_(Inbound)_</i></td>
<td><i class='view1'></i><i class='view2'>_(Transmitted packets)_</i><i class='view3'>_(Transmit counters)_</i><i class='fa fa-fw fa-arrow-up orange-text'></i>&nbsp;<i class='view4 orange-text'>_(Outbound)_</i>
<td><i class='view1'>_(Mode of operation)_</i><i class='view2'>_(Received packets)_</i><i class='view3'>_(Receive counters)_</i><i class='fa fa-fw fa-arrow-down view4 red-text'></i>&nbsp;<i class='view4 red-text'>_(Inbound)_</i></td>
<td><i class='view1'></i><i class='view2'>_(Transmitted packets)_</i><i class='view3'>_(Transmit counters)_</i><i class='fa fa-fw fa-arrow-up view4 orange-text'></i>&nbsp;<i class='view4 orange-text'>_(Outbound)_</i>
<span class='view4' style='float:right;margin-right:24px'><select id='netline' class='auto' title="_(Select time frame)_" onchange='changeNetline(this.value)'>
<?=mk_option("","10", _("10 s"));?>
<?=mk_option("","30", _("30 s"));?>
+42 -55
View File
@@ -93,73 +93,60 @@ function updateDNS(button) {
};
$.post("/webGui/include/UpdateDNS.php",success).fail(failure);
}
function validatePorts(form) {
if (checkPorts(form,false)) form.submit();
}
function checkPorts(form,provision) {
var portsInUse = JSON.parse('<?=json_encode($portsInUse)?>');
if (provision) // SSL is already set to auto
var check = [{'key':'PORTSSL','port':'<?=$var['PORTSSL']?>','default':'443',name:'_(HTTPS port)_'}];
else
var check = [
{'key':'PORTTELNET','port':'<?=($var['USE_TELNET'] == 'no') ? "0" : $var['PORTTELNET']?>','default':'23',name:'_(TELNET port)_'},
{'key':'PORTSSH','port':'<?=($var['USE_SSH'] == 'no') ? "0" : $var['PORTSSH']?>','default':'22',name:'_(SSH port)_'},
{'key':'PORT','port':'<?=$var['PORT']?>','default':'80',name:'_(HTTP port)_'},
{'key':'PORTSSL','port':'<?=($var['USE_SSL'] == 'no') ? "0" : $var['PORTSSL']?>','default':'443',name:'_(HTTPS port)_'}
];
var list = [];
var dupeCheck = [];
var range = [];
for (var i=0; i < check.length; i++) {
var key = check[i]['key'];
var port = check[i]['port'];
var portdefault = check[i]['default'];
var name = check[i]['name'];
var item = $(form).find('input[name="'+key+'"]');
if (!item.val()) item.val(portdefault);
item.val(parseInt(item.val()));
if ($(item).is(':disabled')) continue;
if (provision)
var userPort = '<?=$var['PORTSSL']?>';
else {
var userPort = item.val();
if ( userPort < 1 || userPort > 65535 )
range.push(userPort+" ("+name+")");
}
dupeCheck.push(userPort);
if ( userPort !== port || provision) {
if ( portsInUse.includes(userPort) )
list.push(userPort+" ("+name+")");
function checkPorts(form) {
var portsInUse = JSON.parse('<?=json_encode($portsInUse)?>');
var range = [], list = [], duplicates = [];
var checks = [
{'key':"PORTTELNET", 'used':"<?=$var['USE_TELNET']=='yes'?>", 'port':"<?=$var['PORTTELNET']?>", 'default':"23" , 'name':"_(TELNET port)_"},
{'key':"PORTSSH" , 'used':"<?=$var['USE_SSH']=='yes'?>" , 'port':"<?=$var['PORTSSH']?>" , 'default':"22" , 'name':"_(SSH port)_"},
{'key':"PORT" , 'used':"<?=$var['USE_SSL']=='no'?>" , 'port':"<?=$var['PORT']?>" , 'default':"80" , 'name':"_(HTTP port)_"},
{'key':"PORTSSL" , 'used':"<?=$var['USE_SSL']!='no'?>" , 'port':"<?=$var['PORTSSL']?>" , 'default':"443", 'name':"_(HTTPS port)_"}
];
for (var i=0,check; check=checks[i]; i++) {
var item = $(form).find('input[name="'+check['key']+'"]');
if ($(item).is(':disabled')) continue;
item.val(parseInt(item.val()));
var current = (check['port']||check['default']).toString();
var userPort = (item.val()||check['default']).toString();
if (userPort < 1 || userPort > 65535) range.push(userPort+' ('+check['name']+')');
duplicates.push(userPort);
if (check['used'] == '1' && userPort != current) {
if (portsInUse.includes(userPort)) list.push(userPort+' ('+check['name']+')');
}
}
var duplicates = dupeCheck.reduce(function(acc, el, i, arr) {
duplicates = duplicates.reduce(function(acc, el, i, arr) {
if (arr.indexOf(el) !== i && acc.indexOf(el) < 0) acc.push(el); return acc;
}, []);
if ( range.length > 0 ) {
if (range.length > 0) {
swal({title:'_(Port out of range)_',text:sprintf('_(Port %s is out of range (minimum 1 maximum 65535))_',range.join(', ')),type:'error',showCancelButton:false,confirmButtonText:"_(OK)_"});
return false;
return;
}
if ( list.length > 0 ) {
if (list.length > 0) {
swal({title:'_(Port already in use)_',text:sprintf('_(Port %s is already in use by other services)_',list.join(', ')),type:'error',showCancelButton:false,confirmButtonText:"_(OK)_"});
return false;
return;
}
if ( duplicates.length > 0 ) {
if (duplicates.length > 0) {
swal({title:'_(Duplicate port entered)_',text:sprintf('_(Port %s is duplicated)_',duplicates.join(', ')),type:'error',showCancelButton:false,confirmButtonText:"_(OK)_"});
return false;
return;
}
return true;
form.submit();
}
function updateTELNET(form) {
form.PORTTELNET.disabled = form.USE_TELNET.value=="no";
form.PORTTELNET.disabled = form.USE_TELNET.value=='no';
}
function updateSSH(form) {
form.PORTSSH.disabled = form.USE_SSH.value=="no";
form.PORTSSH.disabled = form.USE_SSH.value=='no';
}
function updateSSL(form) {
form.PORTSSL.disabled = form.USE_SSL.value=="no";
form.PORT.disabled = form.USE_SSL.value=='yes';
form.PORTSSL.disabled = form.USE_SSL.value=='no';
}
$(function(){
var form = document.SSLSettings;
updateTELNET(form);
@@ -172,7 +159,7 @@ $(function(){
<input type="hidden" name="server_name" value="<?=$_SERVER['SERVER_NAME']?>">
<input type="hidden" name="server_addr" value="<?=$_SERVER['SERVER_ADDR']?>">
_(User 'root')_:
: [_(Manage)_](/Users/UserEdit?name=root)
: [_(Manage)_](/Settings/Users/ManagementAccess/UserEdit?name=root)
_(Start page)_:
: <select name="START_PAGE">
@@ -202,7 +189,7 @@ _(Use TELNET)_:
:mgmt_use_telnet_help:
_(TELNET port)_:
: <input type="number" name="PORTTELNET" class="narrow" min="1" max="65535" value="<?=htmlspecialchars($var['PORTTELNET']??23)?>">
: <input type="number" name="PORTTELNET" class="narrow" min="1" max="65535" value="<?=$var['PORTTELNET']?>" placeholder="23">
:mgmt_telnet_port_help:
@@ -215,7 +202,7 @@ _(Use SSH)_:
:mgmt_use_ssh_help:
_(SSH port)_:
: <input type="number" name="PORTSSH" class="narrow" min="1" max="65535" value="<?=htmlspecialchars($var['PORTSSH']??22)?>">
: <input type="number" name="PORTSSH" class="narrow" min="1" max="65535" value="<?=$var['PORTSSH']?>" placeholder="22">
:mgmt_ssh_port_help:
@@ -237,12 +224,12 @@ _(Use SSL/TLS)_:
:mgmt_use_ssl_tls_help:
_(HTTP port)_:
: <input type="number" name="PORT" class="narrow" min="1" max="65535" value="<?=htmlspecialchars($var['PORT']??80)?>">
: <input type="number" name="PORT" class="narrow" min="1" max="65535" value="<?=$var['PORT']?>" placeholder="80">
:mgmt_http_port_help:
_(HTTPS port)_:
: <input type="number" name="PORTSSL" class="narrow" min="1" max="65535" value="<?=htmlspecialchars($var['PORTSSL']??443)?>">
: <input type="number" name="PORTSSL" class="narrow" min="1" max="65535" value="<?=$var['PORTSSL']?>" placeholder="443">
:mgmt_https_port_help:
@@ -252,7 +239,7 @@ _(Local TLD)_:
:mgmt_local_tld_help:
&nbsp;
: <input type="button" value="_(Apply)_" onclick="validatePorts(this.form)" disabled><input type="button" value="_(Done)_" onclick="done()">
: <input type="button" value="_(Apply)_" onclick="checkPorts(this.form)" disabled><input type="button" value="_(Done)_" onclick="done()">
</form>
<div style="height:24px"></div>
@@ -295,7 +282,7 @@ _(CA-signed certificate file)_:
<?endif;?>
&nbsp;
: <button type="submit" name="changePorts" value="Provision" <?=$disabled_provision?> ><?=$provisionlabel?></button><button type="submit" name="changePorts" value="Delete" <?=$disabled_delete?> >_(Delete)_</button><button type="button" onclick="updateDNS(this)" <?=$disabled_updatedns?>>_(Update DNS)_</button>
: <button type="submit" name="changePorts" value="Provision" <?=$disabled_provision?>><?=$provisionlabel?></button><button type="submit" name="changePorts" value="Delete" <?=$disabled_delete?> >_(Delete)_</button><button type="button" onclick="updateDNS(this)" <?=$disabled_updatedns?>>_(Update DNS)_</button>
:mgmt_certificate_expiration_help:
+4 -4
View File
@@ -19,17 +19,17 @@ Nchan="wg_poller"
$etc = '/etc/wireguard';
$tmp = '/tmp/list.tmp';
unset($subnets,$hosts,$subnets6,$hosts6,$vtuns,$ipvlan,$docker);
unset($subnets,$hosts,$subnets6,$hosts6,$vtuns,$filter,$docker);
exec("ip -4 route show scope link|awk '/^[^d].+ dev (eth|br|bond)[0-9]+/{print \$1}'",$subnets);
exec("ip -4 addr show scope global|awk '/inet .+ (eth|br|bond)[0-9]+/{split(\$2,ip,\"/\");print ip[1]}'",$hosts);
exec("ip -6 route show type unicast|grep -Pv 'expires|shim-'|awk '/^[^dfm:]/{print \$1}'",$subnets6);
exec("ip -6 addr show scope global|grep -PA2 ': (eth|br|bond)\d+'|awk '/inet6 .+ (global|noprefixroute) \$/{split(\$2,ip,\"/\");print ip[1]}'",$hosts6);
exec("ls --indicator-style=none $etc/wg*.conf*|grep -Po wg[0-9]+",$vtuns);
exec("docker network ls --filter driver='ipvlan' --format='{{.Name}}' 2>/dev/null",$ipvlan);
exec("docker network ls --filter driver='macvlan' --filter driver='ipvlan' --format='{{.Name}}' 2>/dev/null",$filter);
// add subnets defined in Docker custom networks
if (count($ipvlan)) {
exec("docker network inspect --format='{{range .IPAM.Config}}{{println .Subnet}}{{end}}' ".implode(' ',$ipvlan),$docker);
if (count($filter)) {
exec("docker network inspect --format='{{range .IPAM.Config}}{{println .Subnet}}{{end}}' ".implode(' ',$filter),$docker);
foreach (array_filter($docker) as $network) {
if (strpos($network,'.')!==false && !in_array($network,$subnets)) $subnets[] = $network;
elseif (strpos($network,':')!==false && !in_array($network,$subnets6)) $subnets6[] = $network;
+2 -2
View File
@@ -11,7 +11,7 @@
*/
?>
<?
if (session_status()==PHP_SESSION_NONE) {
if (session_status()==PHP_SESSION_NONE && !isset($login_locale)) {
session_start();
session_write_close();
}
@@ -112,7 +112,7 @@ function translate($key) {
// main
$language = [];
$locale = $_SESSION['locale'];
$locale = $_SESSION['locale'] ?? $login_locale;
$return = "function _(t){return t;}";
$jscript = "$docroot/webGui/javascript/translate.en_US.js";
$root = "$docroot/languages/en_US/helptext.txt";
+8 -8
View File
@@ -58,7 +58,7 @@ if (!empty($_POST['username']) && !empty($_POST['password'])) {
}
if (count($fails) >= $maxfails) {
$error = 'Too many invalid login attempts';
$error = _('Too many invalid login attempts');
if (count($fails) == $maxfails)
exec("logger -t webGUI ".escapeshellarg("Ignoring login attempts for {$_POST['username']} from {$remote_addr}"));
@@ -85,7 +85,7 @@ if (!empty($_POST['username']) && !empty($_POST['password'])) {
}
// Invalid login
$error = 'Invalid Username or Password';
$error = _('Invalid Username or Password');
exec("logger -t webGUI ".escapeshellarg("Unsuccessful login user {$_POST['username']} from {$remote_addr}"));
}
@@ -388,25 +388,25 @@ $theme_dark = in_array($display['theme'],['black','gray']);
<form action="/login" method="POST">
<p>
<input name="username" type="text" placeholder="<?= 'Username' ?>" autocapitalize="none" autocomplete="off" autofocus required>
<input name="password" type="password" placeholder="<?= 'Password' ?>" required>
<input name="username" type="text" placeholder="<?=_('Username')?>" autocapitalize="none" autocomplete="off" autofocus required>
<input name="password" type="password" placeholder="<?=_('Password')?>" required>
</p>
<? if ($error) echo '<p class="error">'.$error.'</p>'; ?>
<?if ($error) echo "<p class='error'>$error</p>";?>
<script type="text/javascript">
document.cookie = "cookietest=1";
cookieEnabled = document.cookie.indexOf("cookietest=")!=-1;
document.cookie = "cookietest=1; expires=Thu, 01-Jan-1970 00:00:01 GMT";
if (!cookieEnabled) {
document.write('<p class="error">Browser cookie support required for login</p>');
document.write("<p class='error'><?=_('Browser cookie support required for Unraid OS webgui')?></p>");
}
</script>
<p>
<button type="submit" class="button button--small"><?= 'Login' ?></button>
<button type="submit" class="button button--small"><?=_('Login')?></button>
</p>
</form>
</div>
<p><a href="https://wiki.unraid.net/Manual/Troubleshooting#Lost_root_Password" target="_blank"><?= 'Password recovery' ?></a></p>
<p><a href="https://wiki.unraid.net/Manual/Troubleshooting#Lost_root_Password" target="_blank"><?=_('Password recovery')?></a></p>
</div>
</section>
</body>
+12 -12
View File
@@ -39,7 +39,6 @@ if (!empty($_POST['password']) && !empty($_POST['confirmPassword'])) {
return $POST_ERROR = $VALIDATION_MESSAGES['saveError'];
}
extract(parse_plugin_cfg('dynamix',true));
$THEME_DARK = in_array($display['theme'],['black','gray']);
?>
<!DOCTYPE html>
@@ -340,19 +339,20 @@ $THEME_DARK = in_array($display['theme'],['black','gray']);
<header>
<h1><?=$var['NAME']?></h1>
<h2><?=$var['COMMENT']?></h2>
<p><?= _('Please set a password for the root user account. Maximum length is 128 characters.') ?></p>
<p><?=_('Please set a password for the root user account')?>.</p>
<p><?=_('Max password length is 128 characters')?>.</p>
</header>
<noscript>
<p class="error"><?= _('The Unraid OS webgui requires JavaScript').'. '._('Please enable it').'.' ?></p>
<p class="error"><?= _('Please also ensure you have cookies enabled').'.' ?></p>
<p class="error"><?=_('The Unraid OS webgui requires JavaScript')?>. <?=_('Please enable it')?>.</p>
<p class="error"><?=_('Please also ensure you have cookies enabled')?>.</p>
</noscript>
<form action="/login" method="POST" class="js-validate w-full flex flex-col">
<label for="password"><?= _('Username') ?></label>
<input name="username" type="text" value="root" disabled title="<?= _('Username not changeable') ?>">
<input name="username" type="text" value="root" disabled title="<?=_('Username not changeable')?>">
<div class="flex flex-row items-center justify-between">
<label for="password" class="flex-auto"><?= _('Password') ?></label>
<button type="button" tabIndex="-1" class="js-pass-toggle pass-toggle" title="<?= _('Show Password') ?>">
<label for="password" class="flex-auto"><?=_('Password')?></label>
<button type="button" tabIndex="-1" class="js-pass-toggle pass-toggle" title="<?=_('Show Password')?>">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48">
<path d="M24,9A23.654,23.654,0,0,0,2,24a23.633,23.633,0,0,0,44,0A23.643,23.643,0,0,0,24,9Zm0,25A10,10,0,1,1,34,24,10,10,0,0,1,24,34Zm0-16a6,6,0,1,0,6,6A6,6,0,0,0,24,18Z"/>
<g class="js-pass-toggle-hide">
@@ -364,11 +364,11 @@ $THEME_DARK = in_array($display['theme'],['black','gray']);
</div>
<input id="password" name="password" type="password" max="128" autocomplete="new-password" autofocus required>
<label for="confirmPassword"><?= _('Confirm Password') ?></label>
<label for="confirmPassword"><?=_('Confirm Password')?></label>
<input id="confirmPassword" name="confirmPassword" type="password" max="128" autocomplete="new-password" required>
<p class="js-error error"><?= @$POST_ERROR ?></p>
<p class="js-error error"><?=@$POST_ERROR?></p>
<div class="flex justify-end">
<button disabled type="submit" class="js-submit button button--small"><?= _('Set Password') ?></button>
<button disabled type="submit" class="js-submit button button--small"><?=_('Set Password')?></button>
</div>
</form>
</div>
@@ -378,7 +378,7 @@ $THEME_DARK = in_array($display['theme'],['black','gray']);
document.cookie = "cookietest=1";
cookieEnabled = document.cookie.indexOf("cookietest=")!=-1;
document.cookie = "cookietest=1; expires=Thu, 01-Jan-1970 00:00:01 GMT";
if (!cookieEnabled) document.write('<p class="error">Browser cookie support required for Unraid OS webgui</p>');
if (!cookieEnabled) document.write("<p class='error'><?=_('Browser cookie support required for Unraid OS webgui')?></p>");
// Password toggling
const $passToggle = document.querySelector('.js-pass-toggle');
const $passToggleHideSvg = $passToggle.querySelector('.js-pass-toggle-hide');
@@ -390,7 +390,7 @@ $THEME_DARK = in_array($display['theme'],['black','gray']);
if (!hidePass) $passToggleHideSvg.classList.add('invisible'); // toggle svg elements
else $passToggleHideSvg.classList.remove('invisible');
$passInputs.forEach($el => $el.type = hidePass ? 'password' : 'text'); // change input types
$passToggle.setAttribute('title', hidePass ? "<?= _('Show Password') ?>" : "<?= _('Hide Password') ?>"); // change toggle title
$passToggle.setAttribute('title', hidePass ? "<?=_('Show Password')?>" : "<?=_('Hide Password')?>"); // change toggle title
});
// front-end validation
const $submitBtn = document.querySelector('.js-submit');