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..60bb7f0926b847d9fcddf88ffcced2234c16cfc8 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) { |
|
dcheng
2017/04/25 12:52:14
Nit: #include <stdint.h> for uint8_t, and uppercas
kpaulhamus
2017/05/03 17:00:45
Done.
|
| + 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(); |
|
dcheng
2017/04/25 12:52:14
Similarly, account_information, mojo_account, etc
kpaulhamus
2017/05/03 17:00:45
Done.
dcheng
2017/05/04 07:22:35
Also: mojoAccount => mojo_account
|
| + |
| + 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(); |
| + |
| + String errorMessage; |
| + if (!executionContext->IsSecureContext(errorMessage)) { |
|
dcheng
2017/04/25 12:52:14
Can you check if this is still needed? I think tha
kpaulhamus
2017/05/03 17:00:45
Yeah, looks like it's not needed anymore. Thanks!
|
| + return ScriptPromise::RejectWithDOMException( |
| + script_state, DOMException::Create(kSecurityError, errorMessage)); |
| + } |
| + |
| + if (!m_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)); |
| + } |
| + |
| + 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 |