github.com/philhug/dnscontrol@v0.2.4-0.20180625181521-921fa9849001/pkg/js/js.go (about) 1 package js 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "io/ioutil" 7 8 "github.com/StackExchange/dnscontrol/models" 9 "github.com/StackExchange/dnscontrol/pkg/transform" 10 11 "github.com/robertkrimen/otto" 12 // load underscore js into vm by default 13 14 _ "github.com/robertkrimen/otto/underscore" // required by otto 15 ) 16 17 // ExecuteJavascript accepts a javascript string and runs it, returning the resulting dnsConfig. 18 func ExecuteJavascript(script string, devMode bool) (*models.DNSConfig, error) { 19 vm := otto.New() 20 21 vm.Set("require", require) 22 vm.Set("REV", reverse) 23 24 helperJs := GetHelpers(devMode) 25 // run helper script to prime vm and initialize variables 26 if _, err := vm.Run(helperJs); err != nil { 27 return nil, err 28 } 29 30 // run user script 31 if _, err := vm.Run(script); err != nil { 32 return nil, err 33 } 34 35 // export conf as string and unmarshal 36 value, err := vm.Run(`JSON.stringify(conf)`) 37 if err != nil { 38 return nil, err 39 } 40 str, err := value.ToString() 41 if err != nil { 42 return nil, err 43 } 44 conf := &models.DNSConfig{} 45 if err = json.Unmarshal([]byte(str), conf); err != nil { 46 return nil, err 47 } 48 return conf, nil 49 } 50 51 // GetHelpers returns the filename of helpers.js, or the esc'ed version. 52 func GetHelpers(devMode bool) string { 53 return _escFSMustString(devMode, "/helpers.js") 54 } 55 56 func require(call otto.FunctionCall) otto.Value { 57 if len(call.ArgumentList) != 1 { 58 throw(call.Otto, "require takes exactly one argument") 59 } 60 file := call.Argument(0).String() 61 fmt.Printf("requiring: %s\n", file) 62 data, err := ioutil.ReadFile(file) 63 if err != nil { 64 throw(call.Otto, err.Error()) 65 } 66 _, err = call.Otto.Run(string(data)) 67 if err != nil { 68 throw(call.Otto, err.Error()) 69 } 70 return otto.TrueValue() 71 } 72 73 func throw(vm *otto.Otto, str string) { 74 panic(vm.MakeCustomError("Error", str)) 75 } 76 77 func reverse(call otto.FunctionCall) otto.Value { 78 if len(call.ArgumentList) != 1 { 79 throw(call.Otto, "REV takes exactly one argument") 80 } 81 dom := call.Argument(0).String() 82 rev, err := transform.ReverseDomainName(dom) 83 if err != nil { 84 throw(call.Otto, err.Error()) 85 } 86 v, _ := otto.ToValue(rev) 87 return v 88 }