'use strict';
'require view';
'require dom';
'require ui';
'require fs';
'require uci';
'require form';
'require rpc';
'require tools.password as pwtool';
var formData = {
data: {
rpc_user: null,
user: null,
rpcd: null,
oldpw: null,
pw1: null,
pw2: null
}
};
var callSetPassword = rpc.declare({
object: 'luci',
method: 'setPassword',
params: [ 'username', 'password', 'oldpassword', 'rpcd' ],
expect: { result: 1 }
});
return view.extend({
checkPassword: function(section_id, value) {
var strength = document.querySelector('.cbi-value-description'),
strongRegex = new RegExp("^(?=.{8,})(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*\\W).*$", "g"),
mediumRegex = new RegExp("^(?=.{7,})(((?=.*[A-Z])(?=.*[a-z]))|((?=.*[A-Z])(?=.*[0-9]))|((?=.*[a-z])(?=.*[0-9]))).*$", "g"),
enoughRegex = new RegExp("(?=.{6,}).*", "g");
const pw_enabled = uci.get('rpcd', 'policy', 'enabled');
const pw_length = uci.get('rpcd', 'policy', 'pw_length');
const pw_digits = uci.get('rpcd', 'policy', 'digits');
const pw_ul = uci.get('rpcd', 'policy', 'uc_lc');
const special = uci.get('rpcd', 'policy', 'special_characters');
if (strength && value.length) {
if (false == enoughRegex.test(value))
strength.innerHTML = '%s: %s'.format(_('Password strength'), _('More Characters'));
else if (strongRegex.test(value))
strength.innerHTML = '%s: %s'.format(_('Password strength'), _('Strong'));
else if (mediumRegex.test(value))
strength.innerHTML = '%s: %s'.format(_('Password strength'), _('Medium'));
else
strength.innerHTML = '%s: %s'.format(_('Password strength'), _('Weak'));
}
if (!pw_enabled)
return true;
if (pw_length && !pwtool.checkLength(value, pw_length))
return _('Policy: min. length of %s characters').format(pw_length);
if (pw_digits && !pwtool.checkDigits(value))
return _('Policy: contain digits');
if (pw_ul && !pwtool.checkUpperLower(value))
return _('Policy: contain uppercase/lowercase');
if (special && !pwtool.checkSpecialChars(value))
return _('Policy: contain special characters');
return true;
},
load: function() {
return Promise.all([
L.resolveDefault(fs.stat('/usr/sbin/uhttpd'), null),
fs.lines('/etc/passwd'),
uci.load('rpcd'),
uci.load('luci')
]);
},
render: function([has_uhttpd, passwd]) {
var m, s, o, rpcd;
const known_unix_users = {};
for (let p of passwd) {
const parts = p.split(/:/);
if (parts.length >= 7)
known_unix_users[parts[0]] = true;
}
m = new form.JSONMap(formData, _('Password'), _('Changes the password for accessing the device as (rpcd) user'));
m.readonly = !L.hasViewPermission();
s = m.section(form.NamedSection, 'data', 'data');
if (has_uhttpd) {
let logins = [];
uci.sections('rpcd', 'login', s => logins.push(s.username));
rpcd = s.option(form.Flag, 'rpcd', _('Change password for rpcd user'));
rpcd.default = false;
o = s.option(form.Value, 'rpc_user', _('rpcd username'));
for (let user of logins) {
if (user == 'root')
continue;
o.value(user, _('%s').format(user));
}
o.rmempty = false;
o.depends({ 'rpcd': '1' });
o = s.option(form.Value, 'user', _('Router username'));
for (let user in known_unix_users)
o.value(user, _('%s').format(user));
o.rmempty = false;
o.depends({ 'rpcd': '0' });
o = s.option(form.Value, 'oldpw', _('Old Password'));
o.password = true;
o.depends({ 'rpcd': '1' });
}
if (!has_uhttpd) {
o = s.option(form.Value, 'user', _('Router username'));
for (let user in known_unix_users)
o.value(user);
o.rmempty = false;
}
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.querySelector('input').addEventListener('keydown', function(ev) {
if (ev.keyCode == 13 && !ev.currentTarget.classList.contains('cbi-input-invalid'))
document.querySelector('.cbi-button-save').click();
});
return node;
};
return m.render();
},
handleSave: function() {
var map = document.querySelector('.cbi-map');
return dom.callClassMethod(map, 'save').then(function() {
let rpc_user = formData.data.rpc_user;
let user = formData.data.user;
let rpcd = formData.data.rpcd;
let oldpw = formData.data.oldpw;
if (rpc_user && (oldpw == null || oldpw.length == 0))
return;
if (formData.data.pw1 == null || formData.data.pw1.length == 0)
return;
if (formData.data.pw1 != formData.data.pw2) {
ui.addNotification(null, E('p', _('Given password confirmation did not match, password not changed!')), 'danger');
return;
}
return callSetPassword(
rpc_user ? rpc_user : user,
formData.data.pw1,
oldpw ? oldpw : '',
rpcd ? true : false,
).then(function(success) {
if (success)
ui.addNotification(null, E('p', _('The system password has been successfully changed.')), 'info');
else
ui.addNotification(null, E('p', _('Failed to change the system password.')), 'danger');
formData.data.rpc_user = null;
formData.data.user = null;
formData.data.rpcd = null;
formData.data.pw1 = null;
formData.data.pw2 = null;
formData.data.oldpw = null;
dom.callClassMethod(map, 'render');
});
});
},
handleSaveApply: null,
handleReset: null
});