1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516 |
- package main
- import (
- "encoding/json"
- "net/http"
- "path/filepath"
- "sort"
- "strconv"
- "strings"
- "time"
- "imuslab.com/zoraxy/mod/auth"
- "imuslab.com/zoraxy/mod/dynamicproxy"
- "imuslab.com/zoraxy/mod/dynamicproxy/loadbalance"
- "imuslab.com/zoraxy/mod/dynamicproxy/permissionpolicy"
- "imuslab.com/zoraxy/mod/dynamicproxy/rewrite"
- "imuslab.com/zoraxy/mod/uptime"
- "imuslab.com/zoraxy/mod/utils"
- )
- var (
- dynamicProxyRouter *dynamicproxy.Router
- )
- // Add user customizable reverse proxy
- func ReverseProxtInit() {
- /*
- Load Reverse Proxy Global Settings
- */
- inboundPort := 443
- if sysdb.KeyExists("settings", "inbound") {
- sysdb.Read("settings", "inbound", &inboundPort)
- SystemWideLogger.Println("Serving inbound port ", inboundPort)
- } else {
- SystemWideLogger.Println("Inbound port not set. Using default (443)")
- }
- useTls := true
- sysdb.Read("settings", "usetls", &useTls)
- if useTls {
- SystemWideLogger.Println("TLS mode enabled. Serving proxy request with TLS")
- } else {
- SystemWideLogger.Println("TLS mode disabled. Serving proxy request with plain http")
- }
- forceLatestTLSVersion := false
- sysdb.Read("settings", "forceLatestTLS", &forceLatestTLSVersion)
- if forceLatestTLSVersion {
- SystemWideLogger.Println("Force latest TLS mode enabled. Minimum TLS LS version is set to v1.2")
- } else {
- SystemWideLogger.Println("Force latest TLS mode disabled. Minimum TLS version is set to v1.0")
- }
- developmentMode := false
- sysdb.Read("settings", "devMode", &developmentMode)
- if useTls {
- SystemWideLogger.Println("Development mode enabled. Using no-store Cache Control policy")
- } else {
- SystemWideLogger.Println("Development mode disabled. Proxying with default Cache Control policy")
- }
- listenOnPort80 := true
- sysdb.Read("settings", "listenP80", &listenOnPort80)
- if listenOnPort80 {
- SystemWideLogger.Println("Port 80 listener enabled")
- } else {
- SystemWideLogger.Println("Port 80 listener disabled")
- }
- forceHttpsRedirect := true
- sysdb.Read("settings", "redirect", &forceHttpsRedirect)
- if forceHttpsRedirect {
- SystemWideLogger.Println("Force HTTPS mode enabled")
- //Port 80 listener must be enabled to perform http -> https redirect
- listenOnPort80 = true
- } else {
- SystemWideLogger.Println("Force HTTPS mode disabled")
- }
- /*
- Create a new proxy object
- The DynamicProxy is the parent of all reverse proxy handlers,
- use for managemening and provide functions to access proxy handlers
- */
- dprouter, err := dynamicproxy.NewDynamicProxy(dynamicproxy.RouterOption{
- HostUUID: nodeUUID,
- HostVersion: SYSTEM_VERSION,
- Port: inboundPort,
- UseTls: useTls,
- ForceTLSLatest: forceLatestTLSVersion,
- NoCache: developmentMode,
- ListenOnPort80: listenOnPort80,
- ForceHttpsRedirect: forceHttpsRedirect,
- TlsManager: tlsCertManager,
- RedirectRuleTable: redirectTable,
- GeodbStore: geodbStore,
- StatisticCollector: statisticCollector,
- WebDirectory: *staticWebServerRoot,
- AccessController: accessController,
- LoadBalancer: loadBalancer,
- SSOHandler: ssoHandler,
- Logger: SystemWideLogger,
- })
- if err != nil {
- SystemWideLogger.PrintAndLog("proxy-config", "Unable to create dynamic proxy router", err)
- return
- }
- dynamicProxyRouter = dprouter
- /*
- Load all conf from files
- */
- confs, _ := filepath.Glob("./conf/proxy/*.config")
- for _, conf := range confs {
- err := LoadReverseProxyConfig(conf)
- if err != nil {
- SystemWideLogger.PrintAndLog("proxy-config", "Failed to load config file: "+filepath.Base(conf), err)
- return
- }
- }
- if dynamicProxyRouter.Root == nil {
- //Root config not set (new deployment?), use internal static web server as root
- defaultRootRouter, err := GetDefaultRootConfig()
- if err != nil {
- SystemWideLogger.PrintAndLog("proxy-config", "Failed to generate default root routing", err)
- return
- }
- dynamicProxyRouter.SetProxyRouteAsRoot(defaultRootRouter)
- }
- //Start Service
- //Not sure why but delay must be added if you have another
- //reverse proxy server in front of this service
- time.Sleep(300 * time.Millisecond)
- dynamicProxyRouter.StartProxyService()
- SystemWideLogger.Println("Dynamic Reverse Proxy service started")
- //Add all proxy services to uptime monitor
- //Create a uptime monitor service
- go func() {
- //This must be done in go routine to prevent blocking on system startup
- uptimeMonitor, _ = uptime.NewUptimeMonitor(&uptime.Config{
- Targets: GetUptimeTargetsFromReverseProxyRules(dynamicProxyRouter),
- Interval: 300, //5 minutes
- MaxRecordsStore: 288, //1 day
- Logger: SystemWideLogger, //Logger
- })
- SystemWideLogger.Println("Uptime Monitor background service started")
- }()
- }
- func ReverseProxyHandleOnOff(w http.ResponseWriter, r *http.Request) {
- enable, _ := utils.PostPara(r, "enable") //Support root, vdir and subd
- if enable == "true" {
- err := dynamicProxyRouter.StartProxyService()
- if err != nil {
- utils.SendErrorResponse(w, err.Error())
- return
- }
- } else {
- //Check if it is loopback
- if dynamicProxyRouter.IsProxiedSubdomain(r) {
- //Loopback routing. Turning it off will make the user lost control
- //of the whole system. Do not allow shutdown
- utils.SendErrorResponse(w, "Unable to shutdown in loopback rp mode. Remove proxy rules for management interface and retry.")
- return
- }
- err := dynamicProxyRouter.StopProxyService()
- if err != nil {
- utils.SendErrorResponse(w, err.Error())
- return
- }
- }
- utils.SendOK(w)
- }
- func ReverseProxyHandleAddEndpoint(w http.ResponseWriter, r *http.Request) {
- eptype, err := utils.PostPara(r, "type") //Support root and host
- if err != nil {
- utils.SendErrorResponse(w, "type not defined")
- return
- }
- endpoint, err := utils.PostPara(r, "ep")
- if err != nil {
- utils.SendErrorResponse(w, "endpoint not defined")
- return
- }
- tls, _ := utils.PostPara(r, "tls")
- if tls == "" {
- tls = "false"
- }
- useTLS := (tls == "true")
- //Bypass global TLS value / allow direct access from port 80?
- bypassGlobalTLS, _ := utils.PostPara(r, "bypassGlobalTLS")
- if bypassGlobalTLS == "" {
- bypassGlobalTLS = "false"
- }
- useBypassGlobalTLS := bypassGlobalTLS == "true"
- //Enable TLS validation?
- skipTlsValidation, _ := utils.PostBool(r, "tlsval")
- //Get access rule ID
- accessRuleID, _ := utils.PostPara(r, "access")
- if accessRuleID == "" {
- accessRuleID = "default"
- }
- if !accessController.AccessRuleExists(accessRuleID) {
- utils.SendErrorResponse(w, "invalid access rule ID selected")
- return
- }
- // Require basic auth?
- requireBasicAuth, _ := utils.PostBool(r, "bauth")
- //Use sticky session?
- useStickySession, _ := utils.PostBool(r, "stickysess")
- // Require Rate Limiting?
- requireRateLimit := false
- proxyRateLimit := 1000
- requireRateLimit, err = utils.PostBool(r, "rate")
- if err != nil {
- requireRateLimit = false
- }
- if requireRateLimit {
- proxyRateLimit, err = utils.PostInt(r, "ratenum")
- if err != nil {
- proxyRateLimit = 0
- }
- if err != nil {
- utils.SendErrorResponse(w, "invalid rate limit number")
- return
- }
- if proxyRateLimit <= 0 {
- utils.SendErrorResponse(w, "rate limit number must be greater than 0")
- return
- }
- }
- // Bypass WebSocket Origin Check
- strbpwsorg, _ := utils.PostPara(r, "bpwsorg")
- if strbpwsorg == "" {
- strbpwsorg = "false"
- }
- bypassWebsocketOriginCheck := (strbpwsorg == "true")
- //Prase the basic auth to correct structure
- cred, _ := utils.PostPara(r, "cred")
- basicAuthCredentials := []*dynamicproxy.BasicAuthCredentials{}
- if requireBasicAuth {
- preProcessCredentials := []*dynamicproxy.BasicAuthUnhashedCredentials{}
- err = json.Unmarshal([]byte(cred), &preProcessCredentials)
- if err != nil {
- utils.SendErrorResponse(w, "invalid user credentials")
- return
- }
- //Check if there are empty password credentials
- for _, credObj := range preProcessCredentials {
- if strings.TrimSpace(credObj.Password) == "" {
- utils.SendErrorResponse(w, credObj.Username+" has empty password")
- return
- }
- }
- //Convert and hash the passwords
- for _, credObj := range preProcessCredentials {
- basicAuthCredentials = append(basicAuthCredentials, &dynamicproxy.BasicAuthCredentials{
- Username: credObj.Username,
- PasswordHash: auth.Hash(credObj.Password),
- })
- }
- }
- var proxyEndpointCreated *dynamicproxy.ProxyEndpoint
- if eptype == "host" {
- rootOrMatchingDomain, err := utils.PostPara(r, "rootname")
- if err != nil {
- utils.SendErrorResponse(w, "hostname not defined")
- return
- }
- rootOrMatchingDomain = strings.TrimSpace(rootOrMatchingDomain)
- //Check if it contains ",", if yes, split the remainings as alias
- aliasHostnames := []string{}
- if strings.Contains(rootOrMatchingDomain, ",") {
- matchingDomains := strings.Split(rootOrMatchingDomain, ",")
- if len(matchingDomains) > 1 {
- rootOrMatchingDomain = matchingDomains[0]
- for _, aliasHostname := range matchingDomains[1:] {
- //Filter out any space
- aliasHostnames = append(aliasHostnames, strings.TrimSpace(aliasHostname))
- }
- }
- }
- //Generate a proxy endpoint object
- thisProxyEndpoint := dynamicproxy.ProxyEndpoint{
- //I/O
- ProxyType: dynamicproxy.ProxyType_Host,
- RootOrMatchingDomain: rootOrMatchingDomain,
- MatchingDomainAlias: aliasHostnames,
- ActiveOrigins: []*loadbalance.Upstream{
- {
- OriginIpOrDomain: endpoint,
- RequireTLS: useTLS,
- SkipCertValidations: skipTlsValidation,
- SkipWebSocketOriginCheck: bypassWebsocketOriginCheck,
- Weight: 1,
- },
- },
- InactiveOrigins: []*loadbalance.Upstream{},
- UseStickySession: useStickySession,
- //TLS
- BypassGlobalTLS: useBypassGlobalTLS,
- AccessFilterUUID: accessRuleID,
- //VDir
- VirtualDirectories: []*dynamicproxy.VirtualDirectoryEndpoint{},
- //Custom headers
- UserDefinedHeaders: []*rewrite.UserDefinedHeader{},
- //Auth
- RequireBasicAuth: requireBasicAuth,
- BasicAuthCredentials: basicAuthCredentials,
- BasicAuthExceptionRules: []*dynamicproxy.BasicAuthExceptionRule{},
- DefaultSiteOption: 0,
- DefaultSiteValue: "",
- // Rate Limit
- RequireRateLimit: requireRateLimit,
- RateLimit: int64(proxyRateLimit),
- }
- preparedEndpoint, err := dynamicProxyRouter.PrepareProxyRoute(&thisProxyEndpoint)
- if err != nil {
- utils.SendErrorResponse(w, "unable to prepare proxy route to target endpoint: "+err.Error())
- return
- }
- dynamicProxyRouter.AddProxyRouteToRuntime(preparedEndpoint)
- proxyEndpointCreated = &thisProxyEndpoint
- } else if eptype == "root" {
- //Get the default site options and target
- dsOptString, err := utils.PostPara(r, "defaultSiteOpt")
- if err != nil {
- utils.SendErrorResponse(w, "default site action not defined")
- return
- }
- var defaultSiteOption int = 1
- opt, err := strconv.Atoi(dsOptString)
- if err != nil {
- utils.SendErrorResponse(w, "invalid default site option")
- return
- }
- defaultSiteOption = opt
- dsVal, err := utils.PostPara(r, "defaultSiteVal")
- if err != nil && (defaultSiteOption == 1 || defaultSiteOption == 2) {
- //Reverse proxy or redirect, must require value to be set
- utils.SendErrorResponse(w, "target not defined")
- return
- }
- //Write the root options to file
- rootRoutingEndpoint := dynamicproxy.ProxyEndpoint{
- ProxyType: dynamicproxy.ProxyType_Root,
- RootOrMatchingDomain: "/",
- ActiveOrigins: []*loadbalance.Upstream{
- {
- OriginIpOrDomain: endpoint,
- RequireTLS: useTLS,
- SkipCertValidations: true,
- SkipWebSocketOriginCheck: true,
- Weight: 1,
- },
- },
- InactiveOrigins: []*loadbalance.Upstream{},
- BypassGlobalTLS: false,
- DefaultSiteOption: defaultSiteOption,
- DefaultSiteValue: dsVal,
- }
- preparedRootProxyRoute, err := dynamicProxyRouter.PrepareProxyRoute(&rootRoutingEndpoint)
- if err != nil {
- utils.SendErrorResponse(w, "unable to prepare root routing: "+err.Error())
- return
- }
- err = dynamicProxyRouter.SetProxyRouteAsRoot(preparedRootProxyRoute)
- if err != nil {
- utils.SendErrorResponse(w, "unable to update default site: "+err.Error())
- return
- }
- proxyEndpointCreated = &rootRoutingEndpoint
- } else {
- //Invalid eptype
- utils.SendErrorResponse(w, "invalid endpoint type")
- return
- }
- //Save the config to file
- err = SaveReverseProxyConfig(proxyEndpointCreated)
- if err != nil {
- SystemWideLogger.PrintAndLog("proxy-config", "Unable to save new proxy rule to file", err)
- return
- }
- //Update utm if exists
- UpdateUptimeMonitorTargets()
- utils.SendOK(w)
- }
- /*
- ReverseProxyHandleEditEndpoint handles proxy endpoint edit
- (host only, for root use Default Site page to edit)
- This endpoint do not handle basic auth credential update.
- The credential will be loaded from old config and reused
- */
- func ReverseProxyHandleEditEndpoint(w http.ResponseWriter, r *http.Request) {
- rootNameOrMatchingDomain, err := utils.PostPara(r, "rootname")
- if err != nil {
- utils.SendErrorResponse(w, "Target proxy rule not defined")
- return
- }
- tls, _ := utils.PostPara(r, "tls")
- if tls == "" {
- tls = "false"
- }
- useStickySession, _ := utils.PostBool(r, "ss")
- //Load bypass TLS option
- bpgtls, _ := utils.PostPara(r, "bpgtls")
- if bpgtls == "" {
- bpgtls = "false"
- }
- bypassGlobalTLS := (bpgtls == "true")
- // Basic Auth
- rba, _ := utils.PostPara(r, "bauth")
- if rba == "" {
- rba = "false"
- }
- requireBasicAuth := (rba == "true")
- // Rate Limiting?
- rl, _ := utils.PostPara(r, "rate")
- if rl == "" {
- rl = "false"
- }
- requireRateLimit := (rl == "true")
- rlnum, _ := utils.PostPara(r, "ratenum")
- if rlnum == "" {
- rlnum = "0"
- }
- proxyRateLimit, err := strconv.ParseInt(rlnum, 10, 64)
- if err != nil {
- utils.SendErrorResponse(w, "invalid rate limit number")
- return
- }
- if requireRateLimit && proxyRateLimit <= 0 {
- utils.SendErrorResponse(w, "rate limit number must be greater than 0")
- return
- } else if proxyRateLimit < 0 {
- proxyRateLimit = 1000
- }
- //Load the previous basic auth credentials from current proxy rules
- targetProxyEntry, err := dynamicProxyRouter.LoadProxy(rootNameOrMatchingDomain)
- if err != nil {
- utils.SendErrorResponse(w, "Target proxy config not found or could not be loaded")
- return
- }
- //Generate a new proxyEndpoint from the new config
- newProxyEndpoint := dynamicproxy.CopyEndpoint(targetProxyEntry)
- newProxyEndpoint.BypassGlobalTLS = bypassGlobalTLS
- newProxyEndpoint.RequireBasicAuth = requireBasicAuth
- newProxyEndpoint.RequireRateLimit = requireRateLimit
- newProxyEndpoint.RateLimit = proxyRateLimit
- newProxyEndpoint.UseStickySession = useStickySession
- //Prepare to replace the current routing rule
- readyRoutingRule, err := dynamicProxyRouter.PrepareProxyRoute(newProxyEndpoint)
- if err != nil {
- utils.SendErrorResponse(w, err.Error())
- return
- }
- targetProxyEntry.Remove()
- dynamicProxyRouter.AddProxyRouteToRuntime(readyRoutingRule)
- //Save it to file
- SaveReverseProxyConfig(newProxyEndpoint)
- //Update uptime monitor targets
- UpdateUptimeMonitorTargets()
- utils.SendOK(w)
- }
- func ReverseProxyHandleAlias(w http.ResponseWriter, r *http.Request) {
- rootNameOrMatchingDomain, err := utils.PostPara(r, "ep")
- if err != nil {
- utils.SendErrorResponse(w, "Invalid ep given")
- return
- }
- //No need to check for type as root (/) can be set to default route
- //and hence, you will not need alias
- //Load the previous alias from current proxy rules
- targetProxyEntry, err := dynamicProxyRouter.LoadProxy(rootNameOrMatchingDomain)
- if err != nil {
- utils.SendErrorResponse(w, "Target proxy config not found or could not be loaded")
- return
- }
- newAliasJSON, err := utils.PostPara(r, "alias")
- if err != nil {
- //No new set of alias given
- utils.SendErrorResponse(w, "new alias not given")
- return
- }
- //Write new alias to runtime and file
- newAlias := []string{}
- err = json.Unmarshal([]byte(newAliasJSON), &newAlias)
- if err != nil {
- SystemWideLogger.PrintAndLog("proxy-config", "Unable to parse new alias list", err)
- utils.SendErrorResponse(w, "Invalid alias list given")
- return
- }
- //Set the current alias
- newProxyEndpoint := dynamicproxy.CopyEndpoint(targetProxyEntry)
- newProxyEndpoint.MatchingDomainAlias = newAlias
- // Prepare to replace the current routing rule
- readyRoutingRule, err := dynamicProxyRouter.PrepareProxyRoute(newProxyEndpoint)
- if err != nil {
- utils.SendErrorResponse(w, err.Error())
- return
- }
- targetProxyEntry.Remove()
- dynamicProxyRouter.AddProxyRouteToRuntime(readyRoutingRule)
- // Save it to file
- err = SaveReverseProxyConfig(newProxyEndpoint)
- if err != nil {
- utils.SendErrorResponse(w, "Alias update failed")
- SystemWideLogger.PrintAndLog("proxy-config", "Unable to save alias update", err)
- }
- utils.SendOK(w)
- }
- func DeleteProxyEndpoint(w http.ResponseWriter, r *http.Request) {
- ep, err := utils.PostPara(r, "ep")
- if err != nil {
- utils.SendErrorResponse(w, "Invalid ep given")
- return
- }
- //Remove the config from runtime
- err = dynamicProxyRouter.RemoveProxyEndpointByRootname(ep)
- if err != nil {
- utils.SendErrorResponse(w, err.Error())
- return
- }
- //Remove the config from file
- err = RemoveReverseProxyConfig(ep)
- if err != nil {
- utils.SendErrorResponse(w, err.Error())
- return
- }
- //Update uptime monitor
- UpdateUptimeMonitorTargets()
- utils.SendOK(w)
- }
- /*
- Handle update request for basic auth credential
- Require paramter: ep (Endpoint) and pytype (proxy Type)
- if request with GET, the handler will return current credentials
- on this endpoint by its username
- if request is POST, the handler will write the results to proxy config
- */
- func UpdateProxyBasicAuthCredentials(w http.ResponseWriter, r *http.Request) {
- if r.Method == http.MethodGet {
- ep, err := utils.GetPara(r, "ep")
- if err != nil {
- utils.SendErrorResponse(w, "Invalid ep given")
- return
- }
- //Load the target proxy object from router
- targetProxy, err := dynamicProxyRouter.LoadProxy(ep)
- if err != nil {
- utils.SendErrorResponse(w, err.Error())
- return
- }
- usernames := []string{}
- for _, cred := range targetProxy.BasicAuthCredentials {
- usernames = append(usernames, cred.Username)
- }
- js, _ := json.Marshal(usernames)
- utils.SendJSONResponse(w, string(js))
- } else if r.Method == http.MethodPost {
- //Write to target
- ep, err := utils.PostPara(r, "ep")
- if err != nil {
- utils.SendErrorResponse(w, "Invalid ep given")
- return
- }
- creds, err := utils.PostPara(r, "creds")
- if err != nil {
- utils.SendErrorResponse(w, "Invalid ptype given")
- return
- }
- //Load the target proxy object from router
- targetProxy, err := dynamicProxyRouter.LoadProxy(ep)
- if err != nil {
- utils.SendErrorResponse(w, err.Error())
- return
- }
- //Try to marshal the content of creds into the suitable structure
- newCredentials := []*dynamicproxy.BasicAuthUnhashedCredentials{}
- err = json.Unmarshal([]byte(creds), &newCredentials)
- if err != nil {
- utils.SendErrorResponse(w, "Malformed credential data")
- return
- }
- //Merge the credentials into the original config
- //If a new username exists in old config with no pw given, keep the old pw hash
- //If a new username is found with new password, hash it and push to credential slice
- mergedCredentials := []*dynamicproxy.BasicAuthCredentials{}
- for _, credential := range newCredentials {
- if credential.Password == "" {
- //Check if exists in the old credential files
- keepUnchange := false
- for _, oldCredEntry := range targetProxy.BasicAuthCredentials {
- if oldCredEntry.Username == credential.Username {
- //Exists! Reuse the old hash
- mergedCredentials = append(mergedCredentials, &dynamicproxy.BasicAuthCredentials{
- Username: oldCredEntry.Username,
- PasswordHash: oldCredEntry.PasswordHash,
- })
- keepUnchange = true
- }
- }
- if !keepUnchange {
- //This is a new username with no pw given
- utils.SendErrorResponse(w, "Access password for "+credential.Username+" is empty!")
- return
- }
- } else {
- //This username have given password
- mergedCredentials = append(mergedCredentials, &dynamicproxy.BasicAuthCredentials{
- Username: credential.Username,
- PasswordHash: auth.Hash(credential.Password),
- })
- }
- }
- targetProxy.BasicAuthCredentials = mergedCredentials
- //Save it to file
- SaveReverseProxyConfig(targetProxy)
- //Replace runtime configuration
- targetProxy.UpdateToRuntime()
- utils.SendOK(w)
- } else {
- http.Error(w, "invalid usage", http.StatusMethodNotAllowed)
- }
- }
- // List, Update or Remove the exception paths for basic auth.
- func ListProxyBasicAuthExceptionPaths(w http.ResponseWriter, r *http.Request) {
- if r.Method != http.MethodGet {
- http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
- }
- ep, err := utils.GetPara(r, "ep")
- if err != nil {
- utils.SendErrorResponse(w, "Invalid ep given")
- return
- }
- //Load the target proxy object from router
- targetProxy, err := dynamicProxyRouter.LoadProxy(ep)
- if err != nil {
- utils.SendErrorResponse(w, err.Error())
- return
- }
- //List all the exception paths for this proxy
- results := targetProxy.BasicAuthExceptionRules
- if results == nil {
- //It is a config from a really old version of zoraxy. Overwrite it with empty array
- results = []*dynamicproxy.BasicAuthExceptionRule{}
- }
- js, _ := json.Marshal(results)
- utils.SendJSONResponse(w, string(js))
- return
- }
- func AddProxyBasicAuthExceptionPaths(w http.ResponseWriter, r *http.Request) {
- ep, err := utils.PostPara(r, "ep")
- if err != nil {
- utils.SendErrorResponse(w, "Invalid ep given")
- return
- }
- matchingPrefix, err := utils.PostPara(r, "prefix")
- if err != nil {
- utils.SendErrorResponse(w, "Invalid matching prefix given")
- return
- }
- //Load the target proxy object from router
- targetProxy, err := dynamicProxyRouter.LoadProxy(ep)
- if err != nil {
- utils.SendErrorResponse(w, err.Error())
- return
- }
- //Check if the prefix starts with /. If not, prepend it
- if !strings.HasPrefix(matchingPrefix, "/") {
- matchingPrefix = "/" + matchingPrefix
- }
- //Add a new exception rule if it is not already exists
- alreadyExists := false
- for _, thisExceptionRule := range targetProxy.BasicAuthExceptionRules {
- if thisExceptionRule.PathPrefix == matchingPrefix {
- alreadyExists = true
- break
- }
- }
- if alreadyExists {
- utils.SendErrorResponse(w, "This matching path already exists")
- return
- }
- targetProxy.BasicAuthExceptionRules = append(targetProxy.BasicAuthExceptionRules, &dynamicproxy.BasicAuthExceptionRule{
- PathPrefix: strings.TrimSpace(matchingPrefix),
- })
- //Save configs to runtime and file
- targetProxy.UpdateToRuntime()
- SaveReverseProxyConfig(targetProxy)
- utils.SendOK(w)
- }
- func RemoveProxyBasicAuthExceptionPaths(w http.ResponseWriter, r *http.Request) {
- // Delete a rule
- ep, err := utils.PostPara(r, "ep")
- if err != nil {
- utils.SendErrorResponse(w, "Invalid ep given")
- return
- }
- matchingPrefix, err := utils.PostPara(r, "prefix")
- if err != nil {
- utils.SendErrorResponse(w, "Invalid matching prefix given")
- return
- }
- // Load the target proxy object from router
- targetProxy, err := dynamicProxyRouter.LoadProxy(ep)
- if err != nil {
- utils.SendErrorResponse(w, err.Error())
- return
- }
- newExceptionRuleList := []*dynamicproxy.BasicAuthExceptionRule{}
- matchingExists := false
- for _, thisExceptionalRule := range targetProxy.BasicAuthExceptionRules {
- if thisExceptionalRule.PathPrefix != matchingPrefix {
- newExceptionRuleList = append(newExceptionRuleList, thisExceptionalRule)
- } else {
- matchingExists = true
- }
- }
- if !matchingExists {
- utils.SendErrorResponse(w, "target matching rule not exists")
- return
- }
- targetProxy.BasicAuthExceptionRules = newExceptionRuleList
- // Save configs to runtime and file
- targetProxy.UpdateToRuntime()
- SaveReverseProxyConfig(targetProxy)
- utils.SendOK(w)
- }
- // Report the current status of the reverse proxy server
- func ReverseProxyStatus(w http.ResponseWriter, r *http.Request) {
- js, _ := json.Marshal(dynamicProxyRouter)
- utils.SendJSONResponse(w, string(js))
- }
- // Toggle a certain rule on and off
- func ReverseProxyToggleRuleSet(w http.ResponseWriter, r *http.Request) {
- //No need to check for type as root cannot be turned off
- ep, err := utils.PostPara(r, "ep")
- if err != nil {
- utils.SendErrorResponse(w, "invalid ep given")
- return
- }
- targetProxyRule, err := dynamicProxyRouter.LoadProxy(ep)
- if err != nil {
- utils.SendErrorResponse(w, "invalid endpoint given")
- return
- }
- enableStr, err := utils.PostPara(r, "enable")
- if err != nil {
- enableStr = "true"
- }
- //Flip the enable and disabled tag state
- ruleDisabled := enableStr == "false"
- targetProxyRule.Disabled = ruleDisabled
- err = SaveReverseProxyConfig(targetProxyRule)
- if err != nil {
- utils.SendErrorResponse(w, "unable to save updated rule")
- return
- }
- //Update uptime monitor
- UpdateUptimeMonitorTargets()
- utils.SendOK(w)
- }
- func ReverseProxyListDetail(w http.ResponseWriter, r *http.Request) {
- eptype, err := utils.PostPara(r, "type") //Support root and host
- if err != nil {
- utils.SendErrorResponse(w, "type not defined")
- return
- }
- if eptype == "host" {
- epname, err := utils.PostPara(r, "epname")
- if err != nil {
- utils.SendErrorResponse(w, "epname not defined")
- return
- }
- endpointRaw, ok := dynamicProxyRouter.ProxyEndpoints.Load(epname)
- if !ok {
- utils.SendErrorResponse(w, "proxy rule not found")
- return
- }
- targetEndpoint := dynamicproxy.CopyEndpoint(endpointRaw.(*dynamicproxy.ProxyEndpoint))
- js, _ := json.Marshal(targetEndpoint)
- utils.SendJSONResponse(w, string(js))
- } else if eptype == "root" {
- js, _ := json.Marshal(dynamicProxyRouter.Root)
- utils.SendJSONResponse(w, string(js))
- } else {
- utils.SendErrorResponse(w, "Invalid type given")
- }
- }
- func ReverseProxyList(w http.ResponseWriter, r *http.Request) {
- eptype, err := utils.PostPara(r, "type") //Support root and host
- if err != nil {
- utils.SendErrorResponse(w, "type not defined")
- return
- }
- if eptype == "host" {
- results := []*dynamicproxy.ProxyEndpoint{}
- dynamicProxyRouter.ProxyEndpoints.Range(func(key, value interface{}) bool {
- thisEndpoint := dynamicproxy.CopyEndpoint(value.(*dynamicproxy.ProxyEndpoint))
- //Clear the auth passwords before showing to front-end
- cleanedCredentials := []*dynamicproxy.BasicAuthCredentials{}
- for _, user := range thisEndpoint.BasicAuthCredentials {
- cleanedCredentials = append(cleanedCredentials, &dynamicproxy.BasicAuthCredentials{
- Username: user.Username,
- PasswordHash: "",
- })
- }
- thisEndpoint.BasicAuthCredentials = cleanedCredentials
- results = append(results, thisEndpoint)
- return true
- })
- sort.Slice(results, func(i, j int) bool {
- return results[i].RootOrMatchingDomain < results[j].RootOrMatchingDomain
- })
- js, _ := json.Marshal(results)
- utils.SendJSONResponse(w, string(js))
- } else if eptype == "root" {
- js, _ := json.Marshal(dynamicProxyRouter.Root)
- utils.SendJSONResponse(w, string(js))
- } else {
- utils.SendErrorResponse(w, "Invalid type given")
- }
- }
- // Handle port 80 incoming traffics
- func HandleUpdatePort80Listener(w http.ResponseWriter, r *http.Request) {
- if r.Method == http.MethodGet {
- //Load the current status
- currentEnabled := false
- 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 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")
- dynamicProxyRouter.UpdatePort80ListenerState(true)
- } else if enabled == "false" {
- sysdb.Write("settings", "listenP80", false)
- SystemWideLogger.Println("Disabling port 80 listener")
- dynamicProxyRouter.UpdatePort80ListenerState(false)
- } else {
- 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) {
- if r.Method == http.MethodGet {
- currentRedirectToHttps := false
- //Load the current status
- 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 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 {
- sysdb.Write("settings", "redirect", true)
- SystemWideLogger.Println("Updating force HTTPS redirection to true")
- dynamicProxyRouter.UpdateHttpToHttpsRedirectSetting(true)
- } 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)
- }
- }
- // Handle checking if the current user is accessing via the reverse proxied interface
- // Of the management interface.
- func HandleManagementProxyCheck(w http.ResponseWriter, r *http.Request) {
- isProxied := dynamicProxyRouter.IsProxiedSubdomain(r)
- js, _ := json.Marshal(isProxied)
- utils.SendJSONResponse(w, string(js))
- }
- func HandleDevelopmentModeChange(w http.ResponseWriter, r *http.Request) {
- enableDevelopmentModeStr, err := utils.GetPara(r, "enable")
- if err != nil {
- //Load the current development mode toggle state
- js, _ := json.Marshal(dynamicProxyRouter.Option.NoCache)
- utils.SendJSONResponse(w, string(js))
- } else {
- //Write changes to runtime
- enableDevelopmentMode := false
- if enableDevelopmentModeStr == "true" {
- enableDevelopmentMode = true
- }
- //Write changes to runtime
- dynamicProxyRouter.Option.NoCache = enableDevelopmentMode
- //Write changes to database
- sysdb.Write("settings", "devMode", enableDevelopmentMode)
- utils.SendOK(w)
- }
- }
- // Handle incoming port set. Change the current proxy incoming port
- func HandleIncomingPortSet(w http.ResponseWriter, r *http.Request) {
- newIncomingPort, err := utils.PostPara(r, "incoming")
- if err != nil {
- utils.SendErrorResponse(w, "invalid incoming port given")
- return
- }
- newIncomingPortInt, err := strconv.Atoi(newIncomingPort)
- if err != nil {
- utils.SendErrorResponse(w, "Invalid incoming port given")
- return
- }
- rootProxyTargetOrigin := ""
- if len(dynamicProxyRouter.Root.ActiveOrigins) > 0 {
- rootProxyTargetOrigin = dynamicProxyRouter.Root.ActiveOrigins[0].OriginIpOrDomain
- }
- //Check if it is identical as proxy root (recursion!)
- if dynamicProxyRouter.Root == nil || rootProxyTargetOrigin == "" {
- //Check if proxy root is set before checking recursive listen
- //Fixing issue #43
- utils.SendErrorResponse(w, "Set Proxy Root before changing inbound port")
- return
- }
- proxyRoot := strings.TrimSuffix(rootProxyTargetOrigin, "/")
- if strings.EqualFold(proxyRoot, "localhost:"+strconv.Itoa(newIncomingPortInt)) || strings.EqualFold(proxyRoot, "127.0.0.1:"+strconv.Itoa(newIncomingPortInt)) {
- //Listening port is same as proxy root
- //Not allow recursive settings
- utils.SendErrorResponse(w, "Recursive listening port! Check your proxy root settings.")
- return
- }
- //Stop and change the setting of the reverse proxy service
- if dynamicProxyRouter.Running {
- dynamicProxyRouter.StopProxyService()
- dynamicProxyRouter.Option.Port = newIncomingPortInt
- time.Sleep(1 * time.Second) //Fixed start fail issue
- dynamicProxyRouter.StartProxyService()
- } else {
- //Only change setting but not starting the proxy service
- dynamicProxyRouter.Option.Port = newIncomingPortInt
- }
- sysdb.Write("settings", "inbound", newIncomingPortInt)
- utils.SendOK(w)
- }
- /* Handle Custom Header Rules */
- //List all the custom header defined in this proxy rule
- func HandleCustomHeaderList(w http.ResponseWriter, r *http.Request) {
- epType, err := utils.GetPara(r, "type")
- if err != nil {
- utils.SendErrorResponse(w, "endpoint type not defined")
- return
- }
- domain, err := utils.GetPara(r, "domain")
- if err != nil {
- utils.SendErrorResponse(w, "domain or matching rule not defined")
- return
- }
- var targetProxyEndpoint *dynamicproxy.ProxyEndpoint
- if epType == "root" {
- targetProxyEndpoint = dynamicProxyRouter.Root
- } else {
- ep, err := dynamicProxyRouter.LoadProxy(domain)
- if err != nil {
- utils.SendErrorResponse(w, "target endpoint not exists")
- return
- }
- targetProxyEndpoint = ep
- }
- //List all custom headers
- customHeaderList := targetProxyEndpoint.UserDefinedHeaders
- if customHeaderList == nil {
- customHeaderList = []*rewrite.UserDefinedHeader{}
- }
- js, _ := json.Marshal(customHeaderList)
- utils.SendJSONResponse(w, string(js))
- }
- // Add a new header to the target endpoint
- func HandleCustomHeaderAdd(w http.ResponseWriter, r *http.Request) {
- rewriteType, err := utils.PostPara(r, "type")
- if err != nil {
- utils.SendErrorResponse(w, "rewriteType not defined")
- return
- }
- domain, err := utils.PostPara(r, "domain")
- if err != nil {
- utils.SendErrorResponse(w, "domain or matching rule not defined")
- return
- }
- direction, err := utils.PostPara(r, "direction")
- if err != nil {
- utils.SendErrorResponse(w, "HTTP modifiy direction not set")
- return
- }
- name, err := utils.PostPara(r, "name")
- if err != nil {
- utils.SendErrorResponse(w, "HTTP header name not set")
- return
- }
- value, err := utils.PostPara(r, "value")
- if err != nil && rewriteType == "add" {
- utils.SendErrorResponse(w, "HTTP header value not set")
- return
- }
- targetProxyEndpoint, err := dynamicProxyRouter.LoadProxy(domain)
- if err != nil {
- utils.SendErrorResponse(w, "target endpoint not exists")
- return
- }
- //Create a Custom Header Definition type
- var rewriteDirection rewrite.HeaderDirection
- if direction == "toOrigin" {
- rewriteDirection = rewrite.HeaderDirection_ZoraxyToUpstream
- } else if direction == "toClient" {
- rewriteDirection = rewrite.HeaderDirection_ZoraxyToDownstream
- } else {
- //Unknown direction
- utils.SendErrorResponse(w, "header rewrite direction not supported")
- return
- }
- isRemove := false
- if rewriteType == "remove" {
- isRemove = true
- }
- headerRewriteDefinition := rewrite.UserDefinedHeader{
- Key: name,
- Value: value,
- Direction: rewriteDirection,
- IsRemove: isRemove,
- }
- //Create a new custom header object
- err = targetProxyEndpoint.AddUserDefinedHeader(&headerRewriteDefinition)
- if err != nil {
- utils.SendErrorResponse(w, "unable to add header rewrite rule: "+err.Error())
- return
- }
- //Save it (no need reload as header are not handled by dpcore)
- err = SaveReverseProxyConfig(targetProxyEndpoint)
- if err != nil {
- utils.SendErrorResponse(w, "unable to save update")
- return
- }
- utils.SendOK(w)
- }
- // Remove a header from the target endpoint
- func HandleCustomHeaderRemove(w http.ResponseWriter, r *http.Request) {
- domain, err := utils.PostPara(r, "domain")
- if err != nil {
- utils.SendErrorResponse(w, "domain or matching rule not defined")
- return
- }
- name, err := utils.PostPara(r, "name")
- if err != nil {
- utils.SendErrorResponse(w, "HTTP header name not set")
- return
- }
- targetProxyEndpoint, err := dynamicProxyRouter.LoadProxy(domain)
- if err != nil {
- utils.SendErrorResponse(w, "target endpoint not exists")
- return
- }
- err = targetProxyEndpoint.RemoveUserDefinedHeader(name)
- if err != nil {
- utils.SendErrorResponse(w, "unable to remove header rewrite rule: "+err.Error())
- return
- }
- err = SaveReverseProxyConfig(targetProxyEndpoint)
- if err != nil {
- utils.SendErrorResponse(w, "unable to save update")
- return
- }
- utils.SendOK(w)
- }
- func HandleHostOverwrite(w http.ResponseWriter, r *http.Request) {
- domain, err := utils.PostPara(r, "domain")
- if err != nil {
- domain, err = utils.GetPara(r, "domain")
- if err != nil {
- utils.SendErrorResponse(w, "domain or matching rule not defined")
- return
- }
- }
- //Get the proxy endpoint object dedicated to this domain
- targetProxyEndpoint, err := dynamicProxyRouter.LoadProxy(domain)
- if err != nil {
- utils.SendErrorResponse(w, "target endpoint not exists")
- return
- }
- if r.Method == http.MethodGet {
- //Get the current host header
- js, _ := json.Marshal(targetProxyEndpoint.RequestHostOverwrite)
- utils.SendJSONResponse(w, string(js))
- } else if r.Method == http.MethodPost {
- //Set the new host header
- newHostname, _ := utils.PostPara(r, "hostname")
- //As this will require change in the proxy instance we are running
- //we need to clone and respawn this proxy endpoint
- newProxyEndpoint := targetProxyEndpoint.Clone()
- newProxyEndpoint.RequestHostOverwrite = newHostname
- //Save proxy endpoint
- err = SaveReverseProxyConfig(newProxyEndpoint)
- if err != nil {
- utils.SendErrorResponse(w, err.Error())
- return
- }
- //Spawn a new endpoint with updated dpcore
- preparedEndpoint, err := dynamicProxyRouter.PrepareProxyRoute(newProxyEndpoint)
- if err != nil {
- utils.SendErrorResponse(w, err.Error())
- return
- }
- //Remove the old endpoint
- err = targetProxyEndpoint.Remove()
- if err != nil {
- utils.SendErrorResponse(w, err.Error())
- return
- }
- //Add the newly prepared endpoint to runtime
- err = dynamicProxyRouter.AddProxyRouteToRuntime(preparedEndpoint)
- if err != nil {
- utils.SendErrorResponse(w, err.Error())
- return
- }
- //Print log message
- if newHostname != "" {
- SystemWideLogger.Println("Updated " + domain + " hostname overwrite to: " + newHostname)
- } else {
- SystemWideLogger.Println("Removed " + domain + " hostname overwrite")
- }
- utils.SendOK(w)
- } else {
- //Invalid method
- http.Error(w, "405 - Method not allowed", http.StatusMethodNotAllowed)
- }
- }
- // HandleHopByHop get and set the hop by hop remover state
- // note that it shows the DISABLE STATE of hop-by-hop remover, not the enable state
- func HandleHopByHop(w http.ResponseWriter, r *http.Request) {
- domain, err := utils.PostPara(r, "domain")
- if err != nil {
- domain, err = utils.GetPara(r, "domain")
- if err != nil {
- utils.SendErrorResponse(w, "domain or matching rule not defined")
- return
- }
- }
- targetProxyEndpoint, err := dynamicProxyRouter.LoadProxy(domain)
- if err != nil {
- utils.SendErrorResponse(w, "target endpoint not exists")
- return
- }
- if r.Method == http.MethodGet {
- //Get the current hop by hop header state
- js, _ := json.Marshal(!targetProxyEndpoint.DisableHopByHopHeaderRemoval)
- utils.SendJSONResponse(w, string(js))
- } else if r.Method == http.MethodPost {
- //Set the hop by hop header state
- enableHopByHopRemover, _ := utils.PostBool(r, "removeHopByHop")
- //As this will require change in the proxy instance we are running
- //we need to clone and respawn this proxy endpoint
- newProxyEndpoint := targetProxyEndpoint.Clone()
- //Storage file use false as default, so disable removal = not enable remover
- newProxyEndpoint.DisableHopByHopHeaderRemoval = !enableHopByHopRemover
- //Save proxy endpoint
- err = SaveReverseProxyConfig(newProxyEndpoint)
- if err != nil {
- utils.SendErrorResponse(w, err.Error())
- return
- }
- //Spawn a new endpoint with updated dpcore
- preparedEndpoint, err := dynamicProxyRouter.PrepareProxyRoute(newProxyEndpoint)
- if err != nil {
- utils.SendErrorResponse(w, err.Error())
- return
- }
- //Remove the old endpoint
- err = targetProxyEndpoint.Remove()
- if err != nil {
- utils.SendErrorResponse(w, err.Error())
- return
- }
- //Add the newly prepared endpoint to runtime
- err = dynamicProxyRouter.AddProxyRouteToRuntime(preparedEndpoint)
- if err != nil {
- utils.SendErrorResponse(w, err.Error())
- return
- }
- //Print log message
- if enableHopByHopRemover {
- SystemWideLogger.Println("Enabled hop-by-hop headers removal on " + domain)
- } else {
- SystemWideLogger.Println("Disabled hop-by-hop headers removal on " + domain)
- }
- utils.SendOK(w)
- } else {
- http.Error(w, "405 - Method not allowed", http.StatusMethodNotAllowed)
- }
- }
- // Handle view or edit HSTS states
- func HandleHSTSState(w http.ResponseWriter, r *http.Request) {
- domain, err := utils.PostPara(r, "domain")
- if err != nil {
- domain, err = utils.GetPara(r, "domain")
- if err != nil {
- utils.SendErrorResponse(w, "domain or matching rule not defined")
- return
- }
- }
- targetProxyEndpoint, err := dynamicProxyRouter.LoadProxy(domain)
- if err != nil {
- utils.SendErrorResponse(w, "target endpoint not exists")
- return
- }
- if r.Method == http.MethodGet {
- //Return current HSTS enable state
- hstsAge := targetProxyEndpoint.HSTSMaxAge
- js, _ := json.Marshal(hstsAge)
- utils.SendJSONResponse(w, string(js))
- return
- } else if r.Method == http.MethodPost {
- newMaxAge, err := utils.PostInt(r, "maxage")
- if err != nil {
- utils.SendErrorResponse(w, "maxage not defeined")
- return
- }
- if newMaxAge == 0 || newMaxAge >= 31536000 {
- targetProxyEndpoint.HSTSMaxAge = int64(newMaxAge)
- SaveReverseProxyConfig(targetProxyEndpoint)
- targetProxyEndpoint.UpdateToRuntime()
- } else {
- utils.SendErrorResponse(w, "invalid max age given")
- return
- }
- utils.SendOK(w)
- return
- }
- http.Error(w, "405 - Method not allowed", http.StatusMethodNotAllowed)
- }
- // HandlePermissionPolicy handle read or write to permission policy
- func HandlePermissionPolicy(w http.ResponseWriter, r *http.Request) {
- domain, err := utils.PostPara(r, "domain")
- if err != nil {
- domain, err = utils.GetPara(r, "domain")
- if err != nil {
- utils.SendErrorResponse(w, "domain or matching rule not defined")
- return
- }
- }
- targetProxyEndpoint, err := dynamicProxyRouter.LoadProxy(domain)
- if err != nil {
- utils.SendErrorResponse(w, "target endpoint not exists")
- return
- }
- if r.Method == http.MethodGet {
- type CurrentPolicyState struct {
- PPEnabled bool
- CurrentPolicy *permissionpolicy.PermissionsPolicy
- }
- currentPolicy := permissionpolicy.GetDefaultPermissionPolicy()
- if targetProxyEndpoint.PermissionPolicy != nil {
- currentPolicy = targetProxyEndpoint.PermissionPolicy
- }
- result := CurrentPolicyState{
- PPEnabled: targetProxyEndpoint.EnablePermissionPolicyHeader,
- CurrentPolicy: currentPolicy,
- }
- js, _ := json.Marshal(result)
- utils.SendJSONResponse(w, string(js))
- return
- } else if r.Method == http.MethodPost {
- //Update the enable state of permission policy
- enableState, err := utils.PostBool(r, "enable")
- if err != nil {
- utils.SendErrorResponse(w, "invalid enable state given")
- return
- }
- targetProxyEndpoint.EnablePermissionPolicyHeader = enableState
- SaveReverseProxyConfig(targetProxyEndpoint)
- targetProxyEndpoint.UpdateToRuntime()
- utils.SendOK(w)
- return
- } else if r.Method == http.MethodPut {
- //Store the new permission policy
- newPermissionPolicyJSONString, err := utils.PostPara(r, "pp")
- if err != nil {
- utils.SendErrorResponse(w, "missing pp (permission policy) paramter")
- return
- }
- //Parse the permission policy from JSON string
- newPermissionPolicy := permissionpolicy.GetDefaultPermissionPolicy()
- err = json.Unmarshal([]byte(newPermissionPolicyJSONString), &newPermissionPolicy)
- if err != nil {
- utils.SendErrorResponse(w, "permission policy parse error: "+err.Error())
- return
- }
- //Save it to file
- targetProxyEndpoint.PermissionPolicy = newPermissionPolicy
- SaveReverseProxyConfig(targetProxyEndpoint)
- targetProxyEndpoint.UpdateToRuntime()
- utils.SendOK(w)
- return
- }
- http.Error(w, "405 - Method not allowed", http.StatusMethodNotAllowed)
- }
|