File: plugin.go

package info (click to toggle)
golang-github-evilsocket-islazy 1.11.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 292 kB
  • sloc: javascript: 8; makefile: 3
file content (227 lines) | stat: -rw-r--r-- 6,129 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
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
	}

	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()
	}
}