Title: [227382] trunk
Revision
227382
Author
jiewen_...@apple.com
Date
2018-01-22 19:00:59 -0800 (Mon, 22 Jan 2018)

Log Message

[WebAuthN] Implement PublicKeyCredential's [[Create]] with a dummy authenticator
https://bugs.webkit.org/show_bug.cgi?id=181928
<rdar://problem/36459893>

Reviewed by Brent Fulgham.

Source/WebCore:

This patch implements PublicKeyCredential's [[Create]] from https://www.w3.org/TR/webauthn/#createCredential
as of 5 December 2017. In order to do testing, a dummy authenticator is implemented to exercise a failure
and a pass path. A number of dependencies need to be resolved later in order to comply with the spec.
Also, the current architecture of handling async WebAuthN operations including dispatching, timeout, and aborting
might need a redesign once the underlying authenticator is clear. Since this is our first attempt to implement
a prototype, all those limitations, in my opinion, can be marked as non-blocking to accelerate the whole
process. Those limitations will then be addressed once the first prototype is finshed.

Tests: http/tests/webauthn/public-key-credential-create-with-invalid-parameters.https.html
       http/tests/webauthn/public-key-credential-same-origin-with-ancestors-2.https.html
       http/tests/webauthn/public-key-credential-same-origin-with-ancestors.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

* Modules/credentialmanagement/BasicCredential.h:
* Modules/credentialmanagement/BasicCredential.idl:
* Modules/credentialmanagement/CredentialsContainer.cpp:
(WebCore::CredentialsContainer::PendingPromise::PendingPromise):
(WebCore::CredentialsContainer::dispatchTask):
(WebCore::CredentialsContainer::get):
(WebCore::CredentialsContainer::isCreate):
(WebCore::CredentialsContainer::preventSilentAccess const):
(WebCore::CredentialsContainer::preventSilentAccess): Deleted.
* Modules/credentialmanagement/CredentialsContainer.h:
(WebCore::CredentialsContainer::PendingPromise::create):
* Modules/webauthn/Authenticator.cpp: Copied from Source/WebCore/Modules/webauthn/AuthenticatorResponse.cpp.
(WebCore::Authenticator::singleton):
(WebCore::Authenticator::makeCredential const):
* Modules/webauthn/Authenticator.h: Copied from Source/WebCore/Modules/webauthn/PublicKeyCredentialCreationOptions.h.
* Modules/webauthn/AuthenticatorAssertionResponse.cpp:
(WebCore::AuthenticatorAssertionResponse::authenticatorData const):
(WebCore::AuthenticatorAssertionResponse::signature const):
(WebCore::AuthenticatorAssertionResponse::userHandle const):
(WebCore::AuthenticatorAssertionResponse::~AuthenticatorAssertionResponse): Deleted.
(WebCore::AuthenticatorAssertionResponse::authenticatorData): Deleted.
(WebCore::AuthenticatorAssertionResponse::signature): Deleted.
(WebCore::AuthenticatorAssertionResponse::userHandle): Deleted.
* Modules/webauthn/AuthenticatorAssertionResponse.h:
(WebCore::AuthenticatorAssertionResponse::create):
* Modules/webauthn/AuthenticatorAttestationResponse.cpp:
(WebCore::AuthenticatorAttestationResponse::attestationObject const):
(WebCore::AuthenticatorAttestationResponse::~AuthenticatorAttestationResponse): Deleted.
(WebCore::AuthenticatorAttestationResponse::attestationObject): Deleted.
* Modules/webauthn/AuthenticatorAttestationResponse.h:
(WebCore::AuthenticatorAttestationResponse::create):
* Modules/webauthn/AuthenticatorResponse.cpp:
(WebCore::AuthenticatorResponse::clientDataJSON const):
(WebCore::AuthenticatorResponse::~AuthenticatorResponse): Deleted.
(WebCore::AuthenticatorResponse::clientDataJSON): Deleted.
* Modules/webauthn/AuthenticatorResponse.h:
* Modules/webauthn/AuthenticatorResponse.idl:
* Modules/webauthn/PublicKeyCredential.cpp:
(WebCore::PublicKeyCredentialInternal::produceClientDataJson):
(WebCore::PublicKeyCredentialInternal::produceClientDataJsonHash):
(WebCore::PublicKeyCredentialInternal::getIdFromAttestationObject):
(WebCore::PublicKeyCredential::PublicKeyCredential):
(WebCore::PublicKeyCredential::discoverFromExternalSource):
(WebCore::PublicKeyCredential::create):
(WebCore::PublicKeyCredential::rawId const):
(WebCore::PublicKeyCredential::response const):
(WebCore::PublicKeyCredential::getClientExtensionResults const):
(WebCore::PublicKeyCredential::rawId): Deleted.
(WebCore::PublicKeyCredential::response): Deleted.
(WebCore::PublicKeyCredential::getClientExtensionResults): Deleted.
* Modules/webauthn/PublicKeyCredential.h:
* Modules/webauthn/PublicKeyCredential.idl:
* Modules/webauthn/PublicKeyCredentialCreationOptions.h:
(): Deleted.
* Modules/webauthn/PublicKeyCredentialDescriptor.h:
* Modules/webauthn/PublicKeyCredentialDescriptor.idl:
* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* bindings/js/JSAuthenticatorResponseCustom.cpp: Copied from Source/WebCore/Modules/webauthn/AuthenticatorAttestationResponse.cpp.
(WebCore::toJSNewlyCreated):
(WebCore::toJS):
* bindings/js/JSBasicCredentialCustom.cpp: Copied from Source/WebCore/Modules/webauthn/AuthenticatorResponse.cpp.
(WebCore::toJSNewlyCreated):
(WebCore::toJS):
* bindings/js/JSBindingsAllInOne.cpp:

LayoutTests:

Test cases are divided into two different folders. One follows wpt style. The other contains tests
that I don't know how to write them in wpt style.

* http/tests/webauthn/public-key-credential-create-with-invalid-parameters.https-expected.txt: Added.
* http/tests/webauthn/public-key-credential-create-with-invalid-parameters.https.html: Added.
* http/tests/webauthn/public-key-credential-same-origin-with-ancestors-2.https-expected.txt: Added.
* http/tests/webauthn/public-key-credential-same-origin-with-ancestors-2.https.html: Added.
* http/tests/webauthn/public-key-credential-same-origin-with-ancestors.https-expected.txt: Added.
* http/tests/webauthn/public-key-credential-same-origin-with-ancestors.https.html: Added.
* http/tests/webauthn/resources/last-layer-frame.https.html: Added.
* http/tests/webauthn/resources/second-layer-frame.https.html: Added.
* http/tests/webauthn/resources/util.js: Added.
It will be good to convert them into wpt style.
* http/wpt/webauthn/WebAuthN.idl: Added.
* http/wpt/webauthn/idl.https-expected.txt: Added.
* http/wpt/webauthn/idl.https.html: Added.
* http/wpt/webauthn/public-key-credential-create-failure.https-expected.txt: Added.
* http/wpt/webauthn/public-key-credential-create-failure.https.html: Added.
* http/wpt/webauthn/public-key-credential-create-success.https-expected.txt: Added.
* http/wpt/webauthn/public-key-credential-create-success.https.html: Added.
* http/wpt/webauthn/resources/util.js: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (227381 => 227382)


--- trunk/LayoutTests/ChangeLog	2018-01-23 02:09:22 UTC (rev 227381)
+++ trunk/LayoutTests/ChangeLog	2018-01-23 03:00:59 UTC (rev 227382)
@@ -1,3 +1,33 @@
+2018-01-22  Jiewen Tan  <jiewen_...@apple.com>
+
+        [WebAuthN] Implement PublicKeyCredential's [[Create]] with a dummy authenticator
+        https://bugs.webkit.org/show_bug.cgi?id=181928
+        <rdar://problem/36459893>
+
+        Reviewed by Brent Fulgham.
+
+        Test cases are divided into two different folders. One follows wpt style. The other contains tests
+        that I don't know how to write them in wpt style.
+
+        * http/tests/webauthn/public-key-credential-create-with-invalid-parameters.https-expected.txt: Added.
+        * http/tests/webauthn/public-key-credential-create-with-invalid-parameters.https.html: Added.
+        * http/tests/webauthn/public-key-credential-same-origin-with-ancestors-2.https-expected.txt: Added.
+        * http/tests/webauthn/public-key-credential-same-origin-with-ancestors-2.https.html: Added.
+        * http/tests/webauthn/public-key-credential-same-origin-with-ancestors.https-expected.txt: Added.
+        * http/tests/webauthn/public-key-credential-same-origin-with-ancestors.https.html: Added.
+        * http/tests/webauthn/resources/last-layer-frame.https.html: Added.
+        * http/tests/webauthn/resources/second-layer-frame.https.html: Added.
+        * http/tests/webauthn/resources/util.js: Added.
+        It will be good to convert them into wpt style.
+        * http/wpt/webauthn/WebAuthN.idl: Added.
+        * http/wpt/webauthn/idl.https-expected.txt: Added.
+        * http/wpt/webauthn/idl.https.html: Added.
+        * http/wpt/webauthn/public-key-credential-create-failure.https-expected.txt: Added.
+        * http/wpt/webauthn/public-key-credential-create-failure.https.html: Added.
+        * http/wpt/webauthn/public-key-credential-create-success.https-expected.txt: Added.
+        * http/wpt/webauthn/public-key-credential-create-success.https.html: Added.
+        * http/wpt/webauthn/resources/util.js: Added.
+
 2018-01-22  Ryan Haddad  <ryanhad...@apple.com>
 
         Skip http/tests/ssl/applepay/ApplePayRequestShippingContact.https.html on Sierra.

Added: trunk/LayoutTests/http/tests/webauthn/public-key-credential-create-with-invalid-parameters.https-expected.txt (0 => 227382)


