package web_proxy import ( "bytes" "compress/gzip" "fmt" "io" "net/http" "regexp" "strings" "github.com/samber/lo" ) // RewriteHTMLContent rewrites HTML content to redirect external links through proxy func RewriteHTMLContent(resp *http.Response, assetID int, scheme, proxyHost string) { if resp.Body == nil { return } // Remove Content-Encoding to avoid decoding issues resp.Header.Del("Content-Encoding") resp.Header.Del("Content-Length") body, err := io.ReadAll(resp.Body) if err != nil { return } resp.Body.Close() baseDomain := lo.Ternary(strings.HasPrefix(proxyHost, "asset-"), func() string { parts := strings.SplitN(proxyHost, ".", 2) return lo.Ternary(len(parts) > 1, parts[1], proxyHost) }(), proxyHost) content := string(body) // Universal URL rewriting patterns - catch ALL external URLs patterns := []struct { pattern string rewrite func(matches []string) string }{ // JavaScript location assignments: window.location = "http://example.com/path" { `(window\.location(?:\.href)?\s*=\s*["'])https?://([^/'"]+)(/[^"']*)?["']`, func(matches []string) string { path := lo.Ternary(len(matches) > 3 && matches[3] != "", matches[3], "") return fmt.Sprintf(`%s%s://asset-%d.%s%s"`, matches[1], scheme, assetID, baseDomain, path) }, }, // Form actions:
") { content = strings.Replace(content, "", sessionJS+urlInterceptorJS+"", 1) } else { content = content + sessionJS + urlInterceptorJS } // Step 3: Record activity if enabled if session.WebConfig != nil && session.WebConfig.ProxySettings != nil && session.WebConfig.ProxySettings.RecordingEnabled { // Activity recording is handled elsewhere to avoid accessing ctx.Request here } // Update response newBody := bytes.NewReader([]byte(content)) resp.Body = io.NopCloser(newBody) resp.ContentLength = int64(len(content)) resp.Header.Set("Content-Length", fmt.Sprintf("%d", len(content))) } // RenderExternalRedirectPage renders the page shown when external redirect is blocked func RenderExternalRedirectPage(targetURL string) string { return fmt.Sprintf(`