luci-base: form.js: make map readonly on insufficient uci permissions
authorJo-Philipp Wich <jo@mein.io>
Mon, 13 Apr 2020 15:48:06 +0000 (17:48 +0200)
committerJo-Philipp Wich <jo@mein.io>
Tue, 14 Apr 2020 15:13:19 +0000 (17:13 +0200)
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
modules/luci-base/htdocs/luci-static/resources/form.js

index 3d9b18efa5dcb1ca8ebd1f4ea67750c9d13d47cd..c65cb04b13833dfb452ee096610fd522d8d76bd3 100644 (file)
@@ -1,11 +1,19 @@
 'use strict';
 'require ui';
 'require uci';
+'require rpc';
 'require dom';
 'require baseclass';
 
 var scope = this;
 
+var callSessionAccess = rpc.declare({
+       object: 'session',
+       method: 'access',
+       params: [ 'scope', 'object', 'function' ],
+       expect: { 'access': false }
+});
+
 var CBIJSONConfig = baseclass.extend({
        __init__: function(data) {
                data = Object.assign({}, data);
@@ -360,7 +368,6 @@ var CBIMap = CBIAbstractElement.extend(/** @lends LuCI.form.Map.prototype */ {
 
                this.config = config;
                this.parsechain = [ config ];
-               this.readonly = false;
                this.data = uci;
        },
 
@@ -370,6 +377,10 @@ var CBIMap = CBIAbstractElement.extend(/** @lends LuCI.form.Map.prototype */ {
         * If set to `true`, the Map instance is marked readonly and any form
         * option elements added to it will inherit the readonly state.
         *
+        * If left unset, the Map will test the access permission of the primary
+        * uci configuration upon loading and mark the form readonly if no write
+        * permissions are granted.
+        *
         * @name LuCI.form.Map.prototype#readonly
         * @type boolean
         */
@@ -520,8 +531,17 @@ var CBIMap = CBIAbstractElement.extend(/** @lends LuCI.form.Map.prototype */ {
         * an error.
         */
        load: function() {
-               return this.data.load(this.parsechain || [ this.config ])
-                       .then(this.loadChildren.bind(this));
+               var doCheckACL = (!(this instanceof CBIJSONMap) && this.readonly == null);
+
+               return Promise.all([
+                       doCheckACL ? callSessionAccess('uci', this.config, 'write') : true,
+                       this.data.load(this.parsechain || [ this.config ])
+               ]).then(L.bind(function(res) {
+                       if (res[0] === false)
+                               this.readonly = true;
+
+                       return this.loadChildren();
+               }, this));
        },
 
        /**