Exemplo n.º 1
0
JSValue JSWebNfc::requestAdapter(ExecState* exec)
{
    JSPromiseDeferred* promiseDeferred = JSPromiseDeferred::create(exec, globalObject());
    DeferredWrapper* deferredWrapper = new DeferredWrapper(exec, globalObject(), promiseDeferred);
    impl().requestAdapter(deferredWrapper);
    return promiseDeferred->promise();
}
Exemplo n.º 2
0
JSValue JSSubtleCrypto::exportKey(ExecState* exec)
{
    if (exec->argumentCount() < 2)
        return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec));

    CryptoKeyFormat keyFormat;
    if (!cryptoKeyFormatFromJSValue(exec, exec->argument(0), keyFormat)) {
        ASSERT(exec->hadException());
        return jsUndefined();
    }

    RefPtr<CryptoKey> key = JSCryptoKey::toWrapped(exec->uncheckedArgument(1));
    if (!key)
        return throwTypeError(exec);

    JSPromiseDeferred* promiseDeferred = JSPromiseDeferred::create(exec, globalObject());
    DeferredWrapper wrapper(exec, globalObject(), promiseDeferred);
    auto successCallback = [wrapper](const Vector<uint8_t>& result) mutable {
        wrapper.resolve(result);
    };
    auto failureCallback = [wrapper]() mutable {
        wrapper.reject(nullptr);
    };

    WebCore::exportKey(exec, keyFormat, *key, WTF::move(successCallback), WTF::move(failureCallback));
    if (exec->hadException())
        return jsUndefined();

    return promiseDeferred->promise();
}
Exemplo n.º 3
0
EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncReject(ExecState* exec)
{
    // -- Promise.reject(x) --
    JSValue r = exec->argument(0);

    // 1. Let 'C' be the this value.
    JSValue C = exec->thisValue();

    // 2. Let 'deferred' be the result of calling GetDeferred(C).
    JSValue deferredValue = createJSPromiseDeferredFromConstructor(exec, C);

    // 3. ReturnIfAbrupt(deferred).
    if (exec->hadException())
        return JSValue::encode(jsUndefined());

    JSPromiseDeferred* deferred = jsCast<JSPromiseDeferred*>(deferredValue);

    // 4. Let 'rejectResult' be the result of calling the [[Call]] internal method
    //    of deferred.[[Reject]] with undefined as thisArgument and a List containing r
    //    as argumentsList.
    performDeferredReject(exec, deferred, r);

    // 5. ReturnIfAbrupt(resolveResult).
    if (exec->hadException())
        return JSValue::encode(jsUndefined());

    // 6. Return deferred.[[Promise]].
    return JSValue::encode(deferred->promise());
}
Exemplo n.º 4
0
JSValue JSMediaDevices::getUserMedia(ExecState* exec)
{
    JSPromiseDeferred* promiseDeferred = JSPromiseDeferred::create(exec, globalObject());
    DeferredWrapper wrapper(exec, globalObject(), promiseDeferred);

    Dictionary options(exec, exec->argument(0));
    if (exec->hadException()) {
        Exception* exception = exec->exception();
        exec->clearException();
        wrapper.reject(exception->value());
        return promiseDeferred->promise();
    }

    if (!options.isObject()) {
        JSValue error = createTypeError(exec, "First argument of getUserMedia must be a valid Dictionary");
        wrapper.reject(error);
        return promiseDeferred->promise();
    }

    auto resolveCallback = [wrapper](MediaStream& stream) mutable {
        wrapper.resolve(&stream);
    };
    auto rejectCallback = [wrapper](NavigatorUserMediaError& error) mutable {
        wrapper.reject(&error);
    };

    ExceptionCode ec = 0;
    impl().getUserMedia(options, WTF::move(resolveCallback), WTF::move(rejectCallback), ec);
    if (ec)
        wrapper.reject(ec);

    return promiseDeferred->promise();
}
Exemplo n.º 5
0
JSValue JSSubtleCrypto::verify(ExecState* exec)
{
    if (exec->argumentCount() < 4)
        return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec));

    auto algorithm = createAlgorithmFromJSValue(exec, exec->uncheckedArgument(0));
    if (!algorithm) {
        ASSERT(exec->hadException());
        return jsUndefined();
    }

    auto parameters = JSCryptoAlgorithmDictionary::createParametersForVerify(exec, algorithm->identifier(), exec->uncheckedArgument(0));
    if (!parameters) {
        ASSERT(exec->hadException());
        return jsUndefined();
    }

    RefPtr<CryptoKey> key = JSCryptoKey::toWrapped(exec->uncheckedArgument(1));
    if (!key)
        return throwTypeError(exec);

    if (!key->allows(CryptoKeyUsageVerify)) {
        m_impl->document()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, ASCIILiteral("Key usages do not include 'verify'"));
        setDOMException(exec, NOT_SUPPORTED_ERR);
        return jsUndefined();
    }

    CryptoOperationData signature;
    if (!cryptoOperationDataFromJSValue(exec, exec->uncheckedArgument(2), signature)) {
        ASSERT(exec->hadException());
        return jsUndefined();
    }

    CryptoOperationData data;
    if (!cryptoOperationDataFromJSValue(exec, exec->uncheckedArgument(3), data)) {
        ASSERT(exec->hadException());
        return jsUndefined();
    }

    JSPromiseDeferred* promiseDeferred = JSPromiseDeferred::create(exec, globalObject());
    DeferredWrapper wrapper(exec, globalObject(), promiseDeferred);
    auto successCallback = [wrapper](bool result) mutable {
        wrapper.resolve(result);
    };
    auto failureCallback = [wrapper]() mutable {
        wrapper.reject(nullptr);
    };

    ExceptionCode ec = 0;
    algorithm->verify(*parameters, *key, signature, data, WTF::move(successCallback), WTF::move(failureCallback), ec);
    if (ec) {
        setDOMException(exec, ec);
        return jsUndefined();
    }

    return promiseDeferred->promise();
}
Exemplo n.º 6
0
JSValue JSSubtleCrypto::generateKey(ExecState* exec)
{
    if (exec->argumentCount() < 1)
        return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec));

    auto algorithm = createAlgorithmFromJSValue(exec, exec->uncheckedArgument(0));
    if (!algorithm) {
        ASSERT(exec->hadException());
        return jsUndefined();
    }

    auto parameters = JSCryptoAlgorithmDictionary::createParametersForGenerateKey(exec, algorithm->identifier(), exec->uncheckedArgument(0));
    if (!parameters) {
        ASSERT(exec->hadException());
        return jsUndefined();
    }

    bool extractable = false;
    if (exec->argumentCount() >= 2) {
        extractable = exec->uncheckedArgument(1).toBoolean(exec);
        if (exec->hadException())
            return jsUndefined();
    }

    CryptoKeyUsage keyUsages = 0;
    if (exec->argumentCount() >= 3) {
        if (!cryptoKeyUsagesFromJSValue(exec, exec->argument(2), keyUsages)) {
            ASSERT(exec->hadException());
            return jsUndefined();
        }
    }

    JSPromiseDeferred* promiseDeferred = JSPromiseDeferred::create(exec, globalObject());
    DeferredWrapper wrapper(exec, globalObject(), promiseDeferred);
    auto successCallback = [wrapper](CryptoKey* key, CryptoKeyPair* keyPair) mutable {
        ASSERT(key || keyPair);
        ASSERT(!key || !keyPair);
        if (key)
            wrapper.resolve(key);
        else
            wrapper.resolve(keyPair);
    };
    auto failureCallback = [wrapper]() mutable {
        wrapper.reject(nullptr);
    };

    ExceptionCode ec = 0;
    algorithm->generateKey(*parameters, extractable, keyUsages, WTF::move(successCallback), WTF::move(failureCallback), ec);
    if (ec) {
        setDOMException(exec, ec);
        return jsUndefined();
    }

    return promiseDeferred->promise();
}
Exemplo n.º 7
0
EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncRace(ExecState* exec)
{
    // -- Promise.race(iterable) --
    JSValue iterable = exec->argument(0);
    VM& vm = exec->vm();

    // 1. Let 'C' be the this value.
    JSValue C = exec->thisValue();

    // 2. Let 'deferred' be the result of calling GetDeferred(C).
    JSValue deferredValue = createJSPromiseDeferredFromConstructor(exec, C);

    // 3. ReturnIfAbrupt(deferred).
    if (exec->hadException())
        return JSValue::encode(jsUndefined());

    JSPromiseDeferred* deferred = jsCast<JSPromiseDeferred*>(deferredValue);

    // 4. Let 'iterator' be the result of calling GetIterator(iterable).
    JSValue iteratorFunction = iterable.get(exec, vm.propertyNames->iteratorSymbol);
    if (exec->hadException())
        return JSValue::encode(abruptRejection(exec, deferred));

    CallData iteratorFunctionCallData;
    CallType iteratorFunctionCallType = getCallData(iteratorFunction, iteratorFunctionCallData);
    if (iteratorFunctionCallType == CallTypeNone) {
        throwTypeError(exec);
        return JSValue::encode(abruptRejection(exec, deferred));
    }

    ArgList iteratorFunctionArguments;
    JSValue iterator = call(exec, iteratorFunction, iteratorFunctionCallType, iteratorFunctionCallData, iterable, iteratorFunctionArguments);

    // 5. RejectIfAbrupt(iterator, deferred).
    if (exec->hadException())
        return JSValue::encode(abruptRejection(exec, deferred));

    performPromiseRaceLoop(exec, iterator, deferred, C);
    if (exec->hadException())
        iteratorClose(exec, iterator);
    if (exec->hadException())
        return JSValue::encode(abruptRejection(exec, deferred));
    return JSValue::encode(deferred->promise());
}
Exemplo n.º 8
0
EncodedJSValue JSC_HOST_CALL webAssemblyCompileFunc(ExecState* exec)
{
    VM& vm = exec->vm();
    auto catchScope = DECLARE_CATCH_SCOPE(vm);

    JSPromiseDeferred* promise = JSPromiseDeferred::create(exec, exec->lexicalGlobalObject());
    RETURN_IF_EXCEPTION(catchScope, encodedJSValue());

    // FIXME: Make this truly asynchronous:
    // https://bugs.webkit.org/show_bug.cgi?id=166016
    JSValue module = WebAssemblyModuleConstructor::createModule(exec, exec->lexicalGlobalObject()->WebAssemblyModuleStructure());
    if (Exception* exception = catchScope.exception()) {
        catchScope.clearException();
        promise->reject(exec, exception);
        return JSValue::encode(promise->promise());
    }

    promise->resolve(exec, module);
    return JSValue::encode(promise->promise());
}
Exemplo n.º 9
0
JSValue JSSubtleCrypto::digest(ExecState* exec)
{
    if (exec->argumentCount() < 2)
        return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec));

    auto algorithm = createAlgorithmFromJSValue(exec, exec->uncheckedArgument(0));
    if (!algorithm) {
        ASSERT(exec->hadException());
        return jsUndefined();
    }

    auto parameters = JSCryptoAlgorithmDictionary::createParametersForDigest(exec, algorithm->identifier(), exec->uncheckedArgument(0));
    if (!parameters) {
        ASSERT(exec->hadException());
        return jsUndefined();
    }

    CryptoOperationData data;
    if (!cryptoOperationDataFromJSValue(exec, exec->uncheckedArgument(1), data)) {
        ASSERT(exec->hadException());
        return jsUndefined();
    }

    JSPromiseDeferred* promiseDeferred = JSPromiseDeferred::create(exec, globalObject());
    DeferredWrapper wrapper(exec, globalObject(), promiseDeferred);
    auto successCallback = [wrapper](const Vector<uint8_t>& result) mutable {
        wrapper.resolve(result);
    };
    auto failureCallback = [wrapper]() mutable {
        wrapper.reject(nullptr);
    };

    ExceptionCode ec = 0;
    algorithm->digest(*parameters, data, WTF::move(successCallback), WTF::move(failureCallback), ec);
    if (ec) {
        setDOMException(exec, ec);
        return jsUndefined();
    }

    return promiseDeferred->promise();
}
Exemplo n.º 10
0
EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncResolve(ExecState* exec)
{
    // -- Promise.resolve(x) --
    JSValue x = exec->argument(0);

    // 1. Let 'C' be the this value.
    JSValue C = exec->thisValue();

    // 2. If IsPromise(x) is true,
    JSPromise* promise = jsDynamicCast<JSPromise*>(x);
    if (promise) {
        // i. Let 'constructor' be the value of x's [[PromiseConstructor]] internal slot.
        JSValue constructor = promise->constructor();
        // ii. If SameValue(constructor, C) is true, return x.
        if (sameValue(exec, constructor, C))
            return JSValue::encode(x);
    }

    // 3. Let 'deferred' be the result of calling GetDeferred(C).
    JSValue deferredValue = createJSPromiseDeferredFromConstructor(exec, C);

    // 4. ReturnIfAbrupt(deferred).
    if (exec->hadException())
        return JSValue::encode(jsUndefined());

    JSPromiseDeferred* deferred = jsCast<JSPromiseDeferred*>(deferredValue);

    // 5. Let 'resolveResult' be the result of calling the [[Call]] internal method
    //    of deferred.[[Resolve]] with undefined as thisArgument and a List containing x
    //    as argumentsList.
    performDeferredResolve(exec, deferred, x);

    // 6. ReturnIfAbrupt(resolveResult).
    if (exec->hadException())
        return JSValue::encode(jsUndefined());

    // 7. Return deferred.[[Promise]].
    return JSValue::encode(deferred->promise());
}
Exemplo n.º 11
0
JSValue JSSubtleCrypto::unwrapKey(ExecState* exec)
{
    if (exec->argumentCount() < 5)
        return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec));

    CryptoKeyFormat keyFormat;
    if (!cryptoKeyFormatFromJSValue(exec, exec->argument(0), keyFormat)) {
        ASSERT(exec->hadException());
        return jsUndefined();
    }

    CryptoOperationData wrappedKeyData;
    if (!cryptoOperationDataFromJSValue(exec, exec->uncheckedArgument(1), wrappedKeyData)) {
        ASSERT(exec->hadException());
        return jsUndefined();
    }

    RefPtr<CryptoKey> unwrappingKey = JSCryptoKey::toWrapped(exec->uncheckedArgument(2));
    if (!unwrappingKey)
        return throwTypeError(exec);

    if (!unwrappingKey->allows(CryptoKeyUsageUnwrapKey)) {
        m_impl->document()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, ASCIILiteral("Key usages do not include 'unwrapKey'"));
        setDOMException(exec, NOT_SUPPORTED_ERR);
        return jsUndefined();
    }

    std::unique_ptr<CryptoAlgorithm> unwrapAlgorithm;
    std::unique_ptr<CryptoAlgorithmParameters> unwrapAlgorithmParameters;
    unwrapAlgorithm = createAlgorithmFromJSValue(exec, exec->uncheckedArgument(3));
    if (!unwrapAlgorithm) {
        ASSERT(exec->hadException());
        return jsUndefined();
    }
    unwrapAlgorithmParameters = JSCryptoAlgorithmDictionary::createParametersForDecrypt(exec, unwrapAlgorithm->identifier(), exec->uncheckedArgument(3));
    if (!unwrapAlgorithmParameters) {
        ASSERT(exec->hadException());
        return jsUndefined();
    }

    std::unique_ptr<CryptoAlgorithm> unwrappedKeyAlgorithm;
    std::unique_ptr<CryptoAlgorithmParameters> unwrappedKeyAlgorithmParameters;
    if (!exec->uncheckedArgument(4).isNull()) {
        unwrappedKeyAlgorithm = createAlgorithmFromJSValue(exec, exec->uncheckedArgument(4));
        if (!unwrappedKeyAlgorithm) {
            ASSERT(exec->hadException());
            return jsUndefined();
        }
        unwrappedKeyAlgorithmParameters = JSCryptoAlgorithmDictionary::createParametersForImportKey(exec, unwrappedKeyAlgorithm->identifier(), exec->uncheckedArgument(4));
        if (!unwrappedKeyAlgorithmParameters) {
            ASSERT(exec->hadException());
            return jsUndefined();
        }
    }

    bool extractable = false;
    if (exec->argumentCount() >= 6) {
        extractable = exec->uncheckedArgument(5).toBoolean(exec);
        if (exec->hadException())
            return jsUndefined();
    }

    CryptoKeyUsage keyUsages = 0;
    if (exec->argumentCount() >= 7) {
        if (!cryptoKeyUsagesFromJSValue(exec, exec->argument(6), keyUsages)) {
            ASSERT(exec->hadException());
            return jsUndefined();
        }
    }

    JSPromiseDeferred* promiseDeferred = JSPromiseDeferred::create(exec, globalObject());
    DeferredWrapper wrapper(exec, globalObject(), promiseDeferred);
    Strong<JSDOMGlobalObject> domGlobalObject(exec->vm(), globalObject());

    CryptoAlgorithm* unwrappedKeyAlgorithmPtr = unwrappedKeyAlgorithm.release();
    CryptoAlgorithmParameters* unwrappedKeyAlgorithmParametersPtr = unwrappedKeyAlgorithmParameters.release();

    auto decryptSuccessCallback = [domGlobalObject, keyFormat, unwrappedKeyAlgorithmPtr, unwrappedKeyAlgorithmParametersPtr, extractable, keyUsages, wrapper](const Vector<uint8_t>& result) mutable {
        auto importSuccessCallback = [wrapper](CryptoKey& key) mutable {
            wrapper.resolve(&key);
        };
        auto importFailureCallback = [wrapper]() mutable {
            wrapper.reject(nullptr);
        };
        ExecState* exec = domGlobalObject->globalExec();
        WebCore::importKey(exec, keyFormat, std::make_pair(result.data(), result.size()), std::unique_ptr<CryptoAlgorithm>(unwrappedKeyAlgorithmPtr), std::unique_ptr<CryptoAlgorithmParameters>(unwrappedKeyAlgorithmParametersPtr), extractable, keyUsages, WTF::move(importSuccessCallback), WTF::move(importFailureCallback));
        if (exec->hadException()) {
            // FIXME: Report exception details to console, and possibly to calling script once there is a standardized way to pass errors to WebCrypto promise reject functions.
            exec->clearException();
            importFailureCallback();
        }
    };

    auto decryptFailureCallback = [wrapper, unwrappedKeyAlgorithmPtr, unwrappedKeyAlgorithmParametersPtr]() mutable {
        delete unwrappedKeyAlgorithmPtr;
        delete unwrappedKeyAlgorithmParametersPtr;
        wrapper.reject(nullptr);
    };

    ExceptionCode ec = 0;
    unwrapAlgorithm->decryptForUnwrapKey(*unwrapAlgorithmParameters, *unwrappingKey, wrappedKeyData, WTF::move(decryptSuccessCallback), WTF::move(decryptFailureCallback), ec);
    if (ec) {
        delete unwrappedKeyAlgorithmPtr;
        delete unwrappedKeyAlgorithmParametersPtr;
        setDOMException(exec, ec);
        return jsUndefined();
    }

    return promiseDeferred->promise();
}
Exemplo n.º 12
0
JSValue JSSubtleCrypto::wrapKey(ExecState* exec)
{
    if (exec->argumentCount() < 4)
        return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec));

    CryptoKeyFormat keyFormat;
    if (!cryptoKeyFormatFromJSValue(exec, exec->argument(0), keyFormat)) {
        ASSERT(exec->hadException());
        return jsUndefined();
    }

    RefPtr<CryptoKey> key = JSCryptoKey::toWrapped(exec->uncheckedArgument(1));
    if (!key)
        return throwTypeError(exec);

    RefPtr<CryptoKey> wrappingKey = JSCryptoKey::toWrapped(exec->uncheckedArgument(2));
    if (!key)
        return throwTypeError(exec);

    if (!wrappingKey->allows(CryptoKeyUsageWrapKey)) {
        m_impl->document()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, ASCIILiteral("Key usages do not include 'wrapKey'"));
        setDOMException(exec, NOT_SUPPORTED_ERR);
        return jsUndefined();
    }

    auto algorithm = createAlgorithmFromJSValue(exec, exec->uncheckedArgument(3));
    if (!algorithm) {
        ASSERT(exec->hadException());
        return jsUndefined();
    }

    auto parameters = JSCryptoAlgorithmDictionary::createParametersForEncrypt(exec, algorithm->identifier(), exec->uncheckedArgument(3));
    if (!parameters) {
        ASSERT(exec->hadException());
        return jsUndefined();
    }

    JSPromiseDeferred* promiseDeferred = JSPromiseDeferred::create(exec, globalObject());
    DeferredWrapper wrapper(exec, globalObject(), promiseDeferred);

    CryptoAlgorithm* algorithmPtr = algorithm.release();
    CryptoAlgorithmParameters* parametersPtr = parameters.release();

    auto exportSuccessCallback = [keyFormat, algorithmPtr, parametersPtr, wrappingKey, wrapper](const Vector<uint8_t>& exportedKeyData) mutable {
        auto encryptSuccessCallback = [wrapper, algorithmPtr, parametersPtr](const Vector<uint8_t>& encryptedData) mutable {
            delete algorithmPtr;
            delete parametersPtr;
            wrapper.resolve(encryptedData);
        };
        auto encryptFailureCallback = [wrapper, algorithmPtr, parametersPtr]() mutable {
            delete algorithmPtr;
            delete parametersPtr;
            wrapper.reject(nullptr);
        };
        ExceptionCode ec = 0;
        algorithmPtr->encryptForWrapKey(*parametersPtr, *wrappingKey, std::make_pair(exportedKeyData.data(), exportedKeyData.size()), WTF::move(encryptSuccessCallback), WTF::move(encryptFailureCallback), ec);
        if (ec) {
            // FIXME: Report failure details to console, and possibly to calling script once there is a standardized way to pass errors to WebCrypto promise reject functions.
            encryptFailureCallback();
        }
    };

    auto exportFailureCallback = [wrapper, algorithmPtr, parametersPtr]() mutable {
        delete algorithmPtr;
        delete parametersPtr;
        wrapper.reject(nullptr);
    };

    ExceptionCode ec = 0;
    WebCore::exportKey(exec, keyFormat, *key, WTF::move(exportSuccessCallback), WTF::move(exportFailureCallback));
    if (ec) {
        delete algorithmPtr;
        delete parametersPtr;
        setDOMException(exec, ec);
        return jsUndefined();
    }

    return promiseDeferred->promise();
}
Exemplo n.º 13
0
JSValue JSSubtleCrypto::importKey(ExecState* exec)
{
    if (exec->argumentCount() < 3)
        return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec));

    CryptoKeyFormat keyFormat;
    if (!cryptoKeyFormatFromJSValue(exec, exec->argument(0), keyFormat)) {
        ASSERT(exec->hadException());
        return jsUndefined();
    }

    CryptoOperationData data;
    if (!cryptoOperationDataFromJSValue(exec, exec->uncheckedArgument(1), data)) {
        ASSERT(exec->hadException());
        return jsUndefined();
    }

    std::unique_ptr<CryptoAlgorithm> algorithm;
    std::unique_ptr<CryptoAlgorithmParameters> parameters;
    if (!exec->uncheckedArgument(2).isNull()) {
        algorithm = createAlgorithmFromJSValue(exec, exec->uncheckedArgument(2));
        if (!algorithm) {
            ASSERT(exec->hadException());
            return jsUndefined();
        }
        parameters = JSCryptoAlgorithmDictionary::createParametersForImportKey(exec, algorithm->identifier(), exec->uncheckedArgument(2));
        if (!parameters) {
            ASSERT(exec->hadException());
            return jsUndefined();
        }
    }

    bool extractable = false;
    if (exec->argumentCount() >= 4) {
        extractable = exec->uncheckedArgument(3).toBoolean(exec);
        if (exec->hadException())
            return jsUndefined();
    }

    CryptoKeyUsage keyUsages = 0;
    if (exec->argumentCount() >= 5) {
        if (!cryptoKeyUsagesFromJSValue(exec, exec->argument(4), keyUsages)) {
            ASSERT(exec->hadException());
            return jsUndefined();
        }
    }

    JSPromiseDeferred* promiseDeferred = JSPromiseDeferred::create(exec, globalObject());
    DeferredWrapper wrapper(exec, globalObject(), promiseDeferred);
    auto successCallback = [wrapper](CryptoKey& result) mutable {
        wrapper.resolve(&result);
    };
    auto failureCallback = [wrapper]() mutable {
        wrapper.reject(nullptr);
    };

    WebCore::importKey(exec, keyFormat, data, WTF::move(algorithm), WTF::move(parameters), extractable, keyUsages, WTF::move(successCallback), WTF::move(failureCallback));
    if (exec->hadException())
        return jsUndefined();

    return promiseDeferred->promise();
}
JSPromiseDeferred* JSPromiseDeferred::create(VM& vm, JSObject* promise, JSValue resolve, JSValue reject)
{
    JSPromiseDeferred* deferred = new (NotNull, allocateCell<JSPromiseDeferred>(vm.heap)) JSPromiseDeferred(vm);
    deferred->finishCreation(vm, promise, resolve, reject);
    return deferred;
}
static EncodedJSValue JSC_HOST_CALL promiseResolutionHandlerFunction(ExecState* exec)
{
    JSValue x = exec->argument(0);
    VM& vm = exec->vm();
    JSObject* F = exec->callee();

    // 1. Let 'promise' be the value of F's [[Promise]] internal slot
    JSPromise* promise = jsCast<JSPromise*>(F->get(exec, vm.propertyNames->promisePrivateName));

    // 2. Let 'fulfillmentHandler' be the value of F's [[FulfillmentHandler]] internal slot.
    JSValue fulfillmentHandler = F->get(exec, vm.propertyNames->fulfillmentHandlerPrivateName);
    
    // 3. Let 'rejectionHandler' be the value of F's [[RejectionHandler]] internal slot.
    JSValue rejectionHandler = F->get(exec, vm.propertyNames->rejectionHandlerPrivateName);
    
    // 4. If SameValue(x, promise) is true,
    if (sameValue(exec, x, promise)) {
        // i. Let 'selfResolutionError' be a newly-created TypeError object.
        JSObject* selfResolutionError = createTypeError(exec, ASCIILiteral("Resolve a promise with itself"));
        // ii. Return the result of calling the [[Call]] internal method of rejectionHandler with
        //     undefined as thisArgument and a List containing selfResolutionError as argumentsList.
        CallData rejectCallData;
        CallType rejectCallType = getCallData(rejectionHandler, rejectCallData);
        ASSERT(rejectCallType != CallTypeNone);

        MarkedArgumentBuffer rejectArguments;
        rejectArguments.append(selfResolutionError);

        return JSValue::encode(call(exec, rejectionHandler, rejectCallType, rejectCallData, jsUndefined(), rejectArguments));
    }

    // 5. Let 'C' be the value of promise's [[PromiseConstructor]] internal slot.
    JSValue C = promise->constructor();

    // 6. Let 'deferred' be the result of calling GetDeferred(C)
    JSValue deferredValue = createJSPromiseDeferredFromConstructor(exec, C);

    // 7. ReturnIfAbrupt(deferred).
    if (exec->hadException())
        return JSValue::encode(jsUndefined());

    JSPromiseDeferred* deferred = jsCast<JSPromiseDeferred*>(deferredValue);

    // 8. Let 'updateResult' be the result of calling UpdateDeferredFromPotentialThenable(x, deferred).
    ThenableStatus updateResult = updateDeferredFromPotentialThenable(exec, x, deferred);

    // 9. ReturnIfAbrupt(updateResult).
    if (exec->hadException())
        return JSValue::encode(jsUndefined());

    // 10. If 'updateResult' is not "not a thenable", return the result of calling
    //     Invoke(deferred.[[Promise]], "then", (fulfillmentHandler, rejectionHandler)).
    // NOTE: Invoke does not seem to be defined anywhere, so I am guessing here.
    if (updateResult != NotAThenable) {
        JSObject* deferredPromise = deferred->promise();
    
        JSValue thenValue = deferredPromise->get(exec, exec->vm().propertyNames->then);
        if (exec->hadException())
            return JSValue::encode(jsUndefined());

        CallData thenCallData;
        CallType thenCallType = getCallData(thenValue, thenCallData);
        if (thenCallType == CallTypeNone)
            return JSValue::encode(throwTypeError(exec));

        MarkedArgumentBuffer arguments;
        arguments.append(fulfillmentHandler);
        arguments.append(rejectionHandler);

        return JSValue::encode(call(exec, thenValue, thenCallType, thenCallData, deferredPromise, arguments));
    }
    
    // 11. Return the result of calling the [[Call]] internal method of fulfillmentHandler
    //     with undefined as thisArgument and a List containing x as argumentsList.
    CallData fulfillmentHandlerCallData;
    CallType fulfillmentHandlerCallType = getCallData(fulfillmentHandler, fulfillmentHandlerCallData);
    ASSERT(fulfillmentHandlerCallType != CallTypeNone);
    
    MarkedArgumentBuffer fulfillmentHandlerArguments;
    fulfillmentHandlerArguments.append(x);

    return JSValue::encode(call(exec, fulfillmentHandler, fulfillmentHandlerCallType, fulfillmentHandlerCallData, jsUndefined(), fulfillmentHandlerArguments));
}