Browse Source

auto update script executed

TC pushbot 5 3 years ago
parent
commit
800854dfd1
9 changed files with 290 additions and 28 deletions
  1. 2 0
      .gitignore
  2. 28 0
      README.md
  3. 76 0
      config.go
  4. 1 1
      main.go
  5. 29 7
      mod/dynamicproxy/dpcore/dpcore.go
  6. 4 2
      mod/dynamicproxy/dynamicproxy.go
  7. 25 8
      mod/reverseproxy/reverse.go
  8. 47 6
      reverseproxy.go
  9. 78 4
      web/index.html

+ 2 - 0
.gitignore

@@ -25,3 +25,5 @@ _testmain.go
 *.test
 *.prof
 
+conf/*
+ReverseProxy_*_*

+ 28 - 0
README.md

@@ -17,6 +17,34 @@ You can also use it separately as a really basic reverse proxy server that serve
 Requirement: Go 1.16 or above
 
 ```
+cd ~/arozos/subservices
+git clone {this_repo}
+cd ReverseProxy
 ./build.sh
 ```
 
+To start the module, make sure .disabled file does not exists and start arozos system. You should be able to see a new module named "ReverseProxy" pop up in the start menu.
+
+### Usage
+
+#### Proxy Modes
+
+There are two mode in the ReverseProxy Subservice
+
+1. vdir mode (Virtual Dirctories)
+2. subd mode (Subdomain Proxying Mode)
+
+
+
+Vdir mode proxy web request based on the virtual directories given in the request URL. For example, when configured to redirect /example to example.com, any visits to {your_domain}/example will be proxied to example.com.
+
+
+
+Subd mode proxy web request based on sub-domain exists in the request URL. For example, when configured to redirect example.localhost to example.com, any visits that includes example.localhost (e.g. example.localhost/page1) will be proxied to example.com (e.g. example.com/page1)
+
+#### Root Proxy
+
+Root proxy is the main proxy destination where if all proxy root name did not match, the request will be proxied to this request. If you are working with ArozOS system in default configuration, you can set this to localhost:8080 for any unknown request to be handled by the host ArozOS system
+
+
+

+ 76 - 0
config.go

@@ -0,0 +1,76 @@
+package main
+
+import (
+	"encoding/json"
+	"io/ioutil"
+	"log"
+	"os"
+	"path/filepath"
+	"strings"
+)
+
+type Record struct {
+	ProxyType   string
+	Rootname    string
+	ProxyTarget string
+	UseTLS      bool
+}
+
+func SaveReverseProxyConfig(ptype string, rootname string, proxyTarget string, useTLS bool) error {
+	os.MkdirAll("conf", 0775)
+	filename := getFilenameFromRootName(rootname)
+
+	//Generate record
+	thisRecord := Record{
+		ProxyType:   ptype,
+		Rootname:    rootname,
+		ProxyTarget: proxyTarget,
+		UseTLS:      useTLS,
+	}
+
+	//Write to file
+	js, _ := json.MarshalIndent(thisRecord, "", " ")
+	return ioutil.WriteFile(filepath.Join("conf", filename), js, 0775)
+}
+
+func RemoveReverseProxyConfig(rootname string) error {
+	filename := getFilenameFromRootName(rootname)
+	log.Println("Config Removed: ", filepath.Join("conf", filename))
+	if fileExists(filepath.Join("conf", filename)) {
+		err := os.Remove(filepath.Join("conf", filename))
+		if err != nil {
+			log.Println(err.Error())
+			return err
+		}
+	}
+
+	//File already gone
+	return nil
+}
+
+//Return ptype, rootname and proxyTarget, error if any
+func LoadReverseProxyConfig(filename string) (*Record, error) {
+	thisRecord := Record{}
+	configContent, err := ioutil.ReadFile(filename)
+	if err != nil {
+		return &thisRecord, err
+	}
+
+	//Unmarshal the content into config
+
+	err = json.Unmarshal(configContent, &thisRecord)
+	if err != nil {
+		return &thisRecord, err
+	}
+
+	//Return it
+	return &thisRecord, nil
+}
+
+func getFilenameFromRootName(rootname string) string {
+	//Generate a filename for this rootname
+	filename := strings.ReplaceAll(rootname, ".", "_")
+	filename = strings.ReplaceAll(filename, "/", "-")
+	filename = filename + ".config"
+	return filename
+}

+ 1 - 1
main.go

@@ -41,7 +41,7 @@ func main() {
 		SupportFW:   true,
 		LaunchFWDir: "reverseproxy/index.html",
 		SupportEmb:  false,
-		InitFWSize:  []int{420, 640},
+		InitFWSize:  []int{1080, 580},
 	})
 
 	//Register the standard web services urls

+ 29 - 7
mod/dynamicproxy/dpcore/dpcore.go

@@ -58,6 +58,8 @@ type ReverseProxy struct {
 	//Prepender is an optional prepend text for URL rewrite
 	//
 	Prepender string
+
+	Verbal bool
 }
 
 type requestCanceler interface {
@@ -89,6 +91,7 @@ func NewDynamicProxyCore(target *url.URL, prepender string) *ReverseProxy {
 	return &ReverseProxy{
 		Director:  director,
 		Prepender: prepender,
+		Verbal:    false,
 	}
 }
 
@@ -270,7 +273,10 @@ func (p *ReverseProxy) ProxyHTTP(rw http.ResponseWriter, req *http.Request) erro
 
 	res, err := transport.RoundTrip(outreq)
 	if err != nil {
-		p.logf("http: proxy error: %v", err)
+		if p.Verbal {
+			p.logf("http: proxy error: %v", err)
+		}
+
 		rw.WriteHeader(http.StatusBadGateway)
 		return err
 	}
@@ -280,7 +286,10 @@ func (p *ReverseProxy) ProxyHTTP(rw http.ResponseWriter, req *http.Request) erro
 
 	if p.ModifyResponse != nil {
 		if err := p.ModifyResponse(res); err != nil {
-			p.logf("http: proxy error: %v", err)
+			if p.Verbal {
+				p.logf("http: proxy error: %v", err)
+			}
+
 			rw.WriteHeader(http.StatusBadGateway)
 			return err
 		}
@@ -331,13 +340,18 @@ func (p *ReverseProxy) ProxyHTTPS(rw http.ResponseWriter, req *http.Request) err
 
 	clientConn, _, err := hij.Hijack()
 	if err != nil {
-		p.logf("http: proxy error: %v", err)
+		if p.Verbal {
+			p.logf("http: proxy error: %v", err)
+		}
 		return err
 	}
 
 	proxyConn, err := net.Dial("tcp", req.URL.Host)
 	if err != nil {
-		p.logf("http: proxy error: %v", err)
+		if p.Verbal {
+			p.logf("http: proxy error: %v", err)
+		}
+
 		return err
 	}
 
@@ -354,19 +368,27 @@ func (p *ReverseProxy) ProxyHTTPS(rw http.ResponseWriter, req *http.Request) err
 
 	err = clientConn.SetDeadline(deadline)
 	if err != nil {
-		p.logf("http: proxy error: %v", err)
+		if p.Verbal {
+			p.logf("http: proxy error: %v", err)
+		}
 		return err
 	}
 
 	err = proxyConn.SetDeadline(deadline)
 	if err != nil {
-		p.logf("http: proxy error: %v", err)
+		if p.Verbal {
+			p.logf("http: proxy error: %v", err)
+		}
+
 		return err
 	}
 
 	_, err = clientConn.Write([]byte("HTTP/1.0 200 OK\r\n\r\n"))
 	if err != nil {
-		p.logf("http: proxy error: %v", err)
+		if p.Verbal {
+			p.logf("http: proxy error: %v", err)
+		}
+
 		return err
 	}
 

+ 4 - 2
mod/dynamicproxy/dynamicproxy.go

@@ -135,12 +135,14 @@ func (router *Router) AddVirtualDirectoryProxyService(rootname string, domain st
 
 	proxy := dpcore.NewDynamicProxyCore(path, rootname)
 
-	router.ProxyEndpoints.Store(rootname, &ProxyEndpoint{
+	endpointObject := ProxyEndpoint{
 		Root:       rootname,
 		Domain:     domain,
 		RequireTLS: requireTLS,
 		Proxy:      proxy,
-	})
+	}
+
+	router.ProxyEndpoints.Store(rootname, &endpointObject)
 
 	log.Println("Adding Proxy Rule: ", rootname+" to "+domain)
 	return nil

+ 25 - 8
mod/reverseproxy/reverse.go

@@ -52,6 +52,8 @@ type ReverseProxy struct {
 	// modifies the Response from the backend.
 	// If it returns an error, the proxy returns a StatusBadGateway error.
 	ModifyResponse func(*http.Response) error
+
+	Verbal bool
 }
 
 type requestCanceler interface {
@@ -89,7 +91,7 @@ func NewReverseProxy(target *url.URL) *ReverseProxy {
 		}
 	}
 
-	return &ReverseProxy{Director: director}
+	return &ReverseProxy{Director: director, Verbal: false}
 }
 
 func singleJoiningSlash(a, b string) string {
@@ -270,7 +272,10 @@ func (p *ReverseProxy) ProxyHTTP(rw http.ResponseWriter, req *http.Request) erro
 
 	res, err := transport.RoundTrip(outreq)
 	if err != nil {
-		p.logf("http: proxy error: %v", err)
+		if p.Verbal {
+			p.logf("http: proxy error: %v", err)
+		}
+
 		rw.WriteHeader(http.StatusBadGateway)
 		return err
 	}
@@ -280,7 +285,9 @@ func (p *ReverseProxy) ProxyHTTP(rw http.ResponseWriter, req *http.Request) erro
 
 	if p.ModifyResponse != nil {
 		if err := p.ModifyResponse(res); err != nil {
-			p.logf("http: proxy error: %v", err)
+			if p.Verbal {
+				p.logf("http: proxy error: %v", err)
+			}
 			rw.WriteHeader(http.StatusBadGateway)
 			return err
 		}
@@ -325,13 +332,17 @@ func (p *ReverseProxy) ProxyHTTPS(rw http.ResponseWriter, req *http.Request) err
 
 	clientConn, _, err := hij.Hijack()
 	if err != nil {
-		p.logf("http: proxy error: %v", err)
+		if p.Verbal {
+			p.logf("http: proxy error: %v", err)
+		}
 		return err
 	}
 
 	proxyConn, err := net.Dial("tcp", req.URL.Host)
 	if err != nil {
-		p.logf("http: proxy error: %v", err)
+		if p.Verbal {
+			p.logf("http: proxy error: %v", err)
+		}
 		return err
 	}
 
@@ -348,19 +359,25 @@ func (p *ReverseProxy) ProxyHTTPS(rw http.ResponseWriter, req *http.Request) err
 
 	err = clientConn.SetDeadline(deadline)
 	if err != nil {
-		p.logf("http: proxy error: %v", err)
+		if p.Verbal {
+			p.logf("http: proxy error: %v", err)
+		}
 		return err
 	}
 
 	err = proxyConn.SetDeadline(deadline)
 	if err != nil {
-		p.logf("http: proxy error: %v", err)
+		if p.Verbal {
+			p.logf("http: proxy error: %v", err)
+		}
 		return err
 	}
 
 	_, err = clientConn.Write([]byte("HTTP/1.0 200 OK\r\n\r\n"))
 	if err != nil {
-		p.logf("http: proxy error: %v", err)
+		if p.Verbal {
+			p.logf("http: proxy error: %v", err)
+		}
 		return err
 	}
 

+ 47 - 6
reverseproxy.go

@@ -4,6 +4,7 @@ import (
 	"encoding/json"
 	"log"
 	"net/http"
+	"path/filepath"
 
 	"imuslab.com/arozos/ReverseProxy/mod/dynamicproxy"
 )
@@ -26,13 +27,39 @@ func ReverseProxtInit() {
 	http.HandleFunc("/add", ReverseProxyHandleAddEndpoint)
 	http.HandleFunc("/status", ReverseProxyStatus)
 	http.HandleFunc("/list", ReverseProxyList)
+	http.HandleFunc("/del", DeleteProxyEndpoint)
 
-	dynamicProxyRouter.SetRootProxy("192.168.0.107:8080", false)
-	dynamicProxyRouter.AddSubdomainRoutingService("aroz.localhost", "192.168.0.107:8080/private/AOB/", false)
-	dynamicProxyRouter.AddSubdomainRoutingService("loopback.localhost", "localhost:8080", false)
-	dynamicProxyRouter.AddSubdomainRoutingService("git.localhost", "mc.alanyeung.co:3000", false)
-	dynamicProxyRouter.AddVirtualDirectoryProxyService("/git/server/", "mc.alanyeung.co:3000", false)
+	//Load all conf from files
+	confs, _ := filepath.Glob("./conf/*.config")
+	for _, conf := range confs {
+		record, err := LoadReverseProxyConfig(conf)
+		if err != nil {
+			log.Println("Failed to load "+filepath.Base(conf), err.Error())
+			return
+		}
+
+		if record.ProxyType == "root" {
+			dynamicProxyRouter.SetRootProxy(record.ProxyTarget, record.UseTLS)
+		} else if record.ProxyType == "subd" {
+			dynamicProxyRouter.AddSubdomainRoutingService(record.Rootname, record.ProxyTarget, record.UseTLS)
+		} else if record.ProxyType == "vdir" {
+			dynamicProxyRouter.AddVirtualDirectoryProxyService(record.Rootname, record.ProxyTarget, record.UseTLS)
+		} else {
+			log.Println("Unsupported endpoint type: " + record.ProxyType + ". Skipping " + filepath.Base(conf))
+		}
+	}
+
+	/*
+		dynamicProxyRouter.SetRootProxy("192.168.0.107:8080", false)
+		dynamicProxyRouter.AddSubdomainRoutingService("aroz.localhost", "192.168.0.107:8080/private/AOB/", false)
+		dynamicProxyRouter.AddSubdomainRoutingService("loopback.localhost", "localhost:8080", false)
+		dynamicProxyRouter.AddSubdomainRoutingService("git.localhost", "mc.alanyeung.co:3000", false)
+		dynamicProxyRouter.AddVirtualDirectoryProxyService("/git/server/", "mc.alanyeung.co:3000", false)
+	*/
+
+	//Start Service
 	dynamicProxyRouter.StartProxyService()
