luci-app-acl: enforce password policy
authorChristian Korber <redacted>
Mon, 27 Apr 2026 14:05:47 +0000 (16:05 +0200)
committerPaul Donald <redacted>
Wed, 3 Jun 2026 10:49:07 +0000 (13:49 +0300)
Validation is performed if the password complies to password policy.

Signed-off-by: Christian Korber <redacted>
applications/luci-app-acl/htdocs/luci-static/resources/view/system/acl.js

index 4dcad0cc59b098b9b8cebcc5045838bf014326f9..9a4952e47922b4c77ae13847671bed7fdaa20cb3 100644 (file)
@@ -7,6 +7,7 @@
 'require uci';
 'require form';
 'require tools.widgets as widgets';
+'require tools.password as pwtool';
 
 const aclList = {};
 
@@ -17,6 +18,31 @@ const callSetPassword = rpc.declare({
        expect: { result: 1 }
 });
 
+function checkPassword(value) {
+       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 (!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;
+}
+
 function globListToRegExp(section_id, option) {
        const list = L.toArray(uci.get('rpcd', section_id, option));
        const positivePatterns = [];
@@ -170,7 +196,8 @@ return view.extend({
                return L.resolveDefault(fs.list('/usr/share/rpcd/acl.d'), []).then(function(entries) {
                        const tasks = [
                                L.resolveDefault(fs.stat('/usr/sbin/uhttpd'), null),
-                               fs.lines('/etc/passwd')
+                               fs.lines('/etc/passwd'),
+                               uci.load('rpcd')
                        ];
 
                        for (let e of entries)
@@ -181,7 +208,7 @@ return view.extend({
                });
        },
 
-       render([has_uhttpd, passwd, ...acls]) {
+       render([has_uhttpd, passwd, uci_rpcd, ...acls]) {
                ui.addNotification(null, E('p', [
                        _('The LuCI ACL management is in an experimental stage! It does not yet work reliably with all applications')
                ]), 'warning');
@@ -275,7 +302,7 @@ return view.extend({
                                        return _('Cannot encrypt plaintext password since uhttpd is not installed.');
                        }
 
-                       return true;
+                       return checkPassword(value);
                };
                o.write = function(section_id, value) {
                        const variant = this.map.lookupOption('_variant', section_id)[0];
@@ -286,8 +313,6 @@ return view.extend({
                                        if (!success)
                                                throw new Error('Failed to create password');
                                });
-
-                       uci.set('rpcd', section_id, 'password', value);
                };
                o.remove = function() {};
 
git clone https://git.99rst.org/PROJECT