Преглед на файлове

auto update script executed

Toby Chui преди 1 година
родител
ревизия
b00053f7d7
променени са 9 файла, в които са добавени 316 реда и са изтрити 26 реда
  1. 3 4
      api.go
  2. 27 0
      mod/dynamicproxy/endpoints.go
  3. 5 8
      mod/dynamicproxy/typedef.go
  4. 86 0
      reverseproxy.go
  5. 2 2
      web/components/httprp.html
  6. 1 1
      web/components/redirection.html
  7. 1 1
      web/components/rules.html
  8. 179 9
      web/components/vdir.html
  9. 12 1
      web/main.css

+ 3 - 4
api.go

@@ -48,7 +48,6 @@ func initAPIs() {
 	authRouter.HandleFunc("/api/proxy/add", ReverseProxyHandleAddEndpoint)
 	authRouter.HandleFunc("/api/proxy/status", ReverseProxyStatus)
 	authRouter.HandleFunc("/api/proxy/list", ReverseProxyList)
-	authRouter.HandleFunc("/api/proxy/vdir", ReverseProxyListVdir)
 	authRouter.HandleFunc("/api/proxy/edit", ReverseProxyHandleEditEndpoint)
 	authRouter.HandleFunc("/api/proxy/del", DeleteProxyEndpoint)
 	authRouter.HandleFunc("/api/proxy/updateCredentials", UpdateProxyBasicAuthCredentials)
@@ -57,9 +56,9 @@ func initAPIs() {
 	authRouter.HandleFunc("/api/proxy/useHttpsRedirect", HandleUpdateHttpsRedirect)
 	authRouter.HandleFunc("/api/proxy/listenPort80", HandleUpdatePort80Listener)
 	authRouter.HandleFunc("/api/proxy/requestIsProxied", HandleManagementProxyCheck)
-	//Reverse proxy root related APIs
-	//authRouter.HandleFunc("/api/proxy/root/listOptions", HandleRootRouteOptionList)
-	//authRouter.HandleFunc("/api/proxy/root/updateOptions", HandleRootRouteOptionsUpdate)
+	//Reverse proxy virtual directory APIs
+	authRouter.HandleFunc("/api/proxy/vdir/list", ReverseProxyListVdir)
+	authRouter.HandleFunc("/api/proxy/vdir/add", ReverseProxyAddVdir)
 	//Reverse proxy auth related APIs
 	authRouter.HandleFunc("/api/proxy/auth/exceptions/list", ListProxyBasicAuthExceptionPaths)
 	authRouter.HandleFunc("/api/proxy/auth/exceptions/add", AddProxyBasicAuthExceptionPaths)

+ 27 - 0
mod/dynamicproxy/endpoints.go

@@ -39,6 +39,33 @@ func (router *Router) PrepareProxyRoute(endpoint *ProxyEndpoint) (*ProxyEndpoint
 	endpoint.proxy = proxy
 	endpoint.parent = router
 
+	//Prepare proxy routing hjandler for each of the virtual directories
+	for _, vdir := range endpoint.VirtualDirectories {
+		domain := vdir.Domain
+		if domain[len(domain)-1:] == "/" {
+			domain = domain[:len(domain)-1]
+		}
+
+		//Parse the web proxy endpoint
+		webProxyEndpoint = domain
+		if !strings.HasPrefix("http://", domain) && !strings.HasPrefix("https://", domain) {
+			//TLS is not hardcoded in proxy target domain
+			if vdir.RequireTLS {
+				webProxyEndpoint = "https://" + webProxyEndpoint
+			} else {
+				webProxyEndpoint = "http://" + webProxyEndpoint
+			}
+		}
+
+		path, err := url.Parse(webProxyEndpoint)
+		if err != nil {
+			return nil, err
+		}
+
+		proxy := dpcore.NewDynamicProxyCore(path, vdir.MatchingPath, vdir.SkipCertValidations)
+		vdir.proxy = proxy
+	}
+
 	return endpoint, nil
 }
 

+ 5 - 8
mod/dynamicproxy/typedef.go

@@ -71,14 +71,11 @@ type BasicAuthExceptionRule struct {
 // A Virtual Directory endpoint, provide a subset of ProxyEndpoint for better
 // program structure than directly using ProxyEndpoint
 type VirtualDirectoryEndpoint struct {
-	MatchingPath string //Matching prefix of the request path, also act as key
-	Domain       string //Domain or IP to proxy to
-
-	RequireTLS          bool //Target domain require TLS
-	BypassGlobalTLS     bool //Bypass global TLS setting options if TLS Listener enabled (parent.tlsListener != nil)
-	SkipCertValidations bool //Set to true to accept self signed certs
-
-	proxy *dpcore.ReverseProxy `json:"-"`
+	MatchingPath        string               //Matching prefix of the request path, also act as key
+	Domain              string               //Domain or IP to proxy to
+	RequireTLS          bool                 //Target domain require TLS
+	SkipCertValidations bool                 //Set to true to accept self signed certs
+	proxy               *dpcore.ReverseProxy `json:"-"`
 }
 
 // A proxy endpoint record, a general interface for handling inbound routing

+ 86 - 0
reverseproxy.go

@@ -760,6 +760,92 @@ func ReverseProxyListVdir(w http.ResponseWriter, r *http.Request) {
 	utils.SendJSONResponse(w, string(js))
 }
 
+// Add Virtual Directory to a host
+func ReverseProxyAddVdir(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
+	}
+
+	matchingPath, err := utils.PostPara(r, "path")
+	if err != nil {
+		utils.SendErrorResponse(w, "matching path not defined")
+		return
+	}
+
+	domain, err := utils.PostPara(r, "domain")
+	if err != nil {
+		utils.SendErrorResponse(w, "target domain not defined")
+		return
+	}
+
+	reqTLSStr, err := utils.PostPara(r, "reqTLS")
+	if err != nil {
+		//Assume false
+		reqTLSStr = "false"
+	}
+	reqTLS := (reqTLSStr == "true")
+
+	skipValidStr, err := utils.PostPara(r, "skipValid")
+	if err != nil {
+		//Assume false
+		skipValidStr = "false"
+	}
+
+	skipValid := (skipValidStr == "true")
+
+	//Load the target proxy endpoint from runtime
+	var targetProxyEndpoint *dynamicproxy.ProxyEndpoint
+	if eptype == "root" {
+		targetProxyEndpoint = dynamicProxyRouter.Root
+	} else if eptype == "host" {
+		endpointID, err := utils.PostPara(r, "endpoint")
+		if err != nil {
+			utils.SendErrorResponse(w, "endpoint not defined")
+			return
+		}
+
+		loadedEndpoint, err := dynamicProxyRouter.LoadProxy(endpointID)
+		if err != nil {
+			utils.SendErrorResponse(w, "selected proxy host not exists")
+			return
+		}
+
+		targetProxyEndpoint = loadedEndpoint
+	} else {
+		utils.SendErrorResponse(w, "invalid proxy type given")
+		return
+	}
+
+	// Create a virtual directory entry base on the above info
+	newVirtualDirectoryRouter := dynamicproxy.VirtualDirectoryEndpoint{
+		MatchingPath:        matchingPath,
+		Domain:              domain,
+		RequireTLS:          reqTLS,
+		SkipCertValidations: skipValid,
+	}
+
+	//Append the virtual directory entry to the endpoint
+	targetProxyEndpoint.VirtualDirectories = append(targetProxyEndpoint.VirtualDirectories, &newVirtualDirectoryRouter)
+
+	//Prepare to replace the current routing rule
+	readyRoutingRule, err := dynamicProxyRouter.PrepareProxyRoute(targetProxyEndpoint)
+	if err != nil {
+		utils.SendErrorResponse(w, err.Error())
+		return
+	}
+	targetProxyEndpoint.Remove()
+	dynamicProxyRouter.AddProxyRouteToRuntime(readyRoutingRule)
+
+	//Save it to file
+	SaveReverseProxyConfig(targetProxyEndpoint)
+
+	// Update uptime monitor
+	UpdateUptimeMonitorTargets()
+	utils.SendOK(w)
+}
+
 // Handle port 80 incoming traffics
 func HandleUpdatePort80Listener(w http.ResponseWriter, r *http.Request) {
 	enabled, err := utils.GetPara(r, "enable")

+ 2 - 2
web/components/httprp.html

@@ -29,11 +29,11 @@
             $("#httpProxyList").html(``);
             if (data.error !== undefined){
                     $("#httpProxyList").append(`<tr>
-                    <td data-label="" colspan="3"><i class="remove icon"></i> ${data.error}</td>
+                    <td data-label="" colspan="4"><i class="remove icon"></i> ${data.error}</td>
                 </tr>`);
             }else if (data.length == 0){
                 $("#httpProxyList").append(`<tr>
-                    <td data-label="" colspan="3"><i class="green check circle icon"></i> No HTTP Proxy Record</td>
+                    <td data-label="" colspan="4"><i class="green check circle icon"></i> No HTTP Proxy Record</td>
                 </tr>`);
             }else{
                 data.forEach(subd => {

+ 1 - 1
web/components/redirection.html

@@ -169,7 +169,7 @@
             });
 
             if (data.length == 0){
-              $("#redirectionRuleList").append(`<tr colspan="4"><td><i class="checkmark icon"></i> No redirection rule</td></tr>`);
+              $("#redirectionRuleList").append(`<tr colspan="4"><td><i class="green check circle icon"></i> No redirection rule</td></tr>`);
             }
             
         });

+ 1 - 1
web/components/rules.html

@@ -87,7 +87,7 @@
                         </div>
                     </div>
                     <br>
-                    <button class="ui basic button" onclick="newProxyEndpoint();"><i class="blue add icon"></i> Create Endpoint</button>
+                    <button class="ui basic button" onclick="newProxyEndpoint();"><i class="green add icon"></i> Create Endpoint</button>
                     <br><br>
                 </div>
             </div>

+ 179 - 9
web/components/vdir.html

@@ -3,6 +3,9 @@
         <h2>Virtual Directory</h2>
         <p>A virtual directory is a consolidated view of multiple directories that provides a unified entry point for users to access disparate sources.</p>
     </div>
+    <div id="currentVirtualDirectoryAttachingHost" class="ui basic segment">
+        Select a host / routing rule to start editing Virtual Directory
+    </div>  
     <div class="ui stackable grid">
         <div class="six wide column">
             <h4>Select a Target Host / Site</h4>
@@ -24,31 +27,70 @@
             </div>
         </div>
         <div class="ten wide column">
-            <h4>Virtual Directory Routing Rules</h4>
+            <h4>Edit Virtual Directory Routing Rules</h4>
             <p>The following are the list of Virtual Directories currently handled by the host router above</p>
             <div style="width: 100%; overflow-x: auto; margin-bottom: 1em;">
                 <table class="ui celled sortable basic unstackable compact table">
                     <thead>
                         <tr>
                             <th>Virtual Directory</th>
-                            <th>Proxy To</th>
-                            <th>Basic Auth</th>
+                            <th>Destination</th>
                             <th class="no-sort" style="min-width: 7.2em;">Actions</th>
                         </tr>
                     </thead>
                     <tbody id="vdirList">
                         <tr>
-                            <td data-label=""><button class="ui circular mini red basic button"><i class="remove icon"></i> Remove Proxy</button></td>
+                            <td data-label="" colspan="3">No Selected Host</td>
                         </tr>
                     </tbody>
                 </table>
             </div>
             <button class="ui icon right floated basic button" onclick="listVdirs();"><i class="green refresh icon"></i> Refresh</button>
+            <br><br>
+            <div class="ui divider"></div>
+            <div id="newVDSection" class="disabled section">
+                <h4>New Virtual Directory Rule</h4>
+                <form class="ui form">
+                    <div class="field">
+                        <label>Matching Path Prefix</label>
+                        <input type="text" id="virtualDirectoryPath" placeholder="/mysite/">
+                        <small>Path that follows your select host / domain, e.g. <code>/mysite/</code> as path prefix will forward all request that matches <code>mydomain.com/mysite/*</code></small>
+                    </div>
+                    <div class="field">
+                        <label>Target IP Address or Domain Name with port</label>
+                        <input type="text" id="virtualDirectoryDomain" onchange="updateVDTargetTLSState();">
+                        <small>E.g. 192.168.0.101:8000 or example.com</small>
+                    </div>
+                    <div class="field">
+                        <div class="ui checkbox">
+                            <input type="checkbox" id="vdReqTls">
+                            <label>Proxy Target require TLS Connection <br><small>(i.e. Your proxy target starts with https://)</small></label>
+                        </div>
+                    </div>
+
+                    <!-- Advance configs -->
+                    <div class="ui basic segment" style="background-color: #f7f7f7; border-radius: 1em;">
+                        <div id="advanceProxyRules" class="ui fluid accordion">
+                            <div class="title">
+                            <i class="dropdown icon"></i>
+                            Advance Settings
+                            </div>
+                            <div class="content">
+                                <p></p>
+                                <div class="field">
+                                    <div class="ui checkbox">
+                                        <input type="checkbox" id="vdSkipTLSValidation">
+                                        <label>Ignore TLS/SSL Verification Error<br><small>For targets that is using self-signed, expired certificate (Not Recommended)</small></label>
+                                    </div>
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                    <button class="ui basic button" onclick="addVdirToHost(); event.preventDefault();"><i class="green add icon"></i> Create Virtual Directory</button>
+                </form>
+            </div>
         </div>
     </div>
-    
-    
-    
     <br><br>
 </div>
 <script>
@@ -83,24 +125,152 @@
 
             //Load the vdir list for root
             loadVdirList("root");
+            $("#newVDSection").removeClass("disabled");
         }else{
             $("#vdirBaseRoutingRule").parent().removeClass("disabled");
             let selectedEndpointRule = $("#vdirBaseRoutingRule").val();
             if (selectedEndpointRule != ""){
                 loadVdirList(selectedEndpointRule);
+                $("#newVDSection").removeClass("disabled");
+            }else{
+                $("#newVDSection").addClass("disabled");
             }
         }
     }
 
     function loadVdirList(endpoint){
-        alert("Loading endpoint " + endpoint)
+        $("#currentVirtualDirectoryAttachingHost").html(`Editing Host: ${endpoint}`);
+        let reqURL = "/api/proxy/vdir/list?type=host&ep=" + endpoint;
         if (endpoint == "root"){
             //Load root endpoint vdir list
+            reqURL = "/api/proxy/vdir/list?type=root";
+        }
+        
+        $.get(reqURL, function(data){
+            if (data.error != undefined){
+                msgbox(data.error, false);
+            }else{
+                $("#vdirList").html("");
+                if (data.length == 0){
+                    //No virtual directory for this host
+                    $("#vdirList").append(`<tr>
+                        <td data-label="" colspan="3"><i class="green check circle icon"></i> No Virtual Directory Routing Rule</td>
+                    </tr>`);
+                }else{
+                    //List the vdirs
+                    console.log(data);
+                    data.forEach(vdir => {
+                        $("#vdirList").append(`<tr>
+                            <td data-label="" editable="false">${vdir.MatchingPath}</td>
+                            <td data-label="" editable="true" datatype="domain">${vdir.Domain}</td>
+                            <td class="center aligned" editable="true" datatype="action" data-label="">
+                                <button class="ui circular mini basic icon button editBtn" onclick='editEndpoint("vdir","${vdir.RootOrMatchingDomain}")'><i class="edit icon"></i></button>
+                                <button class="ui circular mini red basic icon button"  onclick='deleteEndpoint("vdir","${vdir.RootOrMatchingDomain}")'><i class="trash icon"></i></button>
+                            </td>
+                        </tr>`);
+                    })
+                }
+            }
+        });
+    }
+
+    function updateVDTargetTLSState(){
+        var targetDomain = $("#virtualDirectoryDomain").val().trim();
+        if (targetDomain != ""){
+            $.ajax({
+                url: "/api/proxy/tlscheck",
+                data: {url: targetDomain},
+                success: function(data){
+                    if (data.error != undefined){
 
+                    }else if (data == "https"){
+                        $("#vdReqTls").parent().checkbox("set checked");
+                    }else if (data == "http"){
+                        $("#vdReqTls").parent().checkbox("set unchecked");
+                    }
+                }
+            });
+        }
+    }
+
+    function reloadVdirList(){
+        if ($("#useRootProxyRouterForVdir")[0].checked){
+            loadVdirList("root");
+            return;
+        }
+        let endpoint = $("#vdirBaseRoutingRule").val().trim();
+        if (endpoint != ""){
+            loadVdirList(endpoint);
+        }
+    }
+
+    //Create a virtual directory routing rule and attach to this endpoint
+    function addVdirToHost(){
+        var matchingPath = $("#virtualDirectoryPath").val().trim();
+        var targetDomain = $("#virtualDirectoryDomain").val().trim();
+        var reqTLS = $("#vdReqTls")[0].checked;
+        var skipTLSValidation = $("#vdSkipTLSValidation")[0].checked;
+
+        //Validate the input data
+        if (matchingPath == ""){
+            $("#virtualDirectoryPath").parent().addClass('error');
+            return;
+        }else{
+            $("#virtualDirectoryPath").parent().removeClass('error');
+        }
+
+        if (targetDomain == ""){
+            $("#virtualDirectoryDomain").parent().addClass('error');
+            return;
         }else{
-            //Load target endpoint list
+            $("#virtualDirectoryDomain").parent().removeClass('error');
+        }
 
+        //Check if we are editing host
+        let epType = "host";
+        let endpoint = "root";
+        if ($("#useRootProxyRouterForVdir")[0].checked){
+            //Editing root virtual directory
+            epType = "root";
+        }else{
+            //Editing hosts virtual directory
+            endpoint = $("#vdirBaseRoutingRule").val().trim();
         }
+
+        //Create a virtual directory endpoint
+        $.ajax({
+            url: "/api/proxy/vdir/add",
+            method: "POST",
+            data: {
+                "type": epType,
+                "endpoint": endpoint,
+                "path": matchingPath,
+                "domain":targetDomain,
+                "reqTLS":reqTLS,
+                "skipValid":skipTLSValidation,
+            },
+            success: function(data){
+                if (data.error != undefined){
+                    msgbox(data.error, false);
+                }else{
+                    msgbox("New Virtual Directory rule added");
+                    reloadVdirList();
+                    resetVdirForm();
+                }
+            }, 
+            error: function(){
+                msgbox("Add Virtual Directory failed due to unknown reasons", false);
+            }
+        })
+        
+    }
+
+    //Reset the vdir form
+    function resetVdirForm(){
+        $("#virtualDirectoryPath").val("");
+        $("#virtualDirectoryDomain").val("");
+        $("#vdReqTls").parent().checkbox("set unchecked");
+        $("#vdSkipTLSValidation").parent().checkbox("set unchecked");
     }
 
     /*

+ 12 - 1
web/main.css

@@ -465,10 +465,21 @@ body{
   }
 
 /*
-  HTTP Proxy overwrite
+  HTTP Proxy & Virtual Directory
 */
 
+#currentVirtualDirectoryAttachingHost{
+    background: var(--theme_background); 
+    color: white;
+    border-radius: 1em;
+    font-weight: bolder;
+}
 
+.section.disabled{
+    opacity: 0.5;
+    user-select: none;
+    pointer-events: none;
+}
 
 /*
     Access Control