1package goja 2 3import ( 4 "github.com/dop251/goja/unistring" 5) 6 7type nativeProxyHandler struct { 8 handler *ProxyTrapConfig 9} 10 11func (h *nativeProxyHandler) getPrototypeOf(target *Object) (Value, bool) { 12 if trap := h.handler.GetPrototypeOf; trap != nil { 13 return trap(target), true 14 } 15 return nil, false 16} 17 18func (h *nativeProxyHandler) setPrototypeOf(target *Object, proto *Object) (bool, bool) { 19 if trap := h.handler.SetPrototypeOf; trap != nil { 20 return trap(target, proto), true 21 } 22 return false, false 23} 24 25func (h *nativeProxyHandler) isExtensible(target *Object) (bool, bool) { 26 if trap := h.handler.IsExtensible; trap != nil { 27 return trap(target), true 28 } 29 return false, false 30} 31 32func (h *nativeProxyHandler) preventExtensions(target *Object) (bool, bool) { 33 if trap := h.handler.PreventExtensions; trap != nil { 34 return trap(target), true 35 } 36 return false, false 37} 38 39func (h *nativeProxyHandler) getOwnPropertyDescriptorStr(target *Object, prop unistring.String) (Value, bool) { 40 if trap := h.handler.GetOwnPropertyDescriptorIdx; trap != nil { 41 if idx, ok := strToInt(prop); ok { 42 desc := trap(target, idx) 43 return desc.toValue(target.runtime), true 44 } 45 } 46 if trap := h.handler.GetOwnPropertyDescriptor; trap != nil { 47 desc := trap(target, prop.String()) 48 return desc.toValue(target.runtime), true 49 } 50 return nil, false 51} 52 53func (h *nativeProxyHandler) getOwnPropertyDescriptorIdx(target *Object, prop valueInt) (Value, bool) { 54 if trap := h.handler.GetOwnPropertyDescriptorIdx; trap != nil { 55 desc := trap(target, toIntStrict(int64(prop))) 56 return desc.toValue(target.runtime), true 57 } 58 if trap := h.handler.GetOwnPropertyDescriptor; trap != nil { 59 desc := trap(target, prop.String()) 60 return desc.toValue(target.runtime), true 61 } 62 return nil, false 63} 64 65func (h *nativeProxyHandler) getOwnPropertyDescriptorSym(target *Object, prop *Symbol) (Value, bool) { 66 if trap := h.handler.GetOwnPropertyDescriptorSym; trap != nil { 67 desc := trap(target, prop) 68 return desc.toValue(target.runtime), true 69 } 70 return nil, false 71} 72 73func (h *nativeProxyHandler) definePropertyStr(target *Object, prop unistring.String, desc PropertyDescriptor) (bool, bool) { 74 if trap := h.handler.DefinePropertyIdx; trap != nil { 75 if idx, ok := strToInt(prop); ok { 76 return trap(target, idx, desc), true 77 } 78 } 79 if trap := h.handler.DefineProperty; trap != nil { 80 return trap(target, prop.String(), desc), true 81 } 82 return false, false 83} 84 85func (h *nativeProxyHandler) definePropertyIdx(target *Object, prop valueInt, desc PropertyDescriptor) (bool, bool) { 86 if trap := h.handler.DefinePropertyIdx; trap != nil { 87 return trap(target, toIntStrict(int64(prop)), desc), true 88 } 89 if trap := h.handler.DefineProperty; trap != nil { 90 return trap(target, prop.String(), desc), true 91 } 92 return false, false 93} 94 95func (h *nativeProxyHandler) definePropertySym(target *Object, prop *Symbol, desc PropertyDescriptor) (bool, bool) { 96 if trap := h.handler.DefinePropertySym; trap != nil { 97 return trap(target, prop, desc), true 98 } 99 return false, false 100} 101 102func (h *nativeProxyHandler) hasStr(target *Object, prop unistring.String) (bool, bool) { 103 if trap := h.handler.HasIdx; trap != nil { 104 if idx, ok := strToInt(prop); ok { 105 return trap(target, idx), true 106 } 107 } 108 if trap := h.handler.Has; trap != nil { 109 return trap(target, prop.String()), true 110 } 111 return false, false 112} 113 114func (h *nativeProxyHandler) hasIdx(target *Object, prop valueInt) (bool, bool) { 115 if trap := h.handler.HasIdx; trap != nil { 116 return trap(target, toIntStrict(int64(prop))), true 117 } 118 if trap := h.handler.Has; trap != nil { 119 return trap(target, prop.String()), true 120 } 121 return false, false 122} 123 124func (h *nativeProxyHandler) hasSym(target *Object, prop *Symbol) (bool, bool) { 125 if trap := h.handler.HasSym; trap != nil { 126 return trap(target, prop), true 127 } 128 return false, false 129} 130 131func (h *nativeProxyHandler) getStr(target *Object, prop unistring.String, receiver Value) (Value, bool) { 132 if trap := h.handler.GetIdx; trap != nil { 133 if idx, ok := strToInt(prop); ok { 134 return trap(target, idx, receiver), true 135 } 136 } 137 if trap := h.handler.Get; trap != nil { 138 return trap(target, prop.String(), receiver), true 139 } 140 return nil, false 141} 142 143func (h *nativeProxyHandler) getIdx(target *Object, prop valueInt, receiver Value) (Value, bool) { 144 if trap := h.handler.GetIdx; trap != nil { 145 return trap(target, toIntStrict(int64(prop)), receiver), true 146 } 147 if trap := h.handler.Get; trap != nil { 148 return trap(target, prop.String(), receiver), true 149 } 150 return nil, false 151} 152 153func (h *nativeProxyHandler) getSym(target *Object, prop *Symbol, receiver Value) (Value, bool) { 154 if trap := h.handler.GetSym; trap != nil { 155 return trap(target, prop, receiver), true 156 } 157 return nil, false 158} 159 160func (h *nativeProxyHandler) setStr(target *Object, prop unistring.String, value Value, receiver Value) (bool, bool) { 161 if trap := h.handler.SetIdx; trap != nil { 162 if idx, ok := strToInt(prop); ok { 163 return trap(target, idx, value, receiver), true 164 } 165 } 166 if trap := h.handler.Set; trap != nil { 167 return trap(target, prop.String(), value, receiver), true 168 } 169 return false, false 170} 171 172func (h *nativeProxyHandler) setIdx(target *Object, prop valueInt, value Value, receiver Value) (bool, bool) { 173 if trap := h.handler.SetIdx; trap != nil { 174 return trap(target, toIntStrict(int64(prop)), value, receiver), true 175 } 176 if trap := h.handler.Set; trap != nil { 177 return trap(target, prop.String(), value, receiver), true 178 } 179 return false, false 180} 181 182func (h *nativeProxyHandler) setSym(target *Object, prop *Symbol, value Value, receiver Value) (bool, bool) { 183 if trap := h.handler.SetSym; trap != nil { 184 return trap(target, prop, value, receiver), true 185 } 186 return false, false 187} 188 189func (h *nativeProxyHandler) deleteStr(target *Object, prop unistring.String) (bool, bool) { 190 if trap := h.handler.DeletePropertyIdx; trap != nil { 191 if idx, ok := strToInt(prop); ok { 192 return trap(target, idx), true 193 } 194 } 195 if trap := h.handler.DeleteProperty; trap != nil { 196 return trap(target, prop.String()), true 197 } 198 return false, false 199} 200 201func (h *nativeProxyHandler) deleteIdx(target *Object, prop valueInt) (bool, bool) { 202 if trap := h.handler.DeletePropertyIdx; trap != nil { 203 return trap(target, toIntStrict(int64(prop))), true 204 } 205 if trap := h.handler.DeleteProperty; trap != nil { 206 return trap(target, prop.String()), true 207 } 208 return false, false 209} 210 211func (h *nativeProxyHandler) deleteSym(target *Object, prop *Symbol) (bool, bool) { 212 if trap := h.handler.DeletePropertySym; trap != nil { 213 return trap(target, prop), true 214 } 215 return false, false 216} 217 218func (h *nativeProxyHandler) ownKeys(target *Object) (*Object, bool) { 219 if trap := h.handler.OwnKeys; trap != nil { 220 return trap(target), true 221 } 222 return nil, false 223} 224 225func (h *nativeProxyHandler) apply(target *Object, this Value, args []Value) (Value, bool) { 226 if trap := h.handler.Apply; trap != nil { 227 return trap(target, this, args), true 228 } 229 return nil, false 230} 231 232func (h *nativeProxyHandler) construct(target *Object, args []Value, newTarget *Object) (Value, bool) { 233 if trap := h.handler.Construct; trap != nil { 234 return trap(target, args, newTarget), true 235 } 236 return nil, false 237} 238 239func (h *nativeProxyHandler) toObject(runtime *Runtime) *Object { 240 return runtime.ToValue(h.handler).ToObject(runtime) 241} 242 243func (r *Runtime) newNativeProxyHandler(nativeHandler *ProxyTrapConfig) proxyHandler { 244 return &nativeProxyHandler{handler: nativeHandler} 245} 246 247// ProxyTrapConfig provides a simplified Go-friendly API for implementing Proxy traps. 248// If an *Idx trap is defined it gets called for integer property keys, including negative ones. Note that 249// this only includes string property keys that represent a canonical integer 250// (i.e. "0", "123", but not "00", "01", " 1" or "-0"). 251// For efficiency strings representing integers exceeding 2^53 are not checked to see if they are canonical, 252// i.e. the *Idx traps will receive "9007199254740993" as well as "9007199254740994", even though the former is not 253// a canonical representation in ECMAScript (Number("9007199254740993") === 9007199254740992). 254// See https://262.ecma-international.org/#sec-canonicalnumericindexstring 255// If an *Idx trap is not set, the corresponding string one is used. 256type ProxyTrapConfig struct { 257 // A trap for Object.getPrototypeOf, Reflect.getPrototypeOf, __proto__, Object.prototype.isPrototypeOf, instanceof 258 GetPrototypeOf func(target *Object) (prototype *Object) 259 260 // A trap for Object.setPrototypeOf, Reflect.setPrototypeOf 261 SetPrototypeOf func(target *Object, prototype *Object) (success bool) 262 263 // A trap for Object.isExtensible, Reflect.isExtensible 264 IsExtensible func(target *Object) (success bool) 265 266 // A trap for Object.preventExtensions, Reflect.preventExtensions 267 PreventExtensions func(target *Object) (success bool) 268 269 // A trap for Object.getOwnPropertyDescriptor, Reflect.getOwnPropertyDescriptor (string properties) 270 GetOwnPropertyDescriptor func(target *Object, prop string) (propertyDescriptor PropertyDescriptor) 271 272 // A trap for Object.getOwnPropertyDescriptor, Reflect.getOwnPropertyDescriptor (integer properties) 273 GetOwnPropertyDescriptorIdx func(target *Object, prop int) (propertyDescriptor PropertyDescriptor) 274 275 // A trap for Object.getOwnPropertyDescriptor, Reflect.getOwnPropertyDescriptor (Symbol properties) 276 GetOwnPropertyDescriptorSym func(target *Object, prop *Symbol) (propertyDescriptor PropertyDescriptor) 277 278 // A trap for Object.defineProperty, Reflect.defineProperty (string properties) 279 DefineProperty func(target *Object, key string, propertyDescriptor PropertyDescriptor) (success bool) 280 281 // A trap for Object.defineProperty, Reflect.defineProperty (integer properties) 282 DefinePropertyIdx func(target *Object, key int, propertyDescriptor PropertyDescriptor) (success bool) 283 284 // A trap for Object.defineProperty, Reflect.defineProperty (Symbol properties) 285 DefinePropertySym func(target *Object, key *Symbol, propertyDescriptor PropertyDescriptor) (success bool) 286 287 // A trap for the in operator, with operator, Reflect.has (string properties) 288 Has func(target *Object, property string) (available bool) 289 290 // A trap for the in operator, with operator, Reflect.has (integer properties) 291 HasIdx func(target *Object, property int) (available bool) 292 293 // A trap for the in operator, with operator, Reflect.has (Symbol properties) 294 HasSym func(target *Object, property *Symbol) (available bool) 295 296 // A trap for getting property values, Reflect.get (string properties) 297 Get func(target *Object, property string, receiver Value) (value Value) 298 299 // A trap for getting property values, Reflect.get (integer properties) 300 GetIdx func(target *Object, property int, receiver Value) (value Value) 301 302 // A trap for getting property values, Reflect.get (Symbol properties) 303 GetSym func(target *Object, property *Symbol, receiver Value) (value Value) 304 305 // A trap for setting property values, Reflect.set (string properties) 306 Set func(target *Object, property string, value Value, receiver Value) (success bool) 307 308 // A trap for setting property values, Reflect.set (integer properties) 309 SetIdx func(target *Object, property int, value Value, receiver Value) (success bool) 310 311 // A trap for setting property values, Reflect.set (Symbol properties) 312 SetSym func(target *Object, property *Symbol, value Value, receiver Value) (success bool) 313 314 // A trap for the delete operator, Reflect.deleteProperty (string properties) 315 DeleteProperty func(target *Object, property string) (success bool) 316 317 // A trap for the delete operator, Reflect.deleteProperty (integer properties) 318 DeletePropertyIdx func(target *Object, property int) (success bool) 319 320 // A trap for the delete operator, Reflect.deleteProperty (Symbol properties) 321 DeletePropertySym func(target *Object, property *Symbol) (success bool) 322 323 // A trap for Object.getOwnPropertyNames, Object.getOwnPropertySymbols, Object.keys, Reflect.ownKeys 324 OwnKeys func(target *Object) (object *Object) 325 326 // A trap for a function call, Function.prototype.apply, Function.prototype.call, Reflect.apply 327 Apply func(target *Object, this Value, argumentsList []Value) (value Value) 328 329 // A trap for the new operator, Reflect.construct 330 Construct func(target *Object, argumentsList []Value, newTarget *Object) (value *Object) 331} 332 333func (r *Runtime) newProxy(args []Value, proto *Object) *Object { 334 if len(args) >= 2 { 335 if target, ok := args[0].(*Object); ok { 336 if proxyHandler, ok := args[1].(*Object); ok { 337 return r.newProxyObject(target, proxyHandler, proto).val 338 } 339 } 340 } 341 panic(r.NewTypeError("Cannot create proxy with a non-object as target or handler")) 342} 343 344func (r *Runtime) builtin_newProxy(args []Value, newTarget *Object) *Object { 345 if newTarget == nil { 346 panic(r.needNew("Proxy")) 347 } 348 return r.newProxy(args, r.getPrototypeFromCtor(newTarget, r.global.Proxy, r.global.ObjectPrototype)) 349} 350 351func (r *Runtime) NewProxy(target *Object, nativeHandler *ProxyTrapConfig) Proxy { 352 if p, ok := target.self.(*proxyObject); ok { 353 if p.handler == nil { 354 panic(r.NewTypeError("Cannot create proxy with a revoked proxy as target")) 355 } 356 } 357 handler := r.newNativeProxyHandler(nativeHandler) 358 proxy := r._newProxyObject(target, handler, nil) 359 return Proxy{proxy: proxy} 360} 361 362func (r *Runtime) builtin_proxy_revocable(call FunctionCall) Value { 363 if len(call.Arguments) >= 2 { 364 if target, ok := call.Argument(0).(*Object); ok { 365 if proxyHandler, ok := call.Argument(1).(*Object); ok { 366 proxy := r.newProxyObject(target, proxyHandler, nil) 367 revoke := r.newNativeFunc(func(FunctionCall) Value { 368 proxy.revoke() 369 return _undefined 370 }, nil, "", nil, 0) 371 ret := r.NewObject() 372 ret.self._putProp("proxy", proxy.val, true, true, true) 373 ret.self._putProp("revoke", revoke, true, true, true) 374 return ret 375 } 376 } 377 } 378 panic(r.NewTypeError("Cannot create proxy with a non-object as target or handler")) 379} 380 381func (r *Runtime) createProxy(val *Object) objectImpl { 382 o := r.newNativeConstructOnly(val, r.builtin_newProxy, nil, "Proxy", 2) 383 384 o._putProp("revocable", r.newNativeFunc(r.builtin_proxy_revocable, nil, "revocable", nil, 2), true, false, true) 385 return o 386} 387 388func (r *Runtime) initProxy() { 389 r.global.Proxy = r.newLazyObject(r.createProxy) 390 r.addToGlobal("Proxy", r.global.Proxy) 391} 392