mirror of https://github.com/PCManiac/ottoman
commit
c7e7709165
@ -0,0 +1,21 @@ |
|||||||
|
MIT License |
||||||
|
|
||||||
|
Copyright (c) 2022 Valery Stadchenko |
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||||
|
of this software and associated documentation files (the "Software"), to deal |
||||||
|
in the Software without restriction, including without limitation the rights |
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||||
|
copies of the Software, and to permit persons to whom the Software is |
||||||
|
furnished to do so, subject to the following conditions: |
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all |
||||||
|
copies or substantial portions of the Software. |
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||||
|
SOFTWARE. |
||||||
@ -0,0 +1,14 @@ |
|||||||
|
module github.com/PCManiac/ottoman |
||||||
|
|
||||||
|
go 1.17 |
||||||
|
|
||||||
|
require ( |
||||||
|
github.com/caarlos0/env v3.5.0+incompatible |
||||||
|
github.com/robertkrimen/otto v0.0.0-20211024170158-b87d35c0b86f |
||||||
|
) |
||||||
|
|
||||||
|
require ( |
||||||
|
github.com/davecgh/go-spew v1.1.1 // indirect |
||||||
|
gopkg.in/sourcemap.v1 v1.0.5 // indirect |
||||||
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect |
||||||
|
) |
||||||
@ -0,0 +1,21 @@ |
|||||||
|
github.com/caarlos0/env v3.5.0+incompatible h1:Yy0UN8o9Wtr/jGHZDpCBLpNrzcFLLM2yixi/rBrKyJs= |
||||||
|
github.com/caarlos0/env v3.5.0+incompatible/go.mod h1:tdCsowwCzMLdkqRYDlHpZCp2UooDD3MspDBjZ2AD02Y= |
||||||
|
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= |
||||||
|
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= |
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= |
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= |
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= |
||||||
|
github.com/robertkrimen/otto v0.0.0-20211024170158-b87d35c0b86f h1:a7clxaGmmqtdNTXyvrp/lVO/Gnkzlhc/+dLs5v965GM= |
||||||
|
github.com/robertkrimen/otto v0.0.0-20211024170158-b87d35c0b86f/go.mod h1:/mK7FZ3mFYEn9zvNPhpngTyatyehSwte5bJZ4ehL5Xw= |
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= |
||||||
|
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= |
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= |
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
||||||
|
gopkg.in/readline.v1 v1.0.0-20160726135117-62c6fe619375/go.mod h1:lNEQeAhU009zbRxng+XOj5ITVgY24WcbNnQopyfKoYQ= |
||||||
|
gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI= |
||||||
|
gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78= |
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
||||||
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= |
||||||
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
||||||
@ -0,0 +1,120 @@ |
|||||||
|
package ottoman |
||||||
|
|
||||||
|
import ( |
||||||
|
"encoding/base64" |
||||||
|
"errors" |
||||||
|
"fmt" |
||||||
|
"reflect" |
||||||
|
"time" |
||||||
|
|
||||||
|
"github.com/caarlos0/env" |
||||||
|
"github.com/robertkrimen/otto" |
||||||
|
) |
||||||
|
|
||||||
|
type otto_config struct { |
||||||
|
Timeout int `env:"JS_TIMEOUT" envDefault:"2"` |
||||||
|
} |
||||||
|
|
||||||
|
func jsBtoa(b string) string { |
||||||
|
return base64.StdEncoding.EncodeToString([]byte(b)) |
||||||
|
} |
||||||
|
|
||||||
|
func jsAtob(str string) string { |
||||||
|
b, err := base64.StdEncoding.DecodeString(str) |
||||||
|
if err != nil { |
||||||
|
v, _ := otto.ToValue("Failed to execute 'jsAtob': The string to be decoded is not correctly encoded.") |
||||||
|
panic(v) |
||||||
|
} |
||||||
|
return string(b) |
||||||
|
} |
||||||
|
|
||||||
|
func jsRegisterFunctions(vm *otto.Otto) (err error) { |
||||||
|
err = vm.Set("btoa", jsBtoa) |
||||||
|
if err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
err = vm.Set("atob", jsAtob) |
||||||
|
if err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
|
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
func ProcessRequest(script string, params map[string]interface{}) (response map[string]interface{}, err error) { |
||||||
|
var cfg otto_config |
||||||
|
if err := env.Parse(&cfg); err != nil { |
||||||
|
return nil, fmt.Errorf("env vars parse error: %w", err) |
||||||
|
} |
||||||
|
|
||||||
|
vm := otto.New() |
||||||
|
|
||||||
|
err = jsRegisterFunctions(vm) |
||||||
|
if err != nil { |
||||||
|
return nil, fmt.Errorf("otto registreing standart functions error: %w", err) |
||||||
|
} |
||||||
|
|
||||||
|
for key, uf := range params { |
||||||
|
err = vm.Set(key, uf) |
||||||
|
if err != nil { |
||||||
|
return nil, fmt.Errorf("otto setting variables error: %w", err) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
vm.Interrupt = make(chan func(), 1) |
||||||
|
go func() { |
||||||
|
time.Sleep(time.Duration(cfg.Timeout) * time.Second) |
||||||
|
vm.Interrupt <- func() { |
||||||
|
panic(errors.New("some code took to long! Stopping after timeout")) |
||||||
|
} |
||||||
|
}() |
||||||
|
|
||||||
|
_, err = vm.Run(script) |
||||||
|
|
||||||
|
if err != nil { |
||||||
|
return nil, fmt.Errorf("otto run error: %w", err) |
||||||
|
} |
||||||
|
|
||||||
|
getOttoValue := func(variable string, err error) (interface{}, error) { |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
value, err := vm.Get(variable) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
exported, err := value.Export() |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
return exported, nil |
||||||
|
} |
||||||
|
|
||||||
|
response = make(map[string]interface{}) |
||||||
|
|
||||||
|
for v := range params { |
||||||
|
message, err := getOttoValue(v, err) |
||||||
|
if err != nil { |
||||||
|
return nil, fmt.Errorf("otto get value error: %w", err) |
||||||
|
} |
||||||
|
|
||||||
|
switch message := message.(type) { |
||||||
|
case string, |
||||||
|
int, int8, int16, int32, int64, |
||||||
|
float32, float64, |
||||||
|
bool: |
||||||
|
response[v] = message |
||||||
|
default: |
||||||
|
rt := reflect.TypeOf(message) |
||||||
|
switch rt.Kind() { |
||||||
|
case reflect.Slice, reflect.Array: |
||||||
|
response[v] = []byte(message.([]byte)) |
||||||
|
default: |
||||||
|
response[v] = nil |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return |
||||||
|
} |
||||||
Loading…
Reference in new issue