new: added removeEventListener builtin function (closes #1139)

This commit is contained in:
evilsocket 2024-11-20 14:30:17 +01:00
parent a7e4572416
commit 169b0cb8c9
2 changed files with 85 additions and 26 deletions

View file

@ -2,8 +2,10 @@ package session
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"sync"
"github.com/bettercap/bettercap/v2/js"
"github.com/evilsocket/islazy/fs"
@ -14,6 +16,8 @@ import (
// see https://github.com/robertkrimen/otto/issues/213
var jsRuntime = otto.New()
var jsListeners = sync.Map{}
func jsRunFunc(call otto.FunctionCall) otto.Value {
argv := call.ArgumentList
argc := len(argv)
@ -57,12 +61,25 @@ func jsOnEventFunc(call otto.FunctionCall) otto.Value {
cb = argv[1]
}
listenerKey := fmt.Sprintf("%s:%s", filterExpr, cb.String())
if _, found := jsListeners.Load(listenerKey); found {
return js.ReportError("listener already exists")
}
// add to listeners
closeChan := make(chan bool)
jsListeners.Store(listenerKey, closeChan)
// start a go routine for this event listener
go func(expr string, cb otto.Value) {
go func(expr string, cb otto.Value, closeChan chan bool) {
listener := I.Events.Listen()
defer I.Events.Unlisten(listener)
defer close(closeChan)
for event := range listener {
for {
select {
case event := <-listener:
if expr == "" || event.Tag == expr {
// some objects don't do well with js, so convert them to a generic map
// before passing them to the callback
@ -89,8 +106,49 @@ func jsOnEventFunc(call otto.FunctionCall) otto.Value {
I.script.Unlock()
}
}
case <-closeChan:
return
}
}
}(filterExpr, cb, closeChan)
return js.NullValue
}
func jsRemoveEventListenerFunc(call otto.FunctionCall) otto.Value {
argv := call.ArgumentList
argc := len(argv)
cb := otto.NullValue()
filterExpr := ""
// just one argument, a function to receive all events
if argc == 1 {
if argv[0].IsFunction() == false {
return js.ReportError("the single argument must be a function")
}
cb = argv[0]
} else {
if argc != 2 {
return js.ReportError("expected two arguments (event_name, callback), got %d", argc)
} else if argv[0].IsString() == false {
return js.ReportError("first argument must be a string")
} else if argv[1].IsFunction() == false {
return js.ReportError("second argument must be a function")
}
filterExpr = argv[0].String()
cb = argv[1]
}
listenerKey := fmt.Sprintf("%s:%s", filterExpr, cb.String())
if closer, found := jsListeners.Load(listenerKey); found {
closer.(chan bool) <- true
jsListeners.Delete(listenerKey)
} else {
return js.ReportError("listener not found")
}
}(filterExpr, cb)
return js.NullValue
}

View file

@ -330,6 +330,7 @@ func (s *Session) Start() error {
plugin.Defines["saveJSON"] = jsSaveJSONFunc
plugin.Defines["saveToFile"] = jsSaveToFileFunc
plugin.Defines["onEvent"] = jsOnEventFunc
plugin.Defines["removeEventListener"] = jsRemoveEventListenerFunc
plugin.Defines["session"] = s
// load the script here so the session and its internal objects are ready