- 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:
Toby Chui
2024-07-24 21:58:44 +08:00
parent b1c5bc2963
commit f595da92a1
45 changed files with 535 additions and 307 deletions

View File

@ -22,11 +22,11 @@ import (
var requireAuth = true var requireAuth = true
func initAPIs() { func initAPIs(targetMux *http.ServeMux) {
authRouter := auth.NewManagedHTTPRouter(auth.RouterOption{ authRouter := auth.NewManagedHTTPRouter(auth.RouterOption{
AuthAgent: authAgent, AuthAgent: authAgent,
RequireAuth: requireAuth, RequireAuth: requireAuth,
TargetMux: targetMux,
DeniedHandler: func(w http.ResponseWriter, r *http.Request) { DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
http.Error(w, "401 - Unauthorized", http.StatusUnauthorized) http.Error(w, "401 - Unauthorized", http.StatusUnauthorized)
}, },
@ -37,12 +37,12 @@ func initAPIs() {
if development { if development {
fs = http.FileServer(http.Dir("web/")) 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) advHandler := FSHandler(fs)
http.Handle("/", advHandler) targetMux.Handle("/", advHandler)
//Authentication APIs //Authentication APIs
registerAuthAPIs(requireAuth) registerAuthAPIs(requireAuth, targetMux)
//Reverse proxy //Reverse proxy
authRouter.HandleFunc("/api/proxy/enable", ReverseProxyHandleOnOff) authRouter.HandleFunc("/api/proxy/enable", ReverseProxyHandleOnOff)
@ -187,8 +187,8 @@ func initAPIs() {
authRouter.HandleFunc("/api/tools/fwdproxy/port", forwardProxy.HandlePort) authRouter.HandleFunc("/api/tools/fwdproxy/port", forwardProxy.HandlePort)
//Account Reset //Account Reset
http.HandleFunc("/api/account/reset", HandleAdminAccountResetEmail) targetMux.HandleFunc("/api/account/reset", HandleAdminAccountResetEmail)
http.HandleFunc("/api/account/new", HandleNewPasswordSetup) targetMux.HandleFunc("/api/account/new", HandleNewPasswordSetup)
//ACME & Auto Renewer //ACME & Auto Renewer
authRouter.HandleFunc("/api/acme/listExpiredDomains", acmeHandler.HandleGetExpiredDomains) authRouter.HandleFunc("/api/acme/listExpiredDomains", acmeHandler.HandleGetExpiredDomains)
@ -228,7 +228,7 @@ func initAPIs() {
authRouter.HandleFunc("/api/docker/containers", DockerUXOptimizer.HandleDockerContainersList) authRouter.HandleFunc("/api/docker/containers", DockerUXOptimizer.HandleDockerContainersList)
//Others //Others
http.HandleFunc("/api/info/x", HandleZoraxyInfo) targetMux.HandleFunc("/api/info/x", HandleZoraxyInfo)
authRouter.HandleFunc("/api/info/geoip", HandleGeoIpLookup) authRouter.HandleFunc("/api/info/geoip", HandleGeoIpLookup)
authRouter.HandleFunc("/api/conf/export", ExportConfigAsZip) authRouter.HandleFunc("/api/conf/export", ExportConfigAsZip)
authRouter.HandleFunc("/api/conf/import", ImportConfigFromZip) authRouter.HandleFunc("/api/conf/import", ImportConfigFromZip)
@ -243,18 +243,18 @@ func initAPIs() {
} }
// Function to renders Auth related APIs // Function to renders Auth related APIs
func registerAuthAPIs(requireAuth bool) { func registerAuthAPIs(requireAuth bool, targetMux *http.ServeMux) {
//Auth APIs //Auth APIs
http.HandleFunc("/api/auth/login", authAgent.HandleLogin) targetMux.HandleFunc("/api/auth/login", authAgent.HandleLogin)
http.HandleFunc("/api/auth/logout", authAgent.HandleLogout) targetMux.HandleFunc("/api/auth/logout", authAgent.HandleLogout)
http.HandleFunc("/api/auth/checkLogin", func(w http.ResponseWriter, r *http.Request) { targetMux.HandleFunc("/api/auth/checkLogin", func(w http.ResponseWriter, r *http.Request) {
if requireAuth { if requireAuth {
authAgent.CheckLogin(w, r) authAgent.CheckLogin(w, r)
} else { } else {
utils.SendJSONResponse(w, "true") 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) username, err := authAgent.GetUserName(w, r)
if err != nil { if err != nil {
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
@ -264,12 +264,12 @@ func registerAuthAPIs(requireAuth bool) {
js, _ := json.Marshal(username) js, _ := json.Marshal(username)
utils.SendJSONResponse(w, string(js)) 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() uc := authAgent.GetUserCounts()
js, _ := json.Marshal(uc) js, _ := json.Marshal(uc)
utils.SendJSONResponse(w, string(js)) 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 { if authAgent.GetUserCounts() == 0 {
//Allow register root admin //Allow register root admin
authAgent.HandleRegisterWithoutEmail(w, r, func(username, reserved string) { authAgent.HandleRegisterWithoutEmail(w, r, func(username, reserved string) {
@ -280,7 +280,7 @@ func registerAuthAPIs(requireAuth bool) {
utils.SendErrorResponse(w, "Root management account already exists") 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) username, err := authAgent.GetUserName(w, r)
if err != nil { if err != nil {
http.Error(w, "401 - Unauthorized", http.StatusUnauthorized) http.Error(w, "401 - Unauthorized", http.StatusUnauthorized)

View File

@ -182,27 +182,28 @@ func handleToggleTLSProxy(w http.ResponseWriter, r *http.Request) {
sysdb.Read("settings", "usetls", &currentTlsSetting) sysdb.Read("settings", "usetls", &currentTlsSetting)
} }
newState, err := utils.PostPara(r, "set") if r.Method == http.MethodGet {
if err != nil { //Get the current status
//No setting. Get the current status
js, _ := json.Marshal(currentTlsSetting) js, _ := json.Marshal(currentTlsSetting)
utils.SendJSONResponse(w, string(js)) utils.SendJSONResponse(w, string(js))
} else { } else if r.Method == http.MethodPost {
if newState == "true" { 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) sysdb.Write("settings", "usetls", true)
SystemWideLogger.Println("Enabling TLS mode on reverse proxy") SystemWideLogger.Println("Enabling TLS mode on reverse proxy")
dynamicProxyRouter.UpdateTLSSetting(true) dynamicProxyRouter.UpdateTLSSetting(true)
} else if newState == "false" { } else {
sysdb.Write("settings", "usetls", false) sysdb.Write("settings", "usetls", false)
SystemWideLogger.Println("Disabling TLS mode on reverse proxy") SystemWideLogger.Println("Disabling TLS mode on reverse proxy")
dynamicProxyRouter.UpdateTLSSetting(false) dynamicProxyRouter.UpdateTLSSetting(false)
} else {
utils.SendErrorResponse(w, "invalid state given. Only support true or false")
return
} }
utils.SendOK(w) utils.SendOK(w)
} else {
http.Error(w, "405 - Method not allowed", http.StatusMethodNotAllowed)
} }
} }

View File

@ -95,6 +95,7 @@ require (
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
github.com/googleapis/gax-go/v2 v2.12.2 // indirect github.com/googleapis/gax-go/v2 v2.12.2 // indirect
github.com/gophercloud/gophercloud v1.0.0 // 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/css v1.0.1 // indirect
github.com/gorilla/securecookie v1.1.2 // indirect github.com/gorilla/securecookie v1.1.2 // indirect
github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect

View File

@ -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 h1:9nTGx0jizmHxDobe4mck89FyQHVyA3CaXLIUSGJjP9k=
github.com/gophercloud/gophercloud v1.0.0/go.mod h1:Q8fZtyi5zZxPS/j9aj3sSxtvj41AdQMDwyo1myduD5c= 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/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 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=
github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0= 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= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=

View File

@ -12,6 +12,7 @@ import (
"time" "time"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/gorilla/csrf"
"imuslab.com/zoraxy/mod/access" "imuslab.com/zoraxy/mod/access"
"imuslab.com/zoraxy/mod/acme" "imuslab.com/zoraxy/mod/acme"
"imuslab.com/zoraxy/mod/auth" "imuslab.com/zoraxy/mod/auth"
@ -60,7 +61,7 @@ var (
name = "Zoraxy" name = "Zoraxy"
version = "3.1.0" version = "3.1.0"
nodeUUID = "generic" //System uuid, in uuidv4 format 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() bootTime = time.Now().Unix()
/* /*
@ -72,10 +73,12 @@ var (
/* /*
Handler Modules Handler Modules
*/ */
sysdb *database.Database //System database sysdb *database.Database //System database
authAgent *auth.AuthAgent //Authentication agent authAgent *auth.AuthAgent //Authentication agent
tlsCertManager *tlscert.Manager //TLS / SSL management tlsCertManager *tlscert.Manager //TLS / SSL management
redirectTable *redirection.RuleTable //Handle special redirection rule sets 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 pathRuleHandler *pathrule.Handler //Handle specific path blocking or custom headers
geodbStore *geodb.Store //GeoIP database, for resolving IP into country code geodbStore *geodb.Store //GeoIP database, for resolving IP into country code
@ -176,12 +179,16 @@ func main() {
} }
nodeUUID = string(uuidBytes) nodeUUID = string(uuidBytes)
//Create a new webmin mux and csrf middleware layer
webminPanelMux := http.NewServeMux()
csrfMiddleware := csrf.Protect([]byte(nodeUUID))
//Startup all modules //Startup all modules
startupSequence() startupSequence()
//Initiate management interface APIs //Initiate management interface APIs
requireAuth = !(*noauth) requireAuth = !(*noauth)
initAPIs() initAPIs(webminPanelMux)
//Start the reverse proxy server in go routine //Start the reverse proxy server in go routine
go func() { go func() {
@ -194,7 +201,7 @@ func main() {
finalSequence() finalSequence()
SystemWideLogger.Println("Zoraxy started. Visit control panel at http://localhost" + *webUIPort) 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 { if err != nil {
log.Fatal(err) log.Fatal(err)

View File

@ -140,7 +140,7 @@ func (a *AutoRenewer) StopAutoRenewTicker() {
// opr = setSelected -> Enter a list of file names (or matching rules) for auto renew // opr = setSelected -> Enter a list of file names (or matching rules) for auto renew
// opr = setAuto -> Set to use auto detect certificates and renew // opr = setAuto -> Set to use auto detect certificates and renew
func (a *AutoRenewer) HandleSetAutoRenewDomains(w http.ResponseWriter, r *http.Request) { 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 { if err != nil {
utils.SendErrorResponse(w, "Operation not set") utils.SendErrorResponse(w, "Operation not set")
return return
@ -170,6 +170,8 @@ func (a *AutoRenewer) HandleSetAutoRenewDomains(w http.ResponseWriter, r *http.R
a.RenewerConfig.RenewAll = true a.RenewerConfig.RenewAll = true
a.saveRenewConfigToFile() a.saveRenewConfigToFile()
utils.SendOK(w) 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)) utils.SendJSONResponse(w, string(js))
} }
// HandleAutoRenewEnable get and set the auto renew enable state
func (a *AutoRenewer) HandleAutoRenewEnable(w http.ResponseWriter, r *http.Request) { func (a *AutoRenewer) HandleAutoRenewEnable(w http.ResponseWriter, r *http.Request) {
val, err := utils.PostPara(r, "enable") if r.Method == http.MethodGet {
if err != nil {
js, _ := json.Marshal(a.RenewerConfig.Enabled) js, _ := json.Marshal(a.RenewerConfig.Enabled)
utils.SendJSONResponse(w, string(js)) utils.SendJSONResponse(w, string(js))
} else { } else if r.Method == http.MethodPost {
if val == "true" { 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 //Check if the email is not empty
if a.RenewerConfig.Email == "" { if a.RenewerConfig.Email == "" {
utils.SendErrorResponse(w, "Email is not set") utils.SendErrorResponse(w, "Email is not set")
return return
} }
a.RenewerConfig.Enabled = true a.RenewerConfig.Enabled = true
a.saveRenewConfigToFile() a.saveRenewConfigToFile()
log.Println("[ACME] ACME auto renew enabled") 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") log.Println("[ACME] ACME auto renew disabled")
a.StopAutoRenewTicker() a.StopAutoRenewTicker()
} }
} else {
http.Error(w, "405 - Method not allowed", http.StatusMethodNotAllowed)
} }
} }
func (a *AutoRenewer) HandleACMEEmail(w http.ResponseWriter, r *http.Request) { func (a *AutoRenewer) HandleACMEEmail(w http.ResponseWriter, r *http.Request) {

View File

@ -10,7 +10,7 @@ type RouterOption struct {
AuthAgent *AuthAgent AuthAgent *AuthAgent
RequireAuth bool //This router require authentication RequireAuth bool //This router require authentication
DeniedHandler func(http.ResponseWriter, *http.Request) //Things to do when request is rejected DeniedHandler func(http.ResponseWriter, *http.Request) //Things to do when request is rejected
TargetMux *http.ServeMux
} }
type RouterDef struct { type RouterDef struct {
@ -35,17 +35,31 @@ func (router *RouterDef) HandleFunc(endpoint string, handler func(http.ResponseW
authAgent := router.option.AuthAgent authAgent := router.option.AuthAgent
//OK. Register handler //OK. Register handler
http.HandleFunc(endpoint, func(w http.ResponseWriter, r *http.Request) { if router.option.TargetMux == nil {
//Check authentication of the user http.HandleFunc(endpoint, func(w http.ResponseWriter, r *http.Request) {
if router.option.RequireAuth { //Check authentication of the user
authAgent.HandleCheckAuth(w, r, func(w http.ResponseWriter, r *http.Request) { if router.option.RequireAuth {
authAgent.HandleCheckAuth(w, r, func(w http.ResponseWriter, r *http.Request) {
handler(w, r)
})
} else {
handler(w, r) 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 router.endpoints[endpoint] = handler

View File

@ -3,8 +3,6 @@
package dockerux package dockerux
/* Windows docker optimizer*/
import ( import (
"context" "context"
"encoding/json" "encoding/json"
@ -16,7 +14,6 @@ import (
"imuslab.com/zoraxy/mod/utils" "imuslab.com/zoraxy/mod/utils"
) )
// Windows build not support docker
func (d *UXOptimizer) HandleDockerAvailable(w http.ResponseWriter, r *http.Request) { func (d *UXOptimizer) HandleDockerAvailable(w http.ResponseWriter, r *http.Request) {
js, _ := json.Marshal(d.RunninInDocker) js, _ := json.Marshal(d.RunninInDocker)
utils.SendJSONResponse(w, string(js)) utils.SendJSONResponse(w, string(js))

View File

@ -173,7 +173,7 @@ func (fm *FileManager) HandleDownload(w http.ResponseWriter, r *http.Request) {
// HandleNewFolder creates a new folder in the specified directory // HandleNewFolder creates a new folder in the specified directory
func (fm *FileManager) HandleNewFolder(w http.ResponseWriter, r *http.Request) { func (fm *FileManager) HandleNewFolder(w http.ResponseWriter, r *http.Request) {
// Parse the directory name from the request // Parse the directory name from the request
dirName, err := utils.GetPara(r, "path") dirName, err := utils.PostPara(r, "path")
if err != nil { if err != nil {
utils.SendErrorResponse(w, "invalid directory name") utils.SendErrorResponse(w, "invalid directory name")
return 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) { func (fm *FileManager) HandleFileMove(w http.ResponseWriter, r *http.Request) {
// Parse the source and destination paths from the 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 { if err != nil {
utils.SendErrorResponse(w, "invalid source path") utils.SendErrorResponse(w, "invalid source path")
return return
} }
destPath, err := utils.GetPara(r, "destpath") destPath, err := utils.PostPara(r, "destpath")
if err != nil { if err != nil {
utils.SendErrorResponse(w, "invalid destination path") utils.SendErrorResponse(w, "invalid destination path")
return return

View File

@ -572,7 +572,7 @@ func ReverseProxyHandleAlias(w http.ResponseWriter, r *http.Request) {
} }
func DeleteProxyEndpoint(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 { if err != nil {
utils.SendErrorResponse(w, "Invalid ep given") utils.SendErrorResponse(w, "Invalid ep given")
return return
@ -941,18 +941,22 @@ func ReverseProxyList(w http.ResponseWriter, r *http.Request) {
// Handle port 80 incoming traffics // Handle port 80 incoming traffics
func HandleUpdatePort80Listener(w http.ResponseWriter, r *http.Request) { func HandleUpdatePort80Listener(w http.ResponseWriter, r *http.Request) {
enabled, err := utils.GetPara(r, "enable") if r.Method == http.MethodGet {
if err != nil {
//Load the current status //Load the current status
currentEnabled := false currentEnabled := false
err = sysdb.Read("settings", "listenP80", &currentEnabled) err := sysdb.Read("settings", "listenP80", &currentEnabled)
if err != nil { if err != nil {
utils.SendErrorResponse(w, err.Error()) utils.SendErrorResponse(w, err.Error())
return return
} }
js, _ := json.Marshal(currentEnabled) js, _ := json.Marshal(currentEnabled)
utils.SendJSONResponse(w, string(js)) 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" { if enabled == "true" {
sysdb.Write("settings", "listenP80", true) sysdb.Write("settings", "listenP80", true)
SystemWideLogger.Println("Enabling port 80 listener") 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.SendErrorResponse(w, "invalid mode given: "+enabled)
} }
utils.SendOK(w) utils.SendOK(w)
} else {
http.Error(w, "405 - Method not allowed", http.StatusMethodNotAllowed)
} }
} }
// Handle https redirect // Handle https redirect
func HandleUpdateHttpsRedirect(w http.ResponseWriter, r *http.Request) { func HandleUpdateHttpsRedirect(w http.ResponseWriter, r *http.Request) {
useRedirect, err := utils.GetPara(r, "set") if r.Method == http.MethodGet {
if err != nil {
currentRedirectToHttps := false currentRedirectToHttps := false
//Load the current status //Load the current status
err = sysdb.Read("settings", "redirect", &currentRedirectToHttps) err := sysdb.Read("settings", "redirect", &currentRedirectToHttps)
if err != nil { if err != nil {
utils.SendErrorResponse(w, err.Error()) utils.SendErrorResponse(w, err.Error())
return return
} }
js, _ := json.Marshal(currentRedirectToHttps) js, _ := json.Marshal(currentRedirectToHttps)
utils.SendJSONResponse(w, string(js)) 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 { if dynamicProxyRouter.Option.Port == 80 {
utils.SendErrorResponse(w, "This option is not available when listening on port 80") utils.SendErrorResponse(w, "This option is not available when listening on port 80")
return return
} }
if useRedirect == "true" { if useRedirect {
sysdb.Write("settings", "redirect", true) sysdb.Write("settings", "redirect", true)
SystemWideLogger.Println("Updating force HTTPS redirection to true") SystemWideLogger.Println("Updating force HTTPS redirection to true")
dynamicProxyRouter.UpdateHttpToHttpsRedirectSetting(true) dynamicProxyRouter.UpdateHttpToHttpsRedirectSetting(true)
} else if useRedirect == "false" { } else {
sysdb.Write("settings", "redirect", false) sysdb.Write("settings", "redirect", false)
SystemWideLogger.Println("Updating force HTTPS redirection to false") SystemWideLogger.Println("Updating force HTTPS redirection to false")
dynamicProxyRouter.UpdateHttpToHttpsRedirectSetting(false) dynamicProxyRouter.UpdateHttpToHttpsRedirectSetting(false)
} }
utils.SendOK(w) 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 //List all the custom header defined in this proxy rule
func HandleCustomHeaderList(w http.ResponseWriter, r *http.Request) { func HandleCustomHeaderList(w http.ResponseWriter, r *http.Request) {
epType, err := utils.PostPara(r, "type") epType, err := utils.GetPara(r, "type")
if err != nil { if err != nil {
utils.SendErrorResponse(w, "endpoint type not defined") utils.SendErrorResponse(w, "endpoint type not defined")
return return
} }
domain, err := utils.PostPara(r, "domain") domain, err := utils.GetPara(r, "domain")
if err != nil { if err != nil {
utils.SendErrorResponse(w, "domain or matching rule not defined") utils.SendErrorResponse(w, "domain or matching rule not defined")
return return

View File

@ -4,9 +4,11 @@ import (
"fmt" "fmt"
"net/http" "net/http"
"net/url" "net/url"
"os"
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/gorilla/csrf"
"imuslab.com/zoraxy/mod/sshprox" "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 // 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 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) handler.ServeHTTP(w, r)
return return
} }
// check authentication // Check authentication
if !authAgent.CheckAuth(r) && requireAuth { if !authAgent.CheckAuth(r) && requireAuth {
http.Redirect(w, r, ppf("/login.html"), http.StatusTemporaryRedirect) http.Redirect(w, r, ppf("/login.html"), http.StatusTemporaryRedirect)
return return
@ -77,6 +83,10 @@ func FSHandler(handler http.Handler) http.Handler {
} }
//Authenticated //Authenticated
if isHTMLFilePath(r.URL.Path) {
handleInjectHTML(w, r, r.URL.Path)
return
}
handler.ServeHTTP(w, r) handler.ServeHTTP(w, r)
}) })
} }
@ -88,3 +98,53 @@ func ppf(relativeFilepath string) string {
} }
return relativeFilepath 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))
}

View File

@ -292,7 +292,7 @@ func startupSequence() {
/* Docker UX Optimizer */ /* Docker UX Optimizer */
if runtime.GOOS == "windows" && *runningInDocker { 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) DockerUXOptimizer = dockerux.NewDockerOptimizer(*runningInDocker, SystemWideLogger)

View File

@ -19,7 +19,7 @@ import (
// List upstreams from a endpoint // List upstreams from a endpoint
func ReverseProxyUpstreamList(w http.ResponseWriter, r *http.Request) { func ReverseProxyUpstreamList(w http.ResponseWriter, r *http.Request) {
endpoint, err := utils.PostPara(r, "ep") endpoint, err := utils.GetPara(r, "ep")
if err != nil { if err != nil {
utils.SendErrorResponse(w, "endpoint not defined") utils.SendErrorResponse(w, "endpoint not defined")
return return

View File

@ -1000,7 +1000,7 @@
*/ */
function enableBlacklist() { function enableBlacklist() {
var isChecked = $('#enableBlacklist').is(':checked'); var isChecked = $('#enableBlacklist').is(':checked');
$.ajax({ $.cjax({
type: 'POST', type: 'POST',
url: '/api/blacklist/enable', url: '/api/blacklist/enable',
data: { enable: isChecked, id: currentEditingAccessRule}, data: { enable: isChecked, id: currentEditingAccessRule},
@ -1028,9 +1028,10 @@
let counter = 0; let counter = 0;
for(var i = 0; i < ccs.length; i++){ for(var i = 0; i < ccs.length; i++){
let thisCountryCode = ccs[i]; let thisCountryCode = ccs[i];
$.ajax({ $.cjax({
type: "POST", type: "POST",
url: "/api/blacklist/country/add", url: "/api/blacklist/country/add",
method: "POST",
data: { cc: thisCountryCode, id: currentEditingAccessRule}, data: { cc: thisCountryCode, id: currentEditingAccessRule},
success: function(response) { success: function(response) {
if (response.error != undefined){ if (response.error != undefined){
@ -1066,7 +1067,7 @@
function removeFromBannedList(countryCode){ function removeFromBannedList(countryCode){
countryCode = countryCode.toLowerCase(); countryCode = countryCode.toLowerCase();
let countryName = getCountryName(countryCode); let countryName = getCountryName(countryCode);
$.ajax({ $.cjax({
url: "/api/blacklist/country/remove", url: "/api/blacklist/country/remove",
method: "POST", method: "POST",
data: { cc: countryCode, id: currentEditingAccessRule}, data: { cc: countryCode, id: currentEditingAccessRule},
@ -1097,7 +1098,7 @@
} }
} }
$.ajax({ $.cjax({
url: "/api/blacklist/ip/add", url: "/api/blacklist/ip/add",
type: "POST", type: "POST",
data: {ip: targetIp.toLowerCase(), id: currentEditingAccessRule}, data: {ip: targetIp.toLowerCase(), id: currentEditingAccessRule},
@ -1119,7 +1120,7 @@
function removeIpBlacklist(ipaddr){ function removeIpBlacklist(ipaddr){
if (confirm("Confirm remove blacklist for " + ipaddr + " ?")){ if (confirm("Confirm remove blacklist for " + ipaddr + " ?")){
$.ajax({ $.cjax({
url: "/api/blacklist/ip/remove", url: "/api/blacklist/ip/remove",
type: "POST", type: "POST",
data: {ip: ipaddr.toLowerCase(), id: currentEditingAccessRule}, data: {ip: ipaddr.toLowerCase(), id: currentEditingAccessRule},
@ -1143,7 +1144,7 @@
*/ */
function enableWhitelist() { function enableWhitelist() {
var isChecked = $('#enableWhitelist').is(':checked'); var isChecked = $('#enableWhitelist').is(':checked');
$.ajax({ $.cjax({
type: 'POST', type: 'POST',
url: '/api/whitelist/enable', url: '/api/whitelist/enable',
data: { enable: isChecked , id: currentEditingAccessRule}, data: { enable: isChecked , id: currentEditingAccessRule},
@ -1165,7 +1166,7 @@
let counter = 0; let counter = 0;
for(var i = 0; i < ccs.length; i++){ for(var i = 0; i < ccs.length; i++){
let thisCountryCode = ccs[i]; let thisCountryCode = ccs[i];
$.ajax({ $.cjax({
type: "POST", type: "POST",
url: "/api/whitelist/country/add", url: "/api/whitelist/country/add",
data: { cc: thisCountryCode , id: currentEditingAccessRule}, data: { cc: thisCountryCode , id: currentEditingAccessRule},
@ -1199,7 +1200,7 @@
function removeFromWhiteList(countryCode){ function removeFromWhiteList(countryCode){
if (confirm("Confirm removing " + getCountryName(countryCode) + " from whitelist?")){ if (confirm("Confirm removing " + getCountryName(countryCode) + " from whitelist?")){
countryCode = countryCode.toLowerCase(); countryCode = countryCode.toLowerCase();
$.ajax({ $.cjax({
url: "/api/whitelist/country/remove", url: "/api/whitelist/country/remove",
method: "POST", method: "POST",
data: { cc: countryCode , id: currentEditingAccessRule}, data: { cc: countryCode , id: currentEditingAccessRule},
@ -1230,7 +1231,7 @@
} }
} }
$.ajax({ $.cjax({
url: "/api/whitelist/ip/add", url: "/api/whitelist/ip/add",
type: "POST", type: "POST",
data: {ip: targetIp.toLowerCase(), "comment": remarks, id: currentEditingAccessRule}, data: {ip: targetIp.toLowerCase(), "comment": remarks, id: currentEditingAccessRule},
@ -1253,7 +1254,7 @@
function removeIpWhitelist(ipaddr){ function removeIpWhitelist(ipaddr){
if (confirm("Confirm remove whitelist for " + ipaddr + " ?")){ if (confirm("Confirm remove whitelist for " + ipaddr + " ?")){
$.ajax({ $.cjax({
url: "/api/whitelist/ip/remove", url: "/api/whitelist/ip/remove",
type: "POST", type: "POST",
data: {ip: ipaddr.toLowerCase(), id: currentEditingAccessRule}, data: {ip: ipaddr.toLowerCase(), id: currentEditingAccessRule},

View File

@ -257,7 +257,7 @@
//Delete the certificate by its domain //Delete the certificate by its domain
function deleteCertificate(domain){ function deleteCertificate(domain){
if (confirm("Confirm delete certificate for " + domain + " ?")){ if (confirm("Confirm delete certificate for " + domain + " ?")){
$.ajax({ $.cjax({
url: "/api/cert/delete", url: "/api/cert/delete",
method: "POST", method: "POST",
data: {domain: domain}, data: {domain: domain},
@ -316,7 +316,7 @@
return; return;
} }
$.ajax({ $.cjax({
url: "/api/acme/autoRenew/email", url: "/api/acme/autoRenew/email",
method: "POST", method: "POST",
data: {"set": newDefaultEmail}, data: {"set": newDefaultEmail},
@ -330,7 +330,7 @@
} }
}); });
$.ajax({ $.cjax({
url: "/api/acme/autoRenew/ca", url: "/api/acme/autoRenew/ca",
data: {"set": newDefaultCA}, data: {"set": newDefaultCA},
method: "POST", method: "POST",

View File

@ -87,7 +87,7 @@
} }
function addGANet() { function addGANet() {
$.ajax({ $.cjax({
url: "/api/gan/network/add", url: "/api/gan/network/add",
type: "POST", type: "POST",
dataType: "json", dataType: "json",
@ -191,7 +191,7 @@
//Remove the given GANet //Remove the given GANet
function removeGANet(netid){ function removeGANet(netid){
if (confirm("Confirm remove Network " + netid + " PERMANENTLY ?")) if (confirm("Confirm remove Network " + netid + " PERMANENTLY ?"))
$.ajax({ $.cjax({
url: "/api/gan/network/remove", url: "/api/gan/network/remove",
type: "POST", type: "POST",
dataType: "json", dataType: "json",

View File

@ -214,7 +214,7 @@
//Get CIDR from selected range group //Get CIDR from selected range group
var cidr = $(".iprange.active").attr("cidr"); var cidr = $(".iprange.active").attr("cidr");
$.ajax({ $.cjax({
url: "/api/gan/network/setRange", url: "/api/gan/network/setRange",
metohd: "POST", metohd: "POST",
data:{ data:{
@ -240,7 +240,7 @@
if (object != undefined){ if (object != undefined){
$(object).addClass("loading"); $(object).addClass("loading");
} }
$.ajax({ $.cjax({
url: "/api/gan/network/name", url: "/api/gan/network/name",
method: "POST", method: "POST",
data: { data: {
@ -287,7 +287,7 @@
//Handle delete IP from memeber //Handle delete IP from memeber
function deleteIpFromMemeber(memberid, ip){ function deleteIpFromMemeber(memberid, ip){
$.ajax({ $.cjax({
url: "/api/gan/members/ip", url: "/api/gan/members/ip",
metohd: "POST", metohd: "POST",
data: { data: {
@ -334,7 +334,7 @@
return return
} }
$.ajax({ $.cjax({
url: "/api/gan/members/ip", url: "/api/gan/members/ip",
metohd: "POST", metohd: "POST",
data: { data: {
@ -461,7 +461,7 @@
$(".memberName").each(function(){ $(".memberName").each(function(){
let addr = $(this).attr("addr"); let addr = $(this).attr("addr");
let targetDOM = $(this); let targetDOM = $(this);
$.ajax({ $.cjax({
url: "/api/gan/members/name", url: "/api/gan/members/name",
method: "POST", method: "POST",
data: { data: {
@ -487,7 +487,7 @@
let newname = prompt("Enter a easy manageable name for " + targetMemberAddr, ""); let newname = prompt("Enter a easy manageable name for " + targetMemberAddr, "");
if (newname != null && newname.trim() != "") { if (newname != null && newname.trim() != "") {
$.ajax({ $.cjax({
url: "/api/gan/members/name", url: "/api/gan/members/name",
method: "POST", method: "POST",
data: { data: {
@ -553,7 +553,7 @@
function handleMemberAuth(object){ function handleMemberAuth(object){
let targetMemberAddr = $(object).attr("addr"); let targetMemberAddr = $(object).attr("addr");
let isAuthed = object.checked; let isAuthed = object.checked;
$.ajax({ $.cjax({
url: "/api/gan/members/authorize", url: "/api/gan/members/authorize",
method: "POST", method: "POST",
data: { data: {
@ -580,7 +580,7 @@
function handleMemberDelete(addr){ function handleMemberDelete(addr){
if (confirm("Confirm delete member " + addr + " ?")){ if (confirm("Confirm delete member " + addr + " ?")){
$.ajax({ $.cjax({
url: "/api/gan/members/delete", url: "/api/gan/members/delete",
method: "POST", method: "POST",
data: { data: {
@ -605,7 +605,7 @@
$(".addControllerToNetworkBtn").addClass("disabled"); $(".addControllerToNetworkBtn").addClass("disabled");
$(".addControllerToNetworkBtn").addClass("loading"); $(".addControllerToNetworkBtn").addClass("loading");
$.ajax({ $.cjax({
url: "/api/gan/network/join", url: "/api/gan/network/join",
method: "POST", method: "POST",
data: { data: {
@ -630,7 +630,7 @@
$(".removeControllerFromNetworkBtn").addClass("disabled"); $(".removeControllerFromNetworkBtn").addClass("disabled");
$(".removeControllerFromNetworkBtn").addClass("loading"); $(".removeControllerFromNetworkBtn").addClass("loading");
$.ajax({ $.cjax({
url: "/api/gan/network/leave", url: "/api/gan/network/leave",
method: "POST", method: "POST",
data: { data: {

View File

@ -400,7 +400,7 @@
let rateLimit = $(row).find(".RateLimit").val(); let rateLimit = $(row).find(".RateLimit").val();
let bypassGlobalTLS = $(row).find(".BypassGlobalTLS")[0].checked; let bypassGlobalTLS = $(row).find(".BypassGlobalTLS")[0].checked;
$.ajax({ $.cjax({
url: "/api/proxy/edit", url: "/api/proxy/edit",
method: "POST", method: "POST",
data: { 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 */ /* button events */
function editBasicAuthCredentials(uuid){ function editBasicAuthCredentials(uuid){
@ -474,7 +496,7 @@
function handleProxyRuleToggle(object){ function handleProxyRuleToggle(object){
let endpointUUID = $(object).attr("eptuuid"); let endpointUUID = $(object).attr("eptuuid");
let isChecked = object.checked; let isChecked = object.checked;
$.ajax({ $.cjax({
url: "/api/proxy/toggle", url: "/api/proxy/toggle",
data: { data: {
"ep": endpointUUID, "ep": endpointUUID,

View File

@ -339,7 +339,7 @@ function setWoLAddress() {
$("#wol_mac").parent().removeClass("error"); $("#wol_mac").parent().removeClass("error");
} }
$.ajax({ $.cjax({
url: wake_on_lan_API, url: wake_on_lan_API,
type: "POST", type: "POST",
data: { data: {
@ -363,7 +363,7 @@ function setWoLAddress() {
function delWoLAddr(mac, name) { function delWoLAddr(mac, name) {
if (confirm(`Confirm remove WoL record for ${name} (${mac}) ?`)){ if (confirm(`Confirm remove WoL record for ${name} (${mac}) ?`)){
$.ajax({ $.cjax({
url: wake_on_lan_API, url: wake_on_lan_API,
type: "POST", type: "POST",
data: { data: {
@ -385,7 +385,7 @@ function wakeWoL(mac, object=undefined) {
if (object != undefined){ if (object != undefined){
$(object).addClass("loading").addClass("disabled"); $(object).addClass("loading").addClass("disabled");
} }
$.ajax({ $.cjax({
url: wake_on_lan_API, url: wake_on_lan_API,
type: "POST", type: "POST",
data: { data: {
@ -594,7 +594,7 @@ function initForwardProxyInfo(){
initForwardProxyInfo(); initForwardProxyInfo();
function toggleForwadProxy(enabled){ function toggleForwadProxy(enabled){
$.ajax({ $.cjax({
url: "/api/tools/fwdproxy/enable", url: "/api/tools/fwdproxy/enable",
method: "POST", method: "POST",
data: { data: {
@ -620,7 +620,7 @@ function updateForwardProxyPort(){
$("#newPortNumber").parent().removeClass('error'); $("#newPortNumber").parent().removeClass('error');
} }
$.ajax({ $.cjax({
url: "/api/tools/fwdproxy/port", url: "/api/tools/fwdproxy/port",
method: "POST", method: "POST",
data: { data: {

View File

@ -116,7 +116,7 @@
let forwardChildpath = document.querySelector('input[name="forward-childpath"]').checked; let forwardChildpath = document.querySelector('input[name="forward-childpath"]').checked;
let redirectType = document.querySelector('input[name="redirect-type"]:checked').value; let redirectType = document.querySelector('input[name="redirect-type"]:checked').value;
$.ajax({ $.cjax({
url: "/api/redirect/add", url: "/api/redirect/add",
method: "POST", method: "POST",
data: { data: {
@ -141,7 +141,7 @@
let targetURL = $(obj).attr("rurl"); let targetURL = $(obj).attr("rurl");
targetURL = JSON.parse(decodeURIComponent(targetURL)); targetURL = JSON.parse(decodeURIComponent(targetURL));
if (confirm("Confirm remove redirection from " + targetURL + " ?")){ if (confirm("Confirm remove redirection from " + targetURL + " ?")){
$.ajax({ $.cjax({
url: "/api/redirect/delete", url: "/api/redirect/delete",
method: "POST", method: "POST",
data: { data: {
@ -191,8 +191,9 @@
//Bind event to the checkbox //Bind event to the checkbox
$("#redirectRegex").on("change", function(){ $("#redirectRegex").on("change", function(){
$.ajax({ $.cjax({
url: "/api/redirect/regex", url: "/api/redirect/regex",
method: "POST",
data: {"enable": $(this)[0].checked}, data: {"enable": $(this)[0].checked},
success: function(data){ success: function(data){
if (data.error != undefined){ if (data.error != undefined){

View File

@ -181,8 +181,9 @@
targetDomain = targetDomain.substring(8); targetDomain = targetDomain.substring(8);
$("#proxyRoot").val(targetDomain); $("#proxyRoot").val(targetDomain);
} }
$.ajax({ $.cjax({
url: "/api/proxy/tlscheck", url: "/api/proxy/tlscheck",
method: "POST",
data: {url: targetDomain}, data: {url: targetDomain},
success: function(data){ success: function(data){
if (data.error != undefined){ if (data.error != undefined){
@ -232,7 +233,7 @@
} }
//Create the endpoint by calling add //Create the endpoint by calling add
$.ajax({ $.cjax({
url: "/api/proxy/add", url: "/api/proxy/add",
data: { data: {
"type": "root", "type": "root",

View File

@ -212,8 +212,9 @@
} }
//Create the endpoint by calling add //Create the endpoint by calling add
$.ajax({ $.cjax({
url: "/api/proxy/add", url: "/api/proxy/add",
method: "POST",
data: { data: {
type: "host", type: "host",
rootname: rootname, 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:// //Clearn the proxy target value, make sure user do not enter http:// or https://
//and auto select TLS checkbox if https:// exists //and auto select TLS checkbox if https:// exists
function autoFillTargetTLS(input){ function autoFillTargetTLS(input){
@ -307,12 +292,12 @@
//Automatic check if the site require TLS and check the checkbox if needed //Automatic check if the site require TLS and check the checkbox if needed
function autoCheckTls(targetDomain){ function autoCheckTls(targetDomain){
$.ajax({ $.cjax({
url: "/api/proxy/tlscheck", url: "/api/proxy/tlscheck",
data: {url: targetDomain}, data: {url: targetDomain},
success: function(data){ success: function(data){
if (data.error != undefined){ if (data.error != undefined){
msgbox(data.error, false);
}else if (data == "https"){ }else if (data == "https"){
$("#reqTls").parent().checkbox("set checked"); $("#reqTls").parent().checkbox("set checked");
}else if (data == "http"){ }else if (data == "http"){

View File

@ -315,26 +315,39 @@
//Start and stop service button //Start and stop service button
function startService(){ function startService(){
$.post("/api/proxy/enable", {enable: true}, function(data){ $.cjax({
if (data.error != undefined){ url: "/api/proxy/enable",
msgbox(data.error, false, 5000); method: "POST",
data: {enable: true},
success: function(data){
if (data.error != undefined){
msgbox(data.error, false, 5000);
}
initRPStaste();
} }
initRPStaste();
}); });
} }
function stopService(){ function stopService(){
$.post("/api/proxy/enable", {enable: false}, function(data){ $.cjax({
if (data.error != undefined){ url: "/api/proxy/enable",
msgbox(data.error, false, 5000); method: "POST",
data: {enable: false},
success: function(data){
if (data.error != undefined){
msgbox(data.error, false, 5000);
}
initRPStaste();
} }
initRPStaste();
}); });
} }
function handleP80ListenerStateChange(enabled){ function handleP80ListenerStateChange(enabled){
$.ajax({ $.cjax({
url: "/api/proxy/listenPort80", url: "/api/proxy/listenPort80",
method: "POST",
data: {"enable": enabled}, data: {"enable": enabled},
success: function(data){ success: function(data){
if (data.error != undefined){ if (data.error != undefined){
@ -361,16 +374,21 @@
return; return;
} }
$.post("/api/proxy/setIncoming", {incoming: newPortValue}, function(data){ $.cjax({
if (data.error != undefined){ url: "/api/proxy/setIncoming",
msgbox(data.error, false, 5000); method: "POST",
return; data: {incoming: newPortValue},
} success: function(data){
msgbox("Listening Port Updated"); if (data.error != undefined){
initRPStaste(); msgbox(data.error, false, 5000);
return;
}
msgbox("Listening Port Updated");
initRPStaste();
//Hide the reminder text //Hide the reminder text
$("#applyButtonReminder").hide(); $("#applyButtonReminder").hide();
}
}); });
} }
@ -402,8 +420,9 @@
//Initiate the input listener on the checkbox //Initiate the input listener on the checkbox
$("#redirect").find("input").on("change", function(){ $("#redirect").find("input").on("change", function(){
let thisValue = $("#redirect").checkbox("is checked"); let thisValue = $("#redirect").checkbox("is checked");
$.ajax({ $.cjax({
url: "/api/proxy/useHttpsRedirect", url: "/api/proxy/useHttpsRedirect",
method: "POST",
data: {set: thisValue}, data: {set: thisValue},
success: function(data){ success: function(data){
if (data.error != undefined){ if (data.error != undefined){
@ -440,9 +459,10 @@
//Bind events to the checkbox //Bind events to the checkbox
$("#tlsMinVer").find("input").on("change", function(){ $("#tlsMinVer").find("input").on("change", function(){
let thisValue = $("#tlsMinVer").checkbox("is checked"); let thisValue = $("#tlsMinVer").checkbox("is checked");
$.ajax({ $.cjax({
url: "/api/cert/tlsRequireLatest", url: "/api/cert/tlsRequireLatest",
data: {"set": thisValue}, data: {"set": thisValue},
method: "POST",
success: function(data){ success: function(data){
if (data.error != undefined){ if (data.error != undefined){
msgbox(data.error, false, 5000); msgbox(data.error, false, 5000);
@ -498,15 +518,15 @@
}else{ }else{
$(".tlsEnabledOnly").addClass('disabled'); $(".tlsEnabledOnly").addClass('disabled');
} }
$.ajax({ $.cjax({
url: "/api/cert/tls", url: "/api/cert/tls",
method: "POST",
data: {set: thisValue}, data: {set: thisValue},
success: function(data){ success: function(data){
if (data.error != undefined){ if (data.error != undefined){
alert(data.error); msgbox(data.error, false);
}else{ }else{
//Updated //Updated
//Check for case if the port is invalid default ports //Check for case if the port is invalid default ports
if ($("#incomingPort").val() == "80" && thisValue == true){ if ($("#incomingPort").val() == "80" && thisValue == true){
confirmBox("Change listen port to :443?", function(choice){ confirmBox("Change listen port to :443?", function(choice){

View File

@ -100,7 +100,7 @@
} }
// Send the AJAX POST request // Send the AJAX POST request
$.ajax({ $.cjax({
type: 'POST', type: 'POST',
url: '/api/streamprox/config/add', url: '/api/streamprox/config/add',
data: form.serialize(), data: form.serialize(),
@ -285,7 +285,7 @@
} }
// Send the AJAX POST request // Send the AJAX POST request
$.ajax({ $.cjax({
type: 'POST', type: 'POST',
url: '/api/streamprox/config/edit', url: '/api/streamprox/config/edit',
method: "POST", method: "POST",
@ -316,7 +316,7 @@
} }
function deleteTCPProxyConfig(configUUID){ function deleteTCPProxyConfig(configUUID){
$.ajax({ $.cjax({
url: "/api/streamprox/config/delete", url: "/api/streamprox/config/delete",
method: "POST", method: "POST",
data: {uuid: configUUID}, data: {uuid: configUUID},
@ -333,7 +333,7 @@
//Start a TCP proxy by their config UUID //Start a TCP proxy by their config UUID
function startStreamProx(configUUID){ function startStreamProx(configUUID){
$.ajax({ $.cjax({
url: "/api/streamprox/config/start", url: "/api/streamprox/config/start",
method: "POST", method: "POST",
data: {uuid: configUUID}, data: {uuid: configUUID},
@ -351,7 +351,7 @@
//Stop a TCP proxy by their config UUID //Stop a TCP proxy by their config UUID
function stopStreamProx(configUUID){ function stopStreamProx(configUUID){
$.ajax({ $.cjax({
url: "/api/streamprox/config/stop", url: "/api/streamprox/config/stop",
method: "POST", method: "POST",
data: {uuid: configUUID}, data: {uuid: configUUID},

View File

@ -233,7 +233,7 @@
const newPassword = document.getElementsByName('newPassword')[0].value; const newPassword = document.getElementsByName('newPassword')[0].value;
const confirmNewPassword = document.getElementsByName('confirmNewPassword')[0].value; const confirmNewPassword = document.getElementsByName('confirmNewPassword')[0].value;
$.ajax({ $.cjax({
type: "POST", type: "POST",
url: "/api/auth/changePassword", url: "/api/auth/changePassword",
data: { data: {
@ -279,7 +279,7 @@
return; return;
} }
$.ajax({ $.cjax({
type: "POST", type: "POST",
url: "/api/tools/smtp/set", url: "/api/tools/smtp/set",
data: data, data: data,

View File

@ -190,7 +190,7 @@
function updateVDTargetTLSState(){ function updateVDTargetTLSState(){
var targetDomain = $("#virtualDirectoryDomain").val().trim(); var targetDomain = $("#virtualDirectoryDomain").val().trim();
if (targetDomain != ""){ if (targetDomain != ""){
$.ajax({ $.cjax({
url: "/api/proxy/tlscheck", url: "/api/proxy/tlscheck",
data: {url: targetDomain}, data: {url: targetDomain},
success: function(data){ success: function(data){
@ -252,7 +252,7 @@
} }
//Create a virtual directory endpoint //Create a virtual directory endpoint
$.ajax({ $.cjax({
url: "/api/proxy/vdir/add", url: "/api/proxy/vdir/add",
method: "POST", method: "POST",
data: { data: {
@ -295,7 +295,7 @@
epType = "root"; epType = "root";
path = ""; path = "";
} }
$.ajax({ $.cjax({
url: "/api/proxy/vdir/del", url: "/api/proxy/vdir/del",
method: "POST", method: "POST",
data: { data: {
@ -384,7 +384,7 @@
//console.log(mathingPath, newDomain, requireTLS, skipValidation); //console.log(mathingPath, newDomain, requireTLS, skipValidation);
$.ajax({ $.cjax({
url: "/api/proxy/vdir/edit", url: "/api/proxy/vdir/edit",
method: "POST", method: "POST",
data: { data: {

View File

@ -164,7 +164,7 @@
$("#webserv_enableDirList").off("change").on("change", function(){ $("#webserv_enableDirList").off("change").on("change", function(){
let enable = $(this)[0].checked; let enable = $(this)[0].checked;
$.ajax({ $.cjax({
url: "/api/webserv/setDirList", url: "/api/webserv/setDirList",
method: "POST", method: "POST",
data: {"enable": enable}, data: {"enable": enable},
@ -186,7 +186,7 @@
confirmBox("This setting might cause port conflict. Continue Anyway?", function(choice){ confirmBox("This setting might cause port conflict. Continue Anyway?", function(choice){
if (choice == true){ if (choice == true){
//Continue anyway //Continue anyway
$.ajax({ $.cjax({
url: "/api/webserv/setPort", url: "/api/webserv/setPort",
method: "POST", method: "POST",
data: {"port": newPort}, data: {"port": newPort},
@ -206,7 +206,7 @@
} }
}); });
}else{ }else{
$.ajax({ $.cjax({
url: "/api/webserv/setPort", url: "/api/webserv/setPort",
method: "POST", method: "POST",
data: {"port": newPort}, data: {"port": newPort},

View File

@ -5,6 +5,7 @@
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1"/> <meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1"/>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="theme-color" content="#4b75ff"> <meta name="theme-color" content="#4b75ff">
<meta name="zoraxy.csrf.Token" content="{{.csrfToken}}">
<link rel="icon" type="image/png" href="./favicon.png" /> <link rel="icon" type="image/png" href="./favicon.png" />
<title>Control Panel | Zoraxy</title> <title>Control Panel | Zoraxy</title>
<link rel="stylesheet" href="script/semantic/semantic.min.css"> <link rel="stylesheet" href="script/semantic/semantic.min.css">

View File

@ -4,6 +4,7 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="robots" content="noindex" /> <meta name="robots" content="noindex" />
<meta name="viewport" content="width=device-width, initial-scale=1"> <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" /> <link rel="icon" type="image/png" href="./favicon.png" />
<title>Login | Zoraxy</title> <title>Login | Zoraxy</title>
<link rel="stylesheet" href="script/semantic/semantic.min.css"> <link rel="stylesheet" href="script/semantic/semantic.min.css">
@ -250,10 +251,10 @@
}); });
$("#regsiterbtn").on("click", function(event){ $("#regsiterbtn").on("click", function(event){
var username = $("#username").val(); let username = $("#username").val();
var magic = $("#magic").val(); let magic = $("#magic").val();
var repeatMagic = $("#repeatMagic").val(); let repeatMagic = $("#repeatMagic").val();
let csrfToken = document.getElementsByTagName("meta")["zoraxy.csrf.Token"].getAttribute("content");
if (magic !== repeatMagic) { if (magic !== repeatMagic) {
alert("Password does not match"); alert("Password does not match");
return; return;
@ -262,6 +263,9 @@
$.ajax({ $.ajax({
url: "/api/auth/register", url: "/api/auth/register",
method: "POST", method: "POST",
beforeSend: function(request) {
request.setRequestHeader("X-CSRF-Token",csrfToken);
},
data: { data: {
username: username, username: username,
password: magic password: magic
@ -297,29 +301,45 @@
//Login system with the given username and password //Login system with the given username and password
function login(){ function login(){
var username = $("#username").val(); let username = $("#username").val();
var magic = $("#magic").val(); let magic = $("#magic").val();
var rmbme = document.getElementById("rmbme").checked; let rmbme = document.getElementById("rmbme").checked;
let csrfToken = document.getElementsByTagName("meta")["zoraxy.csrf.Token"].getAttribute("content");
$("#errmsg").stop().finish().slideUp("fast"); $("#errmsg").stop().finish().slideUp("fast");
$("input").addClass('disabled'); $("input").addClass('disabled');
$.post(loginAddress, {"username": username, "password": magic, "rmbme": rmbme}).done(function(data){ $.ajax({
if (data.error !== undefined){ url: loginAddress,
//Something went wrong during the login type: "POST",
$("#errmsg").html(`<i class="red remove icon"></i> ${data.error}`); beforeSend: function(request) {
$("#errmsg").stop().finish().slideDown('fast'); request.setRequestHeader("X-CSRF-Token",csrfToken);
}else if(data.redirect !== undefined){ },
//LDAP Related Code data: {
window.location.href = data.redirect; "username": username,
}else{ "password": magic,
//Login succeed "rmbme": rmbme,
if (redirectionAddress == ""){ },
//Redirect back to index success: function(data){
window.location.href = "./"; 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{ }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');
}); });
} }

View File

@ -2,6 +2,7 @@
<html> <html>
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="zoraxy.csrf.Token" content="{{.csrfToken}}">
<meta name="robots" content="noindex" /> <meta name="robots" content="noindex" />
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/png" href="./favicon.png" /> <link rel="icon" type="image/png" href="./favicon.png" />
@ -255,25 +256,36 @@
} }
// Send POST request with input values as data // Send POST request with input values as data
$.post('/api/account/new', { username: username, token: token, newpw: newPassword }) let csrfToken = document.getElementsByTagName("meta")["zoraxy.csrf.Token"].getAttribute("content");
.done(function(data) { $.ajax({
// Handle successful response url: "/api/account/new",
if (data.error != undefined){ method: "POST",
$("#errmsg").html(`<i class="red circle times icon"></i> ` + data.error); data: {
$("#errmsg").show(); username: username,
}else{ token: token,
$("#errmsg").hide(); newpw: newPassword
$("#countdown").hide(); },
$("#succmsg").show(); headers: {
setTimeout(function(){ "X-CSRF-Token": csrfToken,
window.location.href = "/"; },
}, 3000); 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);
});
}); });

View File

@ -26,4 +26,18 @@ Object.defineProperty(String.prototype, 'capitalize', {
return this.charAt(0).toUpperCase() + this.slice(1); return this.charAt(0).toUpperCase() + this.slice(1);
}, },
enumerable: false 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);
}

View File

@ -3,9 +3,11 @@
<head> <head>
<!-- Notes: This should be open in its original path--> <!-- Notes: This should be open in its original path-->
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="zoraxy.csrf.Token" content="{{.csrfToken}}">
<link rel="stylesheet" href="../script/semantic/semantic.min.css"> <link rel="stylesheet" href="../script/semantic/semantic.min.css">
<script src="../script/jquery-3.6.0.min.js"></script> <script src="../script/jquery-3.6.0.min.js"></script>
<script src="../script/semantic/semantic.min.js"></script> <script src="../script/semantic/semantic.min.js"></script>
<script src="../script/utils.js"></script>
<style> <style>
#refreshAccessRuleListBtn{ #refreshAccessRuleListBtn{
position: absolute; position: absolute;
@ -94,7 +96,7 @@
$("#accessRuleForm input[name='accessRuleName']").val(""); $("#accessRuleForm input[name='accessRuleName']").val("");
$("#accessRuleForm textarea[name='description']").val(""); $("#accessRuleForm textarea[name='description']").val("");
$.ajax({ $.cjax({
url: "/api/access/create", url: "/api/access/create",
method: "POST", method: "POST",
data: { data: {
@ -162,7 +164,7 @@
console.log('Access Rule Name:', accessRuleName); console.log('Access Rule Name:', accessRuleName);
console.log('Description:', description); console.log('Description:', description);
$.ajax({ $.cjax({
url: "/api/access/update", url: "/api/access/update",
method: "POST", method: "POST",
data: { data: {
@ -238,7 +240,7 @@
} }
let accessRuleName = $("#modifyRuleInfo input[name='accessRuleName']").val(); let accessRuleName = $("#modifyRuleInfo input[name='accessRuleName']").val();
if (confirm("Confirm removing access rule " + accessRuleName + "?")){ if (confirm("Confirm removing access rule " + accessRuleName + "?")){
$.ajax({ $.cjax({
url: "/api/access/remove", url: "/api/access/remove",
data: { data: {
"id": accessRuleUUID "id": accessRuleUUID

View File

@ -3,9 +3,11 @@
<head> <head>
<!-- Notes: This should be open in its original path--> <!-- Notes: This should be open in its original path-->
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="zoraxy.csrf.Token" content="{{.csrfToken}}">
<link rel="stylesheet" href="../script/semantic/semantic.min.css"> <link rel="stylesheet" href="../script/semantic/semantic.min.css">
<script src="../script/jquery-3.6.0.min.js"></script> <script src="../script/jquery-3.6.0.min.js"></script>
<script src="../script/semantic/semantic.min.js"></script> <script src="../script/semantic/semantic.min.js"></script>
<script src="../script/utils.js"></script>
<style> <style>
.disabled.table{ .disabled.table{
opacity: 0.5; opacity: 0.5;
@ -234,8 +236,9 @@
initRenewerConfigFromFile(); initRenewerConfigFromFile();
function saveEmailToConfig(btn){ function saveEmailToConfig(btn){
$.ajax({ $.cjax({
url: "/api/acme/autoRenew/email", url: "/api/acme/autoRenew/email",
method: "POST",
data: {set: $("#caRegisterEmail").val()}, data: {set: $("#caRegisterEmail").val()},
success: function(data){ success: function(data){
if (data.error != undefined){ if (data.error != undefined){
@ -256,27 +259,29 @@
function toggleAutoRenew(){ function toggleAutoRenew(){
var enabled = $("#enableCertAutoRenew").parent().checkbox("is checked"); var enabled = $("#enableCertAutoRenew").parent().checkbox("is checked");
$.post("/api/acme/autoRenew/enable?enable=" + enabled, function(data){ $.cjax({
if (data.error){ url: "/api/acme/autoRenew/enable",
parent.msgbox(data.error, false, 5000); method: "POST",
if (enabled){ data: {"enable": enabled},
enableTrigerOnChangeEvent = false; success: function(data){
$("#enableCertAutoRenew").parent().checkbox("set unchecked"); if (data.error){
enableTrigerOnChangeEvent = true; parent.msgbox(data.error, false, 5000);
} if (enabled){
if (parent && parent.setACMEEnableStates){ enableTrigerOnChangeEvent = false;
parent.setACMEEnableStates(!enabled); $("#enableCertAutoRenew").parent().checkbox("set unchecked");
} enableTrigerOnChangeEvent = true;
}else{ }
$("#enableToggleSucc").stop().finish().fadeIn("fast").delay(3000).fadeOut("fast"); if (parent && parent.setACMEEnableStates){
if (parent && parent.setACMEEnableStates){ parent.setACMEEnableStates(!enabled);
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 //Render the domains table that exists in this zoraxy host
@ -630,7 +635,7 @@
return; return;
} }
$.ajax({ $.cjax({
url: "/api/acme/autoRenew/setDNS", url: "/api/acme/autoRenew/setDNS",
method: "POST", method: "POST",
data: { data: {
@ -843,8 +848,9 @@
function saveAutoRenewPolicy(){ function saveAutoRenewPolicy(){
let autoRenewAll = $("#renewAllSupported").parent().checkbox("is checked"); let autoRenewAll = $("#renewAllSupported").parent().checkbox("is checked");
if (autoRenewAll == true){ if (autoRenewAll == true){
$.ajax({ $.cjax({
url: "/api/acme/autoRenew/setDomains", url: "/api/acme/autoRenew/setDomains",
method: "POST",
data: {opr: "setAuto"}, data: {opr: "setAuto"},
success: function(data){ success: function(data){
parent.msgbox("Renew policy rule updated") parent.msgbox("Renew policy rule updated")
@ -856,8 +862,9 @@
checkedNames.push($(this).attr('name')); checkedNames.push($(this).attr('name'));
}); });
$.ajax({ $.cjax({
url: "/api/acme/autoRenew/setDomains", url: "/api/acme/autoRenew/setDomains",
method: "POST",
data: {opr: "setSelected", domains: JSON.stringify(checkedNames)}, data: {opr: "setSelected", domains: JSON.stringify(checkedNames)},
success: function(data){ success: function(data){
parent.msgbox("Renew policy rule updated") parent.msgbox("Renew policy rule updated")

View File

@ -3,9 +3,11 @@
<head> <head>
<!-- Notes: This should be open in its original path--> <!-- Notes: This should be open in its original path-->
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="zoraxy.csrf.Token" content="{{.csrfToken}}">
<link rel="stylesheet" href="../script/semantic/semantic.min.css"> <link rel="stylesheet" href="../script/semantic/semantic.min.css">
<script src="../script/jquery-3.6.0.min.js"></script> <script src="../script/jquery-3.6.0.min.js"></script>
<script src="../script/semantic/semantic.min.js"></script> <script src="../script/semantic/semantic.min.js"></script>
<script src="../script/utils.js"></script>
</head> </head>
<body> <body>
<br> <br>
@ -46,7 +48,7 @@
function handleResetStats(){ function handleResetStats(){
if (confirm("Confirm remove statistics from " + startDate + " to " + endDate +"?")){ if (confirm("Confirm remove statistics from " + startDate + " to " + endDate +"?")){
$.ajax({ $.cjax({
url: "/api/analytic/resetRange?start=" + startDate + "&end=" + endDate, url: "/api/analytic/resetRange?start=" + startDate + "&end=" + endDate,
method: "DELETE", method: "DELETE",
success: function(data){ success: function(data){

View File

@ -3,9 +3,11 @@
<head> <head>
<!-- Notes: This should be open in its original path--> <!-- Notes: This should be open in its original path-->
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="zoraxy.csrf.Token" content="{{.csrfToken}}">
<link rel="stylesheet" href="../script/semantic/semantic.min.css"> <link rel="stylesheet" href="../script/semantic/semantic.min.css">
<script src="../script/jquery-3.6.0.min.js"></script> <script src="../script/jquery-3.6.0.min.js"></script>
<script src="../script/semantic/semantic.min.js"></script> <script src="../script/semantic/semantic.min.js"></script>
<script src="../script/utils.js"></script>
</head> </head>
<body> <body>
<br> <br>
@ -71,7 +73,7 @@
} }
function initAliasNames(){ function initAliasNames(){
$.ajax({ $.cjax({
url: "/api/proxy/detail", url: "/api/proxy/detail",
method: "POST", method: "POST",
data: { data: {
@ -130,7 +132,7 @@
} }
function saveCurrentAliasList(callback=undefined){ function saveCurrentAliasList(callback=undefined){
$.ajax({ $.cjax({
url: "/api/proxy/setAlias", url: "/api/proxy/setAlias",
method: "POST", method: "POST",
data:{ data:{

View File

@ -3,9 +3,11 @@
<head> <head>
<!-- Notes: This should be open in its original path--> <!-- Notes: This should be open in its original path-->
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="zoraxy.csrf.Token" content="{{.csrfToken}}">
<link rel="stylesheet" href="../script/semantic/semantic.min.css"> <link rel="stylesheet" href="../script/semantic/semantic.min.css">
<script src="../script/jquery-3.6.0.min.js"></script> <script src="../script/jquery-3.6.0.min.js"></script>
<script src="../script/semantic/semantic.min.js"></script> <script src="../script/semantic/semantic.min.js"></script>
<script src="../script/utils.js"></script>
</head> </head>
<body> <body>
<br> <br>
@ -174,7 +176,7 @@
parent.msgbox("Matching prefix cannot be empty!", false, 5000); parent.msgbox("Matching prefix cannot be empty!", false, 5000);
return; return;
} }
$.ajax({ $.cjax({
url: "/api/proxy/auth/exceptions/add", url: "/api/proxy/auth/exceptions/add",
data:{ data:{
ep: editingEndpoint.ep, ep: editingEndpoint.ep,
@ -195,7 +197,7 @@
function removeExceptionPath(object){ function removeExceptionPath(object){
let matchingPrefix = $(object).attr("prefix"); let matchingPrefix = $(object).attr("prefix");
$.ajax({ $.cjax({
url: "/api/proxy/auth/exceptions/delete", url: "/api/proxy/auth/exceptions/delete",
data:{ data:{
ep: editingEndpoint.ep, ep: editingEndpoint.ep,
@ -290,7 +292,7 @@
} }
function saveCredentials(){ function saveCredentials(){
$.ajax({ $.cjax({
url: "/api/proxy/updateCredentials", url: "/api/proxy/updateCredentials",
method: "POST", method: "POST",
data: { data: {

View File

@ -3,9 +3,11 @@
<head> <head>
<!-- Notes: This should be open in its original path--> <!-- Notes: This should be open in its original path-->
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="zoraxy.csrf.Token" content="{{.csrfToken}}">
<link rel="stylesheet" href="../script/semantic/semantic.min.css"> <link rel="stylesheet" href="../script/semantic/semantic.min.css">
<script src="../script/jquery-3.6.0.min.js"></script> <script src="../script/jquery-3.6.0.min.js"></script>
<script src="../script/semantic/semantic.min.js"></script> <script src="../script/semantic/semantic.min.js"></script>
<script src="../script/utils.js"></script>
</head> </head>
<body> <body>
<br> <br>
@ -70,10 +72,10 @@
} }
} }
document.getElementById("uploadForm").addEventListener("submit", function(event) { $("#uploadForm").submit(function(event) {
event.preventDefault(); // Prevent the form from submitting normally event.preventDefault(); // Prevent the form from submitting normally
var fileInput = document.getElementById("fileInput"); var fileInput = $("#fileInput")[0];
var file = fileInput.files[0]; var file = fileInput.files[0];
if (!file) { if (!file) {
alert("Missing file."); alert("Missing file.");
@ -83,18 +85,19 @@
var formData = new FormData(); var formData = new FormData();
formData.append("file", file); formData.append("file", file);
var xhr = new XMLHttpRequest(); $.cjax({
xhr.open("POST", "/api/conf/import", true); url: "/api/conf/import",
xhr.onreadystatechange = function() { type: "POST",
if (xhr.readyState === XMLHttpRequest.DONE) { data: formData,
if (xhr.status === 200) { processData: false, // Not to process the data
parent.msgbox("Config restore succeed. Restart Zoraxy to apply changes.") contentType: false, // Not to set contentType
} else { success: function(response) {
parent.msgbox("Restore failed: " + xhr.responseText, false, 5000); 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> </script>
</body> </body>

View File

@ -3,9 +3,11 @@
<head> <head>
<!-- Notes: This should be open in its original path--> <!-- Notes: This should be open in its original path-->
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="zoraxy.csrf.Token" content="{{.csrfToken}}">
<link rel="stylesheet" href="../script/semantic/semantic.min.css"> <link rel="stylesheet" href="../script/semantic/semantic.min.css">
<script src="../script/jquery-3.6.0.min.js"></script> <script src="../script/jquery-3.6.0.min.js"></script>
<script src="../script/semantic/semantic.min.js"></script> <script src="../script/semantic/semantic.min.js"></script>
<script src="../script/utils.js"></script>
<style> <style>
.ui.tabular.menu .item.narrowpadding{ .ui.tabular.menu .item.narrowpadding{
padding: 0.6em !important; padding: 0.6em !important;
@ -92,9 +94,6 @@
</div> </div>
<div class="content"> <div class="content">
<br> <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"> <div class="ui container">
<h4>Overwrite Host Header</h4> <h4>Overwrite Host Header</h4>
<p>Manual override the automatic "Host" header rewrite logic. Leave empty for automatic.</p> <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> <label>Remove Hop-by-hop Header<br>
<small>This should be ON by default</small></label> <small>This should be ON by default</small></label>
</div> </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> </div>
</div> </div>
@ -247,8 +248,9 @@
} }
} }
$.ajax({ $.cjax({
url: "/api/proxy/header/add", url: "/api/proxy/header/add",
method: "POST",
data: { data: {
"type": getHeaderEditMode(), "type": getHeaderEditMode(),
"domain": editingEndpoint.ep, "domain": editingEndpoint.ep,
@ -279,10 +281,10 @@
} }
function deleteCustomHeader(name){ function deleteCustomHeader(name){
$.ajax({ $.cjax({
url: "/api/proxy/header/remove", url: "/api/proxy/header/remove",
method: "POST",
data: { data: {
//"type": editingEndpoint.ept,
"domain": editingEndpoint.ep, "domain": editingEndpoint.ep,
"name": name, "name": name,
}, },
@ -299,6 +301,7 @@
$("#headerTable").html(`<tr><td colspan="3"><i class="ui loading spinner icon"></i> Loading</td></tr>`); $("#headerTable").html(`<tr><td colspan="3"><i class="ui loading spinner icon"></i> Loading</td></tr>`);
$.ajax({ $.ajax({
url: "/api/proxy/header/list", url: "/api/proxy/header/list",
method: "GET",
data: { data: {
"type": editingEndpoint.ept, "type": editingEndpoint.ept,
"domain": editingEndpoint.ep, "domain": editingEndpoint.ep,
@ -307,7 +310,6 @@
if (data.error != undefined){ if (data.error != undefined){
alert(data.error); alert(data.error);
}else{ }else{
$("#headerTable").html(""); $("#headerTable").html("");
data.forEach(header => { data.forEach(header => {
let editModeIcon = header.IsRemove?`<i class="ui red times circle icon"></i>`:`<i class="ui green add circle icon"></i>`; 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 */ /* Bind events to toggles */
$("#enableHSTS").on("change", function(){ $("#enableHSTS").on("change", function(){
let HSTSEnabled = $("#enableHSTS")[0].checked; let HSTSEnabled = $("#enableHSTS")[0].checked;
$.ajax({ $.cjax({
url: "/api/proxy/header/handleHSTS", url: "/api/proxy/header/handleHSTS",
method: "POST", method: "POST",
data: { data: {
@ -426,7 +428,7 @@
$("#permissionPolicyEditor").addClass("disabled"); $("#permissionPolicyEditor").addClass("disabled");
} }
$.ajax({ $.cjax({
url: "/api/proxy/header/handlePermissionPolicy", url: "/api/proxy/header/handlePermissionPolicy",
method: "POST", method: "POST",
data: { data: {
@ -532,7 +534,7 @@
let permissionPolicy = generatePermissionPolicyObject(); let permissionPolicy = generatePermissionPolicyObject();
let domain = editingEndpoint.ep; let domain = editingEndpoint.ep;
$.ajax({ $.cjax({
url: "/api/proxy/header/handlePermissionPolicy", url: "/api/proxy/header/handlePermissionPolicy",
method: "PUT", method: "PUT",
data: { data: {
@ -576,7 +578,7 @@
function updateManualHostOverwriteVal(callback=undefined){ function updateManualHostOverwriteVal(callback=undefined){
let newHostname = $("#manualHostOverwrite").val().trim(); let newHostname = $("#manualHostOverwrite").val().trim();
$.ajax({ $.cjax({
url: "/api/proxy/header/handleHostOverwrite", url: "/api/proxy/header/handleHostOverwrite",
method: "POST", method: "POST",
data: { data: {
@ -615,7 +617,7 @@
//Bind event to the checkbox //Bind event to the checkbox
$("#removeHopByHop").on("change", function(evt){ $("#removeHopByHop").on("change", function(evt){
let isChecked = $(this)[0].checked; let isChecked = $(this)[0].checked;
$.ajax({ $.cjax({
url: "/api/proxy/header/handleHopByHop", url: "/api/proxy/header/handleHopByHop",
method: "POST", method: "POST",
data: { data: {

View File

@ -3,9 +3,11 @@
<head> <head>
<!-- Notes: This should be open in its original path--> <!-- Notes: This should be open in its original path-->
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="zoraxy.csrf.Token" content="{{.csrfToken}}">
<link rel="stylesheet" href="../script/semantic/semantic.min.css"> <link rel="stylesheet" href="../script/semantic/semantic.min.css">
<script src="../script/jquery-3.6.0.min.js"></script> <script src="../script/jquery-3.6.0.min.js"></script>
<script src="../script/semantic/semantic.min.js"></script> <script src="../script/semantic/semantic.min.js"></script>
<script src="../script/utils.js"></script>
<style> <style>
.accessRule{ .accessRule{
cursor: pointer; cursor: pointer;
@ -124,12 +126,10 @@
} }
} }
}); });
} }
initAccessRuleList(function(){ initAccessRuleList(function(){
$.ajax({ $.cjax({
url: "/api/proxy/detail", url: "/api/proxy/detail",
method: "POST", method: "POST",
data: {"type":"host", "epname": editingEndpoint.ep }, data: {"type":"host", "epname": editingEndpoint.ep },
@ -160,7 +160,7 @@
function applyChangeAndClose(){ function applyChangeAndClose(){
let newAccessRuleID = $(".accessRule.active").attr("ruleid"); let newAccessRuleID = $(".accessRule.active").attr("ruleid");
let targetEndpoint = editingEndpoint.ep; let targetEndpoint = editingEndpoint.ep;
$.ajax({ $.cjax({
url: "/api/access/attach", url: "/api/access/attach",
method: "POST", method: "POST",
data: { data: {

View File

@ -2,9 +2,11 @@
<html> <html>
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="zoraxy.csrf.Token" content="{{.csrfToken}}">
<link rel="stylesheet" href="../script/semantic/semantic.min.css"> <link rel="stylesheet" href="../script/semantic/semantic.min.css">
<script src="../script/jquery-3.6.0.min.js"></script> <script src="../script/jquery-3.6.0.min.js"></script>
<script src="../script/semantic/semantic.min.js"></script> <script src="../script/semantic/semantic.min.js"></script>
<script src="../script/utils.js"></script>
<style> <style>
body{ body{
height: 100%; height: 100%;

View File

@ -3,9 +3,11 @@
<head> <head>
<!-- Notes: This should be open in its original path--> <!-- Notes: This should be open in its original path-->
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="zoraxy.csrf.Token" content="{{.csrfToken}}">
<link rel="stylesheet" href="../script/semantic/semantic.min.css"> <link rel="stylesheet" href="../script/semantic/semantic.min.css">
<script src="../script/jquery-3.6.0.min.js"></script> <script src="../script/jquery-3.6.0.min.js"></script>
<script src="../script/semantic/semantic.min.js"></script> <script src="../script/semantic/semantic.min.js"></script>
<script src="../script/utils.js"></script>
<style> <style>
.upstreamActions{ .upstreamActions{
position: absolute; position: absolute;
@ -133,7 +135,7 @@
function initOriginList(){ function initOriginList(){
$.ajax({ $.ajax({
url: "/api/proxy/upstream/list", url: "/api/proxy/upstream/list",
method: "POST", method: "GET",
data: { data: {
"type":"host", "type":"host",
"ep": editingEndpoint.ep "ep": editingEndpoint.ep
@ -284,8 +286,9 @@
}else{ }else{
//URL does not contains https or http protocol tag //URL does not contains https or http protocol tag
//sniff header //sniff header
$.ajax({ $.cjax({
url: "/api/proxy/tlscheck", url: "/api/proxy/tlscheck",
method: "POST",
data: {url: targetDomain}, data: {url: targetDomain},
success: function(data){ success: function(data){
if (data.error != undefined){ if (data.error != undefined){
@ -313,7 +316,7 @@
return; return;
} }
$.ajax({ $.cjax({
url: "/api/proxy/upstream/add", url: "/api/proxy/upstream/add",
method: "POST", method: "POST",
data:{ data:{
@ -365,7 +368,7 @@
let newConfig = getUpstreamSettingFromDOM(targetDOM); let newConfig = getUpstreamSettingFromDOM(targetDOM);
let isActive = $(targetDOM).find(".enableState")[0].checked; let isActive = $(targetDOM).find(".enableState")[0].checked;
console.log(newConfig); console.log(newConfig);
$.ajax({ $.cjax({
url: "/api/proxy/upstream/update", url: "/api/proxy/upstream/update",
method: "POST", method: "POST",
data: { data: {
@ -418,8 +421,9 @@
}else{ }else{
//URL does not contains https or http protocol tag //URL does not contains https or http protocol tag
//sniff header //sniff header
$.ajax({ $.cjax({
url: "/api/proxy/tlscheck", url: "/api/proxy/tlscheck",
method: "POST",
data: {url: targetDomain}, data: {url: targetDomain},
success: function(data){ success: function(data){
if (data.error != undefined){ if (data.error != undefined){
@ -460,7 +464,7 @@
//Set a weight of a upstream //Set a weight of a upstream
function setUpstreamWeight(originIP, newWeight){ function setUpstreamWeight(originIP, newWeight){
$.ajax({ $.cjax({
url: "/api/proxy/upstream/setPriority", url: "/api/proxy/upstream/setPriority",
method: "POST", method: "POST",
data: { data: {
@ -489,7 +493,7 @@
return; return;
} }
//Remove the upstream //Remove the upstream
$.ajax({ $.cjax({
url: "/api/proxy/upstream/remove", url: "/api/proxy/upstream/remove",
method: "POST", method: "POST",
data: { data: {

View File

@ -2,12 +2,14 @@
<head> <head>
<title>File Manager</title> <title>File Manager</title>
<meta charset="UTF-8"> <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"> <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> <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" /> <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/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> <script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.6.0/jszip.min.js"></script>
<link rel="stylesheet" href="fs.css"> <link rel="stylesheet" href="fs.css">
<script src="../script/utils.js"></script>
<script> <script>
</script> </script>
@ -199,7 +201,7 @@
let counter = $(".fileObject.selected").length; let counter = $(".fileObject.selected").length;
$(".fileObject.selected").each(function(){ $(".fileObject.selected").each(function(){
let thisFilepath = $(this).attr("filepath"); let thisFilepath = $(this).attr("filepath");
$.ajax({ $.cjax({
url: "/api/fs/del?target=" + thisFilepath, url: "/api/fs/del?target=" + thisFilepath,
method: "POST", method: "POST",
success: function(data){ success: function(data){
@ -241,22 +243,9 @@
let filename = $(this).attr("filename"); let filename = $(this).attr("filename");
if (ftype != "folder"){ if (ftype != "folder"){
let ext = filepath.split(".").pop(); let ext = filepath.split(".").pop();
if (isCodeFiles(ext)){ openthis($(this), evt);
editableCodeFiles.push({
"filename": filename,
"filepath": filepath
});
}else{
openthis($(this), evt);
}
} }
}); });
if (editableCodeFiles.length > 0){
let hash = encodeURIComponent(JSON.stringify(editableCodeFiles))
window.open("notepad/index.html#" + hash);
}
} }
function refresh(){ function refresh(){
@ -571,12 +560,19 @@
return; return;
} }
$.post("/api/fs/newFolder?path=" + currentPath + folderName, function(data){ $.cjax({
if (data.error != undefined){ url: "/api/fs/newFolder",
msgbox(data.error, false); method: "POST",
}else{ data: {
msgbox("Folder Created"); "path": currentPath + folderName,
refresh(); },
success: function(data){
if (data.error != undefined){
msgbox(data.error, false);
}else{
msgbox("Folder Created");
refresh();
}
} }
}); });
} }
@ -597,8 +593,12 @@
if (newName && newName != oldName) { if (newName && newName != oldName) {
// User entered a new name, perform renaming logic here // User entered a new name, perform renaming logic here
console.log(oldPath, currentPath + newName); console.log(oldPath, currentPath + newName);
$.ajax({ $.cjax({
url: "/api/fs/move?srcpath=" + oldPath + "&destpath=" + currentPath + newName, url: "/api/fs/move",
data: {
"srcpath": oldPath,
"destpath": currentPath + newName
},
method: "POST", method: "POST",
success: function(data){ success: function(data){
if (data.error != undefined){ if (data.error != undefined){
@ -826,6 +826,7 @@
ajax.addEventListener("error", errorHandler, false); ajax.addEventListener("error", errorHandler, false);
ajax.addEventListener("abort", abortHandler, false); ajax.addEventListener("abort", abortHandler, false);
ajax.open("POST", "/api/fs/upload?dir=" + dir); ajax.open("POST", "/api/fs/upload?dir=" + dir);
ajax.setRequestHeader("X-CSRF-Token", document.getElementsByTagName("meta")["zoraxy.csrf.Token"].getAttribute("content"));
ajax.send(formdata); ajax.send(formdata);
} }
@ -914,8 +915,12 @@
let filename = fileToPaste.filename; let filename = fileToPaste.filename;
let filepath = fileToPaste.filepath; let filepath = fileToPaste.filepath;
$.ajax({ $.cjax({
url: "/api/fs/move?srcpath=" + filepath + "&destpath=" + currentPath + filename, url: "/api/fs/move",
data:{
"srcpath": filepath,
"destpath": currentPath + filename,
},
method: "POST", method: "POST",
success: function(data){ success: function(data){
if (data.error != undefined){ if (data.error != undefined){
@ -939,7 +944,7 @@
function copyFirstItemInQueueUntilAllCopied(){ function copyFirstItemInQueueUntilAllCopied(){
let file = copyPendingFiles.shift(); let file = copyPendingFiles.shift();
let startingDir = currentPath; let startingDir = currentPath;
$.ajax({ $.cjax({
url: "/api/fs/copy", url: "/api/fs/copy",
method: "POST", method: "POST",
data: { data: {

View File

@ -1,6 +1,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta name="zoraxy.csrf.Token" content="{{.csrfToken}}">
<meta name="apple-mobile-web-app-capable" content="yes" /> <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 name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1"/>
<meta charset="UTF-8"> <meta charset="UTF-8">
@ -13,6 +14,7 @@
<script src="../script/semantic/semantic.min.js"></script> <script src="../script/semantic/semantic.min.js"></script>
<script src="../script/tablesort.js"></script> <script src="../script/tablesort.js"></script>
<link rel="stylesheet" href="../main.css"> <link rel="stylesheet" href="../main.css">
<script src="../script/utils.js"></script>
<style> <style>
.offlinehost{ .offlinehost{
display: none; display: none;
@ -86,9 +88,14 @@
<div class="ui basic segment" align="center"> <div class="ui basic segment" align="center">
<i class="loading spinner icon"></i> Scanning <i class="loading spinner icon"></i> Scanning
</div>`); </div>`);
$.post("/api/tools/ipscan", {start: start, end: end}, function(data) { $.cjax({
displayResults(data); url: "/api/tools/ipscan",
$(".scanbtn").removeClass("disabled"); 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"> <div class="ui basic segment" align="center">
<i class="loading spinner icon"></i> Scanning <i class="loading spinner icon"></i> Scanning
</div>`); </div>`);
$.post("/api/tools/ipscan", {cidr: cidr}, function(data) { $.cjax({
displayResults(data); url: "/api/tools/ipscan",
$(".scanbtn").removeClass("disabled"); method: "POST",
data: {cidr: cidr},
success: function(data) {
displayResults(data);
$(".scanbtn").removeClass("disabled");
}
}); });
}); });

View File

@ -1,6 +1,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta name="zoraxy.csrf.Token" content="{{.csrfToken}}">
<meta name="apple-mobile-web-app-capable" content="yes" /> <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 name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1"/>
<meta charset="UTF-8"> <meta charset="UTF-8">
@ -13,6 +14,7 @@
<script src="../script/semantic/semantic.min.js"></script> <script src="../script/semantic/semantic.min.js"></script>
<script src="../script/tablesort.js"></script> <script src="../script/tablesort.js"></script>
<link rel="stylesheet" href="../main.css"> <link rel="stylesheet" href="../main.css">
<script src="../script/utils.js"></script>
<style> <style>
body{ body{
overflow-x: auto; overflow-x: auto;
@ -54,7 +56,7 @@
var domain = $("#domain").val(); var domain = $("#domain").val();
$("#discover").addClass("loading").addClass('disabled'); $("#discover").addClass("loading").addClass('disabled');
setCountdown(); setCountdown();
$.ajax({ $.cjax({
type: "POST", type: "POST",
url: "/api/mdns/discover", url: "/api/mdns/discover",
data: { domain: domain }, data: { domain: domain },

View File

@ -1,6 +1,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta name="zoraxy.csrf.Token" content="{{.csrfToken}}">
<meta name="apple-mobile-web-app-capable" content="yes" /> <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 name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1"/>
<meta charset="UTF-8"> <meta charset="UTF-8">
@ -13,6 +14,7 @@
<script src="../script/semantic/semantic.min.js"></script> <script src="../script/semantic/semantic.min.js"></script>
<script src="../script/tablesort.js"></script> <script src="../script/tablesort.js"></script>
<link rel="stylesheet" href="../main.css"> <link rel="stylesheet" href="../main.css">
<script src="../script/utils.js"></script>
<style> <style>
#loadingUI{ #loadingUI{
width: 100%; width: 100%;
@ -153,7 +155,7 @@
//Try to ask the server side to create a ssh proxy object //Try to ask the server side to create a ssh proxy object
function createSSHProxy(remoteAddr, remotePort, username){ function createSSHProxy(remoteAddr, remotePort, username){
//Request to create a ssh session instance //Request to create a ssh session instance
$.ajax({ $.cjax({
url: "/api/tools/webssh", url: "/api/tools/webssh",
data: {ipaddr: remoteAddr, port: remotePort, username:username}, data: {ipaddr: remoteAddr, port: remotePort, username:username},
method: "POST", method: "POST",