--- trunk/LayoutTests/http/tests/webauthn/public-key-credential-create-with-invalid-parameters.https-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/tests/webauthn/public-key-credential-create-with-invalid-parameters.https-expected.txt	2018-01-23 03:00:59 UTC (rev 227382)
@@ -0,0 +1,64 @@
+Tests that PublicKeyCredential's [[create]] throws TypeError when invalid options are passed.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Member PublicKeyCredentialCreationOptions.rp is required and must be an instance of PublicKeyCredentialRpEntity.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Member PublicKeyCredentialCreationOptions.user is required and must be an instance of PublicKeyCredentialUserEntity.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Member PublicKeyCredentialCreationOptions.challenge is required and must be an instance of (ArrayBufferView or ArrayBuffer).
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Member PublicKeyCredentialCreationOptions.pubKeyCredParams is required and must be an instance of sequence.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Member PublicKeyCredentialRpEntity.name is required and must be an instance of DOMString.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Member PublicKeyCredentialUserEntity.name is required and must be an instance of DOMString.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Member PublicKeyCredentialUserEntity.id is required and must be an instance of (ArrayBufferView or ArrayBuffer).
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Member PublicKeyCredentialUserEntity.displayName is required and must be an instance of DOMString.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Member PublicKeyCredentialParameters.type is required and must be an instance of PublicKeyCredentialType.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Member PublicKeyCredentialParameters.alg is required and must be an instance of long.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Member PublicKeyCredentialDescriptor.type is required and must be an instance of PublicKeyCredentialType.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Member PublicKeyCredentialDescriptor.id is required and must be an instance of (ArrayBufferView or ArrayBuffer).
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Cannot convert a symbol to a string.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Cannot convert a symbol to a string.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Cannot convert a symbol to a string.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Cannot convert a symbol to a string.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Type error.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Type error.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Type error.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Type error.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Type error.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Type error.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Type error.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Cannot convert a symbol to a string.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Cannot convert a symbol to a string.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Type error.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Type error.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Type error.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Type error.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Type error.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Type error.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Type error.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Type error.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Type error.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Type error.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Cannot convert a symbol to a string.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Type error.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Type error.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Type error.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Cannot convert a symbol to a number.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Cannot convert a symbol to a number.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Type error.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Type error.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Type error.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Cannot convert a symbol to a string.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Type error.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Type error.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Type error.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Type error.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Type error.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Type error.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Type error.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Type error.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Type error.
+PASS navigator.credentials.create(invalidOptions) rejected promise  with TypeError: Type error.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/http/tests/webauthn/public-key-credential-create-with-invalid-parameters.https.html (0 => 227382)


--- trunk/LayoutTests/http/tests/webauthn/public-key-credential-create-with-invalid-parameters.https.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/webauthn/public-key-credential-create-with-invalid-parameters.https.html	2018-01-23 03:00:59 UTC (rev 227382)
@@ -0,0 +1,123 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src=""
+    <script src=""
+</head>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+<script>
+    description("Tests that PublicKeyCredential's [[create]] throws TypeError when invalid options are passed.");
+
+    jsTestIsAsync = true;
+
+    const rp = {
+        name: "example.com"
+    };
+    const user = {
+        name: "John Appleseed",
+        id: asciiToUint8Array("123456"),
+        displayName: "Appleseed"
+    };
+    const challenge = asciiToUint8Array("123456");
+    const pubKeyCredParam = { type: "public-key", alg: -7 };
+    const excludeCredentials = { type: "public-key", id: asciiToUint8Array("123456") };
+
+    const missingAttributeVector = [
+        // missing top level attribute
+        [undefined, user, challenge, [pubKeyCredParam]],
+        [rp, undefined, challenge, [pubKeyCredParam]],
+        [rp, user, undefined, [pubKeyCredParam]],
+        [rp, user, challenge, undefined],
+        // missing rp attribute
+        [{ name: undefined }, user, challenge, [pubKeyCredParam]],
+        // missing user attribute
+        [rp, { name: undefined, id: user.id, displayName: user.displayName}, challenge, [pubKeyCredParam]],
+        [rp, { name: user.name, id: undefined, displayName: user.displayName}, challenge, [pubKeyCredParam]],
+        [rp, { name: user.name, id: user.id, displayName: undefined}, challenge, [pubKeyCredParam]],
+        // missing pubKeyCredParams attribute
+        [rp, user, challenge, [{ type: undefined, alg: pubKeyCredParam.alg }]],
+        [rp, user, challenge, [{ type: pubKeyCredParam.type, alg: undefined }]],
+        // missing excludeCredentials attribute
+        [rp, user, challenge, [pubKeyCredParam], undefined, [{ type: undefined, id: excludeCredentials.id }]],
+        [rp, user, challenge, [pubKeyCredParam], undefined, [{ type: excludeCredentials.type, id: undefined }]]
+    ];
+
+    const wrongTypeAttributeVector = [
+        // wrong rp attribute type
+        [{ name: Symbol() }, user, challenge, [pubKeyCredParam]],
+        [{ name: rp.name, icon: Symbol() }, user, challenge, [pubKeyCredParam]],
+        [{ name: rp.name, id: Symbol() }, user, challenge, [pubKeyCredParam]],
+        // wrong user attribute type
+        [rp, { name: Symbol(), id: user.id, displayName: user.displayName}, challenge, [pubKeyCredParam]],
+        [rp, { name: user.name, id: 1, displayName: user.displayName}, challenge, [pubKeyCredParam]],
+        [rp, { name: user.name, id: true, displayName: user.displayName}, challenge, [pubKeyCredParam]],
+        [rp, { name: user.name, id: null, displayName: user.displayName}, challenge, [pubKeyCredParam]],
+        [rp, { name: user.name, id: Symbol(), displayName: user.displayName}, challenge, [pubKeyCredParam]],
+        [rp, { name: user.name, id: { }, displayName: user.displayName}, challenge, [pubKeyCredParam]],
+        [rp, { name: user.name, id: "foo", displayName: user.displayName}, challenge, [pubKeyCredParam]],
+        [rp, { name: user.name, id: [ ], displayName: user.displayName}, challenge, [pubKeyCredParam]],
+        [rp, { name: user.name, id: user.id, displayName: Symbol()}, challenge, [pubKeyCredParam]],
+        [rp, { name: user.name, id: user.id, displayName: user.displayName, icon: Symbol()}, challenge, [pubKeyCredParam]],
+        // wrong challenge type
+        [rp, user, 1, [pubKeyCredParam]],
+        [rp, user, true, [pubKeyCredParam]],
+        [rp, user, null, [pubKeyCredParam]],
+        [rp, user, Symbol(), [pubKeyCredParam]],
+        [rp, user, "foo", [pubKeyCredParam]],
+        [rp, user, [ ], [pubKeyCredParam]],
+        [rp, user, { }, [pubKeyCredParam]],
+        // wrong pubKeyCredParam type
+        [rp, user, challenge, [{ type: 1, alg: pubKeyCredParam.alg }]],
+        [rp, user, challenge, [{ type: true, alg: pubKeyCredParam.alg }]],
+        [rp, user, challenge, [{ type: null, alg: pubKeyCredParam.alg }]],
+        [rp, user, challenge, [{ type: Symbol(), alg: pubKeyCredParam.alg }]],
+        [rp, user, challenge, [{ type: "foo", alg: pubKeyCredParam.alg }]],
+        [rp, user, challenge, [{ type: [ ], alg: pubKeyCredParam.alg }]],
+        [rp, user, challenge, [{ type: { }, alg: pubKeyCredParam.alg }]],
+        [rp, user, challenge, [{ type: pubKeyCredParam.type, alg: Symbol() }]],
+        // wrong timeout type
+        [rp, user, challenge, [pubKeyCredParam], Symbol(), undefined],
+        // wrong excludeCredentials
+        [rp, user, challenge, [pubKeyCredParam], undefined, [{ type: 1, id: excludeCredentials.id }]],
+        [rp, user, challenge, [pubKeyCredParam], undefined, [{ type: true, id: excludeCredentials.id }]],
+        [rp, user, challenge, [pubKeyCredParam], undefined, [{ type: null, id: excludeCredentials.id }]],
+        [rp, user, challenge, [pubKeyCredParam], undefined, [{ type: Symbol(), id: excludeCredentials.id }]],
+        [rp, user, challenge, [pubKeyCredParam], undefined, [{ type: "foo", id: excludeCredentials.id }]],
+        [rp, user, challenge, [pubKeyCredParam], undefined, [{ type: [ ], id: excludeCredentials.id }]],
+        [rp, user, challenge, [pubKeyCredParam], undefined, [{ type: { }, id: excludeCredentials.id }]],
+        [rp, user, challenge, [pubKeyCredParam], undefined, [{ type: excludeCredentials.type, id: 1 }]],
+        [rp, user, challenge, [pubKeyCredParam], undefined, [{ type: excludeCredentials.type, id: true }]],
+        [rp, user, challenge, [pubKeyCredParam], undefined, [{ type: excludeCredentials.type, id: null }]],
+        [rp, user, challenge, [pubKeyCredParam], undefined, [{ type: excludeCredentials.type, id: Symbol() }]],
+        [rp, user, challenge, [pubKeyCredParam], undefined, [{ type: excludeCredentials.type, id: "foo" }]],
+        [rp, user, challenge, [pubKeyCredParam], undefined, [{ type: excludeCredentials.type, id: [ ] }]],
+        [rp, user, challenge, [pubKeyCredParam], undefined, [{ type: excludeCredentials.type, id: { } }]]
+    ]
+
+    function makeOptions(attributes)
+    {
+        if (attributes.length == 4)
+            return { publicKey: { rp: attributes[0], user: attributes[1], challenge: attributes[2], pubKeyCredParams: attributes[3] } };
+        return { publicKey: { rp: attributes[0], user: attributes[1], challenge: attributes[2], pubKeyCredParams: attributes[3], timeout: attributes[4],  excludeCredentials: attributes[5]} };
+    }
+
+    function runTest(attributesVectors) {
+        attributesVectors.forEach(function(attributesVector) {
+            attributesVector.forEach(async function(attributes) {
+                invalidOptions = makeOptions(attributes);
+                await shouldReject('navigator.credentials.create(invalidOptions)');
+            });
+        });
+
+        finishJSTest();
+    }
+
+    const vectors = [];
+    vectors.push(missingAttributeVector);
+    vectors.push(wrongTypeAttributeVector);
+    runTest(vectors);
+</script>
+</body>
+</html>

Added: trunk/LayoutTests/http/tests/webauthn/public-key-credential-same-origin-with-ancestors-2.https-expected.txt (0 => 227382)


--- trunk/LayoutTests/http/tests/webauthn/public-key-credential-same-origin-with-ancestors-2.https-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/tests/webauthn/public-key-credential-same-origin-with-ancestors-2.https-expected.txt	2018-01-23 03:00:59 UTC (rev 227382)
@@ -0,0 +1,10 @@
+Tests that a frame that doesn't share the same origin with all its ancestors could not access the API.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS Throw NotAllowedError.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/http/tests/webauthn/public-key-credential-same-origin-with-ancestors-2.https.html (0 => 227382)


--- trunk/LayoutTests/http/tests/webauthn/public-key-credential-same-origin-with-ancestors-2.https.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/webauthn/public-key-credential-same-origin-with-ancestors-2.https.html	2018-01-23 03:00:59 UTC (rev 227382)
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src=""
+    <script src=""
+    <script>
+        description("Tests that a frame that doesn't share the same origin with all its ancestors could not access the API.");
+        jsTestIsAsync = true;
+
+        window.addEventListener("message", receiveMessage, false);
+    </script>
+</head>
+<body>
+    <iframe src=""
+</body>
+</html>

Added: trunk/LayoutTests/http/tests/webauthn/public-key-credential-same-origin-with-ancestors.https-expected.txt (0 => 227382)


