diff --git a/sui/api/guards.go b/sui/api/guards.go index 81f2e221..c58bbe3a 100644 --- a/sui/api/guards.go +++ b/sui/api/guards.go @@ -9,7 +9,11 @@ import ( "github.com/gin-gonic/gin" jsoniter "github.com/json-iterator/go" "github.com/yaoapp/gou/process" + v8 "github.com/yaoapp/gou/runtime/v8" + "github.com/yaoapp/gou/runtime/v8/bridge" + "github.com/yaoapp/kun/log" "github.com/yaoapp/yao/helper" + "rogchap.com/v8go" ) // Guards middlewares @@ -119,6 +123,265 @@ func (r *Request) processGuard(name string) error { r.Headers, // Request headers } + if strings.HasPrefix(name, "scripts.") { + return r.scriptGuardExec(c, name, args) + } + return r.processGuardExec(c, name, args) +} + +func (r *Request) scriptGuardExec(c *gin.Context, name string, args []interface{}) error { + + namer := strings.Split(strings.TrimPrefix(name, "scripts."), ".") + id := strings.Join(namer[:len(namer)-1], ".") + method := namer[len(namer)-1] + + script, err := v8.Select(id) + if err != nil { + c.JSON(403, gin.H{"code": 403, "message": fmt.Sprintf("Guard: %s %s", name, err.Error())}) + c.Abort() + return err + } + + sid := "" + global := map[string]interface{}{} + if v, has := c.Get("__sid"); has { // 设定会话ID + if v, ok := v.(string); ok { + sid = v + } + } + + if v, has := c.Get("__global"); has { // 设定全局变量 + if v, ok := v.(map[string]interface{}); ok { + global = v + } + } + + ctx, err := script.NewContext(sid, global) + if err != nil { + c.JSON(403, gin.H{"code": 403, "message": fmt.Sprintf("Guard: %s %s", name, err.Error())}) + c.Abort() + return err + } + defer ctx.Close() + + // Should be refector after the runtime refector + // Add the context object + ctx.WithFunction("SetSid", func(info *v8go.FunctionCallbackInfo) *v8go.Value { + if len(info.Args()) < 1 { + log.Error("SetSid no sid") + return v8go.Undefined(info.Context().Isolate()) + } + + sid, err := bridge.GoValue(info.Args()[0], info.Context()) + if err != nil { + log.Error("SetSid %s", err.Error()) + return v8go.Undefined(info.Context().Isolate()) + } + + c.Set("__sid", sid) + return v8go.Undefined(info.Context().Isolate()) + }) + + ctx.WithFunction("SetGlobal", func(info *v8go.FunctionCallbackInfo) *v8go.Value { + if len(info.Args()) < 1 { + log.Error("SetGlobal no global") + return v8go.Undefined(info.Context().Isolate()) + } + + global, err := bridge.GoValue(info.Args()[0], info.Context()) + if err != nil { + log.Error("SetGlobal %s", err.Error()) + return v8go.Undefined(info.Context().Isolate()) + } + + if global, ok := global.(map[string]interface{}); ok { + c.Set("__global", global) + } + + return v8go.Undefined(info.Context().Isolate()) + }) + + ctx.WithFunction("Redirect", func(info *v8go.FunctionCallbackInfo) *v8go.Value { + + if len(info.Args()) < 2 { + log.Error("Redirect no url") + return v8go.Undefined(info.Context().Isolate()) + } + + var ok = false + var code = 0 + var url = "" + v, err := bridge.GoValue(info.Args()[0], info.Context()) + if err != nil { + log.Error("Redirect %s", err.Error()) + return v8go.Undefined(info.Context().Isolate()) + } + + if code, ok = v.(int); !ok { + log.Error("Redirect code error") + return v8go.Undefined(info.Context().Isolate()) + } + + v, err = bridge.GoValue(info.Args()[1], info.Context()) + if err != nil { + log.Error("Redirect %s", err.Error()) + return v8go.Undefined(info.Context().Isolate()) + } + + if url, ok = v.(string); !ok { + log.Error("Redirect url error") + return v8go.Undefined(info.Context().Isolate()) + } + + c.Redirect(code, url) + c.Abort() + return nil + }) + + ctx.WithFunction("Abort", func(info *v8go.FunctionCallbackInfo) *v8go.Value { + c.Abort() + + return nil + }) + + ctx.WithFunction("Cookie", func(info *v8go.FunctionCallbackInfo) *v8go.Value { + if len(info.Args()) < 1 { + log.Error("SetGlobal no global") + return v8go.Undefined(info.Context().Isolate()) + } + + name, err := bridge.GoValue(info.Args()[0], info.Context()) + if err != nil { + log.Error("Cookie %s", err.Error()) + return v8go.Undefined(info.Context().Isolate()) + } + + if name, ok := name.(string); ok { + value, err := c.Cookie(name) + if err != nil { + log.Error("Cookie %s", err.Error()) + return v8go.Undefined(info.Context().Isolate()) + } + + jsValue, err := bridge.JsValue(info.Context(), value) + if err != nil { + log.Error("Cookie %s", err.Error()) + return v8go.Undefined(info.Context().Isolate()) + } + return jsValue + } + + return v8go.Undefined(info.Context().Isolate()) + + }) + + // This function should be refector after the next version + ctx.WithFunction("SetCookie", func(info *v8go.FunctionCallbackInfo) *v8go.Value { + + if len(info.Args()) < 7 { + log.Error("SetCookie no enough params") + return v8go.Undefined(info.Context().Isolate()) + } + + var ok = false + var name = "" + var value = "" + var maxAge = 0 + var path = "" + var domain = "" + var secure = false + var httpOnly = false + + v, err := bridge.GoValue(info.Args()[0], info.Context()) + if err != nil { + log.Error("SetCookie %s", err.Error()) + return v8go.Undefined(info.Context().Isolate()) + } + + if name, ok = v.(string); !ok { + log.Error("SetCookie name error") + return v8go.Undefined(info.Context().Isolate()) + } + + v, err = bridge.GoValue(info.Args()[1], info.Context()) + if err != nil { + log.Error("SetCookie %s", err.Error()) + return v8go.Undefined(info.Context().Isolate()) + } + + if value, ok = v.(string); !ok { + log.Error("SetCookie value error") + return v8go.Undefined(info.Context().Isolate()) + } + + v, err = bridge.GoValue(info.Args()[2], info.Context()) + if err != nil { + log.Error("SetCookie %s", err.Error()) + return v8go.Undefined(info.Context().Isolate()) + } + + if maxAge, ok = v.(int); !ok { + log.Error("SetCookie maxAge error") + return v8go.Undefined(info.Context().Isolate()) + } + + v, err = bridge.GoValue(info.Args()[3], info.Context()) + if err != nil { + log.Error("SetCookie %s", err.Error()) + return v8go.Undefined(info.Context().Isolate()) + } + if path, ok = v.(string); !ok { + log.Error("SetCookie path error") + return v8go.Undefined(info.Context().Isolate()) + } + + v, err = bridge.GoValue(info.Args()[4], info.Context()) + if err != nil { + log.Error("SetCookie %s", err.Error()) + return v8go.Undefined(info.Context().Isolate()) + } + + if domain, ok = v.(string); !ok { + log.Error("SetCookie domain error") + return v8go.Undefined(info.Context().Isolate()) + } + + v, err = bridge.GoValue(info.Args()[5], info.Context()) + if err != nil { + log.Error("SetCookie %s", err.Error()) + return v8go.Undefined(info.Context().Isolate()) + } + + if secure, ok = v.(bool); !ok { + log.Error("SetCookie secure error") + return v8go.Undefined(info.Context().Isolate()) + } + + v, err = bridge.GoValue(info.Args()[6], info.Context()) + if err != nil { + log.Error("SetCookie %s", err.Error()) + return v8go.Undefined(info.Context().Isolate()) + } + + if httpOnly, ok = v.(bool); !ok { + log.Error("SetCookie httpOnly error") + return v8go.Undefined(info.Context().Isolate()) + } + + c.SetCookie(name, value, maxAge, path, domain, secure, httpOnly) + return nil + }) + + _, err = ctx.Call(method, args...) + if err != nil { + c.JSON(403, gin.H{"code": 403, "message": fmt.Sprintf("Guard: %s %s", name, err.Error())}) + c.Abort() + return err + } + return nil +} + +func (r *Request) processGuardExec(c *gin.Context, name string, args []interface{}) error { process, err := process.Of(name, args...) if err != nil { c.JSON(403, gin.H{"code": 403, "message": fmt.Sprintf("Guard: %s %s", name, err.Error())})