mirror of
https://github.com/bettercap/bettercap
synced 2025-08-13 02:06:57 -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
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