| 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 1274dcf6c690975e947e853361836ae62d97788a..500b09e16b685103cb7e07f07522a3210bb14e1d 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 "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().View()->BaseAddress()),
|
| + buffer.getAsArrayBufferView().View()->byteLength());
|
| + }
|
| + return vector;
|
| +}
|
| +
|
| +ScopedCredentialType convertScopedCredentialType(const String& credType) {
|
| + if (credType == "ScopedCred")
|
| + return ScopedCredentialType::SCOPEDCRED;
|
| + NOTREACHED();
|
| + return ScopedCredentialType::SCOPEDCRED;
|
| +}
|
| +
|
| +Transport convertTransport(const 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->relying_party_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->relying_party_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.GetDocument()) {
|
| + frame.GetInterfaceProvider()->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> crypto_parameters,
|
| const BufferSource& attestation_challenge,
|
| ScopedCredentialOptions& options) {
|
| - NOTREACHED();
|
| - return ScriptPromise();
|
| + ExecutionContext* executionContext = script_state->GetExecutionContext();
|
| +
|
| + if (!m_authenticator) {
|
| + return ScriptPromise::RejectWithDOMException(
|
| + script_state, DOMException::Create(kNotSupportedError));
|
| + }
|
| +
|
| + String errorMessage;
|
| + if (!executionContext->IsSecureContext(errorMessage)) {
|
| + return ScriptPromise::RejectWithDOMException(
|
| + script_state, DOMException::Create(kSecurityError, errorMessage));
|
| + }
|
| +
|
| + ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
|
| + ScriptPromise promise = resolver->Promise();
|
| +
|
| + // TODO(kpaulhamus) validate parameters according to spec
|
| + auto account =
|
| + mojo::convertRelyingPartyAccount(account_information, resolver);
|
| + Vector<uint8_t> buffer = mojo::convertBufferSource(attestation_challenge);
|
| + auto opts = mojo::convertScopedCredentialOptions(options, resolver);
|
| + Vector<webauth::mojom::blink::ScopedCredentialParametersPtr> parameters;
|
| + for (const auto& parameter : crypto_parameters) {
|
| + 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(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(kNotFoundError, 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(kNotFoundError, "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
|
|
|