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