mirror of
				https://github.com/tobychui/zoraxy.git
				synced 2025-11-03 23:44:08 +01:00 
			
		
		
		
	Fixed #267
- Added csrf middleware to management portal mux - Added csrf token to all html templates - Added csrf validation to all endpoints - Optimized some old endpoints implementation
This commit is contained in:
		
							
								
								
									
										32
									
								
								src/api.go
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								src/api.go
									
									
									
									
									
								
							@@ -22,11 +22,11 @@ import (
 | 
			
		||||
 | 
			
		||||
var requireAuth = true
 | 
			
		||||
 | 
			
		||||
func initAPIs() {
 | 
			
		||||
 | 
			
		||||
func initAPIs(targetMux *http.ServeMux) {
 | 
			
		||||
	authRouter := auth.NewManagedHTTPRouter(auth.RouterOption{
 | 
			
		||||
		AuthAgent:   authAgent,
 | 
			
		||||
		RequireAuth: requireAuth,
 | 
			
		||||
		TargetMux:   targetMux,
 | 
			
		||||
		DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
			http.Error(w, "401 - Unauthorized", http.StatusUnauthorized)
 | 
			
		||||
		},
 | 
			
		||||
@@ -37,12 +37,12 @@ func initAPIs() {
 | 
			
		||||
	if development {
 | 
			
		||||
		fs = http.FileServer(http.Dir("web/"))
 | 
			
		||||
	}
 | 
			
		||||
	//Add a layer of middleware for advance  control
 | 
			
		||||
	//Add a layer of middleware for advance control
 | 
			
		||||
	advHandler := FSHandler(fs)
 | 
			
		||||
	http.Handle("/", advHandler)
 | 
			
		||||
	targetMux.Handle("/", advHandler)
 | 
			
		||||
 | 
			
		||||
	//Authentication APIs
 | 
			
		||||
	registerAuthAPIs(requireAuth)
 | 
			
		||||
	registerAuthAPIs(requireAuth, targetMux)
 | 
			
		||||
 | 
			
		||||
	//Reverse proxy
 | 
			
		||||
	authRouter.HandleFunc("/api/proxy/enable", ReverseProxyHandleOnOff)
 | 
			
		||||
@@ -187,8 +187,8 @@ func initAPIs() {
 | 
			
		||||
	authRouter.HandleFunc("/api/tools/fwdproxy/port", forwardProxy.HandlePort)
 | 
			
		||||
 | 
			
		||||
	//Account Reset
 | 
			
		||||
	http.HandleFunc("/api/account/reset", HandleAdminAccountResetEmail)
 | 
			
		||||
	http.HandleFunc("/api/account/new", HandleNewPasswordSetup)
 | 
			
		||||
	targetMux.HandleFunc("/api/account/reset", HandleAdminAccountResetEmail)
 | 
			
		||||
	targetMux.HandleFunc("/api/account/new", HandleNewPasswordSetup)
 | 
			
		||||
 | 
			
		||||
	//ACME & Auto Renewer
 | 
			
		||||
	authRouter.HandleFunc("/api/acme/listExpiredDomains", acmeHandler.HandleGetExpiredDomains)
 | 
			
		||||
@@ -228,7 +228,7 @@ func initAPIs() {
 | 
			
		||||
	authRouter.HandleFunc("/api/docker/containers", DockerUXOptimizer.HandleDockerContainersList)
 | 
			
		||||
 | 
			
		||||
	//Others
 | 
			
		||||
	http.HandleFunc("/api/info/x", HandleZoraxyInfo)
 | 
			
		||||
	targetMux.HandleFunc("/api/info/x", HandleZoraxyInfo)
 | 
			
		||||
	authRouter.HandleFunc("/api/info/geoip", HandleGeoIpLookup)
 | 
			
		||||
	authRouter.HandleFunc("/api/conf/export", ExportConfigAsZip)
 | 
			
		||||
	authRouter.HandleFunc("/api/conf/import", ImportConfigFromZip)
 | 
			
		||||
@@ -243,18 +243,18 @@ func initAPIs() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Function to renders Auth related APIs
 | 
			
		||||
func registerAuthAPIs(requireAuth bool) {
 | 
			
		||||
func registerAuthAPIs(requireAuth bool, targetMux *http.ServeMux) {
 | 
			
		||||
	//Auth APIs
 | 
			
		||||
	http.HandleFunc("/api/auth/login", authAgent.HandleLogin)
 | 
			
		||||
	http.HandleFunc("/api/auth/logout", authAgent.HandleLogout)
 | 
			
		||||
	http.HandleFunc("/api/auth/checkLogin", func(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	targetMux.HandleFunc("/api/auth/login", authAgent.HandleLogin)
 | 
			
		||||
	targetMux.HandleFunc("/api/auth/logout", authAgent.HandleLogout)
 | 
			
		||||
	targetMux.HandleFunc("/api/auth/checkLogin", func(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
		if requireAuth {
 | 
			
		||||
			authAgent.CheckLogin(w, r)
 | 
			
		||||
		} else {
 | 
			
		||||
			utils.SendJSONResponse(w, "true")
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	http.HandleFunc("/api/auth/username", func(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	targetMux.HandleFunc("/api/auth/username", func(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
		username, err := authAgent.GetUserName(w, r)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
 | 
			
		||||
@@ -264,12 +264,12 @@ func registerAuthAPIs(requireAuth bool) {
 | 
			
		||||
		js, _ := json.Marshal(username)
 | 
			
		||||
		utils.SendJSONResponse(w, string(js))
 | 
			
		||||
	})
 | 
			
		||||
	http.HandleFunc("/api/auth/userCount", func(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	targetMux.HandleFunc("/api/auth/userCount", func(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
		uc := authAgent.GetUserCounts()
 | 
			
		||||
		js, _ := json.Marshal(uc)
 | 
			
		||||
		utils.SendJSONResponse(w, string(js))
 | 
			
		||||
	})
 | 
			
		||||
	http.HandleFunc("/api/auth/register", func(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	targetMux.HandleFunc("/api/auth/register", func(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
		if authAgent.GetUserCounts() == 0 {
 | 
			
		||||
			//Allow register root admin
 | 
			
		||||
			authAgent.HandleRegisterWithoutEmail(w, r, func(username, reserved string) {
 | 
			
		||||
@@ -280,7 +280,7 @@ func registerAuthAPIs(requireAuth bool) {
 | 
			
		||||
			utils.SendErrorResponse(w, "Root management account already exists")
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	http.HandleFunc("/api/auth/changePassword", func(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	targetMux.HandleFunc("/api/auth/changePassword", func(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
		username, err := authAgent.GetUserName(w, r)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			http.Error(w, "401 - Unauthorized", http.StatusUnauthorized)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										23
									
								
								src/cert.go
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								src/cert.go
									
									
									
									
									
								
							@@ -182,27 +182,28 @@ func handleToggleTLSProxy(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
		sysdb.Read("settings", "usetls", ¤tTlsSetting)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	newState, err := utils.PostPara(r, "set")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		//No setting. Get the current status
 | 
			
		||||
	if r.Method == http.MethodGet {
 | 
			
		||||
		//Get the current status
 | 
			
		||||
		js, _ := json.Marshal(currentTlsSetting)
 | 
			
		||||
		utils.SendJSONResponse(w, string(js))
 | 
			
		||||
	} else {
 | 
			
		||||
		if newState == "true" {
 | 
			
		||||
	} else if r.Method == http.MethodPost {
 | 
			
		||||
		newState, err := utils.PostBool(r, "set")
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			utils.SendErrorResponse(w, "new state not set or invalid")
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		if newState {
 | 
			
		||||
			sysdb.Write("settings", "usetls", true)
 | 
			
		||||
			SystemWideLogger.Println("Enabling TLS mode on reverse proxy")
 | 
			
		||||
			dynamicProxyRouter.UpdateTLSSetting(true)
 | 
			
		||||
		} else if newState == "false" {
 | 
			
		||||
		} else {
 | 
			
		||||
			sysdb.Write("settings", "usetls", false)
 | 
			
		||||
			SystemWideLogger.Println("Disabling TLS mode on reverse proxy")
 | 
			
		||||
			dynamicProxyRouter.UpdateTLSSetting(false)
 | 
			
		||||
		} else {
 | 
			
		||||
			utils.SendErrorResponse(w, "invalid state given. Only support true or false")
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		utils.SendOK(w)
 | 
			
		||||
 | 
			
		||||
	} else {
 | 
			
		||||
		http.Error(w, "405 - Method not allowed", http.StatusMethodNotAllowed)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -95,6 +95,7 @@ require (
 | 
			
		||||
	github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
 | 
			
		||||
	github.com/googleapis/gax-go/v2 v2.12.2 // indirect
 | 
			
		||||
	github.com/gophercloud/gophercloud v1.0.0 // indirect
 | 
			
		||||
	github.com/gorilla/csrf v1.7.2 // indirect
 | 
			
		||||
	github.com/gorilla/css v1.0.1 // indirect
 | 
			
		||||
	github.com/gorilla/securecookie v1.1.2 // indirect
 | 
			
		||||
	github.com/hashicorp/errwrap v1.0.0 // indirect
 | 
			
		||||
 
 | 
			
		||||
@@ -317,6 +317,8 @@ github.com/googleapis/gax-go/v2 v2.12.2/go.mod h1:61M8vcyyXR2kqKFxKrfA22jaA8JGF7
 | 
			
		||||
github.com/gophercloud/gophercloud v1.0.0 h1:9nTGx0jizmHxDobe4mck89FyQHVyA3CaXLIUSGJjP9k=
 | 
			
		||||
github.com/gophercloud/gophercloud v1.0.0/go.mod h1:Q8fZtyi5zZxPS/j9aj3sSxtvj41AdQMDwyo1myduD5c=
 | 
			
		||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
 | 
			
		||||
github.com/gorilla/csrf v1.7.2 h1:oTUjx0vyf2T+wkrx09Trsev1TE+/EbDAeHtSTbtC2eI=
 | 
			
		||||
github.com/gorilla/csrf v1.7.2/go.mod h1:F1Fj3KG23WYHE6gozCmBAezKookxbIvUJT+121wTuLk=
 | 
			
		||||
github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=
 | 
			
		||||
github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0=
 | 
			
		||||
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										21
									
								
								src/main.go
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								src/main.go
									
									
									
									
									
								
							@@ -12,6 +12,7 @@ import (
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/google/uuid"
 | 
			
		||||
	"github.com/gorilla/csrf"
 | 
			
		||||
	"imuslab.com/zoraxy/mod/access"
 | 
			
		||||
	"imuslab.com/zoraxy/mod/acme"
 | 
			
		||||
	"imuslab.com/zoraxy/mod/auth"
 | 
			
		||||
@@ -60,7 +61,7 @@ var (
 | 
			
		||||
	name        = "Zoraxy"
 | 
			
		||||
	version     = "3.1.0"
 | 
			
		||||
	nodeUUID    = "generic" //System uuid, in uuidv4 format
 | 
			
		||||
	development = true      //Set this to false to use embedded web fs
 | 
			
		||||
	development = false     //Set this to false to use embedded web fs
 | 
			
		||||
	bootTime    = time.Now().Unix()
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
@@ -72,10 +73,12 @@ var (
 | 
			
		||||
	/*
 | 
			
		||||
		Handler Modules
 | 
			
		||||
	*/
 | 
			
		||||
	sysdb          *database.Database     //System database
 | 
			
		||||
	authAgent      *auth.AuthAgent        //Authentication agent
 | 
			
		||||
	tlsCertManager *tlscert.Manager       //TLS / SSL management
 | 
			
		||||
	redirectTable  *redirection.RuleTable //Handle special redirection rule sets
 | 
			
		||||
	sysdb          *database.Database              //System database
 | 
			
		||||
	authAgent      *auth.AuthAgent                 //Authentication agent
 | 
			
		||||
	tlsCertManager *tlscert.Manager                //TLS / SSL management
 | 
			
		||||
	redirectTable  *redirection.RuleTable          //Handle special redirection rule sets
 | 
			
		||||
	webminPanelMux *http.ServeMux                  //Server mux for handling webmin panel APIs
 | 
			
		||||
	csrfMiddleware func(http.Handler) http.Handler //CSRF protection middleware
 | 
			
		||||
 | 
			
		||||
	pathRuleHandler    *pathrule.Handler         //Handle specific path blocking or custom headers
 | 
			
		||||
	geodbStore         *geodb.Store              //GeoIP database, for resolving IP into country code
 | 
			
		||||
@@ -176,12 +179,16 @@ func main() {
 | 
			
		||||
	}
 | 
			
		||||
	nodeUUID = string(uuidBytes)
 | 
			
		||||
 | 
			
		||||
	//Create a new webmin mux and csrf middleware layer
 | 
			
		||||
	webminPanelMux := http.NewServeMux()
 | 
			
		||||
	csrfMiddleware := csrf.Protect([]byte(nodeUUID))
 | 
			
		||||
 | 
			
		||||
	//Startup all modules
 | 
			
		||||
	startupSequence()
 | 
			
		||||
 | 
			
		||||
	//Initiate management interface APIs
 | 
			
		||||
	requireAuth = !(*noauth)
 | 
			
		||||
	initAPIs()
 | 
			
		||||
	initAPIs(webminPanelMux)
 | 
			
		||||
 | 
			
		||||
	//Start the reverse proxy server in go routine
 | 
			
		||||
	go func() {
 | 
			
		||||
@@ -194,7 +201,7 @@ func main() {
 | 
			
		||||
	finalSequence()
 | 
			
		||||
 | 
			
		||||
	SystemWideLogger.Println("Zoraxy started. Visit control panel at http://localhost" + *webUIPort)
 | 
			
		||||
	err = http.ListenAndServe(*webUIPort, nil)
 | 
			
		||||
	err = http.ListenAndServe(*webUIPort, csrfMiddleware(webminPanelMux))
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatal(err)
 | 
			
		||||
 
 | 
			
		||||
@@ -140,7 +140,7 @@ func (a *AutoRenewer) StopAutoRenewTicker() {
 | 
			
		||||
// opr = setSelected -> Enter a list of file names (or matching rules) for auto renew
 | 
			
		||||
// opr = setAuto -> Set to use auto detect certificates and renew
 | 
			
		||||
func (a *AutoRenewer) HandleSetAutoRenewDomains(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	opr, err := utils.GetPara(r, "opr")
 | 
			
		||||
	opr, err := utils.PostPara(r, "opr")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.SendErrorResponse(w, "Operation not set")
 | 
			
		||||
		return
 | 
			
		||||
@@ -170,6 +170,8 @@ func (a *AutoRenewer) HandleSetAutoRenewDomains(w http.ResponseWriter, r *http.R
 | 
			
		||||
		a.RenewerConfig.RenewAll = true
 | 
			
		||||
		a.saveRenewConfigToFile()
 | 
			
		||||
		utils.SendOK(w)
 | 
			
		||||
	} else {
 | 
			
		||||
		utils.SendErrorResponse(w, "invalid operation given")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -213,19 +215,22 @@ func (a *AutoRenewer) HandleRenewNow(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	utils.SendJSONResponse(w, string(js))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HandleAutoRenewEnable get and set the auto renew enable state
 | 
			
		||||
func (a *AutoRenewer) HandleAutoRenewEnable(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	val, err := utils.PostPara(r, "enable")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
	if r.Method == http.MethodGet {
 | 
			
		||||
		js, _ := json.Marshal(a.RenewerConfig.Enabled)
 | 
			
		||||
		utils.SendJSONResponse(w, string(js))
 | 
			
		||||
	} else {
 | 
			
		||||
		if val == "true" {
 | 
			
		||||
	} else if r.Method == http.MethodPost {
 | 
			
		||||
		val, err := utils.PostBool(r, "enable")
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			utils.SendErrorResponse(w, "invalid or empty enable state")
 | 
			
		||||
		}
 | 
			
		||||
		if val {
 | 
			
		||||
			//Check if the email is not empty
 | 
			
		||||
			if a.RenewerConfig.Email == "" {
 | 
			
		||||
				utils.SendErrorResponse(w, "Email is not set")
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			a.RenewerConfig.Enabled = true
 | 
			
		||||
			a.saveRenewConfigToFile()
 | 
			
		||||
			log.Println("[ACME] ACME auto renew enabled")
 | 
			
		||||
@@ -236,7 +241,10 @@ func (a *AutoRenewer) HandleAutoRenewEnable(w http.ResponseWriter, r *http.Reque
 | 
			
		||||
			log.Println("[ACME] ACME auto renew disabled")
 | 
			
		||||
			a.StopAutoRenewTicker()
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		http.Error(w, "405 - Method not allowed", http.StatusMethodNotAllowed)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (a *AutoRenewer) HandleACMEEmail(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,7 @@ type RouterOption struct {
 | 
			
		||||
	AuthAgent     *AuthAgent
 | 
			
		||||
	RequireAuth   bool                                     //This router require authentication
 | 
			
		||||
	DeniedHandler func(http.ResponseWriter, *http.Request) //Things to do when request is rejected
 | 
			
		||||
 | 
			
		||||
	TargetMux     *http.ServeMux
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type RouterDef struct {
 | 
			
		||||
@@ -35,17 +35,31 @@ func (router *RouterDef) HandleFunc(endpoint string, handler func(http.ResponseW
 | 
			
		||||
	authAgent := router.option.AuthAgent
 | 
			
		||||
 | 
			
		||||
	//OK. Register handler
 | 
			
		||||
	http.HandleFunc(endpoint, func(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
		//Check authentication of the user
 | 
			
		||||
		if router.option.RequireAuth {
 | 
			
		||||
			authAgent.HandleCheckAuth(w, r, func(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	if router.option.TargetMux == nil {
 | 
			
		||||
		http.HandleFunc(endpoint, func(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
			//Check authentication of the user
 | 
			
		||||
			if router.option.RequireAuth {
 | 
			
		||||
				authAgent.HandleCheckAuth(w, r, func(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
					handler(w, r)
 | 
			
		||||
				})
 | 
			
		||||
			} else {
 | 
			
		||||
				handler(w, r)
 | 
			
		||||
			})
 | 
			
		||||
		} else {
 | 
			
		||||
			handler(w, r)
 | 
			
		||||
		}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
	})
 | 
			
		||||
		})
 | 
			
		||||
	} else {
 | 
			
		||||
		router.option.TargetMux.HandleFunc(endpoint, func(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
			//Check authentication of the user
 | 
			
		||||
			if router.option.RequireAuth {
 | 
			
		||||
				authAgent.HandleCheckAuth(w, r, func(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
					handler(w, r)
 | 
			
		||||
				})
 | 
			
		||||
			} else {
 | 
			
		||||
				handler(w, r)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	router.endpoints[endpoint] = handler
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -3,8 +3,6 @@
 | 
			
		||||
 | 
			
		||||
package dockerux
 | 
			
		||||
 | 
			
		||||
/* Windows docker optimizer*/
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
@@ -16,7 +14,6 @@ import (
 | 
			
		||||
	"imuslab.com/zoraxy/mod/utils"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Windows build not support docker
 | 
			
		||||
func (d *UXOptimizer) HandleDockerAvailable(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	js, _ := json.Marshal(d.RunninInDocker)
 | 
			
		||||
	utils.SendJSONResponse(w, string(js))
 | 
			
		||||
 
 | 
			
		||||
@@ -173,7 +173,7 @@ func (fm *FileManager) HandleDownload(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
// HandleNewFolder creates a new folder in the specified directory
 | 
			
		||||
func (fm *FileManager) HandleNewFolder(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	// Parse the directory name from the request
 | 
			
		||||
	dirName, err := utils.GetPara(r, "path")
 | 
			
		||||
	dirName, err := utils.PostPara(r, "path")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.SendErrorResponse(w, "invalid directory name")
 | 
			
		||||
		return
 | 
			
		||||
@@ -268,13 +268,13 @@ func (fm *FileManager) HandleFileCopy(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
 | 
			
		||||
func (fm *FileManager) HandleFileMove(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	// Parse the source and destination paths from the request
 | 
			
		||||
	srcPath, err := utils.GetPara(r, "srcpath")
 | 
			
		||||
	srcPath, err := utils.PostPara(r, "srcpath")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.SendErrorResponse(w, "invalid source path")
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	destPath, err := utils.GetPara(r, "destpath")
 | 
			
		||||
	destPath, err := utils.PostPara(r, "destpath")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.SendErrorResponse(w, "invalid destination path")
 | 
			
		||||
		return
 | 
			
		||||
 
 | 
			
		||||
@@ -572,7 +572,7 @@ func ReverseProxyHandleAlias(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func DeleteProxyEndpoint(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	ep, err := utils.GetPara(r, "ep")
 | 
			
		||||
	ep, err := utils.PostPara(r, "ep")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.SendErrorResponse(w, "Invalid ep given")
 | 
			
		||||
		return
 | 
			
		||||
@@ -941,18 +941,22 @@ func ReverseProxyList(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
 | 
			
		||||
// Handle port 80 incoming traffics
 | 
			
		||||
func HandleUpdatePort80Listener(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	enabled, err := utils.GetPara(r, "enable")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
	if r.Method == http.MethodGet {
 | 
			
		||||
		//Load the current status
 | 
			
		||||
		currentEnabled := false
 | 
			
		||||
		err = sysdb.Read("settings", "listenP80", ¤tEnabled)
 | 
			
		||||
		err := sysdb.Read("settings", "listenP80", ¤tEnabled)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			utils.SendErrorResponse(w, err.Error())
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		js, _ := json.Marshal(currentEnabled)
 | 
			
		||||
		utils.SendJSONResponse(w, string(js))
 | 
			
		||||
	} else {
 | 
			
		||||
	} else if r.Method == http.MethodPost {
 | 
			
		||||
		enabled, err := utils.PostPara(r, "enable")
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			utils.SendErrorResponse(w, "enable state not set")
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		if enabled == "true" {
 | 
			
		||||
			sysdb.Write("settings", "listenP80", true)
 | 
			
		||||
			SystemWideLogger.Println("Enabling port 80 listener")
 | 
			
		||||
@@ -965,38 +969,48 @@ func HandleUpdatePort80Listener(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
			utils.SendErrorResponse(w, "invalid mode given: "+enabled)
 | 
			
		||||
		}
 | 
			
		||||
		utils.SendOK(w)
 | 
			
		||||
	} else {
 | 
			
		||||
		http.Error(w, "405 - Method not allowed", http.StatusMethodNotAllowed)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Handle https redirect
 | 
			
		||||
func HandleUpdateHttpsRedirect(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	useRedirect, err := utils.GetPara(r, "set")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
	if r.Method == http.MethodGet {
 | 
			
		||||
		currentRedirectToHttps := false
 | 
			
		||||
		//Load the current status
 | 
			
		||||
		err = sysdb.Read("settings", "redirect", ¤tRedirectToHttps)
 | 
			
		||||
		err := sysdb.Read("settings", "redirect", ¤tRedirectToHttps)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			utils.SendErrorResponse(w, err.Error())
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		js, _ := json.Marshal(currentRedirectToHttps)
 | 
			
		||||
		utils.SendJSONResponse(w, string(js))
 | 
			
		||||
	} else {
 | 
			
		||||
	} else if r.Method == http.MethodPost {
 | 
			
		||||
		useRedirect, err := utils.PostBool(r, "set")
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			utils.SendErrorResponse(w, "status not set")
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if dynamicProxyRouter.Option.Port == 80 {
 | 
			
		||||
			utils.SendErrorResponse(w, "This option is not available when listening on port 80")
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		if useRedirect == "true" {
 | 
			
		||||
		if useRedirect {
 | 
			
		||||
			sysdb.Write("settings", "redirect", true)
 | 
			
		||||
			SystemWideLogger.Println("Updating force HTTPS redirection to true")
 | 
			
		||||
			dynamicProxyRouter.UpdateHttpToHttpsRedirectSetting(true)
 | 
			
		||||
		} else if useRedirect == "false" {
 | 
			
		||||
		} else {
 | 
			
		||||
			sysdb.Write("settings", "redirect", false)
 | 
			
		||||
			SystemWideLogger.Println("Updating force HTTPS redirection to false")
 | 
			
		||||
			dynamicProxyRouter.UpdateHttpToHttpsRedirectSetting(false)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		utils.SendOK(w)
 | 
			
		||||
	} else {
 | 
			
		||||
		http.Error(w, "405 - Method not allowed", http.StatusMethodNotAllowed)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1086,13 +1100,13 @@ func HandleIncomingPortSet(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
//List all the custom header defined in this proxy rule
 | 
			
		||||
 | 
			
		||||
func HandleCustomHeaderList(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	epType, err := utils.PostPara(r, "type")
 | 
			
		||||
	epType, err := utils.GetPara(r, "type")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.SendErrorResponse(w, "endpoint type not defined")
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	domain, err := utils.PostPara(r, "domain")
 | 
			
		||||
	domain, err := utils.GetPara(r, "domain")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.SendErrorResponse(w, "domain or matching rule not defined")
 | 
			
		||||
		return
 | 
			
		||||
 
 | 
			
		||||
@@ -4,9 +4,11 @@ import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/gorilla/csrf"
 | 
			
		||||
	"imuslab.com/zoraxy/mod/sshprox"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -42,11 +44,15 @@ func FSHandler(handler http.Handler) http.Handler {
 | 
			
		||||
 | 
			
		||||
		// Allow access to /script/*, /img/pubic/* and /login.html without authentication
 | 
			
		||||
		if strings.HasPrefix(r.URL.Path, ppf("/script/")) || strings.HasPrefix(r.URL.Path, ppf("/img/public/")) || r.URL.Path == ppf("/login.html") || r.URL.Path == ppf("/reset.html") || r.URL.Path == ppf("/favicon.png") {
 | 
			
		||||
			if isHTMLFilePath(r.URL.Path) {
 | 
			
		||||
				handleInjectHTML(w, r, r.URL.Path)
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			handler.ServeHTTP(w, r)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// check authentication
 | 
			
		||||
		// Check authentication
 | 
			
		||||
		if !authAgent.CheckAuth(r) && requireAuth {
 | 
			
		||||
			http.Redirect(w, r, ppf("/login.html"), http.StatusTemporaryRedirect)
 | 
			
		||||
			return
 | 
			
		||||
@@ -77,6 +83,10 @@ func FSHandler(handler http.Handler) http.Handler {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		//Authenticated
 | 
			
		||||
		if isHTMLFilePath(r.URL.Path) {
 | 
			
		||||
			handleInjectHTML(w, r, r.URL.Path)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		handler.ServeHTTP(w, r)
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
@@ -88,3 +98,53 @@ func ppf(relativeFilepath string) string {
 | 
			
		||||
	}
 | 
			
		||||
	return relativeFilepath
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isHTMLFilePath(requestURI string) bool {
 | 
			
		||||
	return strings.HasSuffix(requestURI, ".html") || strings.HasSuffix(requestURI, "/")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Serve the html file with template token injected
 | 
			
		||||
func handleInjectHTML(w http.ResponseWriter, r *http.Request, relativeFilepath string) {
 | 
			
		||||
	// Read the HTML file
 | 
			
		||||
	var content []byte
 | 
			
		||||
	var err error
 | 
			
		||||
	if len(relativeFilepath) > 0 && relativeFilepath[len(relativeFilepath)-1:] == "/" {
 | 
			
		||||
		relativeFilepath = relativeFilepath + "index.html"
 | 
			
		||||
	}
 | 
			
		||||
	if development {
 | 
			
		||||
		//Load from disk
 | 
			
		||||
		targetFilePath := strings.ReplaceAll(filepath.Join("web/", relativeFilepath), "\\", "/")
 | 
			
		||||
		content, err = os.ReadFile(targetFilePath)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			http.Error(w, "Internal Server Error", http.StatusInternalServerError)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		//Load from embedded fs, require trimming off the prefix slash for relative path
 | 
			
		||||
		relativeFilepath = strings.TrimPrefix(relativeFilepath, "/")
 | 
			
		||||
		content, err = webres.ReadFile(relativeFilepath)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			SystemWideLogger.Println("load embedded web file failed: ", err)
 | 
			
		||||
			http.Error(w, "Internal Server Error", http.StatusInternalServerError)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Convert the file content to a string
 | 
			
		||||
	htmlContent := string(content)
 | 
			
		||||
 | 
			
		||||
	//Defeine the system template for this request
 | 
			
		||||
	templateStrings := map[string]string{
 | 
			
		||||
		".csrfToken": csrf.Token(r),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Replace template tokens in the HTML content
 | 
			
		||||
	for key, value := range templateStrings {
 | 
			
		||||
		placeholder := "{{" + key + "}}"
 | 
			
		||||
		htmlContent = strings.ReplaceAll(htmlContent, placeholder, value)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Write the modified HTML content to the response
 | 
			
		||||
	w.Header().Set("Content-Type", "text/html")
 | 
			
		||||
	w.Write([]byte(htmlContent))
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -292,7 +292,7 @@ func startupSequence() {
 | 
			
		||||
 | 
			
		||||
	/* Docker UX Optimizer */
 | 
			
		||||
	if runtime.GOOS == "windows" && *runningInDocker {
 | 
			
		||||
		SystemWideLogger.PrintAndLog("WARNING", "Invalid start flag combination: docker=true && runtime.GOOS == windows. Running in docker UX development mode.", nil)
 | 
			
		||||
		SystemWideLogger.PrintAndLog("warning", "Invalid start flag combination: docker=true && runtime.GOOS == windows. Running in docker UX development mode.", nil)
 | 
			
		||||
	}
 | 
			
		||||
	DockerUXOptimizer = dockerux.NewDockerOptimizer(*runningInDocker, SystemWideLogger)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,7 @@ import (
 | 
			
		||||
 | 
			
		||||
// List upstreams from a endpoint
 | 
			
		||||
func ReverseProxyUpstreamList(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	endpoint, err := utils.PostPara(r, "ep")
 | 
			
		||||
	endpoint, err := utils.GetPara(r, "ep")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.SendErrorResponse(w, "endpoint not defined")
 | 
			
		||||
		return
 | 
			
		||||
 
 | 
			
		||||
@@ -1000,7 +1000,7 @@
 | 
			
		||||
    */
 | 
			
		||||
    function enableBlacklist() {
 | 
			
		||||
        var isChecked = $('#enableBlacklist').is(':checked');
 | 
			
		||||
        $.ajax({
 | 
			
		||||
        $.cjax({
 | 
			
		||||
            type: 'POST',
 | 
			
		||||
            url: '/api/blacklist/enable',
 | 
			
		||||
            data: { enable: isChecked, id: currentEditingAccessRule},
 | 
			
		||||
@@ -1028,9 +1028,10 @@
 | 
			
		||||
        let counter = 0;
 | 
			
		||||
        for(var i = 0; i < ccs.length; i++){
 | 
			
		||||
            let thisCountryCode = ccs[i];
 | 
			
		||||
            $.ajax({
 | 
			
		||||
            $.cjax({
 | 
			
		||||
                type: "POST",
 | 
			
		||||
                url: "/api/blacklist/country/add",
 | 
			
		||||
                method: "POST",
 | 
			
		||||
                data: { cc: thisCountryCode, id: currentEditingAccessRule},
 | 
			
		||||
                success: function(response) {
 | 
			
		||||
                    if (response.error != undefined){
 | 
			
		||||
@@ -1066,7 +1067,7 @@
 | 
			
		||||
    function removeFromBannedList(countryCode){
 | 
			
		||||
        countryCode = countryCode.toLowerCase();
 | 
			
		||||
        let countryName = getCountryName(countryCode);
 | 
			
		||||
        $.ajax({
 | 
			
		||||
        $.cjax({
 | 
			
		||||
            url: "/api/blacklist/country/remove",
 | 
			
		||||
            method: "POST",
 | 
			
		||||
            data: { cc: countryCode, id: currentEditingAccessRule},
 | 
			
		||||
@@ -1097,7 +1098,7 @@
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $.ajax({
 | 
			
		||||
        $.cjax({
 | 
			
		||||
            url: "/api/blacklist/ip/add",
 | 
			
		||||
            type: "POST",
 | 
			
		||||
            data: {ip: targetIp.toLowerCase(), id: currentEditingAccessRule},
 | 
			
		||||
@@ -1119,7 +1120,7 @@
 | 
			
		||||
 | 
			
		||||
    function removeIpBlacklist(ipaddr){
 | 
			
		||||
        if (confirm("Confirm remove blacklist for " + ipaddr + " ?")){
 | 
			
		||||
            $.ajax({
 | 
			
		||||
            $.cjax({
 | 
			
		||||
                url: "/api/blacklist/ip/remove",
 | 
			
		||||
                type: "POST",
 | 
			
		||||
                data: {ip: ipaddr.toLowerCase(), id: currentEditingAccessRule},
 | 
			
		||||
@@ -1143,7 +1144,7 @@
 | 
			
		||||
    */
 | 
			
		||||
    function enableWhitelist() {
 | 
			
		||||
        var isChecked = $('#enableWhitelist').is(':checked');
 | 
			
		||||
        $.ajax({
 | 
			
		||||
        $.cjax({
 | 
			
		||||
            type: 'POST',
 | 
			
		||||
            url: '/api/whitelist/enable',
 | 
			
		||||
            data: { enable: isChecked , id: currentEditingAccessRule},
 | 
			
		||||
@@ -1165,7 +1166,7 @@
 | 
			
		||||
        let counter = 0;
 | 
			
		||||
        for(var i = 0; i < ccs.length; i++){
 | 
			
		||||
            let thisCountryCode = ccs[i];
 | 
			
		||||
            $.ajax({
 | 
			
		||||
            $.cjax({
 | 
			
		||||
                type: "POST",
 | 
			
		||||
                url: "/api/whitelist/country/add",
 | 
			
		||||
                data: { cc: thisCountryCode , id: currentEditingAccessRule},
 | 
			
		||||
@@ -1199,7 +1200,7 @@
 | 
			
		||||
    function removeFromWhiteList(countryCode){
 | 
			
		||||
        if (confirm("Confirm removing " + getCountryName(countryCode) + " from whitelist?")){
 | 
			
		||||
            countryCode = countryCode.toLowerCase(); 
 | 
			
		||||
            $.ajax({
 | 
			
		||||
            $.cjax({
 | 
			
		||||
                url: "/api/whitelist/country/remove",
 | 
			
		||||
                method: "POST",
 | 
			
		||||
                data: { cc: countryCode , id: currentEditingAccessRule},
 | 
			
		||||
@@ -1230,7 +1231,7 @@
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $.ajax({
 | 
			
		||||
        $.cjax({
 | 
			
		||||
            url: "/api/whitelist/ip/add",
 | 
			
		||||
            type: "POST",
 | 
			
		||||
            data: {ip: targetIp.toLowerCase(), "comment": remarks, id: currentEditingAccessRule},
 | 
			
		||||
@@ -1253,7 +1254,7 @@
 | 
			
		||||
 | 
			
		||||
    function removeIpWhitelist(ipaddr){
 | 
			
		||||
        if (confirm("Confirm remove whitelist for " + ipaddr + " ?")){
 | 
			
		||||
            $.ajax({
 | 
			
		||||
            $.cjax({
 | 
			
		||||
                url: "/api/whitelist/ip/remove",
 | 
			
		||||
                type: "POST",
 | 
			
		||||
                data: {ip: ipaddr.toLowerCase(), id: currentEditingAccessRule},
 | 
			
		||||
 
 | 
			
		||||
@@ -257,7 +257,7 @@
 | 
			
		||||
    //Delete the certificate by its domain
 | 
			
		||||
    function deleteCertificate(domain){
 | 
			
		||||
        if (confirm("Confirm delete certificate for " + domain + " ?")){
 | 
			
		||||
            $.ajax({
 | 
			
		||||
            $.cjax({
 | 
			
		||||
                url: "/api/cert/delete",
 | 
			
		||||
                method: "POST",
 | 
			
		||||
                data: {domain: domain},
 | 
			
		||||
@@ -316,7 +316,7 @@
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $.ajax({
 | 
			
		||||
        $.cjax({
 | 
			
		||||
            url: "/api/acme/autoRenew/email",
 | 
			
		||||
            method: "POST",
 | 
			
		||||
            data: {"set": newDefaultEmail},
 | 
			
		||||
@@ -330,7 +330,7 @@
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        $.ajax({
 | 
			
		||||
        $.cjax({
 | 
			
		||||
            url: "/api/acme/autoRenew/ca",
 | 
			
		||||
            data: {"set": newDefaultCA},
 | 
			
		||||
            method: "POST",
 | 
			
		||||
 
 | 
			
		||||
@@ -87,7 +87,7 @@
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function addGANet() {
 | 
			
		||||
        $.ajax({
 | 
			
		||||
        $.cjax({
 | 
			
		||||
            url: "/api/gan/network/add",
 | 
			
		||||
            type: "POST",
 | 
			
		||||
            dataType: "json",
 | 
			
		||||
@@ -191,7 +191,7 @@
 | 
			
		||||
    //Remove the given GANet
 | 
			
		||||
    function removeGANet(netid){
 | 
			
		||||
        if (confirm("Confirm remove Network " + netid + " PERMANENTLY ?"))
 | 
			
		||||
        $.ajax({
 | 
			
		||||
        $.cjax({
 | 
			
		||||
            url: "/api/gan/network/remove",
 | 
			
		||||
            type: "POST",
 | 
			
		||||
            dataType: "json",
 | 
			
		||||
 
 | 
			
		||||
@@ -214,7 +214,7 @@
 | 
			
		||||
        //Get CIDR from selected range group
 | 
			
		||||
        var cidr = $(".iprange.active").attr("cidr");
 | 
			
		||||
 | 
			
		||||
        $.ajax({
 | 
			
		||||
        $.cjax({
 | 
			
		||||
            url: "/api/gan/network/setRange",
 | 
			
		||||
            metohd: "POST",
 | 
			
		||||
            data:{
 | 
			
		||||
@@ -240,7 +240,7 @@
 | 
			
		||||
        if (object != undefined){
 | 
			
		||||
            $(object).addClass("loading");
 | 
			
		||||
        }
 | 
			
		||||
        $.ajax({
 | 
			
		||||
        $.cjax({
 | 
			
		||||
            url: "/api/gan/network/name",
 | 
			
		||||
            method: "POST",
 | 
			
		||||
            data: {
 | 
			
		||||
@@ -287,7 +287,7 @@
 | 
			
		||||
 | 
			
		||||
    //Handle delete IP from memeber
 | 
			
		||||
    function deleteIpFromMemeber(memberid, ip){
 | 
			
		||||
        $.ajax({
 | 
			
		||||
        $.cjax({
 | 
			
		||||
            url: "/api/gan/members/ip",
 | 
			
		||||
            metohd: "POST",
 | 
			
		||||
            data: {
 | 
			
		||||
@@ -334,7 +334,7 @@
 | 
			
		||||
            return
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $.ajax({
 | 
			
		||||
        $.cjax({
 | 
			
		||||
            url: "/api/gan/members/ip",
 | 
			
		||||
            metohd: "POST",
 | 
			
		||||
            data: {
 | 
			
		||||
@@ -461,7 +461,7 @@
 | 
			
		||||
        $(".memberName").each(function(){
 | 
			
		||||
            let addr = $(this).attr("addr");
 | 
			
		||||
            let targetDOM = $(this);
 | 
			
		||||
            $.ajax({
 | 
			
		||||
            $.cjax({
 | 
			
		||||
                url: "/api/gan/members/name",
 | 
			
		||||
                method: "POST",
 | 
			
		||||
                data: {
 | 
			
		||||
@@ -487,7 +487,7 @@
 | 
			
		||||
 | 
			
		||||
        let newname = prompt("Enter a easy manageable name for " + targetMemberAddr, "");
 | 
			
		||||
        if (newname != null && newname.trim() != "") {
 | 
			
		||||
          $.ajax({
 | 
			
		||||
          $.cjax({
 | 
			
		||||
            url: "/api/gan/members/name",
 | 
			
		||||
            method: "POST",
 | 
			
		||||
            data: {
 | 
			
		||||
@@ -553,7 +553,7 @@
 | 
			
		||||
    function handleMemberAuth(object){
 | 
			
		||||
        let targetMemberAddr = $(object).attr("addr");
 | 
			
		||||
        let isAuthed = object.checked;
 | 
			
		||||
        $.ajax({
 | 
			
		||||
        $.cjax({
 | 
			
		||||
            url: "/api/gan/members/authorize",
 | 
			
		||||
            method: "POST",
 | 
			
		||||
            data: {
 | 
			
		||||
@@ -580,7 +580,7 @@
 | 
			
		||||
 | 
			
		||||
    function handleMemberDelete(addr){
 | 
			
		||||
        if (confirm("Confirm delete member " + addr + " ?")){
 | 
			
		||||
            $.ajax({
 | 
			
		||||
            $.cjax({
 | 
			
		||||
                url: "/api/gan/members/delete",
 | 
			
		||||
                method: "POST",
 | 
			
		||||
                data: {
 | 
			
		||||
@@ -605,7 +605,7 @@
 | 
			
		||||
        $(".addControllerToNetworkBtn").addClass("disabled");
 | 
			
		||||
        $(".addControllerToNetworkBtn").addClass("loading");
 | 
			
		||||
    
 | 
			
		||||
        $.ajax({
 | 
			
		||||
        $.cjax({
 | 
			
		||||
            url: "/api/gan/network/join",
 | 
			
		||||
            method: "POST",
 | 
			
		||||
            data: {
 | 
			
		||||
@@ -630,7 +630,7 @@
 | 
			
		||||
        $(".removeControllerFromNetworkBtn").addClass("disabled");
 | 
			
		||||
        $(".removeControllerFromNetworkBtn").addClass("loading");
 | 
			
		||||
        
 | 
			
		||||
        $.ajax({
 | 
			
		||||
        $.cjax({
 | 
			
		||||
            url: "/api/gan/network/leave",
 | 
			
		||||
            method: "POST",
 | 
			
		||||
            data: {
 | 
			
		||||
 
 | 
			
		||||
@@ -400,7 +400,7 @@
 | 
			
		||||
        let rateLimit = $(row).find(".RateLimit").val();
 | 
			
		||||
        let bypassGlobalTLS = $(row).find(".BypassGlobalTLS")[0].checked;
 | 
			
		||||
 | 
			
		||||
        $.ajax({
 | 
			
		||||
        $.cjax({
 | 
			
		||||
            url: "/api/proxy/edit",
 | 
			
		||||
            method: "POST",
 | 
			
		||||
            data: {
 | 
			
		||||
@@ -422,6 +422,28 @@
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Generic functions for delete rp endpoints 
 | 
			
		||||
    function deleteEndpoint(epoint){
 | 
			
		||||
        epoint = decodeURIComponent(epoint).hexDecode();
 | 
			
		||||
        if (confirm("Confirm remove proxy for :" + epoint + "?")){
 | 
			
		||||
            $.cjax({
 | 
			
		||||
                url: "/api/proxy/del",
 | 
			
		||||
                method: "POST",
 | 
			
		||||
                data: {ep: epoint},
 | 
			
		||||
                success: function(data){
 | 
			
		||||
                    if (data.error == undefined){
 | 
			
		||||
                        listProxyEndpoints();
 | 
			
		||||
                        msgbox("Proxy Rule Deleted", true);
 | 
			
		||||
                        reloadUptimeList();
 | 
			
		||||
                    }else{
 | 
			
		||||
                        msgbox(data.error, false);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            })
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    /* button events */
 | 
			
		||||
    function editBasicAuthCredentials(uuid){
 | 
			
		||||
@@ -474,7 +496,7 @@
 | 
			
		||||
    function handleProxyRuleToggle(object){
 | 
			
		||||
        let endpointUUID = $(object).attr("eptuuid");
 | 
			
		||||
        let isChecked = object.checked;
 | 
			
		||||
        $.ajax({
 | 
			
		||||
        $.cjax({
 | 
			
		||||
            url: "/api/proxy/toggle",
 | 
			
		||||
            data: {
 | 
			
		||||
                "ep": endpointUUID,
 | 
			
		||||
 
 | 
			
		||||
@@ -339,7 +339,7 @@ function setWoLAddress() {
 | 
			
		||||
        $("#wol_mac").parent().removeClass("error");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $.ajax({
 | 
			
		||||
    $.cjax({
 | 
			
		||||
        url: wake_on_lan_API,
 | 
			
		||||
        type: "POST",
 | 
			
		||||
        data: {
 | 
			
		||||
@@ -363,7 +363,7 @@ function setWoLAddress() {
 | 
			
		||||
 | 
			
		||||
function delWoLAddr(mac, name) {
 | 
			
		||||
    if (confirm(`Confirm remove WoL record for ${name} (${mac}) ?`)){
 | 
			
		||||
        $.ajax({
 | 
			
		||||
        $.cjax({
 | 
			
		||||
            url: wake_on_lan_API,
 | 
			
		||||
            type: "POST",
 | 
			
		||||
            data: {
 | 
			
		||||
@@ -385,7 +385,7 @@ function wakeWoL(mac, object=undefined) {
 | 
			
		||||
    if (object != undefined){
 | 
			
		||||
        $(object).addClass("loading").addClass("disabled");
 | 
			
		||||
    }
 | 
			
		||||
    $.ajax({
 | 
			
		||||
    $.cjax({
 | 
			
		||||
        url: wake_on_lan_API,
 | 
			
		||||
        type: "POST",
 | 
			
		||||
        data: {
 | 
			
		||||
@@ -594,7 +594,7 @@ function initForwardProxyInfo(){
 | 
			
		||||
initForwardProxyInfo();
 | 
			
		||||
 | 
			
		||||
function toggleForwadProxy(enabled){
 | 
			
		||||
    $.ajax({
 | 
			
		||||
    $.cjax({
 | 
			
		||||
        url: "/api/tools/fwdproxy/enable",
 | 
			
		||||
        method: "POST",
 | 
			
		||||
        data: {
 | 
			
		||||
@@ -620,7 +620,7 @@ function updateForwardProxyPort(){
 | 
			
		||||
        $("#newPortNumber").parent().removeClass('error');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $.ajax({
 | 
			
		||||
    $.cjax({
 | 
			
		||||
        url: "/api/tools/fwdproxy/port",
 | 
			
		||||
        method: "POST",
 | 
			
		||||
        data: {
 | 
			
		||||
 
 | 
			
		||||
@@ -116,7 +116,7 @@
 | 
			
		||||
        let forwardChildpath = document.querySelector('input[name="forward-childpath"]').checked;
 | 
			
		||||
        let redirectType = document.querySelector('input[name="redirect-type"]:checked').value;
 | 
			
		||||
 | 
			
		||||
        $.ajax({
 | 
			
		||||
        $.cjax({
 | 
			
		||||
            url: "/api/redirect/add", 
 | 
			
		||||
            method: "POST",
 | 
			
		||||
            data: {
 | 
			
		||||
@@ -141,7 +141,7 @@
 | 
			
		||||
      let targetURL = $(obj).attr("rurl");
 | 
			
		||||
      targetURL = JSON.parse(decodeURIComponent(targetURL));
 | 
			
		||||
      if (confirm("Confirm remove redirection from " + targetURL + " ?")){
 | 
			
		||||
        $.ajax({
 | 
			
		||||
        $.cjax({
 | 
			
		||||
              url: "/api/redirect/delete", 
 | 
			
		||||
              method: "POST",
 | 
			
		||||
              data: {
 | 
			
		||||
@@ -191,8 +191,9 @@
 | 
			
		||||
 | 
			
		||||
        //Bind event to the checkbox
 | 
			
		||||
        $("#redirectRegex").on("change", function(){
 | 
			
		||||
          $.ajax({
 | 
			
		||||
          $.cjax({
 | 
			
		||||
            url: "/api/redirect/regex",
 | 
			
		||||
            method: "POST",
 | 
			
		||||
            data: {"enable": $(this)[0].checked},
 | 
			
		||||
            success: function(data){
 | 
			
		||||
              if (data.error != undefined){
 | 
			
		||||
 
 | 
			
		||||
@@ -181,8 +181,9 @@
 | 
			
		||||
            targetDomain = targetDomain.substring(8);
 | 
			
		||||
            $("#proxyRoot").val(targetDomain);
 | 
			
		||||
        }
 | 
			
		||||
       $.ajax({
 | 
			
		||||
       $.cjax({
 | 
			
		||||
            url: "/api/proxy/tlscheck",
 | 
			
		||||
            method: "POST",
 | 
			
		||||
            data: {url: targetDomain},
 | 
			
		||||
            success: function(data){
 | 
			
		||||
                if (data.error != undefined){
 | 
			
		||||
@@ -232,7 +233,7 @@
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Create the endpoint by calling add
 | 
			
		||||
        $.ajax({
 | 
			
		||||
        $.cjax({
 | 
			
		||||
            url: "/api/proxy/add",
 | 
			
		||||
            data: {
 | 
			
		||||
                "type": "root", 
 | 
			
		||||
 
 | 
			
		||||
@@ -212,8 +212,9 @@
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Create the endpoint by calling add
 | 
			
		||||
        $.ajax({
 | 
			
		||||
        $.cjax({
 | 
			
		||||
            url: "/api/proxy/add",
 | 
			
		||||
            method: "POST",
 | 
			
		||||
            data: {
 | 
			
		||||
                type: "host",
 | 
			
		||||
                rootname: rootname, 
 | 
			
		||||
@@ -270,22 +271,6 @@
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Generic functions for delete rp endpoints 
 | 
			
		||||
    function deleteEndpoint(epoint){
 | 
			
		||||
        epoint = decodeURIComponent(epoint).hexDecode();
 | 
			
		||||
        if (confirm("Confirm remove proxy for :" + epoint + "?")){
 | 
			
		||||
            $.ajax({
 | 
			
		||||
                url: "/api/proxy/del",
 | 
			
		||||
                data: {ep: epoint, },
 | 
			
		||||
                success: function(){
 | 
			
		||||
                    listProxyEndpoints();
 | 
			
		||||
                    msgbox("Proxy Rule Deleted", true);
 | 
			
		||||
                    reloadUptimeList();
 | 
			
		||||
                }
 | 
			
		||||
            })
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Clearn the proxy target value, make sure user do not enter http:// or https://
 | 
			
		||||
    //and auto select TLS checkbox if https:// exists
 | 
			
		||||
    function autoFillTargetTLS(input){
 | 
			
		||||
@@ -307,12 +292,12 @@
 | 
			
		||||
 | 
			
		||||
    //Automatic check if the site require TLS and check the checkbox if needed
 | 
			
		||||
    function autoCheckTls(targetDomain){
 | 
			
		||||
       $.ajax({
 | 
			
		||||
       $.cjax({
 | 
			
		||||
            url: "/api/proxy/tlscheck",
 | 
			
		||||
            data: {url: targetDomain},
 | 
			
		||||
            success: function(data){
 | 
			
		||||
                if (data.error != undefined){
 | 
			
		||||
 | 
			
		||||
                    msgbox(data.error, false);
 | 
			
		||||
                }else if (data == "https"){
 | 
			
		||||
                    $("#reqTls").parent().checkbox("set checked");
 | 
			
		||||
                }else if (data == "http"){
 | 
			
		||||
 
 | 
			
		||||
@@ -315,26 +315,39 @@
 | 
			
		||||
 | 
			
		||||
    //Start and stop service button
 | 
			
		||||
    function startService(){
 | 
			
		||||
        $.post("/api/proxy/enable", {enable: true}, function(data){
 | 
			
		||||
            if (data.error != undefined){
 | 
			
		||||
                msgbox(data.error, false, 5000);
 | 
			
		||||
        $.cjax({
 | 
			
		||||
            url: "/api/proxy/enable",
 | 
			
		||||
            method: "POST",
 | 
			
		||||
            data: {enable: true},
 | 
			
		||||
            success: function(data){
 | 
			
		||||
                if (data.error != undefined){
 | 
			
		||||
                    msgbox(data.error, false, 5000);
 | 
			
		||||
                }
 | 
			
		||||
                initRPStaste();
 | 
			
		||||
            }
 | 
			
		||||
            initRPStaste();
 | 
			
		||||
 | 
			
		||||
        });
 | 
			
		||||
    }   
 | 
			
		||||
 | 
			
		||||
    function stopService(){
 | 
			
		||||
        $.post("/api/proxy/enable", {enable: false}, function(data){
 | 
			
		||||
            if (data.error != undefined){
 | 
			
		||||
                msgbox(data.error, false, 5000);
 | 
			
		||||
        $.cjax({
 | 
			
		||||
            url: "/api/proxy/enable",
 | 
			
		||||
            method: "POST",
 | 
			
		||||
            data: {enable: false},
 | 
			
		||||
            success: function(data){
 | 
			
		||||
                if (data.error != undefined){
 | 
			
		||||
                    msgbox(data.error, false, 5000);
 | 
			
		||||
                }
 | 
			
		||||
                initRPStaste();
 | 
			
		||||
            }
 | 
			
		||||
            initRPStaste();
 | 
			
		||||
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function handleP80ListenerStateChange(enabled){
 | 
			
		||||
        $.ajax({
 | 
			
		||||
        $.cjax({
 | 
			
		||||
            url: "/api/proxy/listenPort80",
 | 
			
		||||
            method: "POST",
 | 
			
		||||
            data: {"enable": enabled},
 | 
			
		||||
            success: function(data){
 | 
			
		||||
                if (data.error != undefined){
 | 
			
		||||
@@ -361,16 +374,21 @@
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $.post("/api/proxy/setIncoming", {incoming: newPortValue}, function(data){
 | 
			
		||||
            if (data.error != undefined){
 | 
			
		||||
                msgbox(data.error, false, 5000);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            msgbox("Listening Port Updated");
 | 
			
		||||
            initRPStaste();
 | 
			
		||||
        $.cjax({
 | 
			
		||||
            url: "/api/proxy/setIncoming",
 | 
			
		||||
            method: "POST",
 | 
			
		||||
            data: {incoming: newPortValue},
 | 
			
		||||
            success: function(data){
 | 
			
		||||
                if (data.error != undefined){
 | 
			
		||||
                    msgbox(data.error, false, 5000);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                msgbox("Listening Port Updated");
 | 
			
		||||
                initRPStaste();
 | 
			
		||||
 | 
			
		||||
            //Hide the reminder text
 | 
			
		||||
            $("#applyButtonReminder").hide();
 | 
			
		||||
                //Hide the reminder text
 | 
			
		||||
                $("#applyButtonReminder").hide();
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -402,8 +420,9 @@
 | 
			
		||||
            //Initiate the input listener on the checkbox
 | 
			
		||||
            $("#redirect").find("input").on("change", function(){
 | 
			
		||||
                let thisValue = $("#redirect").checkbox("is checked");
 | 
			
		||||
                    $.ajax({
 | 
			
		||||
                    $.cjax({
 | 
			
		||||
                        url: "/api/proxy/useHttpsRedirect",
 | 
			
		||||
                        method: "POST",
 | 
			
		||||
                        data: {set: thisValue},
 | 
			
		||||
                        success: function(data){
 | 
			
		||||
                            if (data.error != undefined){
 | 
			
		||||
@@ -440,9 +459,10 @@
 | 
			
		||||
            //Bind events to the checkbox
 | 
			
		||||
            $("#tlsMinVer").find("input").on("change", function(){
 | 
			
		||||
                let thisValue = $("#tlsMinVer").checkbox("is checked");
 | 
			
		||||
                $.ajax({
 | 
			
		||||
                $.cjax({
 | 
			
		||||
                    url: "/api/cert/tlsRequireLatest",
 | 
			
		||||
                    data: {"set": thisValue},
 | 
			
		||||
                    method: "POST",
 | 
			
		||||
                    success: function(data){
 | 
			
		||||
                        if (data.error != undefined){
 | 
			
		||||
                            msgbox(data.error, false, 5000);
 | 
			
		||||
@@ -498,15 +518,15 @@
 | 
			
		||||
                }else{
 | 
			
		||||
                    $(".tlsEnabledOnly").addClass('disabled');
 | 
			
		||||
                }
 | 
			
		||||
                $.ajax({
 | 
			
		||||
                $.cjax({
 | 
			
		||||
                    url: "/api/cert/tls",
 | 
			
		||||
                    method: "POST",
 | 
			
		||||
                    data: {set: thisValue},
 | 
			
		||||
                    success: function(data){
 | 
			
		||||
                        if (data.error != undefined){
 | 
			
		||||
                            alert(data.error);
 | 
			
		||||
                            msgbox(data.error, false);
 | 
			
		||||
                        }else{
 | 
			
		||||
                            //Updated
 | 
			
		||||
                            
 | 
			
		||||
                            //Check for case if the port is invalid default ports
 | 
			
		||||
                            if ($("#incomingPort").val() == "80" && thisValue == true){
 | 
			
		||||
                                confirmBox("Change listen port to :443?", function(choice){
 | 
			
		||||
 
 | 
			
		||||
@@ -100,7 +100,7 @@
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Send the AJAX POST request
 | 
			
		||||
            $.ajax({
 | 
			
		||||
            $.cjax({
 | 
			
		||||
                type: 'POST',
 | 
			
		||||
                url: '/api/streamprox/config/add',
 | 
			
		||||
                data: form.serialize(),
 | 
			
		||||
@@ -285,7 +285,7 @@
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Send the AJAX POST request
 | 
			
		||||
            $.ajax({
 | 
			
		||||
            $.cjax({
 | 
			
		||||
                type: 'POST',
 | 
			
		||||
                url: '/api/streamprox/config/edit',
 | 
			
		||||
                method: "POST",
 | 
			
		||||
@@ -316,7 +316,7 @@
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        function deleteTCPProxyConfig(configUUID){
 | 
			
		||||
            $.ajax({
 | 
			
		||||
            $.cjax({
 | 
			
		||||
                url: "/api/streamprox/config/delete",
 | 
			
		||||
                method: "POST",
 | 
			
		||||
                data: {uuid: configUUID},
 | 
			
		||||
@@ -333,7 +333,7 @@
 | 
			
		||||
 | 
			
		||||
        //Start a TCP proxy by their config UUID
 | 
			
		||||
        function startStreamProx(configUUID){
 | 
			
		||||
            $.ajax({
 | 
			
		||||
            $.cjax({
 | 
			
		||||
                url: "/api/streamprox/config/start",
 | 
			
		||||
                method: "POST",
 | 
			
		||||
                data: {uuid: configUUID},
 | 
			
		||||
@@ -351,7 +351,7 @@
 | 
			
		||||
 | 
			
		||||
        //Stop a TCP proxy by their config UUID
 | 
			
		||||
        function stopStreamProx(configUUID){
 | 
			
		||||
            $.ajax({
 | 
			
		||||
            $.cjax({
 | 
			
		||||
                url: "/api/streamprox/config/stop",
 | 
			
		||||
                method: "POST",
 | 
			
		||||
                data: {uuid: configUUID},
 | 
			
		||||
 
 | 
			
		||||
@@ -233,7 +233,7 @@
 | 
			
		||||
        const newPassword = document.getElementsByName('newPassword')[0].value;
 | 
			
		||||
        const confirmNewPassword = document.getElementsByName('confirmNewPassword')[0].value;
 | 
			
		||||
        
 | 
			
		||||
        $.ajax({
 | 
			
		||||
        $.cjax({
 | 
			
		||||
            type: "POST",
 | 
			
		||||
            url: "/api/auth/changePassword",
 | 
			
		||||
            data: {
 | 
			
		||||
@@ -279,7 +279,7 @@
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $.ajax({
 | 
			
		||||
        $.cjax({
 | 
			
		||||
            type: "POST",
 | 
			
		||||
            url: "/api/tools/smtp/set",
 | 
			
		||||
            data: data,
 | 
			
		||||
 
 | 
			
		||||
@@ -190,7 +190,7 @@
 | 
			
		||||
    function updateVDTargetTLSState(){
 | 
			
		||||
        var targetDomain = $("#virtualDirectoryDomain").val().trim();
 | 
			
		||||
        if (targetDomain != ""){
 | 
			
		||||
            $.ajax({
 | 
			
		||||
            $.cjax({
 | 
			
		||||
                url: "/api/proxy/tlscheck",
 | 
			
		||||
                data: {url: targetDomain},
 | 
			
		||||
                success: function(data){
 | 
			
		||||
@@ -252,7 +252,7 @@
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Create a virtual directory endpoint
 | 
			
		||||
        $.ajax({
 | 
			
		||||
        $.cjax({
 | 
			
		||||
            url: "/api/proxy/vdir/add",
 | 
			
		||||
            method: "POST",
 | 
			
		||||
            data: {
 | 
			
		||||
@@ -295,7 +295,7 @@
 | 
			
		||||
            epType = "root";
 | 
			
		||||
            path = "";
 | 
			
		||||
        }
 | 
			
		||||
        $.ajax({
 | 
			
		||||
        $.cjax({
 | 
			
		||||
            url: "/api/proxy/vdir/del",
 | 
			
		||||
            method: "POST",
 | 
			
		||||
            data: {
 | 
			
		||||
@@ -384,7 +384,7 @@
 | 
			
		||||
 | 
			
		||||
        //console.log(mathingPath, newDomain, requireTLS, skipValidation);
 | 
			
		||||
 | 
			
		||||
        $.ajax({
 | 
			
		||||
        $.cjax({
 | 
			
		||||
            url: "/api/proxy/vdir/edit",
 | 
			
		||||
            method: "POST",
 | 
			
		||||
            data: {
 | 
			
		||||
 
 | 
			
		||||
@@ -164,7 +164,7 @@
 | 
			
		||||
 | 
			
		||||
                $("#webserv_enableDirList").off("change").on("change", function(){
 | 
			
		||||
                    let enable = $(this)[0].checked;
 | 
			
		||||
                    $.ajax({
 | 
			
		||||
                    $.cjax({
 | 
			
		||||
                        url: "/api/webserv/setDirList",
 | 
			
		||||
                        method: "POST",
 | 
			
		||||
                        data: {"enable": enable},
 | 
			
		||||
@@ -186,7 +186,7 @@
 | 
			
		||||
                        confirmBox("This setting might cause port conflict. Continue Anyway?", function(choice){
 | 
			
		||||
                            if (choice == true){
 | 
			
		||||
                                //Continue anyway
 | 
			
		||||
                                $.ajax({
 | 
			
		||||
                                $.cjax({
 | 
			
		||||
                                    url: "/api/webserv/setPort",
 | 
			
		||||
                                    method: "POST",
 | 
			
		||||
                                    data: {"port": newPort},
 | 
			
		||||
@@ -206,7 +206,7 @@
 | 
			
		||||
                            }
 | 
			
		||||
                        });
 | 
			
		||||
                    }else{
 | 
			
		||||
                        $.ajax({
 | 
			
		||||
                        $.cjax({
 | 
			
		||||
                            url: "/api/webserv/setPort",
 | 
			
		||||
                            method: "POST",
 | 
			
		||||
                            data: {"port": newPort},
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@
 | 
			
		||||
        <meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1"/>
 | 
			
		||||
        <meta charset="UTF-8">
 | 
			
		||||
        <meta name="theme-color" content="#4b75ff">
 | 
			
		||||
        <meta name="zoraxy.csrf.Token" content="{{.csrfToken}}">
 | 
			
		||||
        <link rel="icon" type="image/png" href="./favicon.png" />
 | 
			
		||||
        <title>Control Panel | Zoraxy</title>
 | 
			
		||||
        <link rel="stylesheet" href="script/semantic/semantic.min.css">
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@
 | 
			
		||||
    <meta charset="UTF-8">
 | 
			
		||||
    <meta name="robots" content="noindex" />
 | 
			
		||||
    <meta name="viewport" content="width=device-width, initial-scale=1">
 | 
			
		||||
    <meta name="zoraxy.csrf.Token" content="{{.csrfToken}}">
 | 
			
		||||
    <link rel="icon" type="image/png" href="./favicon.png" />
 | 
			
		||||
    <title>Login | Zoraxy</title>
 | 
			
		||||
    <link rel="stylesheet" href="script/semantic/semantic.min.css">
 | 
			
		||||
@@ -250,10 +251,10 @@
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        $("#regsiterbtn").on("click", function(event){
 | 
			
		||||
            var username = $("#username").val();
 | 
			
		||||
            var magic = $("#magic").val();
 | 
			
		||||
            var repeatMagic = $("#repeatMagic").val();
 | 
			
		||||
 | 
			
		||||
            let username = $("#username").val();
 | 
			
		||||
            let magic = $("#magic").val();
 | 
			
		||||
            let repeatMagic = $("#repeatMagic").val();
 | 
			
		||||
            let csrfToken = document.getElementsByTagName("meta")["zoraxy.csrf.Token"].getAttribute("content");
 | 
			
		||||
            if (magic !== repeatMagic) {
 | 
			
		||||
                alert("Password does not match");
 | 
			
		||||
                return;
 | 
			
		||||
@@ -262,6 +263,9 @@
 | 
			
		||||
            $.ajax({
 | 
			
		||||
                url: "/api/auth/register",
 | 
			
		||||
                method: "POST",
 | 
			
		||||
                beforeSend: function(request) {
 | 
			
		||||
                    request.setRequestHeader("X-CSRF-Token",csrfToken);
 | 
			
		||||
                },
 | 
			
		||||
                data: {
 | 
			
		||||
                    username: username,
 | 
			
		||||
                    password: magic
 | 
			
		||||
@@ -297,29 +301,45 @@
 | 
			
		||||
 | 
			
		||||
        //Login system with the given username and password
 | 
			
		||||
        function login(){
 | 
			
		||||
            var username = $("#username").val();
 | 
			
		||||
            var magic = $("#magic").val();
 | 
			
		||||
            var rmbme = document.getElementById("rmbme").checked;
 | 
			
		||||
            let username = $("#username").val();
 | 
			
		||||
            let magic = $("#magic").val();
 | 
			
		||||
            let rmbme = document.getElementById("rmbme").checked;
 | 
			
		||||
            let csrfToken = document.getElementsByTagName("meta")["zoraxy.csrf.Token"].getAttribute("content");
 | 
			
		||||
            $("#errmsg").stop().finish().slideUp("fast");
 | 
			
		||||
            $("input").addClass('disabled');
 | 
			
		||||
            $.post(loginAddress, {"username": username, "password": magic, "rmbme": rmbme}).done(function(data){
 | 
			
		||||
                if (data.error !== undefined){
 | 
			
		||||
                    //Something went wrong during the login
 | 
			
		||||
                    $("#errmsg").html(`<i class="red remove icon"></i> ${data.error}`);
 | 
			
		||||
                    $("#errmsg").stop().finish().slideDown('fast');
 | 
			
		||||
                }else if(data.redirect !== undefined){
 | 
			
		||||
                    //LDAP Related Code
 | 
			
		||||
                    window.location.href = data.redirect;
 | 
			
		||||
                }else{
 | 
			
		||||
                    //Login succeed
 | 
			
		||||
                    if (redirectionAddress == ""){
 | 
			
		||||
                        //Redirect back to index
 | 
			
		||||
                        window.location.href = "./";
 | 
			
		||||
            $.ajax({
 | 
			
		||||
                url: loginAddress, 
 | 
			
		||||
                type: "POST",
 | 
			
		||||
                beforeSend: function(request) {
 | 
			
		||||
                    request.setRequestHeader("X-CSRF-Token",csrfToken);
 | 
			
		||||
                },
 | 
			
		||||
                data: {
 | 
			
		||||
                    "username": username, 
 | 
			
		||||
                    "password": magic, 
 | 
			
		||||
                    "rmbme": rmbme,
 | 
			
		||||
                },
 | 
			
		||||
                success: function(data){
 | 
			
		||||
                    if (data.error !== undefined){
 | 
			
		||||
                        //Something went wrong during the login
 | 
			
		||||
                        $("#errmsg").html(`<i class="red remove icon"></i> ${data.error}`);
 | 
			
		||||
                        $("#errmsg").stop().finish().slideDown('fast');
 | 
			
		||||
                    }else if(data.redirect !== undefined){
 | 
			
		||||
                        //LDAP Related Code
 | 
			
		||||
                        window.location.href = data.redirect;
 | 
			
		||||
                    }else{
 | 
			
		||||
                        window.location.href = redirectionAddress;
 | 
			
		||||
                        //Login succeed
 | 
			
		||||
                        if (redirectionAddress == ""){
 | 
			
		||||
                            //Redirect back to index
 | 
			
		||||
                            window.location.href = "./";
 | 
			
		||||
                        }else{
 | 
			
		||||
                            window.location.href = redirectionAddress;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    $("input").removeClass('disabled');
 | 
			
		||||
                },
 | 
			
		||||
                error: function(){
 | 
			
		||||
                    alert("Something went wrong.")
 | 
			
		||||
                }
 | 
			
		||||
                $("input").removeClass('disabled');
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@
 | 
			
		||||
<html>
 | 
			
		||||
    <head>
 | 
			
		||||
    <meta charset="UTF-8">
 | 
			
		||||
    <meta name="zoraxy.csrf.Token" content="{{.csrfToken}}">
 | 
			
		||||
    <meta name="robots" content="noindex" />
 | 
			
		||||
    <meta name="viewport" content="width=device-width, initial-scale=1">
 | 
			
		||||
    <link rel="icon" type="image/png" href="./favicon.png" />
 | 
			
		||||
@@ -255,25 +256,36 @@
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Send POST request with input values as data
 | 
			
		||||
            $.post('/api/account/new', { username: username, token: token, newpw: newPassword })
 | 
			
		||||
            .done(function(data) {
 | 
			
		||||
                // Handle successful response
 | 
			
		||||
                if (data.error != undefined){
 | 
			
		||||
                    $("#errmsg").html(`<i class="red circle times icon"></i> ` + data.error);
 | 
			
		||||
                    $("#errmsg").show();
 | 
			
		||||
                }else{
 | 
			
		||||
                    $("#errmsg").hide();
 | 
			
		||||
                    $("#countdown").hide();
 | 
			
		||||
                    $("#succmsg").show();
 | 
			
		||||
                    setTimeout(function(){
 | 
			
		||||
                        window.location.href = "/";
 | 
			
		||||
                    }, 3000);
 | 
			
		||||
            let csrfToken = document.getElementsByTagName("meta")["zoraxy.csrf.Token"].getAttribute("content");
 | 
			
		||||
            $.ajax({
 | 
			
		||||
                url: "/api/account/new",
 | 
			
		||||
                method: "POST",
 | 
			
		||||
                data: {
 | 
			
		||||
                    username: username, 
 | 
			
		||||
                    token: token, 
 | 
			
		||||
                    newpw: newPassword
 | 
			
		||||
                },
 | 
			
		||||
                headers: {
 | 
			
		||||
                    "X-CSRF-Token": csrfToken,
 | 
			
		||||
                },
 | 
			
		||||
                success: function(data){
 | 
			
		||||
                    // Handle successful response
 | 
			
		||||
                    if (data.error != undefined){
 | 
			
		||||
                        $("#errmsg").html(`<i class="red circle times icon"></i> ` + data.error);
 | 
			
		||||
                        $("#errmsg").show();
 | 
			
		||||
                    }else{
 | 
			
		||||
                        $("#errmsg").hide();
 | 
			
		||||
                        $("#countdown").hide();
 | 
			
		||||
                        $("#succmsg").show();
 | 
			
		||||
                        setTimeout(function(){
 | 
			
		||||
                            window.location.href = "/";
 | 
			
		||||
                        }, 3000);
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
                error: function(){
 | 
			
		||||
                    console.error(error);
 | 
			
		||||
                }
 | 
			
		||||
            })
 | 
			
		||||
            .fail(function(error) {
 | 
			
		||||
                // Handle error response
 | 
			
		||||
                console.error(error);
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -26,4 +26,18 @@ Object.defineProperty(String.prototype, 'capitalize', {
 | 
			
		||||
        return this.charAt(0).toUpperCase() + this.slice(1);
 | 
			
		||||
    },
 | 
			
		||||
    enumerable: false
 | 
			
		||||
});
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
//Add a new function to jquery for ajax override with csrf token injected
 | 
			
		||||
$.cjax = function(payload){
 | 
			
		||||
    let requireTokenMethod = ["POST", "PUT", "DELETE"];;
 | 
			
		||||
    if (requireTokenMethod.includes(payload.method) || requireTokenMethod.includes(payload.type)){
 | 
			
		||||
        //csrf token is required
 | 
			
		||||
        let csrfToken = document.getElementsByTagName("meta")["zoraxy.csrf.Token"].getAttribute("content");
 | 
			
		||||
        payload.headers = {
 | 
			
		||||
            "X-CSRF-Token": csrfToken,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $.ajax(payload);
 | 
			
		||||
}
 | 
			
		||||
@@ -3,9 +3,11 @@
 | 
			
		||||
  <head>
 | 
			
		||||
      <!-- Notes: This should be open in its original path-->
 | 
			
		||||
      <meta charset="utf-8">
 | 
			
		||||
      <meta name="zoraxy.csrf.Token" content="{{.csrfToken}}">
 | 
			
		||||
      <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>
 | 
			
		||||
      <script src="../script/utils.js"></script>
 | 
			
		||||
      <style>
 | 
			
		||||
        #refreshAccessRuleListBtn{
 | 
			
		||||
            position: absolute;
 | 
			
		||||
@@ -94,7 +96,7 @@
 | 
			
		||||
        $("#accessRuleForm input[name='accessRuleName']").val("");
 | 
			
		||||
        $("#accessRuleForm textarea[name='description']").val("");
 | 
			
		||||
 | 
			
		||||
        $.ajax({
 | 
			
		||||
        $.cjax({
 | 
			
		||||
            url: "/api/access/create",
 | 
			
		||||
            method: "POST",
 | 
			
		||||
            data: {
 | 
			
		||||
@@ -162,7 +164,7 @@
 | 
			
		||||
        console.log('Access Rule Name:', accessRuleName);
 | 
			
		||||
        console.log('Description:', description);
 | 
			
		||||
 | 
			
		||||
        $.ajax({
 | 
			
		||||
        $.cjax({
 | 
			
		||||
            url: "/api/access/update",
 | 
			
		||||
            method: "POST",
 | 
			
		||||
            data: {
 | 
			
		||||
@@ -238,7 +240,7 @@
 | 
			
		||||
        }
 | 
			
		||||
        let accessRuleName = $("#modifyRuleInfo input[name='accessRuleName']").val();
 | 
			
		||||
        if (confirm("Confirm removing access rule " + accessRuleName + "?")){
 | 
			
		||||
            $.ajax({
 | 
			
		||||
            $.cjax({
 | 
			
		||||
                url: "/api/access/remove",
 | 
			
		||||
                data: {
 | 
			
		||||
                    "id": accessRuleUUID
 | 
			
		||||
 
 | 
			
		||||
@@ -3,9 +3,11 @@
 | 
			
		||||
  <head>
 | 
			
		||||
      <!-- Notes: This should be open in its original path-->
 | 
			
		||||
      <meta charset="utf-8">
 | 
			
		||||
      <meta name="zoraxy.csrf.Token" content="{{.csrfToken}}">
 | 
			
		||||
      <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>
 | 
			
		||||
      <script src="../script/utils.js"></script>
 | 
			
		||||
      <style>
 | 
			
		||||
        .disabled.table{
 | 
			
		||||
          opacity: 0.5;
 | 
			
		||||
@@ -234,8 +236,9 @@
 | 
			
		||||
    initRenewerConfigFromFile();
 | 
			
		||||
 | 
			
		||||
    function saveEmailToConfig(btn){
 | 
			
		||||
      $.ajax({
 | 
			
		||||
      $.cjax({
 | 
			
		||||
        url: "/api/acme/autoRenew/email",
 | 
			
		||||
        method: "POST",
 | 
			
		||||
        data: {set: $("#caRegisterEmail").val()},
 | 
			
		||||
        success: function(data){
 | 
			
		||||
          if (data.error != undefined){
 | 
			
		||||
@@ -256,27 +259,29 @@
 | 
			
		||||
 | 
			
		||||
    function toggleAutoRenew(){
 | 
			
		||||
      var enabled = $("#enableCertAutoRenew").parent().checkbox("is checked");
 | 
			
		||||
      $.post("/api/acme/autoRenew/enable?enable=" + enabled, function(data){
 | 
			
		||||
        if (data.error){
 | 
			
		||||
          parent.msgbox(data.error, false, 5000);
 | 
			
		||||
          if (enabled){
 | 
			
		||||
            enableTrigerOnChangeEvent = false;
 | 
			
		||||
            $("#enableCertAutoRenew").parent().checkbox("set unchecked");
 | 
			
		||||
            enableTrigerOnChangeEvent = true;
 | 
			
		||||
          }
 | 
			
		||||
          if (parent && parent.setACMEEnableStates){
 | 
			
		||||
            parent.setACMEEnableStates(!enabled);
 | 
			
		||||
          }
 | 
			
		||||
        }else{
 | 
			
		||||
          $("#enableToggleSucc").stop().finish().fadeIn("fast").delay(3000).fadeOut("fast");
 | 
			
		||||
          if (parent && parent.setACMEEnableStates){
 | 
			
		||||
            parent.setACMEEnableStates(enabled);
 | 
			
		||||
      $.cjax({
 | 
			
		||||
        url: "/api/acme/autoRenew/enable",
 | 
			
		||||
        method: "POST",
 | 
			
		||||
        data: {"enable": enabled},
 | 
			
		||||
        success: function(data){
 | 
			
		||||
          if (data.error){
 | 
			
		||||
            parent.msgbox(data.error, false, 5000);
 | 
			
		||||
            if (enabled){
 | 
			
		||||
              enableTrigerOnChangeEvent = false;
 | 
			
		||||
              $("#enableCertAutoRenew").parent().checkbox("set unchecked");
 | 
			
		||||
              enableTrigerOnChangeEvent = true;
 | 
			
		||||
            }
 | 
			
		||||
            if (parent && parent.setACMEEnableStates){
 | 
			
		||||
               parent.setACMEEnableStates(!enabled);
 | 
			
		||||
            }
 | 
			
		||||
          }else{
 | 
			
		||||
            $("#enableToggleSucc").stop().finish().fadeIn("fast").delay(3000).fadeOut("fast");
 | 
			
		||||
            if (parent && parent.setACMEEnableStates){
 | 
			
		||||
              parent.setACMEEnableStates(enabled);
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      
 | 
			
		||||
      
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Render the domains table that exists in this zoraxy host
 | 
			
		||||
@@ -630,7 +635,7 @@
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      $.ajax({
 | 
			
		||||
      $.cjax({
 | 
			
		||||
        url: "/api/acme/autoRenew/setDNS",
 | 
			
		||||
        method: "POST",
 | 
			
		||||
        data: {
 | 
			
		||||
@@ -843,8 +848,9 @@
 | 
			
		||||
    function saveAutoRenewPolicy(){
 | 
			
		||||
      let autoRenewAll = $("#renewAllSupported").parent().checkbox("is checked");
 | 
			
		||||
      if (autoRenewAll == true){
 | 
			
		||||
        $.ajax({
 | 
			
		||||
        $.cjax({
 | 
			
		||||
          url: "/api/acme/autoRenew/setDomains",
 | 
			
		||||
          method: "POST",
 | 
			
		||||
          data: {opr: "setAuto"},
 | 
			
		||||
          success: function(data){
 | 
			
		||||
            parent.msgbox("Renew policy rule updated")
 | 
			
		||||
@@ -856,8 +862,9 @@
 | 
			
		||||
          checkedNames.push($(this).attr('name'));
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        $.ajax({
 | 
			
		||||
        $.cjax({
 | 
			
		||||
          url: "/api/acme/autoRenew/setDomains",
 | 
			
		||||
          method: "POST",
 | 
			
		||||
          data: {opr: "setSelected", domains: JSON.stringify(checkedNames)},
 | 
			
		||||
          success: function(data){
 | 
			
		||||
            parent.msgbox("Renew policy rule updated")
 | 
			
		||||
 
 | 
			
		||||
@@ -3,9 +3,11 @@
 | 
			
		||||
    <head>
 | 
			
		||||
        <!-- Notes: This should be open in its original path-->
 | 
			
		||||
        <meta charset="utf-8">
 | 
			
		||||
        <meta name="zoraxy.csrf.Token" content="{{.csrfToken}}">
 | 
			
		||||
        <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>
 | 
			
		||||
        <script src="../script/utils.js"></script>
 | 
			
		||||
    </head>
 | 
			
		||||
    <body>
 | 
			
		||||
        <br>
 | 
			
		||||
@@ -46,7 +48,7 @@
 | 
			
		||||
 | 
			
		||||
            function handleResetStats(){
 | 
			
		||||
                if (confirm("Confirm remove statistics from " + startDate + " to " + endDate +"?")){
 | 
			
		||||
                    $.ajax({
 | 
			
		||||
                    $.cjax({
 | 
			
		||||
                        url: "/api/analytic/resetRange?start=" + startDate + "&end=" + endDate,
 | 
			
		||||
                        method: "DELETE",
 | 
			
		||||
                        success: function(data){
 | 
			
		||||
 
 | 
			
		||||
@@ -3,9 +3,11 @@
 | 
			
		||||
    <head>
 | 
			
		||||
        <!-- Notes: This should be open in its original path-->
 | 
			
		||||
        <meta charset="utf-8">
 | 
			
		||||
        <meta name="zoraxy.csrf.Token" content="{{.csrfToken}}">
 | 
			
		||||
        <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>
 | 
			
		||||
        <script src="../script/utils.js"></script>
 | 
			
		||||
    </head>
 | 
			
		||||
    <body>
 | 
			
		||||
        <br>
 | 
			
		||||
@@ -71,7 +73,7 @@
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function initAliasNames(){
 | 
			
		||||
                $.ajax({
 | 
			
		||||
                $.cjax({
 | 
			
		||||
                    url: "/api/proxy/detail",
 | 
			
		||||
                    method: "POST",
 | 
			
		||||
                    data: {
 | 
			
		||||
@@ -130,7 +132,7 @@
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function saveCurrentAliasList(callback=undefined){
 | 
			
		||||
                $.ajax({
 | 
			
		||||
                $.cjax({
 | 
			
		||||
                    url: "/api/proxy/setAlias",
 | 
			
		||||
                    method: "POST",
 | 
			
		||||
                    data:{
 | 
			
		||||
 
 | 
			
		||||
@@ -3,9 +3,11 @@
 | 
			
		||||
    <head>
 | 
			
		||||
        <!-- Notes: This should be open in its original path-->
 | 
			
		||||
        <meta charset="utf-8">
 | 
			
		||||
        <meta name="zoraxy.csrf.Token" content="{{.csrfToken}}">
 | 
			
		||||
        <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>
 | 
			
		||||
        <script src="../script/utils.js"></script>
 | 
			
		||||
    </head>
 | 
			
		||||
    <body>
 | 
			
		||||
        <br>
 | 
			
		||||
@@ -174,7 +176,7 @@
 | 
			
		||||
                    parent.msgbox("Matching prefix cannot be empty!", false, 5000);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                $.ajax({
 | 
			
		||||
                $.cjax({
 | 
			
		||||
                    url: "/api/proxy/auth/exceptions/add",
 | 
			
		||||
                    data:{
 | 
			
		||||
                        ep: editingEndpoint.ep,
 | 
			
		||||
@@ -195,7 +197,7 @@
 | 
			
		||||
 | 
			
		||||
            function removeExceptionPath(object){
 | 
			
		||||
                let matchingPrefix = $(object).attr("prefix");
 | 
			
		||||
                $.ajax({
 | 
			
		||||
                $.cjax({
 | 
			
		||||
                    url: "/api/proxy/auth/exceptions/delete",
 | 
			
		||||
                    data:{
 | 
			
		||||
                        ep: editingEndpoint.ep,
 | 
			
		||||
@@ -290,7 +292,7 @@
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function saveCredentials(){
 | 
			
		||||
                $.ajax({
 | 
			
		||||
                $.cjax({
 | 
			
		||||
                    url: "/api/proxy/updateCredentials",
 | 
			
		||||
                    method: "POST",
 | 
			
		||||
                    data: {
 | 
			
		||||
 
 | 
			
		||||
@@ -3,9 +3,11 @@
 | 
			
		||||
    <head>
 | 
			
		||||
        <!-- Notes: This should be open in its original path-->
 | 
			
		||||
        <meta charset="utf-8">
 | 
			
		||||
        <meta name="zoraxy.csrf.Token" content="{{.csrfToken}}">
 | 
			
		||||
        <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>
 | 
			
		||||
        <script src="../script/utils.js"></script>
 | 
			
		||||
    </head>
 | 
			
		||||
    <body>
 | 
			
		||||
        <br>
 | 
			
		||||
@@ -70,10 +72,10 @@
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            document.getElementById("uploadForm").addEventListener("submit", function(event) {
 | 
			
		||||
            $("#uploadForm").submit(function(event) {
 | 
			
		||||
                event.preventDefault(); // Prevent the form from submitting normally
 | 
			
		||||
 | 
			
		||||
                var fileInput = document.getElementById("fileInput");
 | 
			
		||||
                var fileInput = $("#fileInput")[0];
 | 
			
		||||
                var file = fileInput.files[0];
 | 
			
		||||
                if (!file) {
 | 
			
		||||
                    alert("Missing file.");
 | 
			
		||||
@@ -83,18 +85,19 @@
 | 
			
		||||
                var formData = new FormData();
 | 
			
		||||
                formData.append("file", file);
 | 
			
		||||
 | 
			
		||||
                var xhr = new XMLHttpRequest();
 | 
			
		||||
                xhr.open("POST", "/api/conf/import", true);
 | 
			
		||||
                xhr.onreadystatechange = function() {
 | 
			
		||||
                    if (xhr.readyState === XMLHttpRequest.DONE) {
 | 
			
		||||
                        if (xhr.status === 200) {
 | 
			
		||||
                            parent.msgbox("Config restore succeed. Restart Zoraxy to apply changes.")
 | 
			
		||||
                        } else {
 | 
			
		||||
                            parent.msgbox("Restore failed: " + xhr.responseText, false, 5000);
 | 
			
		||||
                        }
 | 
			
		||||
                $.cjax({
 | 
			
		||||
                    url: "/api/conf/import",
 | 
			
		||||
                    type: "POST",
 | 
			
		||||
                    data: formData,
 | 
			
		||||
                    processData: false, // Not to process the data
 | 
			
		||||
                    contentType: false, // Not to set contentType
 | 
			
		||||
                    success: function(response) {
 | 
			
		||||
                        parent.msgbox("Config restore succeed. Restart Zoraxy to apply changes.");
 | 
			
		||||
                    },
 | 
			
		||||
                    error: function(xhr) {
 | 
			
		||||
                        parent.msgbox("Restore failed: " + xhr.responseText, false, 5000);
 | 
			
		||||
                    }
 | 
			
		||||
                };
 | 
			
		||||
                xhr.send(formData);
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
        </script>
 | 
			
		||||
    </body>
 | 
			
		||||
 
 | 
			
		||||
@@ -3,9 +3,11 @@
 | 
			
		||||
    <head>
 | 
			
		||||
        <!-- Notes: This should be open in its original path-->
 | 
			
		||||
        <meta charset="utf-8">
 | 
			
		||||
        <meta name="zoraxy.csrf.Token" content="{{.csrfToken}}">
 | 
			
		||||
        <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>
 | 
			
		||||
        <script src="../script/utils.js"></script>
 | 
			
		||||
        <style>
 | 
			
		||||
            .ui.tabular.menu .item.narrowpadding{
 | 
			
		||||
                padding: 0.6em !important;
 | 
			
		||||
@@ -92,9 +94,6 @@
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="content">
 | 
			
		||||
                            <br>
 | 
			
		||||
                            <div class="ui yellow message">
 | 
			
		||||
                                <p><i class="exclamation triangle icon"></i>Settings in this section are for advanced users. Invalid settings might cause werid, unexpected behavior.</p>
 | 
			
		||||
                            </div>
 | 
			
		||||
                            <div class="ui container">
 | 
			
		||||
                                <h4>Overwrite Host Header</h4>
 | 
			
		||||
                                <p>Manual override the automatic "Host" header rewrite logic. Leave empty for automatic.</p>
 | 
			
		||||
@@ -112,7 +111,9 @@
 | 
			
		||||
                                    <label>Remove Hop-by-hop Header<br>
 | 
			
		||||
                                    <small>This should be ON by default</small></label>
 | 
			
		||||
                                </div>
 | 
			
		||||
                                <div class="ui divider"></div>
 | 
			
		||||
                                <div class="ui yellow message">
 | 
			
		||||
                                    <p><i class="exclamation triangle icon"></i>Settings in this section are for advanced users. Invalid settings might cause werid, unexpected behavior.</p>
 | 
			
		||||
                                </div>
 | 
			
		||||
                            </div>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
@@ -247,8 +248,9 @@
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                $.ajax({
 | 
			
		||||
                $.cjax({
 | 
			
		||||
                    url: "/api/proxy/header/add",
 | 
			
		||||
                    method: "POST",
 | 
			
		||||
                    data: {
 | 
			
		||||
                        "type": getHeaderEditMode(),
 | 
			
		||||
                        "domain": editingEndpoint.ep,
 | 
			
		||||
@@ -279,10 +281,10 @@
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function deleteCustomHeader(name){
 | 
			
		||||
                $.ajax({
 | 
			
		||||
                $.cjax({
 | 
			
		||||
                    url: "/api/proxy/header/remove",
 | 
			
		||||
                    method: "POST",
 | 
			
		||||
                    data: {
 | 
			
		||||
                        //"type": editingEndpoint.ept,
 | 
			
		||||
                        "domain": editingEndpoint.ep,
 | 
			
		||||
                        "name": name,
 | 
			
		||||
                    },
 | 
			
		||||
@@ -299,6 +301,7 @@
 | 
			
		||||
                $("#headerTable").html(`<tr><td colspan="3"><i class="ui loading spinner icon"></i> Loading</td></tr>`);
 | 
			
		||||
                $.ajax({
 | 
			
		||||
                    url: "/api/proxy/header/list",
 | 
			
		||||
                    method: "GET",
 | 
			
		||||
                    data: {
 | 
			
		||||
                        "type": editingEndpoint.ept,
 | 
			
		||||
                        "domain": editingEndpoint.ep,
 | 
			
		||||
@@ -307,7 +310,6 @@
 | 
			
		||||
                        if (data.error != undefined){
 | 
			
		||||
                            alert(data.error);
 | 
			
		||||
                        }else{
 | 
			
		||||
                           
 | 
			
		||||
                            $("#headerTable").html("");
 | 
			
		||||
                            data.forEach(header => {
 | 
			
		||||
                                let editModeIcon = header.IsRemove?`<i class="ui red times circle icon"></i>`:`<i class="ui green add circle icon"></i>`;
 | 
			
		||||
@@ -351,7 +353,7 @@
 | 
			
		||||
                    /* Bind events to toggles */
 | 
			
		||||
                    $("#enableHSTS").on("change", function(){
 | 
			
		||||
                        let HSTSEnabled = $("#enableHSTS")[0].checked;
 | 
			
		||||
                        $.ajax({
 | 
			
		||||
                        $.cjax({
 | 
			
		||||
                            url: "/api/proxy/header/handleHSTS",
 | 
			
		||||
                            method: "POST",
 | 
			
		||||
                            data: {
 | 
			
		||||
@@ -426,7 +428,7 @@
 | 
			
		||||
                            $("#permissionPolicyEditor").addClass("disabled");
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        $.ajax({
 | 
			
		||||
                        $.cjax({
 | 
			
		||||
                            url: "/api/proxy/header/handlePermissionPolicy",
 | 
			
		||||
                            method: "POST",
 | 
			
		||||
                            data: {
 | 
			
		||||
@@ -532,7 +534,7 @@
 | 
			
		||||
                let permissionPolicy = generatePermissionPolicyObject();
 | 
			
		||||
                let domain = editingEndpoint.ep;
 | 
			
		||||
 | 
			
		||||
                $.ajax({
 | 
			
		||||
                $.cjax({
 | 
			
		||||
                    url: "/api/proxy/header/handlePermissionPolicy",
 | 
			
		||||
                    method: "PUT",
 | 
			
		||||
                    data: {
 | 
			
		||||
@@ -576,7 +578,7 @@
 | 
			
		||||
 | 
			
		||||
            function updateManualHostOverwriteVal(callback=undefined){
 | 
			
		||||
                let newHostname = $("#manualHostOverwrite").val().trim();
 | 
			
		||||
                $.ajax({
 | 
			
		||||
                $.cjax({
 | 
			
		||||
                    url: "/api/proxy/header/handleHostOverwrite",
 | 
			
		||||
                    method: "POST",
 | 
			
		||||
                    data: {
 | 
			
		||||
@@ -615,7 +617,7 @@
 | 
			
		||||
                        //Bind event to the checkbox
 | 
			
		||||
                        $("#removeHopByHop").on("change", function(evt){
 | 
			
		||||
                            let isChecked = $(this)[0].checked;
 | 
			
		||||
                            $.ajax({
 | 
			
		||||
                            $.cjax({
 | 
			
		||||
                                url: "/api/proxy/header/handleHopByHop",
 | 
			
		||||
                                method: "POST",
 | 
			
		||||
                                data: {
 | 
			
		||||
 
 | 
			
		||||
@@ -3,9 +3,11 @@
 | 
			
		||||
    <head>
 | 
			
		||||
        <!-- Notes: This should be open in its original path-->
 | 
			
		||||
        <meta charset="utf-8">
 | 
			
		||||
        <meta name="zoraxy.csrf.Token" content="{{.csrfToken}}">
 | 
			
		||||
        <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>
 | 
			
		||||
        <script src="../script/utils.js"></script>
 | 
			
		||||
        <style>
 | 
			
		||||
            .accessRule{
 | 
			
		||||
                cursor: pointer;
 | 
			
		||||
@@ -124,12 +126,10 @@
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            initAccessRuleList(function(){
 | 
			
		||||
                $.ajax({
 | 
			
		||||
                $.cjax({
 | 
			
		||||
                    url: "/api/proxy/detail",
 | 
			
		||||
                    method: "POST",
 | 
			
		||||
                    data: {"type":"host", "epname": editingEndpoint.ep },
 | 
			
		||||
@@ -160,7 +160,7 @@
 | 
			
		||||
            function applyChangeAndClose(){
 | 
			
		||||
                let newAccessRuleID = $(".accessRule.active").attr("ruleid");
 | 
			
		||||
                let targetEndpoint = editingEndpoint.ep;
 | 
			
		||||
                $.ajax({
 | 
			
		||||
                $.cjax({
 | 
			
		||||
                    url: "/api/access/attach",
 | 
			
		||||
                    method: "POST",
 | 
			
		||||
                    data: {
 | 
			
		||||
 
 | 
			
		||||
@@ -2,9 +2,11 @@
 | 
			
		||||
<html>
 | 
			
		||||
    <head>
 | 
			
		||||
        <meta charset="utf-8">
 | 
			
		||||
        <meta name="zoraxy.csrf.Token" content="{{.csrfToken}}">
 | 
			
		||||
        <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>
 | 
			
		||||
        <script src="../script/utils.js"></script>
 | 
			
		||||
        <style>
 | 
			
		||||
            body{
 | 
			
		||||
                height: 100%;
 | 
			
		||||
 
 | 
			
		||||
@@ -3,9 +3,11 @@
 | 
			
		||||
    <head>
 | 
			
		||||
        <!-- Notes: This should be open in its original path-->
 | 
			
		||||
        <meta charset="utf-8">
 | 
			
		||||
        <meta name="zoraxy.csrf.Token" content="{{.csrfToken}}">
 | 
			
		||||
        <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>
 | 
			
		||||
        <script src="../script/utils.js"></script>
 | 
			
		||||
        <style>
 | 
			
		||||
            .upstreamActions{
 | 
			
		||||
                position: absolute;
 | 
			
		||||
@@ -133,7 +135,7 @@
 | 
			
		||||
            function initOriginList(){
 | 
			
		||||
                $.ajax({
 | 
			
		||||
                    url: "/api/proxy/upstream/list",
 | 
			
		||||
                    method: "POST",
 | 
			
		||||
                    method: "GET",
 | 
			
		||||
                    data: {
 | 
			
		||||
                        "type":"host",
 | 
			
		||||
                        "ep": editingEndpoint.ep
 | 
			
		||||
@@ -284,8 +286,9 @@
 | 
			
		||||
                }else{
 | 
			
		||||
                    //URL does not contains https or http protocol tag
 | 
			
		||||
                    //sniff header
 | 
			
		||||
                    $.ajax({
 | 
			
		||||
                    $.cjax({
 | 
			
		||||
                            url: "/api/proxy/tlscheck",
 | 
			
		||||
                            method: "POST",
 | 
			
		||||
                            data: {url: targetDomain},
 | 
			
		||||
                            success: function(data){
 | 
			
		||||
                                if (data.error != undefined){
 | 
			
		||||
@@ -313,7 +316,7 @@
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                $.ajax({
 | 
			
		||||
                $.cjax({
 | 
			
		||||
                    url: "/api/proxy/upstream/add",
 | 
			
		||||
                    method: "POST",
 | 
			
		||||
                    data:{
 | 
			
		||||
@@ -365,7 +368,7 @@
 | 
			
		||||
                let newConfig = getUpstreamSettingFromDOM(targetDOM);
 | 
			
		||||
                let isActive = $(targetDOM).find(".enableState")[0].checked;
 | 
			
		||||
                console.log(newConfig);
 | 
			
		||||
                $.ajax({
 | 
			
		||||
                $.cjax({
 | 
			
		||||
                    url: "/api/proxy/upstream/update",
 | 
			
		||||
                    method: "POST",
 | 
			
		||||
                    data: {
 | 
			
		||||
@@ -418,8 +421,9 @@
 | 
			
		||||
                }else{
 | 
			
		||||
                    //URL does not contains https or http protocol tag
 | 
			
		||||
                    //sniff header
 | 
			
		||||
                    $.ajax({
 | 
			
		||||
                    $.cjax({
 | 
			
		||||
                            url: "/api/proxy/tlscheck",
 | 
			
		||||
                            method: "POST",
 | 
			
		||||
                            data: {url: targetDomain},
 | 
			
		||||
                            success: function(data){
 | 
			
		||||
                                if (data.error != undefined){
 | 
			
		||||
@@ -460,7 +464,7 @@
 | 
			
		||||
 | 
			
		||||
            //Set a weight of a upstream
 | 
			
		||||
            function setUpstreamWeight(originIP, newWeight){
 | 
			
		||||
                $.ajax({
 | 
			
		||||
                $.cjax({
 | 
			
		||||
                    url: "/api/proxy/upstream/setPriority",
 | 
			
		||||
                    method: "POST",
 | 
			
		||||
                    data: {
 | 
			
		||||
@@ -489,7 +493,7 @@
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                //Remove the upstream
 | 
			
		||||
                $.ajax({
 | 
			
		||||
                $.cjax({
 | 
			
		||||
                    url: "/api/proxy/upstream/remove",
 | 
			
		||||
                    method: "POST",
 | 
			
		||||
                    data: {
 | 
			
		||||
 
 | 
			
		||||
@@ -2,12 +2,14 @@
 | 
			
		||||
    <head>
 | 
			
		||||
        <title>File Manager</title>
 | 
			
		||||
        <meta charset="UTF-8">
 | 
			
		||||
        <meta name="zoraxy.csrf.Token" content="{{.csrfToken}}">
 | 
			
		||||
        <meta name="viewport" content="width=device-width, initial-scale=1.0 user-scalable=no">
 | 
			
		||||
        <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
 | 
			
		||||
        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.4.1/semantic.min.css" />
 | 
			
		||||
        <script src="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.4.1/semantic.min.js"></script>
 | 
			
		||||
        <script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.6.0/jszip.min.js"></script>
 | 
			
		||||
        <link rel="stylesheet" href="fs.css">
 | 
			
		||||
        <script src="../script/utils.js"></script>
 | 
			
		||||
        <script>
 | 
			
		||||
         
 | 
			
		||||
        </script>
 | 
			
		||||
@@ -199,7 +201,7 @@
 | 
			
		||||
                    let counter = $(".fileObject.selected").length;
 | 
			
		||||
                    $(".fileObject.selected").each(function(){
 | 
			
		||||
                        let thisFilepath = $(this).attr("filepath");
 | 
			
		||||
                        $.ajax({
 | 
			
		||||
                        $.cjax({
 | 
			
		||||
                            url: "/api/fs/del?target=" + thisFilepath,
 | 
			
		||||
                            method: "POST",
 | 
			
		||||
                            success: function(data){
 | 
			
		||||
@@ -241,22 +243,9 @@
 | 
			
		||||
                    let filename = $(this).attr("filename");
 | 
			
		||||
                    if (ftype != "folder"){
 | 
			
		||||
                        let ext = filepath.split(".").pop();
 | 
			
		||||
                        if (isCodeFiles(ext)){
 | 
			
		||||
                            editableCodeFiles.push({
 | 
			
		||||
                                "filename": filename,
 | 
			
		||||
                                "filepath": filepath
 | 
			
		||||
                            });
 | 
			
		||||
                        }else{
 | 
			
		||||
                            openthis($(this), evt);
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        openthis($(this), evt);
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                if (editableCodeFiles.length > 0){
 | 
			
		||||
                    let hash = encodeURIComponent(JSON.stringify(editableCodeFiles))
 | 
			
		||||
                    window.open("notepad/index.html#" + hash);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function refresh(){
 | 
			
		||||
@@ -571,12 +560,19 @@
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                $.post("/api/fs/newFolder?path=" + currentPath + folderName, function(data){
 | 
			
		||||
                    if (data.error != undefined){
 | 
			
		||||
                        msgbox(data.error, false);
 | 
			
		||||
                    }else{
 | 
			
		||||
                        msgbox("Folder Created");
 | 
			
		||||
                        refresh();
 | 
			
		||||
                $.cjax({
 | 
			
		||||
                    url: "/api/fs/newFolder",
 | 
			
		||||
                    method: "POST",
 | 
			
		||||
                    data: {
 | 
			
		||||
                        "path": currentPath + folderName,
 | 
			
		||||
                    },
 | 
			
		||||
                    success: function(data){
 | 
			
		||||
                        if (data.error != undefined){
 | 
			
		||||
                            msgbox(data.error, false);
 | 
			
		||||
                        }else{
 | 
			
		||||
                            msgbox("Folder Created");
 | 
			
		||||
                            refresh();
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
@@ -597,8 +593,12 @@
 | 
			
		||||
                    if (newName && newName != oldName) {
 | 
			
		||||
                        // User entered a new name, perform renaming logic here
 | 
			
		||||
                        console.log(oldPath, currentPath + newName);
 | 
			
		||||
                        $.ajax({
 | 
			
		||||
                            url: "/api/fs/move?srcpath=" + oldPath + "&destpath=" + currentPath + newName,
 | 
			
		||||
                        $.cjax({
 | 
			
		||||
                            url: "/api/fs/move",
 | 
			
		||||
                            data: {
 | 
			
		||||
                                "srcpath": oldPath,
 | 
			
		||||
                                "destpath": currentPath + newName
 | 
			
		||||
                            },
 | 
			
		||||
                            method: "POST",
 | 
			
		||||
                            success: function(data){
 | 
			
		||||
                                if (data.error != undefined){
 | 
			
		||||
@@ -826,6 +826,7 @@
 | 
			
		||||
                ajax.addEventListener("error", errorHandler, false);
 | 
			
		||||
                ajax.addEventListener("abort", abortHandler, false);
 | 
			
		||||
                ajax.open("POST", "/api/fs/upload?dir=" + dir);
 | 
			
		||||
                ajax.setRequestHeader("X-CSRF-Token", document.getElementsByTagName("meta")["zoraxy.csrf.Token"].getAttribute("content"));
 | 
			
		||||
                ajax.send(formdata);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -914,8 +915,12 @@
 | 
			
		||||
                        let filename = fileToPaste.filename;
 | 
			
		||||
                        let filepath = fileToPaste.filepath;
 | 
			
		||||
 | 
			
		||||
                        $.ajax({
 | 
			
		||||
                            url: "/api/fs/move?srcpath=" + filepath + "&destpath=" + currentPath + filename,
 | 
			
		||||
                        $.cjax({
 | 
			
		||||
                            url: "/api/fs/move",
 | 
			
		||||
                            data:{
 | 
			
		||||
                                "srcpath": filepath,
 | 
			
		||||
                                "destpath": currentPath + filename,
 | 
			
		||||
                            },
 | 
			
		||||
                            method: "POST",
 | 
			
		||||
                            success: function(data){
 | 
			
		||||
                                if (data.error != undefined){
 | 
			
		||||
@@ -939,7 +944,7 @@
 | 
			
		||||
            function copyFirstItemInQueueUntilAllCopied(){
 | 
			
		||||
                let file = copyPendingFiles.shift();
 | 
			
		||||
                let startingDir = currentPath;
 | 
			
		||||
                $.ajax({
 | 
			
		||||
                $.cjax({
 | 
			
		||||
                    url: "/api/fs/copy",
 | 
			
		||||
                    method: "POST",
 | 
			
		||||
                    data: {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<html>
 | 
			
		||||
    <head>
 | 
			
		||||
        <meta name="zoraxy.csrf.Token" content="{{.csrfToken}}">
 | 
			
		||||
        <meta name="apple-mobile-web-app-capable" content="yes" />
 | 
			
		||||
        <meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1"/>
 | 
			
		||||
        <meta charset="UTF-8">
 | 
			
		||||
@@ -13,6 +14,7 @@
 | 
			
		||||
        <script src="../script/semantic/semantic.min.js"></script>
 | 
			
		||||
        <script src="../script/tablesort.js"></script>
 | 
			
		||||
        <link rel="stylesheet" href="../main.css">
 | 
			
		||||
        <script src="../script/utils.js"></script>
 | 
			
		||||
        <style>
 | 
			
		||||
            .offlinehost{
 | 
			
		||||
                display: none;
 | 
			
		||||
@@ -86,9 +88,14 @@
 | 
			
		||||
                        <div class="ui basic segment" align="center">
 | 
			
		||||
                            <i class="loading spinner icon"></i> Scanning
 | 
			
		||||
                        </div>`);
 | 
			
		||||
                    $.post("/api/tools/ipscan", {start: start, end: end}, function(data) {
 | 
			
		||||
                        displayResults(data);
 | 
			
		||||
                        $(".scanbtn").removeClass("disabled");
 | 
			
		||||
                    $.cjax({
 | 
			
		||||
                        url: "/api/tools/ipscan",
 | 
			
		||||
                        data: {start: start, end: end},
 | 
			
		||||
                        method: "POST",
 | 
			
		||||
                        success: function(data){
 | 
			
		||||
                            displayResults(data);
 | 
			
		||||
                            $(".scanbtn").removeClass("disabled");
 | 
			
		||||
                        }
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
        
 | 
			
		||||
@@ -109,9 +116,14 @@
 | 
			
		||||
                        <div class="ui basic segment" align="center">
 | 
			
		||||
                            <i class="loading spinner icon"></i> Scanning
 | 
			
		||||
                        </div>`);
 | 
			
		||||
                    $.post("/api/tools/ipscan", {cidr: cidr}, function(data) {
 | 
			
		||||
                        displayResults(data);
 | 
			
		||||
                        $(".scanbtn").removeClass("disabled");
 | 
			
		||||
                    $.cjax({
 | 
			
		||||
                        url: "/api/tools/ipscan",
 | 
			
		||||
                        method: "POST",
 | 
			
		||||
                        data: {cidr: cidr},
 | 
			
		||||
                        success: function(data) {
 | 
			
		||||
                            displayResults(data);
 | 
			
		||||
                            $(".scanbtn").removeClass("disabled");
 | 
			
		||||
                        }
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<html>
 | 
			
		||||
    <head>
 | 
			
		||||
        <meta name="zoraxy.csrf.Token" content="{{.csrfToken}}">
 | 
			
		||||
        <meta name="apple-mobile-web-app-capable" content="yes" />
 | 
			
		||||
        <meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1"/>
 | 
			
		||||
        <meta charset="UTF-8">
 | 
			
		||||
@@ -13,6 +14,7 @@
 | 
			
		||||
        <script src="../script/semantic/semantic.min.js"></script>
 | 
			
		||||
        <script src="../script/tablesort.js"></script>
 | 
			
		||||
        <link rel="stylesheet" href="../main.css">
 | 
			
		||||
        <script src="../script/utils.js"></script>
 | 
			
		||||
        <style>
 | 
			
		||||
            body{
 | 
			
		||||
                overflow-x: auto;
 | 
			
		||||
@@ -54,7 +56,7 @@
 | 
			
		||||
                var domain = $("#domain").val();
 | 
			
		||||
                $("#discover").addClass("loading").addClass('disabled');
 | 
			
		||||
                setCountdown();
 | 
			
		||||
                $.ajax({
 | 
			
		||||
                $.cjax({
 | 
			
		||||
                    type: "POST",
 | 
			
		||||
                    url: "/api/mdns/discover",
 | 
			
		||||
                    data: { domain: domain },
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<html>
 | 
			
		||||
    <head>
 | 
			
		||||
        <meta name="zoraxy.csrf.Token" content="{{.csrfToken}}">
 | 
			
		||||
        <meta name="apple-mobile-web-app-capable" content="yes" />
 | 
			
		||||
        <meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1"/>
 | 
			
		||||
        <meta charset="UTF-8">
 | 
			
		||||
@@ -13,6 +14,7 @@
 | 
			
		||||
        <script src="../script/semantic/semantic.min.js"></script>
 | 
			
		||||
        <script src="../script/tablesort.js"></script>
 | 
			
		||||
        <link rel="stylesheet" href="../main.css">
 | 
			
		||||
        <script src="../script/utils.js"></script>
 | 
			
		||||
        <style>
 | 
			
		||||
            #loadingUI{
 | 
			
		||||
                width: 100%;
 | 
			
		||||
@@ -153,7 +155,7 @@
 | 
			
		||||
            //Try to ask the server side to create a ssh proxy object
 | 
			
		||||
            function createSSHProxy(remoteAddr, remotePort, username){
 | 
			
		||||
                //Request to create a ssh session instance
 | 
			
		||||
                $.ajax({
 | 
			
		||||
                $.cjax({
 | 
			
		||||
                    url: "/api/tools/webssh",
 | 
			
		||||
                    data: {ipaddr: remoteAddr, port: remotePort, username:username},
 | 
			
		||||
                    method: "POST",
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user