--- trunk/LayoutTests/http/tests/webauthn/public-key-credential-same-origin-with-ancestors.https-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/tests/webauthn/public-key-credential-same-origin-with-ancestors.https-expected.txt	2018-01-23 03:00:59 UTC (rev 227382)
@@ -0,0 +1,10 @@
+Tests that a frame that doesn't share the same origin with all its ancestors could not access the API.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS Throw NotAllowedError.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/http/tests/webauthn/public-key-credential-same-origin-with-ancestors.https.html (0 => 227382)


--- trunk/LayoutTests/http/tests/webauthn/public-key-credential-same-origin-with-ancestors.https.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/webauthn/public-key-credential-same-origin-with-ancestors.https.html	2018-01-23 03:00:59 UTC (rev 227382)
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src=""
+    <script src=""
+    <script>
+        description("Tests that a frame that doesn't share the same origin with all its ancestors could not access the API.");
+        jsTestIsAsync = true;
+
+        window.addEventListener("message", receiveMessage, false);
+    </script>
+</head>
+<body>
+    <iframe src=""
+</body>
+</html>

Added: trunk/LayoutTests/http/tests/webauthn/resources/last-layer-frame.https.html (0 => 227382)


--- trunk/LayoutTests/http/tests/webauthn/resources/last-layer-frame.https.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/webauthn/resources/last-layer-frame.https.html	2018-01-23 03:00:59 UTC (rev 227382)
@@ -0,0 +1,37 @@
+<html>
+<head>
+    <script src=""
+    <script src=""
+    <script>
+    function messageToTop(messagePrefix) {
+        top.postMessage(messagePrefix, "https://127.0.0.1:8443");
+    }
+
+    const options = {
+        publicKey: {
+            rp: {
+                name: "example.com"
+            },
+            user: {
+                name: "John Appleseed",
+                id: asciiToUint8Array("123456"),
+                displayName: "John",
+            },
+            challenge: asciiToUint8Array("123456"),
+            pubKeyCredParams: [{ type: "public-key", alg: -7 }]
+        }
+    };
+    navigator.credentials.create(options).then(
+        function(value) {
+            messageToTop("Access granted. " + value);
+        },
+        function(exception) {
+            if (exception.name == "NotAllowedError")
+                messageToTop("PASS Throw NotAllowedError.");
+            else
+                messageToTop("Throw " + exception.name  + ".");
+        }
+    );
+    </script>
+</head>
+</html>

Added: trunk/LayoutTests/http/tests/webauthn/resources/second-layer-frame.https.html (0 => 227382)


--- trunk/LayoutTests/http/tests/webauthn/resources/second-layer-frame.https.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/webauthn/resources/second-layer-frame.https.html	2018-01-23 03:00:59 UTC (rev 227382)
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<html>
+<head>
+</head>
+<body>
+    <iframe src=""
+</body>
+</html>

Added: trunk/LayoutTests/http/tests/webauthn/resources/util.js (0 => 227382)


--- trunk/LayoutTests/http/tests/webauthn/resources/util.js	                        (rev 0)
+++ trunk/LayoutTests/http/tests/webauthn/resources/util.js	2018-01-23 03:00:59 UTC (rev 227382)
@@ -0,0 +1,18 @@
+function receiveMessage(event) {
+    if (event.origin === "https://localhost:8443") {
+        if (event.data.indexOf("PASS ") !== -1)
+            testPassed(event.data.replace("PASS ", ""));
+        else
+            testFailed(event.data);
+    } else
+        testFailed("Received a message from an unexpected origin: " + event.origin);
+    finishJSTest();
+}
+
+function asciiToUint8Array(str)
+{
+    const chars = [];
+    for (var i = 0; i < str.length; ++i)
+        chars.push(str.charCodeAt(i));
+    return new Uint8Array(chars);
+}

Added: trunk/LayoutTests/http/wpt/webauthn/WebAuthN.idl (0 => 227382)


--- trunk/LayoutTests/http/wpt/webauthn/WebAuthN.idl	                        (rev 0)
+++ trunk/LayoutTests/http/wpt/webauthn/WebAuthN.idl	2018-01-23 03:00:59 UTC (rev 227382)
@@ -0,0 +1,135 @@
+// Copied from https://www.w3.org/TR/webauthn/#idl-index as of 5 December 2017
+[SecureContext, Exposed=Window]
+interface PublicKeyCredential : Credential {
+    [SameObject] readonly attribute ArrayBuffer              rawId;
+    [SameObject] readonly attribute AuthenticatorResponse    response;
+    AuthenticationExtensions getClientExtensionResults();
+};
+
+partial dictionary CredentialCreationOptions {
+    MakePublicKeyCredentialOptions      publicKey;
+};
+
+partial dictionary CredentialRequestOptions {
+    PublicKeyCredentialRequestOptions      publicKey;
+};
+
+partial interface PublicKeyCredential {
+    static Promise < boolean > isUserVerifyingPlatformAuthenticatorAvailable();
+};
+
+[SecureContext, Exposed=Window]
+interface AuthenticatorResponse {
+    [SameObject] readonly attribute ArrayBuffer      clientDataJSON;
+};
+
+[SecureContext, Exposed=Window]
+interface AuthenticatorAttestationResponse : AuthenticatorResponse {
+    [SameObject] readonly attribute ArrayBuffer      attestationObject;
+};
+
+[SecureContext, Exposed=Window]
+interface AuthenticatorAssertionResponse : AuthenticatorResponse {
+    [SameObject] readonly attribute ArrayBuffer      authenticatorData;
+    [SameObject] readonly attribute ArrayBuffer      signature;
+    [SameObject] readonly attribute ArrayBuffer      userHandle;
+};
+
+dictionary PublicKeyCredentialParameters {
+    required PublicKeyCredentialType      type;
+    required COSEAlgorithmIdentifier      alg;
+};
+
+dictionary MakePublicKeyCredentialOptions {
+    required PublicKeyCredentialRpEntity         rp;
+    required PublicKeyCredentialUserEntity       user;
+
+    required BufferSource                             challenge;
+    required sequence<PublicKeyCredentialParameters>  pubKeyCredParams;
+
+    unsigned long                                timeout;
+    sequence<PublicKeyCredentialDescriptor>      excludeCredentials = [];
+    AuthenticatorSelectionCriteria               authenticatorSelection;
+    AttestationConveyancePreference              attestation = "none";
+    AuthenticationExtensions                     extensions;
+};
+
+dictionary PublicKeyCredentialEntity {
+    required DOMString    name;
+    USVString             icon;
+};
+
+dictionary PublicKeyCredentialRpEntity : PublicKeyCredentialEntity {
+    DOMString      id;
+};
+
+dictionary PublicKeyCredentialUserEntity : PublicKeyCredentialEntity {
+    required BufferSource   id;
+    required DOMString      displayName;
+};
+
+dictionary AuthenticatorSelectionCriteria {
+    AuthenticatorAttachment      authenticatorAttachment;
+    boolean                      requireResidentKey = false;
+    UserVerificationRequirement  userVerification = "preferred";
+};
+
+enum AuthenticatorAttachment {
+    "platform",       // Platform attachment
+    "cross-platform"  // Cross-platform attachment
+};
+
+enum AttestationConveyancePreference {
+    "none",
+    "indirect",
+    "direct"
+};
+
+dictionary PublicKeyCredentialRequestOptions {
+    required BufferSource                challenge;
+    unsigned long                        timeout;
+    USVString                            rpId;
+    sequence<PublicKeyCredentialDescriptor> allowCredentials = [];
+    UserVerificationRequirement          userVerification = "preferred";
+    AuthenticationExtensions             extensions;
+};
+
+typedef record<DOMString, any>       AuthenticationExtensions;
+
+dictionary CollectedClientData {
+    required DOMString           type;
+    required DOMString           challenge;
+    required DOMString           origin;
+    required DOMString           hashAlgorithm;
+    DOMString                    tokenBindingId;
+    AuthenticationExtensions     clientExtensions;
+    AuthenticationExtensions     authenticatorExtensions;
+};
+
+enum PublicKeyCredentialType {
+    "public-key"
+};
+
+dictionary PublicKeyCredentialDescriptor {
+    required PublicKeyCredentialType      type;
+    required BufferSource                 id;
+    sequence<AuthenticatorTransport>      transports;
+};
+
+enum AuthenticatorTransport {
+    "usb",
+    "nfc",
+    "ble"
+};
+
+typedef long COSEAlgorithmIdentifier;
+
+enum UserVerificationRequirement {
+    "required",
+    "preferred",
+    "discouraged"
+};
+
+typedef sequence<AAGUID>      AuthenticatorSelectionList;
+
+typedef BufferSource      AAGUID;

Added: trunk/LayoutTests/http/wpt/webauthn/idl.https-expected.txt (0 => 227382)


--- trunk/LayoutTests/http/wpt/webauthn/idl.https-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/wpt/webauthn/idl.https-expected.txt	2018-01-23 03:00:59 UTC (rev 227382)
@@ -0,0 +1,55 @@
+Description
+
+This test verifies that the implementations of the WebAuthN API match with its WebIDL definition.
+
+
+PASS Setup for WebAuthN API IDL tests. 
+PASS Credential interface: existence and properties of interface object 
+PASS Credential interface object length 
+PASS Credential interface object name 
+PASS Credential interface: existence and properties of interface prototype object 
+PASS Credential interface: existence and properties of interface prototype object's "constructor" property 
+PASS Credential interface: attribute id 
+PASS Credential interface: attribute type 
+PASS PublicKeyCredential interface: existence and properties of interface object 
+PASS PublicKeyCredential interface object length 
+PASS PublicKeyCredential interface object name 
+PASS PublicKeyCredential interface: existence and properties of interface prototype object 
+PASS PublicKeyCredential interface: existence and properties of interface prototype object's "constructor" property 
+PASS PublicKeyCredential interface: attribute rawId 
+PASS PublicKeyCredential interface: attribute response 
+PASS PublicKeyCredential interface: operation getClientExtensionResults() 
+PASS PublicKeyCredential interface: operation isUserVerifyingPlatformAuthenticatorAvailable() 
+PASS PublicKeyCredential must be primary interface of credential 
+PASS Stringification of credential 
+PASS PublicKeyCredential interface: credential must inherit property "rawId" with the proper type 
+PASS PublicKeyCredential interface: credential must inherit property "response" with the proper type 
+PASS PublicKeyCredential interface: credential must inherit property "getClientExtensionResults()" with the proper type 
+PASS PublicKeyCredential interface: credential must inherit property "isUserVerifyingPlatformAuthenticatorAvailable()" with the proper type 
+PASS Credential interface: credential must inherit property "id" with the proper type 
+PASS Credential interface: credential must inherit property "type" with the proper type 
+PASS AuthenticatorResponse interface: existence and properties of interface object 
+PASS AuthenticatorResponse interface object length 
+PASS AuthenticatorResponse interface object name 
+PASS AuthenticatorResponse interface: existence and properties of interface prototype object 
+PASS AuthenticatorResponse interface: existence and properties of interface prototype object's "constructor" property 
+PASS AuthenticatorResponse interface: attribute clientDataJSON 
+PASS AuthenticatorAttestationResponse interface: existence and properties of interface object 
+PASS AuthenticatorAttestationResponse interface object length 
+PASS AuthenticatorAttestationResponse interface object name 
+PASS AuthenticatorAttestationResponse interface: existence and properties of interface prototype object 
+PASS AuthenticatorAttestationResponse interface: existence and properties of interface prototype object's "constructor" property 
+PASS AuthenticatorAttestationResponse interface: attribute attestationObject 
+PASS AuthenticatorAttestationResponse must be primary interface of credential.response 
+PASS Stringification of credential.response 
+PASS AuthenticatorAttestationResponse interface: credential.response must inherit property "attestationObject" with the proper type 
+PASS AuthenticatorResponse interface: credential.response must inherit property "clientDataJSON" with the proper type 
+PASS AuthenticatorAssertionResponse interface: existence and properties of interface object 
+PASS AuthenticatorAssertionResponse interface object length 
+PASS AuthenticatorAssertionResponse interface object name 
+PASS AuthenticatorAssertionResponse interface: existence and properties of interface prototype object 
+PASS AuthenticatorAssertionResponse interface: existence and properties of interface prototype object's "constructor" property 
+PASS AuthenticatorAssertionResponse interface: attribute authenticatorData 
+PASS AuthenticatorAssertionResponse interface: attribute signature 
+PASS AuthenticatorAssertionResponse interface: attribute userHandle 
+

