builtin_proxy.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. package goja
  2. import (
  3. "fmt"
  4. "github.com/dop251/goja/unistring"
  5. )
  6. func (r *Runtime) newNativeProxyHandler(nativeHandler *ProxyTrapConfig) *Object {
  7. handler := r.NewObject()
  8. r.proxyproto_nativehandler_gen_obj_obj(proxy_trap_getPrototypeOf, nativeHandler.GetPrototypeOf, handler)
  9. r.proxyproto_nativehandler_setPrototypeOf(nativeHandler.SetPrototypeOf, handler)
  10. r.proxyproto_nativehandler_gen_obj_bool(proxy_trap_isExtensible, nativeHandler.IsExtensible, handler)
  11. r.proxyproto_nativehandler_gen_obj_bool(proxy_trap_preventExtensions, nativeHandler.PreventExtensions, handler)
  12. r.proxyproto_nativehandler_getOwnPropertyDescriptor(nativeHandler.GetOwnPropertyDescriptor, handler)
  13. r.proxyproto_nativehandler_defineProperty(nativeHandler.DefineProperty, handler)
  14. r.proxyproto_nativehandler_gen_obj_string_bool(proxy_trap_has, nativeHandler.Has, handler)
  15. r.proxyproto_nativehandler_get(nativeHandler.Get, handler)
  16. r.proxyproto_nativehandler_set(nativeHandler.Set, handler)
  17. r.proxyproto_nativehandler_gen_obj_string_bool(proxy_trap_deleteProperty, nativeHandler.DeleteProperty, handler)
  18. r.proxyproto_nativehandler_gen_obj_obj(proxy_trap_ownKeys, nativeHandler.OwnKeys, handler)
  19. r.proxyproto_nativehandler_apply(nativeHandler.Apply, handler)
  20. r.proxyproto_nativehandler_construct(nativeHandler.Construct, handler)
  21. return handler
  22. }
  23. func (r *Runtime) proxyproto_nativehandler_gen_obj_obj(name proxyTrap, native func(*Object) *Object, handler *Object) {
  24. if native != nil {
  25. handler.self._putProp(unistring.String(name), r.newNativeFunc(func(call FunctionCall) Value {
  26. if len(call.Arguments) >= 1 {
  27. if t, ok := call.Argument(0).(*Object); ok {
  28. return native(t)
  29. }
  30. }
  31. panic(r.NewTypeError("%s needs to be called with target as Object", name))
  32. }, nil, unistring.String(fmt.Sprintf("[native %s]", name)), nil, 1), true, true, true)
  33. }
  34. }
  35. func (r *Runtime) proxyproto_nativehandler_setPrototypeOf(native func(*Object, *Object) bool, handler *Object) {
  36. if native != nil {
  37. handler.self._putProp("setPrototypeOf", r.newNativeFunc(func(call FunctionCall) Value {
  38. if len(call.Arguments) >= 2 {
  39. if t, ok := call.Argument(0).(*Object); ok {
  40. if p, ok := call.Argument(1).(*Object); ok {
  41. s := native(t, p)
  42. return r.ToValue(s)
  43. }
  44. }
  45. }
  46. panic(r.NewTypeError("setPrototypeOf needs to be called with target and prototype as Object"))
  47. }, nil, "[native setPrototypeOf]", nil, 2), true, true, true)
  48. }
  49. }
  50. func (r *Runtime) proxyproto_nativehandler_gen_obj_bool(name proxyTrap, native func(*Object) bool, handler *Object) {
  51. if native != nil {
  52. handler.self._putProp(unistring.String(name), r.newNativeFunc(func(call FunctionCall) Value {
  53. if len(call.Arguments) >= 1 {
  54. if t, ok := call.Argument(0).(*Object); ok {
  55. s := native(t)
  56. return r.ToValue(s)
  57. }
  58. }
  59. panic(r.NewTypeError("%s needs to be called with target as Object", name))
  60. }, nil, unistring.String(fmt.Sprintf("[native %s]", name)), nil, 1), true, true, true)
  61. }
  62. }
  63. func (r *Runtime) proxyproto_nativehandler_getOwnPropertyDescriptor(native func(*Object, string) PropertyDescriptor, handler *Object) {
  64. if native != nil {
  65. handler.self._putProp("getOwnPropertyDescriptor", r.newNativeFunc(func(call FunctionCall) Value {
  66. if len(call.Arguments) >= 2 {
  67. if t, ok := call.Argument(0).(*Object); ok {
  68. switch p := call.Argument(1).(type) {
  69. case *Symbol:
  70. return _undefined
  71. default:
  72. desc := native(t, p.String())
  73. return desc.toValue(r)
  74. }
  75. }
  76. }
  77. panic(r.NewTypeError("getOwnPropertyDescriptor needs to be called with target as Object and prop as string"))
  78. }, nil, "[native getOwnPropertyDescriptor]", nil, 2), true, true, true)
  79. }
  80. }
  81. func (r *Runtime) proxyproto_nativehandler_defineProperty(native func(*Object, string, PropertyDescriptor) bool, handler *Object) {
  82. if native != nil {
  83. handler.self._putProp("defineProperty", r.newNativeFunc(func(call FunctionCall) Value {
  84. if len(call.Arguments) >= 3 {
  85. if t, ok := call.Argument(0).(*Object); ok {
  86. if k, ok := call.Argument(1).(valueString); ok {
  87. propertyDescriptor := r.toPropertyDescriptor(call.Argument(2))
  88. s := native(t, k.String(), propertyDescriptor)
  89. return r.ToValue(s)
  90. }
  91. }
  92. }
  93. panic(r.NewTypeError("defineProperty needs to be called with target as Object and propertyDescriptor as string and key as string"))
  94. }, nil, "[native defineProperty]", nil, 3), true, true, true)
  95. }
  96. }
  97. func (r *Runtime) proxyproto_nativehandler_gen_obj_string_bool(name proxyTrap, native func(*Object, string) bool, handler *Object) {
  98. if native != nil {
  99. handler.self._putProp(unistring.String(name), r.newNativeFunc(func(call FunctionCall) Value {
  100. if len(call.Arguments) >= 2 {
  101. if t, ok := call.Argument(0).(*Object); ok {
  102. switch p := call.Argument(1).(type) {
  103. case *Symbol:
  104. return valueFalse
  105. default:
  106. o := native(t, p.String())
  107. return r.ToValue(o)
  108. }
  109. }
  110. }
  111. panic(r.NewTypeError("%s needs to be called with target as Object and property as string", name))
  112. }, nil, unistring.String(fmt.Sprintf("[native %s]", name)), nil, 2), true, true, true)
  113. }
  114. }
  115. func (r *Runtime) proxyproto_nativehandler_get(native func(*Object, string, *Object) Value, handler *Object) {
  116. if native != nil {
  117. handler.self._putProp("get", r.newNativeFunc(func(call FunctionCall) Value {
  118. if len(call.Arguments) >= 3 {
  119. if t, ok := call.Argument(0).(*Object); ok {
  120. if r, ok := call.Argument(2).(*Object); ok {
  121. switch p := call.Argument(1).(type) {
  122. case *Symbol:
  123. return _undefined
  124. default:
  125. return native(t, p.String(), r)
  126. }
  127. }
  128. }
  129. }
  130. panic(r.NewTypeError("get needs to be called with target and receiver as Object and property as string"))
  131. }, nil, "[native get]", nil, 3), true, true, true)
  132. }
  133. }
  134. func (r *Runtime) proxyproto_nativehandler_set(native func(*Object, string, Value, *Object) bool, handler *Object) {
  135. if native != nil {
  136. handler.self._putProp("set", r.newNativeFunc(func(call FunctionCall) Value {
  137. if len(call.Arguments) >= 4 {
  138. if t, ok := call.Argument(0).(*Object); ok {
  139. if p, ok := call.Argument(1).(valueString); ok {
  140. v := call.Argument(2)
  141. if re, ok := call.Argument(3).(*Object); ok {
  142. s := native(t, p.String(), v, re)
  143. return r.ToValue(s)
  144. }
  145. }
  146. }
  147. }
  148. panic(r.NewTypeError("set needs to be called with target and receiver as Object, property as string and value as a legal javascript value"))
  149. }, nil, "[native set]", nil, 4), true, true, true)
  150. }
  151. }
  152. func (r *Runtime) proxyproto_nativehandler_apply(native func(*Object, *Object, []Value) Value, handler *Object) {
  153. if native != nil {
  154. handler.self._putProp("apply", r.newNativeFunc(func(call FunctionCall) Value {
  155. if len(call.Arguments) >= 3 {
  156. if t, ok := call.Argument(0).(*Object); ok {
  157. if this, ok := call.Argument(1).(*Object); ok {
  158. if v, ok := call.Argument(2).(*Object); ok {
  159. if a, ok := v.self.(*arrayObject); ok {
  160. v := native(t, this, a.values)
  161. return r.ToValue(v)
  162. }
  163. }
  164. }
  165. }
  166. }
  167. panic(r.NewTypeError("apply needs to be called with target and this as Object and argumentsList as an array of legal javascript values"))
  168. }, nil, "[native apply]", nil, 3), true, true, true)
  169. }
  170. }
  171. func (r *Runtime) proxyproto_nativehandler_construct(native func(*Object, []Value, *Object) *Object, handler *Object) {
  172. if native != nil {
  173. handler.self._putProp("construct", r.newNativeFunc(func(call FunctionCall) Value {
  174. if len(call.Arguments) >= 3 {
  175. if t, ok := call.Argument(0).(*Object); ok {
  176. if v, ok := call.Argument(1).(*Object); ok {
  177. if newTarget, ok := call.Argument(2).(*Object); ok {
  178. if a, ok := v.self.(*arrayObject); ok {
  179. return native(t, a.values, newTarget)
  180. }
  181. }
  182. }
  183. }
  184. }
  185. panic(r.NewTypeError("construct needs to be called with target and newTarget as Object and argumentsList as an array of legal javascript values"))
  186. }, nil, "[native construct]", nil, 3), true, true, true)
  187. }
  188. }
  189. // ProxyTrapConfig provides a simplified Go-friendly API for implementing Proxy traps.
  190. // Note that the Proxy may not have Symbol properties when using this as a handler because property keys are
  191. // passed as strings.
  192. // get() and getOwnPropertyDescriptor() for Symbol properties will always return undefined;
  193. // has() and deleteProperty() for Symbol properties will always return false;
  194. // set() and defineProperty() for Symbol properties will throw a TypeError.
  195. // If you need Symbol properties implement the handler in JavaScript.
  196. type ProxyTrapConfig struct {
  197. // A trap for Object.getPrototypeOf, Reflect.getPrototypeOf, __proto__, Object.prototype.isPrototypeOf, instanceof
  198. GetPrototypeOf func(target *Object) (prototype *Object)
  199. // A trap for Object.setPrototypeOf, Reflect.setPrototypeOf
  200. SetPrototypeOf func(target *Object, prototype *Object) (success bool)
  201. // A trap for Object.isExtensible, Reflect.isExtensible
  202. IsExtensible func(target *Object) (success bool)
  203. // A trap for Object.preventExtensions, Reflect.preventExtensions
  204. PreventExtensions func(target *Object) (success bool)
  205. // A trap for Object.getOwnPropertyDescriptor, Reflect.getOwnPropertyDescriptor
  206. GetOwnPropertyDescriptor func(target *Object, prop string) (propertyDescriptor PropertyDescriptor)
  207. // A trap for Object.defineProperty, Reflect.defineProperty
  208. DefineProperty func(target *Object, key string, propertyDescriptor PropertyDescriptor) (success bool)
  209. // A trap for the in operator, with operator, Reflect.has
  210. Has func(target *Object, property string) (available bool)
  211. // A trap for getting property values, Reflect.get
  212. Get func(target *Object, property string, receiver *Object) (value Value)
  213. // A trap for setting property values, Reflect.set
  214. Set func(target *Object, property string, value Value, receiver *Object) (success bool)
  215. // A trap for the delete operator, Reflect.deleteProperty
  216. DeleteProperty func(target *Object, property string) (success bool)
  217. // A trap for Object.getOwnPropertyNames, Object.getOwnPropertySymbols, Object.keys, Reflect.ownKeys
  218. OwnKeys func(target *Object) (object *Object)
  219. // A trap for a function call, Function.prototype.apply, Function.prototype.call, Reflect.apply
  220. Apply func(target *Object, this *Object, argumentsList []Value) (value Value)
  221. // A trap for the new operator, Reflect.construct
  222. Construct func(target *Object, argumentsList []Value, newTarget *Object) (value *Object)
  223. }
  224. func (r *Runtime) newProxy(args []Value, proto *Object) *Object {
  225. if len(args) >= 2 {
  226. if target, ok := args[0].(*Object); ok {
  227. if proxyHandler, ok := args[1].(*Object); ok {
  228. return r.newProxyObject(target, proxyHandler, proto).val
  229. }
  230. }
  231. }
  232. panic(r.NewTypeError("Cannot create proxy with a non-object as target or handler"))
  233. }
  234. func (r *Runtime) builtin_newProxy(args []Value, newTarget *Object) *Object {
  235. if newTarget == nil {
  236. panic(r.needNew("Proxy"))
  237. }
  238. return r.newProxy(args, r.getPrototypeFromCtor(newTarget, r.global.Proxy, r.global.ObjectPrototype))
  239. }
  240. func (r *Runtime) NewProxy(target *Object, nativeHandler *ProxyTrapConfig) Proxy {
  241. handler := r.newNativeProxyHandler(nativeHandler)
  242. proxy := r.newProxyObject(target, handler, nil)
  243. return Proxy{proxy: proxy}
  244. }
  245. func (r *Runtime) builtin_proxy_revocable(call FunctionCall) Value {
  246. if len(call.Arguments) >= 2 {
  247. if target, ok := call.Argument(0).(*Object); ok {
  248. if proxyHandler, ok := call.Argument(1).(*Object); ok {
  249. proxy := r.newProxyObject(target, proxyHandler, nil)
  250. revoke := r.newNativeFunc(func(FunctionCall) Value {
  251. proxy.revoke()
  252. return _undefined
  253. }, nil, "", nil, 0)
  254. ret := r.NewObject()
  255. ret.self._putProp("proxy", proxy.val, true, true, true)
  256. ret.self._putProp("revoke", revoke, true, true, true)
  257. return ret
  258. }
  259. }
  260. }
  261. panic(r.NewTypeError("Cannot create proxy with a non-object as target or handler"))
  262. }
  263. func (r *Runtime) createProxy(val *Object) objectImpl {
  264. o := r.newNativeConstructOnly(val, r.builtin_newProxy, nil, "Proxy", 2)
  265. o._putProp("revocable", r.newNativeFunc(r.builtin_proxy_revocable, nil, "revocable", nil, 2), true, false, true)
  266. return o
  267. }
  268. func (r *Runtime) initProxy() {
  269. r.global.Proxy = r.newLazyObject(r.createProxy)
  270. r.addToGlobal("Proxy", r.global.Proxy)
  271. }