فهرست منبع

Added more restructing

Toby Chui 3 ماه پیش
والد
کامیت
69218c56bb

+ 16 - 12
config.go

@@ -59,7 +59,7 @@ func LoadReverseProxyConfig(configFilepath string) error {
 		thisConfigEndpoint.RootOrMatchingDomain = "/"
 	}
 
-	if thisConfigEndpoint.ProxyType == dynamicproxy.ProxyType_Root {
+	if thisConfigEndpoint.ProxyType == dynamicproxy.ProxyTypeRoot {
 		//This is a root config file
 		rootProxyEndpoint, err := dynamicProxyRouter.PrepareProxyRoute(&thisConfigEndpoint)
 		if err != nil {
@@ -68,7 +68,7 @@ func LoadReverseProxyConfig(configFilepath string) error {
 
 		dynamicProxyRouter.SetProxyRouteAsRoot(rootProxyEndpoint)
 
-	} else if thisConfigEndpoint.ProxyType == dynamicproxy.ProxyType_Host {
+	} else if thisConfigEndpoint.ProxyType == dynamicproxy.ProxyTypeHost {
 		//This is a host config file
 		readyProxyEndpoint, err := dynamicProxyRouter.PrepareProxyRoute(&thisConfigEndpoint)
 		if err != nil {
@@ -97,7 +97,7 @@ func filterProxyConfigFilename(filename string) string {
 func SaveReverseProxyConfig(endpoint *dynamicproxy.ProxyEndpoint) error {
 	//Get filename for saving
 	filename := filepath.Join("./conf/proxy/", endpoint.RootOrMatchingDomain+".config")
-	if endpoint.ProxyType == dynamicproxy.ProxyType_Root {
+	if endpoint.ProxyType == dynamicproxy.ProxyTypeRoot {
 		filename = "./conf/proxy/root.config"
 	}
 
@@ -129,9 +129,15 @@ func RemoveReverseProxyConfig(endpoint string) error {
 // Get the default root config that point to the internal static web server
 // this will be used if root config is not found (new deployment / missing root.config file)
 func GetDefaultRootConfig() (*dynamicproxy.ProxyEndpoint, error) {
+	//Default Authentication Provider
+	defaultAuth := &dynamicproxy.AuthenticationProvider{
+		AuthMethod:              dynamicproxy.AuthMethodNone,
+		BasicAuthCredentials:    []*dynamicproxy.BasicAuthCredentials{},
+		BasicAuthExceptionRules: []*dynamicproxy.BasicAuthExceptionRule{},
+	}
 	//Default settings
 	rootProxyEndpoint, err := dynamicProxyRouter.PrepareProxyRoute(&dynamicproxy.ProxyEndpoint{
-		ProxyType:            dynamicproxy.ProxyType_Root,
+		ProxyType:            dynamicproxy.ProxyTypeRoot,
 		RootOrMatchingDomain: "/",
 		ActiveOrigins: []*loadbalance.Upstream{
 			{
@@ -141,14 +147,12 @@ func GetDefaultRootConfig() (*dynamicproxy.ProxyEndpoint, error) {
 				Weight:              0,
 			},
 		},
-		InactiveOrigins:         []*loadbalance.Upstream{},
-		BypassGlobalTLS:         false,
-		VirtualDirectories:      []*dynamicproxy.VirtualDirectoryEndpoint{},
-		RequireBasicAuth:        false,
-		BasicAuthCredentials:    []*dynamicproxy.BasicAuthCredentials{},
-		BasicAuthExceptionRules: []*dynamicproxy.BasicAuthExceptionRule{},
-		DefaultSiteOption:       dynamicproxy.DefaultSite_InternalStaticWebServer,
-		DefaultSiteValue:        "",
+		InactiveOrigins:        []*loadbalance.Upstream{},
+		BypassGlobalTLS:        false,
+		VirtualDirectories:     []*dynamicproxy.VirtualDirectoryEndpoint{},
+		AuthenticationProvider: defaultAuth,
+		DefaultSiteOption:      dynamicproxy.DefaultSite_InternalStaticWebServer,
+		DefaultSiteValue:       "",
 	})
 	if err != nil {
 		return nil, err

+ 87 - 0
mod/auth/sso/authelia/authelia.go

@@ -0,0 +1,87 @@
+package authelia
+
+import (
+	"errors"
+	"fmt"
+	"net/http"
+	"net/url"
+
+	"imuslab.com/zoraxy/mod/dynamicproxy"
+	"imuslab.com/zoraxy/mod/info/logger"
+)
+
+type Options struct {
+	AutheliaURL string //URL of the Authelia server, e.g. authelia.example.com
+	UseHTTPS    bool   //Whether to use HTTPS for the Authelia server
+	Logger      logger.Logger
+}
+
+type AutheliaHandler struct {
+	options *Options
+}
+
+func NewAutheliaAuthenticator(options *Options) *AutheliaHandler {
+	return &AutheliaHandler{
+		options: options,
+	}
+}
+
+// HandleAutheliaAuthRouting is the handler for Authelia authentication, if the error is not nil, the request will be forwarded to the endpoint
+// Do not continue processing or write to the response writer if the error is not nil
+func (h *AutheliaHandler) HandleAutheliaAuthRouting(w http.ResponseWriter, r *http.Request, pe *dynamicproxy.ProxyEndpoint) error {
+	err := h.handleAutheliaAuth(w, r)
+	if err != nil {
+		return nil
+	}
+	return err
+}
+
+func (h *AutheliaHandler) handleAutheliaAuth(w http.ResponseWriter, r *http.Request) error {
+	client := &http.Client{}
+
+	protocol := "http"
+	if h.options.UseHTTPS {
+		protocol = "https"
+	}
+
+	autheliaBaseURL := protocol + "://" + h.options.AutheliaURL
+	//Remove tailing slash if any
+	if autheliaBaseURL[len(autheliaBaseURL)-1] == '/' {
+		autheliaBaseURL = autheliaBaseURL[:len(autheliaBaseURL)-1]
+	}
+
+	//Make a request to Authelia to verify the request
+	req, err := http.NewRequest("POST", autheliaBaseURL+"/api/verify", nil)
+	if err != nil {
+		h.options.Logger.PrintAndLog("Authelia", "Unable to create request", err)
+		w.WriteHeader(401)
+		return errors.New("unauthorized")
+	}
+
+	scheme := "http"
+	if r.TLS != nil {
+		scheme = "https"
+	}
+	req.Header.Add("X-Original-URL", fmt.Sprintf("%s://%s", scheme, r.Host))
+
+	// Copy cookies from the incoming request
+	for _, cookie := range r.Cookies() {
+		req.AddCookie(cookie)
+	}
+
+	// Making the verification request
+	resp, err := client.Do(req)
+	if err != nil {
+		h.options.Logger.PrintAndLog("Authelia", "Unable to verify", err)
+		w.WriteHeader(401)
+		return errors.New("unauthorized")
+	}
+
+	if resp.StatusCode != 200 {
+		redirectURL := autheliaBaseURL + "/?rd=" + url.QueryEscape(scheme+"://"+r.Host+r.URL.String()) + "&rm=" + r.Method
+		http.Redirect(w, r, redirectURL, http.StatusSeeOther)
+		return errors.New("unauthorized")
+	}
+
+	return nil
+}

+ 11 - 9
mod/dynamicproxy/Server.go

@@ -84,16 +84,18 @@ func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 		}
 
 		//SSO Interception Mode
-		if sep.UseSSOIntercept {
-			allowPass := h.Parent.Option.SSOHandler.ServeForwardAuth(w, r)
-			if !allowPass {
-				h.Parent.Option.Logger.LogHTTPRequest(r, "sso-x", 307)
-				return
+		/*
+			if sep.AuthenticationProvider.SSOInterceptMode {
+				allowPass := h.Parent.Option.SSOHandler.ServeForwardAuth(w, r)
+				if !allowPass {
+					h.Parent.Option.Logger.LogHTTPRequest(r, "sso-x", 307)
+					return
+				}
 			}
-		}
+		*/
 
 		//Validate basic auth
-		if sep.RequireBasicAuth {
+		if sep.AuthenticationProvider.AuthMethod == AuthMethodBasic {
 			err := h.handleBasicAuthRouting(w, r, sep)
 			if err != nil {
 				h.Parent.Option.Logger.LogHTTPRequest(r, "host", 401)
@@ -108,7 +110,7 @@ func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 			//Virtual directory routing rule found. Route via vdir mode
 			h.vdirRequest(w, r, targetProxyEndpoint)
 			return
-		} else if !strings.HasSuffix(proxyingPath, "/") && sep.ProxyType != ProxyType_Root {
+		} else if !strings.HasSuffix(proxyingPath, "/") && sep.ProxyType != ProxyTypeRoot {
 			potentialProxtEndpoint := sep.GetVirtualDirectoryHandlerFromRequestURI(proxyingPath + "/")
 			if potentialProxtEndpoint != nil && !potentialProxtEndpoint.Disabled {
 				//Missing tailing slash. Redirect to target proxy endpoint
@@ -180,7 +182,7 @@ func (h *ProxyHandler) handleRootRouting(w http.ResponseWriter, r *http.Request)
 			//Virtual directory routing rule found. Route via vdir mode
 			h.vdirRequest(w, r, targetProxyEndpoint)
 			return
-		} else if !strings.HasSuffix(proxyingPath, "/") && proot.ProxyType != ProxyType_Root {
+		} else if !strings.HasSuffix(proxyingPath, "/") && proot.ProxyType != ProxyTypeRoot {
 			potentialProxtEndpoint := proot.GetVirtualDirectoryHandlerFromRequestURI(proxyingPath + "/")
 			if potentialProxtEndpoint != nil && !targetProxyEndpoint.Disabled {
 				//Missing tailing slash. Redirect to target proxy endpoint

+ 0 - 57
mod/dynamicproxy/authelia.go

@@ -1,57 +0,0 @@
-package dynamicproxy
-
-import (
-	"errors"
-	"fmt"
-	"net/http"
-	"net/url"
-)
-
-func (h *ProxyHandler) handleAutheliaAuthRouting(w http.ResponseWriter, r *http.Request, pe *ProxyEndpoint) error {
-	err := handleAutheliaAuth(w, r, pe)
-	if err != nil {
-		h.Parent.logRequest(r, false, 401, "host", r.URL.Hostname())
-	}
-	return err
-}
-
-func handleAutheliaAuth(w http.ResponseWriter, r *http.Request, pe *ProxyEndpoint) error {
-
-	client := &http.Client{}
-
-	// TODO: provide authelia url by config variable
-	req, err := http.NewRequest("POST", "https://authelia.mydomain.com/api/verify", nil)
-	if err != nil {
-		pe.parent.Option.Logger.PrintAndLog("Authelia", "Unable to create request", err)
-		w.WriteHeader(401)
-		return errors.New("unauthorized")
-	}
-
-	scheme := "http"
-	if r.TLS != nil {
-		scheme = "https"
-	}
-	req.Header.Add("X-Original-URL", fmt.Sprintf("%s://%s", scheme, r.Host))
-
-	// Copy cookies from the incoming request
-	for _, cookie := range r.Cookies() {
-		req.AddCookie(cookie)
-	}
-
-	resp, err := client.Do(req)
-	if err != nil {
-		pe.parent.Option.Logger.PrintAndLog("Authelia", "Unable to verify", err)
-		w.WriteHeader(401)
-		return errors.New("unauthorized")
-	}
-
-	if resp.StatusCode != 200 {
-		// TODO: provide authelia url by config variable
-		redirectURL := "https://authelia.mydomain.com/?rd=" + url.QueryEscape(scheme+"://"+r.Host+r.URL.String()) + "&rm=" + r.Method
-
-		http.Redirect(w, r, redirectURL, http.StatusSeeOther)
-		return errors.New("unauthorized")
-	}
-
-	return nil
-}

+ 3 - 3
mod/dynamicproxy/basicAuth.go

@@ -26,9 +26,9 @@ func (h *ProxyHandler) handleBasicAuthRouting(w http.ResponseWriter, r *http.Req
 // Handle basic auth logic
 // do not write to http.ResponseWriter if err return is not nil (already handled by this function)
 func handleBasicAuth(w http.ResponseWriter, r *http.Request, pe *ProxyEndpoint) error {
-	if len(pe.BasicAuthExceptionRules) > 0 {
+	if len(pe.AuthenticationProvider.BasicAuthExceptionRules) > 0 {
 		//Check if the current path matches the exception rules
-		for _, exceptionRule := range pe.BasicAuthExceptionRules {
+		for _, exceptionRule := range pe.AuthenticationProvider.BasicAuthExceptionRules {
 			if strings.HasPrefix(r.RequestURI, exceptionRule.PathPrefix) {
 				//This path is excluded from basic auth
 				return nil
@@ -46,7 +46,7 @@ func handleBasicAuth(w http.ResponseWriter, r *http.Request, pe *ProxyEndpoint)
 	//Check for the credentials to see if there is one matching
 	hashedPassword := auth.Hash(p)
 	matchingFound := false
-	for _, cred := range pe.BasicAuthCredentials {
+	for _, cred := range pe.AuthenticationProvider.BasicAuthCredentials {
 		if u == cred.Username && hashedPassword == cred.PasswordHash {
 			matchingFound = true
 

+ 3 - 3
mod/dynamicproxy/dynamicproxy.go

@@ -144,7 +144,7 @@ func (router *Router) StartProxyService() error {
 						}
 
 						//Validate basic auth
-						if sep.RequireBasicAuth {
+						if sep.AuthenticationProvider.AuthMethod == AuthMethodBasic {
 							err := handleBasicAuth(w, r, sep)
 							if err != nil {
 								return
@@ -161,8 +161,8 @@ func (router *Router) StartProxyService() error {
 							ProxyDomain:         selectedUpstream.OriginIpOrDomain,
 							OriginalHost:        originalHostHeader,
 							UseTLS:              selectedUpstream.RequireTLS,
-							HostHeaderOverwrite: sep.RequestHostOverwrite,
-							NoRemoveHopByHop:    sep.DisableHopByHopHeaderRemoval,
+							HostHeaderOverwrite: sep.HeaderRewriteRules.RequestHostOverwrite,
+							NoRemoveHopByHop:    sep.HeaderRewriteRules.DisableHopByHopHeaderRemoval,
 							PathPrefix:          "",
 							Version:             sep.parent.Option.HostVersion,
 						})

+ 6 - 6
mod/dynamicproxy/endpoints.go

@@ -27,7 +27,7 @@ import (
 
 // Check if a user define header exists in this endpoint, ignore case
 func (ep *ProxyEndpoint) UserDefinedHeaderExists(key string) bool {
-	for _, header := range ep.UserDefinedHeaders {
+	for _, header := range ep.HeaderRewriteRules.UserDefinedHeaders {
 		if strings.EqualFold(header.Key, key) {
 			return true
 		}
@@ -38,13 +38,13 @@ func (ep *ProxyEndpoint) UserDefinedHeaderExists(key string) bool {
 // Remvoe a user defined header from the list
 func (ep *ProxyEndpoint) RemoveUserDefinedHeader(key string) error {
 	newHeaderList := []*rewrite.UserDefinedHeader{}
-	for _, header := range ep.UserDefinedHeaders {
+	for _, header := range ep.HeaderRewriteRules.UserDefinedHeaders {
 		if !strings.EqualFold(header.Key, key) {
 			newHeaderList = append(newHeaderList, header)
 		}
 	}
 
-	ep.UserDefinedHeaders = newHeaderList
+	ep.HeaderRewriteRules.UserDefinedHeaders = newHeaderList
 
 	return nil
 }
@@ -56,7 +56,7 @@ func (ep *ProxyEndpoint) AddUserDefinedHeader(newHeaderRule *rewrite.UserDefined
 	}
 
 	newHeaderRule.Key = cases.Title(language.Und, cases.NoLower).String(newHeaderRule.Key)
-	ep.UserDefinedHeaders = append(ep.UserDefinedHeaders, newHeaderRule)
+	ep.HeaderRewriteRules.UserDefinedHeaders = append(ep.HeaderRewriteRules.UserDefinedHeaders, newHeaderRule)
 	return nil
 }
 
@@ -123,9 +123,9 @@ func (ep *ProxyEndpoint) AddVirtualDirectoryRule(vdir *VirtualDirectoryEndpoint)
 		return nil, err
 	}
 
-	if ep.ProxyType == ProxyType_Root {
+	if ep.ProxyType == ProxyTypeRoot {
 		parentRouter.Root = readyRoutingRule
-	} else if ep.ProxyType == ProxyType_Host {
+	} else if ep.ProxyType == ProxyTypeHost {
 		ep.Remove()
 		parentRouter.AddProxyRouteToRuntime(readyRoutingRule)
 	} else {

+ 11 - 11
mod/dynamicproxy/proxyRequestHandler.go

@@ -160,15 +160,15 @@ func (h *ProxyHandler) hostRequest(w http.ResponseWriter, r *http.Request, targe
 	}
 
 	//Populate the user-defined headers with the values from the request
-	rewrittenUserDefinedHeaders := rewrite.PopulateRequestHeaderVariables(r, target.UserDefinedHeaders)
+	rewrittenUserDefinedHeaders := rewrite.PopulateRequestHeaderVariables(r, target.HeaderRewriteRules.UserDefinedHeaders)
 
 	//Build downstream and upstream header rules
 	upstreamHeaders, downstreamHeaders := rewrite.SplitUpDownStreamHeaders(&rewrite.HeaderRewriteOptions{
 		UserDefinedHeaders:           rewrittenUserDefinedHeaders,
-		HSTSMaxAge:                   target.HSTSMaxAge,
+		HSTSMaxAge:                   target.HeaderRewriteRules.HSTSMaxAge,
 		HSTSIncludeSubdomains:        target.ContainsWildcardName(true),
-		EnablePermissionPolicyHeader: target.EnablePermissionPolicyHeader,
-		PermissionPolicy:             target.PermissionPolicy,
+		EnablePermissionPolicyHeader: target.HeaderRewriteRules.EnablePermissionPolicyHeader,
+		PermissionPolicy:             target.HeaderRewriteRules.PermissionPolicy,
 	})
 
 	//Handle the request reverse proxy
@@ -180,8 +180,8 @@ func (h *ProxyHandler) hostRequest(w http.ResponseWriter, r *http.Request, targe
 		PathPrefix:          "",
 		UpstreamHeaders:     upstreamHeaders,
 		DownstreamHeaders:   downstreamHeaders,
-		HostHeaderOverwrite: target.RequestHostOverwrite,
-		NoRemoveHopByHop:    target.DisableHopByHopHeaderRemoval,
+		HostHeaderOverwrite: target.HeaderRewriteRules.RequestHostOverwrite,
+		NoRemoveHopByHop:    target.HeaderRewriteRules.DisableHopByHopHeaderRemoval,
 		Version:             target.parent.Option.HostVersion,
 	})
 
@@ -238,15 +238,15 @@ func (h *ProxyHandler) vdirRequest(w http.ResponseWriter, r *http.Request, targe
 	}
 
 	//Populate the user-defined headers with the values from the request
-	rewrittenUserDefinedHeaders := rewrite.PopulateRequestHeaderVariables(r, target.parent.UserDefinedHeaders)
+	rewrittenUserDefinedHeaders := rewrite.PopulateRequestHeaderVariables(r, target.parent.HeaderRewriteRules.UserDefinedHeaders)
 
 	//Build downstream and upstream header rules, use the parent (subdomain) endpoint's headers
 	upstreamHeaders, downstreamHeaders := rewrite.SplitUpDownStreamHeaders(&rewrite.HeaderRewriteOptions{
 		UserDefinedHeaders:           rewrittenUserDefinedHeaders,
-		HSTSMaxAge:                   target.parent.HSTSMaxAge,
+		HSTSMaxAge:                   target.parent.HeaderRewriteRules.HSTSMaxAge,
 		HSTSIncludeSubdomains:        target.parent.ContainsWildcardName(true),
-		EnablePermissionPolicyHeader: target.parent.EnablePermissionPolicyHeader,
-		PermissionPolicy:             target.parent.PermissionPolicy,
+		EnablePermissionPolicyHeader: target.parent.HeaderRewriteRules.EnablePermissionPolicyHeader,
+		PermissionPolicy:             target.parent.HeaderRewriteRules.PermissionPolicy,
 	})
 
 	//Handle the virtual directory reverse proxy request
@@ -257,7 +257,7 @@ func (h *ProxyHandler) vdirRequest(w http.ResponseWriter, r *http.Request, targe
 		PathPrefix:          target.MatchingPath,
 		UpstreamHeaders:     upstreamHeaders,
 		DownstreamHeaders:   downstreamHeaders,
-		HostHeaderOverwrite: target.parent.RequestHostOverwrite,
+		HostHeaderOverwrite: target.parent.HeaderRewriteRules.RequestHostOverwrite,
 		Version:             target.parent.parent.Option.HostVersion,
 	})
 

+ 51 - 21
mod/dynamicproxy/typedef.go

@@ -19,10 +19,12 @@ import (
 	"imuslab.com/zoraxy/mod/tlscert"
 )
 
+type ProxyType int
+
 const (
-	ProxyType_Root = 0
-	ProxyType_Host = 1
-	ProxyType_Vdir = 2
+	ProxyTypeRoot ProxyType = iota //Root Proxy, everything not matching will be routed here
+	ProxyTypeHost                  //Host Proxy, match by host (domain) name
+	ProxyTypeVdir                  //Virtual Directory Proxy, match by path prefix
 )
 
 type ProxyHandler struct {
@@ -53,14 +55,14 @@ type RouterOption struct {
 /* Router Object */
 type Router struct {
 	Option         *RouterOption
-	ProxyEndpoints *sync.Map
-	Running        bool
-	Root           *ProxyEndpoint
-	mux            http.Handler
-	server         *http.Server
-	tlsListener    net.Listener
+	ProxyEndpoints *sync.Map                 //Map of ProxyEndpoint objects, each ProxyEndpoint object is a routing rule that handle incoming requests
+	Running        bool                      //If the router is running
+	Root           *ProxyEndpoint            //Root proxy endpoint, default site
+	mux            http.Handler              //HTTP handler
+	server         *http.Server              //HTTP server
+	tlsListener    net.Listener              //TLS listener, handle SNI routing
 	loadBalancer   *loadbalance.RouteManager //Load balancer routing manager
-	routingRules   []*RoutingRule
+	routingRules   []*RoutingRule            //Special routing rules, handle high priority routing like ACME request handling
 
 	tlsRedirectStop  chan bool              //Stop channel for tls redirection server
 	rateLimterStop   chan bool              //Stop channel for rate limiter
@@ -99,9 +101,42 @@ type VirtualDirectoryEndpoint struct {
 	parent              *ProxyEndpoint       `json:"-"`
 }
 
+// Rules and settings for header rewriting
+type HeaderRewriteRules struct {
+	UserDefinedHeaders           []*rewrite.UserDefinedHeader        //Custom headers to append when proxying requests from this endpoint
+	RequestHostOverwrite         string                              //If not empty, this domain will be used to overwrite the Host field in request header
+	HSTSMaxAge                   int64                               //HSTS max age, set to 0 for disable HSTS headers
+	EnablePermissionPolicyHeader bool                                //Enable injection of permission policy header
+	PermissionPolicy             *permissionpolicy.PermissionsPolicy //Permission policy header
+	DisableHopByHopHeaderRemoval bool                                //Do not remove hop-by-hop headers
+
+}
+
+/*
+
+	Authentication Provider
+
+	TODO: Move these into a dedicated module
+*/
+
+type AuthMethod int
+
+const (
+	AuthMethodNone     AuthMethod = iota //No authentication required
+	AuthMethodBasic                      //Basic Auth
+	AuthMethodAuthelia                   //Authelia
+	AuthMethodOauth2                     //Oauth2
+)
+
+type AuthenticationProvider struct {
+	AuthMethod              AuthMethod                //The authentication method to use
+	BasicAuthCredentials    []*BasicAuthCredentials   //Basic auth credentials
+	BasicAuthExceptionRules []*BasicAuthExceptionRule //Path to exclude in a basic auth enabled proxy target
+}
+
 // A proxy endpoint record, a general interface for handling inbound routing
 type ProxyEndpoint struct {
-	ProxyType            int                     //The type of this proxy, see const def
+	ProxyType            ProxyType               //The type of this proxy, see const def
 	RootOrMatchingDomain string                  //Matching domain for host, also act as key
 	MatchingDomainAlias  []string                //A list of domains that alias to this rule
 	ActiveOrigins        []*loadbalance.Upstream //Activated Upstream or origin servers IP or domain to proxy to
@@ -117,23 +152,18 @@ type ProxyEndpoint struct {
 	VirtualDirectories []*VirtualDirectoryEndpoint
 
 	//Custom Headers
-	UserDefinedHeaders           []*rewrite.UserDefinedHeader        //Custom headers to append when proxying requests from this endpoint
-	RequestHostOverwrite         string                              //If not empty, this domain will be used to overwrite the Host field in request header
-	HSTSMaxAge                   int64                               //HSTS max age, set to 0 for disable HSTS headers
-	EnablePermissionPolicyHeader bool                                //Enable injection of permission policy header
-	PermissionPolicy             *permissionpolicy.PermissionsPolicy //Permission policy header
-	DisableHopByHopHeaderRemoval bool                                //Do not remove hop-by-hop headers
+	HeaderRewriteRules *HeaderRewriteRules
 
 	//Authentication
-	RequireBasicAuth        bool                      //Set to true to request basic auth before proxy
-	BasicAuthCredentials    []*BasicAuthCredentials   //Basic auth credentials
-	BasicAuthExceptionRules []*BasicAuthExceptionRule //Path to exclude in a basic auth enabled proxy target
-	UseSSOIntercept         bool                      //Allow SSO to intercept this endpoint and provide authentication via Oauth2 credentials
+	AuthenticationProvider *AuthenticationProvider
 
 	// Rate Limiting
 	RequireRateLimit bool
 	RateLimit        int64 // Rate limit in requests per second
 
+	//Uptime Monitor
+	DisableUptimeMonitor bool //Disable uptime monitor for this endpoint
+
 	//Access Control
 	AccessFilterUUID string //Access filter ID
 

+ 10 - 1
mod/update/updatelogic.go

@@ -1,6 +1,9 @@
 package update
 
-import v308 "imuslab.com/zoraxy/mod/update/v308"
+import (
+	v308 "imuslab.com/zoraxy/mod/update/v308"
+	v315 "imuslab.com/zoraxy/mod/update/v315"
+)
 
 // Updater Core logic
 func runUpdateRoutineWithVersion(fromVersion int, toVersion int) {
@@ -10,6 +13,12 @@ func runUpdateRoutineWithVersion(fromVersion int, toVersion int) {
 		if err != nil {
 			panic(err)
 		}
+	} else if fromVersion == 314 && toVersion == 315 {
+		//Updating from v3.1.4 to v3.1.5
+		err := v315.UpdateFrom314To315()
+		if err != nil {
+			panic(err)
+		}
 	}
 
 	//ADD MORE VERSIONS HERE

+ 24 - 0
mod/update/updateutil/updateutil.go

@@ -0,0 +1,24 @@
+package updateutil
+
+import (
+	"io"
+	"os"
+)
+
+// Helper function to copy files
+func CopyFile(src, dst string) error {
+	sourceFile, err := os.Open(src)
+	if err != nil {
+		return err
+	}
+	defer sourceFile.Close()
+
+	destinationFile, err := os.Create(dst)
+	if err != nil {
+		return err
+	}
+	defer destinationFile.Close()
+
+	_, err = io.Copy(destinationFile, sourceFile)
+	return err
+}

+ 50 - 0
mod/update/v315/typedef314.go

@@ -0,0 +1,50 @@
+package v315
+
+import (
+	"imuslab.com/zoraxy/mod/dynamicproxy/loadbalance"
+	"imuslab.com/zoraxy/mod/dynamicproxy/permissionpolicy"
+	"imuslab.com/zoraxy/mod/dynamicproxy/rewrite"
+)
+
+// A proxy endpoint record, a general interface for handling inbound routing
+type v314ProxyEndpoint struct {
+	ProxyType            int                     //The type of this proxy, see const def
+	RootOrMatchingDomain string                  //Matching domain for host, also act as key
+	MatchingDomainAlias  []string                //A list of domains that alias to this rule
+	ActiveOrigins        []*loadbalance.Upstream //Activated Upstream or origin servers IP or domain to proxy to
+	InactiveOrigins      []*loadbalance.Upstream //Disabled Upstream or origin servers IP or domain to proxy to
+	UseStickySession     bool                    //Use stick session for load balancing
+	UseActiveLoadBalance bool                    //Use active loadbalancing, default passive
+	Disabled             bool                    //If the rule is disabled
+
+	//Inbound TLS/SSL Related
+	BypassGlobalTLS bool //Bypass global TLS setting options if TLS Listener enabled (parent.tlsListener != nil)
+
+	//Virtual Directories
+	VirtualDirectories []*VirtualDirectoryEndpoint
+
+	//Custom Headers
+	UserDefinedHeaders           []*rewrite.UserDefinedHeader        //Custom headers to append when proxying requests from this endpoint
+	RequestHostOverwrite         string                              //If not empty, this domain will be used to overwrite the Host field in request header
+	HSTSMaxAge                   int64                               //HSTS max age, set to 0 for disable HSTS headers
+	EnablePermissionPolicyHeader bool                                //Enable injection of permission policy header
+	PermissionPolicy             *permissionpolicy.PermissionsPolicy //Permission policy header
+	DisableHopByHopHeaderRemoval bool                                //Do not remove hop-by-hop headers
+
+	//Authentication
+	RequireBasicAuth        bool                      //Set to true to request basic auth before proxy
+	BasicAuthCredentials    []*BasicAuthCredentials   //Basic auth credentials
+	BasicAuthExceptionRules []*BasicAuthExceptionRule //Path to exclude in a basic auth enabled proxy target
+	UseSSOIntercept         bool                      //Allow SSO to intercept this endpoint and provide authentication via Oauth2 credentials
+
+	// Rate Limiting
+	RequireRateLimit bool
+	RateLimit        int64 // Rate limit in requests per second
+
+	//Access Control
+	AccessFilterUUID string //Access filter ID
+
+	//Fallback routing logic (Special Rule Sets Only)
+	DefaultSiteOption int    //Fallback routing logic options
+	DefaultSiteValue  string //Fallback routing target, optional
+}

+ 106 - 0
mod/update/v315/typedef315.go

@@ -0,0 +1,106 @@
+package v315
+
+import (
+	"imuslab.com/zoraxy/mod/dynamicproxy/loadbalance"
+	"imuslab.com/zoraxy/mod/dynamicproxy/permissionpolicy"
+	"imuslab.com/zoraxy/mod/dynamicproxy/rewrite"
+)
+
+type ProxyType int
+
+const (
+	ProxyTypeRoot ProxyType = iota //Root Proxy, everything not matching will be routed here
+	ProxyTypeHost                  //Host Proxy, match by host (domain) name
+	ProxyTypeVdir                  //Virtual Directory Proxy, match by path prefix
+)
+
+/* Basic Auth Related Data structure*/
+// Auth credential for basic auth on certain endpoints
+type BasicAuthCredentials struct {
+	Username     string
+	PasswordHash string
+}
+
+// Auth credential for basic auth on certain endpoints
+type BasicAuthUnhashedCredentials struct {
+	Username string
+	Password string
+}
+
+// Paths to exclude in basic auth enabled proxy handler
+type BasicAuthExceptionRule struct {
+	PathPrefix string
+}
+
+/* Routing Rule Data Structures */
+
+// 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
+	SkipCertValidations bool   //Set to true to accept self signed certs
+	Disabled            bool   //If the rule is enabled
+}
+
+// Rules and settings for header rewriting
+type HeaderRewriteRules struct {
+	UserDefinedHeaders           []*rewrite.UserDefinedHeader        //Custom headers to append when proxying requests from this endpoint
+	RequestHostOverwrite         string                              //If not empty, this domain will be used to overwrite the Host field in request header
+	HSTSMaxAge                   int64                               //HSTS max age, set to 0 for disable HSTS headers
+	EnablePermissionPolicyHeader bool                                //Enable injection of permission policy header
+	PermissionPolicy             *permissionpolicy.PermissionsPolicy //Permission policy header
+	DisableHopByHopHeaderRemoval bool                                //Do not remove hop-by-hop headers
+}
+
+type AuthProvider int
+
+const (
+	AuthProviderNone AuthProvider = iota
+	AuthProviderBasicAuth
+	AuthProviderAuthelia
+	AuthProviderOauth2
+)
+
+type AuthenticationProvider struct {
+	AuthProvider            AuthProvider              //The type of authentication provider
+	RequireBasicAuth        bool                      //Set to true to request basic auth before proxy
+	BasicAuthCredentials    []*BasicAuthCredentials   //Basic auth credentials
+	BasicAuthExceptionRules []*BasicAuthExceptionRule //Path to exclude in a basic auth enabled proxy target
+}
+
+// A proxy endpoint record, a general interface for handling inbound routing
+type v315ProxyEndpoint struct {
+	ProxyType            ProxyType               //The type of this proxy, see const def
+	RootOrMatchingDomain string                  //Matching domain for host, also act as key
+	MatchingDomainAlias  []string                //A list of domains that alias to this rule
+	ActiveOrigins        []*loadbalance.Upstream //Activated Upstream or origin servers IP or domain to proxy to
+	InactiveOrigins      []*loadbalance.Upstream //Disabled Upstream or origin servers IP or domain to proxy to
+	UseStickySession     bool                    //Use stick session for load balancing
+	UseActiveLoadBalance bool                    //Use active loadbalancing, default passive
+	Disabled             bool                    //If the rule is disabled
+
+	//Inbound TLS/SSL Related
+	BypassGlobalTLS bool //Bypass global TLS setting options if TLS Listener enabled (parent.tlsListener != nil)
+
+	//Virtual Directories
+	VirtualDirectories []*VirtualDirectoryEndpoint
+
+	//Custom Headers
+	HeaderRewriteRules *HeaderRewriteRules
+
+	//Authentication
+	AuthenticationProvider *AuthenticationProvider
+
+	// Rate Limiting
+	RequireRateLimit bool
+	RateLimit        int64 // Rate limit in requests per second
+
+	//Access Control
+	AccessFilterUUID string //Access filter ID
+
+	//Fallback routing logic (Special Rule Sets Only)
+	DefaultSiteOption int    //Fallback routing logic options
+	DefaultSiteValue  string //Fallback routing target, optional
+}

+ 124 - 0
mod/update/v315/v315.go

@@ -0,0 +1,124 @@
+package v315
+
+import (
+	"encoding/json"
+	"log"
+	"os"
+	"path/filepath"
+
+	"imuslab.com/zoraxy/mod/update/updateutil"
+)
+
+func UpdateFrom314To315() error {
+	//Load the configs
+	oldConfigFiles, err := filepath.Glob("./conf/proxy/*.config")
+	if err != nil {
+		return err
+	}
+
+	//Backup all the files
+	err = os.MkdirAll("./conf/proxy-314.old/", 0775)
+	if err != nil {
+		return err
+	}
+
+	for _, oldConfigFile := range oldConfigFiles {
+		// Extract the file name from the path
+		fileName := filepath.Base(oldConfigFile)
+		// Construct the backup file path
+		backupFile := filepath.Join("./conf/proxy-314.old/", fileName)
+
+		// Copy the file to the backup directory
+		err := updateutil.CopyFile(oldConfigFile, backupFile)
+		if err != nil {
+			return err
+		}
+	}
+
+	//read the config into the old struct
+	for _, oldConfigFile := range oldConfigFiles {
+		configContent, err := os.ReadFile(oldConfigFile)
+		if err != nil {
+			log.Println("Unable to read config file "+filepath.Base(oldConfigFile), err.Error())
+			continue
+		}
+
+		thisOldConfigStruct := v314ProxyEndpoint{}
+		err = json.Unmarshal(configContent, &thisOldConfigStruct)
+		if err != nil {
+			log.Println("Unable to parse file "+filepath.Base(oldConfigFile), err.Error())
+			continue
+		}
+
+		//Convert the old struct to the new struct
+		thisNewConfigStruct := convertV314ToV315(thisOldConfigStruct)
+
+		//Write the new config to file
+		newConfigContent, err := json.MarshalIndent(thisNewConfigStruct, "", "    ")
+		if err != nil {
+			log.Println("Unable to marshal new config "+filepath.Base(oldConfigFile), err.Error())
+			continue
+		}
+
+		err = os.WriteFile(oldConfigFile, newConfigContent, 0664)
+		if err != nil {
+			log.Println("Unable to write new config "+filepath.Base(oldConfigFile), err.Error())
+			continue
+		}
+	}
+
+	return nil
+}
+
+func convertV314ToV315(thisOldConfigStruct v314ProxyEndpoint) v315ProxyEndpoint {
+	//Move old header and auth configs into struct
+	newHeaderRewriteRules := HeaderRewriteRules{
+		UserDefinedHeaders:           thisOldConfigStruct.UserDefinedHeaders,
+		RequestHostOverwrite:         thisOldConfigStruct.RequestHostOverwrite,
+		HSTSMaxAge:                   thisOldConfigStruct.HSTSMaxAge,
+		EnablePermissionPolicyHeader: thisOldConfigStruct.EnablePermissionPolicyHeader,
+		PermissionPolicy:             thisOldConfigStruct.PermissionPolicy,
+		DisableHopByHopHeaderRemoval: thisOldConfigStruct.DisableHopByHopHeaderRemoval,
+	}
+
+	newAuthenticationProvider := AuthenticationProvider{
+		RequireBasicAuth:        thisOldConfigStruct.RequireBasicAuth,
+		BasicAuthCredentials:    thisOldConfigStruct.BasicAuthCredentials,
+		BasicAuthExceptionRules: thisOldConfigStruct.BasicAuthExceptionRules,
+	}
+
+	//Convert proxy type int to enum
+	var newConfigProxyType ProxyType
+	if thisOldConfigStruct.ProxyType == 0 {
+		newConfigProxyType = ProxyTypeRoot
+	} else if thisOldConfigStruct.ProxyType == 1 {
+		newConfigProxyType = ProxyTypeHost
+	} else if thisOldConfigStruct.ProxyType == 2 {
+		newConfigProxyType = ProxyTypeVdir
+	}
+
+	//Update the config struct
+	thisNewConfigStruct := v315ProxyEndpoint{
+		ProxyType:            newConfigProxyType,
+		RootOrMatchingDomain: thisOldConfigStruct.RootOrMatchingDomain,
+		MatchingDomainAlias:  thisOldConfigStruct.MatchingDomainAlias,
+		ActiveOrigins:        thisOldConfigStruct.ActiveOrigins,
+		InactiveOrigins:      thisOldConfigStruct.InactiveOrigins,
+		UseStickySession:     thisOldConfigStruct.UseStickySession,
+		UseActiveLoadBalance: thisOldConfigStruct.UseActiveLoadBalance,
+		Disabled:             thisOldConfigStruct.Disabled,
+		BypassGlobalTLS:      thisOldConfigStruct.BypassGlobalTLS,
+		VirtualDirectories:   thisOldConfigStruct.VirtualDirectories,
+		RequireRateLimit:     thisOldConfigStruct.RequireRateLimit,
+		RateLimit:            thisOldConfigStruct.RateLimit,
+		AccessFilterUUID:     thisOldConfigStruct.AccessFilterUUID,
+		DefaultSiteOption:    thisOldConfigStruct.DefaultSiteOption,
+		DefaultSiteValue:     thisOldConfigStruct.DefaultSiteValue,
+
+		//Append the new struct into the new config
+		HeaderRewriteRules:     &newHeaderRewriteRules,
+		AuthenticationProvider: &newAuthenticationProvider,
+	}
+
+	return thisNewConfigStruct
+}

+ 61 - 31
reverseproxy.go

@@ -309,10 +309,25 @@ func ReverseProxyHandleAddEndpoint(w http.ResponseWriter, r *http.Request) {
 			}
 		}
 
+		//Generate a default authenticaion provider
+		authMethod := dynamicproxy.AuthMethodNone
+		if requireBasicAuth {
+			authMethod = dynamicproxy.AuthMethodBasic
+		}
+		thisAuthenticationProvider := dynamicproxy.AuthenticationProvider{
+			AuthMethod:              authMethod,
+			BasicAuthCredentials:    basicAuthCredentials,
+			BasicAuthExceptionRules: []*dynamicproxy.BasicAuthExceptionRule{},
+		}
+
+		thisCustomHeaderRules := dynamicproxy.HeaderRewriteRules{
+			UserDefinedHeaders: []*rewrite.UserDefinedHeader{},
+		}
+
 		//Generate a proxy endpoint object
 		thisProxyEndpoint := dynamicproxy.ProxyEndpoint{
 			//I/O
-			ProxyType:            dynamicproxy.ProxyType_Host,
+			ProxyType:            dynamicproxy.ProxyTypeHost,
 			RootOrMatchingDomain: rootOrMatchingDomain,
 			MatchingDomainAlias:  aliasHostnames,
 			ActiveOrigins: []*loadbalance.Upstream{
@@ -333,13 +348,16 @@ func ReverseProxyHandleAddEndpoint(w http.ResponseWriter, r *http.Request) {
 			//VDir
 			VirtualDirectories: []*dynamicproxy.VirtualDirectoryEndpoint{},
 			//Custom headers
-			UserDefinedHeaders: []*rewrite.UserDefinedHeader{},
+
 			//Auth
-			RequireBasicAuth:        requireBasicAuth,
-			BasicAuthCredentials:    basicAuthCredentials,
-			BasicAuthExceptionRules: []*dynamicproxy.BasicAuthExceptionRule{},
-			DefaultSiteOption:       0,
-			DefaultSiteValue:        "",
+			AuthenticationProvider: &thisAuthenticationProvider,
+
+			//Header Rewrite
+			HeaderRewriteRules: &thisCustomHeaderRules,
+
+			//Default Site
+			DefaultSiteOption: 0,
+			DefaultSiteValue:  "",
 			// Rate Limit
 			RequireRateLimit: requireRateLimit,
 			RateLimit:        int64(proxyRateLimit),
@@ -379,7 +397,7 @@ func ReverseProxyHandleAddEndpoint(w http.ResponseWriter, r *http.Request) {
 
 		//Write the root options to file
 		rootRoutingEndpoint := dynamicproxy.ProxyEndpoint{
-			ProxyType:            dynamicproxy.ProxyType_Root,
+			ProxyType:            dynamicproxy.ProxyTypeRoot,
 			RootOrMatchingDomain: "/",
 			ActiveOrigins: []*loadbalance.Upstream{
 				{
@@ -494,7 +512,19 @@ func ReverseProxyHandleEditEndpoint(w http.ResponseWriter, r *http.Request) {
 	//Generate a new proxyEndpoint from the new config
 	newProxyEndpoint := dynamicproxy.CopyEndpoint(targetProxyEntry)
 	newProxyEndpoint.BypassGlobalTLS = bypassGlobalTLS
-	newProxyEndpoint.RequireBasicAuth = requireBasicAuth
+	if newProxyEndpoint.AuthenticationProvider == nil {
+		newProxyEndpoint.AuthenticationProvider = &dynamicproxy.AuthenticationProvider{
+			AuthMethod:              dynamicproxy.AuthMethodNone,
+			BasicAuthCredentials:    []*dynamicproxy.BasicAuthCredentials{},
+			BasicAuthExceptionRules: []*dynamicproxy.BasicAuthExceptionRule{},
+		}
+	}
+	if requireBasicAuth {
+		newProxyEndpoint.AuthenticationProvider.AuthMethod = dynamicproxy.AuthMethodBasic
+	} else {
+		newProxyEndpoint.AuthenticationProvider.AuthMethod = dynamicproxy.AuthMethodNone
+	}
+
 	newProxyEndpoint.RequireRateLimit = requireRateLimit
 	newProxyEndpoint.RateLimit = proxyRateLimit
 	newProxyEndpoint.UseStickySession = useStickySession
@@ -624,7 +654,7 @@ func UpdateProxyBasicAuthCredentials(w http.ResponseWriter, r *http.Request) {
 		}
 
 		usernames := []string{}
-		for _, cred := range targetProxy.BasicAuthCredentials {
+		for _, cred := range targetProxy.AuthenticationProvider.BasicAuthCredentials {
 			usernames = append(usernames, cred.Username)
 		}
 
@@ -668,7 +698,7 @@ func UpdateProxyBasicAuthCredentials(w http.ResponseWriter, r *http.Request) {
 			if credential.Password == "" {
 				//Check if exists in the old credential files
 				keepUnchange := false
-				for _, oldCredEntry := range targetProxy.BasicAuthCredentials {
+				for _, oldCredEntry := range targetProxy.AuthenticationProvider.BasicAuthCredentials {
 					if oldCredEntry.Username == credential.Username {
 						//Exists! Reuse the old hash
 						mergedCredentials = append(mergedCredentials, &dynamicproxy.BasicAuthCredentials{
@@ -693,7 +723,7 @@ func UpdateProxyBasicAuthCredentials(w http.ResponseWriter, r *http.Request) {
 			}
 		}
 
-		targetProxy.BasicAuthCredentials = mergedCredentials
+		targetProxy.AuthenticationProvider.BasicAuthCredentials = mergedCredentials
 
 		//Save it to file
 		SaveReverseProxyConfig(targetProxy)
@@ -727,7 +757,7 @@ func ListProxyBasicAuthExceptionPaths(w http.ResponseWriter, r *http.Request) {
 	}
 
 	//List all the exception paths for this proxy
-	results := targetProxy.BasicAuthExceptionRules
+	results := targetProxy.AuthenticationProvider.BasicAuthExceptionRules
 	if results == nil {
 		//It is a config from a really old version of zoraxy. Overwrite it with empty array
 		results = []*dynamicproxy.BasicAuthExceptionRule{}
@@ -764,7 +794,7 @@ func AddProxyBasicAuthExceptionPaths(w http.ResponseWriter, r *http.Request) {
 
 	//Add a new exception rule if it is not already exists
 	alreadyExists := false
-	for _, thisExceptionRule := range targetProxy.BasicAuthExceptionRules {
+	for _, thisExceptionRule := range targetProxy.AuthenticationProvider.BasicAuthExceptionRules {
 		if thisExceptionRule.PathPrefix == matchingPrefix {
 			alreadyExists = true
 			break
@@ -774,7 +804,7 @@ func AddProxyBasicAuthExceptionPaths(w http.ResponseWriter, r *http.Request) {
 		utils.SendErrorResponse(w, "This matching path already exists")
 		return
 	}
-	targetProxy.BasicAuthExceptionRules = append(targetProxy.BasicAuthExceptionRules, &dynamicproxy.BasicAuthExceptionRule{
+	targetProxy.AuthenticationProvider.BasicAuthExceptionRules = append(targetProxy.AuthenticationProvider.BasicAuthExceptionRules, &dynamicproxy.BasicAuthExceptionRule{
 		PathPrefix: strings.TrimSpace(matchingPrefix),
 	})
 
@@ -808,7 +838,7 @@ func RemoveProxyBasicAuthExceptionPaths(w http.ResponseWriter, r *http.Request)
 
 	newExceptionRuleList := []*dynamicproxy.BasicAuthExceptionRule{}
 	matchingExists := false
-	for _, thisExceptionalRule := range targetProxy.BasicAuthExceptionRules {
+	for _, thisExceptionalRule := range targetProxy.AuthenticationProvider.BasicAuthExceptionRules {
 		if thisExceptionalRule.PathPrefix != matchingPrefix {
 			newExceptionRuleList = append(newExceptionRuleList, thisExceptionalRule)
 		} else {
@@ -821,7 +851,7 @@ func RemoveProxyBasicAuthExceptionPaths(w http.ResponseWriter, r *http.Request)
 		return
 	}
 
-	targetProxy.BasicAuthExceptionRules = newExceptionRuleList
+	targetProxy.AuthenticationProvider.BasicAuthExceptionRules = newExceptionRuleList
 
 	// Save configs to runtime and file
 	targetProxy.UpdateToRuntime()
@@ -914,13 +944,13 @@ func ReverseProxyList(w http.ResponseWriter, r *http.Request) {
 			thisEndpoint := dynamicproxy.CopyEndpoint(value.(*dynamicproxy.ProxyEndpoint))
 			//Clear the auth passwords before showing to front-end
 			cleanedCredentials := []*dynamicproxy.BasicAuthCredentials{}
-			for _, user := range thisEndpoint.BasicAuthCredentials {
+			for _, user := range thisEndpoint.AuthenticationProvider.BasicAuthCredentials {
 				cleanedCredentials = append(cleanedCredentials, &dynamicproxy.BasicAuthCredentials{
 					Username:     user.Username,
 					PasswordHash: "",
 				})
 			}
-			thisEndpoint.BasicAuthCredentials = cleanedCredentials
+			thisEndpoint.AuthenticationProvider.BasicAuthCredentials = cleanedCredentials
 			results = append(results, thisEndpoint)
 			return true
 		})
@@ -1127,7 +1157,7 @@ func HandleCustomHeaderList(w http.ResponseWriter, r *http.Request) {
 	}
 
 	//List all custom headers
-	customHeaderList := targetProxyEndpoint.UserDefinedHeaders
+	customHeaderList := targetProxyEndpoint.HeaderRewriteRules.UserDefinedHeaders
 	if customHeaderList == nil {
 		customHeaderList = []*rewrite.UserDefinedHeader{}
 	}
@@ -1269,7 +1299,7 @@ func HandleHostOverwrite(w http.ResponseWriter, r *http.Request) {
 
 	if r.Method == http.MethodGet {
 		//Get the current host header
-		js, _ := json.Marshal(targetProxyEndpoint.RequestHostOverwrite)
+		js, _ := json.Marshal(targetProxyEndpoint.HeaderRewriteRules.RequestHostOverwrite)
 		utils.SendJSONResponse(w, string(js))
 	} else if r.Method == http.MethodPost {
 		//Set the new host header
@@ -1278,7 +1308,7 @@ func HandleHostOverwrite(w http.ResponseWriter, r *http.Request) {
 		//As this will require change in the proxy instance we are running
 		//we need to clone and respawn this proxy endpoint
 		newProxyEndpoint := targetProxyEndpoint.Clone()
-		newProxyEndpoint.RequestHostOverwrite = newHostname
+		newProxyEndpoint.HeaderRewriteRules.RequestHostOverwrite = newHostname
 		//Save proxy endpoint
 		err = SaveReverseProxyConfig(newProxyEndpoint)
 		if err != nil {
@@ -1341,7 +1371,7 @@ func HandleHopByHop(w http.ResponseWriter, r *http.Request) {
 
 	if r.Method == http.MethodGet {
 		//Get the current hop by hop header state
-		js, _ := json.Marshal(!targetProxyEndpoint.DisableHopByHopHeaderRemoval)
+		js, _ := json.Marshal(!targetProxyEndpoint.HeaderRewriteRules.DisableHopByHopHeaderRemoval)
 		utils.SendJSONResponse(w, string(js))
 	} else if r.Method == http.MethodPost {
 		//Set the hop by hop header state
@@ -1351,7 +1381,7 @@ func HandleHopByHop(w http.ResponseWriter, r *http.Request) {
 		//we need to clone and respawn this proxy endpoint
 		newProxyEndpoint := targetProxyEndpoint.Clone()
 		//Storage file use false as default, so disable removal = not enable remover
-		newProxyEndpoint.DisableHopByHopHeaderRemoval = !enableHopByHopRemover
+		newProxyEndpoint.HeaderRewriteRules.DisableHopByHopHeaderRemoval = !enableHopByHopRemover
 
 		//Save proxy endpoint
 		err = SaveReverseProxyConfig(newProxyEndpoint)
@@ -1414,7 +1444,7 @@ func HandleHSTSState(w http.ResponseWriter, r *http.Request) {
 
 	if r.Method == http.MethodGet {
 		//Return current HSTS enable state
-		hstsAge := targetProxyEndpoint.HSTSMaxAge
+		hstsAge := targetProxyEndpoint.HeaderRewriteRules.HSTSMaxAge
 		js, _ := json.Marshal(hstsAge)
 		utils.SendJSONResponse(w, string(js))
 		return
@@ -1426,7 +1456,7 @@ func HandleHSTSState(w http.ResponseWriter, r *http.Request) {
 		}
 
 		if newMaxAge == 0 || newMaxAge >= 31536000 {
-			targetProxyEndpoint.HSTSMaxAge = int64(newMaxAge)
+			targetProxyEndpoint.HeaderRewriteRules.HSTSMaxAge = int64(newMaxAge)
 			err = SaveReverseProxyConfig(targetProxyEndpoint)
 			if err != nil {
 				utils.SendErrorResponse(w, "save HSTS state failed: "+err.Error())
@@ -1468,11 +1498,11 @@ func HandlePermissionPolicy(w http.ResponseWriter, r *http.Request) {
 		}
 
 		currentPolicy := permissionpolicy.GetDefaultPermissionPolicy()
-		if targetProxyEndpoint.PermissionPolicy != nil {
-			currentPolicy = targetProxyEndpoint.PermissionPolicy
+		if targetProxyEndpoint.HeaderRewriteRules.PermissionPolicy != nil {
+			currentPolicy = targetProxyEndpoint.HeaderRewriteRules.PermissionPolicy
 		}
 		result := CurrentPolicyState{
-			PPEnabled:     targetProxyEndpoint.EnablePermissionPolicyHeader,
+			PPEnabled:     targetProxyEndpoint.HeaderRewriteRules.EnablePermissionPolicyHeader,
 			CurrentPolicy: currentPolicy,
 		}
 
@@ -1487,7 +1517,7 @@ func HandlePermissionPolicy(w http.ResponseWriter, r *http.Request) {
 			return
 		}
 
-		targetProxyEndpoint.EnablePermissionPolicyHeader = enableState
+		targetProxyEndpoint.HeaderRewriteRules.EnablePermissionPolicyHeader = enableState
 		SaveReverseProxyConfig(targetProxyEndpoint)
 		targetProxyEndpoint.UpdateToRuntime()
 		utils.SendOK(w)
@@ -1509,7 +1539,7 @@ func HandlePermissionPolicy(w http.ResponseWriter, r *http.Request) {
 		}
 
 		//Save it to file
-		targetProxyEndpoint.PermissionPolicy = newPermissionPolicy
+		targetProxyEndpoint.HeaderRewriteRules.PermissionPolicy = newPermissionPolicy
 		SaveReverseProxyConfig(targetProxyEndpoint)
 		targetProxyEndpoint.UpdateToRuntime()
 		utils.SendOK(w)

+ 5 - 5
web/components/httprp.html

@@ -125,10 +125,10 @@
                         </td>
                         <td data-label="" editable="true" datatype="vdir">${vdList}</td>
                         <td data-label="" editable="true" datatype="advanced" style="width: 350px;">
-                            ${subd.RequireBasicAuth?`<i class="ui green check icon"></i> Basic Auth`:``}
-                            ${subd.RequireBasicAuth && subd.RequireRateLimit?"<br>":""}
-                            ${subd.RequireRateLimit?`<i class="ui green check icon"></i> Rate Limit @ ${subd.RateLimit} req/s`:``}
-                            ${!subd.RequireBasicAuth && !subd.RequireRateLimit?`<small style="opacity: 0.3; pointer-events: none; user-select: none;">No Special Settings</small>`:""}
+                            ${subd.AuthenticationProvider.AuthMethod == 0x1?`<i class="ui green check icon"></i> Basic Auth`:``}
+                            ${subd.AuthenticationProvider.AuthMethod == 0x1 && subd.RequireRateLimit?"<br>":""}
+                            ${subd.AuthenticationProvider.RequireRateLimit?`<i class="ui green check icon"></i> Rate Limit @ ${subd.RateLimit} req/s`:``}
+                            ${!subd.AuthenticationProvider.AuthMethod == 0x1 && !subd.RequireRateLimit?`<small style="opacity: 0.3; pointer-events: none; user-select: none;">No Special Settings</small>`:""}
                         </td>
                         <td class="center aligned ignoremw" 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">
@@ -269,7 +269,7 @@
                 </button>`);
 
             }else if (datatype == "advanced"){
-                let requireBasicAuth = payload.RequireBasicAuth;
+                let requireBasicAuth = payload.AuthenticationProvider.AuthMethod == 0x1;
                 let basicAuthCheckstate = "";
                 if (requireBasicAuth){
                     basicAuthCheckstate = "checked";

+ 1 - 1
wrappers.go

@@ -90,7 +90,7 @@ func GetUptimeTargetsFromReverseProxyRules(dp *dynamicproxy.Router) []*uptime.Ta
 
 	UptimeTargets := []*uptime.Target{}
 	for hostid, target := range hosts {
-		if target.Disabled {
+		if target.Disabled || target.DisableUptimeMonitor {
 			//Skip those proxy rules that is disabled
 			continue
 		}