Line data Source code
1 : /* THIS FILE IS AUTOGENERATED FROM U2F.webidl BY Codegen.py - DO NOT EDIT */
2 :
3 : #include "AtomList.h"
4 : #include "U2FBinding.h"
5 : #include "WrapperFactory.h"
6 : #include "jsapi.h"
7 : #include "mozilla/OwningNonNull.h"
8 : #include "mozilla/Preferences.h"
9 : #include "mozilla/dom/BindingUtils.h"
10 : #include "mozilla/dom/DOMJSClass.h"
11 : #include "mozilla/dom/NonRefcountedDOMObject.h"
12 : #include "mozilla/dom/Nullable.h"
13 : #include "mozilla/dom/PrimitiveConversions.h"
14 : #include "mozilla/dom/ScriptSettings.h"
15 : #include "mozilla/dom/SimpleGlobalObject.h"
16 : #include "mozilla/dom/U2F.h"
17 : #include "mozilla/dom/XrayExpandoClass.h"
18 :
19 : namespace mozilla {
20 : namespace dom {
21 :
22 : namespace TransportValues {
23 : extern const EnumEntry strings[5] = {
24 : {"bt", 2},
25 : {"ble", 3},
26 : {"nfc", 3},
27 : {"usb", 3},
28 : { nullptr, 0 }
29 : };
30 : } // namespace TransportValues
31 :
32 : bool
33 0 : ToJSValue(JSContext* aCx, Transport aArgument, JS::MutableHandle<JS::Value> aValue)
34 : {
35 0 : MOZ_ASSERT(uint32_t(aArgument) < ArrayLength(TransportValues::strings));
36 : JSString* resultStr =
37 0 : JS_NewStringCopyN(aCx, TransportValues::strings[uint32_t(aArgument)].value,
38 0 : TransportValues::strings[uint32_t(aArgument)].length);
39 0 : if (!resultStr) {
40 0 : return false;
41 : }
42 0 : aValue.setString(resultStr);
43 0 : return true;
44 : }
45 :
46 :
47 :
48 0 : RegisterRequest::RegisterRequest()
49 : {
50 : // Safe to pass a null context if we pass a null value
51 0 : Init(nullptr, JS::NullHandleValue);
52 0 : }
53 :
54 :
55 :
56 : bool
57 0 : RegisterRequest::InitIds(JSContext* cx, RegisterRequestAtoms* atomsCache)
58 : {
59 0 : MOZ_ASSERT(!*reinterpret_cast<jsid**>(atomsCache));
60 :
61 : // Initialize these in reverse order so that any failure leaves the first one
62 : // uninitialized.
63 0 : if (!atomsCache->version_id.init(cx, "version") ||
64 0 : !atomsCache->challenge_id.init(cx, "challenge")) {
65 0 : return false;
66 : }
67 0 : return true;
68 : }
69 :
70 : bool
71 0 : RegisterRequest::Init(JSContext* cx, JS::Handle<JS::Value> val, const char* sourceDescription, bool passedToJSImpl)
72 : {
73 : // Passing a null JSContext is OK only if we're initing from null,
74 : // Since in that case we will not have to do any property gets
75 : // Also evaluate isNullOrUndefined in order to avoid false-positive
76 : // checkers by static analysis tools
77 0 : MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined());
78 0 : RegisterRequestAtoms* atomsCache = nullptr;
79 0 : if (cx) {
80 0 : atomsCache = GetAtomCache<RegisterRequestAtoms>(cx);
81 0 : if (!*reinterpret_cast<jsid**>(atomsCache) && !InitIds(cx, atomsCache)) {
82 0 : return false;
83 : }
84 : }
85 :
86 0 : if (!IsConvertibleToDictionary(val)) {
87 0 : return ThrowErrorMessage(cx, MSG_NOT_DICTIONARY, sourceDescription);
88 : }
89 :
90 0 : bool isNull = val.isNullOrUndefined();
91 : // We only need these if !isNull, in which case we have |cx|.
92 0 : Maybe<JS::Rooted<JSObject *> > object;
93 0 : Maybe<JS::Rooted<JS::Value> > temp;
94 0 : if (!isNull) {
95 0 : MOZ_ASSERT(cx);
96 0 : object.emplace(cx, &val.toObject());
97 0 : temp.emplace(cx);
98 : }
99 0 : if (!isNull) {
100 0 : if (!JS_GetPropertyById(cx, *object, atomsCache->challenge_id, temp.ptr())) {
101 0 : return false;
102 : }
103 : }
104 0 : if (!isNull && !temp->isUndefined()) {
105 0 : mChallenge.Construct();
106 0 : if (!ConvertJSValueToString(cx, temp.ref(), eStringify, eStringify, (mChallenge.Value()))) {
107 0 : return false;
108 : }
109 0 : mIsAnyMemberPresent = true;
110 : }
111 :
112 0 : if (!isNull) {
113 0 : if (!JS_GetPropertyById(cx, *object, atomsCache->version_id, temp.ptr())) {
114 0 : return false;
115 : }
116 : }
117 0 : if (!isNull && !temp->isUndefined()) {
118 0 : mVersion.Construct();
119 0 : if (!ConvertJSValueToString(cx, temp.ref(), eStringify, eStringify, (mVersion.Value()))) {
120 0 : return false;
121 : }
122 0 : mIsAnyMemberPresent = true;
123 : }
124 0 : return true;
125 : }
126 :
127 : bool
128 0 : RegisterRequest::Init(const nsAString& aJSON)
129 : {
130 0 : AutoJSAPI jsapi;
131 0 : JSObject* cleanGlobal = SimpleGlobalObject::Create(SimpleGlobalObject::GlobalType::BindingDetail);
132 0 : if (!cleanGlobal) {
133 0 : return false;
134 : }
135 0 : if (!jsapi.Init(cleanGlobal)) {
136 0 : return false;
137 : }
138 0 : JSContext* cx = jsapi.cx();
139 0 : JS::Rooted<JS::Value> json(cx);
140 0 : bool ok = ParseJSON(cx, aJSON, &json);
141 0 : NS_ENSURE_TRUE(ok, false);
142 0 : return Init(cx, json);
143 : }
144 :
145 : bool
146 0 : RegisterRequest::ToObjectInternal(JSContext* cx, JS::MutableHandle<JS::Value> rval) const
147 : {
148 0 : RegisterRequestAtoms* atomsCache = GetAtomCache<RegisterRequestAtoms>(cx);
149 0 : if (!*reinterpret_cast<jsid**>(atomsCache) && !InitIds(cx, atomsCache)) {
150 0 : return false;
151 : }
152 :
153 0 : JS::Rooted<JSObject*> obj(cx, JS_NewPlainObject(cx));
154 0 : if (!obj) {
155 0 : return false;
156 : }
157 0 : rval.set(JS::ObjectValue(*obj));
158 :
159 0 : if (mChallenge.WasPassed()) {
160 : do {
161 : // block for our 'break' successCode and scope for 'temp' and 'currentValue'
162 0 : JS::Rooted<JS::Value> temp(cx);
163 0 : nsString const & currentValue = mChallenge.InternalValue();
164 0 : if (!xpc::NonVoidStringToJsval(cx, currentValue, &temp)) {
165 0 : return false;
166 : }
167 0 : if (!JS_DefinePropertyById(cx, obj, atomsCache->challenge_id, temp, JSPROP_ENUMERATE)) {
168 0 : return false;
169 : }
170 0 : break;
171 : } while(0);
172 : }
173 :
174 0 : if (mVersion.WasPassed()) {
175 : do {
176 : // block for our 'break' successCode and scope for 'temp' and 'currentValue'
177 0 : JS::Rooted<JS::Value> temp(cx);
178 0 : nsString const & currentValue = mVersion.InternalValue();
179 0 : if (!xpc::NonVoidStringToJsval(cx, currentValue, &temp)) {
180 0 : return false;
181 : }
182 0 : if (!JS_DefinePropertyById(cx, obj, atomsCache->version_id, temp, JSPROP_ENUMERATE)) {
183 0 : return false;
184 : }
185 0 : break;
186 : } while(0);
187 : }
188 :
189 0 : return true;
190 : }
191 :
192 : bool
193 0 : RegisterRequest::ToJSON(nsAString& aJSON) const
194 : {
195 0 : AutoJSAPI jsapi;
196 0 : jsapi.Init();
197 0 : JSContext *cx = jsapi.cx();
198 : // It's safe to use UnprivilegedJunkScopeOrWorkerGlobal here
199 : // because we'll only be creating objects, in ways that have no
200 : // side-effects, followed by a call to JS::ToJSONMaybeSafely,
201 : // which likewise guarantees no side-effects for the sorts of
202 : // things we will pass it.
203 0 : JSAutoCompartment ac(cx, binding_detail::UnprivilegedJunkScopeOrWorkerGlobal());
204 0 : JS::Rooted<JS::Value> val(cx);
205 0 : if (!ToObjectInternal(cx, &val)) {
206 0 : return false;
207 : }
208 0 : JS::Rooted<JSObject*> obj(cx, &val.toObject());
209 0 : return StringifyToJSON(cx, obj, aJSON);
210 : }
211 :
212 : void
213 0 : RegisterRequest::TraceDictionary(JSTracer* trc)
214 : {
215 0 : }
216 :
217 : RegisterRequest&
218 0 : RegisterRequest::operator=(const RegisterRequest& aOther)
219 : {
220 0 : mChallenge.Reset();
221 0 : if (aOther.mChallenge.WasPassed()) {
222 0 : mChallenge.Construct(aOther.mChallenge.Value());
223 : }
224 0 : mVersion.Reset();
225 0 : if (aOther.mVersion.WasPassed()) {
226 0 : mVersion.Construct(aOther.mVersion.Value());
227 : }
228 0 : return *this;
229 : }
230 :
231 : namespace binding_detail {
232 : } // namespace binding_detail
233 :
234 :
235 :
236 0 : RegisterResponse::RegisterResponse()
237 : {
238 : // Safe to pass a null context if we pass a null value
239 0 : Init(nullptr, JS::NullHandleValue);
240 0 : }
241 :
242 :
243 :
244 : bool
245 0 : RegisterResponse::InitIds(JSContext* cx, RegisterResponseAtoms* atomsCache)
246 : {
247 0 : MOZ_ASSERT(!*reinterpret_cast<jsid**>(atomsCache));
248 :
249 : // Initialize these in reverse order so that any failure leaves the first one
250 : // uninitialized.
251 0 : if (!atomsCache->version_id.init(cx, "version") ||
252 0 : !atomsCache->registrationData_id.init(cx, "registrationData") ||
253 0 : !atomsCache->errorMessage_id.init(cx, "errorMessage") ||
254 0 : !atomsCache->errorCode_id.init(cx, "errorCode") ||
255 0 : !atomsCache->clientData_id.init(cx, "clientData")) {
256 0 : return false;
257 : }
258 0 : return true;
259 : }
260 :
261 : bool
262 0 : RegisterResponse::Init(JSContext* cx, JS::Handle<JS::Value> val, const char* sourceDescription, bool passedToJSImpl)
263 : {
264 : // Passing a null JSContext is OK only if we're initing from null,
265 : // Since in that case we will not have to do any property gets
266 : // Also evaluate isNullOrUndefined in order to avoid false-positive
267 : // checkers by static analysis tools
268 0 : MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined());
269 0 : RegisterResponseAtoms* atomsCache = nullptr;
270 0 : if (cx) {
271 0 : atomsCache = GetAtomCache<RegisterResponseAtoms>(cx);
272 0 : if (!*reinterpret_cast<jsid**>(atomsCache) && !InitIds(cx, atomsCache)) {
273 0 : return false;
274 : }
275 : }
276 :
277 0 : if (!IsConvertibleToDictionary(val)) {
278 0 : return ThrowErrorMessage(cx, MSG_NOT_DICTIONARY, sourceDescription);
279 : }
280 :
281 0 : bool isNull = val.isNullOrUndefined();
282 : // We only need these if !isNull, in which case we have |cx|.
283 0 : Maybe<JS::Rooted<JSObject *> > object;
284 0 : Maybe<JS::Rooted<JS::Value> > temp;
285 0 : if (!isNull) {
286 0 : MOZ_ASSERT(cx);
287 0 : object.emplace(cx, &val.toObject());
288 0 : temp.emplace(cx);
289 : }
290 0 : if (!isNull) {
291 0 : if (!JS_GetPropertyById(cx, *object, atomsCache->clientData_id, temp.ptr())) {
292 0 : return false;
293 : }
294 : }
295 0 : if (!isNull && !temp->isUndefined()) {
296 0 : mClientData.Construct();
297 0 : if (!ConvertJSValueToString(cx, temp.ref(), eStringify, eStringify, (mClientData.Value()))) {
298 0 : return false;
299 : }
300 0 : mIsAnyMemberPresent = true;
301 : }
302 :
303 0 : if (!isNull) {
304 0 : if (!JS_GetPropertyById(cx, *object, atomsCache->errorCode_id, temp.ptr())) {
305 0 : return false;
306 : }
307 : }
308 0 : if (!isNull && !temp->isUndefined()) {
309 0 : mErrorCode.Construct();
310 0 : if (temp.ref().isNullOrUndefined()) {
311 0 : (mErrorCode.Value()).SetNull();
312 0 : } else if (!ValueToPrimitive<uint16_t, eDefault>(cx, temp.ref(), &(mErrorCode.Value()).SetValue())) {
313 0 : return false;
314 : }
315 0 : mIsAnyMemberPresent = true;
316 : }
317 :
318 0 : if (!isNull) {
319 0 : if (!JS_GetPropertyById(cx, *object, atomsCache->errorMessage_id, temp.ptr())) {
320 0 : return false;
321 : }
322 : }
323 0 : if (!isNull && !temp->isUndefined()) {
324 0 : mErrorMessage.Construct();
325 0 : if (!ConvertJSValueToString(cx, temp.ref(), eNull, eNull, (mErrorMessage.Value()))) {
326 0 : return false;
327 : }
328 0 : mIsAnyMemberPresent = true;
329 : }
330 :
331 0 : if (!isNull) {
332 0 : if (!JS_GetPropertyById(cx, *object, atomsCache->registrationData_id, temp.ptr())) {
333 0 : return false;
334 : }
335 : }
336 0 : if (!isNull && !temp->isUndefined()) {
337 0 : mRegistrationData.Construct();
338 0 : if (!ConvertJSValueToString(cx, temp.ref(), eStringify, eStringify, (mRegistrationData.Value()))) {
339 0 : return false;
340 : }
341 0 : mIsAnyMemberPresent = true;
342 : }
343 :
344 0 : if (!isNull) {
345 0 : if (!JS_GetPropertyById(cx, *object, atomsCache->version_id, temp.ptr())) {
346 0 : return false;
347 : }
348 : }
349 0 : if (!isNull && !temp->isUndefined()) {
350 0 : mVersion.Construct();
351 0 : if (!ConvertJSValueToString(cx, temp.ref(), eStringify, eStringify, (mVersion.Value()))) {
352 0 : return false;
353 : }
354 0 : mIsAnyMemberPresent = true;
355 : }
356 0 : return true;
357 : }
358 :
359 : bool
360 0 : RegisterResponse::Init(const nsAString& aJSON)
361 : {
362 0 : AutoJSAPI jsapi;
363 0 : JSObject* cleanGlobal = SimpleGlobalObject::Create(SimpleGlobalObject::GlobalType::BindingDetail);
364 0 : if (!cleanGlobal) {
365 0 : return false;
366 : }
367 0 : if (!jsapi.Init(cleanGlobal)) {
368 0 : return false;
369 : }
370 0 : JSContext* cx = jsapi.cx();
371 0 : JS::Rooted<JS::Value> json(cx);
372 0 : bool ok = ParseJSON(cx, aJSON, &json);
373 0 : NS_ENSURE_TRUE(ok, false);
374 0 : return Init(cx, json);
375 : }
376 :
377 : bool
378 0 : RegisterResponse::ToObjectInternal(JSContext* cx, JS::MutableHandle<JS::Value> rval) const
379 : {
380 0 : RegisterResponseAtoms* atomsCache = GetAtomCache<RegisterResponseAtoms>(cx);
381 0 : if (!*reinterpret_cast<jsid**>(atomsCache) && !InitIds(cx, atomsCache)) {
382 0 : return false;
383 : }
384 :
385 0 : JS::Rooted<JSObject*> obj(cx, JS_NewPlainObject(cx));
386 0 : if (!obj) {
387 0 : return false;
388 : }
389 0 : rval.set(JS::ObjectValue(*obj));
390 :
391 0 : if (mClientData.WasPassed()) {
392 : do {
393 : // block for our 'break' successCode and scope for 'temp' and 'currentValue'
394 0 : JS::Rooted<JS::Value> temp(cx);
395 0 : nsString const & currentValue = mClientData.InternalValue();
396 0 : if (!xpc::NonVoidStringToJsval(cx, currentValue, &temp)) {
397 0 : return false;
398 : }
399 0 : if (!JS_DefinePropertyById(cx, obj, atomsCache->clientData_id, temp, JSPROP_ENUMERATE)) {
400 0 : return false;
401 : }
402 0 : break;
403 : } while(0);
404 : }
405 :
406 0 : if (mErrorCode.WasPassed()) {
407 : do {
408 : // block for our 'break' successCode and scope for 'temp' and 'currentValue'
409 0 : JS::Rooted<JS::Value> temp(cx);
410 0 : Nullable<uint16_t> const & currentValue = mErrorCode.InternalValue();
411 0 : if (currentValue.IsNull()) {
412 0 : temp.setNull();
413 0 : if (!JS_DefinePropertyById(cx, obj, atomsCache->errorCode_id, temp, JSPROP_ENUMERATE)) {
414 0 : return false;
415 : }
416 0 : break;
417 : }
418 0 : temp.setInt32(int32_t(currentValue.Value()));
419 0 : if (!JS_DefinePropertyById(cx, obj, atomsCache->errorCode_id, temp, JSPROP_ENUMERATE)) {
420 0 : return false;
421 : }
422 0 : break;
423 : } while(0);
424 : }
425 :
426 0 : if (mErrorMessage.WasPassed()) {
427 : do {
428 : // block for our 'break' successCode and scope for 'temp' and 'currentValue'
429 0 : JS::Rooted<JS::Value> temp(cx);
430 0 : nsString const & currentValue = mErrorMessage.InternalValue();
431 0 : if (!xpc::StringToJsval(cx, currentValue, &temp)) {
432 0 : return false;
433 : }
434 0 : if (!JS_DefinePropertyById(cx, obj, atomsCache->errorMessage_id, temp, JSPROP_ENUMERATE)) {
435 0 : return false;
436 : }
437 0 : break;
438 : } while(0);
439 : }
440 :
441 0 : if (mRegistrationData.WasPassed()) {
442 : do {
443 : // block for our 'break' successCode and scope for 'temp' and 'currentValue'
444 0 : JS::Rooted<JS::Value> temp(cx);
445 0 : nsString const & currentValue = mRegistrationData.InternalValue();
446 0 : if (!xpc::NonVoidStringToJsval(cx, currentValue, &temp)) {
447 0 : return false;
448 : }
449 0 : if (!JS_DefinePropertyById(cx, obj, atomsCache->registrationData_id, temp, JSPROP_ENUMERATE)) {
450 0 : return false;
451 : }
452 0 : break;
453 : } while(0);
454 : }
455 :
456 0 : if (mVersion.WasPassed()) {
457 : do {
458 : // block for our 'break' successCode and scope for 'temp' and 'currentValue'
459 0 : JS::Rooted<JS::Value> temp(cx);
460 0 : nsString const & currentValue = mVersion.InternalValue();
461 0 : if (!xpc::NonVoidStringToJsval(cx, currentValue, &temp)) {
462 0 : return false;
463 : }
464 0 : if (!JS_DefinePropertyById(cx, obj, atomsCache->version_id, temp, JSPROP_ENUMERATE)) {
465 0 : return false;
466 : }
467 0 : break;
468 : } while(0);
469 : }
470 :
471 0 : return true;
472 : }
473 :
474 : bool
475 0 : RegisterResponse::ToJSON(nsAString& aJSON) const
476 : {
477 0 : AutoJSAPI jsapi;
478 0 : jsapi.Init();
479 0 : JSContext *cx = jsapi.cx();
480 : // It's safe to use UnprivilegedJunkScopeOrWorkerGlobal here
481 : // because we'll only be creating objects, in ways that have no
482 : // side-effects, followed by a call to JS::ToJSONMaybeSafely,
483 : // which likewise guarantees no side-effects for the sorts of
484 : // things we will pass it.
485 0 : JSAutoCompartment ac(cx, binding_detail::UnprivilegedJunkScopeOrWorkerGlobal());
486 0 : JS::Rooted<JS::Value> val(cx);
487 0 : if (!ToObjectInternal(cx, &val)) {
488 0 : return false;
489 : }
490 0 : JS::Rooted<JSObject*> obj(cx, &val.toObject());
491 0 : return StringifyToJSON(cx, obj, aJSON);
492 : }
493 :
494 : void
495 0 : RegisterResponse::TraceDictionary(JSTracer* trc)
496 : {
497 0 : }
498 :
499 : RegisterResponse&
500 0 : RegisterResponse::operator=(const RegisterResponse& aOther)
501 : {
502 0 : mClientData.Reset();
503 0 : if (aOther.mClientData.WasPassed()) {
504 0 : mClientData.Construct(aOther.mClientData.Value());
505 : }
506 0 : mErrorCode.Reset();
507 0 : if (aOther.mErrorCode.WasPassed()) {
508 0 : mErrorCode.Construct(aOther.mErrorCode.Value());
509 : }
510 0 : mErrorMessage.Reset();
511 0 : if (aOther.mErrorMessage.WasPassed()) {
512 0 : mErrorMessage.Construct(aOther.mErrorMessage.Value());
513 : }
514 0 : mRegistrationData.Reset();
515 0 : if (aOther.mRegistrationData.WasPassed()) {
516 0 : mRegistrationData.Construct(aOther.mRegistrationData.Value());
517 : }
518 0 : mVersion.Reset();
519 0 : if (aOther.mVersion.WasPassed()) {
520 0 : mVersion.Construct(aOther.mVersion.Value());
521 : }
522 0 : return *this;
523 : }
524 :
525 : namespace binding_detail {
526 : } // namespace binding_detail
527 :
528 :
529 :
530 0 : RegisteredKey::RegisteredKey()
531 : {
532 : // Safe to pass a null context if we pass a null value
533 0 : Init(nullptr, JS::NullHandleValue);
534 0 : }
535 :
536 :
537 :
538 : bool
539 0 : RegisteredKey::InitIds(JSContext* cx, RegisteredKeyAtoms* atomsCache)
540 : {
541 0 : MOZ_ASSERT(!*reinterpret_cast<jsid**>(atomsCache));
542 :
543 : // Initialize these in reverse order so that any failure leaves the first one
544 : // uninitialized.
545 0 : if (!atomsCache->version_id.init(cx, "version") ||
546 0 : !atomsCache->transports_id.init(cx, "transports") ||
547 0 : !atomsCache->keyHandle_id.init(cx, "keyHandle") ||
548 0 : !atomsCache->appId_id.init(cx, "appId")) {
549 0 : return false;
550 : }
551 0 : return true;
552 : }
553 :
554 : bool
555 0 : RegisteredKey::Init(JSContext* cx, JS::Handle<JS::Value> val, const char* sourceDescription, bool passedToJSImpl)
556 : {
557 : // Passing a null JSContext is OK only if we're initing from null,
558 : // Since in that case we will not have to do any property gets
559 : // Also evaluate isNullOrUndefined in order to avoid false-positive
560 : // checkers by static analysis tools
561 0 : MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined());
562 0 : RegisteredKeyAtoms* atomsCache = nullptr;
563 0 : if (cx) {
564 0 : atomsCache = GetAtomCache<RegisteredKeyAtoms>(cx);
565 0 : if (!*reinterpret_cast<jsid**>(atomsCache) && !InitIds(cx, atomsCache)) {
566 0 : return false;
567 : }
568 : }
569 :
570 0 : if (!IsConvertibleToDictionary(val)) {
571 0 : return ThrowErrorMessage(cx, MSG_NOT_DICTIONARY, sourceDescription);
572 : }
573 :
574 0 : bool isNull = val.isNullOrUndefined();
575 : // We only need these if !isNull, in which case we have |cx|.
576 0 : Maybe<JS::Rooted<JSObject *> > object;
577 0 : Maybe<JS::Rooted<JS::Value> > temp;
578 0 : if (!isNull) {
579 0 : MOZ_ASSERT(cx);
580 0 : object.emplace(cx, &val.toObject());
581 0 : temp.emplace(cx);
582 : }
583 0 : if (!isNull) {
584 0 : if (!JS_GetPropertyById(cx, *object, atomsCache->appId_id, temp.ptr())) {
585 0 : return false;
586 : }
587 : }
588 0 : if (!isNull && !temp->isUndefined()) {
589 0 : mAppId.Construct();
590 0 : if (!ConvertJSValueToString(cx, temp.ref(), eNull, eNull, (mAppId.Value()))) {
591 0 : return false;
592 : }
593 0 : mIsAnyMemberPresent = true;
594 : }
595 :
596 0 : if (!isNull) {
597 0 : if (!JS_GetPropertyById(cx, *object, atomsCache->keyHandle_id, temp.ptr())) {
598 0 : return false;
599 : }
600 : }
601 0 : if (!isNull && !temp->isUndefined()) {
602 0 : mKeyHandle.Construct();
603 0 : if (!ConvertJSValueToString(cx, temp.ref(), eStringify, eStringify, (mKeyHandle.Value()))) {
604 0 : return false;
605 : }
606 0 : mIsAnyMemberPresent = true;
607 : }
608 :
609 0 : if (!isNull) {
610 0 : if (!JS_GetPropertyById(cx, *object, atomsCache->transports_id, temp.ptr())) {
611 0 : return false;
612 : }
613 : }
614 0 : if (!isNull && !temp->isUndefined()) {
615 0 : mTransports.Construct();
616 0 : if (temp.ref().isObject()) {
617 0 : JS::ForOfIterator iter(cx);
618 0 : if (!iter.init(temp.ref(), JS::ForOfIterator::AllowNonIterable)) {
619 0 : return false;
620 : }
621 0 : if (!iter.valueIsIterable()) {
622 0 : ThrowErrorMessage(cx, MSG_NOT_SEQUENCE, "'transports' member of RegisteredKey");
623 0 : return false;
624 : }
625 0 : Sequence<Transport> &arr = (mTransports.Value()).SetValue();
626 0 : JS::Rooted<JS::Value> temp(cx);
627 : while (true) {
628 : bool done;
629 0 : if (!iter.next(&temp, &done)) {
630 0 : return false;
631 : }
632 0 : if (done) {
633 0 : break;
634 : }
635 0 : Transport* slotPtr = arr.AppendElement(mozilla::fallible);
636 0 : if (!slotPtr) {
637 0 : JS_ReportOutOfMemory(cx);
638 0 : return false;
639 : }
640 0 : Transport& slot = *slotPtr;
641 : {
642 : int index;
643 0 : if (!FindEnumStringIndex<true>(cx, temp, TransportValues::strings, "Transport", "Element of 'transports' member of RegisteredKey", &index)) {
644 0 : return false;
645 : }
646 0 : MOZ_ASSERT(index >= 0);
647 0 : slot = static_cast<Transport>(index);
648 : }
649 0 : }
650 0 : } else if (temp.ref().isNullOrUndefined()) {
651 0 : (mTransports.Value()).SetNull();
652 : } else {
653 0 : ThrowErrorMessage(cx, MSG_NOT_SEQUENCE, "'transports' member of RegisteredKey");
654 0 : return false;
655 : }
656 0 : mIsAnyMemberPresent = true;
657 : }
658 :
659 0 : if (!isNull) {
660 0 : if (!JS_GetPropertyById(cx, *object, atomsCache->version_id, temp.ptr())) {
661 0 : return false;
662 : }
663 : }
664 0 : if (!isNull && !temp->isUndefined()) {
665 0 : mVersion.Construct();
666 0 : if (!ConvertJSValueToString(cx, temp.ref(), eStringify, eStringify, (mVersion.Value()))) {
667 0 : return false;
668 : }
669 0 : mIsAnyMemberPresent = true;
670 : }
671 0 : return true;
672 : }
673 :
674 : bool
675 0 : RegisteredKey::Init(const nsAString& aJSON)
676 : {
677 0 : AutoJSAPI jsapi;
678 0 : JSObject* cleanGlobal = SimpleGlobalObject::Create(SimpleGlobalObject::GlobalType::BindingDetail);
679 0 : if (!cleanGlobal) {
680 0 : return false;
681 : }
682 0 : if (!jsapi.Init(cleanGlobal)) {
683 0 : return false;
684 : }
685 0 : JSContext* cx = jsapi.cx();
686 0 : JS::Rooted<JS::Value> json(cx);
687 0 : bool ok = ParseJSON(cx, aJSON, &json);
688 0 : NS_ENSURE_TRUE(ok, false);
689 0 : return Init(cx, json);
690 : }
691 :
692 : bool
693 0 : RegisteredKey::ToObjectInternal(JSContext* cx, JS::MutableHandle<JS::Value> rval) const
694 : {
695 0 : RegisteredKeyAtoms* atomsCache = GetAtomCache<RegisteredKeyAtoms>(cx);
696 0 : if (!*reinterpret_cast<jsid**>(atomsCache) && !InitIds(cx, atomsCache)) {
697 0 : return false;
698 : }
699 :
700 0 : JS::Rooted<JSObject*> obj(cx, JS_NewPlainObject(cx));
701 0 : if (!obj) {
702 0 : return false;
703 : }
704 0 : rval.set(JS::ObjectValue(*obj));
705 :
706 0 : if (mAppId.WasPassed()) {
707 : do {
708 : // block for our 'break' successCode and scope for 'temp' and 'currentValue'
709 0 : JS::Rooted<JS::Value> temp(cx);
710 0 : nsString const & currentValue = mAppId.InternalValue();
711 0 : if (!xpc::StringToJsval(cx, currentValue, &temp)) {
712 0 : return false;
713 : }
714 0 : if (!JS_DefinePropertyById(cx, obj, atomsCache->appId_id, temp, JSPROP_ENUMERATE)) {
715 0 : return false;
716 : }
717 0 : break;
718 : } while(0);
719 : }
720 :
721 0 : if (mKeyHandle.WasPassed()) {
722 : do {
723 : // block for our 'break' successCode and scope for 'temp' and 'currentValue'
724 0 : JS::Rooted<JS::Value> temp(cx);
725 0 : nsString const & currentValue = mKeyHandle.InternalValue();
726 0 : if (!xpc::NonVoidStringToJsval(cx, currentValue, &temp)) {
727 0 : return false;
728 : }
729 0 : if (!JS_DefinePropertyById(cx, obj, atomsCache->keyHandle_id, temp, JSPROP_ENUMERATE)) {
730 0 : return false;
731 : }
732 0 : break;
733 : } while(0);
734 : }
735 :
736 0 : if (mTransports.WasPassed()) {
737 : do {
738 : // block for our 'break' successCode and scope for 'temp' and 'currentValue'
739 0 : JS::Rooted<JS::Value> temp(cx);
740 0 : Nullable<Sequence<Transport>> const & currentValue = mTransports.InternalValue();
741 :
742 0 : if (currentValue.IsNull()) {
743 0 : temp.setNull();
744 0 : if (!JS_DefinePropertyById(cx, obj, atomsCache->transports_id, temp, JSPROP_ENUMERATE)) {
745 0 : return false;
746 : }
747 0 : break;
748 : }
749 :
750 0 : uint32_t length = currentValue.Value().Length();
751 0 : JS::Rooted<JSObject*> returnArray(cx, JS_NewArrayObject(cx, length));
752 0 : if (!returnArray) {
753 0 : return false;
754 : }
755 : // Scope for 'tmp'
756 : {
757 0 : JS::Rooted<JS::Value> tmp(cx);
758 0 : for (uint32_t sequenceIdx0 = 0; sequenceIdx0 < length; ++sequenceIdx0) {
759 : // Control block to let us common up the JS_DefineElement calls when there
760 : // are different ways to succeed at wrapping the object.
761 : do {
762 0 : if (!ToJSValue(cx, currentValue.Value()[sequenceIdx0], &tmp)) {
763 0 : return false;
764 : }
765 0 : break;
766 : } while (0);
767 0 : if (!JS_DefineElement(cx, returnArray, sequenceIdx0, tmp,
768 : JSPROP_ENUMERATE)) {
769 0 : return false;
770 : }
771 : }
772 : }
773 0 : temp.setObject(*returnArray);
774 0 : if (!JS_DefinePropertyById(cx, obj, atomsCache->transports_id, temp, JSPROP_ENUMERATE)) {
775 0 : return false;
776 : }
777 0 : break;
778 : } while(0);
779 : }
780 :
781 0 : if (mVersion.WasPassed()) {
782 : do {
783 : // block for our 'break' successCode and scope for 'temp' and 'currentValue'
784 0 : JS::Rooted<JS::Value> temp(cx);
785 0 : nsString const & currentValue = mVersion.InternalValue();
786 0 : if (!xpc::NonVoidStringToJsval(cx, currentValue, &temp)) {
787 0 : return false;
788 : }
789 0 : if (!JS_DefinePropertyById(cx, obj, atomsCache->version_id, temp, JSPROP_ENUMERATE)) {
790 0 : return false;
791 : }
792 0 : break;
793 : } while(0);
794 : }
795 :
796 0 : return true;
797 : }
798 :
799 : bool
800 0 : RegisteredKey::ToJSON(nsAString& aJSON) const
801 : {
802 0 : AutoJSAPI jsapi;
803 0 : jsapi.Init();
804 0 : JSContext *cx = jsapi.cx();
805 : // It's safe to use UnprivilegedJunkScopeOrWorkerGlobal here
806 : // because we'll only be creating objects, in ways that have no
807 : // side-effects, followed by a call to JS::ToJSONMaybeSafely,
808 : // which likewise guarantees no side-effects for the sorts of
809 : // things we will pass it.
810 0 : JSAutoCompartment ac(cx, binding_detail::UnprivilegedJunkScopeOrWorkerGlobal());
811 0 : JS::Rooted<JS::Value> val(cx);
812 0 : if (!ToObjectInternal(cx, &val)) {
813 0 : return false;
814 : }
815 0 : JS::Rooted<JSObject*> obj(cx, &val.toObject());
816 0 : return StringifyToJSON(cx, obj, aJSON);
817 : }
818 :
819 : void
820 0 : RegisteredKey::TraceDictionary(JSTracer* trc)
821 : {
822 0 : }
823 :
824 : RegisteredKey&
825 0 : RegisteredKey::operator=(const RegisteredKey& aOther)
826 : {
827 0 : mAppId.Reset();
828 0 : if (aOther.mAppId.WasPassed()) {
829 0 : mAppId.Construct(aOther.mAppId.Value());
830 : }
831 0 : mKeyHandle.Reset();
832 0 : if (aOther.mKeyHandle.WasPassed()) {
833 0 : mKeyHandle.Construct(aOther.mKeyHandle.Value());
834 : }
835 0 : mTransports.Reset();
836 0 : if (aOther.mTransports.WasPassed()) {
837 0 : mTransports.Construct(aOther.mTransports.Value());
838 : }
839 0 : mVersion.Reset();
840 0 : if (aOther.mVersion.WasPassed()) {
841 0 : mVersion.Construct(aOther.mVersion.Value());
842 : }
843 0 : return *this;
844 : }
845 :
846 : namespace binding_detail {
847 : } // namespace binding_detail
848 :
849 :
850 :
851 0 : SignResponse::SignResponse()
852 : {
853 : // Safe to pass a null context if we pass a null value
854 0 : Init(nullptr, JS::NullHandleValue);
855 0 : }
856 :
857 :
858 :
859 : bool
860 0 : SignResponse::InitIds(JSContext* cx, SignResponseAtoms* atomsCache)
861 : {
862 0 : MOZ_ASSERT(!*reinterpret_cast<jsid**>(atomsCache));
863 :
864 : // Initialize these in reverse order so that any failure leaves the first one
865 : // uninitialized.
866 0 : if (!atomsCache->signatureData_id.init(cx, "signatureData") ||
867 0 : !atomsCache->keyHandle_id.init(cx, "keyHandle") ||
868 0 : !atomsCache->errorMessage_id.init(cx, "errorMessage") ||
869 0 : !atomsCache->errorCode_id.init(cx, "errorCode") ||
870 0 : !atomsCache->clientData_id.init(cx, "clientData")) {
871 0 : return false;
872 : }
873 0 : return true;
874 : }
875 :
876 : bool
877 0 : SignResponse::Init(JSContext* cx, JS::Handle<JS::Value> val, const char* sourceDescription, bool passedToJSImpl)
878 : {
879 : // Passing a null JSContext is OK only if we're initing from null,
880 : // Since in that case we will not have to do any property gets
881 : // Also evaluate isNullOrUndefined in order to avoid false-positive
882 : // checkers by static analysis tools
883 0 : MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined());
884 0 : SignResponseAtoms* atomsCache = nullptr;
885 0 : if (cx) {
886 0 : atomsCache = GetAtomCache<SignResponseAtoms>(cx);
887 0 : if (!*reinterpret_cast<jsid**>(atomsCache) && !InitIds(cx, atomsCache)) {
888 0 : return false;
889 : }
890 : }
891 :
892 0 : if (!IsConvertibleToDictionary(val)) {
893 0 : return ThrowErrorMessage(cx, MSG_NOT_DICTIONARY, sourceDescription);
894 : }
895 :
896 0 : bool isNull = val.isNullOrUndefined();
897 : // We only need these if !isNull, in which case we have |cx|.
898 0 : Maybe<JS::Rooted<JSObject *> > object;
899 0 : Maybe<JS::Rooted<JS::Value> > temp;
900 0 : if (!isNull) {
901 0 : MOZ_ASSERT(cx);
902 0 : object.emplace(cx, &val.toObject());
903 0 : temp.emplace(cx);
904 : }
905 0 : if (!isNull) {
906 0 : if (!JS_GetPropertyById(cx, *object, atomsCache->clientData_id, temp.ptr())) {
907 0 : return false;
908 : }
909 : }
910 0 : if (!isNull && !temp->isUndefined()) {
911 0 : mClientData.Construct();
912 0 : if (!ConvertJSValueToString(cx, temp.ref(), eStringify, eStringify, (mClientData.Value()))) {
913 0 : return false;
914 : }
915 0 : mIsAnyMemberPresent = true;
916 : }
917 :
918 0 : if (!isNull) {
919 0 : if (!JS_GetPropertyById(cx, *object, atomsCache->errorCode_id, temp.ptr())) {
920 0 : return false;
921 : }
922 : }
923 0 : if (!isNull && !temp->isUndefined()) {
924 0 : mErrorCode.Construct();
925 0 : if (temp.ref().isNullOrUndefined()) {
926 0 : (mErrorCode.Value()).SetNull();
927 0 : } else if (!ValueToPrimitive<uint16_t, eDefault>(cx, temp.ref(), &(mErrorCode.Value()).SetValue())) {
928 0 : return false;
929 : }
930 0 : mIsAnyMemberPresent = true;
931 : }
932 :
933 0 : if (!isNull) {
934 0 : if (!JS_GetPropertyById(cx, *object, atomsCache->errorMessage_id, temp.ptr())) {
935 0 : return false;
936 : }
937 : }
938 0 : if (!isNull && !temp->isUndefined()) {
939 0 : mErrorMessage.Construct();
940 0 : if (!ConvertJSValueToString(cx, temp.ref(), eNull, eNull, (mErrorMessage.Value()))) {
941 0 : return false;
942 : }
943 0 : mIsAnyMemberPresent = true;
944 : }
945 :
946 0 : if (!isNull) {
947 0 : if (!JS_GetPropertyById(cx, *object, atomsCache->keyHandle_id, temp.ptr())) {
948 0 : return false;
949 : }
950 : }
951 0 : if (!isNull && !temp->isUndefined()) {
952 0 : mKeyHandle.Construct();
953 0 : if (!ConvertJSValueToString(cx, temp.ref(), eStringify, eStringify, (mKeyHandle.Value()))) {
954 0 : return false;
955 : }
956 0 : mIsAnyMemberPresent = true;
957 : }
958 :
959 0 : if (!isNull) {
960 0 : if (!JS_GetPropertyById(cx, *object, atomsCache->signatureData_id, temp.ptr())) {
961 0 : return false;
962 : }
963 : }
964 0 : if (!isNull && !temp->isUndefined()) {
965 0 : mSignatureData.Construct();
966 0 : if (!ConvertJSValueToString(cx, temp.ref(), eStringify, eStringify, (mSignatureData.Value()))) {
967 0 : return false;
968 : }
969 0 : mIsAnyMemberPresent = true;
970 : }
971 0 : return true;
972 : }
973 :
974 : bool
975 0 : SignResponse::Init(const nsAString& aJSON)
976 : {
977 0 : AutoJSAPI jsapi;
978 0 : JSObject* cleanGlobal = SimpleGlobalObject::Create(SimpleGlobalObject::GlobalType::BindingDetail);
979 0 : if (!cleanGlobal) {
980 0 : return false;
981 : }
982 0 : if (!jsapi.Init(cleanGlobal)) {
983 0 : return false;
984 : }
985 0 : JSContext* cx = jsapi.cx();
986 0 : JS::Rooted<JS::Value> json(cx);
987 0 : bool ok = ParseJSON(cx, aJSON, &json);
988 0 : NS_ENSURE_TRUE(ok, false);
989 0 : return Init(cx, json);
990 : }
991 :
992 : bool
993 0 : SignResponse::ToObjectInternal(JSContext* cx, JS::MutableHandle<JS::Value> rval) const
994 : {
995 0 : SignResponseAtoms* atomsCache = GetAtomCache<SignResponseAtoms>(cx);
996 0 : if (!*reinterpret_cast<jsid**>(atomsCache) && !InitIds(cx, atomsCache)) {
997 0 : return false;
998 : }
999 :
1000 0 : JS::Rooted<JSObject*> obj(cx, JS_NewPlainObject(cx));
1001 0 : if (!obj) {
1002 0 : return false;
1003 : }
1004 0 : rval.set(JS::ObjectValue(*obj));
1005 :
1006 0 : if (mClientData.WasPassed()) {
1007 : do {
1008 : // block for our 'break' successCode and scope for 'temp' and 'currentValue'
1009 0 : JS::Rooted<JS::Value> temp(cx);
1010 0 : nsString const & currentValue = mClientData.InternalValue();
1011 0 : if (!xpc::NonVoidStringToJsval(cx, currentValue, &temp)) {
1012 0 : return false;
1013 : }
1014 0 : if (!JS_DefinePropertyById(cx, obj, atomsCache->clientData_id, temp, JSPROP_ENUMERATE)) {
1015 0 : return false;
1016 : }
1017 0 : break;
1018 : } while(0);
1019 : }
1020 :
1021 0 : if (mErrorCode.WasPassed()) {
1022 : do {
1023 : // block for our 'break' successCode and scope for 'temp' and 'currentValue'
1024 0 : JS::Rooted<JS::Value> temp(cx);
1025 0 : Nullable<uint16_t> const & currentValue = mErrorCode.InternalValue();
1026 0 : if (currentValue.IsNull()) {
1027 0 : temp.setNull();
1028 0 : if (!JS_DefinePropertyById(cx, obj, atomsCache->errorCode_id, temp, JSPROP_ENUMERATE)) {
1029 0 : return false;
1030 : }
1031 0 : break;
1032 : }
1033 0 : temp.setInt32(int32_t(currentValue.Value()));
1034 0 : if (!JS_DefinePropertyById(cx, obj, atomsCache->errorCode_id, temp, JSPROP_ENUMERATE)) {
1035 0 : return false;
1036 : }
1037 0 : break;
1038 : } while(0);
1039 : }
1040 :
1041 0 : if (mErrorMessage.WasPassed()) {
1042 : do {
1043 : // block for our 'break' successCode and scope for 'temp' and 'currentValue'
1044 0 : JS::Rooted<JS::Value> temp(cx);
1045 0 : nsString const & currentValue = mErrorMessage.InternalValue();
1046 0 : if (!xpc::StringToJsval(cx, currentValue, &temp)) {
1047 0 : return false;
1048 : }
1049 0 : if (!JS_DefinePropertyById(cx, obj, atomsCache->errorMessage_id, temp, JSPROP_ENUMERATE)) {
1050 0 : return false;
1051 : }
1052 0 : break;
1053 : } while(0);
1054 : }
1055 :
1056 0 : if (mKeyHandle.WasPassed()) {
1057 : do {
1058 : // block for our 'break' successCode and scope for 'temp' and 'currentValue'
1059 0 : JS::Rooted<JS::Value> temp(cx);
1060 0 : nsString const & currentValue = mKeyHandle.InternalValue();
1061 0 : if (!xpc::NonVoidStringToJsval(cx, currentValue, &temp)) {
1062 0 : return false;
1063 : }
1064 0 : if (!JS_DefinePropertyById(cx, obj, atomsCache->keyHandle_id, temp, JSPROP_ENUMERATE)) {
1065 0 : return false;
1066 : }
1067 0 : break;
1068 : } while(0);
1069 : }
1070 :
1071 0 : if (mSignatureData.WasPassed()) {
1072 : do {
1073 : // block for our 'break' successCode and scope for 'temp' and 'currentValue'
1074 0 : JS::Rooted<JS::Value> temp(cx);
1075 0 : nsString const & currentValue = mSignatureData.InternalValue();
1076 0 : if (!xpc::NonVoidStringToJsval(cx, currentValue, &temp)) {
1077 0 : return false;
1078 : }
1079 0 : if (!JS_DefinePropertyById(cx, obj, atomsCache->signatureData_id, temp, JSPROP_ENUMERATE)) {
1080 0 : return false;
1081 : }
1082 0 : break;
1083 : } while(0);
1084 : }
1085 :
1086 0 : return true;
1087 : }
1088 :
1089 : bool
1090 0 : SignResponse::ToJSON(nsAString& aJSON) const
1091 : {
1092 0 : AutoJSAPI jsapi;
1093 0 : jsapi.Init();
1094 0 : JSContext *cx = jsapi.cx();
1095 : // It's safe to use UnprivilegedJunkScopeOrWorkerGlobal here
1096 : // because we'll only be creating objects, in ways that have no
1097 : // side-effects, followed by a call to JS::ToJSONMaybeSafely,
1098 : // which likewise guarantees no side-effects for the sorts of
1099 : // things we will pass it.
1100 0 : JSAutoCompartment ac(cx, binding_detail::UnprivilegedJunkScopeOrWorkerGlobal());
1101 0 : JS::Rooted<JS::Value> val(cx);
1102 0 : if (!ToObjectInternal(cx, &val)) {
1103 0 : return false;
1104 : }
1105 0 : JS::Rooted<JSObject*> obj(cx, &val.toObject());
1106 0 : return StringifyToJSON(cx, obj, aJSON);
1107 : }
1108 :
1109 : void
1110 0 : SignResponse::TraceDictionary(JSTracer* trc)
1111 : {
1112 0 : }
1113 :
1114 : SignResponse&
1115 0 : SignResponse::operator=(const SignResponse& aOther)
1116 : {
1117 0 : mClientData.Reset();
1118 0 : if (aOther.mClientData.WasPassed()) {
1119 0 : mClientData.Construct(aOther.mClientData.Value());
1120 : }
1121 0 : mErrorCode.Reset();
1122 0 : if (aOther.mErrorCode.WasPassed()) {
1123 0 : mErrorCode.Construct(aOther.mErrorCode.Value());
1124 : }
1125 0 : mErrorMessage.Reset();
1126 0 : if (aOther.mErrorMessage.WasPassed()) {
1127 0 : mErrorMessage.Construct(aOther.mErrorMessage.Value());
1128 : }
1129 0 : mKeyHandle.Reset();
1130 0 : if (aOther.mKeyHandle.WasPassed()) {
1131 0 : mKeyHandle.Construct(aOther.mKeyHandle.Value());
1132 : }
1133 0 : mSignatureData.Reset();
1134 0 : if (aOther.mSignatureData.WasPassed()) {
1135 0 : mSignatureData.Construct(aOther.mSignatureData.Value());
1136 : }
1137 0 : return *this;
1138 : }
1139 :
1140 : namespace binding_detail {
1141 : } // namespace binding_detail
1142 :
1143 :
1144 :
1145 0 : U2FClientData::U2FClientData()
1146 : {
1147 : // Safe to pass a null context if we pass a null value
1148 0 : Init(nullptr, JS::NullHandleValue);
1149 0 : }
1150 :
1151 :
1152 :
1153 : bool
1154 0 : U2FClientData::InitIds(JSContext* cx, U2FClientDataAtoms* atomsCache)
1155 : {
1156 0 : MOZ_ASSERT(!*reinterpret_cast<jsid**>(atomsCache));
1157 :
1158 : // Initialize these in reverse order so that any failure leaves the first one
1159 : // uninitialized.
1160 0 : if (!atomsCache->typ_id.init(cx, "typ") ||
1161 0 : !atomsCache->origin_id.init(cx, "origin") ||
1162 0 : !atomsCache->challenge_id.init(cx, "challenge")) {
1163 0 : return false;
1164 : }
1165 0 : return true;
1166 : }
1167 :
1168 : bool
1169 0 : U2FClientData::Init(JSContext* cx, JS::Handle<JS::Value> val, const char* sourceDescription, bool passedToJSImpl)
1170 : {
1171 : // Passing a null JSContext is OK only if we're initing from null,
1172 : // Since in that case we will not have to do any property gets
1173 : // Also evaluate isNullOrUndefined in order to avoid false-positive
1174 : // checkers by static analysis tools
1175 0 : MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined());
1176 0 : U2FClientDataAtoms* atomsCache = nullptr;
1177 0 : if (cx) {
1178 0 : atomsCache = GetAtomCache<U2FClientDataAtoms>(cx);
1179 0 : if (!*reinterpret_cast<jsid**>(atomsCache) && !InitIds(cx, atomsCache)) {
1180 0 : return false;
1181 : }
1182 : }
1183 :
1184 0 : if (!IsConvertibleToDictionary(val)) {
1185 0 : return ThrowErrorMessage(cx, MSG_NOT_DICTIONARY, sourceDescription);
1186 : }
1187 :
1188 0 : bool isNull = val.isNullOrUndefined();
1189 : // We only need these if !isNull, in which case we have |cx|.
1190 0 : Maybe<JS::Rooted<JSObject *> > object;
1191 0 : Maybe<JS::Rooted<JS::Value> > temp;
1192 0 : if (!isNull) {
1193 0 : MOZ_ASSERT(cx);
1194 0 : object.emplace(cx, &val.toObject());
1195 0 : temp.emplace(cx);
1196 : }
1197 0 : if (!isNull) {
1198 0 : if (!JS_GetPropertyById(cx, *object, atomsCache->challenge_id, temp.ptr())) {
1199 0 : return false;
1200 : }
1201 : }
1202 0 : if (!isNull && !temp->isUndefined()) {
1203 0 : mChallenge.Construct();
1204 0 : if (!ConvertJSValueToString(cx, temp.ref(), eStringify, eStringify, (mChallenge.Value()))) {
1205 0 : return false;
1206 : }
1207 0 : mIsAnyMemberPresent = true;
1208 : }
1209 :
1210 0 : if (!isNull) {
1211 0 : if (!JS_GetPropertyById(cx, *object, atomsCache->origin_id, temp.ptr())) {
1212 0 : return false;
1213 : }
1214 : }
1215 0 : if (!isNull && !temp->isUndefined()) {
1216 0 : mOrigin.Construct();
1217 0 : if (!ConvertJSValueToString(cx, temp.ref(), eStringify, eStringify, (mOrigin.Value()))) {
1218 0 : return false;
1219 : }
1220 0 : mIsAnyMemberPresent = true;
1221 : }
1222 :
1223 0 : if (!isNull) {
1224 0 : if (!JS_GetPropertyById(cx, *object, atomsCache->typ_id, temp.ptr())) {
1225 0 : return false;
1226 : }
1227 : }
1228 0 : if (!isNull && !temp->isUndefined()) {
1229 0 : mTyp.Construct();
1230 0 : if (!ConvertJSValueToString(cx, temp.ref(), eStringify, eStringify, (mTyp.Value()))) {
1231 0 : return false;
1232 : }
1233 0 : mIsAnyMemberPresent = true;
1234 : }
1235 0 : return true;
1236 : }
1237 :
1238 : bool
1239 0 : U2FClientData::Init(const nsAString& aJSON)
1240 : {
1241 0 : AutoJSAPI jsapi;
1242 0 : JSObject* cleanGlobal = SimpleGlobalObject::Create(SimpleGlobalObject::GlobalType::BindingDetail);
1243 0 : if (!cleanGlobal) {
1244 0 : return false;
1245 : }
1246 0 : if (!jsapi.Init(cleanGlobal)) {
1247 0 : return false;
1248 : }
1249 0 : JSContext* cx = jsapi.cx();
1250 0 : JS::Rooted<JS::Value> json(cx);
1251 0 : bool ok = ParseJSON(cx, aJSON, &json);
1252 0 : NS_ENSURE_TRUE(ok, false);
1253 0 : return Init(cx, json);
1254 : }
1255 :
1256 : bool
1257 0 : U2FClientData::ToObjectInternal(JSContext* cx, JS::MutableHandle<JS::Value> rval) const
1258 : {
1259 0 : U2FClientDataAtoms* atomsCache = GetAtomCache<U2FClientDataAtoms>(cx);
1260 0 : if (!*reinterpret_cast<jsid**>(atomsCache) && !InitIds(cx, atomsCache)) {
1261 0 : return false;
1262 : }
1263 :
1264 0 : JS::Rooted<JSObject*> obj(cx, JS_NewPlainObject(cx));
1265 0 : if (!obj) {
1266 0 : return false;
1267 : }
1268 0 : rval.set(JS::ObjectValue(*obj));
1269 :
1270 0 : if (mChallenge.WasPassed()) {
1271 : do {
1272 : // block for our 'break' successCode and scope for 'temp' and 'currentValue'
1273 0 : JS::Rooted<JS::Value> temp(cx);
1274 0 : nsString const & currentValue = mChallenge.InternalValue();
1275 0 : if (!xpc::NonVoidStringToJsval(cx, currentValue, &temp)) {
1276 0 : return false;
1277 : }
1278 0 : if (!JS_DefinePropertyById(cx, obj, atomsCache->challenge_id, temp, JSPROP_ENUMERATE)) {
1279 0 : return false;
1280 : }
1281 0 : break;
1282 : } while(0);
1283 : }
1284 :
1285 0 : if (mOrigin.WasPassed()) {
1286 : do {
1287 : // block for our 'break' successCode and scope for 'temp' and 'currentValue'
1288 0 : JS::Rooted<JS::Value> temp(cx);
1289 0 : nsString const & currentValue = mOrigin.InternalValue();
1290 0 : if (!xpc::NonVoidStringToJsval(cx, currentValue, &temp)) {
1291 0 : return false;
1292 : }
1293 0 : if (!JS_DefinePropertyById(cx, obj, atomsCache->origin_id, temp, JSPROP_ENUMERATE)) {
1294 0 : return false;
1295 : }
1296 0 : break;
1297 : } while(0);
1298 : }
1299 :
1300 0 : if (mTyp.WasPassed()) {
1301 : do {
1302 : // block for our 'break' successCode and scope for 'temp' and 'currentValue'
1303 0 : JS::Rooted<JS::Value> temp(cx);
1304 0 : nsString const & currentValue = mTyp.InternalValue();
1305 0 : if (!xpc::NonVoidStringToJsval(cx, currentValue, &temp)) {
1306 0 : return false;
1307 : }
1308 0 : if (!JS_DefinePropertyById(cx, obj, atomsCache->typ_id, temp, JSPROP_ENUMERATE)) {
1309 0 : return false;
1310 : }
1311 0 : break;
1312 : } while(0);
1313 : }
1314 :
1315 0 : return true;
1316 : }
1317 :
1318 : bool
1319 0 : U2FClientData::ToJSON(nsAString& aJSON) const
1320 : {
1321 0 : AutoJSAPI jsapi;
1322 0 : jsapi.Init();
1323 0 : JSContext *cx = jsapi.cx();
1324 : // It's safe to use UnprivilegedJunkScopeOrWorkerGlobal here
1325 : // because we'll only be creating objects, in ways that have no
1326 : // side-effects, followed by a call to JS::ToJSONMaybeSafely,
1327 : // which likewise guarantees no side-effects for the sorts of
1328 : // things we will pass it.
1329 0 : JSAutoCompartment ac(cx, binding_detail::UnprivilegedJunkScopeOrWorkerGlobal());
1330 0 : JS::Rooted<JS::Value> val(cx);
1331 0 : if (!ToObjectInternal(cx, &val)) {
1332 0 : return false;
1333 : }
1334 0 : JS::Rooted<JSObject*> obj(cx, &val.toObject());
1335 0 : return StringifyToJSON(cx, obj, aJSON);
1336 : }
1337 :
1338 : void
1339 0 : U2FClientData::TraceDictionary(JSTracer* trc)
1340 : {
1341 0 : }
1342 :
1343 : U2FClientData&
1344 0 : U2FClientData::operator=(const U2FClientData& aOther)
1345 : {
1346 0 : mChallenge.Reset();
1347 0 : if (aOther.mChallenge.WasPassed()) {
1348 0 : mChallenge.Construct(aOther.mChallenge.Value());
1349 : }
1350 0 : mOrigin.Reset();
1351 0 : if (aOther.mOrigin.WasPassed()) {
1352 0 : mOrigin.Construct(aOther.mOrigin.Value());
1353 : }
1354 0 : mTyp.Reset();
1355 0 : if (aOther.mTyp.WasPassed()) {
1356 0 : mTyp.Construct(aOther.mTyp.Value());
1357 : }
1358 0 : return *this;
1359 : }
1360 :
1361 : namespace binding_detail {
1362 : } // namespace binding_detail
1363 :
1364 :
1365 : void
1366 0 : U2FRegisterCallback::Call(JSContext* cx, JS::Handle<JS::Value> aThisVal, const RegisterResponse& response, ErrorResult& aRv)
1367 : {
1368 0 : JS::Rooted<JS::Value> rval(cx, JS::UndefinedValue());
1369 0 : JS::AutoValueVector argv(cx);
1370 0 : if (!argv.resize(1)) {
1371 0 : aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
1372 0 : return;
1373 : }
1374 0 : unsigned argc = 1;
1375 :
1376 : do {
1377 0 : if (!response.ToObjectInternal(cx, argv[0])) {
1378 0 : aRv.Throw(NS_ERROR_UNEXPECTED);
1379 0 : return;
1380 : }
1381 0 : break;
1382 : } while (0);
1383 :
1384 0 : JS::Rooted<JS::Value> callable(cx, JS::ObjectValue(*mCallback));
1385 0 : if (!JS::Call(cx, aThisVal, callable,
1386 0 : JS::HandleValueArray::subarray(argv, 0, argc), &rval)) {
1387 0 : aRv.NoteJSContextException(cx);
1388 0 : return;
1389 : }
1390 : }
1391 :
1392 :
1393 :
1394 : void
1395 0 : U2FSignCallback::Call(JSContext* cx, JS::Handle<JS::Value> aThisVal, const SignResponse& response, ErrorResult& aRv)
1396 : {
1397 0 : JS::Rooted<JS::Value> rval(cx, JS::UndefinedValue());
1398 0 : JS::AutoValueVector argv(cx);
1399 0 : if (!argv.resize(1)) {
1400 0 : aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
1401 0 : return;
1402 : }
1403 0 : unsigned argc = 1;
1404 :
1405 : do {
1406 0 : if (!response.ToObjectInternal(cx, argv[0])) {
1407 0 : aRv.Throw(NS_ERROR_UNEXPECTED);
1408 0 : return;
1409 : }
1410 0 : break;
1411 : } while (0);
1412 :
1413 0 : JS::Rooted<JS::Value> callable(cx, JS::ObjectValue(*mCallback));
1414 0 : if (!JS::Call(cx, aThisVal, callable,
1415 0 : JS::HandleValueArray::subarray(argv, 0, argc), &rval)) {
1416 0 : aRv.NoteJSContextException(cx);
1417 0 : return;
1418 : }
1419 : }
1420 :
1421 :
1422 :
1423 : namespace binding_detail {
1424 : } // namespace binding_detail
1425 :
1426 :
1427 : namespace binding_detail {
1428 : } // namespace binding_detail
1429 :
1430 :
1431 : namespace U2FBinding {
1432 :
1433 : static bool
1434 0 : _register_(JSContext* cx, JS::Handle<JSObject*> obj, mozilla::dom::U2F* self, const JSJitMethodCallArgs& args)
1435 : {
1436 0 : if (MOZ_UNLIKELY(args.length() < 4)) {
1437 0 : return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, "U2F.register");
1438 : }
1439 0 : binding_detail::FakeString arg0;
1440 0 : if (!ConvertJSValueToString(cx, args[0], eStringify, eStringify, arg0)) {
1441 0 : return false;
1442 : }
1443 0 : binding_detail::AutoSequence<RegisterRequest> arg1;
1444 0 : if (args[1].isObject()) {
1445 0 : JS::ForOfIterator iter(cx);
1446 0 : if (!iter.init(args[1], JS::ForOfIterator::AllowNonIterable)) {
1447 0 : return false;
1448 : }
1449 0 : if (!iter.valueIsIterable()) {
1450 0 : ThrowErrorMessage(cx, MSG_NOT_SEQUENCE, "Argument 2 of U2F.register");
1451 0 : return false;
1452 : }
1453 0 : binding_detail::AutoSequence<RegisterRequest> &arr = arg1;
1454 0 : JS::Rooted<JS::Value> temp(cx);
1455 : while (true) {
1456 : bool done;
1457 0 : if (!iter.next(&temp, &done)) {
1458 0 : return false;
1459 : }
1460 0 : if (done) {
1461 0 : break;
1462 : }
1463 0 : RegisterRequest* slotPtr = arr.AppendElement(mozilla::fallible);
1464 0 : if (!slotPtr) {
1465 0 : JS_ReportOutOfMemory(cx);
1466 0 : return false;
1467 : }
1468 0 : RegisterRequest& slot = *slotPtr;
1469 0 : if (!slot.Init(cx, temp, "Element of argument 2 of U2F.register", false)) {
1470 0 : return false;
1471 : }
1472 0 : }
1473 : } else {
1474 0 : ThrowErrorMessage(cx, MSG_NOT_SEQUENCE, "Argument 2 of U2F.register");
1475 0 : return false;
1476 : }
1477 0 : binding_detail::AutoSequence<RegisteredKey> arg2;
1478 0 : if (args[2].isObject()) {
1479 0 : JS::ForOfIterator iter(cx);
1480 0 : if (!iter.init(args[2], JS::ForOfIterator::AllowNonIterable)) {
1481 0 : return false;
1482 : }
1483 0 : if (!iter.valueIsIterable()) {
1484 0 : ThrowErrorMessage(cx, MSG_NOT_SEQUENCE, "Argument 3 of U2F.register");
1485 0 : return false;
1486 : }
1487 0 : binding_detail::AutoSequence<RegisteredKey> &arr = arg2;
1488 0 : JS::Rooted<JS::Value> temp(cx);
1489 : while (true) {
1490 : bool done;
1491 0 : if (!iter.next(&temp, &done)) {
1492 0 : return false;
1493 : }
1494 0 : if (done) {
1495 0 : break;
1496 : }
1497 0 : RegisteredKey* slotPtr = arr.AppendElement(mozilla::fallible);
1498 0 : if (!slotPtr) {
1499 0 : JS_ReportOutOfMemory(cx);
1500 0 : return false;
1501 : }
1502 0 : RegisteredKey& slot = *slotPtr;
1503 0 : if (!slot.Init(cx, temp, "Element of argument 3 of U2F.register", false)) {
1504 0 : return false;
1505 : }
1506 0 : }
1507 : } else {
1508 0 : ThrowErrorMessage(cx, MSG_NOT_SEQUENCE, "Argument 3 of U2F.register");
1509 0 : return false;
1510 : }
1511 0 : RootedCallback<OwningNonNull<binding_detail::FastU2FRegisterCallback>> arg3(cx);
1512 0 : if (args[3].isObject()) {
1513 0 : if (JS::IsCallable(&args[3].toObject())) {
1514 : { // scope for tempRoot
1515 0 : JS::Rooted<JSObject*> tempRoot(cx, &args[3].toObject());
1516 0 : arg3 = new binding_detail::FastU2FRegisterCallback(tempRoot);
1517 : }
1518 : } else {
1519 0 : ThrowErrorMessage(cx, MSG_NOT_CALLABLE, "Argument 4 of U2F.register");
1520 0 : return false;
1521 : }
1522 : } else {
1523 0 : ThrowErrorMessage(cx, MSG_NOT_OBJECT, "Argument 4 of U2F.register");
1524 0 : return false;
1525 : }
1526 0 : Optional<Nullable<int32_t>> arg4;
1527 0 : if (args.hasDefined(4)) {
1528 0 : arg4.Construct();
1529 0 : if (args[4].isNullOrUndefined()) {
1530 0 : arg4.Value().SetNull();
1531 0 : } else if (!ValueToPrimitive<int32_t, eDefault>(cx, args[4], &arg4.Value().SetValue())) {
1532 0 : return false;
1533 : }
1534 : }
1535 0 : binding_detail::FastErrorResult rv;
1536 0 : self->Register(NonNullHelper(Constify(arg0)), Constify(arg1), Constify(arg2), NonNullHelper(arg3), Constify(arg4), rv);
1537 0 : if (MOZ_UNLIKELY(rv.MaybeSetPendingException(cx))) {
1538 0 : return false;
1539 : }
1540 0 : MOZ_ASSERT(!JS_IsExceptionPending(cx));
1541 0 : args.rval().setUndefined();
1542 0 : return true;
1543 : }
1544 :
1545 : static const JSJitInfo register_methodinfo = {
1546 : { (JSJitGetterOp)_register_ },
1547 : { prototypes::id::U2F },
1548 : { PrototypeTraits<prototypes::id::U2F>::Depth },
1549 : JSJitInfo::Method,
1550 : JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */
1551 : JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */
1552 : false, /* isInfallible. False in setters. */
1553 : false, /* isMovable. Not relevant for setters. */
1554 : false, /* isEliminatable. Not relevant for setters. */
1555 : false, /* isAlwaysInSlot. Only relevant for getters. */
1556 : false, /* isLazilyCachedInSlot. Only relevant for getters. */
1557 : false, /* isTypedMethod. Only relevant for methods. */
1558 : 0 /* Reserved slot index, if we're stored in a slot, else 0. */
1559 : };
1560 : static_assert(0 <= JSJitInfo::maxSlotIndex, "We won't fit");
1561 : static_assert(0 < 1, "There is no slot for us");
1562 :
1563 : static bool
1564 0 : sign(JSContext* cx, JS::Handle<JSObject*> obj, mozilla::dom::U2F* self, const JSJitMethodCallArgs& args)
1565 : {
1566 0 : if (MOZ_UNLIKELY(args.length() < 4)) {
1567 0 : return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, "U2F.sign");
1568 : }
1569 0 : binding_detail::FakeString arg0;
1570 0 : if (!ConvertJSValueToString(cx, args[0], eStringify, eStringify, arg0)) {
1571 0 : return false;
1572 : }
1573 0 : binding_detail::FakeString arg1;
1574 0 : if (!ConvertJSValueToString(cx, args[1], eStringify, eStringify, arg1)) {
1575 0 : return false;
1576 : }
1577 0 : binding_detail::AutoSequence<RegisteredKey> arg2;
1578 0 : if (args[2].isObject()) {
1579 0 : JS::ForOfIterator iter(cx);
1580 0 : if (!iter.init(args[2], JS::ForOfIterator::AllowNonIterable)) {
1581 0 : return false;
1582 : }
1583 0 : if (!iter.valueIsIterable()) {
1584 0 : ThrowErrorMessage(cx, MSG_NOT_SEQUENCE, "Argument 3 of U2F.sign");
1585 0 : return false;
1586 : }
1587 0 : binding_detail::AutoSequence<RegisteredKey> &arr = arg2;
1588 0 : JS::Rooted<JS::Value> temp(cx);
1589 : while (true) {
1590 : bool done;
1591 0 : if (!iter.next(&temp, &done)) {
1592 0 : return false;
1593 : }
1594 0 : if (done) {
1595 0 : break;
1596 : }
1597 0 : RegisteredKey* slotPtr = arr.AppendElement(mozilla::fallible);
1598 0 : if (!slotPtr) {
1599 0 : JS_ReportOutOfMemory(cx);
1600 0 : return false;
1601 : }
1602 0 : RegisteredKey& slot = *slotPtr;
1603 0 : if (!slot.Init(cx, temp, "Element of argument 3 of U2F.sign", false)) {
1604 0 : return false;
1605 : }
1606 0 : }
1607 : } else {
1608 0 : ThrowErrorMessage(cx, MSG_NOT_SEQUENCE, "Argument 3 of U2F.sign");
1609 0 : return false;
1610 : }
1611 0 : RootedCallback<OwningNonNull<binding_detail::FastU2FSignCallback>> arg3(cx);
1612 0 : if (args[3].isObject()) {
1613 0 : if (JS::IsCallable(&args[3].toObject())) {
1614 : { // scope for tempRoot
1615 0 : JS::Rooted<JSObject*> tempRoot(cx, &args[3].toObject());
1616 0 : arg3 = new binding_detail::FastU2FSignCallback(tempRoot);
1617 : }
1618 : } else {
1619 0 : ThrowErrorMessage(cx, MSG_NOT_CALLABLE, "Argument 4 of U2F.sign");
1620 0 : return false;
1621 : }
1622 : } else {
1623 0 : ThrowErrorMessage(cx, MSG_NOT_OBJECT, "Argument 4 of U2F.sign");
1624 0 : return false;
1625 : }
1626 0 : Optional<Nullable<int32_t>> arg4;
1627 0 : if (args.hasDefined(4)) {
1628 0 : arg4.Construct();
1629 0 : if (args[4].isNullOrUndefined()) {
1630 0 : arg4.Value().SetNull();
1631 0 : } else if (!ValueToPrimitive<int32_t, eDefault>(cx, args[4], &arg4.Value().SetValue())) {
1632 0 : return false;
1633 : }
1634 : }
1635 0 : binding_detail::FastErrorResult rv;
1636 0 : self->Sign(NonNullHelper(Constify(arg0)), NonNullHelper(Constify(arg1)), Constify(arg2), NonNullHelper(arg3), Constify(arg4), rv);
1637 0 : if (MOZ_UNLIKELY(rv.MaybeSetPendingException(cx))) {
1638 0 : return false;
1639 : }
1640 0 : MOZ_ASSERT(!JS_IsExceptionPending(cx));
1641 0 : args.rval().setUndefined();
1642 0 : return true;
1643 : }
1644 :
1645 : static const JSJitInfo sign_methodinfo = {
1646 : { (JSJitGetterOp)sign },
1647 : { prototypes::id::U2F },
1648 : { PrototypeTraits<prototypes::id::U2F>::Depth },
1649 : JSJitInfo::Method,
1650 : JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */
1651 : JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */
1652 : false, /* isInfallible. False in setters. */
1653 : false, /* isMovable. Not relevant for setters. */
1654 : false, /* isEliminatable. Not relevant for setters. */
1655 : false, /* isAlwaysInSlot. Only relevant for getters. */
1656 : false, /* isLazilyCachedInSlot. Only relevant for getters. */
1657 : false, /* isTypedMethod. Only relevant for methods. */
1658 : 0 /* Reserved slot index, if we're stored in a slot, else 0. */
1659 : };
1660 : static_assert(0 <= JSJitInfo::maxSlotIndex, "We won't fit");
1661 : static_assert(0 < 1, "There is no slot for us");
1662 :
1663 : static bool
1664 0 : _addProperty(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, JS::Handle<JS::Value> val)
1665 : {
1666 0 : mozilla::dom::U2F* self = UnwrapPossiblyNotInitializedDOMObject<mozilla::dom::U2F>(obj);
1667 : // We don't want to preserve if we don't have a wrapper, and we
1668 : // obviously can't preserve if we're not initialized.
1669 0 : if (self && self->GetWrapperPreserveColor()) {
1670 0 : PreserveWrapper(self);
1671 : }
1672 0 : return true;
1673 : }
1674 :
1675 : static void
1676 0 : _finalize(js::FreeOp* fop, JSObject* obj)
1677 : {
1678 0 : mozilla::dom::U2F* self = UnwrapPossiblyNotInitializedDOMObject<mozilla::dom::U2F>(obj);
1679 0 : if (self) {
1680 0 : ClearWrapper(self, self, obj);
1681 0 : AddForDeferredFinalization<mozilla::dom::U2F>(self);
1682 : }
1683 0 : }
1684 :
1685 : static void
1686 0 : _objectMoved(JSObject* obj, const JSObject* old)
1687 : {
1688 0 : mozilla::dom::U2F* self = UnwrapPossiblyNotInitializedDOMObject<mozilla::dom::U2F>(obj);
1689 0 : if (self) {
1690 0 : UpdateWrapper(self, self, obj, old);
1691 : }
1692 0 : }
1693 :
1694 : // We deliberately use brace-elision to make Visual Studio produce better initalization code.
1695 : #if defined(__clang__)
1696 : #pragma clang diagnostic push
1697 : #pragma clang diagnostic ignored "-Wmissing-braces"
1698 : #endif
1699 : static const JSFunctionSpec sMethods_specs[] = {
1700 : JS_FNSPEC("register", GenericBindingMethod, reinterpret_cast<const JSJitInfo*>(®ister_methodinfo), 4, JSPROP_ENUMERATE, nullptr),
1701 : JS_FNSPEC("sign", GenericBindingMethod, reinterpret_cast<const JSJitInfo*>(&sign_methodinfo), 4, JSPROP_ENUMERATE, nullptr),
1702 : JS_FS_END
1703 : };
1704 : #if defined(__clang__)
1705 : #pragma clang diagnostic pop
1706 : #endif
1707 :
1708 :
1709 : // Can't be const because the pref-enabled boolean needs to be writable
1710 : static Prefable<const JSFunctionSpec> sMethods[] = {
1711 : { nullptr, &sMethods_specs[0] },
1712 : { nullptr, nullptr }
1713 : };
1714 :
1715 : static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX,
1716 : "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)");
1717 : static_assert(2 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX,
1718 : "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)");
1719 :
1720 : // We deliberately use brace-elision to make Visual Studio produce better initalization code.
1721 : #if defined(__clang__)
1722 : #pragma clang diagnostic push
1723 : #pragma clang diagnostic ignored "-Wmissing-braces"
1724 : #endif
1725 : static const ConstantSpec sConstants_specs[] = {
1726 : { "OK", JS::Int32Value(0) },
1727 : { "OTHER_ERROR", JS::Int32Value(1) },
1728 : { "BAD_REQUEST", JS::Int32Value(2) },
1729 : { "CONFIGURATION_UNSUPPORTED", JS::Int32Value(3) },
1730 : { "DEVICE_INELIGIBLE", JS::Int32Value(4) },
1731 : { "TIMEOUT", JS::Int32Value(5) },
1732 : { 0, JS::UndefinedValue() }
1733 : };
1734 : #if defined(__clang__)
1735 : #pragma clang diagnostic pop
1736 : #endif
1737 :
1738 :
1739 : // Can't be const because the pref-enabled boolean needs to be writable
1740 : static Prefable<const ConstantSpec> sConstants[] = {
1741 : { nullptr, &sConstants_specs[0] },
1742 : { nullptr, nullptr }
1743 : };
1744 :
1745 : static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX,
1746 : "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)");
1747 : static_assert(6 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX,
1748 : "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)");
1749 :
1750 :
1751 : static uint16_t sNativeProperties_sortedPropertyIndices[8];
1752 : static PropertyInfo sNativeProperties_propertyInfos[8];
1753 :
1754 : static const NativePropertiesN<2> sNativeProperties = {
1755 : false, 0,
1756 : false, 0,
1757 : true, 0 /* sMethods */,
1758 : false, 0,
1759 : false, 0,
1760 : false, 0,
1761 : true, 1 /* sConstants */,
1762 : -1,
1763 : 8,
1764 : sNativeProperties_sortedPropertyIndices,
1765 : {
1766 : { sMethods, &sNativeProperties_propertyInfos[0] },
1767 : { sConstants, &sNativeProperties_propertyInfos[2] }
1768 : }
1769 : };
1770 : static_assert(8 < 1ull << CHAR_BIT * sizeof(sNativeProperties.propertyInfoCount),
1771 : "We have a property info count that is oversized");
1772 :
1773 : static const DOMIfaceAndProtoJSClass sInterfaceObjectClass = {
1774 : {
1775 : "Function",
1776 : JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_SLOTS_BASE),
1777 : &sBoringInterfaceObjectClassClassOps,
1778 : JS_NULL_CLASS_SPEC,
1779 : JS_NULL_CLASS_EXT,
1780 : &sInterfaceObjectClassObjectOps
1781 : },
1782 : eInterface,
1783 : true,
1784 : prototypes::id::U2F,
1785 : PrototypeTraits<prototypes::id::U2F>::Depth,
1786 : sNativePropertyHooks,
1787 : "function U2F() {\n [native code]\n}",
1788 : JS::GetRealmFunctionPrototype
1789 : };
1790 :
1791 : static const DOMIfaceAndProtoJSClass sPrototypeClass = {
1792 : {
1793 : "U2FPrototype",
1794 : JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_PROTO_SLOTS_BASE),
1795 : JS_NULL_CLASS_OPS,
1796 : JS_NULL_CLASS_SPEC,
1797 : JS_NULL_CLASS_EXT,
1798 : JS_NULL_OBJECT_OPS
1799 : },
1800 : eInterfacePrototype,
1801 : false,
1802 : prototypes::id::U2F,
1803 : PrototypeTraits<prototypes::id::U2F>::Depth,
1804 : sNativePropertyHooks,
1805 : "[object U2FPrototype]",
1806 : JS::GetRealmObjectPrototype
1807 : };
1808 :
1809 : bool
1810 0 : ConstructorEnabled(JSContext* aCx, JS::Handle<JSObject*> aObj)
1811 : {
1812 : static bool sPrefValue;
1813 : static bool sPrefCacheSetUp = false;
1814 0 : if (!sPrefCacheSetUp) {
1815 0 : sPrefCacheSetUp = true;
1816 0 : Preferences::AddBoolVarCache(&sPrefValue, "security.webauth.u2f");
1817 : }
1818 :
1819 0 : return sPrefValue;
1820 : }
1821 :
1822 : JSObject*
1823 0 : DefineDOMInterface(JSContext* aCx, JS::Handle<JSObject*> aGlobal, JS::Handle<jsid> id, bool aDefineOnGlobal)
1824 : {
1825 0 : return GetConstructorObjectHandle(aCx, aDefineOnGlobal);
1826 : }
1827 :
1828 : static const js::ClassOps sClassOps = {
1829 : _addProperty, /* addProperty */
1830 : nullptr, /* delProperty */
1831 : nullptr, /* getProperty */
1832 : nullptr, /* setProperty */
1833 : nullptr, /* enumerate */
1834 : nullptr, /* newEnumerate */
1835 : nullptr, /* resolve */
1836 : nullptr, /* mayResolve */
1837 : _finalize, /* finalize */
1838 : nullptr, /* call */
1839 : nullptr, /* hasInstance */
1840 : nullptr, /* construct */
1841 : nullptr, /* trace */
1842 : };
1843 :
1844 : static const js::ClassExtension sClassExtension = {
1845 : nullptr, /* weakmapKeyDelegateOp */
1846 : _objectMoved /* objectMovedOp */
1847 : };
1848 :
1849 : static const DOMJSClass sClass = {
1850 : { "U2F",
1851 : JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | JSCLASS_HAS_RESERVED_SLOTS(1),
1852 : &sClassOps,
1853 : JS_NULL_CLASS_SPEC,
1854 : &sClassExtension,
1855 : JS_NULL_OBJECT_OPS
1856 : },
1857 : { prototypes::id::U2F, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count },
1858 : IsBaseOf<nsISupports, mozilla::dom::U2F >::value,
1859 : sNativePropertyHooks,
1860 : FindAssociatedGlobalForNative<mozilla::dom::U2F>::Get,
1861 : GetProtoObjectHandle,
1862 : GetCCParticipant<mozilla::dom::U2F>::Get()
1863 : };
1864 : static_assert(1 == DOM_INSTANCE_RESERVED_SLOTS,
1865 : "Must have the right minimal number of reserved slots.");
1866 : static_assert(1 >= 1,
1867 : "Must have enough reserved slots.");
1868 :
1869 : const JSClass*
1870 0 : GetJSClass()
1871 : {
1872 0 : return sClass.ToJSClass();
1873 : }
1874 :
1875 : bool
1876 0 : Wrap(JSContext* aCx, mozilla::dom::U2F* aObject, nsWrapperCache* aCache, JS::Handle<JSObject*> aGivenProto, JS::MutableHandle<JSObject*> aReflector)
1877 : {
1878 : MOZ_ASSERT(static_cast<mozilla::dom::U2F*>(aObject) ==
1879 : reinterpret_cast<mozilla::dom::U2F*>(aObject),
1880 : "Multiple inheritance for mozilla::dom::U2F is broken.");
1881 0 : MOZ_ASSERT(ToSupportsIsCorrect(aObject));
1882 0 : MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx));
1883 0 : MOZ_ASSERT(!aCache->GetWrapper(),
1884 : "You should probably not be using Wrap() directly; use "
1885 : "GetOrCreateDOMReflector instead");
1886 :
1887 0 : MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache),
1888 : "nsISupports must be on our primary inheritance chain");
1889 :
1890 0 : JS::Rooted<JSObject*> global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject()));
1891 0 : if (!global) {
1892 0 : return false;
1893 : }
1894 0 : MOZ_ASSERT(JS_IsGlobalObject(global));
1895 0 : MOZ_ASSERT(JS::ObjectIsNotGray(global));
1896 :
1897 : // That might have ended up wrapping us already, due to the wonders
1898 : // of XBL. Check for that, and bail out as needed.
1899 0 : aReflector.set(aCache->GetWrapper());
1900 0 : if (aReflector) {
1901 : #ifdef DEBUG
1902 0 : binding_detail::AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto);
1903 : #endif // DEBUG
1904 0 : return true;
1905 : }
1906 :
1907 0 : JSAutoCompartment ac(aCx, global);
1908 0 : JS::Handle<JSObject*> canonicalProto = GetProtoObjectHandle(aCx);
1909 0 : if (!canonicalProto) {
1910 0 : return false;
1911 : }
1912 0 : JS::Rooted<JSObject*> proto(aCx);
1913 0 : if (aGivenProto) {
1914 0 : proto = aGivenProto;
1915 : // Unfortunately, while aGivenProto was in the compartment of aCx
1916 : // coming in, we changed compartments to that of "parent" so may need
1917 : // to wrap the proto here.
1918 0 : if (js::GetContextCompartment(aCx) != js::GetObjectCompartment(proto)) {
1919 0 : if (!JS_WrapObject(aCx, &proto)) {
1920 0 : return false;
1921 : }
1922 : }
1923 : } else {
1924 0 : proto = canonicalProto;
1925 : }
1926 :
1927 0 : BindingJSObjectCreator<mozilla::dom::U2F> creator(aCx);
1928 0 : creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector);
1929 0 : if (!aReflector) {
1930 0 : return false;
1931 : }
1932 :
1933 0 : aCache->SetWrapper(aReflector);
1934 0 : creator.InitializationSucceeded();
1935 :
1936 0 : MOZ_ASSERT(aCache->GetWrapperPreserveColor() &&
1937 : aCache->GetWrapperPreserveColor() == aReflector);
1938 : // If proto != canonicalProto, we have to preserve our wrapper;
1939 : // otherwise we won't be able to properly recreate it later, since
1940 : // we won't know what proto to use. Note that we don't check
1941 : // aGivenProto here, since it's entirely possible (and even
1942 : // somewhat common) to have a non-null aGivenProto which is the
1943 : // same as canonicalProto.
1944 0 : if (proto != canonicalProto) {
1945 0 : PreserveWrapper(aObject);
1946 : }
1947 :
1948 0 : return true;
1949 : }
1950 :
1951 : const NativePropertyHooks sNativePropertyHooks[] = { {
1952 : nullptr,
1953 : nullptr,
1954 : nullptr,
1955 : { sNativeProperties.Upcast(), nullptr },
1956 : prototypes::id::U2F,
1957 : constructors::id::U2F,
1958 : nullptr,
1959 : &DefaultXrayExpandoObjectClass
1960 : } };
1961 :
1962 : void
1963 0 : CreateInterfaceObjects(JSContext* aCx, JS::Handle<JSObject*> aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, bool aDefineOnGlobal)
1964 : {
1965 0 : JS::Rooted<JSObject*> parentProto(aCx, JS::GetRealmObjectPrototype(aCx));
1966 0 : if (!parentProto) {
1967 0 : return;
1968 : }
1969 :
1970 0 : JS::Rooted<JSObject*> constructorProto(aCx, JS::GetRealmFunctionPrototype(aCx));
1971 0 : if (!constructorProto) {
1972 0 : return;
1973 : }
1974 :
1975 : static bool sIdsInited = false;
1976 0 : if (!sIdsInited && NS_IsMainThread()) {
1977 0 : if (!InitIds(aCx, sNativeProperties.Upcast())) {
1978 0 : return;
1979 : }
1980 0 : sIdsInited = true;
1981 : }
1982 :
1983 0 : JS::Heap<JSObject*>* protoCache = &aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::U2F);
1984 0 : JS::Heap<JSObject*>* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::U2F);
1985 0 : dom::CreateInterfaceObjects(aCx, aGlobal, parentProto,
1986 : &sPrototypeClass.mBase, protoCache,
1987 : constructorProto, &sInterfaceObjectClass.mBase, 0, nullptr,
1988 : interfaceCache,
1989 : sNativeProperties.Upcast(),
1990 : nullptr,
1991 : "U2F", aDefineOnGlobal,
1992 : nullptr,
1993 0 : false);
1994 : }
1995 :
1996 : JS::Handle<JSObject*>
1997 0 : GetProtoObjectHandle(JSContext* aCx)
1998 : {
1999 : /* Get the interface prototype object for this class. This will create the
2000 : object as needed. */
2001 0 : bool aDefineOnGlobal = true;
2002 :
2003 : /* Make sure our global is sane. Hopefully we can remove this sometime */
2004 0 : JSObject* global = JS::CurrentGlobalOrNull(aCx);
2005 0 : if (!(js::GetObjectClass(global)->flags & JSCLASS_DOM_GLOBAL)) {
2006 0 : return nullptr;
2007 : }
2008 :
2009 : /* Check to see whether the interface objects are already installed */
2010 0 : ProtoAndIfaceCache& protoAndIfaceCache = *GetProtoAndIfaceCache(global);
2011 0 : if (!protoAndIfaceCache.HasEntryInSlot(prototypes::id::U2F)) {
2012 0 : JS::Rooted<JSObject*> rootedGlobal(aCx, global);
2013 0 : CreateInterfaceObjects(aCx, rootedGlobal, protoAndIfaceCache, aDefineOnGlobal);
2014 : }
2015 :
2016 : /*
2017 : * The object might _still_ be null, but that's OK.
2018 : *
2019 : * Calling fromMarkedLocation() is safe because protoAndIfaceCache is
2020 : * traced by TraceProtoAndIfaceCache() and its contents are never
2021 : * changed after they have been set.
2022 : *
2023 : * Calling address() avoids the read read barrier that does gray
2024 : * unmarking, but it's not possible for the object to be gray here.
2025 : */
2026 :
2027 0 : const JS::Heap<JSObject*>& entrySlot = protoAndIfaceCache.EntrySlotMustExist(prototypes::id::U2F);
2028 0 : MOZ_ASSERT(JS::ObjectIsNotGray(entrySlot));
2029 0 : return JS::Handle<JSObject*>::fromMarkedLocation(entrySlot.address());
2030 : }
2031 :
2032 : JS::Handle<JSObject*>
2033 0 : GetConstructorObjectHandle(JSContext* aCx, bool aDefineOnGlobal)
2034 : {
2035 : /* Get the interface object for this class. This will create the object as
2036 : needed. */
2037 :
2038 : /* Make sure our global is sane. Hopefully we can remove this sometime */
2039 0 : JSObject* global = JS::CurrentGlobalOrNull(aCx);
2040 0 : if (!(js::GetObjectClass(global)->flags & JSCLASS_DOM_GLOBAL)) {
2041 0 : return nullptr;
2042 : }
2043 :
2044 : /* Check to see whether the interface objects are already installed */
2045 0 : ProtoAndIfaceCache& protoAndIfaceCache = *GetProtoAndIfaceCache(global);
2046 0 : if (!protoAndIfaceCache.HasEntryInSlot(constructors::id::U2F)) {
2047 0 : JS::Rooted<JSObject*> rootedGlobal(aCx, global);
2048 0 : CreateInterfaceObjects(aCx, rootedGlobal, protoAndIfaceCache, aDefineOnGlobal);
2049 : }
2050 :
2051 : /*
2052 : * The object might _still_ be null, but that's OK.
2053 : *
2054 : * Calling fromMarkedLocation() is safe because protoAndIfaceCache is
2055 : * traced by TraceProtoAndIfaceCache() and its contents are never
2056 : * changed after they have been set.
2057 : *
2058 : * Calling address() avoids the read read barrier that does gray
2059 : * unmarking, but it's not possible for the object to be gray here.
2060 : */
2061 :
2062 0 : const JS::Heap<JSObject*>& entrySlot = protoAndIfaceCache.EntrySlotMustExist(constructors::id::U2F);
2063 0 : MOZ_ASSERT(JS::ObjectIsNotGray(entrySlot));
2064 0 : return JS::Handle<JSObject*>::fromMarkedLocation(entrySlot.address());
2065 : }
2066 :
2067 : JSObject*
2068 0 : GetConstructorObject(JSContext* aCx)
2069 : {
2070 0 : return GetConstructorObjectHandle(aCx);
2071 : }
2072 :
2073 : } // namespace U2FBinding
2074 :
2075 :
2076 :
2077 : } // namespace dom
2078 : } // namespace mozilla
|