luci-mod-system: remplement password change as client side view
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
This commit is contained in:
parent
a31d1d10e0
commit
9ae9657a85
4 changed files with 91 additions and 99 deletions
|
@ -50,7 +50,7 @@
|
||||||
"ubus": {
|
"ubus": {
|
||||||
"file": [ "write", "remove" ],
|
"file": [ "write", "remove" ],
|
||||||
"iwinfo": [ "scan" ],
|
"iwinfo": [ "scan" ],
|
||||||
"luci": [ "setInitAction", "setLocaltime" ],
|
"luci": [ "setInitAction", "setLocaltime", "setPassword" ],
|
||||||
"uci": [ "add", "apply", "confirm", "delete", "order", "set", "rename" ]
|
"uci": [ "add", "apply", "confirm", "delete", "order", "set", "rename" ]
|
||||||
},
|
},
|
||||||
"uci": [ "*" ]
|
"uci": [ "*" ]
|
||||||
|
|
|
@ -1,31 +1,94 @@
|
||||||
function submitPassword(ev) {
|
'use strict';
|
||||||
var pw1 = document.body.querySelector('[name="pw1"]'),
|
'require form';
|
||||||
pw2 = document.body.querySelector('[name="pw2"]');
|
'require rpc';
|
||||||
|
|
||||||
if (!pw1.value.length || !pw2.value.length)
|
var formData = {
|
||||||
return;
|
password: {
|
||||||
|
pw1: null,
|
||||||
|
pw2: null
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (pw1.value === pw2.value) {
|
var callSetPassword = rpc.declare({
|
||||||
L.showModal(_('Change login password'),
|
object: 'luci',
|
||||||
E('p', { class: 'spinning' }, _('Changing password…')));
|
method: 'setPassword',
|
||||||
|
params: [ 'username', 'password' ],
|
||||||
|
expect: { result: false }
|
||||||
|
});
|
||||||
|
|
||||||
L.post('admin/system/admin/password/json', { password: pw1.value },
|
return L.view.extend({
|
||||||
function() {
|
checkPassword: function(section_id, value) {
|
||||||
showModal(_('Change login password'), [
|
var strength = document.querySelector('.cbi-value-description'),
|
||||||
E('div', _('The system password has been successfully changed.')),
|
strongRegex = new RegExp("^(?=.{8,})(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*\\W).*$", "g"),
|
||||||
E('div', { 'class': 'right' },
|
mediumRegex = new RegExp("^(?=.{7,})(((?=.*[A-Z])(?=.*[a-z]))|((?=.*[A-Z])(?=.*[0-9]))|((?=.*[a-z])(?=.*[0-9]))).*$", "g"),
|
||||||
E('div', { class: 'btn', click: L.hideModal }, _('Dismiss')))
|
enoughRegex = new RegExp("(?=.{6,}).*", "g");
|
||||||
]);
|
|
||||||
|
|
||||||
pw1.value = pw2.value = '';
|
if (strength && value.length) {
|
||||||
|
if (false == enoughRegex.test(value))
|
||||||
|
strength.innerHTML = '%s: <span style="color:red">%s</span>'.format(_('Password strength'), _('More Characters'));
|
||||||
|
else if (strongRegex.test(value))
|
||||||
|
strength.innerHTML = '%s: <span style="color:green">%s</span>'.format(_('Password strength'), _('Strong'));
|
||||||
|
else if (mediumRegex.test(value))
|
||||||
|
strength.innerHTML = '%s: <span style="color:orange">%s</span>'.format(_('Password strength'), _('Medium'));
|
||||||
|
else
|
||||||
|
strength.innerHTML = '%s: <span style="color:red">%s</span>'.format(_('Password strength'), _('Weak'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function() {
|
||||||
|
var m, s, o;
|
||||||
|
|
||||||
|
m = new form.JSONMap(formData, _('Router Password'), _('Changes the administrator password for accessing the device'));
|
||||||
|
s = m.section(form.NamedSection, 'password', 'password');
|
||||||
|
|
||||||
|
o = s.option(form.Value, 'pw1', _('Password'));
|
||||||
|
o.password = true;
|
||||||
|
o.validate = this.checkPassword;
|
||||||
|
|
||||||
|
o = s.option(form.Value, 'pw2', _('Confirmation'), ' ');
|
||||||
|
o.password = true;
|
||||||
|
o.renderWidget = function(/* ... */) {
|
||||||
|
var node = form.Value.prototype.renderWidget.apply(this, arguments);
|
||||||
|
|
||||||
|
node.childNodes[1].addEventListener('keydown', function(ev) {
|
||||||
|
if (ev.keyCode == 13 && !ev.currentTarget.classList.contains('cbi-input-invalid'))
|
||||||
|
document.querySelector('.cbi-button-save').click();
|
||||||
});
|
});
|
||||||
}
|
|
||||||
else {
|
return node;
|
||||||
L.showModal(_('Change login password'), [
|
};
|
||||||
E('div', { class: 'alert-message warning' },
|
|
||||||
_('Given password confirmation did not match, password not changed!')),
|
return m.render();
|
||||||
E('div', { 'class': 'right' },
|
},
|
||||||
E('div', { class: 'btn', click: L.hideModal }, _('Dismiss')))
|
|
||||||
]);
|
handleSave: function() {
|
||||||
}
|
var map = document.querySelector('.cbi-map');
|
||||||
}
|
|
||||||
|
return L.dom.callClassMethod(map, 'save').then(function() {
|
||||||
|
if (formData.password.pw1 == null || formData.password.pw1.length == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (formData.password.pw1 != formData.password.pw2) {
|
||||||
|
L.ui.addNotification(null, E('p', _('Given password confirmation did not match, password not changed!')), 'danger');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return callSetPassword('root', formData.password.pw1).then(function(success) {
|
||||||
|
if (success)
|
||||||
|
L.ui.addNotification(null, E('p', _('The system password has been successfully changed.')), 'info');
|
||||||
|
else
|
||||||
|
L.ui.addNotification(null, E('p', _('Failed to change the system password.')), 'danger');
|
||||||
|
|
||||||
|
formData.password.pw1 = null;
|
||||||
|
formData.password.pw2 = null;
|
||||||
|
|
||||||
|
L.dom.callClassMethod(map, 'render');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
handleSaveApply: null,
|
||||||
|
handleReset: null
|
||||||
|
});
|
||||||
|
|
|
@ -12,8 +12,7 @@ function index()
|
||||||
entry({"admin", "system", "ntp_restart"}, call("action_ntp_restart"), nil).leaf = true
|
entry({"admin", "system", "ntp_restart"}, call("action_ntp_restart"), nil).leaf = true
|
||||||
|
|
||||||
entry({"admin", "system", "admin"}, firstchild(), _("Administration"), 2)
|
entry({"admin", "system", "admin"}, firstchild(), _("Administration"), 2)
|
||||||
entry({"admin", "system", "admin", "password"}, template("admin_system/password"), _("Router Password"), 1)
|
entry({"admin", "system", "admin", "password"}, view("system/password"), _("Router Password"), 1)
|
||||||
entry({"admin", "system", "admin", "password", "json"}, post("action_password"))
|
|
||||||
|
|
||||||
if fs.access("/etc/config/dropbear") then
|
if fs.access("/etc/config/dropbear") then
|
||||||
entry({"admin", "system", "admin", "dropbear"}, cbi("admin_system/dropbear"), _("SSH Access"), 2)
|
entry({"admin", "system", "admin", "dropbear"}, cbi("admin_system/dropbear"), _("SSH Access"), 2)
|
||||||
|
@ -281,17 +280,6 @@ function action_reset()
|
||||||
http.redirect(luci.dispatcher.build_url('admin/system/flashops'))
|
http.redirect(luci.dispatcher.build_url('admin/system/flashops'))
|
||||||
end
|
end
|
||||||
|
|
||||||
function action_password()
|
|
||||||
local password = luci.http.formvalue("password")
|
|
||||||
if not password then
|
|
||||||
luci.http.status(400, "Bad Request")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
luci.http.prepare_content("application/json")
|
|
||||||
luci.http.write_json({ code = luci.sys.user.setpasswd("root", password) })
|
|
||||||
end
|
|
||||||
|
|
||||||
function action_reboot()
|
function action_reboot()
|
||||||
luci.sys.reboot()
|
luci.sys.reboot()
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,59 +0,0 @@
|
||||||
<%+header%>
|
|
||||||
|
|
||||||
<input type="password" aria-hidden="true" style="position:absolute; left:-10000px" />
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
|
||||||
function checkPassword() {
|
|
||||||
var pw1 = document.body.querySelector('[name="pw1"]');
|
|
||||||
var view = document.getElementById("passstrength");
|
|
||||||
|
|
||||||
var strongRegex = new RegExp("^(?=.{8,})(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*\\W).*$", "g");
|
|
||||||
var mediumRegex = new RegExp("^(?=.{7,})(((?=.*[A-Z])(?=.*[a-z]))|((?=.*[A-Z])(?=.*[0-9]))|((?=.*[a-z])(?=.*[0-9]))).*$", "g");
|
|
||||||
var enoughRegex = new RegExp("(?=.{6,}).*", "g");
|
|
||||||
if (false == enoughRegex.test(pw1.value)) {
|
|
||||||
view.innerHTML = '<%:Password strength%>: <span style="color:red"><%:More Characters%></span>';
|
|
||||||
} else if (strongRegex.test(pw1.value)) {
|
|
||||||
view.innerHTML = '<%:Password strength%>: <span style="color:green"><%:Strong%></span>';
|
|
||||||
} else if (mediumRegex.test(pw1.value)) {
|
|
||||||
view.innerHTML = '<%:Password strength%>: <span style="color:orange"><%:Medium%></span>';
|
|
||||||
} else {
|
|
||||||
view.innerHTML = '<%:Password strength%>: <span style="color:red"><%:Weak%></span>';
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class="cbi-map">
|
|
||||||
<h2><%:Router Password%></h2>
|
|
||||||
|
|
||||||
<div class="cbi-section-descr">
|
|
||||||
<%:Changes the administrator password for accessing the device%>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="cbi-section-node">
|
|
||||||
<div class="cbi-value">
|
|
||||||
<label class="cbi-value-title" for="image"><%:Password%></label>
|
|
||||||
<div class="cbi-value-field">
|
|
||||||
<input type="password" name="pw1" onkeyup="checkPassword()"/><!--
|
|
||||||
--><button class="cbi-button cbi-button-neutral" title="<%:Reveal/hide password%>" aria-label="<%:Reveal/hide password%>" onclick="var e = this.previousElementSibling; e.type = (e.type === 'password') ? 'text' : 'password'">∗</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="cbi-value">
|
|
||||||
<label class="cbi-value-title" for="image"><%:Confirmation%></label>
|
|
||||||
<div class="cbi-value-field">
|
|
||||||
<input type="password" name="pw2" onkeydown="if (event.keyCode === 13) submitPassword(event)" /><!--
|
|
||||||
--><button class="cbi-button cbi-button-neutral" title="<%:Reveal/hide password%>" aria-label="<%:Reveal/hide password%>" onclick="var e = this.previousElementSibling; e.type = (e.type === 'password') ? 'text' : 'password'">∗</button>
|
|
||||||
<div id="passstrength" class="cbi-value-description"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="cbi-page-actions">
|
|
||||||
<button class="btn cbi-button-apply" onclick="submitPassword(event)"><%:Save%></button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script type="application/javascript" src="<%=resource%>/view/system/password.js"></script>
|
|
||||||
|
|
||||||
<%+footer%>
|
|
Loading…
Reference in a new issue