Added: trunk/LayoutTests/http/wpt/webauthn/idl.https.html (0 => 227382)


--- trunk/LayoutTests/http/wpt/webauthn/idl.https.html	                        (rev 0)
+++ trunk/LayoutTests/http/wpt/webauthn/idl.https.html	2018-01-23 03:00:59 UTC (rev 227382)
@@ -0,0 +1,57 @@
+<!doctype html>
+<html>
+<head>
+    <meta charset=utf-8>
+    <title>IDL check of WebAuthN</title>
+    <link rel="help" href=""
+    <script src=""
+    <script src=""
+    <script src=""
+    <script src=""
+    <script src=""
+</head>
+<body>
+
+<h1 class="instructions">Description</h1>
+
+<p class="instructions">This test verifies that the implementations of the WebAuthN API match with its WebIDL definition.</p>
+
+<div id='log'></div>
+
+<script>
+promise_test(async () => {
+    const idlURL = ["WebAuthN.idl"];
+    const idlArray = new IdlArray();
+    const idlText = await fetch(idlURL).then(r => r.text());
+
+    idlArray.add_untested_idls("interface ArrayBuffer {};");
+
+    idlArray.add_idls(`
+        [Exposed=Window, SecureContext]
+        interface Credential {
+            readonly attribute USVString id;
+            readonly attribute DOMString type;
+        };
+    `);
+    idlArray.add_idls(idlText);
+
+    const options = {
+        publicKey: {
+            rp: {
+                name: "localhost",
+            },
+            user: {
+                name: "John Appleseed",
+                id: asciiToUint8Array("123456"),
+                displayName: "Appleseed",
+            },
+            challenge: Base64URL.parse("MTIzNDU2"),
+            pubKeyCredParams: [{ type: "public-key", alg: -7 }],
+        }
+    };
+    credential = await navigator.credentials.create(options);
+
+    idlArray.add_objects({"PublicKeyCredential": ["credential"], "AuthenticatorAttestationResponse": ["credential.response"]});
+    idlArray.test();
+}, "Setup for WebAuthN API IDL tests.");
+</script>

Added: trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure.https-expected.txt (0 => 227382)


--- trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure.https-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure.https-expected.txt	2018-01-23 03:00:59 UTC (rev 227382)
@@ -0,0 +1,6 @@
+
+PASS PublicKeyCredential's [[create]] with timeout 
+PASS PublicKeyCredential's [[create]] with a mismatched RP ID 
+PASS PublicKeyCredential's [[create]] with an empty pubKeyCredParams 
+PASS PublicKeyCredential's [[create]] with user cancellations 
+

Added: trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure.https.html (0 => 227382)


--- trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure.https.html	                        (rev 0)
+++ trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-failure.https.html	2018-01-23 03:00:59 UTC (rev 227382)
@@ -0,0 +1,88 @@
+<!DOCTYPE html>
+<title>Web Authentication API: PublicKeyCredential's [[create]] failure cases.</title>
+<script src=""
+<script src=""
+<script src=""
+<script>
+    promise_test(function(t) {
+        const options = {
+            publicKey: {
+                rp: {
+                    name: "example.com"
+                },
+                user: {
+                    name: "John Appleseed",
+                    id: asciiToUint8Array("123456"),
+                    displayName: "John",
+                },
+                challenge: asciiToUint8Array("123456"),
+                pubKeyCredParams: [{ type: "public-key", alg: -7 }],
+                timeout: 0,
+            }
+        };
+        return promise_rejects(t, "NotAllowedError",
+            navigator.credentials.create(options));
+    }, "PublicKeyCredential's [[create]] with timeout");
+
+    promise_test(function(t) {
+        const options = {
+            publicKey: {
+                rp: {
+                    name: "example.com",
+                    id: "example.com"
+                },
+                user: {
+                    name: "John Appleseed",
+                    id: asciiToUint8Array("123456"),
+                    displayName: "John",
+                },
+                challenge: asciiToUint8Array("123456"),
+                pubKeyCredParams: [{ type: "public-key", alg: -7 }],
+            }
+        };
+        return promise_rejects(t, "SecurityError",
+            navigator.credentials.create(options));
+    }, "PublicKeyCredential's [[create]] with a mismatched RP ID");
+
+    promise_test(function(t) {
+        const options = {
+            publicKey: {
+                rp: {
+                    name: "localhost",
+                    id: "localhost"
+                },
+                user: {
+                    name: "John Appleseed",
+                    id: asciiToUint8Array("123456"),
+                    displayName: "Appleseed",
+                },
+                challenge: asciiToUint8Array("123456"),
+                pubKeyCredParams: [ ],
+            }
+        };
+        return promise_rejects(t, "NotSupportedError",
+            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: {
+                rp: {
+                    name: "localhost",
+                    id: "localhost"
+                },
+                user: {
+                    name: "John Appleseed",
+                    id: asciiToUint8Array("123456"),
+                    displayName: "John",
+                },
+                challenge: asciiToUint8Array("123456"),
+                pubKeyCredParams: [{ type: "public-key", alg: -7 }],
+            }
+        };
+        return promise_rejects(t, "NotAllowedError",
+            navigator.credentials.create(options));
+    }, "PublicKeyCredential's [[create]] with user cancellations");
+</script>

Added: trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-success.https-expected.txt (0 => 227382)


--- trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-success.https-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-success.https-expected.txt	2018-01-23 03:00:59 UTC (rev 227382)
@@ -0,0 +1,3 @@
+
+PASS PublicKeyCredential's [[create]] with minimum options 
+

Added: trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-success.https.html (0 => 227382)


--- trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-success.https.html	                        (rev 0)
+++ trunk/LayoutTests/http/wpt/webauthn/public-key-credential-create-success.https.html	2018-01-23 03:00:59 UTC (rev 227382)
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<title>Web Authentication API: PublicKeyCredential's [[create]] success cases.</title>
+<script src=""
+<script src=""
+<script src=""
+<script>
+    // The following test is specifically tuned for current dummy authenticator.
+    promise_test(function(t) {
+        const options = {
+            publicKey: {
+                rp: {
+                    name: "localhost",
+                },
+                user: {
+                    name: "John Appleseed",
+                    id: asciiToUint8Array("123456"),
+                    displayName: "Appleseed",
+                },
+                challenge: Base64URL.parse("MTIzNDU2"),
+                pubKeyCredParams: [{ type: "public-key", alg: -7 }],
+            }
+        };
+
+        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');
+                try {
+                    assert_throws("NotSupportedError", credential.getClientExtensionResults());
+                } catch { }
+            });
+    }, "PublicKeyCredential's [[create]] with minimum options");
+</script>

Added: trunk/LayoutTests/http/wpt/webauthn/resources/util.js (0 => 227382)


--- trunk/LayoutTests/http/wpt/webauthn/resources/util.js	                        (rev 0)
+++ trunk/LayoutTests/http/wpt/webauthn/resources/util.js	2018-01-23 03:00:59 UTC (rev 227382)
@@ -0,0 +1,45 @@
+function asciiToUint8Array(str)
+{
+    var chars = [];
+    for (var i = 0; i < str.length; ++i)
+        chars.push(str.charCodeAt(i));
+    return new Uint8Array(chars);
+}
+
+// Builds a hex string representation for an array-like input.
+// "bytes" can be an Array of bytes, an ArrayBuffer, or any TypedArray.
+// The output looks like this:
+//    ab034c99
+function bytesToHexString(bytes)
+{
+    if (!bytes)
+        return null;
+
+    bytes = new Uint8Array(bytes);
+    var hexBytes = [];
+
+    for (var i = 0; i < bytes.length; ++i) {
+        var byteString = bytes[i].toString(16);
+        if (byteString.length < 2)
+            byteString = "0" + byteString;
+        hexBytes.push(byteString);
+    }
+
+    return hexBytes.join("");
+}
+
+function bytesToASCIIString(bytes)
+{
+    return String.fromCharCode.apply(null, new Uint8Array(bytes));
+}
+
+var Base64URL = {
+    stringify: function (a) {
+        var base64string = btoa(String.fromCharCode.apply(0, a));
+        return base64string.replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
+    },
+    parse: function (s) {
+        s = s.replace(/-/g, "+").replace(/_/g, "/").replace(/\s/g, '');
+        return new Uint8Array(Array.prototype.map.call(atob(s), function (c) { return c.charCodeAt(0) }));
+    }
+};

Modified: trunk/Source/WebCore/ChangeLog (227381 => 227382)


