Browse Source

Added more filter ui

Toby Chui 11 months ago
parent
commit
d1081b2ea2
5 changed files with 220 additions and 5 deletions
  1. 1 0
      api.go
  2. 29 0
      reverseproxy.go
  3. 1 1
      web/components/access.html
  4. 23 4
      web/components/httprp.html
  5. 166 0
      web/snippet/hostAccessEditor.html

+ 1 - 0
api.go

@@ -49,6 +49,7 @@ func initAPIs() {
 	authRouter.HandleFunc("/api/proxy/status", ReverseProxyStatus)
 	authRouter.HandleFunc("/api/proxy/toggle", ReverseProxyToggleRuleSet)
 	authRouter.HandleFunc("/api/proxy/list", ReverseProxyList)
+	authRouter.HandleFunc("/api/proxy/detail", ReverseProxyListDetail)
 	authRouter.HandleFunc("/api/proxy/edit", ReverseProxyHandleEditEndpoint)
 	authRouter.HandleFunc("/api/proxy/del", DeleteProxyEndpoint)
 	authRouter.HandleFunc("/api/proxy/updateCredentials", UpdateProxyBasicAuthCredentials)

+ 29 - 0
reverseproxy.go

@@ -740,6 +740,35 @@ func ReverseProxyToggleRuleSet(w http.ResponseWriter, r *http.Request) {
 	utils.SendOK(w)
 }
 
+func ReverseProxyListDetail(w http.ResponseWriter, r *http.Request) {
+	eptype, err := utils.PostPara(r, "type") //Support root and host
+	if err != nil {
+		utils.SendErrorResponse(w, "type not defined")
+		return
+	}
+
+	if eptype == "host" {
+		epname, err := utils.PostPara(r, "epname")
+		if err != nil {
+			utils.SendErrorResponse(w, "epname not defined")
+			return
+		}
+		endpointRaw, ok := dynamicProxyRouter.ProxyEndpoints.Load(epname)
+		if !ok {
+			utils.SendErrorResponse(w, "proxy rule not found")
+			return
+		}
+		targetEndpoint := dynamicproxy.CopyEndpoint(endpointRaw.(*dynamicproxy.ProxyEndpoint))
+		js, _ := json.Marshal(targetEndpoint)
+		utils.SendJSONResponse(w, string(js))
+	} else if eptype == "root" {
+		js, _ := json.Marshal(dynamicProxyRouter.Root)
+		utils.SendJSONResponse(w, string(js))
+	} else {
+		utils.SendErrorResponse(w, "Invalid type given")
+	}
+}
+
 func ReverseProxyList(w http.ResponseWriter, r *http.Request) {
 	eptype, err := utils.PostPara(r, "type") //Support root and host
 	if err != nil {

+ 1 - 1
web/components/access.html

@@ -33,7 +33,7 @@
             
             <div class="ui divider"></div>
             <div style="width: 100%;" align="center">
-                <button class="ui basic circular icon button" onclick="openAccessRuleEditor();" title="Edit Access Rules"><i class="ui edit icon"></i></button>
+                <button class="ui basic circular button" onclick="openAccessRuleEditor();" title="Edit Access Rules"><i class="ui edit icon"></i> Access Rule Editor</button>
                 <button class="ui basic circular icon button" onclick="reloadAccessRulesWithFeedback();"><i class="ui green refresh icon"></i></button>
             </div>
         </div>

+ 23 - 4
web/components/httprp.html

@@ -8,7 +8,7 @@
             background-color: #00ca52 !important;
         }
     </style>
-    <div style="width: 100%; overflow-x: auto; margin-bottom: 1em;">
+    <div style="width: 100%; overflow-x: auto; margin-bottom: 1em; min-height: 300px;">
         <table class="ui celled sortable unstackable compact table">
             <thead>
                 <tr>
@@ -16,7 +16,7 @@
                     <th>Destination</th>
                     <th>Virtual Directory</th>
                     <th>Basic Auth</th>
-                    <th class="no-sort" style="min-width:100px;">Actions</th>
+                    <th class="no-sort" style="min-width:150px;">Actions</th>
                 </tr>
             </thead>
             <tbody id="httpProxyList">
@@ -30,6 +30,8 @@
 </div>
 
 <script>
+
+    /* List all proxy endpoints */
     function listProxyEndpoints(){
         $.get("/api/proxy/list?type=host", function(data){
             $("#httpProxyList").html(``);
@@ -82,7 +84,9 @@
                         <td data-label="" editable="true" datatype="inbound"><a href="//${subd.RootOrMatchingDomain}" target="_blank">${subd.RootOrMatchingDomain}</a> ${inboundTlsIcon}</td>
                         <td data-label="" editable="true" datatype="domain">${subd.Domain} ${tlsIcon}</td>
                         <td data-label="" editable="true" datatype="vdir">${vdList}</td>
-                        <td data-label="" editable="true" datatype="basicauth">${subd.RequireBasicAuth?`<i class="ui green check icon"></i>`:`<i class="ui grey remove icon"></i>`}</td>
+                        <td data-label="" editable="true" datatype="basicauth">
+                            ${subd.RequireBasicAuth?`<i class="ui green check icon"></i>`:`<i class="ui grey remove icon"></i>`}
+                        </td>
                         <td class="center aligned" editable="true" datatype="action" data-label="">
                             <div class="ui toggle tiny fitted checkbox" style="margin-bottom: -0.5em; margin-right: 0.4em;" title="Enable / Disable Rule">
                                 <input type="checkbox" class="enableToggle" name="active" ${enableChecked} eptuuid="${subd.RootOrMatchingDomain}" onchange="handleProxyRuleToggle(this);">
@@ -176,7 +180,7 @@
 
                 column.empty().append(`<div class="ui checkbox" style="margin-top: 0.4em;">
                     <input type="checkbox" class="RequireBasicAuth" ${checkstate}>
-                    <label>Require Basic Auth</label>
+                        <label>Require Basic Auth</label>
                     </div>
                     <button class="ui basic tiny button" style="margin-left: 0.4em; margin-top: 0.4em;" onclick="editBasicAuthCredentials('${uuid}');"><i class="ui blue user circle icon"></i> Edit Credentials</button>
                     <div class="ui basic advance segment" style="padding: 0.4em !important; border-radius: 0.4em;">
@@ -191,6 +195,7 @@
                                     <label>Skip WebSocket Origin Check<br>
                                     <small>Check this to allow cross-origin websocket requests</small></label>
                                 </div>
+                                <br>
                                 <button class="ui basic compact tiny button" style="margin-left: 0.4em; margin-top: 0.4em;" onclick="editCustomHeaders('${uuid}');"><i class="heading icon"></i> Custom Headers</button>
                                 <!-- <button class="ui basic compact tiny button" style="margin-left: 0.4em; margin-top: 0.4em;" onclick="editLoadBalanceOptions('${uuid}');"><i class="blue server icon"></i> Load Balance</button> -->
                             </div>
@@ -213,7 +218,10 @@
                         <label>Allow plain HTTP access<br>
                             <small>Allow inbound connections without TLS/SSL</small></label>
                     </div><br>
+                    <button class="ui basic tiny button" style="margin-left: 0.4em; margin-top: 0.4em;" onclick="editAccessRule('${uuid}');"><i class="ui filter icon"></i> Edit Access Rule</button>
                 `);
+
+                $(".hostAccessRuleSelector").dropdown();
             }else{
                 //Unknown field. Leave it untouched
             }
@@ -277,6 +285,14 @@
         showSideWrapper("snippet/basicAuthEditor.html?t=" + Date.now() + "#" + payload);
     }
 
+    function editAccessRule(uuid){
+        let payload = encodeURIComponent(JSON.stringify({
+            ept: "host",
+            ep: uuid
+        }));
+        showSideWrapper("snippet/hostAccessEditor.html?t=" + Date.now() + "#" + payload);
+    }
+
     function quickEditVdir(uuid){
         openTabById("vdir");
         $("#vdirBaseRoutingRule").parent().dropdown("set selected", uuid);
@@ -313,6 +329,9 @@
             }
         })
     }
