| Index: third_party/WebKit/Source/modules/webauth/WebAuthentication.cpp
|
| diff --git a/third_party/WebKit/Source/modules/webauth/WebAuthentication.cpp b/third_party/WebKit/Source/modules/webauth/WebAuthentication.cpp
|
| index baecd1d0a595b24722d66a3c81d7288167138384..9ceeb8da358a3bcadb82157c71d7a8299c6b0cde 100644
|
| --- a/third_party/WebKit/Source/modules/webauth/WebAuthentication.cpp
|
| +++ b/third_party/WebKit/Source/modules/webauth/WebAuthentication.cpp
|
| @@ -5,12 +5,124 @@
|
| #include "modules/webauth/WebAuthentication.h"
|
|
|
| #include "bindings/core/v8/ScriptPromise.h"
|
| +#include "bindings/core/v8/ScriptPromiseResolver.h"
|
| +#include "core/dom/DOMException.h"
|
| +#include "core/dom/Document.h"
|
| +#include "core/dom/ExceptionCode.h"
|
| +#include "core/frame/LocalFrame.h"
|
| +#include "core/frame/UseCounter.h"
|
| +#include "modules/webauth/RelyingPartyAccount.h"
|
| +#include "modules/webauth/ScopedCredential.h"
|
| +#include "modules/webauth/ScopedCredentialOptions.h"
|
| +#include "modules/webauth/ScopedCredentialParameters.h"
|
| +#include "public/platform/InterfaceProvider.h"
|
| +
|
| +namespace {
|
| +const char kNoAuthenticatorError[] = "Authenticator unavailable.";
|
| +} // anonymous namespace
|
| +
|
| +namespace mojo {
|
| +
|
| +using webauth::mojom::blink::RelyingPartyAccount;
|
| +using webauth::mojom::blink::RelyingPartyAccountPtr;
|
| +using webauth::mojom::blink::ScopedCredentialOptions;
|
| +using webauth::mojom::blink::ScopedCredentialOptionsPtr;
|
| +using webauth::mojom::blink::ScopedCredentialParameters;
|
| +using webauth::mojom::blink::ScopedCredentialParametersPtr;
|
| +using webauth::mojom::blink::ScopedCredentialDescriptor;
|
| +using webauth::mojom::blink::ScopedCredentialType;
|
| +using webauth::mojom::blink::Transport;
|
| +
|
| +Vector<uint8_t> convertBufferSource(const blink::BufferSource& buffer) {
|
| + DCHECK(buffer.isNull());
|
| + Vector<uint8_t> vector;
|
| + if (buffer.isArrayBuffer()) {
|
| + vector.append(static_cast<uint8_t*>(buffer.getAsArrayBuffer()->data()),
|
| + buffer.getAsArrayBuffer()->byteLength());
|
| + } else {
|
| + vector.append(
|
| + static_cast<uint8_t*>(buffer.getAsArrayBufferView()->baseAddress()),
|
| + buffer.getAsArrayBufferView()->byteLength());
|
| + }
|
| + return vector;
|
| +}
|
| +
|
| +ScopedCredentialType convertScopedCredentialType(const WTF::String& credType) {
|
| + if (credType == "ScopedCred")
|
| + return ScopedCredentialType::SCOPEDCRED;
|
| + NOTREACHED();
|
| + return ScopedCredentialType::SCOPEDCRED;
|
| +}
|
| +
|
| +Transport convertTransport(const WTF::String& transport) {
|
| + if (transport == "usb")
|
| + return Transport::USB;
|
| + if (transport == "nfc")
|
| + return Transport::NFC;
|
| + if (transport == "ble")
|
| + return Transport::BLE;
|
| + NOTREACHED();
|
| + return Transport::USB;
|
| +}
|
| +
|
| +RelyingPartyAccountPtr convertRelyingPartyAccount(
|
| + const blink::RelyingPartyAccount& accountInformation,
|
| + blink::ScriptPromiseResolver* resolver) {
|
| + auto mojoAccount = RelyingPartyAccount::New();
|
| +
|
| + mojoAccount->rp_display_name = accountInformation.rpDisplayName();
|
| + mojoAccount->display_name = accountInformation.displayName();
|
| + mojoAccount->id = accountInformation.id();
|
| + mojoAccount->name = accountInformation.name();
|
| + mojoAccount->image_url = accountInformation.imageURL();
|
| + return mojoAccount;
|
| +}
|
| +
|
| +ScopedCredentialOptionsPtr convertScopedCredentialOptions(
|
| + const blink::ScopedCredentialOptions options,
|
| + blink::ScriptPromiseResolver* resolver) {
|
| + auto mojoOptions = ScopedCredentialOptions::New();
|
| + mojoOptions->timeout_seconds = options.timeoutSeconds();
|
| + mojoOptions->rp_id = options.rpId();
|
| +
|
| + // Adds the excludeList members (which are ScopedCredentialDescriptors)
|
| + for (const auto& descriptor : options.excludeList()) {
|
| + auto mojoDescriptor = ScopedCredentialDescriptor::New();
|
| + mojoDescriptor->type = convertScopedCredentialType(descriptor.type());
|
| + mojoDescriptor->id = convertBufferSource(descriptor.id());
|
| + for (const auto& transport : descriptor.transports())
|
| + mojoDescriptor->transports.push_back(convertTransport(transport));
|
| + mojoOptions->exclude_list.push_back(std::move(mojoDescriptor));
|
| + }
|
| + // TODO (kpaulhamus) add AuthenticationExtensions;
|
| + return mojoOptions;
|
| +}
|
| +
|
| +ScopedCredentialParametersPtr convertScopedCredentialParameter(
|
| + const blink::ScopedCredentialParameters parameter,
|
| + blink::ScriptPromiseResolver* resolver) {
|
| + auto mojoParameter = ScopedCredentialParameters::New();
|
| + mojoParameter->type = convertScopedCredentialType(parameter.type());
|
| + // TODO (kpaulhamus) add AlgorithmIdentifier
|
| + return mojoParameter;
|
| +}
|
| +} // namespace mojo
|
|
|
| namespace blink {
|
|
|
| -WebAuthentication::WebAuthentication(LocalFrame& frame) {}
|
| +WebAuthentication::WebAuthentication(LocalFrame& frame)
|
| + : ContextLifecycleObserver(frame.document()) {
|
| + frame.interfaceProvider()->getInterface(mojo::MakeRequest(&m_authenticator));
|
| + m_authenticator.set_connection_error_handler(convertToBaseCallback(
|
| + WTF::bind(&WebAuthentication::onAuthenticatorConnectionError,
|
| + wrapWeakPersistent(this))));
|
| +}
|
|
|
| -WebAuthentication::~WebAuthentication() {}
|
| +WebAuthentication::~WebAuthentication() {
|
| + // |m_authenticator| may still be valid but there should be no more
|
| + // outstanding requests because each holds a persistent handle to this object.
|
| + DCHECK(m_authenticatorRequests.isEmpty());
|
| +}
|
|
|
| void WebAuthentication::dispose() {}
|
|
|
| @@ -20,8 +132,40 @@ ScriptPromise WebAuthentication::makeCredential(
|
| const HeapVector<ScopedCredentialParameters> cryptoParameters,
|
| const BufferSource& attestationChallenge,
|
| ScopedCredentialOptions& options) {
|
| - NOTREACHED();
|
| - return ScriptPromise();
|
| + ExecutionContext* executionContext = scriptState->getExecutionContext();
|
| + UseCounter::count(executionContext, UseCounter::AuthenticationMakeCredential);
|
| +
|
| + if (!m_authenticator) {
|
| + return ScriptPromise::rejectWithDOMException(
|
| + scriptState, DOMException::create(NotSupportedError));
|
| + }
|
| +
|
| + String errorMessage;
|
| + if (!executionContext->isSecureContext(errorMessage)) {
|
| + return ScriptPromise::rejectWithDOMException(
|
| + scriptState, DOMException::create(SecurityError, errorMessage));
|
| + }
|
| +
|
| + ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
|
| + ScriptPromise promise = resolver->promise();
|
| +
|
| + // TODO(kpaulhamus) validate parameters according to spec
|
| + auto account = mojo::convertRelyingPartyAccount(accountInformation, resolver);
|
| + Vector<uint8_t> buffer = mojo::convertBufferSource(attestationChallenge);
|
| + auto opts = mojo::convertScopedCredentialOptions(options, resolver);
|
| + Vector<webauth::mojom::blink::ScopedCredentialParametersPtr> parameters;
|
| + for (const auto& parameter : cryptoParameters) {
|
| + parameters.push_back(
|
| + mojo::convertScopedCredentialParameter(parameter, resolver));
|
| + }
|
| +
|
| + m_authenticatorRequests.insert(resolver);
|
| + m_authenticator->makeCredential(
|
| + std::move(account), std::move(parameters), buffer, std::move(opts),
|
| + convertToBaseCallback(WTF::bind(&WebAuthentication::onMakeCredential,
|
| + wrapPersistent(this),
|
| + wrapPersistent(resolver))));
|
| + return promise;
|
| }
|
|
|
| ScriptPromise WebAuthentication::getAssertion(
|
| @@ -32,4 +176,59 @@ ScriptPromise WebAuthentication::getAssertion(
|
| return ScriptPromise();
|
| }
|
|
|
| +void WebAuthentication::contextDestroyed(ExecutionContext*) {
|
| + m_authenticator.reset();
|
| + m_authenticatorRequests.clear();
|
| +}
|
| +
|
| +void WebAuthentication::onAuthenticatorConnectionError() {
|
| + m_authenticator.reset();
|
| + for (ScriptPromiseResolver* resolver : m_authenticatorRequests) {
|
| + resolver->reject(
|
| + DOMException::create(NotFoundError, kNoAuthenticatorError));
|
| + }
|
| + m_authenticatorRequests.clear();
|
| +}
|
| +
|
| +void WebAuthentication::onMakeCredential(
|
| + ScriptPromiseResolver* resolver,
|
| + Vector<webauth::mojom::blink::ScopedCredentialInfoPtr> credentials) {
|
| + if (!markRequestComplete(resolver))
|
| + return;
|
| +
|
| + HeapVector<Member<ScopedCredentialInfo>> scopedCredentials;
|
| + for (auto& credential : credentials) {
|
| + if (credential->client_data.isEmpty() ||
|
| + credential->attestation.isEmpty()) {
|
| + resolver->reject(
|
| + DOMException::create(NotFoundError, "No credentials returned."));
|
| + }
|
| + DOMArrayBuffer* clientDataBuffer = DOMArrayBuffer::create(
|
| + static_cast<void*>(&credential->client_data.front()),
|
| + credential->client_data.size());
|
| +
|
| + DOMArrayBuffer* attestationBuffer = DOMArrayBuffer::create(
|
| + static_cast<void*>(&credential->attestation.front()),
|
| + credential->attestation.size());
|
| +
|
| + scopedCredentials.push_back(
|
| + ScopedCredentialInfo::create(clientDataBuffer, attestationBuffer));
|
| + }
|
| + resolver->resolve(scopedCredentials);
|
| + m_authenticatorRequests.erase(resolver);
|
| +}
|
| +
|
| +bool WebAuthentication::markRequestComplete(ScriptPromiseResolver* resolver) {
|
| + auto requestEntry = m_authenticatorRequests.find(resolver);
|
| + if (requestEntry == m_authenticatorRequests.end())
|
| + return false;
|
| + m_authenticatorRequests.erase(requestEntry);
|
| + return true;
|
| +}
|
| +
|
| +DEFINE_TRACE(WebAuthentication) {
|
| + visitor->trace(m_authenticatorRequests);
|
| + ContextLifecycleObserver::trace(visitor);
|
| +}
|
| +
|
| } // namespace blink
|
|
|