--- trunk/Source/WebCore/ChangeLog	2018-01-23 02:09:22 UTC (rev 227381)
+++ trunk/Source/WebCore/ChangeLog	2018-01-23 03:00:59 UTC (rev 227382)
@@ -1,3 +1,92 @@
+2018-01-22  Jiewen Tan  <jiewen_...@apple.com>
+
+        [WebAuthN] Implement PublicKeyCredential's [[Create]] with a dummy authenticator
+        https://bugs.webkit.org/show_bug.cgi?id=181928
+        <rdar://problem/36459893>
+
+        Reviewed by Brent Fulgham.
+
+        This patch implements PublicKeyCredential's [[Create]] from https://www.w3.org/TR/webauthn/#createCredential
+        as of 5 December 2017. In order to do testing, a dummy authenticator is implemented to exercise a failure
+        and a pass path. A number of dependencies need to be resolved later in order to comply with the spec.
+        Also, the current architecture of handling async WebAuthN operations including dispatching, timeout, and aborting
+        might need a redesign once the underlying authenticator is clear. Since this is our first attempt to implement
+        a prototype, all those limitations, in my opinion, can be marked as non-blocking to accelerate the whole
+        process. Those limitations will then be addressed once the first prototype is finshed.
+
+        Tests: http/tests/webauthn/public-key-credential-create-with-invalid-parameters.https.html
+               http/tests/webauthn/public-key-credential-same-origin-with-ancestors-2.https.html
+               http/tests/webauthn/public-key-credential-same-origin-with-ancestors.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
+
+        * Modules/credentialmanagement/BasicCredential.h:
+        * Modules/credentialmanagement/BasicCredential.idl:
+        * Modules/credentialmanagement/CredentialsContainer.cpp:
+        (WebCore::CredentialsContainer::PendingPromise::PendingPromise):
+        (WebCore::CredentialsContainer::dispatchTask):
+        (WebCore::CredentialsContainer::get):
+        (WebCore::CredentialsContainer::isCreate):
+        (WebCore::CredentialsContainer::preventSilentAccess const):
+        (WebCore::CredentialsContainer::preventSilentAccess): Deleted.
+        * Modules/credentialmanagement/CredentialsContainer.h:
+        (WebCore::CredentialsContainer::PendingPromise::create):
+        * Modules/webauthn/Authenticator.cpp: Copied from Source/WebCore/Modules/webauthn/AuthenticatorResponse.cpp.
+        (WebCore::Authenticator::singleton):
+        (WebCore::Authenticator::makeCredential const):
+        * Modules/webauthn/Authenticator.h: Copied from Source/WebCore/Modules/webauthn/PublicKeyCredentialCreationOptions.h.
+        * Modules/webauthn/AuthenticatorAssertionResponse.cpp:
+        (WebCore::AuthenticatorAssertionResponse::authenticatorData const):
+        (WebCore::AuthenticatorAssertionResponse::signature const):
+        (WebCore::AuthenticatorAssertionResponse::userHandle const):
+        (WebCore::AuthenticatorAssertionResponse::~AuthenticatorAssertionResponse): Deleted.
+        (WebCore::AuthenticatorAssertionResponse::authenticatorData): Deleted.
+        (WebCore::AuthenticatorAssertionResponse::signature): Deleted.
+        (WebCore::AuthenticatorAssertionResponse::userHandle): Deleted.
+        * Modules/webauthn/AuthenticatorAssertionResponse.h:
+        (WebCore::AuthenticatorAssertionResponse::create):
+        * Modules/webauthn/AuthenticatorAttestationResponse.cpp:
+        (WebCore::AuthenticatorAttestationResponse::attestationObject const):
+        (WebCore::AuthenticatorAttestationResponse::~AuthenticatorAttestationResponse): Deleted.
+        (WebCore::AuthenticatorAttestationResponse::attestationObject): Deleted.
+        * Modules/webauthn/AuthenticatorAttestationResponse.h:
+        (WebCore::AuthenticatorAttestationResponse::create):
+        * Modules/webauthn/AuthenticatorResponse.cpp:
+        (WebCore::AuthenticatorResponse::clientDataJSON const):
+        (WebCore::AuthenticatorResponse::~AuthenticatorResponse): Deleted.
+        (WebCore::AuthenticatorResponse::clientDataJSON): Deleted.
+        * Modules/webauthn/AuthenticatorResponse.h:
+        * Modules/webauthn/AuthenticatorResponse.idl:
+        * Modules/webauthn/PublicKeyCredential.cpp:
+        (WebCore::PublicKeyCredentialInternal::produceClientDataJson):
+        (WebCore::PublicKeyCredentialInternal::produceClientDataJsonHash):
+        (WebCore::PublicKeyCredentialInternal::getIdFromAttestationObject):
+        (WebCore::PublicKeyCredential::PublicKeyCredential):
+        (WebCore::PublicKeyCredential::discoverFromExternalSource):
+        (WebCore::PublicKeyCredential::create):
+        (WebCore::PublicKeyCredential::rawId const):
+        (WebCore::PublicKeyCredential::response const):
+        (WebCore::PublicKeyCredential::getClientExtensionResults const):
+        (WebCore::PublicKeyCredential::rawId): Deleted.
+        (WebCore::PublicKeyCredential::response): Deleted.
+        (WebCore::PublicKeyCredential::getClientExtensionResults): Deleted.
+        * Modules/webauthn/PublicKeyCredential.h:
+        * Modules/webauthn/PublicKeyCredential.idl:
+        * Modules/webauthn/PublicKeyCredentialCreationOptions.h:
+        (): Deleted.
+        * Modules/webauthn/PublicKeyCredentialDescriptor.h:
+        * Modules/webauthn/PublicKeyCredentialDescriptor.idl:
+        * Sources.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        * bindings/js/JSAuthenticatorResponseCustom.cpp: Copied from Source/WebCore/Modules/webauthn/AuthenticatorAttestationResponse.cpp.
+        (WebCore::toJSNewlyCreated):
+        (WebCore::toJS):
+        * bindings/js/JSBasicCredentialCustom.cpp: Copied from Source/WebCore/Modules/webauthn/AuthenticatorResponse.cpp.
+        (WebCore::toJSNewlyCreated):
+        (WebCore::toJS):
+        * bindings/js/JSBindingsAllInOne.cpp:
+
 2018-01-22  Myles C. Maxfield  <mmaxfi...@apple.com>
 
         [Cocoa] Support font collections

Modified: trunk/Source/WebCore/Modules/credentialmanagement/BasicCredential.h (227381 => 227382)


--- trunk/Source/WebCore/Modules/credentialmanagement/BasicCredential.h	2018-01-23 02:09:22 UTC (rev 227381)
+++ trunk/Source/WebCore/Modules/credentialmanagement/BasicCredential.h	2018-01-23 03:00:59 UTC (rev 227382)
@@ -26,6 +26,7 @@
 #pragma once
 
 #include <wtf/ThreadSafeRefCounted.h>
+#include <wtf/TypeCasts.h>
 #include <wtf/text/WTFString.h>
 
 namespace WebCore {
@@ -41,15 +42,15 @@
         Remote,
     };
 
+    BasicCredential(const String&, Type, Discovery);
     virtual ~BasicCredential();
 
+    virtual Type credentialType() const = 0;
+
     const String& id() const { return m_id; }
     String type() const;
     Discovery discovery() const { return m_discovery; }
 
-protected:
-    BasicCredential(const String&, Type, Discovery);
-
 private:
     String m_id;
     Type m_type;
@@ -57,3 +58,8 @@
 };
 
 } // namespace WebCore
+
+#define SPECIALIZE_TYPE_TRAITS_BASIC_CREDENTIAL(ToClassName, Type) \
+SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::ToClassName) \
+    static bool isType(const WebCore::BasicCredential& credential) { return credential.credentialType() == WebCore::Type; } \
+SPECIALIZE_TYPE_TRAITS_END()

Modified: trunk/Source/WebCore/Modules/credentialmanagement/BasicCredential.idl (227381 => 227382)


--- trunk/Source/WebCore/Modules/credentialmanagement/BasicCredential.idl	2018-01-23 02:09:22 UTC (rev 227381)
+++ trunk/Source/WebCore/Modules/credentialmanagement/BasicCredential.idl	2018-01-23 03:00:59 UTC (rev 227382)
@@ -25,6 +25,7 @@
 
 [
     InterfaceName=Credential,
+    CustomToJSObject,
     EnabledAtRuntime=WebAuthentication,
     Exposed=Window,
     SecureContext

Modified: trunk/Source/WebCore/Modules/credentialmanagement/CredentialCreationOptions.h (227381 => 227382)


--- trunk/Source/WebCore/Modules/credentialmanagement/CredentialCreationOptions.h	2018-01-23 02:09:22 UTC (rev 227381)
+++ trunk/Source/WebCore/Modules/credentialmanagement/CredentialCreationOptions.h	2018-01-23 03:00:59 UTC (rev 227382)
@@ -32,8 +32,6 @@
 
 namespace WebCore {
 
-class AbortSignal;
-
 struct CredentialCreationOptions {
     RefPtr<AbortSignal> signal;
     std::optional<PublicKeyCredentialCreationOptions> publicKey;

Modified: trunk/Source/WebCore/Modules/credentialmanagement/CredentialsContainer.cpp (227381 => 227382)


--- trunk/Source/WebCore/Modules/credentialmanagement/CredentialsContainer.cpp	2018-01-23 02:09:22 UTC (rev 227381)
+++ trunk/Source/WebCore/Modules/credentialmanagement/CredentialsContainer.cpp	2018-01-23 03:00:59 UTC (rev 227382)
@@ -35,9 +35,21 @@
 #include "JSBasicCredential.h"
 #include "PublicKeyCredential.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"))
@@ -44,6 +56,8 @@
 {
 }
 
+// The following implements https://w3c.github.io/webappsec-credential-management/#same-origin-with-its-ancestors
+// as of 14 November 2017.
 bool CredentialsContainer::doesHaveSameOriginAsItsAncestors()
 {
     if (!m_document)
@@ -57,21 +71,50 @@
     return true;
 }
 
+// FIXME: 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.
+// https://bugs.webkit.org/show_bug.cgi?id=181946.
+// FIXME: 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.
+// https://bugs.webkit.org/show_bug.cgi?id=181945.
 template<typename OperationType>
-void CredentialsContainer::dispatchTask(OperationType&& operation, Ref<DeferredPromise>&& promise)
+void CredentialsContainer::dispatchTask(OperationType&& operation, Ref<DeferredPromise>&& promise, std::optional<unsigned long> timeOutInMs)
 {
+    ASSERT(isMainThread());
+    if (!m_document)
+        return;
+
     auto* promiseIndex = promise.ptr();
-    m_pendingPromises.add(promiseIndex, WTFMove(promise));
     auto weakThis = m_weakPtrFactory.createWeakPtr(*this);
-    auto task = [promiseIndex, weakThis, isSameOriginWithItsAncestors = doesHaveSameOriginAsItsAncestors(), operation = WTFMove(operation)] () {
-        auto result = operation(isSameOriginWithItsAncestors);
+    // FIXME: We should probably trim timeOutInMs to some max allowable number.
+    // https://bugs.webkit.org/show_bug.cgi?id=181947
+    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()->reject(result.releaseException());
-                    else
-                        promise.value()->resolve<IDLNullable<IDLInterface<BasicCredential>>>(result.releaseReturnValue().get());
+                        promise.value()->promise->reject(result.releaseException());
+                    else {
+                        // FIXME: Got some crazy compile error when I was trying to pass RHS to the resolve method.
+                        RefPtr<BasicCredential> credential = result.releaseReturnValue();
+                        promise.value()->promise->resolve<IDLNullable<IDLInterface<BasicCredential>>>(credential.get());
+                    }
                 }
             }
         });
@@ -99,10 +142,10 @@
         return;
     }
 