+
+    /* Access List handling */
+    
     
 
     //Bind on tab switch events

+ 166 - 0
web/snippet/hostAccessEditor.html

@@ -0,0 +1,166 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <!-- Notes: This should be open in its original path-->
+        <link rel="stylesheet" href="../script/semantic/semantic.min.css">
+        <script src="../script/jquery-3.6.0.min.js"></script>
+        <script src="../script/semantic/semantic.min.js"></script>
+        <style>
+            .accessRule{
+                cursor: pointer;
+                border-radius: 0.4em !important;
+                border: 1px solid rgb(233, 233, 233) !important;
+            }
+
+            .accessRule:hover{
+                background-color: rgb(241, 241, 241) !important;
+            }
+
+            .accessRule.active{
+                background-color: rgb(241, 241, 241) !important;
+            }
+
+            .accessRule .selected{
+                position: absolute;
+                top: 1em;
+                right: 0.6em;
+            }
+
+            .accessRule:not(.active) .selected{
+                display:none;
+            }
+
+            #accessRuleList{
+                padding: 0.6em;
+                border: 1px solid rgb(228, 228, 228);
+                border-radius: 0.4em !important;
+                max-height: calc(100vh - 15em);
+                min-height: 300px;
+                overflow-y: auto;
+            }
+        </style>
+    </head>
+    <body>
+        <br>
+        <div class="ui container">
+            <div class="ui header">
+                <div class="content">
+                    Host Access Settings
+                    <div class="sub header" id="epname"></div>
+                </div>
+            </div>
+            <div class="ui divider"></div>
+            <p>Select an access rule to apply blacklist / whitelist filtering</p>
+            <div id="accessRuleList">
+                <div class="ui segment accessRule">
+                    <div class="ui header">
+                        <i class="filter icon"></i>
+                        <div class="content">
+                            Account Settings
+                            <div class="sub header">Manage your preferences</div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <br>
+            <button class="ui basic button" onclick="applyChangeAndClose()"><i class="ui green check icon"></i> Apply Change</button>
+            
+            <button class="ui basic button"  style="float: right;" onclick="parent.hideSideWrapper();"><i class="remove icon"></i> Close</button>
+            <br><br><br>
+
+        </div>
+        <script>
+            let editingEndpoint = {};
+            if (window.location.hash.length > 1){
+                let payloadHash = window.location.hash.substr(1);
+                try{
+                    payloadHash = JSON.parse(decodeURIComponent(payloadHash));
+                    $("#epname").text(payloadHash.ep);
+                    editingEndpoint = payloadHash;
+                }catch(ex){
+                    console.log("Unable to load endpoint data from hash")
+                }
+            }
+
+            function initAccessRuleList(callback = undefined){
+                $("#accessRuleList").html("<small>Loading</small>");
+                $.get("/api/access/list", function(data){
+                    if (data.error == undefined){
+                        $("#accessRuleList").html("");
+                        data.forEach(function(rule){
+                            let icon = `<i class="ui grey filter icon"></i>`;
+                            if (rule.ID == "default"){
+                                icon = `<i class="ui yellow star icon"></i>`;
+                            }else if (rule.BlacklistEnabled && !rule.WhitelistEnabled){
+                                //This is a blacklist filter
+                                icon = `<i class="ui red filter icon"></i>`;
+                            }else if (rule.WhitelistEnabled && !rule.BlacklistEnabled){
+                                //This is a whitelist filter
+                                icon = `<i class="ui green filter icon"></i>`;
+                            }else if (rule.WhitelistEnabled && rule.BlacklistEnabled){
+                                //Whitelist and blacklist filter
+                                icon = `<i class="ui yellow filter icon"></i>`;
+                            }
+
+                            $("#accessRuleList").append(`<div class="ui basic segment accessRule" ruleid="${rule.ID}" onclick="selectThisRule(this);">
+                                <h5 class="ui header">
+                                    ${icon}
+                                    <div class="content">
+                                        ${rule.Name}
+                                        <div class="sub header">${rule.ID}</div>
+                                    </div>
+                                </h5>
+                                <p>${rule.Desc}</p>
+                                ${rule.BlacklistEnabled?`<small><i class="ui red filter icon"></i> Blacklist Enabled</small>`:""}
+                                ${rule.WhitelistEnabled?`<small><i class="ui green filter icon"></i> Whitelist Enabled</small>`:""}
+                                <div class="selected"><i class="ui large green check icon"></i></div>
+                            </div>`);
+                        });
+                        accessRuleList = data;
+                        $(".dropdown").dropdown();
+                        if (callback != undefined){
+                            callback();
+                        }
+                    }
+                });
+
+
+            }
+
+            initAccessRuleList(function(){
+                $.ajax({
+                    url: "/api/proxy/detail",
+                    method: "POST",
+                    data: {"type":"host", "epname": editingEndpoint.ep },
+                    success: function(data){
+                        console.log(data);
+                        if (data.error != undefined){
+                            alert(data.error);
+                        }else{
+                            let currentAccessFilter = data.AccessFilterUUID;
+                            if (currentAccessFilter == ""){
+                                //Use default
+                                currentAccessFilter = "default";
+                            }
+
+                            $(`.accessRule[ruleid=${currentAccessFilter}]`).addClass("active");
+                        }
+                    }
+                })
+            });
+
+
+            function selectThisRule(accessRuleObject){
+                let accessRuleID = $(accessRuleObject).attr("ruleid");
+                $(".accessRule").removeClass('active');
+                $(accessRuleObject).addClass('active');
+            }
+
+            function applyChangeAndClose(){
+                let newAccessRuleID = $(".accessRule.active").attr("ruleid");
+                alert(newAccessRuleID);
+            }
+          
+        </script>
+    </body>
+</html>