From ee406aeecfb26a19efa5513f8e9d6a27cc045825 Mon Sep 17 00:00:00 2001 From: Ronni Skansing Date: Wed, 15 Oct 2025 22:44:35 +0200 Subject: [PATCH] nil checks Signed-off-by: Ronni Skansing --- backend/proxy/proxy.go | 128 +++++++++++++++++++++++---------------- backend/service/proxy.go | 50 ++++++++------- 2 files changed, 103 insertions(+), 75 deletions(-) diff --git a/backend/proxy/proxy.go b/backend/proxy/proxy.go index 6df3d10..969991a 100644 --- a/backend/proxy/proxy.go +++ b/backend/proxy/proxy.go @@ -573,9 +573,11 @@ func (m *ProxyHandler) applyCustomResponseHeaderReplacements(resp *http.Response session.Config.Range(func(key, value interface{}) bool { hostConfig := value.(service.ProxyServiceDomainConfig) - for _, replacement := range hostConfig.Rewrite { - if replacement.From == "response_header" || replacement.From == "any" { - headers = m.applyReplacement(headers, replacement, session.ID) + if hostConfig.Rewrite != nil { + for _, replacement := range hostConfig.Rewrite { + if replacement.From == "response_header" || replacement.From == "any" { + headers = m.applyReplacement(headers, replacement, session.ID) + } } } return true @@ -986,9 +988,11 @@ func (m *ProxyHandler) findSessionByCampaignRecipient(campaignRecipientID *uuid. func (m *ProxyHandler) initializeRequiredCaptures(session *ProxySession) { session.Config.Range(func(key, value interface{}) bool { hostConfig := value.(service.ProxyServiceDomainConfig) - for _, capture := range hostConfig.Capture { - if capture.Required == nil || *capture.Required { - session.RequiredCaptures.Store(capture.Name, false) + if hostConfig.Capture != nil { + for _, capture := range hostConfig.Capture { + if capture.Required == nil || *capture.Required { + session.RequiredCaptures.Store(capture.Name, false) + } } } return true @@ -1004,9 +1008,11 @@ func (m *ProxyHandler) onRequestBody(req *http.Request, session *ProxySession) { hostConfig := hostConfigInterface.(service.ProxyServiceDomainConfig) body := m.readRequestBody(req) - for _, capture := range hostConfig.Capture { - if m.shouldApplyCaptureRule(capture, "request_body", req) { - m.captureFromText(string(body), capture, session, req, "request_body") + if hostConfig.Capture != nil { + for _, capture := range hostConfig.Capture { + if m.shouldApplyCaptureRule(capture, "request_body", req) { + m.captureFromText(string(body), capture, session, req, "request_body") + } } } @@ -1023,9 +1029,11 @@ func (m *ProxyHandler) onRequestHeader(req *http.Request, session *ProxySession) var buf bytes.Buffer req.Header.Write(&buf) - for _, capture := range hostConfig.Capture { - if m.shouldApplyCaptureRule(capture, "request_header", req) { - m.captureFromText(buf.String(), capture, session, req, "request_header") + if hostConfig.Capture != nil { + for _, capture := range hostConfig.Capture { + if m.shouldApplyCaptureRule(capture, "request_header", req) { + m.captureFromText(buf.String(), capture, session, req, "request_header") + } } } } @@ -1043,12 +1051,14 @@ func (m *ProxyHandler) onResponseBody(resp *http.Response, body []byte, session hostConfig := hostConfigInterface.(service.ProxyServiceDomainConfig) - for _, capture := range hostConfig.Capture { - if m.shouldProcessResponseBodyCapture(capture, resp.Request) { - if capture.Find == "" { - m.handlePathBasedCapture(capture, session, resp) - } else { - m.captureFromText(string(body), capture, session, resp.Request, "response_body") + if hostConfig.Capture != nil { + for _, capture := range hostConfig.Capture { + if m.shouldProcessResponseBodyCapture(capture, resp.Request) { + if capture.Find == "" { + m.handlePathBasedCapture(capture, session, resp) + } else { + m.captureFromText(string(body), capture, session, resp.Request, "response_body") + } } } } @@ -1068,17 +1078,19 @@ func (m *ProxyHandler) onResponseCookies(resp *http.Response, session *ProxySess capturedCookies := make(map[string]map[string]string) - for _, capture := range hostConfig.Capture { - if capture.From == "cookie" && m.matchesPath(capture, resp.Request) { - if cookieData := m.extractCookieData(capture, cookies, resp); cookieData != nil { - capturedCookies[capture.Name] = cookieData - // always overwrite cookie data to ensure we have the latest cookies - // this is important for scenarios like failed login -> successful login - session.CapturedData.Store(capture.Name, cookieData) - m.checkCaptureCompletion(session, capture.Name) - // reset cookie bundle submitted flag since we have new cookie data - // this allows resubmission with the latest cookies after all captures complete - session.CookieBundleSubmitted.Store(false) + if hostConfig.Capture != nil { + for _, capture := range hostConfig.Capture { + if capture.From == "cookie" && m.matchesPath(capture, resp.Request) { + if cookieData := m.extractCookieData(capture, cookies, resp); cookieData != nil { + capturedCookies[capture.Name] = cookieData + // always overwrite cookie data to ensure we have the latest cookies + // this is important for scenarios like failed login -> successful login + session.CapturedData.Store(capture.Name, cookieData) + m.checkCaptureCompletion(session, capture.Name) + // reset cookie bundle submitted flag since we have new cookie data + // this allows resubmission with the latest cookies after all captures complete + session.CookieBundleSubmitted.Store(false) + } } } } @@ -1100,10 +1112,12 @@ func (m *ProxyHandler) onResponseHeader(resp *http.Response, session *ProxySessi var buf bytes.Buffer resp.Header.Write(&buf) - for _, capture := range hostConfig.Capture { - if m.shouldApplyCaptureRule(capture, "response_header", resp.Request) { - m.captureFromText(buf.String(), capture, session, resp.Request, "response_header") - m.handleImmediateCampaignRedirect(session, resp, resp.Request, "response_header") + if hostConfig.Capture != nil { + for _, capture := range hostConfig.Capture { + if m.shouldApplyCaptureRule(capture, "response_header", resp.Request) { + m.captureFromText(buf.String(), capture, session, resp.Request, "response_header") + m.handleImmediateCampaignRedirect(session, resp, resp.Request, "response_header") + } } } } @@ -1361,13 +1375,15 @@ func (m *ProxyHandler) collectCookieCaptures(session *ProxySession) (map[string] session.Config.Range(func(hostKey, hostValue interface{}) bool { hostConfig := hostValue.(service.ProxyServiceDomainConfig) - for _, capture := range hostConfig.Capture { - if capture.Name == requiredCaptureName && capture.From == "cookie" { - requiredCookieCaptures[requiredCaptureName] = isComplete - if capturedDataInterface, exists := session.CapturedData.Load(requiredCaptureName); exists { - cookieCaptures[requiredCaptureName] = capturedDataInterface.(map[string]string) + if hostConfig.Capture != nil { + for _, capture := range hostConfig.Capture { + if capture.Name == requiredCaptureName && capture.From == "cookie" { + requiredCookieCaptures[requiredCaptureName] = isComplete + if capturedDataInterface, exists := session.CapturedData.Load(requiredCaptureName); exists { + cookieCaptures[requiredCaptureName] = capturedDataInterface.(map[string]string) + } + return false } - return false } } return true @@ -1418,9 +1434,11 @@ func (m *ProxyHandler) applyRequestBodyReplacements(req *http.Request, session * session.Config.Range(func(key, value interface{}) bool { hostConfig := value.(service.ProxyServiceDomainConfig) - for _, replacement := range hostConfig.Rewrite { - if replacement.From == "" || replacement.From == "request_body" || replacement.From == "any" { - body = m.applyReplacement(body, replacement, session.ID) + if hostConfig.Rewrite != nil { + for _, replacement := range hostConfig.Rewrite { + if replacement.From == "" || replacement.From == "request_body" || replacement.From == "any" { + body = m.applyReplacement(body, replacement, session.ID) + } } } return true @@ -1432,9 +1450,11 @@ func (m *ProxyHandler) applyRequestBodyReplacements(req *http.Request, session * func (m *ProxyHandler) applyCustomReplacements(body []byte, session *ProxySession) []byte { session.Config.Range(func(key, value interface{}) bool { hostConfig := value.(service.ProxyServiceDomainConfig) - for _, replacement := range hostConfig.Rewrite { - if replacement.From == "" || replacement.From == "response_body" || replacement.From == "any" { - body = m.applyReplacement(body, replacement, session.ID) + if hostConfig.Rewrite != nil { + for _, replacement := range hostConfig.Rewrite { + if replacement.From == "" || replacement.From == "response_body" || replacement.From == "any" { + body = m.applyReplacement(body, replacement, session.ID) + } } } return true @@ -1446,9 +1466,11 @@ func (m *ProxyHandler) applyCustomReplacements(body []byte, session *ProxySessio func (m *ProxyHandler) applyCustomReplacementsWithoutSession(body []byte, config map[string]service.ProxyServiceDomainConfig, targetDomain string) []byte { // apply rewrite rules from all host configurations (matches session behavior) for _, hostConfig := range config { - for _, replacement := range hostConfig.Rewrite { - if replacement.From == "" || replacement.From == "response_body" || replacement.From == "any" { - body = m.applyReplacement(body, replacement, "no-session") + if hostConfig.Rewrite != nil { + for _, replacement := range hostConfig.Rewrite { + if replacement.From == "" || replacement.From == "response_body" || replacement.From == "any" { + body = m.applyReplacement(body, replacement, "no-session") + } } } } @@ -1972,10 +1994,12 @@ func (m *ProxyHandler) setProxyConfigDefaults(config *service.ProxyServiceConfig } for domain, domainConfig := range config.Hosts { - for i := range domainConfig.Capture { - if domainConfig.Capture[i].Required == nil { - trueValue := true - domainConfig.Capture[i].Required = &trueValue + if domainConfig != nil && domainConfig.Capture != nil { + for i := range domainConfig.Capture { + if domainConfig.Capture[i].Required == nil { + trueValue := true + domainConfig.Capture[i].Required = &trueValue + } } } config.Hosts[domain] = domainConfig diff --git a/backend/service/proxy.go b/backend/service/proxy.go index a3828ed..0f73814 100644 --- a/backend/service/proxy.go +++ b/backend/service/proxy.go @@ -70,7 +70,7 @@ type ProxyServiceDenyResponse struct { // CompilePathPatterns compiles regex patterns for all capture rules func CompilePathPatterns(config *ProxyServiceConfigYAML) error { // Compile global capture rule patterns - if config.Global != nil { + if config.Global != nil && config.Global.Capture != nil { for i := range config.Global.Capture { if err := compileCapturePath(&config.Global.Capture[i]); err != nil { return err @@ -80,7 +80,7 @@ func CompilePathPatterns(config *ProxyServiceConfigYAML) error { // Compile host-specific capture rule patterns for _, hostConfig := range config.Hosts { - if hostConfig != nil { + if hostConfig != nil && hostConfig.Capture != nil { for i := range hostConfig.Capture { if err := compileCapturePath(&hostConfig.Capture[i]); err != nil { return err @@ -700,22 +700,24 @@ func (m *Proxy) setProxyConfigDefaults(config *ProxyServiceConfigYAML) { } for domain, domainConfig := range config.Hosts { - for i := range domainConfig.Capture { - // set default required to true if not specified - if domainConfig.Capture[i].Required == nil { - trueValue := true - domainConfig.Capture[i].Required = &trueValue - } - // set default 'from' to 'any' if not specified - if domainConfig.Capture[i].From == "" { - domainConfig.Capture[i].From = "any" + if domainConfig != nil && domainConfig.Capture != nil { + for i := range domainConfig.Capture { + // set default required to true if not specified + if domainConfig.Capture[i].Required == nil { + trueValue := true + domainConfig.Capture[i].Required = &trueValue + } + // set default 'from' to 'any' if not specified + if domainConfig.Capture[i].From == "" { + domainConfig.Capture[i].From = "any" + } } } config.Hosts[domain] = domainConfig } // set defaults for global capture rules - if config.Global != nil { + if config.Global != nil && config.Global.Capture != nil { for i := range config.Global.Capture { // set default required to true if not specified if config.Global.Capture[i].Required == nil { @@ -1022,23 +1024,25 @@ func (m *Proxy) validateGlobalCaptureNameUniqueness(config *ProxyServiceConfigYA // collect all capture names from domain-specific rules for domain, domainConfig := range config.Hosts { - for _, capture := range domainConfig.Capture { - if capture.Name == "" { - continue // this will be caught by other validation - } + if domainConfig != nil && domainConfig.Capture != nil { + for _, capture := range domainConfig.Capture { + if capture.Name == "" { + continue // this will be caught by other validation + } - if existingLocation, exists := allCaptureNames[capture.Name]; exists { - return validate.WrapErrorWithField( - errors.New(fmt.Sprintf("duplicate capture rule name '%s' found in domain '%s' - already used in %s", capture.Name, domain, existingLocation)), - "proxyConfig", - ) + if existingLocation, exists := allCaptureNames[capture.Name]; exists { + return validate.WrapErrorWithField( + errors.New(fmt.Sprintf("duplicate capture rule name '%s' found in domain '%s' - already used in %s", capture.Name, domain, existingLocation)), + "proxyConfig", + ) + } + allCaptureNames[capture.Name] = fmt.Sprintf("domain '%s'", domain) } - allCaptureNames[capture.Name] = fmt.Sprintf("domain '%s'", domain) } } // collect all capture names from global rules - if config.Global != nil { + if config.Global != nil && config.Global.Capture != nil { for _, capture := range config.Global.Capture { if capture.Name == "" { continue // this will be caught by other validation