-    auto operation = [options = WTFMove(options)] (bool isSameOriginWithItsAncestors) {
-        return PublicKeyCredential::discoverFromExternalSource(options, isSameOriginWithItsAncestors);
+    auto operation = [options = WTFMove(options)] (const SecurityOrigin& origin, bool isSameOriginWithItsAncestors) {
+        return PublicKeyCredential::discoverFromExternalSource(origin, options, isSameOriginWithItsAncestors);
     };
-    dispatchTask(WTFMove(operation), WTFMove(promise));
+    dispatchTask(WTFMove(operation), WTFMove(promise), options.publicKey->timeout);
 }
 
 void CredentialsContainer::store(const BasicCredential&, Ref<DeferredPromise>&& promise)
@@ -112,6 +155,8 @@
 
 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) {
         promise->reject(Exception { NotSupportedError });
@@ -121,23 +166,25 @@
         promise->reject(Exception { AbortError });
         return;
     }
+    // Step 1-2.
     ASSERT(m_document->isSecureContext());
 
-    // This is a shortcut to https://www.w3.org/TR/credential-management-1/#credentialrequestoptions-relevant-credential-interface-objects,
-    // as we only support one kind of credentials.
+    // Step 3-4. Shortcut as we only support one kind of credentials.
     if (!options.publicKey) {
         promise->reject(Exception { NotSupportedError });
         return;
     }
 
-    auto operation = [options = WTFMove(options)] (bool isSameOriginWithItsAncestors) {
+    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(options, isSameOriginWithItsAncestors);
+        return PublicKeyCredential::create(origin, options, isSameOriginWithItsAncestors);
     };
-    dispatchTask(WTFMove(operation), WTFMove(promise));
+    dispatchTask(WTFMove(operation), WTFMove(promise), options.publicKey->timeout);
 }
 
-void CredentialsContainer::preventSilentAccess(Ref<DeferredPromise>&& promise)
+void CredentialsContainer::preventSilentAccess(Ref<DeferredPromise>&& promise) const
 {
     promise->reject(Exception { NotSupportedError });
 }

Modified: trunk/Source/WebCore/Modules/credentialmanagement/CredentialsContainer.h (227381 => 227382)


--- trunk/Source/WebCore/Modules/credentialmanagement/CredentialsContainer.h	2018-01-23 02:09:22 UTC (rev 227381)
+++ trunk/Source/WebCore/Modules/credentialmanagement/CredentialsContainer.h	2018-01-23 03:00:59 UTC (rev 227382)
@@ -27,6 +27,7 @@
 #pragma once
 
 #include "JSDOMPromiseDeferred.h"
+#include "Timer.h"
 #include <wtf/Function.h>
 #include <wtf/RefCounted.h>
 #include <wtf/WeakPtr.h>
@@ -50,7 +51,7 @@
 
     void isCreate(CredentialCreationOptions&&, Ref<DeferredPromise>&&);
 
-    void preventSilentAccess(Ref<DeferredPromise>&&);
+    void preventSilentAccess(Ref<DeferredPromise>&&) const;
 
 private:
     CredentialsContainer(WeakPtr<Document>&&);
@@ -57,12 +58,33 @@
 
     bool doesHaveSameOriginAsItsAncestors();
     template<typename OperationType>
-    void dispatchTask(OperationType&&, Ref<DeferredPromise>&&);
+    void dispatchTask(OperationType&&, Ref<DeferredPromise>&&, std::optional<unsigned long> timeOutInMs = std::nullopt);
 
     WeakPtr<Document> m_document;
-    HashMap<DeferredPromise*, Ref<DeferredPromise>> m_pendingPromises;
     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

Copied: trunk/Source/WebCore/Modules/webauthn/Authenticator.cpp (from rev 227381, trunk/Source/WebCore/Modules/webauthn/AuthenticatorAssertionResponse.cpp) (0 => 227382)


--- trunk/Source/WebCore/Modules/webauthn/Authenticator.cpp	                        (rev 0)
+++ trunk/Source/WebCore/Modules/webauthn/Authenticator.cpp	2018-01-23 03:00:59 UTC (rev 227382)
@@ -0,0 +1,58 @@
+/*
+ * 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"
+
+#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);
+}
+
+} // namespace WebCore

Copied: trunk/Source/WebCore/Modules/webauthn/Authenticator.h (from rev 227381, trunk/Source/WebCore/Modules/webauthn/PublicKeyCredentialCreationOptions.h) (0 => 227382)


--- trunk/Source/WebCore/Modules/webauthn/Authenticator.h	                        (rev 0)
+++ trunk/Source/WebCore/Modules/webauthn/Authenticator.h	2018-01-23 03:00:59 UTC (rev 227382)
@@ -0,0 +1,53 @@
+/*
+ * 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
+
+#include "ExceptionOr.h"
+#include "PublicKeyCredentialCreationOptions.h"
+#include <wtf/Forward.h>
+#include <wtf/Noncopyable.h>
+
+namespace WebCore {
+
+// FIXME: 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:
+    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;
+
+#if !COMPILER(MSVC)
+private:
+#endif
+    Authenticator() = default;
+};
+
+} // namespace WebCore

Modified: trunk/Source/WebCore/Modules/webauthn/AuthenticatorAssertionResponse.cpp (227381 => 227382)


--- trunk/Source/WebCore/Modules/webauthn/AuthenticatorAssertionResponse.cpp	2018-01-23 02:09:22 UTC (rev 227381)
+++ trunk/Source/WebCore/Modules/webauthn/AuthenticatorAssertionResponse.cpp	2018-01-23 03:00:59 UTC (rev 227382)
@@ -36,21 +36,17 @@
 {
 }
 
-AuthenticatorAssertionResponse::~AuthenticatorAssertionResponse()
+ArrayBuffer* AuthenticatorAssertionResponse::authenticatorData() const
 {
-}
-
-ArrayBuffer* AuthenticatorAssertionResponse::authenticatorData()
-{
     return m_authenticatorData.get();
 }
 
-ArrayBuffer* AuthenticatorAssertionResponse::signature()
+ArrayBuffer* AuthenticatorAssertionResponse::signature() const
 {
     return m_signature.get();
 }
 
-ArrayBuffer* AuthenticatorAssertionResponse::userHandle()
+ArrayBuffer* AuthenticatorAssertionResponse::userHandle() const
 {
     return m_userHandle.get();
 }

Modified: trunk/Source/WebCore/Modules/webauthn/AuthenticatorAssertionResponse.h (227381 => 227382)


--- trunk/Source/WebCore/Modules/webauthn/AuthenticatorAssertionResponse.h	2018-01-23 02:09:22 UTC (rev 227381)
+++ trunk/Source/WebCore/Modules/webauthn/AuthenticatorAssertionResponse.h	2018-01-23 03:00:59 UTC (rev 227382)
@@ -31,14 +31,22 @@
 
 class AuthenticatorAssertionResponse : public AuthenticatorResponse {
 public:
+    static Ref<AuthenticatorAssertionResponse> create(RefPtr<ArrayBuffer>&& clientDataJSON, RefPtr<ArrayBuffer>&& authenticatorData, RefPtr<ArrayBuffer>&& signature, RefPtr<ArrayBuffer>&& userHandle)
+    {
+        return adoptRef(*new AuthenticatorAssertionResponse(WTFMove(clientDataJSON), WTFMove(authenticatorData), WTFMove(signature), WTFMove(userHandle)));
+    }
+
+    virtual ~AuthenticatorAssertionResponse() = default;
+
+    ArrayBuffer* authenticatorData() const;
+    ArrayBuffer* signature() const;
+    ArrayBuffer* userHandle() const;
+
+private:
     AuthenticatorAssertionResponse(RefPtr<ArrayBuffer>&& clientDataJSON, RefPtr<ArrayBuffer>&& authenticatorData, RefPtr<ArrayBuffer>&& signature, RefPtr<ArrayBuffer>&& userHandle);
-    virtual ~AuthenticatorAssertionResponse();
 
-    ArrayBuffer* authenticatorData();
-    ArrayBuffer* signature();
-    ArrayBuffer* userHandle();
+    Type type() const final { return Type::Assertion; }
 
-private:
     RefPtr<ArrayBuffer> m_authenticatorData;
     RefPtr<ArrayBuffer> m_signature;
     RefPtr<ArrayBuffer> m_userHandle;
@@ -45,3 +53,5 @@
 };
 
 } // namespace WebCore
+
+SPECIALIZE_TYPE_TRAITS_AUTHENTICATOR_RESPONSE(AuthenticatorAssertionResponse, AuthenticatorResponse::Type::Assertion)

Modified: trunk/Source/WebCore/Modules/webauthn/AuthenticatorAttestationResponse.cpp (227381 => 227382)


--- trunk/Source/WebCore/Modules/webauthn/AuthenticatorAttestationResponse.cpp	2018-01-23 02:09:22 UTC (rev 227381)
+++ trunk/Source/WebCore/Modules/webauthn/AuthenticatorAttestationResponse.cpp	2018-01-23 03:00:59 UTC (rev 227382)
@@ -34,12 +34,8 @@
 {
 }
 
-AuthenticatorAttestationResponse::~AuthenticatorAttestationResponse()
+ArrayBuffer* AuthenticatorAttestationResponse::attestationObject() const
 {
-}
-
-ArrayBuffer* AuthenticatorAttestationResponse::attestationObject()
-{
     return m_attestationObject.get();
 }
 

Modified: trunk/Source/WebCore/Modules/webauthn/AuthenticatorAttestationResponse.h (227381 => 227382)


--- trunk/Source/WebCore/Modules/webauthn/AuthenticatorAttestationResponse.h	2018-01-23 02:09:22 UTC (rev 227381)
+++ trunk/Source/WebCore/Modules/webauthn/AuthenticatorAttestationResponse.h	2018-01-23 03:00:59 UTC (rev 227382)
@@ -31,13 +31,23 @@
 
 class AuthenticatorAttestationResponse : public AuthenticatorResponse {
 public:
+    static Ref<AuthenticatorAttestationResponse> create(RefPtr<ArrayBuffer>&& clientDataJSON, RefPtr<ArrayBuffer>&& attestationObject)
+    {
+        return adoptRef(*new AuthenticatorAttestationResponse(WTFMove(clientDataJSON), WTFMove(attestationObject)));
+    }
+
+    virtual ~AuthenticatorAttestationResponse() = default;
+
+    ArrayBuffer* attestationObject() const;
+
+private:
     AuthenticatorAttestationResponse(RefPtr<ArrayBuffer>&& clientDataJSON, RefPtr<ArrayBuffer>&& attestationObject);
-    virtual ~AuthenticatorAttestationResponse();
 
-    ArrayBuffer* attestationObject();
+    Type type() const final { return Type::Attestation; }
 
-private:
     RefPtr<ArrayBuffer> m_attestationObject;
 };
 
 } // namespace WebCore
+
+SPECIALIZE_TYPE_TRAITS_AUTHENTICATOR_RESPONSE(AuthenticatorAttestationResponse, AuthenticatorResponse::Type::Attestation)

Modified: trunk/Source/WebCore/Modules/webauthn/AuthenticatorResponse.cpp (227381 => 227382)


--- trunk/Source/WebCore/Modules/webauthn/AuthenticatorResponse.cpp	2018-01-23 02:09:22 UTC (rev 227381)
+++ trunk/Source/WebCore/Modules/webauthn/AuthenticatorResponse.cpp	2018-01-23 03:00:59 UTC (rev 227382)
@@ -33,12 +33,8 @@
 {
 }
 
-AuthenticatorResponse::~AuthenticatorResponse()
+ArrayBuffer* AuthenticatorResponse::clientDataJSON() const
 {
-}
-
-ArrayBuffer* AuthenticatorResponse::clientDataJSON()
-{
     return m_clientDataJSON.get();
 }
 

Modified: trunk/Source/WebCore/Modules/webauthn/AuthenticatorResponse.h (227381 => 227382)


--- trunk/Source/WebCore/Modules/webauthn/AuthenticatorResponse.h	2018-01-23 02:09:22 UTC (rev 227381)
+++ trunk/Source/WebCore/Modules/webauthn/AuthenticatorResponse.h	2018-01-23 03:00:59 UTC (rev 227382)
@@ -27,18 +27,31 @@
 
 #include <runtime/ArrayBuffer.h>
 #include <wtf/ThreadSafeRefCounted.h>
+#include <wtf/TypeCasts.h>
 
 namespace WebCore {
 
 class AuthenticatorResponse : public ThreadSafeRefCounted<AuthenticatorResponse> {
 public:
+    enum class Type {
+        Assertion,
+        Attestation
+    };
+
     explicit AuthenticatorResponse(RefPtr<ArrayBuffer>&&);
-    virtual ~AuthenticatorResponse();
+    virtual ~AuthenticatorResponse() = default;
 
-    ArrayBuffer* clientDataJSON();
+    virtual Type type() const = 0;
 
+    ArrayBuffer* clientDataJSON() const;
+
 private:
     RefPtr<ArrayBuffer> m_clientDataJSON;
 };
 
 } // namespace WebCore
+
+#define SPECIALIZE_TYPE_TRAITS_AUTHENTICATOR_RESPONSE(ToClassName, Type) \
+SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::ToClassName) \
+    static bool isType(const WebCore::AuthenticatorResponse& response) { return response.type() == WebCore::Type; } \
+SPECIALIZE_TYPE_TRAITS_END()

Modified: trunk/Source/WebCore/Modules/webauthn/AuthenticatorResponse.idl (227381 => 227382)


--- trunk/Source/WebCore/Modules/webauthn/AuthenticatorResponse.idl	2018-01-23 02:09:22 UTC (rev 227381)
+++ trunk/Source/WebCore/Modules/webauthn/AuthenticatorResponse.idl	2018-01-23 03:00:59 UTC (rev 227382)
@@ -24,6 +24,7 @@
  */
 
 [
+    CustomToJSObject,
     EnabledAtRuntime=WebAuthentication,
     Exposed=Window,
     SecureContext,

Modified: trunk/Source/WebCore/Modules/webauthn/PublicKeyCredential.cpp (227381 => 227382)


--- trunk/Source/WebCore/Modules/webauthn/PublicKeyCredential.cpp	2018-01-23 02:09:22 UTC (rev 227381)
+++ trunk/Source/WebCore/Modules/webauthn/PublicKeyCredential.cpp	2018-01-23 03:00:59 UTC (rev 227382)
@@ -26,21 +26,86 @@
 #include "config.h"
 #include "PublicKeyCredential.h"
 
+#include "Authenticator.h"
+#include "AuthenticatorResponse.h"
+#include "CredentialCreationOptions.h"
 #include "JSDOMPromiseDeferred.h"
+#include "SecurityOrigin.h"
+#include <pal/crypto/CryptoDigest.h>
+#include <wtf/CurrentTime.h>
+#include <wtf/JSONValues.h>
+#include <wtf/text/Base64.h>
 
 namespace WebCore {
 
-PublicKeyCredential::PublicKeyCredential(const String& id)
-    : BasicCredential(id, Type::PublicKey, Discovery::Remote)
+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: Add token binding ID and extensions.
+// https://bugs.webkit.org/show_bug.cgi?id=181948
+// https://bugs.webkit.org/show_bug.cgi?id=181949
+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))
+    , m_response(WTFMove(response))
+{
+}
+
 Vector<Ref<BasicCredential>> PublicKeyCredential::collectFromCredentialStore(CredentialRequestOptions&&, bool)
 {
     return { };
 }
 
