Chromium Code Reviews| 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..685d012b7e3339cf2a07ce62dad9366a9a1f6fdc 100644 |
| --- a/third_party/WebKit/Source/modules/webauth/WebAuthentication.cpp |
| +++ b/third_party/WebKit/Source/modules/webauth/WebAuthentication.cpp |
| @@ -4,13 +4,133 @@ |
| #include "modules/webauth/WebAuthentication.h" |
| +#include <stdint.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; |
| + |
| +// TODO(kpaulhamus): Make this a TypeConverter |
| +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; |
| +} |
| + |
| +// TODO(kpaulhamus): Make this a TypeConverter |
| +ScopedCredentialType ConvertScopedCredentialType(const String& cred_type) { |
| + if (cred_type == "ScopedCred") |
| + return ScopedCredentialType::SCOPEDCRED; |
| + NOTREACHED(); |
| + return ScopedCredentialType::SCOPEDCRED; |
| +} |
| + |
| +// TODO(kpaulhamus): Make this a TypeConverter |
| +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& account_information, |
| + blink::ScriptPromiseResolver* resolver) { |
| + auto mojo_account = RelyingPartyAccount::New(); |
| + |
| + mojo_account->relying_party_display_name = |
| + account_information.rpDisplayName(); |
| + mojo_account->display_name = account_information.displayName(); |
| + mojo_account->id = account_information.id(); |
| + mojo_account->name = account_information.name(); |
| + mojo_account->image_url = account_information.imageURL(); |
| + return mojo_account; |
| +} |
| + |
| +// TODO(kpaulhamus): Make this a TypeConverter |
| +ScopedCredentialOptionsPtr ConvertScopedCredentialOptions( |
| + const blink::ScopedCredentialOptions options, |
| + blink::ScriptPromiseResolver* resolver) { |
| + auto mojo_options = ScopedCredentialOptions::New(); |
| + mojo_options->timeout_seconds = options.timeoutSeconds(); |
| + mojo_options->relying_party_id = options.rpId(); |
| + |
| + // Adds the excludeList members (which are ScopedCredentialDescriptors) |
| + for (const auto& descriptor : options.excludeList()) { |
| + auto mojo_descriptor = ScopedCredentialDescriptor::New(); |
| + mojo_descriptor->type = ConvertScopedCredentialType(descriptor.type()); |
| + mojo_descriptor->id = ConvertBufferSource(descriptor.id()); |
| + for (const auto& transport : descriptor.transports()) |
| + mojo_descriptor->transports.push_back(ConvertTransport(transport)); |
| + mojo_options->exclude_list.push_back(std::move(mojo_descriptor)); |
| + } |
| + // TODO(kpaulhamus): add AuthenticationExtensions; |
| + return mojo_options; |
| +} |
| + |
| +// TODO(kpaulhamus): Make this a TypeConverter |
| +ScopedCredentialParametersPtr ConvertScopedCredentialParameter( |
| + const blink::ScopedCredentialParameters parameter, |
| + blink::ScriptPromiseResolver* resolver) { |
| + auto mojo_parameter = ScopedCredentialParameters::New(); |
| + mojo_parameter->type = ConvertScopedCredentialType(parameter.type()); |
| + // TODO(kpaulhamus): add AlgorithmIdentifier |
| + return mojo_parameter; |
| +} |
| +} // namespace mojo |
| namespace blink { |
| -WebAuthentication::WebAuthentication(LocalFrame& frame) {} |
| +WebAuthentication::WebAuthentication(LocalFrame& frame) |
| + : ContextLifecycleObserver(frame.GetDocument()) { |
| + frame.GetInterfaceProvider()->GetInterface( |
| + mojo::MakeRequest(&authenticator_)); |
| + authenticator_.set_connection_error_handler(ConvertToBaseCallback( |
| + WTF::Bind(&WebAuthentication::OnAuthenticatorConnectionError, |
| + WrapWeakPersistent(this)))); |
| +} |
| -WebAuthentication::~WebAuthentication() {} |
| +WebAuthentication::~WebAuthentication() { |
| + // |authenticator_| may still be valid but there should be no more |
| + // outstanding requests because each holds a persistent handle to this object. |
| + DCHECK(authenticator_requests_.IsEmpty()); |
| +} |
| void WebAuthentication::Dispose() {} |
| @@ -20,8 +140,32 @@ ScriptPromise WebAuthentication::makeCredential( |
| const HeapVector<ScopedCredentialParameters> crypto_parameters, |
| const BufferSource& attestation_challenge, |
| ScopedCredentialOptions& options) { |
| - NOTREACHED(); |
| - return ScriptPromise(); |
| + if (!authenticator_) { |
| + return ScriptPromise::RejectWithDOMException( |
| + script_state, DOMException::Create(kNotSupportedError)); |
| + } |
| + |
| + 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)); |
| + } |
| + |
| + authenticator_requests_.insert(resolver); |
| + 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*) { |
| + authenticator_.reset(); |
|
ikilpatrick
2017/05/09 20:48:58
nothing is needed here except for maybe a TODO
bu
kpaulhamus
2017/05/10 17:58:29
Talked with jyasskin about this and it sounds like
|
| + authenticator_requests_.clear(); |
| +} |
| + |
| +void WebAuthentication::OnAuthenticatorConnectionError() { |
| + authenticator_.reset(); |
| + for (ScriptPromiseResolver* resolver : authenticator_requests_) { |
| + resolver->Reject( |
| + DOMException::Create(kNotFoundError, kNoAuthenticatorError)); |
| + } |
| + authenticator_requests_.clear(); |
| +} |
| + |
| +void WebAuthentication::OnMakeCredential( |
| + ScriptPromiseResolver* resolver, |
| + Vector<webauth::mojom::blink::ScopedCredentialInfoPtr> credentials) { |
| + if (!MarkRequestComplete(resolver)) |
| + return; |
| + |
| + HeapVector<Member<ScopedCredentialInfo>> scoped_credentials; |
| + for (auto& credential : credentials) { |
| + if (credential->client_data.IsEmpty() || |
| + credential->attestation.IsEmpty()) { |
| + resolver->Reject( |
| + DOMException::Create(kNotFoundError, "No credentials returned.")); |
| + } |
| + DOMArrayBuffer* client_data_buffer = DOMArrayBuffer::Create( |
| + static_cast<void*>(&credential->client_data.front()), |
| + credential->client_data.size()); |
| + |
| + DOMArrayBuffer* attestation_buffer = DOMArrayBuffer::Create( |
| + static_cast<void*>(&credential->attestation.front()), |
| + credential->attestation.size()); |
| + |
| + scoped_credentials.push_back( |
| + ScopedCredentialInfo::Create(client_data_buffer, attestation_buffer)); |
| + } |
| + resolver->Resolve(); |
| + authenticator_requests_.erase(resolver); |
|
ikilpatrick
2017/05/09 20:48:58
this isn't needed? (done in MarkRequestComplete?)
kpaulhamus
2017/05/10 17:58:29
Done.
|
| +} |
| + |
| +bool WebAuthentication::MarkRequestComplete(ScriptPromiseResolver* resolver) { |
| + auto request_entry = authenticator_requests_.find(resolver); |
| + if (request_entry == authenticator_requests_.end()) |
| + return false; |
| + authenticator_requests_.erase(request_entry); |
| + return true; |
| +} |
| + |
| +DEFINE_TRACE(WebAuthentication) { |
| + visitor->Trace(authenticator_requests_); |
| + ContextLifecycleObserver::Trace(visitor); |
| +} |
| + |
| } // namespace blink |