commit c7e770916588cc713c5d090a83d24425b227b269 Author: Валерий Стадченко Date: Tue Aug 30 12:16:40 2022 +0300 Начальный импорт diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..882ca7f --- /dev/null +++ b/LICENSE @@ -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. diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..acee9aa --- /dev/null +++ b/go.mod @@ -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 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..0ca08c5 --- /dev/null +++ b/go.sum @@ -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= diff --git a/ottomain.go b/ottomain.go new file mode 100644 index 0000000..732261a --- /dev/null +++ b/ottomain.go @@ -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 +}