-ExceptionOr<RefPtr<BasicCredential>> PublicKeyCredential::discoverFromExternalSource(const CredentialRequestOptions&, bool)
+ExceptionOr<RefPtr<BasicCredential>> PublicKeyCredential::discoverFromExternalSource(const SecurityOrigin&, const CredentialRequestOptions&, bool)
 {
     return Exception { NotSupportedError };
 }
@@ -50,22 +115,66 @@
     return nullptr;
 }
 
-ExceptionOr<RefPtr<BasicCredential>> PublicKeyCredential::create(const CredentialCreationOptions&, bool)
+ExceptionOr<RefPtr<BasicCredential>> PublicKeyCredential::create(const SecurityOrigin& callerOrigin, const PublicKeyCredentialCreationOptions& options, bool sameOriginWithAncestors)
 {
-    return Exception { NotSupportedError };
+    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, 17 are handled by the caller, including options sanitizing, timer and abort signal.
+    // Step 2.
+    if (!sameOriginWithAncestors)
+        return Exception { NotAllowedError };
+
+    // Step 5-7.
+    // FIXME: 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.
+    // https://bugs.webkit.org/show_bug.cgi?id=181950
+    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: The following operation might need to perform async.
+    // https://bugs.webkit.org/show_bug.cgi?id=181946
+    auto result = Authenticator::singleton().makeCredential(clientDataJsonHash, options.rp, options.user, options.pubKeyCredParams, options.excludeCredentials);
+    if (result.hasException())
+        return result.releaseException();
+
+    auto attestationObject = result.releaseReturnValue();
+    // FIXME: Got some crazy compile error when I was trying to return RHS directly.
+    RefPtr<BasicCredential> credential = PublicKeyCredential::create(getIdFromAttestationObject(attestationObject), AuthenticatorAttestationResponse::create(WTFMove(clientDataJson), ArrayBuffer::create(attestationObject.data(), attestationObject.size())));
+    return WTFMove(credential);
 }
 
-ArrayBuffer* PublicKeyCredential::rawId()
+ArrayBuffer* PublicKeyCredential::rawId() const
 {
     return m_rawId.get();
 }
 
-AuthenticatorResponse* PublicKeyCredential::response()
+AuthenticatorResponse* PublicKeyCredential::response() const
 {
     return m_response.get();
 }
 
-ExceptionOr<bool> PublicKeyCredential::getClientExtensionResults()
+ExceptionOr<bool> PublicKeyCredential::getClientExtensionResults() const
 {
     return Exception { NotSupportedError };
 }

Modified: trunk/Source/WebCore/Modules/webauthn/PublicKeyCredential.h (227381 => 227382)


--- trunk/Source/WebCore/Modules/webauthn/PublicKeyCredential.h	2018-01-23 02:09:22 UTC (rev 227381)
+++ trunk/Source/WebCore/Modules/webauthn/PublicKeyCredential.h	2018-01-23 03:00:59 UTC (rev 227382)
@@ -34,34 +34,39 @@
 
 class AuthenticatorResponse;
 class DeferredPromise;
+class SecurityOrigin;
 
-struct CredentialCreationOptions;
+struct PublicKeyCredentialCreationOptions;
 struct CredentialRequestOptions;
 
 class PublicKeyCredential final : public BasicCredential {
 public:
-    static Ref<PublicKeyCredential> create(const String& id)
+    static Ref<PublicKeyCredential> create(RefPtr<ArrayBuffer>&& id, RefPtr<AuthenticatorResponse>&& response)
     {
-        return adoptRef(*new PublicKeyCredential(id));
+        return adoptRef(*new PublicKeyCredential(WTFMove(id), WTFMove(response)));
     }
 
     static Vector<Ref<BasicCredential>> collectFromCredentialStore(CredentialRequestOptions&&, bool);
-    static ExceptionOr<RefPtr<BasicCredential>> discoverFromExternalSource(const CredentialRequestOptions&, bool);
+    static ExceptionOr<RefPtr<BasicCredential>> discoverFromExternalSource(const SecurityOrigin&, const CredentialRequestOptions&, bool sameOriginWithAncestors);
     static RefPtr<BasicCredential> store(RefPtr<BasicCredential>&&, bool);
-    static ExceptionOr<RefPtr<BasicCredential>> create(const CredentialCreationOptions&, bool);
+    static ExceptionOr<RefPtr<BasicCredential>> create(const SecurityOrigin&, const PublicKeyCredentialCreationOptions&, bool sameOriginWithAncestors);
 
-    ArrayBuffer* rawId();
-    AuthenticatorResponse* response();
+    ArrayBuffer* rawId() const;
+    AuthenticatorResponse* response() const;
     // Not support yet. Always throws.
-    ExceptionOr<bool> getClientExtensionResults();
+    ExceptionOr<bool> getClientExtensionResults() const;
 
     static void isUserVerifyingPlatformAuthenticatorAvailable(Ref<DeferredPromise>&&);
 
 private:
-    PublicKeyCredential(const String&);
+    PublicKeyCredential(RefPtr<ArrayBuffer>&& id, RefPtr<AuthenticatorResponse>&&);
 
+    Type credentialType() const final { return Type::PublicKey; }
+
     RefPtr<ArrayBuffer> m_rawId;
     RefPtr<AuthenticatorResponse> m_response;
 };
 
 } // namespace WebCore
+
+SPECIALIZE_TYPE_TRAITS_BASIC_CREDENTIAL(PublicKeyCredential, BasicCredential::Type::PublicKey)

Modified: trunk/Source/WebCore/Modules/webauthn/PublicKeyCredential.idl (227381 => 227382)


--- trunk/Source/WebCore/Modules/webauthn/PublicKeyCredential.idl	2018-01-23 02:09:22 UTC (rev 227381)
+++ trunk/Source/WebCore/Modules/webauthn/PublicKeyCredential.idl	2018-01-23 03:00:59 UTC (rev 227382)
@@ -29,7 +29,7 @@
     EnabledAtRuntime=WebAuthentication,
     Exposed=Window,
     SecureContext,
