static bool IsFrameId(JSContext* cx, JSObject* obj, jsid idArg) { MOZ_ASSERT(!js::IsWrapper(obj)); RootedId id(cx, idArg); nsGlobalWindow* win = WindowOrNull(obj); if (!win) { return false; } nsCOMPtr<nsIDOMWindowCollection> col = win->GetFrames(); if (!col) { return false; } nsCOMPtr<nsIDOMWindow> domwin; if (JSID_IS_INT(id)) { col->Item(JSID_TO_INT(id), getter_AddRefs(domwin)); } else if (JSID_IS_STRING(id)) { nsAutoJSString idAsString; if (!idAsString.init(cx, JSID_TO_STRING(id))) { return false; } col->NamedItem(idAsString, getter_AddRefs(domwin)); } return domwin != nullptr; }
StringData ObjectWrapper::Key::toStringData(JSContext* cx, JSStringWrapper* jsstr) { if (_type == Type::Field) { return _field; } if (_type == Type::Index) { *jsstr = JSStringWrapper(_idx); return jsstr->toStringData(); } JS::RootedId rid(cx); if (_type == Type::Id) { rid.set(_id); } else { InternedStringId id(cx, _internedString); rid.set(id); } if (JSID_IS_INT(rid)) { *jsstr = JSStringWrapper(JSID_TO_INT(rid)); return jsstr->toStringData(); } if (JSID_IS_STRING(rid)) { *jsstr = JSStringWrapper(cx, JSID_TO_STRING(rid)); return jsstr->toStringData(); } uasserted(ErrorCodes::BadValue, "Couldn't convert key to String"); }
/* @location_class.setProperty */ static JSBool location_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval *vp) { JSObject *parent_win; /* instance of @window_class */ struct view_state *vs; struct document_view *doc_view; /* This can be called if @obj if not itself an instance of the * appropriate class but has one in its prototype chain. Fail * such calls. */ if (!JS_InstanceOf(ctx, obj, (JSClass *) &location_class, NULL)) return JS_FALSE; parent_win = JS_GetParent(ctx, obj); assert(JS_InstanceOf(ctx, parent_win, (JSClass *) &window_class, NULL)); if_assert_failed return JS_FALSE; vs = (struct view_state *)JS_GetInstancePrivate(ctx, parent_win, (JSClass *) &window_class, NULL); doc_view = vs->doc_view; if (!JSID_IS_INT(id)) return JS_TRUE; switch (JSID_TO_INT(id)) { case JSP_LOC_HREF: location_goto(doc_view, jsval_to_string(ctx, vp)); break; } return JS_TRUE; }
JSBool JavaObject::setProperty(JSContext* ctx, JSObject* obj, jsid id, JSBool strict, jsval* vp) { #endif //GECKO_VERSION Debug::log(Debug::Spam) << "JavaObject::setProperty obj=" << obj << Debug::flush; if (!JSID_IS_INT(id)) { Debug::log(Debug::Error) << " Error: setting string property id" << Debug::flush; // TODO: throw a better exception here return JS_FALSE; } SessionData* data = JavaObject::getSessionData(ctx, obj); if (!data) { return JS_TRUE; } int objectRef = JavaObject::getObjectId(ctx, obj); int dispId = JSID_TO_INT(id); Value value; data->makeValueFromJsval(value, ctx, *vp); HostChannel* channel = data->getHostChannel(); SessionHandler* handler = data->getSessionHandler(); if (!ServerMethods::setProperty(*channel, handler, objectRef, dispId, value)) { // TODO: throw a better exception here return JS_FALSE; } return JS_TRUE; }
/* @smjs_globhist_item_class.setProperty */ static JSBool smjs_globhist_item_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval *vp) { struct global_history_item *history_item; /* This can be called if @obj if not itself an instance of the * appropriate class but has one in its prototype chain. Fail * such calls. */ if (!JS_InstanceOf(ctx, obj, (JSClass *) &smjs_globhist_item_class, NULL)) return JS_FALSE; history_item = JS_GetInstancePrivate(ctx, obj, (JSClass *) &smjs_globhist_item_class, NULL); if (!history_item) return JS_FALSE; if (!JSID_IS_INT(id)) return JS_FALSE; switch (JSID_TO_INT(id)) { case GLOBHIST_TITLE: { JSString *jsstr = JS_ValueToString(smjs_ctx, *vp); unsigned char *str = JS_EncodeString(smjs_ctx, jsstr); mem_free_set(&history_item->title, stracpy(str)); return JS_TRUE; } case GLOBHIST_URL: { JSString *jsstr = JS_ValueToString(smjs_ctx, *vp); unsigned char *str = JS_EncodeString(smjs_ctx, jsstr); mem_free_set(&history_item->url, stracpy(str)); return JS_TRUE; } case GLOBHIST_LAST_VISIT: { uint32 seconds; /* Bug 923: Assumes time_t values fit in uint32. */ JS_ValueToECMAUint32(smjs_ctx, *vp, &seconds); history_item->last_visit = seconds; return JS_TRUE; } default: /* Unrecognized integer property ID; someone is using * the object as an array. SMJS builtin classes (e.g. * js_RegExpClass) just return JS_TRUE in this case. * Do the same here. */ return JS_TRUE; } }
NS_IMETHODIMP StatementParams::Resolve(nsIXPConnectWrappedNative *aWrapper, JSContext *aCtx, JSObject *aScopeObj, jsid aId, bool *resolvedp, bool *_retval) { NS_ENSURE_TRUE(mStatement, NS_ERROR_NOT_INITIALIZED); // We do not throw at any point after this unless our index is out of range // because we want to allow the prototype chain to be checked for the // property. JS::RootedObject scope(aCtx, aScopeObj); JS::RootedId id(aCtx, aId); bool resolved = false; bool ok = true; if (JSID_IS_INT(id)) { uint32_t idx = JSID_TO_INT(id); // Ensure that our index is within range. We do not care about the // prototype chain being checked here. if (idx >= mParamCount) return NS_ERROR_INVALID_ARG; ok = ::JS_DefineElement(aCtx, scope, idx, JS::UndefinedHandleValue, JSPROP_ENUMERATE | JSPROP_RESOLVING); resolved = true; } else if (JSID_IS_STRING(id)) { JSString *str = JSID_TO_STRING(id); nsAutoJSString autoStr; if (!autoStr.init(aCtx, str)) { return NS_ERROR_FAILURE; } // Check to see if there's a parameter with this name, and if not, let // the rest of the prototype chain be checked. NS_ConvertUTF16toUTF8 name(autoStr); uint32_t idx; nsresult rv = mStatement->GetParameterIndex(name, &idx); if (NS_SUCCEEDED(rv)) { ok = ::JS_DefinePropertyById(aCtx, scope, id, JS::UndefinedHandleValue, JSPROP_ENUMERATE | JSPROP_RESOLVING); resolved = true; } } *_retval = ok; *resolvedp = resolved && ok; return NS_OK; }
NS_IMETHODIMP StatementParams::NewResolve(nsIXPConnectWrappedNative *aWrapper, JSContext *aCtx, JSObject *aScopeObj, jsid aId, uint32_t aFlags, JSObject **_objp, bool *_retval) { NS_ENSURE_TRUE(mStatement, NS_ERROR_NOT_INITIALIZED); // We do not throw at any point after this unless our index is out of range // because we want to allow the prototype chain to be checked for the // property. JS::RootedObject scope(aCtx, aScopeObj); JS::RootedId id(aCtx, aId); bool resolved = false; bool ok = true; if (JSID_IS_INT(id)) { uint32_t idx = JSID_TO_INT(id); // Ensure that our index is within range. We do not care about the // prototype chain being checked here. if (idx >= mParamCount) return NS_ERROR_INVALID_ARG; ok = ::JS_DefineElement(aCtx, scope, idx, JSVAL_VOID, nullptr, nullptr, JSPROP_ENUMERATE); resolved = true; } else if (JSID_IS_STRING(id)) { JSString *str = JSID_TO_STRING(id); size_t nameLength; const jschar *nameChars = JS_GetStringCharsAndLength(aCtx, str, &nameLength); NS_ENSURE_TRUE(nameChars, NS_ERROR_UNEXPECTED); // Check to see if there's a parameter with this name, and if not, let // the rest of the prototype chain be checked. NS_ConvertUTF16toUTF8 name(nameChars, nameLength); uint32_t idx; nsresult rv = mStatement->GetParameterIndex(name, &idx); if (NS_SUCCEEDED(rv)) { ok = ::JS_DefinePropertyById(aCtx, scope, id, JSVAL_VOID, nullptr, nullptr, JSPROP_ENUMERATE); resolved = true; } } *_retval = ok; *_objp = resolved && ok ? scope.get() : nullptr; return NS_OK; }
StringData IdWrapper::toStringData(JSStringWrapper* jsstr) const { if (JSID_IS_STRING(_value)) { *jsstr = JSStringWrapper(_context, JSID_TO_STRING(_value)); } else if (JSID_IS_INT(_value)) { *jsstr = JSStringWrapper(JSID_TO_INT(_value)); } else { throwCurrentJSException(_context, ErrorCodes::TypeMismatch, "Cannot toString() non-string and non-integer jsid"); } return jsstr->toStringData(); }
JSBool JavaObject::getProperty(JSContext* ctx, JSObject* obj, jsid id, jsval* rval) { Debug::log(Debug::Spam) << "JavaObject::getProperty obj=" << obj << Debug::flush; SessionData* data = JavaObject::getSessionData(ctx, obj); if (!data) { // TODO: replace the frame with an error page instead? *rval = JSVAL_VOID; return JS_TRUE; } int objectRef = JavaObject::getObjectId(ctx, obj); if (JSID_IS_STRING(id)) { JSString* str = JSID_TO_STRING(id); if ((JS_GetStringEncodingLength(ctx, str) == 8) && !strncmp("toString", JS_EncodeString(ctx, str), 8)) { *rval = data->getToStringTearOff(); return JS_TRUE; } if ((JS_GetStringEncodingLength(ctx, str) == 2) && !strncmp("id", JS_EncodeString(ctx, str), 2)) { *rval = INT_TO_JSVAL(objectRef); return JS_TRUE; } if ((JS_GetStringEncodingLength(ctx, str) == 16) && !strncmp("__noSuchMethod__", JS_EncodeString(ctx, str), 16)) { // Avoid error spew if we are disconnected *rval = JSVAL_VOID; return JS_TRUE; } // TODO: dumpJsVal can no longer handle this case //Debug::log(Debug::Error) << "Getting unexpected string property " // << dumpJsVal(ctx, id) << Debug::flush; // TODO: throw a better exception here return JS_FALSE; } if (!JSID_IS_INT(id)) { // TODO: dumpJsVal can no longer handle this case //Debug::log(Debug::Error) << "Getting non-int/non-string property " // << dumpJsVal(ctx, id) << Debug::flush; // TODO: throw a better exception here return JS_FALSE; } int dispId = JSID_TO_INT(id); HostChannel* channel = data->getHostChannel(); SessionHandler* handler = data->getSessionHandler(); gwt::Value value = ServerMethods::getProperty(*channel, handler, objectRef, dispId); data->makeJsvalFromValue(*rval, ctx, value); return JS_TRUE; }
JSBool S_AnotherClass::jsPropertySet(JSContext *cx, JSObject *obj, jsid _id, JSBool strict, jsval *val) { int32_t propId = JSID_TO_INT(_id); S_AnotherClass *cobj; JSGET_PTRSHELL(S_AnotherClass, cobj, obj); if (!cobj) return JS_FALSE; switch(propId) { case kAPublicField: do { uint32_t tmp; JS_ValueToECMAUint32(cx, *val, &tmp); cobj->aPublicField = tmp; } while (0); break; default: break; } return JS_TRUE; }
NS_IMETHODIMP StatementParams::NewResolve(nsIXPConnectWrappedNative *aWrapper, JSContext *aCtx, JSObject *aScopeObj, jsid aId, PRUint32 aFlags, JSObject **_objp, PRBool *_retval) { NS_ENSURE_TRUE(mStatement, NS_ERROR_NOT_INITIALIZED); // We do not throw at any point after this unless our index is out of range // because we want to allow the prototype chain to be checked for the // property. bool resolved = false; PRBool ok = PR_TRUE; if (JSID_IS_INT(aId)) { PRUint32 idx = JSID_TO_INT(aId); // Ensure that our index is within range. We do not care about the // prototype chain being checked here. if (idx >= mParamCount) return NS_ERROR_INVALID_ARG; ok = ::JS_DefineElement(aCtx, aScopeObj, idx, JSVAL_VOID, nsnull, nsnull, JSPROP_ENUMERATE); resolved = true; } else if (JSID_IS_STRING(aId)) { JSString *str = JSID_TO_STRING(aId); jschar *nameChars = ::JS_GetStringChars(str); size_t nameLength = ::JS_GetStringLength(str); // Check to see if there's a parameter with this name, and if not, let // the rest of the prototype chain be checked. NS_ConvertUTF16toUTF8 name(reinterpret_cast<const PRUnichar *>(nameChars), nameLength); PRUint32 idx; nsresult rv = mStatement->GetParameterIndex(name, &idx); if (NS_SUCCEEDED(rv)) { ok = ::JS_DefineUCProperty(aCtx, aScopeObj, nameChars, nameLength, JSVAL_VOID, nsnull, nsnull, JSPROP_ENUMERATE); resolved = true; } } *_retval = ok; *_objp = resolved && ok ? aScopeObj : nsnull; return NS_OK; }
/* @bookmark_class.setProperty */ static JSBool bookmark_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval *vp) { struct bookmark *bookmark; jsid tmp; unsigned char *title = NULL; unsigned char *url = NULL; int ok; /* This can be called if @obj if not itself an instance of the * appropriate class but has one in its prototype chain. Fail * such calls. */ if (!JS_InstanceOf(ctx, obj, (JSClass *) &bookmark_class, NULL)) return JS_FALSE; bookmark = JS_GetInstancePrivate(ctx, obj, (JSClass *) &bookmark_class, NULL); if (!bookmark) return JS_FALSE; if (!JSID_IS_INT(id)) return JS_FALSE; switch (JSID_TO_INT(id)) { case BOOKMARK_TITLE: if (!JS_ValueToId(ctx, *vp, &tmp)) return JS_FALSE; if (!jsval_to_bookmark_string(ctx, tmp, &title)) return JS_FALSE; break; case BOOKMARK_URL: if (!JS_ValueToId(ctx, *vp, &tmp)) return JS_FALSE; if (!jsval_to_bookmark_string(ctx, tmp, &url)) return JS_FALSE; break; default: /* Unrecognized integer property ID; someone is using * the object as an array. SMJS builtin classes (e.g. * js_RegExpClass) just return JS_TRUE in this case. * Do the same here. */ return JS_TRUE; } ok = update_bookmark(bookmark, get_cp_index("UTF-8"), title, url); mem_free_if(title); mem_free_if(url); return ok ? JS_TRUE : JS_FALSE; }
JSBool JSI_Console::getProperty(JSContext* UNUSED(cx), JSObject* UNUSED(obj), jsid id, jsval* vp) { if (!JSID_IS_INT(id)) return JS_TRUE; int i = JSID_TO_INT(id); switch (i) { case console_visible: *vp = BOOLEAN_TO_JSVAL(g_Console->IsActive()); return JS_TRUE; default: *vp = JSVAL_NULL; return JS_TRUE; } }
JSBool S_SimpleAudioEngine::jsPropertyGet(JSContext *cx, JSObject *obj, jsid _id, jsval *val) { int32_t propId = JSID_TO_INT(_id); S_SimpleAudioEngine *cobj; JSGET_PTRSHELL(S_SimpleAudioEngine, cobj, obj); if (!cobj) return JS_FALSE; switch(propId) { case kBackgroundMusicVolume: do { jsval tmp; JS_NewNumberValue(cx, cobj->getBackgroundMusicVolume(), &tmp); JS_SET_RVAL(cx, val, tmp); } while (0); break; case kEffectsVolume: do { jsval tmp; JS_NewNumberValue(cx, cobj->getEffectsVolume(), &tmp); JS_SET_RVAL(cx, val, tmp); } while (0); break; default: break; } return JS_TRUE; }
JSBool S_AnotherClass::jsPropertyGet(JSContext *cx, JSObject *obj, jsid _id, jsval *val) { int32_t propId = JSID_TO_INT(_id); S_AnotherClass *cobj; JSGET_PTRSHELL(S_AnotherClass, cobj, obj); if (!cobj) return JS_FALSE; switch(propId) { case kAPublicField: do { jsval tmp; JS_NewNumberValue(cx, cobj->aPublicField, &tmp); JS_SET_RVAL(cx, val, tmp); } while (0); break; case kJustOneField: do { jsval tmp; JS_NewNumberValue(cx, cobj->getJustOneField(), &tmp); JS_SET_RVAL(cx, val, tmp); } while (0); break; default: break; } return JS_TRUE; }
JSBool S_SimpleAudioEngine::jsPropertySet(JSContext *cx, JSObject *obj, jsid _id, JSBool strict, jsval *val) { int32_t propId = JSID_TO_INT(_id); S_SimpleAudioEngine *cobj; JSGET_PTRSHELL(S_SimpleAudioEngine, cobj, obj); if (!cobj) return JS_FALSE; switch(propId) { case kBackgroundMusicVolume: do { double tmp; JS_ValueToNumber(cx, *val, &tmp); cobj->setBackgroundMusicVolume(tmp); } while (0); break; case kEffectsVolume: do { double tmp; JS_ValueToNumber(cx, *val, &tmp); cobj->setEffectsVolume(tmp); } while (0); break; default: break; } return JS_TRUE; }
JSBool S_SimpleNativeClass::jsPropertyGet(JSContext *cx, JSObject *obj, jsid _id, jsval *val) { int32_t propId = JSID_TO_INT(_id); S_SimpleNativeClass *cobj; JSGET_PTRSHELL(S_SimpleNativeClass, cobj, obj); if (!cobj) return JS_FALSE; switch(propId) { case kSomeField: do { jsval tmp; JS_NewNumberValue(cx, cobj->getSomeField(), &tmp); JS_SET_RVAL(cx, val, tmp); } while (0); break; case kSomeOtherField: do { jsval tmp; JS_NewNumberValue(cx, cobj->getSomeOtherField(), &tmp); JS_SET_RVAL(cx, val, tmp); } while (0); break; case kAnotherMoreComplexField: do { JSString *tmp = JS_NewStringCopyZ(cx, cobj->getAnotherMoreComplexField()); JS_SET_RVAL(cx, val, STRING_TO_JSVAL(tmp)); } while (0); break; default: break; } return JS_TRUE; }
JSBool JsPointBinding::PropertySet(JSContext *context, JSObject *obj, jsid id, JSBool strict, jsval *val) { int propId = JSID_TO_INT(id); CCPoint *pPoint = static_cast<CCPoint*> (JS_GetPrivate(context, obj)); if (!pPoint) return JS_FALSE; double data; JS_ValueToNumber(context, *val, &data); switch (propId) { case X: pPoint->x = data; break; case Y: pPoint->y = data; break; default: break; } return JS_TRUE; }
/* @bookmark_class.getProperty */ static JSBool bookmark_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp) { struct bookmark *bookmark; /* This can be called if @obj if not itself an instance of the * appropriate class but has one in its prototype chain. Fail * such calls. */ if (!JS_InstanceOf(ctx, obj, (JSClass *) &bookmark_class, NULL)) return JS_FALSE; bookmark = JS_GetInstancePrivate(ctx, obj, (JSClass *) &bookmark_class, NULL); if (!bookmark) return JS_FALSE; undef_to_jsval(ctx, vp); if (!JSID_IS_INT(id)) return JS_FALSE; switch (JSID_TO_INT(id)) { case BOOKMARK_TITLE: return bookmark_string_to_jsval(ctx, bookmark->title, vp); case BOOKMARK_URL: return bookmark_string_to_jsval(ctx, bookmark->url, vp); case BOOKMARK_CHILDREN: *vp = OBJECT_TO_JSVAL(smjs_get_bookmark_folder_object(bookmark)); return JS_TRUE; default: /* Unrecognized integer property ID; someone is using * the object as an array. SMJS builtin classes (e.g. * js_RegExpClass) just return JS_TRUE in this case * and leave *@vp unchanged. Do the same here. * (Actually not quite the same, as we already used * @undef_to_jsval.) */ return JS_TRUE; } }
/* @location_class.getProperty */ static JSBool location_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp) { JSObject *parent_win; /* instance of @window_class */ struct view_state *vs; /* This can be called if @obj if not itself an instance of the * appropriate class but has one in its prototype chain. Fail * such calls. */ if (!JS_InstanceOf(ctx, obj, (JSClass *) &location_class, NULL)) return JS_FALSE; parent_win = JS_GetParent(ctx, obj); assert(JS_InstanceOf(ctx, parent_win, (JSClass *) &window_class, NULL)); if_assert_failed return JS_FALSE; vs = (struct view_state *)JS_GetInstancePrivate(ctx, parent_win, (JSClass *) &window_class, NULL); if (!JSID_IS_INT(id)) return JS_TRUE; undef_to_jsval(ctx, vp); switch (JSID_TO_INT(id)) { case JSP_LOC_HREF: astring_to_jsval(ctx, vp, get_uri_string(vs->uri, URI_ORIGINAL)); break; default: /* Unrecognized integer property ID; someone is using * the object as an array. SMJS builtin classes (e.g. * js_RegExpClass) just return JS_TRUE in this case * and leave *@vp unchanged. Do the same here. * (Actually not quite the same, as we already used * @undef_to_jsval.) */ break; } return JS_TRUE; }
JSBool JsPointBinding::PropertyGet(JSContext *context, JSObject *obj, jsid id, jsval *val) { int propId = JSID_TO_INT(id); CCPoint *pPoint = static_cast<CCPoint*> (JS_GetPrivate(context, obj)); if (!pPoint) return JS_FALSE; float result = 0; switch (propId) { case X: result = pPoint->x; break; case Y: result = pPoint->y; break; default: break; } jsval resultVal; JS_NewNumberValue(context, result, &resultVal); JS_SET_RVAL(context, val, resultVal); return JS_TRUE; }
JSBool JSI_Console::setProperty(JSContext* UNUSED(cx), JSObject* UNUSED(obj), jsid id, jsval* vp) { if (!JSID_IS_INT(id)) return JS_TRUE; int i = JSID_TO_INT(id); switch (i) { case console_visible: try { g_Console->SetVisible(ToPrimitive<bool> (*vp)); return JS_TRUE; } catch (PSERROR_Scripting_ConversionFailed) { return JS_TRUE; } default: return JS_TRUE; } }
JSBool S_SimpleNativeClass::jsPropertySet(JSContext *cx, JSObject *obj, jsid _id, JSBool strict, jsval *val) { int32_t propId = JSID_TO_INT(_id); S_SimpleNativeClass *cobj; JSGET_PTRSHELL(S_SimpleNativeClass, cobj, obj); if (!cobj) return JS_FALSE; switch(propId) { case kSomeField: do { uint32_t tmp; JS_ValueToECMAUint32(cx, *val, &tmp); cobj->setSomeField(tmp); } while (0); break; case kSomeOtherField: do { uint32_t tmp; JS_ValueToECMAUint32(cx, *val, &tmp); cobj->setSomeOtherField(tmp); } while (0); break; case kAnotherMoreComplexField: do { char *tmp = JS_EncodeString(cx, JSVAL_TO_STRING(*val)); if (tmp) { cobj->setAnotherMoreComplexField(tmp); } } while (0); break; default: break; } return JS_TRUE; }
uint32_t IdWrapper::toInt32() const { uassert(ErrorCodes::TypeMismatch, "Cannot toInt32() non-integer jsid", JSID_IS_INT(_value)); return JSID_TO_INT(_value); }
int RUST_JSID_TO_INT(jsid id) { return JSID_TO_INT(id); }
bool ExposedPropertiesOnly::check(JSContext *cx, HandleObject wrapper, HandleId id, Wrapper::Action act) { RootedObject wrappedObject(cx, Wrapper::wrappedObject(wrapper)); if (act == Wrapper::CALL) return true; // For the case of getting a property descriptor, we allow if either GET or SET // is allowed, and rely on FilteringWrapper to filter out any disallowed accessors. if (act == Wrapper::GET_PROPERTY_DESCRIPTOR) { return check(cx, wrapper, id, Wrapper::GET) || check(cx, wrapper, id, Wrapper::SET); } RootedId exposedPropsId(cx, GetRTIdByIndex(cx, XPCJSRuntime::IDX_EXPOSEDPROPS)); // We need to enter the wrappee's compartment to look at __exposedProps__, // but we want to be in the wrapper's compartment if we call Deny(). // // Unfortunately, |cx| can be in either compartment when we call ::check. :-( JSAutoCompartment ac(cx, wrappedObject); bool found = false; if (!JS_HasPropertyById(cx, wrappedObject, exposedPropsId, &found)) return false; // Always permit access to "length" and indexed properties of arrays. if ((JS_IsArrayObject(cx, wrappedObject) || JS_IsTypedArrayObject(wrappedObject)) && ((JSID_IS_INT(id) && JSID_TO_INT(id) >= 0) || (JSID_IS_STRING(id) && JS_FlatStringEqualsAscii(JSID_TO_FLAT_STRING(id), "length")))) { return true; // Allow } // If no __exposedProps__ existed, deny access. if (!found) { return false; } if (id == JSID_VOID) return true; RootedValue exposedProps(cx); if (!JS_LookupPropertyById(cx, wrappedObject, exposedPropsId, &exposedProps)) return false; if (exposedProps.isNullOrUndefined()) return false; if (!exposedProps.isObject()) { EnterAndThrow(cx, wrapper, "__exposedProps__ must be undefined, null, or an Object"); return false; } RootedObject hallpass(cx, &exposedProps.toObject()); if (!AccessCheck::subsumes(js::UncheckedUnwrap(hallpass), wrappedObject)) { EnterAndThrow(cx, wrapper, "Invalid __exposedProps__"); return false; } Access access = NO_ACCESS; Rooted<JSPropertyDescriptor> desc(cx); if (!JS_GetPropertyDescriptorById(cx, hallpass, id, &desc)) { return false; // Error } if (!desc.object() || !desc.isEnumerable()) return false; if (!desc.value().isString()) { EnterAndThrow(cx, wrapper, "property must be a string"); return false; } JSFlatString *flat = JS_FlattenString(cx, desc.value().toString()); if (!flat) return false; size_t length = JS_GetStringLength(JS_FORGET_STRING_FLATNESS(flat)); for (size_t i = 0; i < length; ++i) { char16_t ch = JS_GetFlatStringCharAt(flat, i); switch (ch) { case 'r': if (access & READ) { EnterAndThrow(cx, wrapper, "duplicate 'readable' property flag"); return false; } access = Access(access | READ); break; case 'w': if (access & WRITE) { EnterAndThrow(cx, wrapper, "duplicate 'writable' property flag"); return false; } access = Access(access | WRITE); break; default: EnterAndThrow(cx, wrapper, "properties can only be readable or read and writable"); return false; } } if (access == NO_ACCESS) { EnterAndThrow(cx, wrapper, "specified properties must have a permission bit set"); return false; } if ((act == Wrapper::SET && !(access & WRITE)) || (act != Wrapper::SET && !(access & READ))) { return false; } return true; }
/* @smjs_globhist_item_class.getProperty */ static JSBool smjs_globhist_item_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp) { struct global_history_item *history_item; /* This can be called if @obj if not itself an instance of the * appropriate class but has one in its prototype chain. Fail * such calls. */ if (!JS_InstanceOf(ctx, obj, (JSClass *) &smjs_globhist_item_class, NULL)) return JS_FALSE; history_item = JS_GetInstancePrivate(ctx, obj, (JSClass *) &smjs_globhist_item_class, NULL); if (!history_item) return JS_FALSE; undef_to_jsval(ctx, vp); if (!JSID_IS_INT(id)) return JS_FALSE; switch (JSID_TO_INT(id)) { case GLOBHIST_TITLE: *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(smjs_ctx, history_item->title)); return JS_TRUE; case GLOBHIST_URL: *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(smjs_ctx, history_item->url)); return JS_TRUE; case GLOBHIST_LAST_VISIT: /* TODO: I'd rather return a date object, but that introduces * synchronisation issues: * * - How do we cause a change to that date object to affect * the actual global history item? * - How do we get a change to that global history item * to affect all date objects? * * The biggest obstacle is that we have no way to trigger code * when one messes with the date object. * * -- Miciah */ /* XXX: Currently, ECMAScript gets seconds since the epoch. * Since the Date object uses milliseconds since the epoch, * I'd rather export that, but SpiderMonkey doesn't provide * a suitable type. -- Miciah */ JS_NewNumberValue(smjs_ctx, history_item->last_visit, vp); return JS_TRUE; default: /* Unrecognized integer property ID; someone is using * the object as an array. SMJS builtin classes (e.g. * js_RegExpClass) just return JS_TRUE in this case * and leave *@vp unchanged. Do the same here. * (Actually not quite the same, as we already used * @undef_to_jsval.) */ return JS_TRUE; } }
/* @cache_entry_class.setProperty */ static JSBool cache_entry_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval *vp) { struct cache_entry *cached; JSBool ret; /* This can be called if @obj if not itself an instance of the * appropriate class but has one in its prototype chain. Fail * such calls. */ if (!JS_InstanceOf(ctx, obj, (JSClass *) &cache_entry_class, NULL)) return JS_FALSE; cached = JS_GetInstancePrivate(ctx, obj, (JSClass *) &cache_entry_class, NULL); if (!cached) return JS_FALSE; /* already detached */ assert(cache_entry_is_valid(cached)); if_assert_failed return JS_FALSE; /* Get a strong reference to the cache entry to prevent it * from being deleted if some function called below decides to * collect garbage. After this, all code paths must * eventually unlock the object. */ object_lock(cached); if (!JSID_IS_INT(id)) ret = JS_FALSE; else switch (JSID_TO_INT(id)) { case CACHE_ENTRY_CONTENT: { JSString *jsstr = JS_ValueToString(smjs_ctx, *vp); unsigned char *str = JS_EncodeString(smjs_ctx, jsstr); size_t len = JS_GetStringLength(jsstr); add_fragment(cached, 0, str, len); normalize_cache_entry(cached, len); ret = JS_TRUE; break; } case CACHE_ENTRY_TYPE: { JSString *jsstr = JS_ValueToString(smjs_ctx, *vp); unsigned char *str = JS_EncodeString(smjs_ctx, jsstr); mem_free_set(&cached->content_type, stracpy(str)); ret = JS_TRUE; break; } case CACHE_ENTRY_HEAD: { JSString *jsstr = JS_ValueToString(smjs_ctx, *vp); unsigned char *str = JS_EncodeString(smjs_ctx, jsstr); mem_free_set(&cached->head, stracpy(str)); ret = JS_TRUE; break; } default: /* Unrecognized integer property ID; someone is using * the object as an array. SMJS builtin classes (e.g. * js_RegExpClass) just return JS_TRUE in this case. * Do the same here. */ ret = JS_TRUE; break; } object_unlock(cached); return ret; }
/* @cache_entry_class.getProperty */ static JSBool cache_entry_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp) { struct cache_entry *cached; JSBool ret; /* This can be called if @obj if not itself an instance of the * appropriate class but has one in its prototype chain. Fail * such calls. */ if (!JS_InstanceOf(ctx, obj, (JSClass *) &cache_entry_class, NULL)) return JS_FALSE; cached = JS_GetInstancePrivate(ctx, obj, (JSClass *) &cache_entry_class, NULL); if (!cached) return JS_FALSE; /* already detached */ assert(cache_entry_is_valid(cached)); if_assert_failed return JS_FALSE; /* Get a strong reference to the cache entry to prevent it * from being deleted if some function called below decides to * collect garbage. After this, all code paths must * eventually unlock the object. */ object_lock(cached); undef_to_jsval(ctx, vp); if (!JSID_IS_INT(id)) ret = JS_FALSE; else switch (JSID_TO_INT(id)) { case CACHE_ENTRY_CONTENT: { struct fragment *fragment = get_cache_fragment(cached); if (!fragment) { ret = JS_FALSE; break; } *vp = STRING_TO_JSVAL(JS_NewStringCopyN(smjs_ctx, fragment->data, fragment->length)); ret = JS_TRUE; break; } case CACHE_ENTRY_TYPE: *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(smjs_ctx, cached->content_type)); ret = JS_TRUE; break; case CACHE_ENTRY_HEAD: *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(smjs_ctx, cached->head)); ret = JS_TRUE; break; case CACHE_ENTRY_LENGTH: *vp = INT_TO_JSVAL(cached->length); ret = JS_TRUE; break; case CACHE_ENTRY_URI: *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(smjs_ctx, struri(cached->uri))); ret = JS_TRUE; break; default: /* Unrecognized integer property ID; someone is using * the object as an array. SMJS builtin classes (e.g. * js_RegExpClass) just return JS_TRUE in this case * and leave *@vp unchanged. Do the same here. * (Actually not quite the same, as we already used * @undef_to_jsval.) */ ret = JS_TRUE; break; } object_unlock(cached); return ret; }
bool ExposedPropertiesOnly::check(JSContext* cx, HandleObject wrapper, HandleId id, Wrapper::Action act) { RootedObject wrappedObject(cx, Wrapper::wrappedObject(wrapper)); if (act == Wrapper::CALL) return false; // For the case of getting a property descriptor, we allow if either GET or SET // is allowed, and rely on FilteringWrapper to filter out any disallowed accessors. if (act == Wrapper::GET_PROPERTY_DESCRIPTOR) { return check(cx, wrapper, id, Wrapper::GET) || check(cx, wrapper, id, Wrapper::SET); } RootedId exposedPropsId(cx, GetRTIdByIndex(cx, XPCJSRuntime::IDX_EXPOSEDPROPS)); // We need to enter the wrappee's compartment to look at __exposedProps__, // but we want to be in the wrapper's compartment if we call Deny(). // // Unfortunately, |cx| can be in either compartment when we call ::check. :-( JSAutoCompartment ac(cx, wrappedObject); bool found = false; if (!JS_HasPropertyById(cx, wrappedObject, exposedPropsId, &found)) return false; // If no __exposedProps__ existed, deny access. if (!found) { // Previously we automatically granted access to indexed properties and // .length for Array COWs. We're not doing that anymore, so make sure to // let people know what's going on. bool isArray; if (!JS_IsArrayObject(cx, wrappedObject, &isArray)) return false; if (!isArray) isArray = JS_IsTypedArrayObject(wrappedObject); bool isIndexedAccessOnArray = isArray && JSID_IS_INT(id) && JSID_TO_INT(id) >= 0; bool isLengthAccessOnArray = isArray && JSID_IS_STRING(id) && JS_FlatStringEqualsAscii(JSID_TO_FLAT_STRING(id), "length"); if (isIndexedAccessOnArray || isLengthAccessOnArray) { JSAutoCompartment ac2(cx, wrapper); ReportWrapperDenial(cx, id, WrapperDenialForCOW, "Access to elements and length of privileged Array not permitted"); } return false; } if (id == JSID_VOID) return true; Rooted<JSPropertyDescriptor> desc(cx); if (!JS_GetPropertyDescriptorById(cx, wrappedObject, exposedPropsId, &desc)) return false; if (!desc.object()) return false; if (desc.hasGetterOrSetter()) { EnterAndThrow(cx, wrapper, "__exposedProps__ must be a value property"); return false; } RootedValue exposedProps(cx, desc.value()); if (exposedProps.isNullOrUndefined()) return false; if (!exposedProps.isObject()) { EnterAndThrow(cx, wrapper, "__exposedProps__ must be undefined, null, or an Object"); return false; } RootedObject hallpass(cx, &exposedProps.toObject()); if (!AccessCheck::subsumes(js::UncheckedUnwrap(hallpass), wrappedObject)) { EnterAndThrow(cx, wrapper, "Invalid __exposedProps__"); return false; } Access access = NO_ACCESS; if (!JS_GetPropertyDescriptorById(cx, hallpass, id, &desc)) { return false; // Error } if (!desc.object() || !desc.enumerable()) return false; if (!desc.value().isString()) { EnterAndThrow(cx, wrapper, "property must be a string"); return false; } JSFlatString* flat = JS_FlattenString(cx, desc.value().toString()); if (!flat) return false; size_t length = JS_GetStringLength(JS_FORGET_STRING_FLATNESS(flat)); for (size_t i = 0; i < length; ++i) { char16_t ch = JS_GetFlatStringCharAt(flat, i); switch (ch) { case 'r': if (access & READ) { EnterAndThrow(cx, wrapper, "duplicate 'readable' property flag"); return false; } access = Access(access | READ); break; case 'w': if (access & WRITE) { EnterAndThrow(cx, wrapper, "duplicate 'writable' property flag"); return false; } access = Access(access | WRITE); break; default: EnterAndThrow(cx, wrapper, "properties can only be readable or read and writable"); return false; } } if (access == NO_ACCESS) { EnterAndThrow(cx, wrapper, "specified properties must have a permission bit set"); return false; } if ((act == Wrapper::SET && !(access & WRITE)) || (act != Wrapper::SET && !(access & READ))) { return false; } // Inspect the property on the underlying object to check for red flags. if (!JS_GetPropertyDescriptorById(cx, wrappedObject, id, &desc)) return false; // Reject accessor properties. if (desc.hasGetterOrSetter()) { EnterAndThrow(cx, wrapper, "Exposing privileged accessor properties is prohibited"); return false; } // Reject privileged or cross-origin callables. if (desc.value().isObject()) { RootedObject maybeCallable(cx, js::UncheckedUnwrap(&desc.value().toObject())); if (JS::IsCallable(maybeCallable) && !AccessCheck::subsumes(wrapper, maybeCallable)) { EnterAndThrow(cx, wrapper, "Exposing privileged or cross-origin callable is prohibited"); return false; } } return true; }