+
 	/*
 		go func() {
 			time.Sleep(10 * time.Second)
@@ -82,13 +109,14 @@ func ReverseProxyHandleAddEndpoint(w http.ResponseWriter, r *http.Request) {
 	}
 
 	useTLS := (tls == "true")
-
+	rootname := ""
 	if eptype == "vdir" {
 		vdir, err := mv(r, "rootname", true)
 		if err != nil {
 			sendErrorResponse(w, "vdir not defined")
 			return
 		}
+		rootname = vdir
 		dynamicProxyRouter.AddVirtualDirectoryProxyService(vdir, endpoint, useTLS)
 
 	} else if eptype == "subd" {
@@ -97,11 +125,20 @@ func ReverseProxyHandleAddEndpoint(w http.ResponseWriter, r *http.Request) {
 			sendErrorResponse(w, "subdomain not defined")
 			return
 		}
+		rootname = subdomain
 		dynamicProxyRouter.AddSubdomainRoutingService(subdomain, endpoint, useTLS)
 	} else if eptype == "root" {
+		rootname = "root"
 		dynamicProxyRouter.SetRootProxy(endpoint, useTLS)
+	} else {
+		//Invalid eptype
+		sendErrorResponse(w, "Invalid endpoint type")
+		return
 	}
 
+	//Save it
+	SaveReverseProxyConfig(eptype, rootname, endpoint, useTLS)
+
 	sendOK(w)
 
 }
@@ -122,6 +159,7 @@ func DeleteProxyEndpoint(w http.ResponseWriter, r *http.Request) {
 		sendErrorResponse(w, err.Error())
 	}
 
+	RemoveReverseProxyConfig(ep)
 	sendOK(w)
 }
 
@@ -154,6 +192,9 @@ func ReverseProxyList(w http.ResponseWriter, r *http.Request) {
 		})
 		js, _ := json.Marshal(results)
 		sendJSONResponse(w, string(js))
+	} else if eptype == "root" {
+		js, _ := json.Marshal(dynamicProxyRouter.Root)
+		sendJSONResponse(w, string(js))
 	} else {
 		sendErrorResponse(w, "Invalid type given")
 	}

+ 78 - 4
web/index.html

@@ -135,7 +135,7 @@
                                     <input type="text" id="proxyDomain">
                                     <small>E.g. 192.168.0.101:8000 or example.com</small>
                                 </div>
-                                    <div class="field">
+                                <div class="field">
                                     <div class="ui checkbox">
                                         <input type="checkbox" id="reqTls">
                                         <label>Proxy Target require TLS Connection (Unstable)</label>
@@ -143,6 +143,9 @@
                                 </div>
                                 <button class="ui teal button" onclick="newProxyEndpoint();">Create Proxy Endpoint</button>
                             </div>
+                            <div class="ui green message" id="proxyaddSucc" style="display:none">
+                                <i class="ui checkmark icon"></i> Proxy Endpoint Added
+                            </div>
                         </div>
                      </div>
 
@@ -150,7 +153,24 @@
                     <div id="setroot" class="functiontab">
                         <h3><i class="ui home icon"></i> Set Proxy Root</h3>
                         <p>For all routing not found in the proxy rule, will be redirected to the proxy root server.</p>
-                        <button class="ui button" onclick=""><i class="edit icon"></i> Set Proxy Root</button>
+                        <div class="ui form">
+                            <div class="field">
+                                <label>Proxy Root</label>
+                                <input type="text" id="proxyRoot">
+                                <small>E.g. localhost:8080</small>
+                            </div>
+                            <div class="field">
+                                <div class="ui checkbox">
+                                    <input type="checkbox" id="rootReqTLS">
+                                    <label>Root require TLS Connection (Not Recommended)</label>
+                                </div>
+                            </div>
+                        </div>
+                        <br>
+                        <button class="ui teal button" onclick="setProxyRoot()"><i class="home icon" ></i> Set Proxy Root</button>
+                        <div class="ui green message" id="ProxyRootUpdate" style="display:none">
+                            <i class="ui checkmark icon"></i> Proxy Root Updated
+                        </div>
                     </div>
                 </div>
               </div>
@@ -197,6 +217,20 @@
                 });
             }
 
+            function deleteEndpoint(ptype, epoint){
+                if (confirm("Confirm remove proxy for :" + epoint + " (type: " + ptype + ")?")){
+                    $.ajax({
+                        url: "./del",
+                        data: {ep: epoint, ptype: ptype},
+                        success: function(){
+                            listVdirs();
+                            listSubd();
+                        }
+                    })
+                }
+               
+            }
+
             function startService(){
                 $.post("enable", {enable: true}, function(data){
                     if (data.error != undefined){
@@ -237,7 +271,7 @@
                             $("#vdirList").append(`<tr>
                                 <td data-label="">${vdir.Root}</td>
                                 <td data-label="">${vdir.Domain} ${tlsIcon}</td>
-                                <td data-label=""><button class="ui circular mini red basic button"><i class="remove icon"></i> Remove Vdir</button></td>
+                                <td data-label=""><button class="ui circular mini red basic button"  onclick='deleteEndpoint("subd","${subd.Root}")'><i class="remove icon"></i> Remove Vdir</button></td>
                             </tr>`);
                         });
                     }
@@ -265,7 +299,7 @@
                             $("#subdList").append(`<tr>
                                 <td data-label="">${subd.MatchingDomain}</td>
                                 <td data-label="">${subd.Domain} ${tlsIcon}</td>
-                                <td data-label=""><button class="ui circular mini red basic button"><i class="remove icon"></i> Remove Subd</button></td>
+                                <td data-label=""><button class="ui circular mini red basic button" onclick='deleteEndpoint("subd","${subd.MatchingDomain}")'><i class="remove icon"></i> Remove Subd</button></td>
                             </tr>`);
                         });
                     }
@@ -304,12 +338,52 @@
                             //OK
                             listVdirs();
                             listSubd();
+                            $("#proxyaddSucc").stop().slideDown('fast').delay(3000).slideUp('fast');
                         }
                     }
                 });
                
             }
 
+            function setProxyRoot(){
+                var newpr = $("#proxyRoot").val();
+                if (newpr.trim() == ""){
+                    $("#proxyRoot").parent().addClass('error');
+                    return
+                }else{
+                    $("#proxyRoot").parent().removeClass('error');
+                }
+
+                var rootReqTls = $("#rootReqTLS")[0].checked;
+
+                //Create the endpoint by calling add
+                $.ajax({
+                    url: "./add",
+                    data: {"type": "root", tls: rootReqTls, ep: newpr},
+                    success: function(data){
+                        if (data.error != undefined){
+                            alert(data.error);
+                        }else{
+                            //OK
+                            initRootInfo();
+                            $("#ProxyRootUpdate").stop().slideDown('fast').delay(3000).slideUp('fast');
+                        }
+                    }
+                });
+
+            }
+
+            initRootInfo();
+            function initRootInfo(){
+                $.get("list?type=root", function(data){
+                    if (data == null){
+
+                    }else{
+                        $("#proxyRoot").val(data.Domain);
+                    }
+                });
+            }
+
             function errmsg(message){
                 $("#errmsg").html(`<i class="red remove icon"></i> ${message}`);
                 $("#errmsg").slideDown('fast').delay(5000).slideUp('fast');