mirror of
https://github.com/bettercap/bettercap
synced 2025-07-07 13:32:07 -07:00
misc: refactored and ported the plugin system to islazy/plugin.Plugin (huge optimization)
This commit is contained in:
parent
788c8d5994
commit
dd2e8784dc
9 changed files with 374 additions and 335 deletions
8
Gopkg.lock
generated
8
Gopkg.lock
generated
|
@ -59,18 +59,19 @@
|
|||
revision = "f58a169a71a51037728990b2d3597a14f56b525b"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:32d8e0c62dc075d198abf73428828689f4e9473cadb8ef270be45fb78ae8648b"
|
||||
digest = "1:a029ce916ee511044c6b7fc41133249a15e8d3c16219274666205efd6431e9cd"
|
||||
name = "github.com/evilsocket/islazy"
|
||||
packages = [
|
||||
"fs",
|
||||
"log",
|
||||
"plugin",
|
||||
"str",
|
||||
"tui",
|
||||
"zip",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "72e580f7bbdfb45d1332e06653248bc609bf0d50"
|
||||
version = "v1.4.0"
|
||||
revision = "db3058040a83dba4e35a8931a3e1287c0b802869"
|
||||
version = "v1.6.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
|
@ -288,6 +289,7 @@
|
|||
"github.com/elazarl/goproxy",
|
||||
"github.com/evilsocket/islazy/fs",
|
||||
"github.com/evilsocket/islazy/log",
|
||||
"github.com/evilsocket/islazy/plugin",
|
||||
"github.com/evilsocket/islazy/str",
|
||||
"github.com/evilsocket/islazy/tui",
|
||||
"github.com/evilsocket/islazy/zip",
|
||||
|
|
|
@ -23,7 +23,9 @@
|
|||
# non-go = false
|
||||
# go-tests = true
|
||||
# unused-packages = true
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/evilsocket/islazy"
|
||||
version = "1.6.0"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
|
|
|
@ -1,129 +1,64 @@
|
|||
package modules
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/bettercap/bettercap/log"
|
||||
"github.com/bettercap/bettercap/session"
|
||||
|
||||
"github.com/robertkrimen/otto"
|
||||
|
||||
"github.com/evilsocket/islazy/plugin"
|
||||
)
|
||||
|
||||
type HttpProxyScript struct {
|
||||
*ProxyScript
|
||||
onRequestScript *otto.Script
|
||||
onResponseScript *otto.Script
|
||||
onCommandScript *otto.Script
|
||||
}
|
||||
*plugin.Plugin
|
||||
|
||||
func LoadHttpProxyScriptSource(path, source string, sess *session.Session) (err error, s *HttpProxyScript) {
|
||||
err, ps := LoadProxyScriptSource(path, source, sess)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
s = &HttpProxyScript{
|
||||
ProxyScript: ps,
|
||||
onRequestScript: nil,
|
||||
onResponseScript: nil,
|
||||
onCommandScript: nil,
|
||||
}
|
||||
|
||||
if s.hasCallback("onRequest") {
|
||||
s.onRequestScript, err = s.VM.Compile("", "onRequest(req, res)")
|
||||
if err != nil {
|
||||
log.Error("Error while compiling onRequest callback: %s", "\nTraceback:\n "+err.(*otto.Error).String())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if s.hasCallback("onResponse") {
|
||||
s.onResponseScript, err = s.VM.Compile("", "onResponse(req, res)")
|
||||
if err != nil {
|
||||
log.Error("Error while compiling onResponse callback: %s", "\nTraceback:\n "+err.(*otto.Error).String())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if s.hasCallback("onCommand") {
|
||||
s.onCommandScript, err = s.VM.Compile("", "onCommand(cmd)")
|
||||
if err != nil {
|
||||
log.Error("Error while compiling onCommand callback: %s", "\nTraceback:\n "+err.(*otto.Error).String())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
doOnRequest bool
|
||||
doOnResponse bool
|
||||
doOnCommand bool
|
||||
}
|
||||
|
||||
func LoadHttpProxyScript(path string, sess *session.Session) (err error, s *HttpProxyScript) {
|
||||
log.Info("loading proxy script %s ...", path)
|
||||
|
||||
raw, err := ioutil.ReadFile(path)
|
||||
plug, err := plugin.Load(path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return LoadHttpProxyScriptSource(path, string(raw), sess)
|
||||
}
|
||||
|
||||
func (s *HttpProxyScript) doRequestDefines(req *http.Request) (err error, jsreq *JSRequest, jsres *JSResponse) {
|
||||
jsreq = NewJSRequest(req)
|
||||
if err = s.VM.Set("req", jsreq); err != nil {
|
||||
log.Error("Error while defining request: %s", "\nTraceback:\n "+err.(*otto.Error).String())
|
||||
// define session pointer
|
||||
if err = plug.Set("env", sess.Env.Data); err != nil {
|
||||
log.Error("Error while defining environment: %+v", err)
|
||||
return
|
||||
}
|
||||
|
||||
jsres = NewJSResponse(nil)
|
||||
if err = s.VM.Set("res", jsres); err != nil {
|
||||
log.Error("Error while defining response: %s", "\nTraceback:\n "+err.(*otto.Error).String())
|
||||
// run onLoad if defined
|
||||
if plug.HasFunc("onLoad") {
|
||||
if _, err = plug.Call("onLoad"); err != nil {
|
||||
log.Error("Error while executing onLoad callback: %s", "\nTraceback:\n "+err.(*otto.Error).String())
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *HttpProxyScript) doResponseDefines(res *http.Response) (err error, jsreq *JSRequest, jsres *JSResponse) {
|
||||
jsreq = NewJSRequest(res.Request)
|
||||
if err = s.VM.Set("req", jsreq); err != nil {
|
||||
log.Error("Error while defining request: %s", "\nTraceback:\n "+err.(*otto.Error).String())
|
||||
return
|
||||
}
|
||||
|
||||
jsres = NewJSResponse(res)
|
||||
if err = s.VM.Set("res", jsres); err != nil {
|
||||
log.Error("Error while defining response: %s", "\nTraceback:\n "+err.(*otto.Error).String())
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (s *HttpProxyScript) doCommandDefines(cmd string) (err error) {
|
||||
if err = s.VM.Set("cmd", cmd); err != nil {
|
||||
log.Error("Error while defining cmd: %s", "\nTraceback:\n "+err.(*otto.Error).String())
|
||||
s = &HttpProxyScript{
|
||||
Plugin: plug,
|
||||
doOnRequest: plug.HasFunc("onRequest"),
|
||||
doOnResponse: plug.HasFunc("onResponse"),
|
||||
doOnCommand: plug.HasFunc("onCommand"),
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *HttpProxyScript) OnRequest(original *http.Request) (jsreq *JSRequest, jsres *JSResponse) {
|
||||
var err error
|
||||
if s.doOnRequest {
|
||||
jsreq := NewJSRequest(original)
|
||||
jsres := NewJSResponse(nil)
|
||||
|
||||
if s.onRequestScript != nil {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
if err, jsreq, jsres = s.doRequestDefines(original); err != nil {
|
||||
log.Error("Error while running bootstrap definitions: %s", "\nTraceback:\n "+err.(*otto.Error).String())
|
||||
if _, err := s.Call("onRequest", jsreq, jsres); err != nil {
|
||||
log.Error("%s", err)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if _, err = s.VM.Run(s.onRequestScript); err != nil {
|
||||
log.Error("Error while executing onRequest callback: %s", "\nTraceback:\n "+err.(*otto.Error).String())
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if jsreq.WasModified() {
|
||||
} else if jsreq.WasModified() {
|
||||
jsreq.UpdateHash()
|
||||
return jsreq, nil
|
||||
} else if jsres.WasModified() {
|
||||
|
@ -136,23 +71,14 @@ func (s *HttpProxyScript) OnRequest(original *http.Request) (jsreq *JSRequest, j
|
|||
}
|
||||
|
||||
func (s *HttpProxyScript) OnResponse(res *http.Response) (jsreq *JSRequest, jsres *JSResponse) {
|
||||
var err error
|
||||
if s.doOnResponse {
|
||||
jsreq := NewJSRequest(res.Request)
|
||||
jsres := NewJSResponse(res)
|
||||
|
||||
if s.onResponseScript != nil {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
if err, jsreq, jsres = s.doResponseDefines(res); err != nil {
|
||||
log.Error("Error while running bootstrap definitions: %s", "\nTraceback:\n "+err.(*otto.Error).String())
|
||||
if _, err := s.Call("onResponse", jsreq, jsres); err != nil {
|
||||
log.Error("%s", err)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if _, err = s.VM.Run(s.onResponseScript); err != nil {
|
||||
log.Error("Error while executing onRequest callback: %s", "\nTraceback:\n "+err.(*otto.Error).String())
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if jsres.WasModified() {
|
||||
} else if jsres.WasModified() {
|
||||
jsres.UpdateHash()
|
||||
return nil, jsres
|
||||
}
|
||||
|
@ -162,19 +88,11 @@ func (s *HttpProxyScript) OnResponse(res *http.Response) (jsreq *JSRequest, jsre
|
|||
}
|
||||
|
||||
func (s *HttpProxyScript) OnCommand(cmd string) bool {
|
||||
if s.onCommandScript != nil {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
if err := s.doCommandDefines(cmd); err != nil {
|
||||
log.Error("Error while running bootstrap onCommand definitions: %s", "\nTraceback:\n "+err.(*otto.Error).String())
|
||||
if s.doOnCommand {
|
||||
if ret, err := s.Call("onCommand", cmd); err != nil {
|
||||
log.Error("Error while executing onCommand callback: %+v", err)
|
||||
return false
|
||||
}
|
||||
|
||||
if ret, err := s.VM.Run(s.onCommandScript); err != nil {
|
||||
log.Error("Error while executing onCommand callback: %s", "\nTraceback:\n "+err.(*otto.Error).String())
|
||||
return false
|
||||
} else if v, err := ret.ToBoolean(); err == nil {
|
||||
} else if v, ok := ret.(bool); ok {
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
package modules
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/bettercap/bettercap/log"
|
||||
"github.com/bettercap/bettercap/session"
|
||||
)
|
||||
|
||||
func getScript(src string) *HttpProxyScript {
|
||||
sess := session.Session{}
|
||||
sess.Env, _ = session.NewEnvironment("")
|
||||
|
||||
err, script := LoadHttpProxyScriptSource("", src, &sess)
|
||||
if err != nil {
|
||||
log.Fatal("%s", err)
|
||||
}
|
||||
return script
|
||||
}
|
||||
|
||||
func getRequest() *http.Request {
|
||||
req, err := http.NewRequest("GET", "http://www.google.com/", nil)
|
||||
if err != nil {
|
||||
log.Fatal("%s", err)
|
||||
}
|
||||
return req
|
||||
}
|
||||
|
||||
func BenchmarkOnRequest(b *testing.B) {
|
||||
script := getScript("function onRequest(req,res){}")
|
||||
req := getRequest()
|
||||
|
||||
for n := 0; n < b.N; n++ {
|
||||
script.OnRequest(req)
|
||||
}
|
||||
}
|
|
@ -3,11 +3,12 @@ package modules
|
|||
import (
|
||||
"encoding/base64"
|
||||
"io/ioutil"
|
||||
"sync"
|
||||
|
||||
"github.com/bettercap/bettercap/log"
|
||||
"github.com/bettercap/bettercap/session"
|
||||
|
||||
"github.com/evilsocket/islazy/plugin"
|
||||
|
||||
"github.com/robertkrimen/otto"
|
||||
)
|
||||
|
||||
|
@ -18,71 +19,9 @@ func errOtto(format string, args ...interface{}) otto.Value {
|
|||
return nullOtto
|
||||
}
|
||||
|
||||
type ProxyScript struct {
|
||||
sync.Mutex
|
||||
|
||||
Path string
|
||||
Source string
|
||||
VM *otto.Otto
|
||||
|
||||
sess *session.Session
|
||||
cbCacheLock *sync.Mutex
|
||||
cbCache map[string]bool
|
||||
}
|
||||
|
||||
func LoadProxyScriptSource(path, source string, sess *session.Session) (err error, s *ProxyScript) {
|
||||
s = &ProxyScript{
|
||||
Path: path,
|
||||
Source: source,
|
||||
VM: otto.New(),
|
||||
sess: sess,
|
||||
cbCacheLock: &sync.Mutex{},
|
||||
cbCache: make(map[string]bool),
|
||||
}
|
||||
|
||||
// this will define callbacks and global objects
|
||||
_, err = s.VM.Run(s.Source)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// define session pointer
|
||||
err = s.VM.Set("env", sess.Env.Data)
|
||||
if err != nil {
|
||||
log.Error("Error while defining environment: %s", "\nTraceback:\n "+err.(*otto.Error).String())
|
||||
return
|
||||
}
|
||||
|
||||
err = s.defineBuiltins()
|
||||
if err != nil {
|
||||
log.Error("Error while defining builtin functions: %s", "\nTraceback:\n "+err.(*otto.Error).String())
|
||||
return
|
||||
}
|
||||
|
||||
// run onLoad if defined
|
||||
if s.hasCallback("onLoad") {
|
||||
_, err = s.VM.Run("onLoad()")
|
||||
if err != nil {
|
||||
log.Error("Error while executing onLoad callback: %s", "\nTraceback:\n "+err.(*otto.Error).String())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func LoadProxyScript(path string, sess *session.Session) (err error, s *ProxyScript) {
|
||||
raw, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return LoadProxyScriptSource(path, string(raw), sess)
|
||||
}
|
||||
|
||||
func (s *ProxyScript) defineBuiltins() error {
|
||||
func init() {
|
||||
// used to read a file ... doh
|
||||
s.VM.Set("readFile", func(call otto.FunctionCall) otto.Value {
|
||||
plugin.Defines["readFile"] = func(call otto.FunctionCall) otto.Value {
|
||||
argv := call.ArgumentList
|
||||
argc := len(argv)
|
||||
if argc != 1 {
|
||||
|
@ -95,14 +34,14 @@ func (s *ProxyScript) defineBuiltins() error {
|
|||
return errOtto("Could not read %s: %s", filename, err)
|
||||
}
|
||||
|
||||
v, err := s.VM.ToValue(string(raw))
|
||||
v, err := otto.ToValue(string(raw))
|
||||
if err != nil {
|
||||
return errOtto("Could not convert to string: %s", err)
|
||||
}
|
||||
return v
|
||||
})
|
||||
}
|
||||
|
||||
s.VM.Set("writeFile", func(call otto.FunctionCall) otto.Value {
|
||||
plugin.Defines["writeFile"] = func(call otto.FunctionCall) otto.Value {
|
||||
argv := call.ArgumentList
|
||||
argc := len(argv)
|
||||
if argc != 2 {
|
||||
|
@ -118,89 +57,89 @@ func (s *ProxyScript) defineBuiltins() error {
|
|||
}
|
||||
|
||||
return otto.NullValue()
|
||||
})
|
||||
}
|
||||
|
||||
// log something
|
||||
s.VM.Set("log", func(call otto.FunctionCall) otto.Value {
|
||||
plugin.Defines["log"] = func(call otto.FunctionCall) otto.Value {
|
||||
for _, v := range call.ArgumentList {
|
||||
log.Info("%s", v.String())
|
||||
}
|
||||
return otto.Value{}
|
||||
})
|
||||
}
|
||||
|
||||
// log debug
|
||||
s.VM.Set("log_debug", func(call otto.FunctionCall) otto.Value {
|
||||
plugin.Defines["log_debug"] = func(call otto.FunctionCall) otto.Value {
|
||||
for _, v := range call.ArgumentList {
|
||||
log.Debug("%s", v.String())
|
||||
}
|
||||
return otto.Value{}
|
||||
})
|
||||
}
|
||||
|
||||
// log info
|
||||
s.VM.Set("log_info", func(call otto.FunctionCall) otto.Value {
|
||||
plugin.Defines["log_info"] = func(call otto.FunctionCall) otto.Value {
|
||||
for _, v := range call.ArgumentList {
|
||||
log.Info("%s", v.String())
|
||||
}
|
||||
return otto.Value{}
|
||||
})
|
||||
}
|
||||
|
||||
// log warning
|
||||
s.VM.Set("log_warn", func(call otto.FunctionCall) otto.Value {
|
||||
plugin.Defines["log_warn"] = func(call otto.FunctionCall) otto.Value {
|
||||
for _, v := range call.ArgumentList {
|
||||
log.Warning("%s", v.String())
|
||||
}
|
||||
return otto.Value{}
|
||||
})
|
||||
}
|
||||
|
||||
// log error
|
||||
s.VM.Set("log_error", func(call otto.FunctionCall) otto.Value {
|
||||
plugin.Defines["log_error"] = func(call otto.FunctionCall) otto.Value {
|
||||
for _, v := range call.ArgumentList {
|
||||
log.Error("%s", v.String())
|
||||
}
|
||||
return otto.Value{}
|
||||
})
|
||||
}
|
||||
|
||||
// log fatal
|
||||
s.VM.Set("log_fatal", func(call otto.FunctionCall) otto.Value {
|
||||
plugin.Defines["log_fatal"] = func(call otto.FunctionCall) otto.Value {
|
||||
for _, v := range call.ArgumentList {
|
||||
log.Fatal("%s", v.String())
|
||||
}
|
||||
return otto.Value{}
|
||||
})
|
||||
}
|
||||
|
||||
// javascript btoa function
|
||||
s.VM.Set("btoa", func(call otto.FunctionCall) otto.Value {
|
||||
plugin.Defines["btoa"] = func(call otto.FunctionCall) otto.Value {
|
||||
varValue := base64.StdEncoding.EncodeToString([]byte(call.Argument(0).String()))
|
||||
v, err := s.VM.ToValue(varValue)
|
||||
v, err := otto.ToValue(varValue)
|
||||
if err != nil {
|
||||
return errOtto("Could not convert to string: %s", varValue)
|
||||
}
|
||||
return v
|
||||
})
|
||||
}
|
||||
|
||||
// javascript atob function
|
||||
s.VM.Set("atob", func(call otto.FunctionCall) otto.Value {
|
||||
plugin.Defines["atob"] = func(call otto.FunctionCall) otto.Value {
|
||||
varValue, err := base64.StdEncoding.DecodeString(call.Argument(0).String())
|
||||
if err != nil {
|
||||
return errOtto("Could not decode string: %s", call.Argument(0).String())
|
||||
}
|
||||
v, err := s.VM.ToValue(string(varValue))
|
||||
v, err := otto.ToValue(string(varValue))
|
||||
if err != nil {
|
||||
return errOtto("Could not convert to string: %s", varValue)
|
||||
}
|
||||
return v
|
||||
})
|
||||
}
|
||||
|
||||
// read or write environment variable
|
||||
s.VM.Set("env", func(call otto.FunctionCall) otto.Value {
|
||||
plugin.Defines["env"] = func(call otto.FunctionCall) otto.Value {
|
||||
argv := call.ArgumentList
|
||||
argc := len(argv)
|
||||
|
||||
if argc == 1 {
|
||||
// get
|
||||
varName := call.Argument(0).String()
|
||||
if found, varValue := s.sess.Env.Get(varName); found {
|
||||
v, err := s.VM.ToValue(varValue)
|
||||
if found, varValue := session.I.Env.Get(varName); found {
|
||||
v, err := otto.ToValue(varValue)
|
||||
if err != nil {
|
||||
return errOtto("Could not convert to string: %s", varValue)
|
||||
}
|
||||
|
@ -211,33 +150,11 @@ func (s *ProxyScript) defineBuiltins() error {
|
|||
// set
|
||||
varName := call.Argument(0).String()
|
||||
varValue := call.Argument(1).String()
|
||||
s.sess.Env.Set(varName, varValue)
|
||||
session.I.Env.Set(varName, varValue)
|
||||
} else {
|
||||
return errOtto("env: expected 1 or 2 arguments, %d given instead.", argc)
|
||||
}
|
||||
|
||||
return nullOtto
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *ProxyScript) hasCallback(name string) bool {
|
||||
s.cbCacheLock.Lock()
|
||||
defer s.cbCacheLock.Unlock()
|
||||
|
||||
// check the cache
|
||||
has, found := s.cbCache[name]
|
||||
if !found {
|
||||
// check the VM
|
||||
cb, err := s.VM.Get(name)
|
||||
if err == nil && cb.IsFunction() {
|
||||
has = true
|
||||
} else {
|
||||
has = false
|
||||
}
|
||||
s.cbCache[name] = has
|
||||
}
|
||||
|
||||
return has
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
package modules
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
|
@ -9,97 +8,62 @@ import (
|
|||
"github.com/bettercap/bettercap/session"
|
||||
|
||||
"github.com/robertkrimen/otto"
|
||||
|
||||
"github.com/evilsocket/islazy/plugin"
|
||||
)
|
||||
|
||||
type TcpProxyScript struct {
|
||||
*ProxyScript
|
||||
onDataScript *otto.Script
|
||||
}
|
||||
|
||||
func LoadTcpProxyScriptSource(path, source string, sess *session.Session) (err error, s *TcpProxyScript) {
|
||||
err, ps := LoadProxyScriptSource(path, source, sess)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
s = &TcpProxyScript{
|
||||
ProxyScript: ps,
|
||||
onDataScript: nil,
|
||||
}
|
||||
|
||||
if s.hasCallback("onData") {
|
||||
s.onDataScript, err = s.VM.Compile("", "onData(from, to, data)")
|
||||
if err != nil {
|
||||
log.Error("Error while compiling onData callback: %s", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
*plugin.Plugin
|
||||
doOnData bool
|
||||
}
|
||||
|
||||
func LoadTcpProxyScript(path string, sess *session.Session) (err error, s *TcpProxyScript) {
|
||||
log.Info("loading TCP proxy script %s ...", path)
|
||||
log.Info("loading tcp proxy script %s ...", path)
|
||||
|
||||
raw, err := ioutil.ReadFile(path)
|
||||
plug, err := plugin.Load(path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return LoadTcpProxyScriptSource(path, string(raw), sess)
|
||||
}
|
||||
// define session pointer
|
||||
if err = plug.Set("env", sess.Env.Data); err != nil {
|
||||
log.Error("Error while defining environment: %+v", err)
|
||||
return
|
||||
}
|
||||
|
||||
func (s *TcpProxyScript) doDefines(from, to net.Addr, data []byte) (err error) {
|
||||
addrFrom := strings.Split(from.String(), ":")[0]
|
||||
addrTo := strings.Split(to.String(), ":")[0]
|
||||
// run onLoad if defined
|
||||
if plug.HasFunc("onLoad") {
|
||||
if _, err = plug.Call("onLoad"); err != nil {
|
||||
log.Error("Error while executing onLoad callback: %s", "\nTraceback:\n "+err.(*otto.Error).String())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if err = s.VM.Set("from", addrFrom); err != nil {
|
||||
log.Error("Error while defining from: %s", err)
|
||||
return
|
||||
} else if err = s.VM.Set("to", addrTo); err != nil {
|
||||
log.Error("Error while defining to: %s", err)
|
||||
return
|
||||
} else if err = s.VM.Set("data", data); err != nil {
|
||||
log.Error("Error while defining data: %s", err)
|
||||
return
|
||||
s = &TcpProxyScript{
|
||||
Plugin: plug,
|
||||
doOnData: plug.HasFunc("onData"),
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *TcpProxyScript) OnData(from, to net.Addr, data []byte) []byte {
|
||||
if s.onDataScript != nil {
|
||||
if s.doOnData {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
err := s.doDefines(from, to, data)
|
||||
if err != nil {
|
||||
log.Error("Error while running bootstrap definitions: %s", err)
|
||||
return nil
|
||||
}
|
||||
addrFrom := strings.Split(from.String(), ":")[0]
|
||||
addrTo := strings.Split(to.String(), ":")[0]
|
||||
|
||||
ret, err := s.VM.Run(s.onDataScript)
|
||||
if err != nil {
|
||||
if ret, err := s.Call("onData", addrFrom, addrTo, data); err != nil {
|
||||
log.Error("Error while executing onData callback: %s", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
// do we have any return value to override the buffer with?
|
||||
if !ret.IsNull() && !ret.IsUndefined() {
|
||||
exported, err := ret.Export()
|
||||
if err != nil {
|
||||
log.Error("Error while exporting results: %s", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
array, ok := exported.([]byte)
|
||||
} else if ret != nil {
|
||||
array, ok := ret.([]byte)
|
||||
if !ok {
|
||||
log.Error("Error while casting exported value to array of byte: value = %s", exported)
|
||||
return nil
|
||||
log.Error("Error while casting exported value to array of byte: value = %+v", ret)
|
||||
}
|
||||
|
||||
return array
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
36
vendor/github.com/evilsocket/islazy/plugin/compile.go
generated
vendored
Normal file
36
vendor/github.com/evilsocket/islazy/plugin/compile.go
generated
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
package plugin
|
||||
|
||||
import (
|
||||
// "unicode"
|
||||
"github.com/robertkrimen/otto"
|
||||
)
|
||||
|
||||
func (p *Plugin) compile() (err error) {
|
||||
// create a new vm
|
||||
p.vm = otto.New()
|
||||
// track objects already defined by Otto
|
||||
predefined := map[string]bool{}
|
||||
for name := range p.vm.Context().Symbols {
|
||||
predefined[name] = true
|
||||
}
|
||||
// run the code once in order to define all the functions
|
||||
// and validate the syntax, then get the callbacks
|
||||
if _, err = p.vm.Run(p.Code); err != nil {
|
||||
return
|
||||
}
|
||||
// every uppercase object is considered exported
|
||||
for name, sym := range p.vm.Context().Symbols {
|
||||
// ignore predefined objects
|
||||
if _, found := predefined[name]; !found {
|
||||
// ignore lowercase global objects
|
||||
// if unicode.IsUpper(rune(name[0])) {
|
||||
if sym.IsFunction() {
|
||||
p.callbacks[name] = sym
|
||||
} else {
|
||||
p.objects[name] = sym
|
||||
}
|
||||
// }
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
4
vendor/github.com/evilsocket/islazy/plugin/doc.go
generated
vendored
Normal file
4
vendor/github.com/evilsocket/islazy/plugin/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
// Package plugin contains objects and functions to load and
|
||||
// use javascript plugins in order to extend the functionalities
|
||||
// of your projects.
|
||||
package plugin
|
233
vendor/github.com/evilsocket/islazy/plugin/plugin.go
generated
vendored
Normal file
233
vendor/github.com/evilsocket/islazy/plugin/plugin.go
generated
vendored
Normal file
|
@ -0,0 +1,233 @@
|
|||
package plugin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/robertkrimen/otto"
|
||||
)
|
||||
|
||||
// Defines is a map containing the predefined objects
|
||||
// and functions for each vm of each plugin.
|
||||
var Defines = map[string]interface{}{}
|
||||
|
||||
// Plugin is an object representing a javascript
|
||||
// file exporting functions and variables that
|
||||
// your project can use to extend its functionalities.
|
||||
type Plugin struct {
|
||||
sync.Mutex
|
||||
// The basename of the plugin.
|
||||
Name string
|
||||
// The actual javascript code.
|
||||
Code string
|
||||
// The full path of the plugin.
|
||||
Path string
|
||||
|
||||
vm *otto.Otto
|
||||
callbacks map[string]otto.Value
|
||||
objects map[string]otto.Value
|
||||
}
|
||||
|
||||
// Parse parsesand compiles a plugin given its source code.
|
||||
func Parse(code string) (*Plugin, error) {
|
||||
plugin := &Plugin{
|
||||
Code: code,
|
||||
callbacks: make(map[string]otto.Value),
|
||||
objects: make(map[string]otto.Value),
|
||||
}
|
||||
|
||||
if err := plugin.compile(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for name, val := range Defines {
|
||||
if err := plugin.vm.Set(name, val); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return plugin, nil
|
||||
}
|
||||
|
||||
// Load loads and compiles a plugin given its path.
|
||||
func Load(path string) (plug *Plugin, err error) {
|
||||
if raw, err := ioutil.ReadFile(path); err != nil {
|
||||
return nil, err
|
||||
} else if plug, err = Parse(string(raw)); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
plug.Path = path
|
||||
plug.Name = strings.Replace(filepath.Base(path), ".js", "", -1)
|
||||
}
|
||||
return plug, nil
|
||||
}
|
||||
|
||||
// Clone returns a new instance identical to the plugin.
|
||||
func (p *Plugin) Clone() (clone *Plugin) {
|
||||
var err error
|
||||
if p.Path == "" {
|
||||
clone, err = Parse(p.Code)
|
||||
} else {
|
||||
clone, err = Load(p.Path)
|
||||
}
|
||||
if err != nil {
|
||||
panic(err) // this should never happen
|
||||
}
|
||||
return clone
|
||||
}
|
||||
|
||||
// HasFunc returns true if the function with `name`
|
||||
// has been declared in the plugin code.
|
||||
func (p *Plugin) HasFunc(name string) bool {
|
||||
_, found := p.callbacks[name]
|
||||
return found
|
||||
}
|
||||
|
||||
// Set sets a variable into the VM of this plugin instance.
|
||||
func (p *Plugin) Set(name string, v interface{}) error {
|
||||
p.Lock()
|
||||
defer p.Unlock()
|
||||
return p.vm.Set(name, v)
|
||||
}
|
||||
|
||||
// Call executes one of the declared callbacks of the plugin by its name.
|
||||
func (p *Plugin) Call(name string, args ...interface{}) (interface{}, error) {
|
||||
p.Lock()
|
||||
defer p.Unlock()
|
||||
|
||||
if cb, found := p.callbacks[name]; !found {
|
||||
return nil, fmt.Errorf("%s does not name a function", name)
|
||||
} else if ret, err := cb.Call(otto.NullValue(), args...); err != nil {
|
||||
return nil, err
|
||||
} else if !ret.IsUndefined() {
|
||||
exported, err := ret.Export()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return exported, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Methods returns a list of methods exported from the javascript
|
||||
func (p *Plugin) Methods() []string {
|
||||
methods := []string{}
|
||||
for key, _ := range p.callbacks {
|
||||
methods = append(methods, key)
|
||||
}
|
||||
return methods
|
||||
}
|
||||
|
||||
// Objects returns a list of object exported by the javascript
|
||||
func (p *Plugin) Objects() []string {
|
||||
objs := []string{}
|
||||
for key, _ := range p.callbacks {
|
||||
objs = append(objs, key)
|
||||
}
|
||||
return objs
|
||||
}
|
||||
|
||||
// GetTypeObject returns the type of the object by its name
|
||||
func (p *Plugin) GetTypeObject(name string) string {
|
||||
if obj, found := p.objects[name]; !found {
|
||||
return ""
|
||||
} else if obj.IsPrimitive() {
|
||||
if obj.IsBoolean() {
|
||||
return "BooleanPrimitive"
|
||||
} else if obj.IsNumber() {
|
||||
return "NumberPrimitive"
|
||||
} else if obj.IsString() {
|
||||
return "StringPrimitive"
|
||||
}
|
||||
} else if obj.IsObject() {
|
||||
switch obj.Class() {
|
||||
case "Array":
|
||||
return "ArrayObject"
|
||||
case "String":
|
||||
return "StringObject"
|
||||
case "Boolean":
|
||||
return "BooleanObject"
|
||||
case "Number":
|
||||
return "NumberObject"
|
||||
case "Date":
|
||||
return "DateObject"
|
||||
case "RegExp":
|
||||
return "RegExpObject"
|
||||
case "Error":
|
||||
return "ErrorObject"
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// IsStringPrimitive returns true if the object with a
|
||||
// given name is a javascript primitive string
|
||||
func (p *Plugin) IsStringPrimitive(name string) bool {
|
||||
return p.GetTypeObject(name) == "StringPrimitive"
|
||||
}
|
||||
|
||||
// IsBooleanPrimitive returns true if the object with a
|
||||
// given name is a javascript primitive boolean, false otherwise
|
||||
func (p *Plugin) IsBooleanPrimitive(name string) bool {
|
||||
return p.GetTypeObject(name) == "BooleanPrimitive"
|
||||
}
|
||||
|
||||
// IsNumberPrimitive returns true if the object with a
|
||||
// given name is a javascript primitive number, false otherwise
|
||||
func (p *Plugin) IsNumberPrimitive(name string) bool {
|
||||
return p.GetTypeObject(name) == "NumberPrimitive"
|
||||
}
|
||||
|
||||
// IsArrayObject returns true if the object with a
|
||||
// given name is a javascript array object, false otherwise
|
||||
func (p *Plugin) IsArrayObject(name string) bool {
|
||||
return p.GetTypeObject(name) == "ArrayObject"
|
||||
}
|
||||
|
||||
// IsStringObject returns true if the object with a
|
||||
// given name is a javascript string object, false otherwise
|
||||
func (p *Plugin) IsStringObject(name string) bool {
|
||||
return p.GetTypeObject(name) == "StringObject"
|
||||
}
|
||||
|
||||
// IsBooleanObject returns true if the object with a
|
||||
// given name is a javascript boolean object, false otherwise
|
||||
func (p *Plugin) IsBooleanObject(name string) bool {
|
||||
return p.GetTypeObject(name) == "BooleanObject"
|
||||
}
|
||||
|
||||
// IsNumberObject returns true if the object with a
|
||||
// given name is a javascript Number object, false otherwise
|
||||
func (p *Plugin) IsNumberObject(name string) bool {
|
||||
return p.GetTypeObject(name) == "NumberObject"
|
||||
}
|
||||
|
||||
// IsDateObject returns true if the object with a
|
||||
// given name is a javascript Date object, false otherwise
|
||||
func (p *Plugin) IsDateObject(name string) bool {
|
||||
return p.GetTypeObject(name) == "DateObject"
|
||||
}
|
||||
|
||||
// IsRegExpObject returns true if the object with a
|
||||
// given name is a javascript RegExp object, false otherwise
|
||||
func (p *Plugin) IsRegExpObject(name string) bool {
|
||||
return p.GetTypeObject(name) == "RegExpObject"
|
||||
}
|
||||
|
||||
// IsErrorObject returns true if the object with a
|
||||
// given name is a javascript error object, false otherwise
|
||||
func (p *Plugin) IsErrorObject(name string) bool {
|
||||
return p.GetTypeObject(name) == "ErrorObject"
|
||||
}
|
||||
|
||||
// GetObject returns an interface containing the value of the object by its name
|
||||
func (p *Plugin) GetObject(name string) (interface{}, error) {
|
||||
if obj, found := p.objects[name]; !found {
|
||||
return nil, fmt.Errorf("%s does not name an object", name)
|
||||
} else {
|
||||
return obj.Export()
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue