[WebAuthN] Revisit the whole async model of task dispatching, timeout and aborting
authorjiewen_tan@apple.com <jiewen_tan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 14 Feb 2018 01:34:21 +0000 (01:34 +0000)
committerjiewen_tan@apple.com <jiewen_tan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 14 Feb 2018 01:34:21 +0000 (01:34 +0000)
https://bugs.webkit.org/show_bug.cgi?id=181946
<rdar://problem/37258262>

Reviewed by Chris Dumez.

Source/WebCore:

This patch changes the original async model from a work queue to IPC between WebProcess
and UIProcess. Since all authenticator operations must be handled in the UIProcess due
to sandboxing, this message passing IPC async model then surpasses the original multi
threading model. To cooperate that, a CredentialsMessenger class is then created and
all task dispatching code is moved thre.

As an improvement over existing code, static functions from PublicKeyCredential are
moved to AuthenticatorManager. AuthenticatorManager is made as a singleton such that
when static functions are called, they could reach the CredentialsMessenger to interact
with UIProccess. CredentialsMessenger and AuthenticatorManager are separated so later
on when other Credential types are created, they can reuse the same IPC messenger.

What's more, a mock CredentialsMessenger is then created to mock behaviors of UIProcess
for testing purpose.

Covered by existing tests.

* DerivedSources.make:
* Modules/credentialmanagement/BasicCredential.h:
* Modules/credentialmanagement/CredentialsContainer.cpp:
(WebCore::CredentialsContainer::CredentialsContainer):
(WebCore::CredentialsContainer::doesHaveSameOriginAsItsAncestors):
(WebCore::CredentialsContainer::get):
(WebCore::CredentialsContainer::isCreate):
(WebCore::CredentialsContainer::PendingPromise::PendingPromise): Deleted.
(WebCore::CredentialsContainer::dispatchTask): Deleted.
* Modules/credentialmanagement/CredentialsContainer.h:
(WebCore::CredentialsContainer::PendingPromise::create): Deleted.
* Modules/credentialmanagement/CredentialsMessenger.cpp: Added.
(WebCore::CredentialsMessenger::exceptionReply):
(WebCore::CredentialsMessenger::addCreationCompletionHandler):
(WebCore::CredentialsMessenger::takeCreationCompletionHandler):
(WebCore::CredentialsMessenger::addRequestCompletionHandler):
(WebCore::CredentialsMessenger::takeRequestCompletionHandler):
(WebCore::CredentialsMessenger::addQueryCompletionHandler):
(WebCore::CredentialsMessenger::takeQueryCompletionHandler):
(WebCore::getIdFromAttestationObject):
* Modules/credentialmanagement/CredentialsMessenger.h: Added.
(WebCore::CreationReturnBundle::CreationReturnBundle):
(WebCore::AssertionReturnBundle::AssertionReturnBundle):
(WebCore::CredentialsMessenger::weakPtrFactory const):
* Modules/webauthn/Authenticator.cpp: Removed.
* Modules/webauthn/Authenticator.h: Removed.
* Modules/webauthn/AuthenticatorManager.cpp: Copied from Source/WebCore/Modules/webauthn/PublicKeyCredential.cpp.
(WebCore::AuthenticatorManagerInternal::produceClientDataJson):
(WebCore::AuthenticatorManagerInternal::produceClientDataJsonHash):
(WebCore::AuthenticatorManagerInternal::initTimer):
(WebCore::AuthenticatorManagerInternal::didTimerFire):
(WebCore::AuthenticatorManager::singleton):
(WebCore::AuthenticatorManager::setMessenger):
(WebCore::AuthenticatorManager::create const):
(WebCore::AuthenticatorManager::discoverFromExternalSource const):
* Modules/webauthn/AuthenticatorManager.h: Copied from Source/WebCore/Modules/webauthn/AuthenticatorResponse.h.
* Modules/webauthn/AuthenticatorResponse.h:
* Modules/webauthn/PublicKeyCredential.cpp:
(WebCore::PublicKeyCredentialInternal::produceClientDataJson): Deleted.
(WebCore::PublicKeyCredentialInternal::produceClientDataJsonHash): Deleted.
(WebCore::PublicKeyCredentialInternal::getIdFromAttestationObject): Deleted.
(WebCore::PublicKeyCredential::collectFromCredentialStore): Deleted.
(WebCore::PublicKeyCredential::discoverFromExternalSource): Deleted.
(WebCore::PublicKeyCredential::store): Deleted.
(WebCore::PublicKeyCredential::create): Deleted.
(WebCore::PublicKeyCredential::rawId const): Deleted.
(WebCore::PublicKeyCredential::response const): Deleted.
* Modules/webauthn/PublicKeyCredential.h:
* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* testing/Internals.cpp:
(WebCore::Internals::Internals):
(WebCore::Internals::mockCredentialsMessenger const):
* testing/Internals.h:
* testing/Internals.idl:
* testing/MockCredentialsMessenger.cpp: Added.
(WebCore::MockCredentialsMessenger::setAttestationObject):
(WebCore::MockCredentialsMessenger::setAssertionReturnBundle):
(WebCore::MockCredentialsMessenger::makeCredential):
(WebCore::MockCredentialsMessenger::getAssertion):
(WebCore::MockCredentialsMessenger::makeCredentialReply):
(WebCore::MockCredentialsMessenger::getAssertionReply):
* testing/MockCredentialsMessenger.h: Copied from Source/WebCore/Modules/webauthn/AuthenticatorResponse.h.
* testing/MockCredentialsMessenger.idl: Copied from Source/WebCore/Modules/webauthn/AuthenticatorResponse.h.

Source/WebKit:

Dummy WebCredentialsMessenger and WebCredentialsMessengerProxy are crafted to establish
a message exchange channel between UIProcess and WebProcess.

* DerivedSources.make:
* UIProcess/CredentialManagement/WebCredentialsMessengerProxy.cpp: Copied from Source/WebCore/Modules/webauthn/AuthenticatorResponse.h.
(WebKit::WebCredentialsMessengerProxy::WebCredentialsMessengerProxy):
(WebKit::WebCredentialsMessengerProxy::~WebCredentialsMessengerProxy):
(WebKit::WebCredentialsMessengerProxy::makeCredential):
(WebKit::WebCredentialsMessengerProxy::getAssertion):
* UIProcess/CredentialManagement/WebCredentialsMessengerProxy.h: Copied from Source/WebCore/Modules/webauthn/AuthenticatorResponse.h.
* UIProcess/CredentialManagement/WebCredentialsMessengerProxy.messages.in: Added.
* UIProcess/WebPageProxy.cpp:
(WebKit::m_configurationPreferenceValues):
(WebKit::WebPageProxy::reattachToWebProcess):
* UIProcess/WebPageProxy.h:
* WebKit.xcodeproj/project.pbxproj:
* WebProcess/CredentialManagement/WebCredentialsMessenger.cpp: Copied from Source/WebCore/Modules/webauthn/AuthenticatorResponse.h.
(WebKit::WebCredentialsMessenger::WebCredentialsMessenger):
(WebKit::WebCredentialsMessenger::~WebCredentialsMessenger):
(WebKit::WebCredentialsMessenger::makeCredential):
(WebKit::WebCredentialsMessenger::getAssertion):
(WebKit::WebCredentialsMessenger::makeCredentialReply):
(WebKit::WebCredentialsMessenger::getAssertionReply):
* WebProcess/CredentialManagement/WebCredentialsMessenger.h: Copied from Source/WebCore/Modules/webauthn/AuthenticatorResponse.h.
* WebProcess/CredentialManagement/WebCredentialsMessenger.messages.in: Added.
* WebProcess/WebPage/WebPage.cpp:
(WebKit::m_credentialsMessenger):
(WebKit::m_cpuLimit): Deleted.
* WebProcess/WebPage/WebPage.h:

LayoutTests:

* http/wpt/credential-management/credentialscontainer-store-basics.https.html:
* http/wpt/webauthn/idl.https.html:
* http/wpt/webauthn/public-key-credential-create-failure.https.html:
* http/wpt/webauthn/public-key-credential-create-success.https.html:
* http/wpt/webauthn/public-key-credential-get-failure.https.html:
* http/wpt/webauthn/public-key-credential-get-success.https.html:
* http/wpt/webauthn/resources/util.js:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@228444 268f45cc-cd09-0410-ab3c-d52691b4dbfc

44 files changed:
LayoutTests/ChangeLog
LayoutTests/http/wpt/credential-management/credentialscontainer-store-basics.https.html
LayoutTests/http/wpt/webauthn/idl.https.html
LayoutTests/http/wpt/webauthn/public-key-credential-create-failure.https.html
LayoutTests/http/wpt/webauthn/public-key-credential-create-success.https.html
LayoutTests/http/wpt/webauthn/public-key-credential-get-failure.https.html
LayoutTests/http/wpt/webauthn/public-key-credential-get-success.https.html
LayoutTests/http/wpt/webauthn/resources/util.js
LayoutTests/imported/w3c/web-platform-tests/credential-management/credentialscontainer-create-basics.https-expected.txt
Source/WebCore/ChangeLog
Source/WebCore/DerivedSources.make
Source/WebCore/Modules/credentialmanagement/BasicCredential.h
Source/WebCore/Modules/credentialmanagement/CredentialsContainer.cpp
Source/WebCore/Modules/credentialmanagement/CredentialsContainer.h
Source/WebCore/Modules/credentialmanagement/CredentialsMessenger.cpp [new file with mode: 0644]
Source/WebCore/Modules/credentialmanagement/CredentialsMessenger.h [new file with mode: 0644]
Source/WebCore/Modules/webauthn/Authenticator.cpp [deleted file]
Source/WebCore/Modules/webauthn/Authenticator.h [deleted file]
Source/WebCore/Modules/webauthn/AuthenticatorManager.cpp [new file with mode: 0644]
Source/WebCore/Modules/webauthn/AuthenticatorManager.h [new file with mode: 0644]
Source/WebCore/Modules/webauthn/AuthenticatorResponse.h
Source/WebCore/Modules/webauthn/PublicKeyCredential.cpp
Source/WebCore/Modules/webauthn/PublicKeyCredential.h
Source/WebCore/Sources.txt
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/testing/Internals.cpp
Source/WebCore/testing/Internals.h
Source/WebCore/testing/Internals.idl
Source/WebCore/testing/MockCredentialsMessenger.cpp [new file with mode: 0644]
Source/WebCore/testing/MockCredentialsMessenger.h [new file with mode: 0644]
Source/WebCore/testing/MockCredentialsMessenger.idl [new file with mode: 0644]
Source/WebKit/ChangeLog
Source/WebKit/DerivedSources.make
Source/WebKit/UIProcess/CredentialManagement/WebCredentialsMessengerProxy.cpp [new file with mode: 0644]
Source/WebKit/UIProcess/CredentialManagement/WebCredentialsMessengerProxy.h [new file with mode: 0644]
Source/WebKit/UIProcess/CredentialManagement/WebCredentialsMessengerProxy.messages.in [new file with mode: 0644]
Source/WebKit/UIProcess/WebPageProxy.cpp
Source/WebKit/UIProcess/WebPageProxy.h
Source/WebKit/WebKit.xcodeproj/project.pbxproj
Source/WebKit/WebProcess/CredentialManagement/WebCredentialsMessenger.cpp [new file with mode: 0644]
Source/WebKit/WebProcess/CredentialManagement/WebCredentialsMessenger.h [new file with mode: 0644]
Source/WebKit/WebProcess/CredentialManagement/WebCredentialsMessenger.messages.in [new file with mode: 0644]
Source/WebKit/WebProcess/WebPage/WebPage.cpp
Source/WebKit/WebProcess/WebPage/WebPage.h

index 72b539e..6ba7ab4 100644 (file)
@@ -1,3 +1,19 @@
+2018-02-13  Jiewen Tan  <jiewen_tan@apple.com>
+
+        [WebAuthN] Revisit the whole async model of task dispatching, timeout and aborting
+        https://bugs.webkit.org/show_bug.cgi?id=181946
+        <rdar://problem/37258262>
+
+        Reviewed by Chris Dumez.
+
+        * http/wpt/credential-management/credentialscontainer-store-basics.https.html:
+        * http/wpt/webauthn/idl.https.html:
+        * http/wpt/webauthn/public-key-credential-create-failure.https.html:
+        * http/wpt/webauthn/public-key-credential-create-success.https.html:
+        * http/wpt/webauthn/public-key-credential-get-failure.https.html:
+        * http/wpt/webauthn/public-key-credential-get-success.https.html:
+        * http/wpt/webauthn/resources/util.js:
+
 2018-02-13  Antti Koivisto  <antti@apple.com>
 
         Crash when breakpoint hit in unload handler
index 01b9bbb..ca47ff9 100644 (file)
             chars.push(str.charCodeAt(i));
         return new Uint8Array(chars);
     }
+    function hexStringToUint8Array(hexString)
+    {
+        if (hexString.length % 2 != 0)
+            throw "Invalid hexString";
+        var arrayBuffer = new Uint8Array(hexString.length / 2);
+
+        for (var i = 0; i < hexString.length; i += 2) {
+            var byteValue = parseInt(hexString.substr(i, 2), 16);
+            if (byteValue == NaN)
+                throw "Invalid hexString";
+            arrayBuffer[i/2] = byteValue;
+        }
+
+        return arrayBuffer;
+    }
 
     promise_test(async function(t) {
         const options = {
                 pubKeyCredParams: [{ type: "public-key", alg: -7 }],
             }
         };
-
+        // A mock attestation object
+        internals.mockCredentialsMessenger.setAttestationObject(hexStringToUint8Array('000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001ff'));
         const credential = await navigator.credentials.create(options);
+
         return promise_rejects(t, "NotSupportedError",
             navigator.credentials.store(credential));
     }, "navigator.credentials.store().");
index 040a145..90e56bb 100644 (file)
@@ -49,6 +49,8 @@ promise_test(async () => {
             pubKeyCredParams: [{ type: "public-key", alg: -7 }],
         }
     };
+    // A mock attestation object
+    internals.mockCredentialsMessenger.setAttestationObject(hexStringToUint8Array('000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001ff'));
     createdCredential = await navigator.credentials.create(creationOptions);
 
 
@@ -57,6 +59,8 @@ promise_test(async () => {
             challenge: Base64URL.parse("MTIzNDU2"),
         }
     };
+    // A mock assertion return bundle.
+    internals.mockCredentialsMessenger.setAssertionReturnBundle(hexStringToUint8Array('00'), hexStringToUint8Array('01'), hexStringToUint8Array('02'), hexStringToUint8Array('03'));
     requestedCredential = await navigator.credentials.get(requestOptions);
 
     idlArray.add_objects({"PublicKeyCredential": ["createdCredential"], "AuthenticatorAttestationResponse": ["createdCredential.response"], "AuthenticatorAssertionResponse": ["requestedCredential.response"]});
index 20e8e41..bb5548c 100644 (file)
@@ -20,6 +20,8 @@
                 timeout: 0,
             }
         };
+        internals.mockCredentialsMessenger.setDidTimeOut();
+
         return promise_rejects(t, "NotAllowedError",
             navigator.credentials.create(options));
     }, "PublicKeyCredential's [[create]] with timeout");
@@ -64,8 +66,6 @@
             navigator.credentials.create(options));
     }, "PublicKeyCredential's [[create]] with an empty pubKeyCredParams");
 
-    // This test is targeting to the dummy authenticator, which always cancel the operation
-    // when user.displayName = "John".
     promise_test(function(t) {
         const options = {
             publicKey: {
@@ -82,6 +82,8 @@
                 pubKeyCredParams: [{ type: "public-key", alg: -7 }],
             }
         };
+        internals.mockCredentialsMessenger.setDidUserCancel();
+
         return promise_rejects(t, "NotAllowedError",
             navigator.credentials.create(options));
     }, "PublicKeyCredential's [[create]] with user cancellations");
index b11c793..b09417b 100644 (file)
@@ -4,7 +4,6 @@
 <script src="/resources/testharnessreport.js"></script>
 <script src="./resources/util.js"></script>
 <script>
-    // The following test is specifically tuned for current dummy authenticator.
     promise_test(function(t) {
         const options = {
             publicKey: {
                 pubKeyCredParams: [{ type: "public-key", alg: -7 }],
             }
         };
+        // A mock attestation object
+        internals.mockCredentialsMessenger.setAttestationObject(hexStringToUint8Array('000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001ff'));
 
         return navigator.credentials.create(options).then(function(credential) {
                 assert_equals(credential.id, '_w');
                 assert_equals(credential.type, 'public-key');
                 assert_equals(bytesToHexString(credential.rawId), 'ff');
                 assert_equals(bytesToASCIIString(credential.response.clientDataJSON), '{"type":"webauthn.create","challenge":"MTIzNDU2","origin":"https://localhost:9443","hashAlgorithm":"SHA-256"}');
-                // This field is completely fake 0x00*43 | 0x0001ff | SHA-256 hash of the clientDataJSON
-                assert_equals(bytesToHexString(credential.response.attestationObject), '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001ff3374b98316b38046727a770b8e95c4580a292b9e2f4bb44a250a5402d6d3783a');
+                assert_equals(bytesToHexString(credential.response.attestationObject), '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001ff');
                 try {
                     assert_throws("NotSupportedError", credential.getClientExtensionResults());
                 } catch(error) { }
index 3354c3a..512bb2d 100644 (file)
@@ -11,6 +11,8 @@
                 timeout: 0,
             }
         };
+        internals.mockCredentialsMessenger.setDidTimeOut();
+
         return promise_rejects(t, "NotAllowedError",
             navigator.credentials.get(options));
     }, "PublicKeyCredential's [[get]] with timeout");
@@ -26,8 +28,6 @@
             navigator.credentials.get(options));
     }, "PublicKeyCredential's [[get]] with a mismatched RP ID");
 
-    // This test is targeting to the dummy authenticator, which always cancel the operation
-    // when allowCredentials is not empty.
     promise_test(function(t) {
         const options = {
             publicKey: {
@@ -35,6 +35,8 @@
                 allowCredentials: [{ type: "public-key", id: asciiToUint8Array("123456") }],
             }
         };
+        internals.mockCredentialsMessenger.setDidUserCancel();
+
         return promise_rejects(t, "NotAllowedError",
             navigator.credentials.get(options));
     }, "PublicKeyCredential's [[get]] with user cancellations");
index 8015f39..2e5ec88 100644 (file)
                 challenge: Base64URL.parse("MTIzNDU2"),
             }
         };