-] interface PublicKeyCredential {
+] interface PublicKeyCredential : BasicCredential {
     [SameObject] readonly attribute ArrayBuffer rawId;
     [SameObject] readonly attribute AuthenticatorResponse response;
     [MayThrowException] AuthenticationExtensions getClientExtensionResults();

Modified: trunk/Source/WebCore/Modules/webauthn/PublicKeyCredentialCreationOptions.h (227381 => 227382)


--- trunk/Source/WebCore/Modules/webauthn/PublicKeyCredentialCreationOptions.h	2018-01-23 02:09:22 UTC (rev 227381)
+++ trunk/Source/WebCore/Modules/webauthn/PublicKeyCredentialCreationOptions.h	2018-01-23 03:00:59 UTC (rev 227382)
@@ -39,7 +39,7 @@
     };
 
     struct RpEntity : public Entity {
-        String id;
+        mutable String id;
     };
 
     struct UserEntity : public Entity {
@@ -49,7 +49,7 @@
 
     struct Parameters {
         PublicKeyCredentialType type;
-        long alg { 0 };
+        long alg;
     };
 
     RpEntity rp;
@@ -58,7 +58,7 @@
     BufferSource challenge;
     Vector<Parameters> pubKeyCredParams;
 
-    unsigned long timeout { 0 };
+    std::optional<unsigned long> timeout;
     Vector<PublicKeyCredentialDescriptor> excludeCredentials;
 };
 

Modified: trunk/Source/WebCore/Modules/webauthn/PublicKeyCredentialDescriptor.h (227381 => 227382)


--- trunk/Source/WebCore/Modules/webauthn/PublicKeyCredentialDescriptor.h	2018-01-23 02:09:22 UTC (rev 227381)
+++ trunk/Source/WebCore/Modules/webauthn/PublicKeyCredentialDescriptor.h	2018-01-23 03:00:59 UTC (rev 227382)
@@ -31,8 +31,15 @@
 namespace WebCore {
 
 struct PublicKeyCredentialDescriptor {
+    enum class AuthenticatorTransport {
+        Usb,
+        Nfc,
+        Ble
+    };
+
     PublicKeyCredentialType type;
     BufferSource id;
+    Vector<AuthenticatorTransport> transports;
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/Modules/webauthn/PublicKeyCredentialDescriptor.idl (227381 => 227382)


--- trunk/Source/WebCore/Modules/webauthn/PublicKeyCredentialDescriptor.idl	2018-01-23 02:09:22 UTC (rev 227381)
+++ trunk/Source/WebCore/Modules/webauthn/PublicKeyCredentialDescriptor.idl	2018-01-23 03:00:59 UTC (rev 227382)
@@ -23,9 +23,14 @@
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+enum AuthenticatorTransport {
+    "usb",
+    "nfc",
+    "ble"
+};
+
 dictionary PublicKeyCredentialDescriptor {
     required PublicKeyCredentialType type;
     required BufferSource id;
-    // We only allow platform attachment at this stage.
-    // sequence<AuthenticatorTransport> transports;
+    sequence<AuthenticatorTransport> transports;
 };

Modified: trunk/Source/WebCore/Sources.txt (227381 => 227382)


--- trunk/Source/WebCore/Sources.txt	2018-01-23 02:09:22 UTC (rev 227381)
+++ trunk/Source/WebCore/Sources.txt	2018-01-23 03:00:59 UTC (rev 227382)
@@ -244,6 +244,7 @@
 Modules/webaudio/WaveShaperNode.cpp
 Modules/webaudio/WaveShaperProcessor.cpp
 
+Modules/webauthn/Authenticator.cpp
 Modules/webauthn/AuthenticatorAssertionResponse.cpp
 Modules/webauthn/AuthenticatorAttestationResponse.cpp
 Modules/webauthn/AuthenticatorResponse.cpp
@@ -345,11 +346,13 @@
 bindings/js/DOMWrapperWorld.cpp
 bindings/js/GCController.cpp
 bindings/js/IDBBindingUtilities.cpp
+bindings/js/JSAuthenticatorResponseCustom.cpp
 bindings/js/JSAnimationEffectCustom.cpp
 bindings/js/JSAnimationTimelineCustom.cpp
 bindings/js/JSAttrCustom.cpp
 bindings/js/JSAudioTrackCustom.cpp
 bindings/js/JSAudioTrackListCustom.cpp
+bindings/js/JSBasicCredentialCustom.cpp
 bindings/js/JSBlobCustom.cpp
 bindings/js/JSCSSRuleCustom.cpp
 bindings/js/JSCSSRuleListCustom.cpp

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (227381 => 227382)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2018-01-23 02:09:22 UTC (rev 227381)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2018-01-23 03:00:59 UTC (rev 227382)
@@ -1663,6 +1663,7 @@
 		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 */; };
 		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 */; };
@@ -8236,6 +8237,8 @@
 		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>"; };
 		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>"; };
@@ -8252,6 +8255,8 @@
 		5750A9851E6A216800705C4A /* CryptoAlgorithmECDH.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CryptoAlgorithmECDH.h; sourceTree = "<group>"; };
 		575471991ECE5D2A00DD63B2 /* JSRsaPssParams.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSRsaPssParams.h; 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>"; };
 		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>"; };
@@ -18200,6 +18205,8 @@
 			isa = PBXGroup;
 			children = (
 				57303BB32006C6ED00355965 /* cbor */,
+				57303C4420105B3D00355965 /* Authenticator.cpp */,
+				57303C4320105B3D00355965 /* Authenticator.h */,
 				57303C282009B2FC00355965 /* AuthenticatorAssertionResponse.cpp */,
 				57303C272009B2FC00355965 /* AuthenticatorAssertionResponse.h */,
 				57303C292009B2FC00355965 /* AuthenticatorAssertionResponse.idl */,
@@ -19248,6 +19255,8 @@
 				BC2ED6BB0C6BD2F000920BFF /* JSAttrCustom.cpp */,
 				BE6DF70E171CA2DA00DD52B8 /* JSAudioTrackCustom.cpp */,
 				BE6DF710171CA2DA00DD52B8 /* JSAudioTrackListCustom.cpp */,
+				576082562011BE0200116678 /* JSAuthenticatorResponseCustom.cpp */,
+				5760824F20118D8D00116678 /* JSBasicCredentialCustom.cpp */,
 				8931DE5A14C44C44000DC9D2 /* JSBlobCustom.cpp */,
 				49EED14B1051971900099FAB /* JSCanvasRenderingContext2DCustom.cpp */,
 				BC46C1ED0C0DDBDF0020CFC3 /* JSCSSRuleCustom.cpp */,
@@ -26523,6 +26532,7 @@
 				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 */,
 				57303BD220087A8300355965 /* AuthenticatorResponse.h in Headers */,

Copied: trunk/Source/WebCore/bindings/js/JSAuthenticatorResponseCustom.cpp (from rev 227381, trunk/Source/WebCore/Modules/webauthn/AuthenticatorAttestationResponse.cpp) (0 => 227382)


--- trunk/Source/WebCore/bindings/js/JSAuthenticatorResponseCustom.cpp	                        (rev 0)
+++ trunk/Source/WebCore/bindings/js/JSAuthenticatorResponseCustom.cpp	2018-01-23 03:00:59 UTC (rev 227382)
@@ -0,0 +1,47 @@
+/*
+ * 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 "JSAuthenticatorResponse.h"
+
+#include "JSAuthenticatorAttestationResponse.h"
+#include "JSDOMBinding.h"
+
+namespace WebCore {
+using namespace JSC;
+
+JSValue toJSNewlyCreated(JSC::ExecState*, JSDOMGlobalObject* globalObject, Ref<AuthenticatorResponse>&& response)
+{
+    if (is<AuthenticatorAttestationResponse>(response))
+        return createWrapper<AuthenticatorAttestationResponse>(globalObject, WTFMove(response));
+    return createWrapper<AuthenticatorResponse>(globalObject, WTFMove(response));
+}
+
+JSValue toJS(ExecState* state, JSDOMGlobalObject* globalObject, AuthenticatorResponse& response)
+{
+    return wrap(state, globalObject, response);
+}
+
+} // namespace WebCore

Copied: trunk/Source/WebCore/bindings/js/JSBasicCredentialCustom.cpp (from rev 227381, trunk/Source/WebCore/Modules/webauthn/AuthenticatorResponse.cpp) (0 => 227382)


--- trunk/Source/WebCore/bindings/js/JSBasicCredentialCustom.cpp	                        (rev 0)
+++ trunk/Source/WebCore/bindings/js/JSBasicCredentialCustom.cpp	2018-01-23 03:00:59 UTC (rev 227382)
@@ -0,0 +1,48 @@
+/*
+ * 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 "JSBasicCredential.h"
+
+#include "JSDOMBinding.h"
+#include "JSPublicKeyCredential.h"
+
+
+namespace WebCore {
+using namespace JSC;
+
+JSValue toJSNewlyCreated(JSC::ExecState*, JSDOMGlobalObject* globalObject, Ref<BasicCredential>&& credential)
+{
+    if (is<PublicKeyCredential>(credential))
+        return createWrapper<PublicKeyCredential>(globalObject, WTFMove(credential));
+    return createWrapper<BasicCredential>(globalObject, WTFMove(credential));
+}
+
+JSValue toJS(ExecState* state, JSDOMGlobalObject* globalObject, BasicCredential& credential)
+{
+    return wrap(state, globalObject, credential);
+}
+
+} // namespace WebCore

Modified: trunk/Source/WebCore/bindings/js/JSBindingsAllInOne.cpp (227381 => 227382)


--- trunk/Source/WebCore/bindings/js/JSBindingsAllInOne.cpp	2018-01-23 02:09:22 UTC (rev 227381)
+++ trunk/Source/WebCore/bindings/js/JSBindingsAllInOne.cpp	2018-01-23 03:00:59 UTC (rev 227382)
@@ -32,6 +32,7 @@
 #include "JSAttrCustom.cpp"
 #include "JSAudioTrackCustom.cpp"
 #include "JSAudioTrackListCustom.cpp"
+#include "JSBasicCredentialCustom.cpp"
 #include "JSBlobCustom.cpp"
 #include "JSCSSRuleCustom.cpp"
 #include "JSCSSRuleListCustom.cpp"

Modified: trunk/Source/WebCore/bindings/js/JSExtendableMessageEventCustom.cpp (227381 => 227382)


--- trunk/Source/WebCore/bindings/js/JSExtendableMessageEventCustom.cpp	2018-01-23 02:09:22 UTC (rev 227381)
+++ trunk/Source/WebCore/bindings/js/JSExtendableMessageEventCustom.cpp	2018-01-23 03:00:59 UTC (rev 227382)
@@ -29,6 +29,7 @@
 #include "JSExtendableMessageEvent.h"
 
 #include "JSDOMConstructor.h"
+#include "JSDOMConvertStrings.h"
 
 namespace WebCore {
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to