mirror of
https://github.com/unraid/webgui.git
synced 2026-01-01 15:10:19 -06:00
- Adjusted the structure of password input sections in UserAdd.page and UserEdit.page to ensure consistent layout and styling. - This change continues the effort to enhance visual consistency across the plugin.
351 lines
14 KiB
Plaintext
351 lines
14 KiB
Plaintext
Menu="UserList"
|
|
Title="Edit User"
|
|
Tag="user"
|
|
---
|
|
<?PHP
|
|
/* Copyright 2005-2023, Lime Technology
|
|
* Copyright 2012-2023, Bergware International.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License version 2,
|
|
* as published by the Free Software Foundation.
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*/
|
|
?>
|
|
<?
|
|
if (!array_key_exists($name, $users)) {
|
|
echo "<script>done()</script>";
|
|
exit;
|
|
}
|
|
$user = "/boot/config/plugins/dynamix/users/$name.png";
|
|
$void = "<img src='/webGui/images/user.png' width='48' height='48' id='image' onclick='$("#drop").click()' style='cursor:pointer' title='"._('Click to select PNG file')."'>";
|
|
$icon = "<i class='fa fa-trash top' title='"._('Restore default image')."' onclick='restore()'></i>";
|
|
$zxcvbn = file_exists('/boot/config/plugins/dynamix/zxcvbn.js');
|
|
|
|
$file = "/boot/config/ssh/root/authorized_keys";
|
|
$text = preg_replace(["/\r\n/","/\r/"],"\n", @file_get_contents($file) ?: '');
|
|
?>
|
|
<script src="<?autov('/webGui/javascript/jquery.filedrop.js')?>"></script>
|
|
<?if ($zxcvbn):?>
|
|
<script src="<?autov('/boot/config/plugins/dynamix/zxcvbn.js')?>" async></script>
|
|
<?endif;?>
|
|
<script>
|
|
var path = '/boot/config/plugins/dynamix/users';
|
|
var filename = '';
|
|
|
|
function base64(str) {
|
|
return window.btoa(unescape(encodeURIComponent(str)));
|
|
}
|
|
function showPassword() {
|
|
if ($('#showPass').hasClass('checked')) {
|
|
$('#showPass').removeClass('checked fa-eye-slash').addClass('fa-eye');
|
|
var type = 'password';
|
|
} else {
|
|
$('#showPass').addClass('checked fa-eye-slash').removeClass('fa-eye');
|
|
var type = 'text';
|
|
}
|
|
$('input[name="userPasswordGUI"]').attr('type',type);
|
|
$('input[name="userPasswordConfGUI"]').attr('type',type);
|
|
}
|
|
function checkPassword(form) {
|
|
if (form.userPasswordGUI.value.length > 128 || form.userPasswordConfGUI.value.length > 128) {
|
|
swal({title:"_(Password too long)_",text:"_(Use a password up to 128 characters)_",type:"error",html:true,confirmButtonText:"_(Ok)_"});
|
|
return false;
|
|
}
|
|
form.userPassword.value = base64(form.userPasswordGUI.value);
|
|
form.userPasswordConf.value = base64(form.userPasswordConfGUI.value);
|
|
form.userPasswordGUI.disabled = true;
|
|
form.userPasswordConfGUI.disabled = true;
|
|
return true;
|
|
}
|
|
function validatePassword(input) {
|
|
<?if ($zxcvbn):?>
|
|
var custom = ['unraid','limetech','lime-technology','bergware','squidly'];
|
|
var strength = ['Worst','Bad','Weak','Good','Strong'];
|
|
var emoji = ['😵','😩','😔','😀','😎'];
|
|
if (!input) {
|
|
$('#strength-bar').css('background-color','transparent');
|
|
$('#strength-text').html('');
|
|
$('.usage-disk.sys').addClass('none');
|
|
} else {
|
|
var bar = zxcvbn(input,custom);
|
|
switch (bar.score) {
|
|
case 0: $('#strength-bar').css('background-color','red'); break;
|
|
case 1: $('#strength-bar').css('background-color','yellow'); break;
|
|
case 2: $('#strength-bar').css('background-color','orange'); break;
|
|
case 3: $('#strength-bar').css('background-color','blue'); break;
|
|
case 4: $('#strength-bar').css('background-color','green'); break;
|
|
}
|
|
$('#strength-bar').css('width',Math.min(input.length*100/64,100)+'%');
|
|
$('#strength-text').html(emoji[bar.score]+' '+strength[bar.score]+'. '+bar.feedback.warning);
|
|
$('.usage-disk.sys').removeClass('none');
|
|
}
|
|
<?endif;?>
|
|
}
|
|
function restore() {
|
|
// restore original image and activate APPLY button
|
|
$('#dropbox').html("<?=$void?>");
|
|
$('input[name="userDesc"]').trigger('change');
|
|
filename = 'reset';
|
|
}
|
|
function upload(remove) {
|
|
// save or delete upload when APPLY is pressed
|
|
if (remove || filename=='reset') {
|
|
$.post("/webGui/include/FileUpload.php",{cmd:'delete',path:path,filename:'<?=addslashes(htmlspecialchars($name))?>.png'});
|
|
} else if (filename) {
|
|
$.post("/webGui/include/FileUpload.php",{cmd:'save',path:path,filename:filename,output:'<?=addslashes(htmlspecialchars($name))?>.png'});
|
|
}
|
|
}
|
|
function checkKey(form) {
|
|
// check syntax of ssh keys
|
|
var rows = form.text.value.split('\n');
|
|
for (var i=0,row; row=rows[i]; i++) {
|
|
if (row.search(/^(ssh-dss AAAAB3NzaC1kc3|ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNT|sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb2|ssh-ed25519 AAAAC3NzaC1lZDI1NTE5|sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29t|ssh-rsa AAAAB3NzaC1yc2)[0-9A-Za-z+/]+[=]{0,3}(\s.*)?$/)==-1) {
|
|
swal({title:"_(Invalid Key)_",text:"["+(i+1)+"] "+row.split(' ')[0]+": _(Syntax of the key is incorrect)_!",type:"error",html:true,confirmButtonText:"_(Ok)_"});
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
$(function(){
|
|
var dropbox = $('#dropbox');
|
|
// attach the drag-n-drop feature to the 'dropbox' element
|
|
dropbox.filedrop({
|
|
maxfiles:1,
|
|
maxfilesize:512, // KB
|
|
url:'/webGui/include/FileUpload.php',
|
|
data:{"csrf_token":"<?=$var['csrf_token']?>"},
|
|
beforeEach:function(file) {
|
|
if (!file.type.match(/^image\/png/)) {
|
|
swal({title:"Warning",text:"_(Only PNG images are allowed)_!",type:"warning",html:true,confirmButtonText:"_(Ok)_"});
|
|
return false;
|
|
}
|
|
},
|
|
error: function(error, file, i) {
|
|
switch (error) {
|
|
case 'BrowserNotSupported':
|
|
swal({title:"_(Browser error)_",text:"_(Your browser does not support HTML5 file uploads)_!",type:"error",html:true,confirmButtonText:"_(Ok)_"});
|
|
break;
|
|
case 'TooManyFiles':
|
|
swal({title:"_(Too many files)_",text:"_(Please select one file only)_!",html:true,type:"error"});
|
|
break;
|
|
case 'FileTooLarge':
|
|
swal({title:"_(File too large)_",text:"_(Maximum file upload size is 512K)_ (524,288 _(bytes)_)",type:"error",html:true,confirmButtonText:"_(Ok)_"});
|
|
break;
|
|
}
|
|
},
|
|
uploadStarted:function(i,file,count) {
|
|
var image = $('img', $(dropbox));
|
|
var reader = new FileReader();
|
|
image.width = 48;
|
|
image.height = 48;
|
|
reader.onload = function(e){image.attr('src',e.target.result);};
|
|
reader.readAsDataURL(file);
|
|
},
|
|
uploadFinished:function(i,file,response) {
|
|
if (response == 'OK 200') {
|
|
if (!filename || filename=='reset') $(dropbox).append("<?=$icon?>");
|
|
$('input[name="userDesc"]').trigger('change');
|
|
filename = file.name;
|
|
} else {
|
|
swal({title:"_(Upload error)_",text:response,type:"error",html:true,confirmButtonText:"_(Ok)_"});
|
|
}
|
|
}
|
|
});
|
|
// simulate a drop action when manual file selection is done
|
|
$('#drop').bind('change', function(e) {
|
|
var files = e.target.files;
|
|
if ($('#dropbox').triggerHandler({type:'drop',dataTransfer:{files:files}})==false) e.stopImmediatePropagation();
|
|
});
|
|
// auto size the textarea
|
|
$('form').find('textarea').on('input change',function(){
|
|
$(this).prop('rows',Math.max(($(this).val().match(/\n/g)||[]).length+1,10));
|
|
$('form').find('input[value="_(Save)_"]').prop('disabled',false);
|
|
});
|
|
});
|
|
</script>
|
|
<div class="spinner fixed"></div>
|
|
<form markdown="1" method="POST" action="/update.htm" target="progressFrame" onsubmit="upload(<?=$name=="root" ? 'false' : 'this.confirmDelete.checked'?>)">
|
|
<input type="hidden" name="userName" value="<?=htmlspecialchars($name)?>">
|
|
|
|
_(User name)_:
|
|
: <?=htmlspecialchars($name)?>
|
|
|
|
_(Description)_:
|
|
: <input type="text" name="userDesc" maxlength="64" value="<?=htmlspecialchars($users[$name]['desc'])?>" pattern='[^&:"]*'>
|
|
|
|
:user_edit_description_help:
|
|
|
|
_(Custom image)_:
|
|
: <span>
|
|
<span id="dropbox">
|
|
<?if (file_exists($user)):?>
|
|
<img src="<?=autov($user)?>" id="image" width="48" height="48" onclick="$('#drop').click()" style="cursor:pointer" title="_(Click to select PNG file)_"><?=$icon?>
|
|
<?else:?>
|
|
<?=$void?>
|
|
<?endif;?>
|
|
</span>
|
|
</span>
|
|
<em>_(Drag-n-drop a PNG file or click the image at the left)_</em><input type="file" id="drop" accept="image/png" style="display:none">
|
|
|
|
:user_edit_custom_image_help:
|
|
|
|
<?if ($name=="root"):?>
|
|
|
|
<?else:?>
|
|
_(Delete)_<input type="checkbox" name="confirmDelete" onChange="chkDelete(this.form, this.form.cmdUserEdit)">
|
|
<?endif;?>
|
|
: <span class="inline-block">
|
|
<input type="submit" name="cmdUserEdit" value="_(Apply)_" onclick="if (this.value=='_(Delete)_') this.value='Delete'; else this.value='Apply';" disabled>
|
|
<input type="button" value="_(Done)_" onclick="done('UserEdit')">
|
|
</span>
|
|
</form>
|
|
|
|
<form markdown="1" method="POST" action="/update.htm" onsubmit="return checkPassword(this)" target="progressFrame">
|
|
<input type="hidden" name="userName" value="<?=htmlspecialchars($name)?>">
|
|
|
|
_(Password)_:
|
|
: <span class="flex flex-row items-center gap-2">
|
|
<input type="hidden" name="userPassword" value="">
|
|
<input type="password" name="userPasswordGUI" maxlength="129" autocomplete="new-password" onKeyUp="validatePassword(this.value);this.form.cmdUserEdit.disabled=(this.form.userPasswordGUI.value != this.form.userPasswordConfGUI.value);">
|
|
<i id="showPass" class="fa fa-eye" style="cursor:pointer" title="_(Show / Hide password)_" onclick="showPassword()"></i>
|
|
<span>
|
|
<span class="usage-disk sys none">
|
|
<span id="strength-bar" style="width:0"></span>
|
|
<span></span>
|
|
</span>
|
|
<span id="strength-text"></span>
|
|
</span>
|
|
</span>
|
|
|
|
:user_password_help:
|
|
|
|
_(Retype password)_:
|
|
: <input type="hidden" name="userPasswordConf" value="">
|
|
<input type="password" name="userPasswordConfGUI" maxlength="129" autocomplete="new-password" onKeyUp="this.form.cmdUserEdit.disabled=(this.form.userPasswordGUI.value != this.form.userPasswordConfGUI.value);">
|
|
|
|
|
|
: <span class="inline-block">
|
|
<input type="submit" name="cmdUserEdit" value="_(Change)_" onclick="this.value='Change'" disabled>
|
|
<input type="button" value="_(Done)_" onclick="done('UserEdit')">
|
|
</span>
|
|
</form>
|
|
|
|
<?if ($name == 'root'):?>
|
|
<form markdown="1" method="POST" action="/update.php" onsubmit="return checkKey(this)" target="progressFrame">
|
|
<input type="hidden" name="#include" value="/webGui/include/update.file.php">
|
|
<input type="hidden" name="#file" value="<?=$file;?>">
|
|
|
|
_(SSH authorized keys)_:
|
|
: <textarea class="font-mono" spellcheck="false" cols="80" rows="<?=max(substr_count($text,"\n")+1,10)?>" maxlength="16384" name="text"><?=htmlspecialchars($text)?></textarea>
|
|
|
|
|
|
: <span class="inline-block">
|
|
<input type="submit" value="_(Save)_" disabled>
|
|
<input type="button" value="_(Done)_" onclick="done()">
|
|
</span>
|
|
|
|
</form>
|
|
<?endif;?>
|
|
|
|
<?if ($name != 'root' && $var['shareSMBEnabled'] != 'no'):?>
|
|
<script>
|
|
var users = {};
|
|
var security = {};
|
|
var readList = {};
|
|
var writeList = {};
|
|
<?
|
|
$rw = 'read-write';
|
|
$ro = 'read-only';
|
|
$no = 'no-access';
|
|
foreach ($users as $user) {
|
|
$idx = $user['idx'];
|
|
if ($idx) echo "users[\"{$user['name']}\"]='$idx';\n";
|
|
}
|
|
foreach ($shares as $share => $data) {
|
|
echo "security[\"$share\"]=\"{$sec[$share]['security']}\";\n";
|
|
echo "readList[\"$share\"]=\"{$sec[$share]['readList']}\";\n";
|
|
echo "writeList[\"$share\"]=\"{$sec[$share]['writeList']}\";\n";
|
|
}
|
|
?>
|
|
function updateAccess(form,data,n,i) {
|
|
var name = "<?=$name?>";
|
|
if (data) {
|
|
if (n<i) {
|
|
$.post('/update.htm',data[n], function(){setTimeout(function(){updateAccess(form,data,++n,i);},3000);});
|
|
} else {
|
|
$('div.spinner.fixed').hide();
|
|
$('input[value="Reset"]').val('Done').prop('disabled',false).prop('onclick',null).off('click').click(function(){done('UserEdit');});
|
|
}
|
|
} else {
|
|
var data = [], i = 0;
|
|
$(form).find('select').each(function(){
|
|
if ($(this).prop('id')) {
|
|
var share = decodeURI($(this).prop('id'));
|
|
var read = readList[share].split(',');
|
|
var write = writeList[share].split(',');
|
|
var access = '';
|
|
data[i] = {};
|
|
data[i]['shareName'] = share;
|
|
data[i]['userAccess.0'] = '<?=$no?>';
|
|
for (var user in users) {
|
|
var idx = users[user];
|
|
switch (security[share]) {
|
|
case 'public':
|
|
access = '<?=$rw?>';
|
|
break;
|
|
case 'secure':
|
|
if (user == name) access = $(this).val();
|
|
else access = write.includes(user) ? '<?=$rw?>' : '<?=$ro?>';
|
|
break;
|
|
case 'private':
|
|
if (user == name) access = $(this).val();
|
|
else access = write.includes(user) ? '<?=$rw?>' : (read.includes(user) ? '<?=$ro?>' : '<?=$no?>');
|
|
break;
|
|
}
|
|
data[i]['userAccess.'+idx] = access;
|
|
}
|
|
data[i]['changeShareAccess'] = 'Apply';
|
|
i++;
|
|
}
|
|
});
|
|
$(form).find('input').prop('disabled',true);
|
|
$('div.spinner.fixed').show();
|
|
updateAccess(form,data,0,i);
|
|
}
|
|
}
|
|
</script>
|
|
<form markdown="1" method="POST">
|
|
<?
|
|
echo "<table class='unraid'>";
|
|
echo "<thead><tr><td>"._('Share')."</td><td>"._('Security')."</td><td>"._('User Access')."</td></tr></thead>";
|
|
echo "<tbody>";
|
|
foreach ($shares as $share => $data) {
|
|
if ($sec[$share]['export']=='-') continue;
|
|
$security = $sec[$share]['security'];
|
|
$read = in_array($name,explode(',',$sec[$share]['readList']));
|
|
$write = in_array($name,explode(',',$sec[$share]['writeList']));
|
|
switch ($security) {
|
|
case 'public' : $access = $rw; break;
|
|
case 'secure' : $access = $write ? $rw : $ro; break;
|
|
case 'private': $access = $write ? $rw : ($read ? $ro : $no); break;}
|
|
echo "<tr><td>$share</td><td>"._(ucfirst($security))."</td><td><select onchange='$(this).prop(\"id\",\"".rawurlencode($share)."\")'>";
|
|
echo mk_option($access,$rw,_('Read/Write'));
|
|
if ($security!='public') echo mk_option($access,$ro,_('Read-only'));
|
|
if ($security=='private') echo mk_option($access,$no,_('No Access'));
|
|
echo "</select></td></tr>";
|
|
}
|
|
echo "</tbody>";
|
|
echo "</table>";
|
|
?>
|
|
|
|
|
|
: <span class="inline-block">
|
|
<input type="button" value="_(Apply)_" onclick="updateAccess(this.form)" disabled>
|
|
<input type="button" value="_(Done)_" onclick="done('UserEdit')">
|
|
</span>
|
|
</form>
|
|
<?endif;?>
|