]> git.ipfire.org Git - thirdparty/rspamd.git/commitdiff
[Feature] WebUI: read-only access to selectors tab 6157/head
authorAlexander Moisseev <moiseev@mezonplus.ru>
Mon, 27 Jul 2026 13:31:11 +0000 (16:31 +0300)
committerAlexander Moisseev <moiseev@mezonplus.ru>
Mon, 27 Jul 2026 13:31:11 +0000 (16:31 +0300)
Open list_extractors, list_transforms and check_selector to
read-only users (enable = false, matching maps.lua). These only
return static catalogs or parse the selector without executing it.
check_message stays privileged (enable = true): it runs a
user-supplied selector against a user-supplied message, so it
remains denied to read-only users (HTTP 401)

interface/index.html
interface/js/app/rspamd.js
interface/js/app/selectors.js
rules/controller/selectors.lua

index 01943e410da15496fe087b46939c829db4dd478e..6e0ad19d01389343ca95ec6e4fa032e442f1a3c3 100644 (file)
@@ -48,7 +48,7 @@
                                <li role="presentation" class="nav-item"><a id="configuration_nav" aria-controls="configuration" role="tab" href="#configuration" data-bs-toggle="tab" class="nav-link">Configuration</a></li>
                                <li role="presentation" class="nav-item"><a id="symbols_nav" aria-controls="symbols" role="tab" href="#symbols" data-bs-toggle="tab" class="nav-link">Symbols</a></li>
                                <li role="presentation" class="nav-item"><a id="scan_nav" aria-controls="scan" role="tab" href="#scan" data-bs-toggle="tab" class="nav-link">Scan<span class="ro-hide d-none">/Learn</span></a></li>
-                               <li role="presentation" class="nav-item"><a id="selectors_nav" aria-controls="selectors" role="tab" href="#selectors" data-bs-toggle="tab" class="nav-link ro-hide d-none">Test selectors</a></li>
+                               <li role="presentation" class="nav-item"><a id="selectors_nav" aria-controls="selectors" role="tab" href="#selectors" data-bs-toggle="tab" class="nav-link">Test selectors</a></li>
                                <li role="presentation" class="nav-item"><a id="history_nav" aria-controls="history" role="tab" href="#history" data-bs-toggle="tab" class="nav-link">History</a></li>
                        </ul>
                </div>
                                        <div class="card-header text-secondary py-2 d-flex align-items-center">
                                                <span class="icon me-3"><i class="fas fa-envelope"></i></span>
                                                <span class="h6 fw-bolder my-auto">Test Rspamd selectors</span>
-                                               <div class="d-flex input-group-sm align-items-center ms-auto">
+                                               <span class="badge text-bg-info ms-2 ro-show d-none" title="Read-only mode: message evaluation is unavailable. You can browse extractors and transforms and validate selector syntax.">Read-only</span>
+                                               <div class="d-flex input-group-sm align-items-center ms-auto ro-hide">
                                                        <label for="formFile" class="col-auto col-form-label-sm me-1">Choose a file:</label>
                                                        <input class="form-control form-control-sm btn btn-secondary" id="selectorsFile" type="file">
                                                </div>
                                                                        <div class="col-lg col-12 mh-100 overflow-auto">
                                                                                <div class="row h-100">
                                                                                        <form class="col-12 d-flex flex-column">
-                                                                                               <div class="row pt-3">
+                                                                                               <div class="row pt-3 ro-hide">
                                                                                                        <div class="col">
                                                                                                                <div class="mb-3">
                                                                                                                        <label class="form-label" for="selectorsMsgArea">Message source:</label>
                                                                                                                        <label class="form-label" for="selectorsSelArea">Selector(s):</label>
                                                                                                                        <textarea class="form-control" id="selectorsSelArea" rows="1" placeholder="extractor.transform(arg);extractor.transform(arg);..."></textarea>
                                                                                                                </div>
-                                                                                                               <button type="submit" class="btn btn-primary d-inline-flex align-items-center" id="selectorsChkMsgBtn"><i class="fas fa-search me-2"></i>Check message</button>
+                                                                                                               <button type="submit" class="btn btn-primary d-inline-flex align-items-center ro-hide" id="selectorsChkMsgBtn"><i class="fas fa-search me-2"></i>Check message</button>
                                                                                                                <button class="btn btn-secondary d-inline-flex align-items-center float-end" id="selectorsClean"><i class="fas fa-trash-alt me-2"></i>Clean form</button>
                                                                                                        </div>
                                                                                                </div>
-                                                                                               <div class="row pt-3 flex-grow-1">
+                                                                                               <div class="row pt-3 flex-grow-1 ro-hide">
                                                                                                        <div class="col d-flex flex-column">
                                                                                                                <div class="mb-3 h-100 d-flex flex-column">
                                                                                                                        <label class="form-label" for="selectorsResArea">Result:</label>
index 698bc96c92384bffb4e89f3878e6ce4e67fe99eb..7c2fadc9e290fd301450d0f117d6442c8823c034 100644 (file)
@@ -279,8 +279,10 @@ define(["app/common", "app/icons", "bootstrap",
                 document.querySelectorAll(".ro-disable").forEach((el) => { el.disabled = common.read_only; });
                 if (common.read_only) {
                     common.hide(".ro-hide");
+                    common.show(".ro-show");
                 } else {
                     common.show(".ro-hide");
+                    common.hide(".ro-show");
                 }
 
                 document.getElementById("preloader").classList.add("d-none");
index d16c75eee3d69b8006e2db7eb906ee90b756af9c..ba6a59fa80981da4014e041924ee06095c35f8cf 100644 (file)
@@ -38,7 +38,7 @@ define(["app/common"],
                 enable_disable_check_btn();
             }
             const selector = selArea.value;
-            if (selector.length && !common.read_only) {
+            if (selector.length) {
                 common.query("plugins/selectors/check_selector?selector=" + encodeURIComponent(selector), {
                     method: "GET",
                     success: function (json) {
@@ -83,8 +83,7 @@ define(["app/common"],
         }
 
         ui.displayUI = function () {
-            if (!common.read_only &&
-                !document.querySelector("#selectorsTable-extractors>tbody>tr") &&
+            if (!document.querySelector("#selectorsTable-extractors>tbody>tr") &&
                 !document.querySelector("#selectorsTable-transforms>tbody>tr")) buildLists();
             if (!document.getElementById("selectorsSelArea").matches(".is-valid, .is-invalid")) checkSelectors();
         };
index 7fc2894d7a1aa835f6a16699215e15ca7703bf54..8046436ca1d83c0f79e6d0e0fea03750818b905b 100644 (file)
@@ -55,15 +55,15 @@ end
 return {
   list_extractors = {
     handler = handle_list_extractors,
-    enable = true,
+    enable = false,
   },
   list_transforms = {
     handler = handle_list_transforms,
-    enable = true,
+    enable = false,
   },
   check_selector = {
     handler = handle_check_selector,
-    enable = true,
+    enable = false,
   },
   check_message = {
     handler = handle_check_message,