+        // A mock assertion return bundle.
+        internals.mockCredentialsMessenger.setAssertionReturnBundle(hexStringToUint8Array('00'), hexStringToUint8Array('01'), hexStringToUint8Array('02'), hexStringToUint8Array('03'));
 
         return navigator.credentials.get(options).then(function(credential) {
-            const clientDataJsonHash = '577cc24b64b3dd011c61a8efb240aee7e77acc3c144d6dfbe097c6a208bb6d49';
-
-            assert_equals(credential.id, 'V3zCS2Sz3QEcYajvskCu5-d6zDwUTW374JfGogi7bUk');
+            assert_equals(credential.id, 'AA');
             assert_equals(credential.type, 'public-key');
-            assert_equals(bytesToHexString(credential.rawId), clientDataJsonHash);
+            assert_equals(bytesToHexString(credential.rawId), '00');
             assert_equals(bytesToASCIIString(credential.response.clientDataJSON), '{"type":"webauthn.get","challenge":"MTIzNDU2","origin":"https://localhost:9443","hashAlgorithm":"SHA-256"}');
-            // This field is completely fake 0x00*43 | 0x0001ff | SHA-256 hash of the clientDataJSON
-            assert_equals(bytesToHexString(credential.response.authenticatorData), clientDataJsonHash);
-            assert_equals(bytesToHexString(credential.response.signature), clientDataJsonHash);
-            assert_equals(bytesToHexString(credential.response.userHandle), clientDataJsonHash);
+            assert_equals(bytesToHexString(credential.response.authenticatorData), '01');
+            assert_equals(bytesToHexString(credential.response.signature), '02');
+            assert_equals(bytesToHexString(credential.response.userHandle), '03');
             try {
                 assert_throws("NotSupportedError", credential.getClientExtensionResults());
             } catch(error) { }
index c075eb7..67ffe6c 100644 (file)
@@ -43,3 +43,19 @@ var Base64URL = {
         return new Uint8Array(Array.prototype.map.call(atob(s), function (c) { return c.charCodeAt(0) }));
     }
 };
+
+function hexStringToUint8Array(hexString)
+{
+    if (hexString.length % 2 != 0)
+        throw "Invalid hexString";
+    var arrayBuffer = new Uint8Array(hexString.length / 2);
+
+    for (var i = 0; i < hexString.length; i += 2) {
+        var byteValue = parseInt(hexString.substr(i, 2), 16);
+        if (byteValue == NaN)
+            throw "Invalid hexString";
+        arrayBuffer[i/2] = byteValue;
+    }
+
+    return arrayBuffer;
+}
index cc6403a..508b272 100644 (file)
@@ -1,15 +1,15 @@
 
 PASS navigator.credentials.create() with no argument. 
 PASS navigator.credentials.create() with empty argument. 
-FAIL navigator.credentials.create() with valid PasswordCredentialData promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL navigator.credentials.create() with valid HTMLFormElement promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL navigator.credentials.create() with bogus password data assert_throws: function "function () { throw e }" threw object "NotSupportedError: The operation is not supported." ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL navigator.credentials.create() with valid FederatedCredentialData promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
-FAIL navigator.credentials.create() with bogus federated data assert_throws: function "function () { throw e }" threw object "NotSupportedError: The operation is not supported." ("NotSupportedError") expected object "TypeError" ("TypeError")
+FAIL navigator.credentials.create() with valid PasswordCredentialData promise_test: Unhandled rejection with value: object "NotSupportedError: Only PublicKeyCredential is supported."
+FAIL navigator.credentials.create() with valid HTMLFormElement promise_test: Unhandled rejection with value: object "NotSupportedError: Only PublicKeyCredential is supported."
+FAIL navigator.credentials.create() with bogus password data assert_throws: function "function () { throw e }" threw object "NotSupportedError: Only PublicKeyCredential is supported." ("NotSupportedError") expected object "TypeError" ("TypeError")
+FAIL navigator.credentials.create() with valid FederatedCredentialData promise_test: Unhandled rejection with value: object "NotSupportedError: Only PublicKeyCredential is supported."
+FAIL navigator.credentials.create() with bogus federated data assert_throws: function "function () { throw e }" threw object "NotSupportedError: Only PublicKeyCredential is supported." ("NotSupportedError") expected object "TypeError" ("TypeError")
 PASS navigator.credentials.create() with bogus publicKey data 
 FAIL navigator.credentials.create() returns PublicKeyCredential promise_test: Unhandled rejection with value: object "TypeError: Member PublicKeyCredentialCreationOptions.pubKeyCredParams is required and must be an instance of sequence"
 PASS navigator.credentials.create() with both PasswordCredentialData and FederatedCredentialData 
-FAIL navigator.credentials.create() with bogus password and federated data assert_throws: function "function () { throw e }" threw object "NotSupportedError: The operation is not supported." ("NotSupportedError") expected object "TypeError" ("TypeError")
+FAIL navigator.credentials.create() with bogus password and federated data assert_throws: function "function () { throw e }" threw object "NotSupportedError: Only PublicKeyCredential is supported." ("NotSupportedError") expected object "TypeError" ("TypeError")
 PASS navigator.credentials.create() with bogus federated and publicKey data 
 PASS navigator.credentials.create() with bogus password and publicKey data 
 PASS navigator.credentials.create() with bogus password, federated, and publicKey data 
index b26185d..c084655 100644 (file)
@@ -1,3 +1,93 @@
+2018-02-13  Jiewen Tan  <jiewen_tan@apple.com>
+
+        [WebAuthN] Revisit the whole async model of task dispatching, timeout and aborting
+        https://bugs.webkit.org/show_bug.cgi?id=181946
+        <rdar://problem/37258262>
+
+        Reviewed by Chris Dumez.
+
+        This patch changes the original async model from a work queue to IPC between WebProcess
+        and UIProcess. Since all authenticator operations must be handled in the UIProcess due
+        to sandboxing, this message passing IPC async model then surpasses the original multi
+        threading model. To cooperate that, a CredentialsMessenger class is then created and
+        all task dispatching code is moved thre.
+
+        As an improvement over existing code, static functions from PublicKeyCredential are
+        moved to AuthenticatorManager. AuthenticatorManager is made as a singleton such that
+        when static functions are called, they could reach the CredentialsMessenger to interact
+        with UIProccess. CredentialsMessenger and AuthenticatorManager are separated so later
+        on when other Credential types are created, they can reuse the same IPC messenger.
+
+        What's more, a mock CredentialsMessenger is then created to mock behaviors of UIProcess
+        for testing purpose.
+
+        Covered by existing tests.
+
+        * DerivedSources.make:
+        * Modules/credentialmanagement/BasicCredential.h:
+        * Modules/credentialmanagement/CredentialsContainer.cpp:
+        (WebCore::CredentialsContainer::CredentialsContainer):
+        (WebCore::CredentialsContainer::doesHaveSameOriginAsItsAncestors):
+        (WebCore::CredentialsContainer::get):
+        (WebCore::CredentialsContainer::isCreate):
+        (WebCore::CredentialsContainer::PendingPromise::PendingPromise): Deleted.
+        (WebCore::CredentialsContainer::dispatchTask): Deleted.
+        * Modules/credentialmanagement/CredentialsContainer.h:
+        (WebCore::CredentialsContainer::PendingPromise::create): Deleted.
+        * Modules/credentialmanagement/CredentialsMessenger.cpp: Added.
+        (WebCore::CredentialsMessenger::exceptionReply):
+        (WebCore::CredentialsMessenger::addCreationCompletionHandler):
+        (WebCore::CredentialsMessenger::takeCreationCompletionHandler):
+        (WebCore::CredentialsMessenger::addRequestCompletionHandler):
+        (WebCore::CredentialsMessenger::takeRequestCompletionHandler):
+        (WebCore::CredentialsMessenger::addQueryCompletionHandler):
+        (WebCore::CredentialsMessenger::takeQueryCompletionHandler):
+        (WebCore::getIdFromAttestationObject):
+        * Modules/credentialmanagement/CredentialsMessenger.h: Added.
+        (WebCore::CreationReturnBundle::CreationReturnBundle):
+        (WebCore::AssertionReturnBundle::AssertionReturnBundle):
+        (WebCore::CredentialsMessenger::weakPtrFactory const):
+        * Modules/webauthn/Authenticator.cpp: Removed.
+        * Modules/webauthn/Authenticator.h: Removed.
+        * Modules/webauthn/AuthenticatorManager.cpp: Copied from Source/WebCore/Modules/webauthn/PublicKeyCredential.cpp.
+        (WebCore::AuthenticatorManagerInternal::produceClientDataJson):
+        (WebCore::AuthenticatorManagerInternal::produceClientDataJsonHash):
+        (WebCore::AuthenticatorManagerInternal::initTimer):
+        (WebCore::AuthenticatorManagerInternal::didTimerFire):
+        (WebCore::AuthenticatorManager::singleton):
+        (WebCore::AuthenticatorManager::setMessenger):
+        (WebCore::AuthenticatorManager::create const):
+        (WebCore::AuthenticatorManager::discoverFromExternalSource const):
+        * Modules/webauthn/AuthenticatorManager.h: Copied from Source/WebCore/Modules/webauthn/AuthenticatorResponse.h.
+        * Modules/webauthn/AuthenticatorResponse.h:
+        * Modules/webauthn/PublicKeyCredential.cpp:
+        (WebCore::PublicKeyCredentialInternal::produceClientDataJson): Deleted.
+        (WebCore::PublicKeyCredentialInternal::produceClientDataJsonHash): Deleted.
+        (WebCore::PublicKeyCredentialInternal::getIdFromAttestationObject): Deleted.
+        (WebCore::PublicKeyCredential::collectFromCredentialStore): Deleted.
+        (WebCore::PublicKeyCredential::discoverFromExternalSource): Deleted.
+        (WebCore::PublicKeyCredential::store): Deleted.
+        (WebCore::PublicKeyCredential::create): Deleted.
+        (WebCore::PublicKeyCredential::rawId const): Deleted.
+        (WebCore::PublicKeyCredential::response const): Deleted.
+        * Modules/webauthn/PublicKeyCredential.h:
+        * Sources.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        * testing/Internals.cpp:
+        (WebCore::Internals::Internals):
+        (WebCore::Internals::mockCredentialsMessenger const):
+        * testing/Internals.h:
+        * testing/Internals.idl:
+        * testing/MockCredentialsMessenger.cpp: Added.
+        (WebCore::MockCredentialsMessenger::setAttestationObject):
+        (WebCore::MockCredentialsMessenger::setAssertionReturnBundle):
+        (WebCore::MockCredentialsMessenger::makeCredential):
+        (WebCore::MockCredentialsMessenger::getAssertion):
+        (WebCore::MockCredentialsMessenger::makeCredentialReply):
+        (WebCore::MockCredentialsMessenger::getAssertionReply):
+        * testing/MockCredentialsMessenger.h: Copied from Source/WebCore/Modules/webauthn/AuthenticatorResponse.h.
+        * testing/MockCredentialsMessenger.idl: Copied from Source/WebCore/Modules/webauthn/AuthenticatorResponse.h.
+
 2018-02-13  Zalan Bujtas  <zalan@apple.com>
 
         [RenderTreeBuilder] Move RenderBlock::takeChild() to RenderTreeBuilder
index 1ab6ef9..b62629c 100644 (file)
@@ -947,6 +947,7 @@ JS_BINDING_IDLS = \
     $(WebCore)/testing/MemoryInfo.idl \
     $(WebCore)/testing/MockCDMFactory.idl \
     $(WebCore)/testing/MockContentFilterSettings.idl \
+    $(WebCore)/testing/MockCredentialsMessenger.idl \
     $(WebCore)/testing/MockPageOverlay.idl \
     $(WebCore)/testing/MockPaymentAddress.idl \
     $(WebCore)/testing/MockPaymentCoordinator.idl \
index b2fe271..3b8f142 100644 (file)
 
 #if ENABLE(WEB_AUTHN)
 
-#include <wtf/ThreadSafeRefCounted.h>
+#include <wtf/RefCounted.h>
 #include <wtf/TypeCasts.h>
 #include <wtf/text/WTFString.h>
 
 namespace WebCore {
 
-class BasicCredential : public ThreadSafeRefCounted<BasicCredential> {
+class BasicCredential : public RefCounted<BasicCredential> {
 public:
     enum class Type {
         PublicKey,
index a25b1f1..fb7d441 100644 (file)
 #if ENABLE(WEB_AUTHN)
 
 #include "AbortSignal.h"
+#include "AuthenticatorManager.h"
 #include "CredentialCreationOptions.h"
 #include "CredentialRequestOptions.h"
 #include "Document.h"
 #include "ExceptionOr.h"
-#include "JSBasicCredential.h"
-#include "PublicKeyCredential.h"
+#include "JSDOMPromiseDeferred.h"
 #include "SecurityOrigin.h"
-#include <wtf/MainThread.h>
 
 namespace WebCore {
 
-CredentialsContainer::PendingPromise::PendingPromise(Ref<DeferredPromise>&& promise, std::unique_ptr<Timer>&& timer)
-    : promise(WTFMove(promise))
-    , timer(WTFMove(timer))
-{
-}
-
-CredentialsContainer::PendingPromise::PendingPromise(Ref<DeferredPromise>&& promise)
-    : promise(WTFMove(promise))
-{
-}
-
 CredentialsContainer::CredentialsContainer(WeakPtr<Document>&& document)
     : m_document(WTFMove(document))
-    , m_workQueue(WorkQueue::create("com.apple.WebKit.CredentialQueue"))
 {
 }
 
-// The following implements https://w3c.github.io/webappsec-credential-management/#same-origin-with-its-ancestors
-// as of 14 November 2017.
 bool CredentialsContainer::doesHaveSameOriginAsItsAncestors()
 {
+    // The following implements https://w3c.github.io/webappsec-credential-management/#same-origin-with-its-ancestors
+    // as of 14 November 2017.
     if (!m_document)
         return false;
 
@@ -73,62 +60,16 @@ bool CredentialsContainer::doesHaveSameOriginAsItsAncestors()
     return true;
 }
 
-// FIXME(181946): Since the underlying authenticator model is not clear at this moment, the timer is moved to CredentialsContainer such that
-// timer can stay with main thread and therefore can easily time out activities on the work queue.
-// FIXME(181945): The usages of AbortSignal are also moved here for the very same reason. Also the AbortSignal is kind of bogus at this moment
-// since it doesn't support observers (or other means) to trigger the actual abort action. Enhancement to AbortSignal is needed.
-template<typename OperationType>
-void CredentialsContainer::dispatchTask(OperationType&& operation, Ref<DeferredPromise>&& promise, std::optional<unsigned long> timeOutInMs)
-{
-    ASSERT(isMainThread());
-    if (!m_document)
-        return;
-
-    auto* promiseIndex = promise.ptr();
-    auto weakThis = m_weakPtrFactory.createWeakPtr(*this);
-    // FIXME(181947): We should probably trim timeOutInMs to some max allowable number.
-    if (timeOutInMs) {
-        auto pendingPromise = PendingPromise::create(WTFMove(promise), std::make_unique<Timer>([promiseIndex, weakThis] () {
-            ASSERT(isMainThread());
-            if (weakThis) {
-                // A lock should not be needed as all callbacks are executed in the main thread.
-                if (auto promise = weakThis->m_pendingPromises.take(promiseIndex))
-                    promise.value()->promise->reject(Exception { NotAllowedError });
-            }
-        }));
-        pendingPromise->timer->startOneShot(Seconds(timeOutInMs.value() / 1000.0));
-        m_pendingPromises.add(promiseIndex, WTFMove(pendingPromise));
-    } else
-        m_pendingPromises.add(promiseIndex, PendingPromise::create(WTFMove(promise)));
-
-    auto task = [promiseIndex, weakThis, origin = m_document->securityOrigin().isolatedCopy(), isSameOriginWithItsAncestors = doesHaveSameOriginAsItsAncestors(), operation = WTFMove(operation)] () {
-        auto result = operation(origin, isSameOriginWithItsAncestors);
-        callOnMainThread([promiseIndex, weakThis, result = WTFMove(result)] () mutable {
-            if (weakThis) {
-                // A lock should not be needed as all callbacks are executed in the main thread.
-                if (auto promise = weakThis->m_pendingPromises.take(promiseIndex)) {
-                    if (result.hasException())
-                        promise.value()->promise->reject(result.releaseException());
-                    else
-                        promise.value()->promise->resolve<IDLNullable<IDLInterface<BasicCredential>>>(result.returnValue().get());
-                }
-            }
-        });
-    };
-    m_workQueue->dispatch(WTFMove(task));
-}
-
 void CredentialsContainer::get(CredentialRequestOptions&& options, Ref<DeferredPromise>&& promise)
 {
     // The following implements https://www.w3.org/TR/credential-management-1/#algorithm-request as of 4 August 2017
     // with enhancement from 14 November 2017 Editor's Draft.
-    // FIXME: Optional options are passed with no contents. It should be std::optional.
-    if ((!options.signal && !options.publicKey) || !m_document) {
+    if (!m_document) {
         promise->reject(Exception { NotSupportedError });
         return;
     }
     if (options.signal && options.signal->aborted()) {
-        promise->reject(Exception { AbortError });
+        promise->reject(Exception { AbortError, ASCIILiteral("Aborted by AbortSignal.") });
         return;
     }
     // Step 1-2.
@@ -138,56 +79,47 @@ void CredentialsContainer::get(CredentialRequestOptions&& options, Ref<DeferredP
     // Step 4-6. Shortcut as we only support PublicKeyCredential which can only
     // be requested from [[discoverFromExternalSource]].
     if (!options.publicKey) {
-        promise->reject(Exception { NotSupportedError });
+        promise->reject(Exception { NotSupportedError, ASCIILiteral("Only PublicKeyCredential is supported.") });
         return;
     }
 
-    auto timeout = options.publicKey->timeout;
-    auto operation = [options = WTFMove(options.publicKey.value())] (const SecurityOrigin& origin, bool isSameOriginWithItsAncestors) {
-        return PublicKeyCredential::discoverFromExternalSource(origin, options, isSameOriginWithItsAncestors);
-    };
-    dispatchTask(WTFMove(operation), WTFMove(promise), timeout);
+    // Async operations are dispatched/handled in (Web)CredentialMessenger, which exchanges messages between WebProcess and UIProcess.
+    AuthenticatorManager::singleton().discoverFromExternalSource(m_document->securityOrigin(), options.publicKey.value(), doesHaveSameOriginAsItsAncestors(), WTFMove(options.signal), WTFMove(promise));
 }
 
 void CredentialsContainer::store(const BasicCredential&, Ref<DeferredPromise>&& promise)
 {
-    promise->reject(Exception { NotSupportedError });
+    promise->reject(Exception { NotSupportedError, ASCIILiteral("Not implemented.") });
 }
 
 void CredentialsContainer::isCreate(CredentialCreationOptions&& options, Ref<DeferredPromise>&& promise)
 {
     // The following implements https://www.w3.org/TR/credential-management-1/#algorithm-create as of 4 August 2017
     // with enhancement from 14 November 2017 Editor's Draft.
-    // FIXME: Optional options are passed with no contents. It should be std::optional.
-    if ((!options.signal && !options.publicKey) || !m_document) {
+    if (!m_document) {
         promise->reject(Exception { NotSupportedError });
         return;
     }
     if (options.signal && options.signal->aborted()) {
-        promise->reject(Exception { AbortError });
+        promise->reject(Exception { AbortError, ASCIILiteral("Aborted by AbortSignal.") });
         return;
     }
     // Step 1-2.
     ASSERT(m_document->isSecureContext());
 
-    // Step 3-4. Shortcut as we only support one kind of credentials.
+    // Step 3-7. Shortcut as we only support one kind of credentials.
     if (!options.publicKey) {
-        promise->reject(Exception { NotSupportedError });
+        promise->reject(Exception { NotSupportedError, ASCIILiteral("Only PublicKeyCredential is supported.") });
         return;
     }
 
-    auto timeout = options.publicKey->timeout;
-    // Step 5-7.
-    auto operation = [options = WTFMove(options.publicKey.value())] (const SecurityOrigin& origin, bool isSameOriginWithItsAncestors) {
-        // Shortcut as well.
-        return PublicKeyCredential::create(origin, options, isSameOriginWithItsAncestors);
-    };
-    dispatchTask(WTFMove(operation), WTFMove(promise), timeout);
+    // Async operations are dispatched/handled in (Web)CredentialMessenger, which exchanges messages between WebProcess and UIProcess.
+    AuthenticatorManager::singleton().create(m_document->securityOrigin(), options.publicKey.value(), doesHaveSameOriginAsItsAncestors(), WTFMove(options.signal), WTFMove(promise));
 }
 
 void CredentialsContainer::preventSilentAccess(Ref<DeferredPromise>&& promise) const
 {
-    promise->reject(Exception { NotSupportedError });
+    promise->reject(Exception { NotSupportedError, ASCIILiteral("Not implemented.") });
 }
 
 } // namespace WebCore
index 3bf2386..07607e3 100644 (file)
 
 #if ENABLE(WEB_AUTHN)
 
-#include "JSDOMPromiseDeferred.h"
-#include "Timer.h"
-#include <wtf/Function.h>
 #include <wtf/RefCounted.h>
 #include <wtf/WeakPtr.h>
-#include <wtf/WorkQueue.h>
 
 namespace WebCore {
 
 class BasicCredential;
+class DeferredPromise;
 class Document;
 
 struct CredentialCreationOptions;
@@ -59,34 +56,8 @@ private:
     CredentialsContainer(WeakPtr<Document>&&);
 
     bool doesHaveSameOriginAsItsAncestors();
-    template<typename OperationType>
-    void dispatchTask(OperationType&&, Ref<DeferredPromise>&&, std::optional<unsigned long> timeOutInMs = std::nullopt);
 
     WeakPtr<Document> m_document;
-    Ref<WorkQueue> m_workQueue;
-    WeakPtrFactory<CredentialsContainer> m_weakPtrFactory;
-
-    // Bundle promise and timer, such that the timer can
-    // times out the corresponding promsie.
-    struct PendingPromise : public RefCounted<PendingPromise> {
-        static Ref<PendingPromise> create(Ref<DeferredPromise>&& promise, std::unique_ptr<Timer>&& timer)
-        {
-            return adoptRef(*new PendingPromise(WTFMove(promise), WTFMove(timer)));
-        }
-        static Ref<PendingPromise> create(Ref<DeferredPromise>&& promise)
-        {
-            return adoptRef(*new PendingPromise(WTFMove(promise)));
-        }
-
-    private:
-        PendingPromise(Ref<DeferredPromise>&&, std::unique_ptr<Timer>&&);
-        PendingPromise(Ref<DeferredPromise>&&);
-
-    public:
-        Ref<DeferredPromise> promise;
-        std::unique_ptr<Timer> timer;
-    };
-    HashMap<DeferredPromise*, Ref<PendingPromise>> m_pendingPromises;
 };
 
 } // namespace WebCore
diff --git a/Source/WebCore/Modules/credentialmanagement/CredentialsMessenger.cpp b/Source/WebCore/Modules/credentialmanagement/CredentialsMessenger.cpp
new file mode 100644 (file)
index 0000000..d76ed36
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "CredentialsMessenger.h"
+
+#if ENABLE(WEB_AUTHN)
+
+namespace WebCore {
+
+namespace CredentialsMessengerInternal {
+
+const uint64_t maxMessageId = 0xFFFFFFFFFFFFFF; // 56 bits
+const size_t callBackClassifierOffset = 56;
+
+// The layout of attestation object: https://www.w3.org/TR/webauthn/#attestation-object as of 5 December 2017.
+// Here is a summary before CredentialID in the layout. All lengths are fixed.
+// RP ID hash (32) || FLAGS (1) || COUNTER (4) || AAGUID (16) || L (2) || CREDENTIAL ID (?) || ...
+const size_t credentialIdLengthOffset = 43;
+const size_t credentialIdLengthLength = 2;
+
+}
+
+void CredentialsMessenger::exceptionReply(uint64_t messageId, const ExceptionData& exception)
+{
+    using namespace CredentialsMessengerInternal;
+
+    if (!(messageId >> callBackClassifierOffset ^ CallBackClassifier::Creation)) {
+        auto handler = takeCreationCompletionHandler(messageId);
+        handler(exception.toException());
+        return;
+    }
+    if (!(messageId >> callBackClassifierOffset ^ CallBackClassifier::Request)) {
+        auto handler = takeRequestCompletionHandler(messageId);
+        handler(exception.toException());
+        return;
+    }
+}
+
+uint64_t CredentialsMessenger::addCreationCompletionHandler(CreationCompletionHandler&& handler)
+{
+    using namespace CredentialsMessengerInternal;
+
+    uint64_t messageId = m_accumulatedMessageId++;
+    ASSERT(messageId <= maxMessageId);
+    messageId = messageId | CallBackClassifier::Creation << callBackClassifierOffset;
+    auto addResult = m_pendingCreationCompletionHandlers.add(messageId, WTFMove(handler));
+    ASSERT_UNUSED(addResult, addResult.isNewEntry);
+    ASSERT(addResult);
+    return messageId;
+}
+
+CreationCompletionHandler CredentialsMessenger::takeCreationCompletionHandler(uint64_t messageId)
+{
+    return m_pendingCreationCompletionHandlers.take(messageId);
+}
+
+uint64_t CredentialsMessenger::addRequestCompletionHandler(RequestCompletionHandler&& handler)
+{
+    using namespace CredentialsMessengerInternal;
+
+    uint64_t messageId = m_accumulatedMessageId++;
+    ASSERT(messageId <= maxMessageId);
+    messageId = messageId | CallBackClassifier::Request << callBackClassifierOffset;
+    auto addResult = m_pendingRequestCompletionHandlers.add(messageId, WTFMove(handler));
+    ASSERT_UNUSED(addResult, addResult.isNewEntry);
+    ASSERT(addResult);
+    return messageId;
+}
+
+RequestCompletionHandler CredentialsMessenger::takeRequestCompletionHandler(uint64_t messageId)
+{
+    return m_pendingRequestCompletionHandlers.take(messageId);
+}
+
+RefPtr<ArrayBuffer> getIdFromAttestationObject(const Vector<uint8_t>& attestationObject)
+{
+    using namespace CredentialsMessengerInternal;
+
+    if (attestationObject.size() < credentialIdLengthOffset + credentialIdLengthLength)
+        return nullptr;
+    // The byte length of L is 2.
+    size_t length = (attestationObject[credentialIdLengthOffset] << 8) + attestationObject[credentialIdLengthOffset + 1];
+    if (attestationObject.size() < credentialIdLengthOffset + credentialIdLengthLength + length)
+        return nullptr;
+    return ArrayBuffer::create(attestationObject.data() + credentialIdLengthOffset + credentialIdLengthLength, length);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUTHN)
diff --git a/Source/WebCore/Modules/credentialmanagement/CredentialsMessenger.h b/Source/WebCore/Modules/credentialmanagement/CredentialsMessenger.h
new file mode 100644 (file)
index 0000000..927b67a
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(WEB_AUTHN)
+
+#include "ExceptionData.h"
+#include "ExceptionOr.h"
+#include <JavaScriptCore/ArrayBuffer.h>
+#include <wtf/CompletionHandler.h>
+#include <wtf/HashMap.h>
+#include <wtf/WeakPtr.h>
+
+namespace WebCore {
+
+class DeferredPromise;
+
+struct PublicKeyCredentialCreationOptions;
+struct PublicKeyCredentialRequestOptions;
+
+struct CreationReturnBundle {
+    CreationReturnBundle(Ref<ArrayBuffer>&& credentialId, Ref<ArrayBuffer>&& attestationObject)
+        : credentialId(WTFMove(credentialId))
+        , attestationObject(WTFMove(attestationObject))
+    {
+    }
+
+    Ref<ArrayBuffer> credentialId;
+    Ref<ArrayBuffer> attestationObject;
+};
+struct AssertionReturnBundle {
+    AssertionReturnBundle(Ref<ArrayBuffer>&& credentialId, Ref<ArrayBuffer>&& authenticatorData, Ref<ArrayBuffer>&& signature, Ref<ArrayBuffer>&& userHandle)
+        : credentialId(WTFMove(credentialId))
+        , authenticatorData(WTFMove(authenticatorData))
+        , signature(WTFMove(signature))
+        , userHandle(WTFMove(userHandle))
+    {
+    }
+
+    Ref<ArrayBuffer> credentialId;
+    Ref<ArrayBuffer> authenticatorData;
+    Ref<ArrayBuffer> signature;
+    Ref<ArrayBuffer> userHandle;
+};
+
+using CreationCompletionHandler = CompletionHandler<void(ExceptionOr<CreationReturnBundle>&&)>;
+using RequestCompletionHandler = CompletionHandler<void(ExceptionOr<AssertionReturnBundle>&&)>;
+
+class CredentialsMessenger {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    // sender
+    virtual void makeCredential(const Vector<uint8_t>& hash, const PublicKeyCredentialCreationOptions&, CreationCompletionHandler&&) = 0;
+    virtual void getAssertion(const Vector<uint8_t>& hash, const PublicKeyCredentialRequestOptions&, RequestCompletionHandler&&) = 0;
+
+    // receiver
+    WEBCORE_EXPORT void exceptionReply(uint64_t messageId, const ExceptionData&);
+    virtual void makeCredentialReply(uint64_t messageId, const Vector<uint8_t>&) = 0;
+    virtual void getAssertionReply(uint64_t messageId, const Vector<uint8_t>& credentialId, const Vector<uint8_t>& authenticatorData, const Vector<uint8_t>& signature, const Vector<uint8_t>& userHandle) = 0;
+
+    auto& weakPtrFactory() const { return m_weakFactory; }
+
+protected:
+    virtual ~CredentialsMessenger() = default;
+
+    WEBCORE_EXPORT uint64_t addCreationCompletionHandler(CreationCompletionHandler&&);
+    WEBCORE_EXPORT CreationCompletionHandler takeCreationCompletionHandler(uint64_t);
+    WEBCORE_EXPORT uint64_t addRequestCompletionHandler(RequestCompletionHandler&&);
+    WEBCORE_EXPORT RequestCompletionHandler takeRequestCompletionHandler(uint64_t);
+
+private:
+    WeakPtrFactory<CredentialsMessenger> m_weakFactory;
+
+    enum CallBackClassifier : uint64_t {
+        Creation = 0x01,
+        Request = 0x02,
+        Query = 0x03,
+    };
+    // The most significant byte is reserved as callback classifier.
+    uint64_t m_accumulatedMessageId { 1 };
+    HashMap<uint64_t, CreationCompletionHandler> m_pendingCreationCompletionHandlers;
+    HashMap<uint64_t, RequestCompletionHandler> m_pendingRequestCompletionHandlers;
+};
+
+// FIXME: We shouldn't expose this into the messenger. Since the receivers can only be passed with const references, we couldn't
+// construct an ExceptionOr wrapper and pass it to AuthenticatorManager's callback.
+WEBCORE_EXPORT RefPtr<ArrayBuffer> getIdFromAttestationObject(const Vector<uint8_t>& attestationObject);
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUTHN)
diff --git a/Source/WebCore/Modules/webauthn/Authenticator.cpp b/Source/WebCore/Modules/webauthn/Authenticator.cpp
deleted file mode 100644 (file)
index 253e3a2..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2018 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "Authenticator.h"
-
-#if ENABLE(WEB_AUTHN)
-
-#include <AuthenticatorAttestationResponse.h>
-#include <wtf/CurrentTime.h>
-#include <wtf/NeverDestroyed.h>
-
-namespace WebCore {
-
-Authenticator& Authenticator::singleton()
-{
-    static NeverDestroyed<Authenticator> authenticator;
-    return authenticator;
-}
-
-ExceptionOr<Vector<uint8_t>> Authenticator::makeCredential(const Vector<uint8_t>& hash, const PublicKeyCredentialCreationOptions::RpEntity&, const PublicKeyCredentialCreationOptions::UserEntity& user, const Vector<PublicKeyCredentialCreationOptions::Parameters>&, const Vector<PublicKeyCredentialDescriptor>&) const
-{
-    // The followings is just a dummy implementaion to support initial development.
-    // User cancellation is effecively NotAllowedError.
-    if (user.displayName == "John")
-        return Exception { NotAllowedError };
-
-    // Fill all parts before CredentialID with 0x00
-    Vector<uint8_t> attestationObject(43, 0x00);
-    // Fill length of CredentialID: 1 Byte
-    attestationObject.append(0x00);
-    attestationObject.append(0x01);
-    // Fill CredentialID: 255
-    attestationObject.append(0xff);
-    // Append clientDataJsonHash
-    attestationObject.appendVector(hash);
-    return WTFMove(attestationObject);
-}
-
-ExceptionOr<Authenticator::AssertionReturnBundle> Authenticator::getAssertion(const String&, const Vector<uint8_t>& hash, const Vector<PublicKeyCredentialDescriptor>& allowCredentialIds) const
-{
-    // The followings is just a dummy implementaion to support initial development.
-    // User cancellation is effecively NotAllowedError.
-    if (!allowCredentialIds.isEmpty())
-        return Exception { NotAllowedError };
-
-    // FIXME: Delay processing for 0.1 seconds to simulate a timeout condition. This code will be removed
-    // when the full test infrastructure is set up.
-    WTF::sleep(0.1);
-
-    // Fill all parts with hash
-    return AssertionReturnBundle(ArrayBuffer::create(hash.data(), hash.size()), ArrayBuffer::create(hash.data(), hash.size()), ArrayBuffer::create(hash.data(), hash.size()), ArrayBuffer::create(hash.data(), hash.size()));
-}
-
-} // namespace WebCore
-
-#endif // ENABLE(WEB_AUTHN)
diff --git a/Source/WebCore/Modules/webauthn/Authenticator.h b/Source/WebCore/Modules/webauthn/Authenticator.h
deleted file mode 100644 (file)
index 8ae6b62..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2018 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#if ENABLE(WEB_AUTHN)
-
-#include "ExceptionOr.h"
-#include "PublicKeyCredentialCreationOptions.h"
-#include <wtf/Forward.h>
-#include <wtf/Noncopyable.h>
-
-namespace WebCore {
-
-// FIXME(181946): Consider moving all static methods from PublicKeyCredential to here and making this
-// as an authenticator manager that controls all authenticator activities, mostly likely asnyc
-// for attestations.
-class Authenticator {
-    WTF_MAKE_NONCOPYABLE(Authenticator);
-    friend class NeverDestroyed<Authenticator>;
-public:
-    // FIXME(181946): After moving all static methods from PublicKeyCredential to here, we will probably
-    // return PublicKeyCredential directly and get rid of the following return type.
-    struct AssertionReturnBundle {
-        AssertionReturnBundle(Ref<ArrayBuffer>&& id, Ref<ArrayBuffer>&& data, Ref<ArrayBuffer>&& sig, Ref<ArrayBuffer>&& handle)
-            : credentialID(WTFMove(id))
-            , authenticatorData(WTFMove(data))
-            , signature(WTFMove(sig))
-            , userHandle(WTFMove(handle))
-        {
-        }
-
-        Ref<ArrayBuffer> credentialID;
-        Ref<ArrayBuffer> authenticatorData;
-        Ref<ArrayBuffer> signature;
-        Ref<ArrayBuffer> userHandle;
-    };
-
-    static Authenticator& singleton();
-
-    // Omit requireResidentKey, requireUserPresence, and requireUserVerification as we always provide resident keys and require user verification.
-    ExceptionOr<Vector<uint8_t>> makeCredential(const Vector<uint8_t>& hash, const PublicKeyCredentialCreationOptions::RpEntity&, const PublicKeyCredentialCreationOptions::UserEntity&, const Vector<PublicKeyCredentialCreationOptions::Parameters>&, const Vector<PublicKeyCredentialDescriptor>& excludeCredentialIds) const;
-    ExceptionOr<AssertionReturnBundle> getAssertion(const String& rpId, const Vector<uint8_t>& hash, const Vector<PublicKeyCredentialDescriptor>& allowCredentialIds) const;
-
-private:
-    Authenticator() = default;
-};
-
-} // namespace WebCore
-
-#endif // ENABLE(WEB_AUTHN)
diff --git a/Source/WebCore/Modules/webauthn/AuthenticatorManager.cpp b/Source/WebCore/Modules/webauthn/AuthenticatorManager.cpp
new file mode 100644 (file)
index 0000000..c7fb14f
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "AuthenticatorManager.h"
+
+#if ENABLE(WEB_AUTHN)
+
+#include "AbortSignal.h"
+#include "AuthenticatorAssertionResponse.h"
+#include "AuthenticatorAttestationResponse.h"
+#include "CredentialsMessenger.h"
+#include "JSBasicCredential.h"
+#include "JSDOMPromiseDeferred.h"
+#include "PublicKeyCredential.h"
+#include "PublicKeyCredentialCreationOptions.h"
+#include "PublicKeyCredentialRequestOptions.h"
+#include "SecurityOrigin.h"
+#include "Timer.h"
+#include <pal/crypto/CryptoDigest.h>
+#include <wtf/JSONValues.h>
+#include <wtf/NeverDestroyed.h>
+#include <wtf/text/Base64.h>
+
+namespace WebCore {
+
+namespace AuthenticatorManagerInternal {
+
+enum class ClientDataType {
+    Create,
+    Get
+};
+
+// FIXME(181948): Add token binding ID and extensions.
+static Ref<ArrayBuffer> produceClientDataJson(ClientDataType type, const BufferSource& challenge, const SecurityOrigin& origin)
+{
+    auto object = JSON::Object::create();
+    switch (type) {
+    case ClientDataType::Create:
+        object->setString(ASCIILiteral("type"), ASCIILiteral("webauthn.create"));
+        break;
+    case ClientDataType::Get:
+        object->setString(ASCIILiteral("type"), ASCIILiteral("webauthn.get"));
+        break;
+    }
+    object->setString(ASCIILiteral("challenge"), WTF::base64URLEncode(challenge.data(), challenge.length()));
+    object->setString(ASCIILiteral("origin"), origin.toRawString());
+    // FIXME: This might be platform dependent.
+    object->setString(ASCIILiteral("hashAlgorithm"), ASCIILiteral("SHA-256"));
+
+    auto utf8JSONString = object->toJSONString().utf8();
+    return ArrayBuffer::create(utf8JSONString.data(), utf8JSONString.length());
+}
+
+static Vector<uint8_t> produceClientDataJsonHash(const ArrayBuffer& clientDataJson)
+{
+    // FIXME: This might be platform dependent.
+    auto crypto = PAL::CryptoDigest::create(PAL::CryptoDigest::Algorithm::SHA_256);
+    crypto->addBytes(clientDataJson.data(), clientDataJson.byteLength());
+    return crypto->computeHash();
+}
+
+// FIXME(181947): We should probably trim timeOutInMs to some max allowable number.
+static std::unique_ptr<Timer> initTimeoutTimer(std::optional<unsigned long> timeOutInMs, const Ref<DeferredPromise>& promise)
+{
+    if (!timeOutInMs)
+        return nullptr;
+
+    auto timer = std::make_unique<Timer>([promise = promise.copyRef()] () {
+        promise->reject(Exception { NotAllowedError, ASCIILiteral("Operation timed out.") });
+    });
+    timer->startOneShot(Seconds::fromMilliseconds(*timeOutInMs));
+    return timer;
+}
+
+static bool didTimeoutTimerFire(Timer* timer)
+{
+    if (!timer)
+        return false;
+    if (!timer->isActive())
+        return true;
+    timer->stop();
+    return false;
+}
+
+} // namespace AuthenticatorManagerInternal
+
+AuthenticatorManager& AuthenticatorManager::singleton()
+{
+    ASSERT(isMainThread());
+    static NeverDestroyed<AuthenticatorManager> authenticator;
+    return authenticator;
+}
+
+void AuthenticatorManager::setMessenger(CredentialsMessenger& messenger)
+{
+    m_messenger = makeWeakPtr(messenger);
+}
+
+void AuthenticatorManager::create(const SecurityOrigin& callerOrigin, const PublicKeyCredentialCreationOptions& options, bool sameOriginWithAncestors, RefPtr<AbortSignal>&& abortSignal, Ref<DeferredPromise>&& promise) const
+{
+    using namespace AuthenticatorManagerInternal;
+
+    // The following implements https://www.w3.org/TR/webauthn/#createCredential as of 5 December 2017.
+    // FIXME: Extensions are not supported yet. Skip Step 11-12.
+    // Step 1, 3, 16 are handled by the caller.
+    // Step 2.
+    if (!sameOriginWithAncestors) {
+        promise->reject(Exception { NotAllowedError, ASCIILiteral("The origin of the document is not the same as its ancestors.") });
+        return;
+    }
+
+    // Step 4 & 17.
+    std::unique_ptr<Timer> timeoutTimer = initTimeoutTimer(options.timeout, promise);
+
+    // Step 5-7.
+    // FIXME(181950): We lack fundamental support from SecurityOrigin to determine if a host is a valid domain or not.
+    // Step 6 is therefore skipped. Also, we lack the support to determine whether a domain is a registrable
+    // domain suffix of another domain. Hence restrict the comparison to equal in Step 7.
+    if (!options.rp.id.isEmpty() && callerOrigin.host() != options.rp.id) {
+        promise->reject(Exception { SecurityError, ASCIILiteral("The origin of the document is not a registrable domain suffix of the provided RP ID.") });
+        return;
+    }
+    if (options.rp.id.isEmpty())
+        options.rp.id = callerOrigin.host();
+
+    // Step 8-10.
+    // Most of the jobs are done by bindings. However, we can't know if the JSValue of options.pubKeyCredParams
+    // is empty or not. Return NotSupportedError as long as it is empty.
+    if (options.pubKeyCredParams.isEmpty()) {
+        promise->reject(Exception { NotSupportedError, ASCIILiteral("No desired properties of the to be created credential are provided.") });
+        return;
+    }
+
+    // Step 13-15.
+    auto clientDataJson = produceClientDataJson(ClientDataType::Create, options.challenge, callerOrigin);
+    auto clientDataJsonHash = produceClientDataJsonHash(clientDataJson);
+
+    // Step 18-21.
+    // Only platform attachments will be supported at this stage. Assuming one authenticator per device.
+    // Also, resident keys, user verifications and direct attestation are enforced at this tage.
+    // For better performance, no filtering is done here regarding to options.excludeCredentials.
+    if (!m_messenger)  {
+        promise->reject(Exception { UnknownError, ASCIILiteral("Unknown internal error.") });
+        return;
+    }
+
+    auto completionHandler = [clientDataJson = WTFMove(clientDataJson), promise = WTFMove(promise), timeoutTimer = WTFMove(timeoutTimer), abortSignal = WTFMove(abortSignal)] (ExceptionOr<CreationReturnBundle>&& result) mutable {
+        if (didTimeoutTimerFire(timeoutTimer.get()))
+            return;
+        if (abortSignal && abortSignal->aborted()) {
+            promise->reject(Exception { AbortError, ASCIILiteral("Aborted by AbortSignal.") });
+            return;
+        }
+        if (result.hasException()) {
+            promise->reject(result.exception());
+            return;
+        }
+
+        auto bundle = result.releaseReturnValue();
+        promise->resolve<IDLNullable<IDLInterface<BasicCredential>>>(PublicKeyCredential::create(WTFMove(bundle.credentialId), AuthenticatorAttestationResponse::create(WTFMove(clientDataJson), ArrayBuffer::create(WTFMove(bundle.attestationObject)))).ptr());
+    };
+    // Async operations are dispatched and handled in the messenger.
+    m_messenger->makeCredential(clientDataJsonHash, options, WTFMove(completionHandler));
+}
+
+void AuthenticatorManager::discoverFromExternalSource(const SecurityOrigin& callerOrigin, const PublicKeyCredentialRequestOptions& options, bool sameOriginWithAncestors, RefPtr<AbortSignal>&& abortSignal, Ref<DeferredPromise>&& promise) const
+{
+    using namespace AuthenticatorManagerInternal;
+
+    // The following implements https://www.w3.org/TR/webauthn/#createCredential as of 5 December 2017.
+    // FIXME: Extensions are not supported yet. Skip Step 8-9.
+    // Step 1, 3, 13 are handled by the caller.
+    // Step 2.
+    if (!sameOriginWithAncestors) {
+        promise->reject(Exception { NotAllowedError, ASCIILiteral("The origin of the document is not the same as its ancestors.") });
+        return;
+    }
+
+    // Step 4 & 16.
+    std::unique_ptr<Timer> timeoutTimer = initTimeoutTimer(options.timeout, promise);
+
+    // Step 5-7.
+    // FIXME(181950): We lack fundamental support from SecurityOrigin to determine if a host is a valid domain or not.
+    // Step 6 is therefore skipped. Also, we lack the support to determine whether a domain is a registrable
+    // domain suffix of another domain. Hence restrict the comparison to equal in Step 7.
+    if (!options.rpId.isEmpty() && callerOrigin.host() != options.rpId) {
+        promise->reject(Exception { SecurityError, ASCIILiteral("The origin of the document is not a registrable domain suffix of the provided RP ID.") });
+        return;
+    }
+    if (options.rpId.isEmpty())
+        options.rpId = callerOrigin.host();
+
+    // Step 10-12.
+    auto clientDataJson = produceClientDataJson(ClientDataType::Get, options.challenge, callerOrigin);
+    auto clientDataJsonHash = produceClientDataJsonHash(clientDataJson);
+
+    // Step 14-15, 17-19.
+    // Only platform attachments will be supported at this stage. Assuming one authenticator per device.
+    // Also, resident keys, user verifications and direct attestation are enforced at this tage.
+    // For better performance, no filtering is done here regarding to options.allowCredentials.
+    if (!m_messenger)  {
+        promise->reject(Exception { UnknownError, ASCIILiteral("Unknown internal error.") });
+        return;
+    }
+
+    auto completionHandler = [clientDataJson = WTFMove(clientDataJson), promise = WTFMove(promise), timeoutTimer = WTFMove(timeoutTimer), abortSignal = WTFMove(abortSignal)] (ExceptionOr<AssertionReturnBundle>&& result) mutable {
+        if (didTimeoutTimerFire(timeoutTimer.get()))
+            return;
+        if (abortSignal && abortSignal->aborted()) {
+            promise->reject(Exception { AbortError, ASCIILiteral("Aborted by AbortSignal.") });
+            return;
+        }
+        if (result.hasException()) {
+            promise->reject(result.exception());
+            return;
+        }
+
+        auto bundle = result.releaseReturnValue();
+        promise->resolve<IDLNullable<IDLInterface<BasicCredential>>>(PublicKeyCredential::create(WTFMove(bundle.credentialId), AuthenticatorAssertionResponse::create(WTFMove(clientDataJson), WTFMove(bundle.authenticatorData), WTFMove(bundle.signature), WTFMove(bundle.userHandle))).ptr());
+    };
+    // Async operations are dispatched and handled in the messenger.
+    m_messenger->getAssertion(clientDataJsonHash, options, WTFMove(completionHandler));
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUTHN)
diff --git a/Source/WebCore/Modules/webauthn/AuthenticatorManager.h b/Source/WebCore/Modules/webauthn/AuthenticatorManager.h
new file mode 100644 (file)
index 0000000..1745734
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(WEB_AUTHN)
+
+#include <wtf/Forward.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/WeakPtr.h>
+
+namespace WebCore {
+
+class AbortSignal;
+class CredentialsMessenger;
+class DeferredPromise;
+class SecurityOrigin;
+
+struct PublicKeyCredentialCreationOptions;
+struct PublicKeyCredentialRequestOptions;
+
+class AuthenticatorManager {
+    WTF_MAKE_NONCOPYABLE(AuthenticatorManager);
+    friend class NeverDestroyed<AuthenticatorManager>;
+public:
+    WEBCORE_EXPORT static AuthenticatorManager& singleton();
+    WEBCORE_EXPORT void setMessenger(CredentialsMessenger&);
+
+    // The following methods implement static methods of PublicKeyCredential.
+    void create(const SecurityOrigin&, const PublicKeyCredentialCreationOptions&, bool sameOriginWithAncestors, RefPtr<AbortSignal>&&, Ref<DeferredPromise>&&) const;
+    void discoverFromExternalSource(const SecurityOrigin&, const PublicKeyCredentialRequestOptions&, bool sameOriginWithAncestors, RefPtr<AbortSignal>&&, Ref<DeferredPromise>&&) const;
+
+private:
+    AuthenticatorManager() = default;
+
+    WeakPtr<CredentialsMessenger> m_messenger;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUTHN)
index bfde2d7..5528c03 100644 (file)
 #if ENABLE(WEB_AUTHN)
 
 #include <JavaScriptCore/ArrayBuffer.h>
-#include <wtf/ThreadSafeRefCounted.h>
+#include <wtf/RefCounted.h>
 #include <wtf/TypeCasts.h>
 
 namespace WebCore {
 
-class AuthenticatorResponse : public ThreadSafeRefCounted<AuthenticatorResponse> {
+class AuthenticatorResponse : public RefCounted<AuthenticatorResponse> {
 public:
     enum class Type {
         Assertion,
index fc0a0a1..136e5f7 100644 (file)
 
 #if ENABLE(WEB_AUTHN)
 
-#include "Authenticator.h"
-#include "AuthenticatorResponse.h"
 #include "JSDOMPromiseDeferred.h"
-#include "PublicKeyCredentialCreationOptions.h"
-#include "PublicKeyCredentialRequestOptions.h"
-#include "SecurityOrigin.h"
-#include <pal/crypto/CryptoDigest.h>
-#include <wtf/CurrentTime.h>
-#include <wtf/JSONValues.h>
 #include <wtf/text/Base64.h>
 
 namespace WebCore {
 
-namespace PublicKeyCredentialInternal {
-
-// The layout of attestation object: https://www.w3.org/TR/webauthn/#attestation-object as of 5 December 2017.
-// Here is a summary before CredentialID in the layout. All lengths are fixed.
-// RP ID hash (32) || FLAGS (1) || COUNTER (4) || AAGUID (16) || L (2) || CREDENTIAL ID (?) || ...
-static constexpr size_t CredentialIdLengthOffset = 43;
-
-enum class ClientDataType {
-    Create,
-    Get
-};
-
-// FIXME(181948): Add token binding ID and extensions.
-static Ref<ArrayBuffer> produceClientDataJson(ClientDataType type, const BufferSource& challenge, const SecurityOrigin& origin)
-{
-    auto object = JSON::Object::create();
-    switch (type) {
-    case ClientDataType::Create:
-        object->setString(ASCIILiteral("type"), ASCIILiteral("webauthn.create"));
-        break;
-    case ClientDataType::Get:
-        object->setString(ASCIILiteral("type"), ASCIILiteral("webauthn.get"));
-        break;
-    }
-    object->setString(ASCIILiteral("challenge"), WTF::base64URLEncode(challenge.data(), challenge.length()));
-    object->setString(ASCIILiteral("origin"), origin.toRawString());
-    // FIXME: This might be platform dependent.
-    object->setString(ASCIILiteral("hashAlgorithm"), ASCIILiteral("SHA-256"));
-
-    auto utf8JSONString = object->toJSONString().utf8();
-    return ArrayBuffer::create(utf8JSONString.data(), utf8JSONString.length());
-}
-
-static Vector<uint8_t> produceClientDataJsonHash(const Ref<ArrayBuffer>& clientDataJson)
-{
-    auto crypto = PAL::CryptoDigest::create(PAL::CryptoDigest::Algorithm::SHA_256);
-    crypto->addBytes(clientDataJson->data(), clientDataJson->byteLength());
-    return crypto->computeHash();
-}
-
-static RefPtr<ArrayBuffer> getIdFromAttestationObject(const Vector<uint8_t>& attestationObject)
-{
-    // The byte length of L is 2.
-    if (attestationObject.size() < CredentialIdLengthOffset + 2)
-        return nullptr;
-    size_t length = (attestationObject[CredentialIdLengthOffset] << 8) + attestationObject[CredentialIdLengthOffset + 1];
-    if (attestationObject.size() < CredentialIdLengthOffset + 2 + length)
-        return nullptr;
-    return ArrayBuffer::create(attestationObject.data() + CredentialIdLengthOffset + 2, length);
-}
-
-} // namespace PublicKeyCredentialInternal
-
 PublicKeyCredential::PublicKeyCredential(RefPtr<ArrayBuffer>&& id, RefPtr<AuthenticatorResponse>&& response)
     : BasicCredential(WTF::base64URLEncode(id->data(), id->byteLength()), Type::PublicKey, Discovery::Remote)
     , m_rawId(WTFMove(id))
@@ -101,110 +40,6 @@ PublicKeyCredential::PublicKeyCredential(RefPtr<ArrayBuffer>&& id, RefPtr<Authen
 {
 }
 
-Vector<Ref<BasicCredential>> PublicKeyCredential::collectFromCredentialStore(PublicKeyCredentialRequestOptions&&, bool)
-{
-    return { };
-}
-
-ExceptionOr<RefPtr<BasicCredential>> PublicKeyCredential::discoverFromExternalSource(const SecurityOrigin& callerOrigin, const PublicKeyCredentialRequestOptions& options, bool sameOriginWithAncestors)
-{
-    using namespace PublicKeyCredentialInternal;
-
-    // The following implements https://www.w3.org/TR/webauthn/#createCredential as of 5 December 2017.
-    // FIXME: Extensions are not supported yet. Skip Step 8-9.
-    // Step 1, 3-4, 13, 16 are handled by the caller, including options sanitizing, timer and abort signal.
-    // Step 2.
-    if (!sameOriginWithAncestors)
-        return Exception { NotAllowedError };
-
-    // Step 5-7.
-    // FIXME(181950): We lack fundamental support from SecurityOrigin to determine if a host is a valid domain or not.
-    // Step 6 is therefore skipped. Also, we lack the support to determine whether a domain is a registrable
-    // domain suffix of another domain. Hence restrict the comparison to equal in Step 7.
-    if (!options.rpId.isEmpty() && !(callerOrigin.host() == options.rpId))
-        return Exception { SecurityError };
-    if (options.rpId.isEmpty())
-        options.rpId = callerOrigin.host();
-
-    // Step 10-12.
-    auto clientDataJson = produceClientDataJson(ClientDataType::Get, options.challenge, callerOrigin);
-    auto clientDataJsonHash = produceClientDataJsonHash(clientDataJson);
-
-    // Step 14-15, 17-19.
-    // Only platform attachments will be supported at this stage. Assuming one authenticator per device.
-    // Also, resident keys, user verifications and direct attestation are enforced at this tage.
-    // For better performance, no filtering is done here regarding to options.excludeCredentials.
-    // What's more, user cancellations effectively means NotAllowedError. Therefore, the below call
-    // will only returns either an exception or a PublicKeyCredential ref.
-    // FIXME(181946): The following operation might need to perform async.
-    auto result = Authenticator::singleton().getAssertion(options.rpId, clientDataJsonHash, options.allowCredentials);
-    if (result.hasException())
-        return result.releaseException();
-
-    auto bundle = result.releaseReturnValue();
-    return ExceptionOr<RefPtr<BasicCredential>>(PublicKeyCredential::create(WTFMove(bundle.credentialID), AuthenticatorAssertionResponse::create(WTFMove(clientDataJson), WTFMove(bundle.authenticatorData), WTFMove(bundle.signature), WTFMove(bundle.userHandle))));
-}
-
-RefPtr<BasicCredential> PublicKeyCredential::store(RefPtr<BasicCredential>&&, bool)
-{
-    return nullptr;
-}
-
-ExceptionOr<RefPtr<BasicCredential>> PublicKeyCredential::create(const SecurityOrigin& callerOrigin, const PublicKeyCredentialCreationOptions& options, bool sameOriginWithAncestors)
-{
-    using namespace PublicKeyCredentialInternal;
-
-    // The following implements https://www.w3.org/TR/webauthn/#createCredential as of 5 December 2017.
-    // FIXME: Extensions are not supported yet. Skip Step 11-12.
-    // Step 1, 3-4, 16-17 are handled by the caller, including options sanitizing, timer and abort signal.
-    // Step 2.
-    if (!sameOriginWithAncestors)
-        return Exception { NotAllowedError };
-
-    // Step 5-7.
-    // FIXME(181950): We lack fundamental support from SecurityOrigin to determine if a host is a valid domain or not.
-    // Step 6 is therefore skipped. Also, we lack the support to determine whether a domain is a registrable
-    // domain suffix of another domain. Hence restrict the comparison to equal in Step 7.
-    if (!options.rp.id.isEmpty() && !(callerOrigin.host() == options.rp.id))
-        return Exception { SecurityError };
-    if (options.rp.id.isEmpty())
-        options.rp.id = callerOrigin.host();
-
-    // Step 8-10.
-    // Most of the jobs are done by bindings. However, we can't know if the JSValue of options.pubKeyCredParams
-    // is empty or not. Return NotSupportedError as long as it is empty.
-    if (options.pubKeyCredParams.isEmpty())
-        return Exception { NotSupportedError };
-
-    // Step 13-15.
-    auto clientDataJson = produceClientDataJson(ClientDataType::Create, options.challenge, callerOrigin);
-    auto clientDataJsonHash = produceClientDataJsonHash(clientDataJson);
-
-    // Step 18-21.
-    // Only platform attachments will be supported at this stage. Assuming one authenticator per device.
-    // Also, resident keys, user verifications and direct attestation are enforced at this tage.
-    // For better performance, no filtering is done here regarding to options.excludeCredentials.
-    // What's more, user cancellations effectively means NotAllowedError. Therefore, the below call
-    // will only returns either an exception or a PublicKeyCredential ref.
-    // FIXME(181946): The following operation might need to perform async.
-    auto result = Authenticator::singleton().makeCredential(clientDataJsonHash, options.rp, options.user, options.pubKeyCredParams, options.excludeCredentials);
-    if (result.hasException())
-        return result.releaseException();
-
-    auto attestationObject = result.releaseReturnValue();
-    return ExceptionOr<RefPtr<BasicCredential>>(PublicKeyCredential::create(getIdFromAttestationObject(attestationObject), AuthenticatorAttestationResponse::create(WTFMove(clientDataJson), ArrayBuffer::create(attestationObject.data(), attestationObject.size()))));
-}
-
-ArrayBuffer* PublicKeyCredential::rawId() const
-{
-    return m_rawId.get();
-}
-
-AuthenticatorResponse* PublicKeyCredential::response() const
-{
-    return m_response.get();
-}
-
 ExceptionOr<bool> PublicKeyCredential::getClientExtensionResults() const
 {
     return Exception { NotSupportedError };
index 16beda8..033dd23 100644 (file)
@@ -36,10 +36,6 @@ namespace WebCore {
 
 class AuthenticatorResponse;
 class DeferredPromise;
-class SecurityOrigin;
-
-struct PublicKeyCredentialCreationOptions;
-struct PublicKeyCredentialRequestOptions;
 
 class PublicKeyCredential final : public BasicCredential {
 public:
@@ -48,13 +44,8 @@ public:
         return adoptRef(*new PublicKeyCredential(WTFMove(id), WTFMove(response)));
     }
 
-    static Vector<Ref<BasicCredential>> collectFromCredentialStore(PublicKeyCredentialRequestOptions&&, bool);
-    static ExceptionOr<RefPtr<BasicCredential>> discoverFromExternalSource(const SecurityOrigin&, const PublicKeyCredentialRequestOptions&, bool sameOriginWithAncestors);
-    static RefPtr<BasicCredential> store(RefPtr<BasicCredential>&&, bool);
-    static ExceptionOr<RefPtr<BasicCredential>> create(const SecurityOrigin&, const PublicKeyCredentialCreationOptions&, bool sameOriginWithAncestors);
-
-    ArrayBuffer* rawId() const;
-    AuthenticatorResponse* response() const;
+    ArrayBuffer* rawId() const { return m_rawId.get(); }
+    AuthenticatorResponse* response() const { return m_response.get(); }
     // Not support yet. Always throws.
     ExceptionOr<bool> getClientExtensionResults() const;
 
index b92085d..d02249d 100644 (file)
@@ -45,6 +45,7 @@ Modules/cache/WorkerGlobalScopeCaches.cpp
 
 Modules/credentialmanagement/BasicCredential.cpp
 Modules/credentialmanagement/CredentialsContainer.cpp
+Modules/credentialmanagement/CredentialsMessenger.cpp
 Modules/credentialmanagement/NavigatorCredentials.cpp
 
 Modules/entriesapi/ErrorCallback.cpp
@@ -244,9 +245,9 @@ Modules/webaudio/WaveShaperDSPKernel.cpp
 Modules/webaudio/WaveShaperNode.cpp
 Modules/webaudio/WaveShaperProcessor.cpp
 
-Modules/webauthn/Authenticator.cpp
 Modules/webauthn/AuthenticatorAssertionResponse.cpp
 Modules/webauthn/AuthenticatorAttestationResponse.cpp
+Modules/webauthn/AuthenticatorManager.cpp
 Modules/webauthn/AuthenticatorResponse.cpp
 Modules/webauthn/PublicKeyCredential.cpp
 Modules/webauthn/cbor/CBORReader.cpp
index 218f07f..25fdb7d 100644 (file)
                57303C222009AF0300355965 /* JSAuthenticatorAttestationResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 57303C212009AEF600355965 /* JSAuthenticatorAttestationResponse.h */; };
                57303C2C2009B4A800355965 /* AuthenticatorAssertionResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 57303C272009B2FC00355965 /* AuthenticatorAssertionResponse.h */; };
                57303C2F2009B7E100355965 /* JSAuthenticatorAssertionResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 57303C2D2009B7D900355965 /* JSAuthenticatorAssertionResponse.h */; };
-               57303C4620105D2F00355965 /* Authenticator.h in Headers */ = {isa = PBXBuildFile; fileRef = 57303C4320105B3D00355965 /* Authenticator.h */; };
+               57303C4620105D2F00355965 /* AuthenticatorManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 57303C4320105B3D00355965 /* AuthenticatorManager.h */; settings = {ATTRIBUTES = (Private, ); }; };
                573489391DAC6B6E00DC0667 /* CryptoAlgorithmParameters.h in Headers */ = {isa = PBXBuildFile; fileRef = 573489381DAC6B6D00DC0667 /* CryptoAlgorithmParameters.h */; };
                5739E12F1DAC7F7800E14383 /* JSCryptoAlgorithmParameters.h in Headers */ = {isa = PBXBuildFile; fileRef = 5739E12E1DAC7F7800E14383 /* JSCryptoAlgorithmParameters.h */; };
                5750A9751E68D00000705C4A /* CryptoKeyEC.h in Headers */ = {isa = PBXBuildFile; fileRef = 5750A9731E68D00000705C4A /* CryptoKeyEC.h */; };
                5750A9821E6A150800705C4A /* JSEcKeyParams.h in Headers */ = {isa = PBXBuildFile; fileRef = 5750A9801E6A150800705C4A /* JSEcKeyParams.h */; };
                5750A9871E6A216800705C4A /* CryptoAlgorithmECDH.h in Headers */ = {isa = PBXBuildFile; fileRef = 5750A9851E6A216800705C4A /* CryptoAlgorithmECDH.h */; };
                5754719F1ECE628300DD63B2 /* JSRsaPssParams.h in Headers */ = {isa = PBXBuildFile; fileRef = 575471991ECE5D2A00DD63B2 /* JSRsaPssParams.h */; };
+               5760827220215A5500116678 /* CredentialsMessenger.h in Headers */ = {isa = PBXBuildFile; fileRef = 576082702021513F00116678 /* CredentialsMessenger.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               5760827A2024EA5C00116678 /* MockCredentialsMessenger.h in Headers */ = {isa = PBXBuildFile; fileRef = 5760827820244DAB00116678 /* MockCredentialsMessenger.h */; };
+               5760827B2024ED2900116678 /* MockCredentialsMessenger.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5760827920244DAC00116678 /* MockCredentialsMessenger.cpp */; };
+               5760828620256AFA00116678 /* JSMockCredentialsMessenger.h in Headers */ = {isa = PBXBuildFile; fileRef = 576082822025679700116678 /* JSMockCredentialsMessenger.h */; };
+               5760828820256AFD00116678 /* JSMockCredentialsMessenger.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 576082812025679600116678 /* JSMockCredentialsMessenger.cpp */; };
                5768142A1E6F99C100E77754 /* CryptoAlgorithmEcdhKeyDeriveParams.h in Headers */ = {isa = PBXBuildFile; fileRef = 576814291E6F99C100E77754 /* CryptoAlgorithmEcdhKeyDeriveParams.h */; };
                576814411E709FA400E77754 /* JSEcdhKeyDeriveParams.h in Headers */ = {isa = PBXBuildFile; fileRef = 5768143E1E709C3600E77754 /* JSEcdhKeyDeriveParams.h */; };
                576814451E70CB1F00E77754 /* JSAesKeyParams.h in Headers */ = {isa = PBXBuildFile; fileRef = 576814431E70CB1000E77754 /* JSAesKeyParams.h */; };
                57303C292009B2FC00355965 /* AuthenticatorAssertionResponse.idl */ = {isa = PBXFileReference; lastKnownFileType = text; path = AuthenticatorAssertionResponse.idl; sourceTree = "<group>"; };
                57303C2D2009B7D900355965 /* JSAuthenticatorAssertionResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSAuthenticatorAssertionResponse.h; sourceTree = "<group>"; };
                57303C2E2009B7DA00355965 /* JSAuthenticatorAssertionResponse.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSAuthenticatorAssertionResponse.cpp; sourceTree = "<group>"; };
-               57303C4320105B3D00355965 /* Authenticator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Authenticator.h; sourceTree = "<group>"; };
-               57303C4420105B3D00355965 /* Authenticator.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Authenticator.cpp; sourceTree = "<group>"; };
+               57303C4320105B3D00355965 /* AuthenticatorManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AuthenticatorManager.h; sourceTree = "<group>"; };
+               57303C4420105B3D00355965 /* AuthenticatorManager.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = AuthenticatorManager.cpp; sourceTree = "<group>"; };
                573489381DAC6B6D00DC0667 /* CryptoAlgorithmParameters.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CryptoAlgorithmParameters.h; sourceTree = "<group>"; };
                5739E12E1DAC7F7800E14383 /* JSCryptoAlgorithmParameters.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCryptoAlgorithmParameters.h; sourceTree = "<group>"; };
                5739E1301DAC7FD100E14383 /* JSCryptoAlgorithmParameters.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSCryptoAlgorithmParameters.cpp; sourceTree = "<group>"; };
                5754719A1ECE5D2A00DD63B2 /* JSRsaPssParams.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSRsaPssParams.cpp; sourceTree = "<group>"; };
                5760824F20118D8D00116678 /* JSBasicCredentialCustom.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = JSBasicCredentialCustom.cpp; sourceTree = "<group>"; };
                576082562011BE0200116678 /* JSAuthenticatorResponseCustom.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = JSAuthenticatorResponseCustom.cpp; sourceTree = "<group>"; };
+               576082702021513F00116678 /* CredentialsMessenger.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CredentialsMessenger.h; sourceTree = "<group>"; };
+               5760827820244DAB00116678 /* MockCredentialsMessenger.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockCredentialsMessenger.h; sourceTree = "<group>"; };
+               5760827920244DAC00116678 /* MockCredentialsMessenger.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = MockCredentialsMessenger.cpp; sourceTree = "<group>"; };
+               57608280202556F400116678 /* MockCredentialsMessenger.idl */ = {isa = PBXFileReference; lastKnownFileType = text; path = MockCredentialsMessenger.idl; sourceTree = "<group>"; };
+               576082812025679600116678 /* JSMockCredentialsMessenger.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSMockCredentialsMessenger.cpp; sourceTree = "<group>"; };
+               576082822025679700116678 /* JSMockCredentialsMessenger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSMockCredentialsMessenger.h; sourceTree = "<group>"; };
+               57608293202BA95300116678 /* CredentialsMessenger.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CredentialsMessenger.cpp; sourceTree = "<group>"; };
                576814281E6F98AD00E77754 /* EcdhKeyDeriveParams.idl */ = {isa = PBXFileReference; lastKnownFileType = text; path = EcdhKeyDeriveParams.idl; sourceTree = "<group>"; };
                576814291E6F99C100E77754 /* CryptoAlgorithmEcdhKeyDeriveParams.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CryptoAlgorithmEcdhKeyDeriveParams.h; sourceTree = "<group>"; };
                576814341E6FE3E800E77754 /* CryptoAlgorithmECDHMac.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CryptoAlgorithmECDHMac.cpp; sourceTree = "<group>"; };
                                A1B5B29C1AAA846E008B6042 /* MockContentFilterSettings.cpp */,
                                A1B5B29D1AAA846E008B6042 /* MockContentFilterSettings.h */,
                                A19AEA1C1AAA7C4900B52B25 /* MockContentFilterSettings.idl */,
+                               5760827920244DAC00116678 /* MockCredentialsMessenger.cpp */,
+                               5760827820244DAB00116678 /* MockCredentialsMessenger.h */,
+                               57608280202556F400116678 /* MockCredentialsMessenger.idl */,
                                51058AD71D679257009A538C /* MockGamepad.cpp */,
                                51058AD81D679257009A538C /* MockGamepad.h */,
                                51058AD91D679257009A538C /* MockGamepadProvider.cpp */,
                                CDF4B72E1E03CA4A00E235A2 /* JSMockCDMFactory.h */,
                                A19AEA1D1AAA806E00B52B25 /* JSMockContentFilterSettings.cpp */,
                                A19AEA1E1AAA806E00B52B25 /* JSMockContentFilterSettings.h */,
+                               576082812025679600116678 /* JSMockCredentialsMessenger.cpp */,
+                               576082822025679700116678 /* JSMockCredentialsMessenger.h */,
                                2D6F3E921C1F85550061DBD4 /* JSMockPageOverlay.cpp */,
                                2D6F3E931C1F85550061DBD4 /* JSMockPageOverlay.h */,
                                A146D3201F99CA3E00D29196 /* JSMockPaymentAddress.cpp */,
                                77D510181ED7159900DA4C87 /* CredentialsContainer.cpp */,
                                77D510161ED6021B00DA4C87 /* CredentialsContainer.h */,
                                57D846291FE99F6300CA3682 /* CredentialsContainer.idl */,
+                               57608293202BA95300116678 /* CredentialsMessenger.cpp */,
+                               576082702021513F00116678 /* CredentialsMessenger.h */,
                                57D846241FE895F500CA3682 /* NavigatorCredentials.cpp */,
                                57D846261FE895F800CA3682 /* NavigatorCredentials.h */,
                                57D846251FE895F600CA3682 /* NavigatorCredentials.idl */,
                        isa = PBXGroup;
                        children = (
                                57303BB32006C6ED00355965 /* cbor */,
-                               57303C4420105B3D00355965 /* Authenticator.cpp */,
-                               57303C4320105B3D00355965 /* Authenticator.h */,
                                57303C282009B2FC00355965 /* AuthenticatorAssertionResponse.cpp */,
                                57303C272009B2FC00355965 /* AuthenticatorAssertionResponse.h */,
                                57303C292009B2FC00355965 /* AuthenticatorAssertionResponse.idl */,
                                57303C1C2009A98600355965 /* AuthenticatorAttestationResponse.cpp */,
                                57303C1B2009A98600355965 /* AuthenticatorAttestationResponse.h */,
                                57303C1D2009A98600355965 /* AuthenticatorAttestationResponse.idl */,
+                               57303C4420105B3D00355965 /* AuthenticatorManager.cpp */,
+                               57303C4320105B3D00355965 /* AuthenticatorManager.h */,
                                57303BD020087A8300355965 /* AuthenticatorResponse.cpp */,
                                57303BCF20087A8300355965 /* AuthenticatorResponse.h */,
                                57303BD120087A8300355965 /* AuthenticatorResponse.idl */,
                                CD5393D4175E018600C07123 /* JSMemoryInfo.h in Headers */,
                                538EC9331F99B9F7004D22A8 /* JSMockCDMFactory.h in Headers */,
                                A19AEA211AAA808600B52B25 /* JSMockContentFilterSettings.h in Headers */,
+                               5760828620256AFA00116678 /* JSMockCredentialsMessenger.h in Headers */,
                                538EC9341F99B9F7004D22A8 /* JSMockPageOverlay.h in Headers */,
                                A146D3231F99D0EF00D29196 /* JSMockPaymentAddress.h in Headers */,
                                A146D31B1F99BCFB00D29196 /* JSMockPaymentCoordinator.h in Headers */,
                                CDC26B41160A8CCE0026757B /* LegacyMockCDM.h in Headers */,
                                A1BF6B831AA96C7D00AF4A8A /* MockContentFilter.h in Headers */,
                                A1B5B29F1AAA846F008B6042 /* MockContentFilterSettings.h in Headers */,
+                               5760827A2024EA5C00116678 /* MockCredentialsMessenger.h in Headers */,
                                51058ADC1D6792C1009A538C /* MockGamepad.h in Headers */,
                                51058ADE1D6792C1009A538C /* MockGamepadProvider.h in Headers */,
                                4157EBFB1E3AB67F00AC9FE9 /* MockLibWebRTCPeerConnection.h in Headers */,
                                934F713A0D5A6F1000018D69 /* AuthenticationChallengeBase.h in Headers */,
                                E124748410AA161D00B79493 /* AuthenticationClient.h in Headers */,
                                514C764C0CE9234E007EF3CD /* AuthenticationMac.h in Headers */,
-                               57303C4620105D2F00355965 /* Authenticator.h in Headers */,
                                57303C2C2009B4A800355965 /* AuthenticatorAssertionResponse.h in Headers */,
                                57303C1F2009AB4200355965 /* AuthenticatorAttestationResponse.h in Headers */,
+                               57303C4620105D2F00355965 /* AuthenticatorManager.h in Headers */,
                                57303BD220087A8300355965 /* AuthenticatorResponse.h in Headers */,
                                A501920E132EBF2E008BFE55 /* Autocapitalize.h in Headers */,
                                A5A7AA43132F0ECC00D3A3C2 /* AutocapitalizeTypes.h in Headers */,
                                77D5100D1ED5E29500DA4C87 /* CredentialCreationOptions.h in Headers */,
                                77D5100B1ED5E28800DA4C87 /* CredentialRequestOptions.h in Headers */,
                                77D510171ED6022200DA4C87 /* CredentialsContainer.h in Headers */,
+                               5760827220215A5500116678 /* CredentialsMessenger.h in Headers */,
                                51A052331058774F00CC9E95 /* CredentialStorage.h in Headers */,
                                2D481F02146B5C5500AA7834 /* CrossfadeGeneratedImage.h in Headers */,
                                E1C416120F6562FD0092D2FB /* CrossOriginAccessControl.h in Headers */,
                                CD5393D3175E018600C07123 /* JSMemoryInfo.cpp in Sources */,
                                CDF4B7321E03D06000E235A2 /* JSMockCDMFactory.cpp in Sources */,
                                A19AEA221AAA808A00B52B25 /* JSMockContentFilterSettings.cpp in Sources */,
+                               5760828820256AFD00116678 /* JSMockCredentialsMessenger.cpp in Sources */,
                                2D4150DE1C1F868C000A3BA2 /* JSMockPageOverlay.cpp in Sources */,
                                A146D3221F99D0EC00D29196 /* JSMockPaymentAddress.cpp in Sources */,
                                A146D31A1F99BCF800D29196 /* JSMockPaymentCoordinator.cpp in Sources */,
                                CDF4B7311E03D00700E235A2 /* MockCDMFactory.cpp in Sources */,
                                A1BF6B821AA96C7D00AF4A8A /* MockContentFilter.cpp in Sources */,
                                A1B5B29E1AAA846E008B6042 /* MockContentFilterSettings.cpp in Sources */,
+                               5760827B2024ED2900116678 /* MockCredentialsMessenger.cpp in Sources */,
                                51058ADB1D6792C1009A538C /* MockGamepad.cpp in Sources */,
                                51058ADD1D6792C1009A538C /* MockGamepadProvider.cpp in Sources */,
                                4157EBFA1E3AB67900AC9FE9 /* MockLibWebRTCPeerConnection.cpp in Sources */,
index e455788..6fa8cc7 100644 (file)
 #include "PaymentCoordinator.h"
 #endif
 
+#if ENABLE(WEB_AUTHN)
+#include "AuthenticatorManager.h"
+#include "MockCredentialsMessenger.h"
+#endif
+
 using JSC::CallData;
 using JSC::CallType;
 using JSC::CodeBlock;
@@ -526,6 +531,11 @@ Internals::Internals(Document& document)
         frame->mainFrame().setPaymentCoordinator(std::make_unique<PaymentCoordinator>(*m_mockPaymentCoordinator));
     }
 #endif
+
+#if ENABLE(WEB_AUTHN)
+    m_mockCredentialsMessenger = std::make_unique<MockCredentialsMessenger>(*this);
+    AuthenticatorManager::singleton().setMessenger(*m_mockCredentialsMessenger);
+#endif
 }
 
 Document* Internals::contextDocument() const
@@ -4375,4 +4385,11 @@ MockPaymentCoordinator& Internals::mockPaymentCoordinator() const
 }
 #endif
 
+#if ENABLE(WEB_AUTHN)
+MockCredentialsMessenger& Internals::mockCredentialsMessenger() const
+{
+    return *m_mockCredentialsMessenger;
+}
+#endif
+
 } // namespace WebCore
index f7c6b12..380fd07 100644 (file)
@@ -71,6 +71,7 @@ class MediaStreamTrack;
 class MemoryInfo;
 class MockCDMFactory;
 class MockContentFilterSettings;
+class MockCredentialsMessenger;
 class MockPageOverlay;
 class MockPaymentCoordinator;
 class NodeList;
@@ -643,6 +644,10 @@ public:
 
     void testIncomingSyncIPCMessageWhileWaitingForSyncReply();
 
+#if ENABLE(WEB_AUTHN)
+    MockCredentialsMessenger& mockCredentialsMessenger() const;
+#endif
+
 private:
     explicit Internals(Document&);
     Document* contextDocument() const;
@@ -668,6 +673,10 @@ private:
 #if ENABLE(APPLE_PAY)
     MockPaymentCoordinator* m_mockPaymentCoordinator { nullptr };
 #endif
+
+#if ENABLE(WEB_AUTHN)
+    std::unique_ptr<MockCredentialsMessenger> m_mockCredentialsMessenger;
+#endif
 };
 
 } // namespace WebCore
index b307036..f8979a2 100644 (file)
@@ -580,4 +580,5 @@ enum EventThrottlingBehavior {
     [EnabledAtRuntime=WebAnimations] void pauseTimeline(AnimationTimeline timeline);
     [EnabledAtRuntime=WebAnimations] void setTimelineCurrentTime(AnimationTimeline timeline, double currentTime);
     [Conditional=APPLE_PAY] readonly attribute MockPaymentCoordinator mockPaymentCoordinator;
+    [Conditional=WEB_AUTHN] readonly attribute MockCredentialsMessenger mockCredentialsMessenger;
 };
diff --git a/Source/WebCore/testing/MockCredentialsMessenger.cpp b/Source/WebCore/testing/MockCredentialsMessenger.cpp
new file mode 100644 (file)
index 0000000..2de7a57
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "MockCredentialsMessenger.h"
+
+#if ENABLE(WEB_AUTHN)
+
+#include "Exception.h"
+#include "Internals.h"
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+MockCredentialsMessenger::MockCredentialsMessenger(Internals& internals)
+    : m_internals(internals)
+{
+}
+
+void MockCredentialsMessenger::setAttestationObject(const BufferSource& attestationObject)
+{
+    ASSERT(m_attestationObject.isEmpty());
+    m_attestationObject.append(attestationObject.data(), attestationObject.length());
+}
+
+void MockCredentialsMessenger::setAssertionReturnBundle(const BufferSource& credentialId, const BufferSource& authenticatorData, const BufferSource& signature, const BufferSource& userHandle)
+{
+    ASSERT(m_credentialId.isEmpty() && m_authenticatorData.isEmpty() && m_signature.isEmpty() && m_userHandle.isEmpty());
+    m_credentialId.append(credentialId.data(), credentialId.length());
+    m_authenticatorData.append(authenticatorData.data(), authenticatorData.length());
+    m_signature.append(signature.data(), signature.length());
+    m_userHandle.append(userHandle.data(), userHandle.length());
+}
+
+void MockCredentialsMessenger::ref()
+{
+    m_internals.ref();
+}
+
+void MockCredentialsMessenger::deref()
+{
+    m_internals.deref();
+}
+
+void MockCredentialsMessenger::makeCredential(const Vector<uint8_t>&, const PublicKeyCredentialCreationOptions&, CreationCompletionHandler&& handler)
+{
+    auto messageId = addCreationCompletionHandler(WTFMove(handler));
+    if (m_didTimeOut) {
+        m_didTimeOut = false;
+        return;
+    }
+    if (m_didUserCancel) {
+        m_didUserCancel = false;
+        exceptionReply(messageId, ExceptionData { NotAllowedError, ASCIILiteral("User cancelled.") });
+        return;
+    }
+    if (!m_attestationObject.isEmpty()) {
+        makeCredentialReply(messageId, m_attestationObject);
+        m_attestationObject.clear();
+        return;
+    }
+}
+
+void MockCredentialsMessenger::getAssertion(const Vector<uint8_t>&, const PublicKeyCredentialRequestOptions&, RequestCompletionHandler&& handler)
+{
+    auto messageId = addRequestCompletionHandler(WTFMove(handler));
+    if (m_didTimeOut) {
+        m_didTimeOut = false;
+        return;
+    }
+    if (m_didUserCancel) {
+        m_didUserCancel = false;
+        exceptionReply(messageId, ExceptionData { NotAllowedError, ASCIILiteral("User cancelled.") });
+        return;
+    }
+    if (!m_credentialId.isEmpty()) {
+        ASSERT(!m_authenticatorData.isEmpty() && !m_signature.isEmpty() && !m_userHandle.isEmpty());
+        getAssertionReply(messageId, m_credentialId, m_authenticatorData, m_signature, m_userHandle);
+        m_credentialId.clear();
+        m_authenticatorData.clear();
+        m_signature.clear();
+        m_userHandle.clear();
+        return;
+    }
+}
+
+void MockCredentialsMessenger::makeCredentialReply(uint64_t messageId, const Vector<uint8_t>& attestationObject)
+{
+    auto handler = takeCreationCompletionHandler(messageId);
+    handler(CreationReturnBundle(getIdFromAttestationObject(attestationObject).releaseNonNull(), ArrayBuffer::create(attestationObject.data(), attestationObject.size())));
+}
+
+void MockCredentialsMessenger::getAssertionReply(uint64_t messageId, const Vector<uint8_t>& credentialId, const Vector<uint8_t>& authenticatorData, const Vector<uint8_t>& signature, const Vector<uint8_t>& userHandle)
+{
+    auto handler = takeRequestCompletionHandler(messageId);
+    handler(AssertionReturnBundle(ArrayBuffer::create(credentialId.data(), credentialId.size()), ArrayBuffer::create(authenticatorData.data(), authenticatorData.size()), ArrayBuffer::create(signature.data(), signature.size()), ArrayBuffer::create(userHandle.data(), userHandle.size())));
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUTHN)
diff --git a/Source/WebCore/testing/MockCredentialsMessenger.h b/Source/WebCore/testing/MockCredentialsMessenger.h
new file mode 100644 (file)
index 0000000..c7ba134
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(WEB_AUTHN)
+
+#include "BufferSource.h"
+#include "CredentialsMessenger.h"
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+class Internals;
+
+class MockCredentialsMessenger final : public CredentialsMessenger {
+public:
+    MockCredentialsMessenger(Internals&);
+
+    void setDidTimeOut() { m_didTimeOut = true; }
+    void setDidUserCancel() { m_didUserCancel = true; }
+    void setAttestationObject(const BufferSource&);
+    void setAssertionReturnBundle(const BufferSource& credentialId, const BufferSource& authenticatorData, const BufferSource& signature, const BufferSource& userHandle);
+
+    void ref();
+    void deref();
+
+private:
+    void makeCredential(const Vector<uint8_t>&, const PublicKeyCredentialCreationOptions&, CreationCompletionHandler&&) final;
+    void getAssertion(const Vector<uint8_t>& hash, const PublicKeyCredentialRequestOptions&, RequestCompletionHandler&&) final;
+    void makeCredentialReply(uint64_t messageId, const Vector<uint8_t>&) final;
+    void getAssertionReply(uint64_t messageId, const Vector<uint8_t>& credentialId, const Vector<uint8_t>& authenticatorData, const Vector<uint8_t>& signature, const Vector<uint8_t>& userHandle) final;
+
+    Internals& m_internals;
+    // All following fields are disposable.
+    bool m_didTimeOut { false };
+    bool m_didUserCancel { false };
+    Vector<uint8_t> m_attestationObject;
+    Vector<uint8_t> m_credentialId;
+    Vector<uint8_t> m_authenticatorData;
+    Vector<uint8_t> m_signature;
+    Vector<uint8_t> m_userHandle;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUTHN)
diff --git a/Source/WebCore/testing/MockCredentialsMessenger.idl b/Source/WebCore/testing/MockCredentialsMessenger.idl
new file mode 100644 (file)
index 0000000..1f42444
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+[
+    Conditional=WEB_AUTHN,
+    NoInterfaceObject,
+] interface MockCredentialsMessenger {
+    void setDidTimeOut();
+    void setDidUserCancel();
+    void setAttestationObject(BufferSource attestationObject);
+    void setAssertionReturnBundle(BufferSource credentialId, BufferSource authenticatorData, BufferSource signature, BufferSource userHandle);
+};
index f5e1ce3..99fa3bd 100644 (file)
@@ -1,3 +1,41 @@
+2018-02-13  Jiewen Tan  <jiewen_tan@apple.com>
+
+        [WebAuthN] Revisit the whole async model of task dispatching, timeout and aborting
+        https://bugs.webkit.org/show_bug.cgi?id=181946
+        <rdar://problem/37258262>
+
+        Reviewed by Chris Dumez.
+
+        Dummy WebCredentialsMessenger and WebCredentialsMessengerProxy are crafted to establish
+        a message exchange channel between UIProcess and WebProcess.
+
+        * DerivedSources.make:
+        * UIProcess/CredentialManagement/WebCredentialsMessengerProxy.cpp: Copied from Source/WebCore/Modules/webauthn/AuthenticatorResponse.h.
+        (WebKit::WebCredentialsMessengerProxy::WebCredentialsMessengerProxy):
+        (WebKit::WebCredentialsMessengerProxy::~WebCredentialsMessengerProxy):
+        (WebKit::WebCredentialsMessengerProxy::makeCredential):
+        (WebKit::WebCredentialsMessengerProxy::getAssertion):
+        * UIProcess/CredentialManagement/WebCredentialsMessengerProxy.h: Copied from Source/WebCore/Modules/webauthn/AuthenticatorResponse.h.
+        * UIProcess/CredentialManagement/WebCredentialsMessengerProxy.messages.in: Added.
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::m_configurationPreferenceValues):
+        (WebKit::WebPageProxy::reattachToWebProcess):
+        * UIProcess/WebPageProxy.h:
+        * WebKit.xcodeproj/project.pbxproj:
+        * WebProcess/CredentialManagement/WebCredentialsMessenger.cpp: Copied from Source/WebCore/Modules/webauthn/AuthenticatorResponse.h.
+        (WebKit::WebCredentialsMessenger::WebCredentialsMessenger):
+        (WebKit::WebCredentialsMessenger::~WebCredentialsMessenger):
+        (WebKit::WebCredentialsMessenger::makeCredential):
+        (WebKit::WebCredentialsMessenger::getAssertion):
+        (WebKit::WebCredentialsMessenger::makeCredentialReply):
+        (WebKit::WebCredentialsMessenger::getAssertionReply):
+        * WebProcess/CredentialManagement/WebCredentialsMessenger.h: Copied from Source/WebCore/Modules/webauthn/AuthenticatorResponse.h.
+        * WebProcess/CredentialManagement/WebCredentialsMessenger.messages.in: Added.
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::m_credentialsMessenger):
+        (WebKit::m_cpuLimit): Deleted.
+        * WebProcess/WebPage/WebPage.h:
+
 2018-02-13  Youenn Fablet  <youenn@apple.com>
 
         Add support for configuring WebsiteDatastore service worker and cache storage path
index 2f28808..c4e3c84 100644 (file)
@@ -43,6 +43,7 @@ VPATH = \
     $(WebKit2)/WebProcess/Automation \
     $(WebKit2)/WebProcess/Cache \
     $(WebKit2)/WebProcess/Cookies \
+    $(WebKit2)/WebProcess/CredentialManagement \
     $(WebKit2)/WebProcess/Databases/IndexedDB \
     $(WebKit2)/WebProcess/FullScreen \
     $(WebKit2)/WebProcess/Geolocation \
@@ -68,6 +69,7 @@ VPATH = \
     $(WebKit2)/UIProcess/ApplePay \
     $(WebKit2)/UIProcess/Automation \
     $(WebKit2)/UIProcess/Cocoa \
+    $(WebKit2)/UIProcess/CredentialManagement \
     $(WebKit2)/UIProcess/Databases \
     $(WebKit2)/UIProcess/Downloads \
     $(WebKit2)/UIProcess/MediaStream \
@@ -145,6 +147,8 @@ MESSAGE_RECEIVERS = \
     WebConnection \
     WebCookieManager \
     WebCookieManagerProxy \
+    WebCredentialsMessenger \
+    WebCredentialsMessengerProxy \
     WebFullScreenManager \
     WebFullScreenManagerProxy \
     WebGeolocationManager \
diff --git a/Source/WebKit/UIProcess/CredentialManagement/WebCredentialsMessengerProxy.cpp b/Source/WebKit/UIProcess/CredentialManagement/WebCredentialsMessengerProxy.cpp
new file mode 100644 (file)
index 0000000..d6bdc1b
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "WebCredentialsMessengerProxy.h"
+
+#if ENABLE(WEB_AUTHN)
+
+#include "WebCredentialsMessengerMessages.h"
+#include "WebCredentialsMessengerProxyMessages.h"
+#include "WebPageProxy.h"
+#include "WebProcessProxy.h"
+
+namespace WebKit {
+
+WebCredentialsMessengerProxy::WebCredentialsMessengerProxy(WebPageProxy& webPageProxy)
+    : m_webPageProxy(webPageProxy)
+{
+    m_webPageProxy.process().addMessageReceiver(Messages::WebCredentialsMessengerProxy::messageReceiverName(), m_webPageProxy.pageID(), *this);
+}
+
+WebCredentialsMessengerProxy::~WebCredentialsMessengerProxy()
+{
+    m_webPageProxy.process().removeMessageReceiver(Messages::WebCredentialsMessengerProxy::messageReceiverName(), m_webPageProxy.pageID());
+}
+
+void WebCredentialsMessengerProxy::makeCredential(uint64_t)
+{
+}
+
+void WebCredentialsMessengerProxy::getAssertion(uint64_t)
+{
+}
+
+} // namespace WebKit
+
+#endif // ENABLE(WEB_AUTHN)
diff --git a/Source/WebKit/UIProcess/CredentialManagement/WebCredentialsMessengerProxy.h b/Source/WebKit/UIProcess/CredentialManagement/WebCredentialsMessengerProxy.h
new file mode 100644 (file)
index 0000000..eaffa81
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(WEB_AUTHN)
+
+#include "MessageReceiver.h"
+
+namespace WebKit {
+
+class WebPageProxy;
+
+class WebCredentialsMessengerProxy : private IPC::MessageReceiver {
+public:
+    explicit WebCredentialsMessengerProxy(WebPageProxy&);
+    ~WebCredentialsMessengerProxy();
+
+private:
+    // IPC::MessageReceiver.
+    void didReceiveMessage(IPC::Connection&, IPC::Decoder&) override;
+
+    // Receivers.
+    void makeCredential(uint64_t messageId);
+    void getAssertion(uint64_t messageId);
+
+    WebPageProxy& m_webPageProxy;
+};
+
+} // namespace WebKit
+
+#endif // ENABLE(WEB_AUTHN)
diff --git a/Source/WebKit/UIProcess/CredentialManagement/WebCredentialsMessengerProxy.messages.in b/Source/WebKit/UIProcess/CredentialManagement/WebCredentialsMessengerProxy.messages.in
new file mode 100644 (file)
index 0000000..fee59ff
--- /dev/null
@@ -0,0 +1,33 @@
+# Copyright (C) 2018 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+# THE POSSIBILITY OF SUCH DAMAGE.
+#/
+
+#if ENABLE(WEB_AUTHN)
+
+messages -> WebCredentialsMessengerProxy {
+
+    MakeCredential(uint64_t messageId);
+    GetAssertion(uint64_t messageId);
+}
+
+#endif
index 3b66d42..d1aabd6 100644 (file)
 #include "PlaybackSessionManagerProxy.h"
 #endif
 
+#if ENABLE(WEB_AUTHN)
+#include "WebCredentialsMessengerProxy.h"
+#endif
+
 // This controls what strategy we use for mouse wheel coalescing.
 #define MERGE_WHEEL_EVENTS 1
 
@@ -408,6 +412,10 @@ WebPageProxy::WebPageProxy(PageClient& pageClient, WebProcessProxy& process, uin
     m_paymentCoordinator = std::make_unique<WebPaymentCoordinatorProxy>(*this);
 #endif
 
+#if ENABLE(WEB_AUTHN)
+    m_credentialsMessenger = std::make_unique<WebCredentialsMessengerProxy>(*this);
+#endif
+
     m_process->addMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_pageID, *this);
 
 #if PLATFORM(COCOA)
@@ -661,6 +669,10 @@ void WebPageProxy::reattachToWebProcess()
     m_paymentCoordinator = std::make_unique<WebPaymentCoordinatorProxy>(*this);
 #endif
 
+#if ENABLE(WEB_AUTHN)
+    m_credentialsMessenger = std::make_unique<WebCredentialsMessengerProxy>(*this);
+#endif
+
     initializeWebPage();
 
     m_pageClient.didRelaunchProcess();
index cff18f5..dab2400 100644 (file)
@@ -217,6 +217,7 @@ class WebFullScreenManagerProxy;
 class PlaybackSessionManagerProxy;
 class WebNavigationState;
 class VideoFullscreenManagerProxy;
+class WebCredentialsMessengerProxy;
 class WebKeyboardEvent;
 class WebURLSchemeHandler;
 class WebMouseEvent;
@@ -1786,6 +1787,10 @@ private:
     std::unique_ptr<WebPaymentCoordinatorProxy> m_paymentCoordinator;
 #endif
 
+#if ENABLE(WEB_AUTHN)
+    std::unique_ptr<WebCredentialsMessengerProxy> m_credentialsMessenger;
+#endif
+
     CallbackMap m_callbacks;
     HashSet<CallbackID> m_loadDependentStringCallbackIDs;
 
index 3b7e56a..8ec5ea7 100644 (file)
                53BA47D01DC2EF5E004DF4AD /* NetworkDataTaskBlob.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 539EB5461DC2EE40009D48CF /* NetworkDataTaskBlob.cpp */; };
                53BA47D11DC2EF5E004DF4AD /* NetworkDataTaskBlob.h in Headers */ = {isa = PBXBuildFile; fileRef = 539EB5471DC2EE40009D48CF /* NetworkDataTaskBlob.h */; };
                53DEA3661DDE423100E82648 /* json.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 53DEA3651DDE422E00E82648 /* json.hpp */; };
+               5760828E2029895E00116678 /* WebCredentialsMessenger.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5760828C2029854200116678 /* WebCredentialsMessenger.cpp */; };
+               57608298202BD8BA00116678 /* WebCredentialsMessengerProxy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 57608296202BD8BA00116678 /* WebCredentialsMessengerProxy.cpp */; };
+               5760829C202D2C3C00116678 /* WebCredentialsMessengerMessageReceiver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5760829020298FBD00116678 /* WebCredentialsMessengerMessageReceiver.cpp */; };
+               5760829D202D2C4000116678 /* WebCredentialsMessengerMessages.h in Headers */ = {isa = PBXBuildFile; fileRef = 5760828F20298FBD00116678 /* WebCredentialsMessengerMessages.h */; };
+               5760829E202D2C4300116678 /* WebCredentialsMessengerProxyMessageReceiver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5760829A202BEE5A00116678 /* WebCredentialsMessengerProxyMessageReceiver.cpp */; };
+               5760829F202D2C4600116678 /* WebCredentialsMessengerProxyMessages.h in Headers */ = {isa = PBXBuildFile; fileRef = 5760829B202BEE5A00116678 /* WebCredentialsMessengerProxyMessages.h */; };
                5C0B17781E7C880E00E9123C /* NetworkSocketStreamMessageReceiver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5C0B17741E7C879C00E9123C /* NetworkSocketStreamMessageReceiver.cpp */; };
                5C0B17791E7C882100E9123C /* WebSocketStreamMessageReceiver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5C0B17761E7C879C00E9123C /* WebSocketStreamMessageReceiver.cpp */; };
                5C0B177C1E7C885400E9123C /* WebSocketStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5C0B177A1E7C884F00E9123C /* WebSocketStream.cpp */; };
                539EB5461DC2EE40009D48CF /* NetworkDataTaskBlob.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NetworkDataTaskBlob.cpp; path = NetworkProcess/NetworkDataTaskBlob.cpp; sourceTree = "<group>"; };
                539EB5471DC2EE40009D48CF /* NetworkDataTaskBlob.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NetworkDataTaskBlob.h; path = NetworkProcess/NetworkDataTaskBlob.h; sourceTree = "<group>"; };
                53DEA3651DDE422E00E82648 /* json.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = json.hpp; path = NetworkProcess/capture/json.hpp; sourceTree = "<group>"; };
+               5760828B2029854200116678 /* WebCredentialsMessenger.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebCredentialsMessenger.h; sourceTree = "<group>"; };
+               5760828C2029854200116678 /* WebCredentialsMessenger.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = WebCredentialsMessenger.cpp; sourceTree = "<group>"; };
+               5760828D202987E600116678 /* WebCredentialsMessenger.messages.in */ = {isa = PBXFileReference; lastKnownFileType = text; path = WebCredentialsMessenger.messages.in; sourceTree = "<group>"; };
+               5760828F20298FBD00116678 /* WebCredentialsMessengerMessages.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebCredentialsMessengerMessages.h; sourceTree = "<group>"; };
+               5760829020298FBD00116678 /* WebCredentialsMessengerMessageReceiver.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = WebCredentialsMessengerMessageReceiver.cpp; sourceTree = "<group>"; };
+               57608295202BD8BA00116678 /* WebCredentialsMessengerProxy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebCredentialsMessengerProxy.h; sourceTree = "<group>"; };
+               57608296202BD8BA00116678 /* WebCredentialsMessengerProxy.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = WebCredentialsMessengerProxy.cpp; sourceTree = "<group>"; };
+               57608299202BDAE200116678 /* WebCredentialsMessengerProxy.messages.in */ = {isa = PBXFileReference; lastKnownFileType = text; path = WebCredentialsMessengerProxy.messages.in; sourceTree = "<group>"; };
+               5760829A202BEE5A00116678 /* WebCredentialsMessengerProxyMessageReceiver.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = WebCredentialsMessengerProxyMessageReceiver.cpp; sourceTree = "<group>"; };
+               5760829B202BEE5A00116678 /* WebCredentialsMessengerProxyMessages.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebCredentialsMessengerProxyMessages.h; sourceTree = "<group>"; };
                5C0B17741E7C879C00E9123C /* NetworkSocketStreamMessageReceiver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NetworkSocketStreamMessageReceiver.cpp; sourceTree = "<group>"; };
                5C0B17751E7C879C00E9123C /* NetworkSocketStreamMessages.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetworkSocketStreamMessages.h; sourceTree = "<group>"; };
                5C0B17761E7C879C00E9123C /* WebSocketStreamMessageReceiver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebSocketStreamMessageReceiver.cpp; sourceTree = "<group>"; };
                        name = capture;
                        sourceTree = "<group>";
                };
+               5760828A202984C900116678 /* CredentialManagement */ = {
+                       isa = PBXGroup;
+                       children = (
+                               5760828C2029854200116678 /* WebCredentialsMessenger.cpp */,
+                               5760828B2029854200116678 /* WebCredentialsMessenger.h */,
+                               5760828D202987E600116678 /* WebCredentialsMessenger.messages.in */,
+                       );
+                       path = CredentialManagement;
+                       sourceTree = "<group>";
+               };
+               57608294202BD84900116678 /* CredentialManagement */ = {
+                       isa = PBXGroup;
+                       children = (
+                               57608296202BD8BA00116678 /* WebCredentialsMessengerProxy.cpp */,
+                               57608295202BD8BA00116678 /* WebCredentialsMessengerProxy.h */,
+                               57608299202BDAE200116678 /* WebCredentialsMessengerProxy.messages.in */,
+                       );
+                       path = CredentialManagement;
+                       sourceTree = "<group>";
+               };
                5C1426F11C23F81700D41183 /* Downloads */ = {
                        isa = PBXGroup;
                        children = (
                                41D129D81F3D101400D15E47 /* Cache */,
                                7C6E70F818B2D47E00F24E2E /* cocoa */,
                                3309344B1315B93A0097A7BC /* Cookies */,
+                               5760828A202984C900116678 /* CredentialManagement */,
                                512A9754180DF9270039A149 /* Databases */,
                                BCACC43B16B24C5D00B6E092 /* EntryPoint */,
                                E170876D16D6CA7200F99226 /* FileAPI */,
                                512F588D12A8836F00629530 /* Authentication */,
                                9955A6E81C79809000EB6A93 /* Automation */,
                                1ABC3DF21899E415004F0626 /* Cocoa */,
+                               57608294202BD84900116678 /* CredentialManagement */,
                                1AB7D4C71288AA9A00CFD08C /* Downloads */,
                                515BE17B1D54EF5A00DD7C68 /* Gamepad */,
                                2DA944A81884E9AB00ED86DB /* ios */,
                                330934441315B9220097A7BC /* WebCookieManagerMessages.h */,
                                330934451315B9220097A7BC /* WebCookieManagerProxyMessageReceiver.cpp */,
                                330934461315B9220097A7BC /* WebCookieManagerProxyMessages.h */,
+                               5760829020298FBD00116678 /* WebCredentialsMessengerMessageReceiver.cpp */,
+                               5760828F20298FBD00116678 /* WebCredentialsMessengerMessages.h */,
+                               5760829A202BEE5A00116678 /* WebCredentialsMessengerProxyMessageReceiver.cpp */,
+                               5760829B202BEE5A00116678 /* WebCredentialsMessengerProxyMessages.h */,
                                CD73BA48131ACD8E00EEDED2 /* WebFullScreenManagerMessageReceiver.cpp */,
                                CD73BA49131ACD8E00EEDED2 /* WebFullScreenManagerMessages.h */,
                                CD73BA45131ACC8800EEDED2 /* WebFullScreenManagerProxyMessageReceiver.cpp */,
                                3309344A1315B9220097A7BC /* WebCookieManagerProxyMessages.h in Headers */,
                                BC1DD7B2114DC396005ADAF3 /* WebCoreArgumentCoders.h in Headers */,
                                512F589B12A8838800629530 /* WebCredential.h in Headers */,
+                               5760829D202D2C4000116678 /* WebCredentialsMessengerMessages.h in Headers */,
+                               5760829F202D2C4600116678 /* WebCredentialsMessengerProxyMessages.h in Headers */,
                                1AA83F6D1A5B63FF00026EC6 /* WebDatabaseProvider.h in Headers */,
                                CD19A26E1A13E834008D650E /* WebDiagnosticLoggingClient.h in Headers */,
                                1A5B1C5518987EDF004FCF9B /* WebDocumentLoader.h in Headers */,
                                1AB1F7901D1B34A6007C9BD1 /* WebCoreArgumentCodersCocoa.mm in Sources */,
                                BCE23263122C6CF300D5C35A /* WebCoreArgumentCodersMac.mm in Sources */,
                                512F589A12A8838800629530 /* WebCredential.cpp in Sources */,
+                               5760828E2029895E00116678 /* WebCredentialsMessenger.cpp in Sources */,
+                               5760829C202D2C3C00116678 /* WebCredentialsMessengerMessageReceiver.cpp in Sources */,
+                               57608298202BD8BA00116678 /* WebCredentialsMessengerProxy.cpp in Sources */,
+                               5760829E202D2C4300116678 /* WebCredentialsMessengerProxyMessageReceiver.cpp in Sources */,
                                1AA83F6C1A5B63FF00026EC6 /* WebDatabaseProvider.cpp in Sources */,
                                CD19A26D1A13E82A008D650E /* WebDiagnosticLoggingClient.cpp in Sources */,
                                1A5B1C5418987EDF004FCF9B /* WebDocumentLoader.cpp in Sources */,
diff --git a/Source/WebKit/WebProcess/CredentialManagement/WebCredentialsMessenger.cpp b/Source/WebKit/WebProcess/CredentialManagement/WebCredentialsMessenger.cpp
new file mode 100644 (file)
index 0000000..3938f7e
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "WebCredentialsMessenger.h"
+
+#if ENABLE(WEB_AUTHN)
+
+#include "WebCredentialsMessengerMessages.h"
+#include "WebCredentialsMessengerProxyMessages.h"
+#include "WebPage.h"
+#include "WebProcess.h"
+
+namespace WebKit {
+
+WebCredentialsMessenger::WebCredentialsMessenger(WebPage& webPage)
+    : m_webPage(webPage)
+{
+    WebProcess::singleton().addMessageReceiver(Messages::WebCredentialsMessenger::messageReceiverName(), m_webPage.pageID(), *this);
+}
+
+WebCredentialsMessenger::~WebCredentialsMessenger()
+{
+    WebProcess::singleton().removeMessageReceiver(*this);
+}
+
+void WebCredentialsMessenger::makeCredential(const Vector<uint8_t>&, const WebCore::PublicKeyCredentialCreationOptions&, WebCore::CreationCompletionHandler&&)
+{
+}
+
+void WebCredentialsMessenger::getAssertion(const Vector<uint8_t>&, const WebCore::PublicKeyCredentialRequestOptions&, WebCore::RequestCompletionHandler&&)
+{
+}
+
+void WebCredentialsMessenger::makeCredentialReply(uint64_t messageId, const Vector<uint8_t>&)
+{
+}
+
+void WebCredentialsMessenger::getAssertionReply(uint64_t messageId, const Vector<uint8_t>& credentialId, const Vector<uint8_t>& authenticatorData, const Vector<uint8_t>& signature, const Vector<uint8_t>& userHandle)
+{
+}
+
+} // namespace WebKit
+
+#endif // ENABLE(WEB_AUTHN)
diff --git a/Source/WebKit/WebProcess/CredentialManagement/WebCredentialsMessenger.h b/Source/WebKit/WebProcess/CredentialManagement/WebCredentialsMessenger.h
new file mode 100644 (file)
index 0000000..4d5f6bd
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(WEB_AUTHN)
+
+#include "MessageReceiver.h"
+#include <WebCore/CredentialsMessenger.h>
+
+namespace WebKit {
+
+class WebPage;
+
+class WebCredentialsMessenger final : public WebCore::CredentialsMessenger, private IPC::MessageReceiver {
+public:
+    explicit WebCredentialsMessenger(WebPage&);
+    ~WebCredentialsMessenger();
+
+private:
+    // WebCore::CredentialsMessenger
+    // sender
+    void makeCredential(const Vector<uint8_t>&, const WebCore::PublicKeyCredentialCreationOptions&, WebCore::CreationCompletionHandler&&) final;
+    void getAssertion(const Vector<uint8_t>& hash, const WebCore::PublicKeyCredentialRequestOptions&, WebCore::RequestCompletionHandler&&) final;
+
+    // receiver
+    void makeCredentialReply(uint64_t messageId, const Vector<uint8_t>&) final;
+    void getAssertionReply(uint64_t messageId, const Vector<uint8_t>& credentialId, const Vector<uint8_t>& authenticatorData, const Vector<uint8_t>& signature, const Vector<uint8_t>& userHandle) final;
+
+    // IPC::MessageReceiver.
+    void didReceiveMessage(IPC::Connection&, IPC::Decoder&) override;
+
+    WebPage& m_webPage;
+};
+
+} // namespace WebKit
+
+#endif // ENABLE(WEB_AUTHN)
diff --git a/Source/WebKit/WebProcess/CredentialManagement/WebCredentialsMessenger.messages.in b/Source/WebKit/WebProcess/CredentialManagement/WebCredentialsMessenger.messages.in
new file mode 100644 (file)
index 0000000..3a2c85d
--- /dev/null
@@ -0,0 +1,34 @@
+# Copyright (C) 2018 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+# THE POSSIBILITY OF SUCH DAMAGE.
+#/
+
+#if ENABLE(WEB_AUTHN)
+
+messages -> WebCredentialsMessenger {
+
+    ExceptionReply(uint64_t messageId, struct WebCore::ExceptionData exception);
+    MakeCredentialReply(uint64_t messageId, Vector<uint8_t> attestationObject);
+    GetAssertionReply(uint64_t messageId, Vector<uint8_t> credentialId, Vector<uint8_t> authenticatorData, Vector<uint8_t> signature, Vector<uint8_t> userHandle);
+}
+
+#endif
index ce07ab5..92e486f 100644 (file)
 #include <WebCore/MediaPlayerRequestInstallMissingPluginsCallback.h>
 #endif
 
+#if ENABLE(WEB_AUTHN)
+#include "WebCredentialsMessenger.h"
+#include <WebCore/AuthenticatorManager.h>
+#endif
+
 using namespace JSC;
 using namespace WebCore;
 
@@ -370,6 +375,9 @@ WebPage::WebPage(uint64_t pageID, WebPageCreationParameters&& parameters)
     , m_userInterfaceLayoutDirection(parameters.userInterfaceLayoutDirection)
     , m_overrideContentSecurityPolicy { parameters.overrideContentSecurityPolicy }
     , m_cpuLimit(parameters.cpuLimit)
+#if ENABLE(WEB_AUTHN)
+    , m_credentialsMessenger(std::make_unique<WebCredentialsMessenger>(*this))
+#endif
 {
     ASSERT(m_pageID);
 
@@ -580,6 +588,10 @@ WebPage::WebPage(uint64_t pageID, WebPageCreationParameters&& parameters)
 #endif
 #endif
 
+#if ENABLE(WEB_AUTHN)
+    WebCore::AuthenticatorManager::singleton().setMessenger(*m_credentialsMessenger);
+#endif
+
     for (auto iterator : parameters.urlSchemeHandlers)
         registerURLSchemeHandler(iterator.value, iterator.key);
 
index c1e8305..8fdcef0 100644 (file)
@@ -211,6 +211,7 @@ class WebUserContentController;
 class VideoFullscreenManager;
 class WebWheelEvent;
 class WebTouchEvent;
+class WebCredentialsMessenger;
 class RemoteLayerTreeTransaction;
 
 struct AssistedNodeInformation;
@@ -1686,6 +1687,11 @@ private:
 #if ENABLE(APPLICATION_MANIFEST)
     HashMap<uint64_t, uint64_t> m_applicationManifestFetchCallbackMap;
 #endif
+
+#if ENABLE(WEB_AUTHN)
+    std::unique_ptr<WebCredentialsMessenger> m_credentialsMessenger;
+#endif
+
 };
 
 } // namespace WebKit