refactor wip

This commit is contained in:
Kevin Pham
2023-11-19 15:03:11 -06:00
parent 98fa53287b
commit ee9066dedb
27 changed files with 377 additions and 210 deletions

2
go.mod
View File

@@ -24,7 +24,7 @@ require (
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.50.0 // indirect
github.com/valyala/tcplisten v1.0.0 // indirect
golang.org/x/net v0.18.0 // indirect
golang.org/x/net v0.18.0
golang.org/x/sys v0.14.0 // indirect
golang.org/x/term v0.14.0
)

View File

@@ -12,8 +12,8 @@ import (
"ladder/pkg/ruleset"
"ladder/proxychain"
"ladder/proxychain/rqm"
"ladder/proxychain/rsm"
rx "ladder/proxychain/requestmodifers"
tx "ladder/proxychain/responsemodifers"
"github.com/PuerkitoBio/goquery"
"github.com/gofiber/fiber/v2"
@@ -49,19 +49,20 @@ func NewProxySiteHandler(opts *ProxyOptions) fiber.Handler {
rs = r
}
*/
proxychain := proxychain.
NewProxyChain().
SetDebugLogging(opts.Verbose).
SetRequestModifications(
rx.DeleteOutgoingCookies(),
).
AddResponseModifications(
tx.DeleteIncomingCookies(),
)
return func(c *fiber.Ctx) error {
return proxychain.NewProxyChain().
SetCtx(c).
//AddRuleset(&rs).
SetRequestModifications(
rqm.BlockOutgoingCookies(),
).
SetResultModifications(
rsm.BlockIncomingCookies(),
).
Execute()
return proxychain.SetFiberCtx(c).Execute()
}
}
func modifyURL(uri string, rule ruleset.Rule) (string, error) {

0
proxychain/cache/memcache.go vendored Normal file
View File

View File

@@ -14,14 +14,6 @@ import (
"github.com/gofiber/fiber/v2"
)
var defaultClient *http.Client
func DefaultClient() {
defaultClient = &http.Client{
Timeout: 15,
}
}
/*
ProxyChain manages the process of forwarding an HTTP request to an upstream server,
applying request and response modifications along the way.
@@ -40,21 +32,22 @@ applying request and response modifications along the way.
import (
"ladder/internal/proxychain/rqm"
"ladder/internal/proxychain/rsm"
rx "ladder/pkg/proxychain/requestmodifers"
tx "ladder/pkg/proxychain/responsemodifers"
"ladder/internal/proxychain"
)
proxychain.NewProxyChain().
SetCtx(c).
AddRuleset(&rs).
SetFiberCtx(c).
SetRequestModifications(
rqm.BlockOutgoingCookies(),
rx.BlockOutgoingCookies(),
rx.SpoofOrigin(),
rx.SpoofReferrer(),
).
SetResultModifications(
rsm.BlockIncomingCookies(),
tx.BlockIncomingCookies(),
).
Execute()
@@ -90,12 +83,12 @@ type ProxyChain struct {
Client *http.Client
Request *http.Request
Response *http.Response
Body []byte
Body io.Reader
requestModifications []RequestModification
resultModifications []ResponseModification
ruleset *ruleset.RuleSet
verbose bool
_abort_err error
Ruleset *ruleset.RuleSet
debugMode bool
abortErr error
}
// a ProxyStrategy is a pre-built proxychain with purpose-built defaults
@@ -123,23 +116,16 @@ func (chain *ProxyChain) AddRequestModifications(mods ...RequestModification) *P
return chain
}
// SetResultModifications sets the ProxyChain's response modifers
// AddResponseModifications sets the ProxyChain's response modifers
// the modifier will not fire until ProxyChain.Execute() is run.
func (chain *ProxyChain) SetResultModifications(mods ...ResponseModification) *ProxyChain {
func (chain *ProxyChain) AddResponseModifications(mods ...ResponseModification) *ProxyChain {
chain.resultModifications = mods
return chain
}
// AddResultModifications adds to the ProxyChain's response modifers
// the modifier will not fire until ProxyChain.Execute() is run.
func (chain *ProxyChain) AddResultModifications(mods ...ResponseModification) *ProxyChain {
chain.resultModifications = append(chain.resultModifications, mods...)
return chain
}
// Adds a ruleset to ProxyChain
func (chain *ProxyChain) AddRuleset(rs *ruleset.RuleSet) *ProxyChain {
chain.ruleset = rs
chain.Ruleset = rs
// TODO: add _applyRuleset method
return chain
}
@@ -178,20 +164,16 @@ func (chain *ProxyChain) _initialize_request() (*http.Request, error) {
// _execute sends the request for the ProxyChain and returns the raw body only
// the caller is responsible for returning a response back to the requestor
// the caller is also responsible for calling pxc._reset() when they are done with the body
func (chain *ProxyChain) _execute() (*[]byte, error) {
chain._validate_ctx_is_set()
if chain._abort_err != nil {
return nil, chain._abort_err
}
if chain.Context == nil {
return nil, errors.New("request ctx not set. Use ProxyChain.SetCtx()")
// the caller is also responsible for calling chain._reset() when they are done with the body
func (chain *ProxyChain) _execute() (io.Reader, error) {
if chain.validateCtxIsSet() != nil {
return nil, chain.abortErr
}
if chain.Request.URL.Scheme == "" {
return nil, errors.New("request url not set or invalid. Check ProxyChain ReqMods for issues")
}
// Apply requestModifications to proxychain (pxc)
// Apply requestModifications to proxychain
for _, applyRequestModificationsTo := range chain.requestModifications {
err := applyRequestModificationsTo(chain)
if err != nil {
@@ -205,13 +187,8 @@ func (chain *ProxyChain) _execute() (*[]byte, error) {
return nil, chain.abort(err)
}
chain.Response = resp
chain.Body = chain.Response.Body
// Buffer response into memory
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, chain.abort(err)
}
chain.Body = body
defer resp.Body.Close()
/* todo: move to rsm
@@ -220,7 +197,7 @@ func (chain *ProxyChain) _execute() (*[]byte, error) {
}
*/
// Apply ResponseModifiers to proxychain (pxc)
// Apply ResponseModifiers to proxychain
for _, applyResultModificationsTo := range chain.resultModifications {
err := applyResultModificationsTo(chain)
if err != nil {
@@ -228,7 +205,7 @@ func (chain *ProxyChain) _execute() (*[]byte, error) {
}
}
return &chain.Body, nil
return chain.Body, nil
}
// Execute sends the request for the ProxyChain and returns the request to the sender
@@ -242,22 +219,7 @@ func (chain *ProxyChain) Execute() error {
return err
}
// Return request back to client
return chain.Context.Send(*body)
}
// ExecuteAPIContent sends the request for the ProxyChain and returns the response body as
// a structured API response to the client
// if any step in the ProxyChain fails, the request will abort and a 500 error will
// be returned to the client
func (chain *ProxyChain) ExecuteAPIContent() error {
defer chain._reset()
body, err := chain._execute()
if err != nil {
return err
}
// TODO: implement reader API
// Return request back to client
return chain.Context.Send(*body)
return chain.Context.SendStream(body)
}
// reconstructUrlFromReferer reconstructs the URL using the referer's scheme, host, and the relative path / queries
@@ -312,50 +274,51 @@ func (chain *ProxyChain) extractUrl() (*url.URL, error) {
return reconstructUrlFromReferer(referer, relativePath)
}
// SetCtx takes the request ctx from the client
// SetFiberCtx takes the request ctx from the client
// for the modifiers and execute function to use.
// it must be set everytime a new request comes through
// if the upstream request url cannot be extracted from the ctx,
// a 500 error will be sent back to the client
func (chain *ProxyChain) SetCtx(ctx *fiber.Ctx) *ProxyChain {
func (chain *ProxyChain) SetFiberCtx(ctx *fiber.Ctx) *ProxyChain {
chain.Context = ctx
// initialize the request and prepare it for modification
req, err := chain._initialize_request()
if err != nil {
chain._abort_err = chain.abort(err)
chain.abortErr = chain.abort(err)
}
chain.Request = req
// extract the URL for the request and add it to the new request
url, err := chain.extractUrl()
if err != nil {
chain._abort_err = chain.abort(err)
chain.abortErr = chain.abort(err)
}
chain.Request.URL = url
return chain
}
func (pxc *ProxyChain) _validate_ctx_is_set() {
if pxc.Context != nil {
return
func (chain *ProxyChain) validateCtxIsSet() error {
if chain.Context != nil {
return nil
}
err := errors.New("proxyChain was called without setting a fiber Ctx. Use ProxyChain.SetCtx()")
pxc._abort_err = pxc.abort(err)
chain.abortErr = chain.abort(err)
return chain.abortErr
}
// SetClient sets a new upstream http client transport
// SetHttpClient sets a new upstream http client transport
// useful for modifying TLS
func (pxc *ProxyChain) SetClient(httpClient *http.Client) *ProxyChain {
pxc.Client = httpClient
return pxc
func (chain *ProxyChain) SetHttpClient(httpClient *http.Client) *ProxyChain {
chain.Client = httpClient
return chain
}
// SetVerbose changes the logging behavior to print
// the modification steps and applied rulesets for debugging
func (chain *ProxyChain) SetVerbose() *ProxyChain {
chain.verbose = true
func (chain *ProxyChain) SetDebugLogging(isDebugMode bool) *ProxyChain {
chain.debugMode = isDebugMode
return chain
}
@@ -363,8 +326,8 @@ func (chain *ProxyChain) SetVerbose() *ProxyChain {
// this will prevent Execute from firing and reset the state
// returns the initial error enriched with context
func (chain *ProxyChain) abort(err error) error {
defer chain._reset()
chain._abort_err = err
//defer chain._reset()
chain.abortErr = err
chain.Context.Response().SetStatusCode(500)
e := fmt.Errorf("ProxyChain error for '%s': %s", chain.Request.URL.String(), err.Error())
chain.Context.SendString(e.Error())
@@ -374,7 +337,7 @@ func (chain *ProxyChain) abort(err error) error {
// internal function to reset state of ProxyChain for reuse
func (chain *ProxyChain) _reset() {
chain._abort_err = nil
chain.abortErr = nil
chain.Body = nil
chain.Request = nil
chain.Response = nil
@@ -384,7 +347,6 @@ func (chain *ProxyChain) _reset() {
// NewProxyChain initializes a new ProxyChain
func NewProxyChain() *ProxyChain {
chain := new(ProxyChain)
//px.Client = defaultClient
chain.Client = http.DefaultClient
return chain
}

View File

@@ -0,0 +1,19 @@
package proxychain
import "time"
// Cache provides an interface for caching mechanisms.
// It supports operations to get, set, and invalidate cache entries.
// Implementations should ensure thread safety, efficiency
type Cache interface {
// Get Retrieves a cached value by its key. Returns the value and a boolean indicating
Get(key string) (value interface{}, found bool)
// Set - Stores a value associated with a key in the cache for a specified time-to-live (ttl).
// If ttl is zero, the cache item has no expiration.
Set(key string, value interface{}, ttl time.Duration)
// Invalidate - Removes a value from the cache by its key. If the key does not exist,
// it should perform a no-op or return a suitable error.
Invalidate(key string) error
}

View File

@@ -1,4 +1,4 @@
package rqm // ReQuestModifier
package requestmodifers
import (
"ladder/proxychain"

View File

@@ -1,4 +1,4 @@
package rqm // ReQuestModifier
package requestmodifers
import (
"ladder/proxychain"

View File

@@ -1,4 +1,4 @@
package rqm // ReQuestModifier
package requestmodifers
import (
"ladder/proxychain"

View File

@@ -1,4 +1,4 @@
package rqm // ReQuestModifier
package requestmodifers
import (
"ladder/proxychain"

View File

@@ -1,4 +1,4 @@
package rqm // ReQuestModifier
package requestmodifers
import (
"ladder/proxychain"

View File

@@ -0,0 +1,23 @@
package requestmodifers
import (
"ladder/proxychain"
)
// SetRequestHeader modifies a specific outgoing header
// This is the header that the upstream server will see.
func SetRequestHeader(name string, val string) proxychain.RequestModification {
return func(px *proxychain.ProxyChain) error {
px.Request.Header.Set(name, val)
return nil
}
}
// DeleteRequestHeader modifies a specific outgoing header
// This is the header that the upstream server will see.
func DeleteRequestHeader(name string) proxychain.RequestModification {
return func(px *proxychain.ProxyChain) error {
px.Request.Header.Del(name)
return nil
}
}

View File

@@ -1,4 +1,4 @@
package rqm
package requestmodifers
import (
"ladder/proxychain"

View File

@@ -1,4 +1,4 @@
package rqm // ReQuestModifier
package requestmodifers
import (
"ladder/proxychain"

View File

@@ -1,4 +1,4 @@
package rqm // ReQuestModifier
package requestmodifers
import (
"ladder/proxychain"

View File

@@ -1,4 +1,4 @@
package rqm
package requestmodifers
import (
"context"

View File

@@ -1,4 +1,4 @@
package rqm // ReQuestModifier
package requestmodifers
import (
"ladder/proxychain"

View File

@@ -1,4 +1,4 @@
package rqm // ReQuestModifier
package requestmodifers
import (
"ladder/proxychain"

View File

@@ -1,4 +1,4 @@
package rqm // ReQuestModifier
package requestmodifers
import (
"ladder/proxychain"

View File

@@ -1,4 +1,4 @@
package rqm // ReQuestModifier
package requestmodifers
import (
"ladder/proxychain"

View File

@@ -0,0 +1,21 @@
package responsemodifers
import (
"ladder/proxychain"
)
// BypassCORS modifies response headers to prevent the browser
// from enforcing any CORS restrictions. This should run at the end of the chain.
func BypassCORS() proxychain.ResponseModification {
return func(chain *proxychain.ProxyChain) error {
chain.AddResponseModifications(
SetResponseHeader("Access-Control-Allow-Origin", "*"),
SetResponseHeader("Access-Control-Expose-Headers", "*"),
SetResponseHeader("Access-Control-Allow-Credentials", "true"),
SetResponseHeader("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE, HEAD, OPTIONS, PATCH"),
SetResponseHeader("Access-Control-Allow-Headers", "*"),
DeleteResponseHeader("X-Frame-Options"),
)
return nil
}
}

View File

@@ -0,0 +1,27 @@
package responsemodifers
import (
"ladder/proxychain"
)
// BypassContentSecurityPolicy modifies response headers to prevent the browser
// from enforcing any CSP restrictions. This should run at the end of the chain.
func BypassContentSecurityPolicy() proxychain.ResponseModification {
return func(chain *proxychain.ProxyChain) error {
chain.AddResponseModifications(
DeleteResponseHeader("Content-Security-Policy"),
DeleteResponseHeader("Content-Security-Policy-Report-Only"),
DeleteResponseHeader("X-Content-Security-Policy"),
DeleteResponseHeader("X-WebKit-CSP"),
)
return nil
}
}
// SetContentSecurityPolicy modifies response headers to a specific CSP
func SetContentSecurityPolicy(csp string) proxychain.ResponseModification {
return func(chain *proxychain.ProxyChain) error {
chain.Response.Header.Set("Content-Security-Policy", csp)
return nil
}
}

View File

@@ -0,0 +1,102 @@
package responsemodifers
import (
"fmt"
"ladder/proxychain"
"net/http"
)
// DeleteIncomingCookies prevents ALL cookies from being sent from the proxy server
// back down to the client.
func DeleteIncomingCookies(whitelist ...string) proxychain.ResponseModification {
return func(px *proxychain.ProxyChain) error {
px.Response.Header.Del("Set-Cookie")
return nil
}
}
// DeleteIncomingCookiesExcept prevents non-whitelisted cookies from being sent from the proxy server
// to the client. Cookies whose names are in the whitelist are not removed.
func DeleteIncomingCookiesExcept(whitelist ...string) proxychain.ResponseModification {
return func(px *proxychain.ProxyChain) error {
// Convert whitelist slice to a map for efficient lookups
whitelistMap := make(map[string]struct{})
for _, cookieName := range whitelist {
whitelistMap[cookieName] = struct{}{}
}
// If the response has no cookies, return early
if px.Response.Header == nil {
return nil
}
// Filter the cookies in the response
filteredCookies := []string{}
for _, cookieStr := range px.Response.Header["Set-Cookie"] {
cookie := parseCookie(cookieStr)
if _, found := whitelistMap[cookie.Name]; found {
filteredCookies = append(filteredCookies, cookieStr)
}
}
// Update the Set-Cookie header with the filtered cookies
if len(filteredCookies) > 0 {
px.Response.Header["Set-Cookie"] = filteredCookies
} else {
px.Response.Header.Del("Set-Cookie")
}
return nil
}
}
// parseCookie parses a cookie string and returns an http.Cookie object.
func parseCookie(cookieStr string) *http.Cookie {
header := http.Header{}
header.Add("Set-Cookie", cookieStr)
request := http.Request{Header: header}
return request.Cookies()[0]
}
// SetIncomingCookies adds a raw cookie string being sent from the proxy server down to the client
func SetIncomingCookies(cookies string) proxychain.ResponseModification {
return func(px *proxychain.ProxyChain) error {
px.Response.Header.Set("Set-Cookie", cookies)
return nil
}
}
// SetIncomingCookie modifies a specific cookie in the response from the proxy server to the client.
func SetIncomingCookie(name string, val string) proxychain.ResponseModification {
return func(px *proxychain.ProxyChain) error {
if px.Response.Header == nil {
return nil
}
updatedCookies := []string{}
found := false
// Iterate over existing cookies and modify the one that matches the cookieName
for _, cookieStr := range px.Response.Header["Set-Cookie"] {
cookie := parseCookie(cookieStr)
if cookie.Name == name {
// Replace the cookie with the new value
updatedCookies = append(updatedCookies, fmt.Sprintf("%s=%s", name, val))
found = true
} else {
// Keep the cookie as is
updatedCookies = append(updatedCookies, cookieStr)
}
}
// If the specified cookie wasn't found, add it
if !found {
updatedCookies = append(updatedCookies, fmt.Sprintf("%s=%s", name, val))
}
// Update the Set-Cookie header
px.Response.Header["Set-Cookie"] = updatedCookies
return nil
}
}

View File

@@ -1,17 +1,12 @@
package rsm // ReSponseModifers
package responsemodifers
import (
"ladder/proxychain"
)
// ModifyResponseHeader modifies response headers from the upstream server
// if value is "", then the response header is deleted.
func ModifyResponseHeader(key string, value string) proxychain.ResponseModification {
// SetResponseHeader modifies response headers from the upstream server
func SetResponseHeader(key string, value string) proxychain.ResponseModification {
return func(px *proxychain.ProxyChain) error {
if value == "" {
px.Context.Response().Header.Del(key)
return nil
}
px.Context.Response().Header.Set(key, value)
return nil
}

View File

@@ -0,0 +1,114 @@
package responsemodifers
import (
"bytes"
"io"
"ladder/proxychain"
"net/url"
"strings"
"golang.org/x/net/html"
)
type HTMLResourceURLRewriter struct {
src io.Reader
buffer *bytes.Buffer // buffer to temporarily hold rewritten output for the reader
proxyURL *url.URL // proxyURL is the URL of the proxy, not the upstream URL
}
func NewHTMLResourceURLRewriter(src io.Reader, proxyURL *url.URL) *HTMLResourceURLRewriter {
return &HTMLResourceURLRewriter{
src: src,
buffer: new(bytes.Buffer),
proxyURL: proxyURL,
}
}
func rewriteToken(token *html.Token, baseURL *url.URL) {
attrsToRewrite := map[string]bool{"href": true, "src": true, "action": true, "srcset": true}
for i := range token.Attr {
attr := &token.Attr[i]
if attrsToRewrite[attr.Key] && strings.HasPrefix(attr.Val, "/") {
// Make URL absolute
attr.Val = "/https://" + baseURL.Host + attr.Val
}
}
}
func (r *HTMLResourceURLRewriter) Read(p []byte) (int, error) {
if r.buffer.Len() != 0 {
return r.buffer.Read(p)
}
tokenizer := html.NewTokenizer(r.src)
for {
tokenType := tokenizer.Next()
if tokenType == html.ErrorToken {
err := tokenizer.Err()
if err == io.EOF {
return 0, io.EOF // End of document
}
return 0, err // Actual error
}
token := tokenizer.Token()
if tokenType == html.StartTagToken || tokenType == html.SelfClosingTagToken {
rewriteToken(&token, r.url)
}
r.buffer.WriteString(token.String())
if r.buffer.Len() > 0 {
break
}
}
}
}
// RewriteHTMLResourceURLs updates src/href attributes in HTML content to route through the proxy.
func RewriteHTMLResourceURLs() proxychain.ResponseModification {
return func(chain *proxychain.ProxyChain) error {
ct := chain.Response.Header.Get("content-type")
if ct != "text/html" {
return nil
}
// parse dom
tokenizer := html.NewTokenizer(chain.Body)
var buffer bytes.Buffer
// traverse dom and proxify existing src/img resource links
for {
tokenType := tokenizer.Next()
switch tokenType {
case html.ErrorToken:
// End of the document, set the new body
chain.Body = io.ReaderFrom(buffer)
return nil
case html.StartTagToken, html.SelfClosingTagToken:
token := tokenizer.Token()
// Rewrite the necessary attributes
token = rewriteToken(token, u)
buffer.WriteString(token.String())
case html.TextToken, html.CommentToken, html.DoctypeToken, html.EndTagToken:
// Write the token to the buffer as is
buffer.WriteString(tokenizer.Token().String())
}
}
}
}
// rewriteToken rewrites the tokens with URLs to point to the proxy server.
func rewriteToken(token html.Token, u *url.URL) html.Token {
// Define attributes to rewrite, add more as needed such as "srcset"
rewriteAttrs := map[string]bool{"href": true, "src": true, "action": true, "srcset": true}
for i, attr := range token.Attr {
_, shouldRewrite := rewriteAttrs[attr.Key]
if shouldRewrite {
val := attr.Val
if strings.HasPrefix(val, "/") {
token.Attr[i].Val = "/https://" + u.Host + val
}
}
}
return token
}

View File

@@ -1,58 +0,0 @@
package rsm // ReSponseModifers
import (
"ladder/proxychain"
"net/http"
)
// BlockIncomingCookies prevents ALL cookies from being sent from the proxy server
// to the client.
func BlockIncomingCookies(whitelist ...string) proxychain.ResponseModification {
return func(px *proxychain.ProxyChain) error {
px.Response.Header.Del("Set-Cookie")
return nil
}
}
// BlockIncomingCookiesExcept prevents non-whitelisted cookies from being sent from the proxy server
// to the client. Cookies whose names are in the whitelist are not removed.
func BlockIncomingCookiesExcept(whitelist ...string) proxychain.ResponseModification {
return func(px *proxychain.ProxyChain) error {
// Convert whitelist slice to a map for efficient lookups
whitelistMap := make(map[string]struct{})
for _, cookieName := range whitelist {
whitelistMap[cookieName] = struct{}{}
}
// If the response has no cookies, return early
if px.Response.Header == nil {
return nil
}
// Filter the cookies in the response
filteredCookies := []string{}
for _, cookieStr := range px.Response.Header["Set-Cookie"] {
cookie := parseCookie(cookieStr)
if _, found := whitelistMap[cookie.Name]; found {
filteredCookies = append(filteredCookies, cookieStr)
}
}
// Update the Set-Cookie header with the filtered cookies
if len(filteredCookies) > 0 {
px.Response.Header["Set-Cookie"] = filteredCookies
} else {
px.Response.Header.Del("Set-Cookie")
}
return nil
}
}
// parseCookie parses a cookie string and returns an http.Cookie object.
func parseCookie(cookieStr string) *http.Cookie {
header := http.Header{}
header.Add("Set-Cookie", cookieStr)
request := http.Request{Header: header}
return request.Cookies()[0]
}

View File

@@ -1,20 +0,0 @@
package rsm // ReSponseModifers
import (
"ladder/proxychain"
)
// BypassCORs modifies response headers to prevent the browser
// from enforcing any CORS restrictions
func BypassCORS() proxychain.ResponseModification {
return func(px *proxychain.ProxyChain) error {
px.AddResultModifications(
ModifyResponseHeader("Access-Control-Allow-Origin", "*"),
ModifyResponseHeader("Access-Control-Expose-Headers", "*"),
ModifyResponseHeader("Access-Control-Allow-Credentials", "true"),
ModifyResponseHeader("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE, HEAD, OPTIONS, PATCH"),
DeleteResponseHeader("X-Frame-Options"),
)
return nil
}
}

View File

@@ -1,19 +0,0 @@
package rsm // ReSponseModifers
import (
"ladder/proxychain"
)
// BypassCSP modifies response headers to prevent the browser
// from enforcing any CORS restrictions
func BypassCSP() proxychain.ResponseModification {
return func(px *proxychain.ProxyChain) error {
px.AddResultModifications(
ModifyResponseHeader("Access-Control-Allow-Origin", "*"),
ModifyResponseHeader("Access-Control-Expose-Headers", "*"),
ModifyResponseHeader("Access-Control-Allow-Credentials", "true"),
ModifyResponseHeader("Access-Control-Allow-Methods", ""),
)
return nil
}
}