diff --git a/src/api.go b/src/api.go index 0d2f7c9..82dbfac 100644 --- a/src/api.go +++ b/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) diff --git a/src/cert.go b/src/cert.go index e4b285a..ce9f83b 100644 --- a/src/cert.go +++ b/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) } } diff --git a/src/go.mod b/src/go.mod index d665e55..57b4f13 100644 --- a/src/go.mod +++ b/src/go.mod @@ -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 diff --git a/src/go.sum b/src/go.sum index 5aaab55..0e2546d 100644 --- a/src/go.sum +++ b/src/go.sum @@ -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= diff --git a/src/main.go b/src/main.go index fc933a5..f3138bf 100644 --- a/src/main.go +++ b/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) diff --git a/src/mod/acme/autorenew.go b/src/mod/acme/autorenew.go index a4134fc..73637cd 100644 --- a/src/mod/acme/autorenew.go +++ b/src/mod/acme/autorenew.go @@ -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) { diff --git a/src/mod/auth/router.go b/src/mod/auth/router.go index 8fca7b4..85f9dae 100644 --- a/src/mod/auth/router.go +++ b/src/mod/auth/router.go @@ -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 diff --git a/src/mod/dockerux/docker.go b/src/mod/dockerux/docker.go index 90aa0c7..9a3d5ad 100644 --- a/src/mod/dockerux/docker.go +++ b/src/mod/dockerux/docker.go @@ -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)) diff --git a/src/mod/webserv/filemanager/filemanager.go b/src/mod/webserv/filemanager/filemanager.go index 8847553..21b6bea 100644 --- a/src/mod/webserv/filemanager/filemanager.go +++ b/src/mod/webserv/filemanager/filemanager.go @@ -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 diff --git a/src/reverseproxy.go b/src/reverseproxy.go index cea0c50..369b7f1 100644 --- a/src/reverseproxy.go +++ b/src/reverseproxy.go @@ -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 diff --git a/src/router.go b/src/router.go index 3b64237..e324f00 100644 --- a/src/router.go +++ b/src/router.go @@ -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)) +} diff --git a/src/start.go b/src/start.go index 44a971e..cadac93 100644 --- a/src/start.go +++ b/src/start.go @@ -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) diff --git a/src/upstreams.go b/src/upstreams.go index 3ab2eab..16df940 100644 --- a/src/upstreams.go +++ b/src/upstreams.go @@ -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 diff --git a/src/web/components/access.html b/src/web/components/access.html index bb06e1d..5fd99cd 100644 --- a/src/web/components/access.html +++ b/src/web/components/access.html @@ -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}, diff --git a/src/web/components/cert.html b/src/web/components/cert.html index 99fe7de..784203f 100644 --- a/src/web/components/cert.html +++ b/src/web/components/cert.html @@ -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", diff --git a/src/web/components/gan.html b/src/web/components/gan.html index 833b401..12402fa 100644 --- a/src/web/components/gan.html +++ b/src/web/components/gan.html @@ -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", diff --git a/src/web/components/gandetails.html b/src/web/components/gandetails.html index 857033c..663109f 100644 --- a/src/web/components/gandetails.html +++ b/src/web/components/gandetails.html @@ -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: { diff --git a/src/web/components/httprp.html b/src/web/components/httprp.html index ba5466f..5eebc2c 100644 --- a/src/web/components/httprp.html +++ b/src/web/components/httprp.html @@ -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, diff --git a/src/web/components/networktools.html b/src/web/components/networktools.html index cc4ea71..dca3347 100644 --- a/src/web/components/networktools.html +++ b/src/web/components/networktools.html @@ -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: { diff --git a/src/web/components/redirection.html b/src/web/components/redirection.html index c34af14..40bbeb4 100644 --- a/src/web/components/redirection.html +++ b/src/web/components/redirection.html @@ -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){ diff --git a/src/web/components/rproot.html b/src/web/components/rproot.html index 56af8de..b1c3883 100644 --- a/src/web/components/rproot.html +++ b/src/web/components/rproot.html @@ -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", diff --git a/src/web/components/rules.html b/src/web/components/rules.html index d175a98..2873660 100644 --- a/src/web/components/rules.html +++ b/src/web/components/rules.html @@ -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"){ diff --git a/src/web/components/status.html b/src/web/components/status.html index 3d187bb..0e0d19b 100644 --- a/src/web/components/status.html +++ b/src/web/components/status.html @@ -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){ diff --git a/src/web/components/streamprox.html b/src/web/components/streamprox.html index 76be84f..64a9cdf 100644 --- a/src/web/components/streamprox.html +++ b/src/web/components/streamprox.html @@ -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}, diff --git a/src/web/components/utils.html b/src/web/components/utils.html index a99d6f0..138ccbe 100644 --- a/src/web/components/utils.html +++ b/src/web/components/utils.html @@ -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, diff --git a/src/web/components/vdir.html b/src/web/components/vdir.html index 1749c13..8d8d7b2 100644 --- a/src/web/components/vdir.html +++ b/src/web/components/vdir.html @@ -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: { diff --git a/src/web/components/webserv.html b/src/web/components/webserv.html index b67ff6a..ccc073e 100644 --- a/src/web/components/webserv.html +++ b/src/web/components/webserv.html @@ -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}, diff --git a/src/web/index.html b/src/web/index.html index a0cddf5..1ac34d7 100644 --- a/src/web/index.html +++ b/src/web/index.html @@ -5,6 +5,7 @@ +