Skip to content

Commit

Permalink
[Digital Identity]: navigator.identity should be implemented by a sep…
Browse files Browse the repository at this point in the history
…arate IdentityCredentialManager

https://bugs.webkit.org/show_bug.cgi?id=269165
rdar://123184696

Reviewed by Andy Estes.

Implements IdentityCredentialsContainer on top of CredentialsContainer by
virtualizing some of the methods of CredentialsContainer.

For IdentityCredentialsContainer, we implement the logic for:

 * navigator.identity.get()
 * navigator.identity.create() - Default to just return null.

And we defer the logic for the following to CredentialsContainer:
 * navigator.identity.store() - which just rejects with a NotSupportedError.

Adds performCommonChecks() to CredentialsContainer to DRY up the code,
and so that we can use it in IdentityCredentialsContainer.

And the DigitalCredentialsEnable preference is now set to "testable".

* LayoutTests/http/wpt/identity/identitycredentialscontainer-get-basics.https-expected.txt: Added.
* LayoutTests/http/wpt/identity/identitycredentialscontainer-get-basics.https.html: Added.
* LayoutTests/http/wpt/identity/identtycredentialscontainer-create-basics.https-expected.txt: Added.
* LayoutTests/http/wpt/identity/identtycredentialscontainer-create-basics.https.html: Added.
* LayoutTests/http/wpt/identity/identtycredentialscontainer-store-basics.https-expected.txt: Added.
* LayoutTests/http/wpt/identity/identtycredentialscontainer-store-basics.https.html: Added.
* LayoutTests/http/wpt/identity/idl.https-expected.txt: Added.
* LayoutTests/http/wpt/identity/idl.https.html: Added.
* LayoutTests/http/wpt/identity/setDigitalCredentialsEnable.https.html:
* LayoutTests/platform/mac-wk2/fast/dom/navigator-detached-no-crash-expected.txt:
* Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml:
* Source/WebCore/Modules/credentialmanagement/CredentialRequestOptions.h:
* Source/WebCore/Modules/credentialmanagement/CredentialsContainer.cpp:
(WebCore::CredentialsContainer::get):
(WebCore::CredentialsContainer::isCreate):
(WebCore::CredentialsContainer::performCommonChecks):
* Source/WebCore/Modules/credentialmanagement/CredentialsContainer.h:
(WebCore::CredentialsContainer::create):
* Source/WebCore/Modules/credentialmanagement/CredentialsContainer.idl:
* Source/WebCore/Modules/identity/IdentityCredentialsContainer.cpp: Added.
(WebCore::IdentityCredentialsContainer::IdentityCredentialsContainer):
(WebCore::IdentityCredentialsContainer::get):
(WebCore::IdentityCredentialsContainer::isCreate):
* Source/WebCore/Modules/identity/IdentityCredentialsContainer.h: Copied from Source/WebCore/Modules/identity/NavigatorIdentity.h.
* Source/WebCore/Modules/identity/NavigatorIdentity.cpp:
(WebCore::NavigatorIdentity::identity):
* Source/WebCore/Modules/identity/NavigatorIdentity.h:
* Source/WebCore/Modules/model-element/ModelPlayerClient.h:
* Source/WebCore/Sources.txt:
* Source/WebCore/WebCore.xcodeproj/project.pbxproj:
* Source/WebCore/bindings/js/WebCoreBuiltinNames.h:
* Tools/DumpRenderTree/TestOptions.cpp:
(WTR::TestOptions::defaults):

Canonical link: https://commits.webkit.org/275939@main
  • Loading branch information
marcoscaceres committed Mar 11, 2024
1 parent ba17ce2 commit 2dbfef3
Show file tree
Hide file tree
Showing 23 changed files with 562 additions and 69 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

PASS navigator.identity.get() default behavior checks.

Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<!DOCTYPE html>
<title>Digital Credential API: get() default behavior checks.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
promise_test(async (t) => {
await promise_rejects_dom(
t,
"NotSupportedError",
navigator.identity.get(),
"navigator.identity.get() with no argument."
);

await promise_rejects_dom(
t,
"NotSupportedError",
navigator.identity.get({}),
"navigator.identity.get() with empty dictionary."
);

await promise_rejects_js(
t,
TypeError,
navigator.identity.get({ digital: "wrong type" }),
"navigator.identity.get() with bogus digital type"
);

await promise_rejects_dom(
t,
"NotSupportedError",
navigator.identity.get({ bogus_key: "bogus" }),
"navigator.identity.get() with unknown key (same as passing empty dictionary)."
);

await promise_rejects_js(
t,
TypeError,
navigator.identity.get({ digital: { providers: [] } }),
"navigator.identity.get() with an empty list of providers"
);

await promise_rejects_js(
t,
TypeError,
navigator.identity.get({
digital: { providers: [{ protocol: "bogus protocol" }] },
}),
"navigator.identity.get() with a provider with unknown protocol"
);

const controller = new AbortController();
const options = { signal: controller.signal };

controller.abort();
await promise_rejects_dom(
t,
"AbortError",
navigator.identity.get(options),
"navigator.identity.get() with abort signal set"
);

assert_equals(
await navigator.identity.get({
digital: { providers: [{ protocol: "mdoc" }] },
}),
null,
"navigator.identity.get() with a valid provider"
);
}, "navigator.identity.get() default behavior checks.");
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

PASS create() checks.
PASS Interaction with Web Authn API.

Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<!DOCTYPE html>
<title>Digital Credentials API: create() default behavior checks.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
promise_test(async (t) => {
await assert_equals(
await navigator.identity.create(),
null,
"No argument defaults be null."
);

await assert_equals(
await navigator.identity.create({}),
null,
"Empty dictionary defaults be null."
);

await assert_equals(
await navigator.identity.create({ identity: "bogus data" }),
null,
"The identity member is not part of CredentialCreationOptions, so defaults be null."
);

const controller = new AbortController();
controller.abort();
await promise_rejects_dom(
t,
"AbortError",
navigator.identity.create({ signal: controller.signal }),
"create() with abort signal set that was already aborted."
);
}, "create() checks.");

promise_test(async (t)=>{
await promise_rejects_js(
t,
TypeError,
navigator.identity.create({ publicKey: "bogus data" }),
"The Digital Credential API knows about public key."
);
}, "Interaction with Web Authn API.")
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

PASS navigator.credentials.store() basic behavior.

Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<!DOCTYPE html>
<title>Digital Credential API: store() basics.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
const testCreationMessageBase64 =
"AKMBZnBhY2tlZAJYxEbMf7lnnVWy25CS4cjZ5eHQK3WA8LSBLHcJYuHkj1rYQQAA" +
"AE74oBHzjApNFYAGFxEfntx9AEAoCK3O6P5OyXN6V/f+9nAga0NA2Cgp4V3mgSJ5" +
"jOHLMDrmxp/S0rbD+aihru1C0aAN3BkiM6GNy5nSlDVqOgTgpQECAyYgASFYIEFb" +
"he3RkNud6sgyraBGjlh1pzTlCZehQlL/b18HZ6WGIlggJgfUd/en9p5AIqMQbUni" +
"nEeXdFLkvW0/zV5BpEjjNxADo2NhbGcmY3NpZ1hHMEUCIQDKg+ZBmEBtf0lWq4Re" +
"dH4/i/LOYqOR4uR2NAj2zQmw9QIgbTXb4hvFbj4T27bv/rGrc+y+0puoYOBkBk9P" +
"mCewWlNjeDVjgVkCwjCCAr4wggGmoAMCAQICBHSG/cIwDQYJKoZIhvcNAQELBQAw" +
"LjEsMCoGA1UEAxMjWXViaWNvIFUyRiBSb290IENBIFNlcmlhbCA0NTcyMDA2MzEw" +
"IBcNMTQwODAxMDAwMDAwWhgPMjA1MDA5MDQwMDAwMDBaMG8xCzAJBgNVBAYTAlNF" +
"MRIwEAYDVQQKDAlZdWJpY28gQUIxIjAgBgNVBAsMGUF1dGhlbnRpY2F0b3IgQXR0" +
"ZXN0YXRpb24xKDAmBgNVBAMMH1l1YmljbyBVMkYgRUUgU2VyaWFsIDE5NTUwMDM4" +
"NDIwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASVXfOt9yR9MXXv/ZzE8xpOh466" +
"4YEJVmFQ+ziLLl9lJ79XQJqlgaUNCsUvGERcChNUihNTyKTlmnBOUjvATevto2ww" +
"ajAiBgkrBgEEAYLECgIEFTEuMy42LjEuNC4xLjQxNDgyLjEuMTATBgsrBgEEAYLl" +
"HAIBAQQEAwIFIDAhBgsrBgEEAYLlHAEBBAQSBBD4oBHzjApNFYAGFxEfntx9MAwG" +
"A1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggEBADFcSIDmmlJ+OGaJvWn9Cqhv" +
"SeueToVFQVVvqtALOgCKHdwB+Wx29mg2GpHiMsgQp5xjB0ybbnpG6x212FxESJ+G" +
"inZD0ipchi7APwPlhIvjgH16zVX44a4e4hOsc6tLIOP71SaMsHuHgCcdH0vg5d2s" +
"c006WJe9TXO6fzV+ogjJnYpNKQLmCXoAXE3JBNwKGBIOCvfQDPyWmiiG5bGxYfPt" +
"y8Z3pnjX+1MDnM2hhr40ulMxlSNDnX/ZSnDyMGIbk8TOQmjTF02UO8auP8k3wt5D" +
"1rROIRU9+FCSX5WQYi68RuDrGMZB8P5+byoJqbKQdxn2LmE1oZAyohPAmLcoPO4=";

promise_test(async (t) => {
const options = {
publicKey: {
rp: {
name: "localhost",
},
user: {
name: "John Appleseed",
id: new Uint8Array(16),
displayName: "Appleseed",
},
challenge: new Uint8Array(16),
pubKeyCredParams: [{ type: "public-key", alg: -7 }],
},
};

// A mock attestation object
internals.setMockWebAuthenticationConfiguration({
hid: {
stage: "request",
subStage: "msg",
error: "success",
payloadBase64: [testCreationMessageBase64],
},
});

const credential = await navigator.credentials.create(options);

await promise_rejects_dom(
t,
"NotSupportedError",
navigator.identity.store(credential),
"Trying to store a web authn credential is not supported."
);
}, "navigator.credentials.store() basic behavior.");
</script>
88 changes: 88 additions & 0 deletions LayoutTests/http/wpt/identity/idl.https-expected.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@

PASS idl_test setup
PASS idl_test validation
PASS Partial interface Navigator: original interface defined
PASS Partial interface Navigator: member names are unique
PASS Partial dictionary CredentialRequestOptions: original dictionary defined
PASS Partial dictionary CredentialRequestOptions: member names are unique
PASS Partial dictionary CredentialCreationOptions: original dictionary defined
PASS Partial dictionary CredentialCreationOptions: member names are unique
PASS Partial dictionary CredentialRequestOptions[2]: original dictionary defined
PASS Partial dictionary CredentialRequestOptions[2]: member names are unique
PASS Partial dictionary CredentialCreationOptions[2]: original dictionary defined
PASS Partial dictionary CredentialCreationOptions[2]: member names are unique
PASS Partial interface mixin NavigatorID: member names are unique
PASS Partial interface Navigator[2]: original interface defined
PASS Partial interface Navigator[2]: member names are unique
PASS Partial dictionary CredentialRequestOptions[3]: original dictionary defined
PASS Partial dictionary CredentialRequestOptions[3]: member names are unique
PASS PasswordCredential includes CredentialUserData: member names are unique
PASS FederatedCredential includes CredentialUserData: member names are unique
PASS HTMLElement includes GlobalEventHandlers: member names are unique
PASS HTMLElement includes DocumentAndElementEventHandlers: member names are unique
PASS HTMLElement includes ElementContentEditable: member names are unique
PASS HTMLElement includes HTMLOrSVGElement: member names are unique
PASS Navigator includes NavigatorID: member names are unique
PASS Navigator includes NavigatorLanguage: member names are unique
PASS Navigator includes NavigatorOnLine: member names are unique
PASS Navigator includes NavigatorContentUtils: member names are unique
PASS Navigator includes NavigatorCookies: member names are unique
PASS Navigator includes NavigatorPlugins: member names are unique
PASS Navigator includes NavigatorConcurrentHardware: member names are unique
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: existence and properties of interface prototype object's @@unscopables property
PASS Credential interface: attribute id
PASS Credential interface: attribute type
PASS CredentialsContainer interface: existence and properties of interface object
PASS CredentialsContainer interface object length
PASS CredentialsContainer interface object name
PASS CredentialsContainer interface: existence and properties of interface prototype object
PASS CredentialsContainer interface: existence and properties of interface prototype object's "constructor" property
PASS CredentialsContainer interface: existence and properties of interface prototype object's @@unscopables property
PASS CredentialsContainer interface: operation get(optional CredentialRequestOptions)
PASS CredentialsContainer interface: operation store(Credential)
PASS CredentialsContainer interface: operation create(optional CredentialCreationOptions)
PASS CredentialsContainer interface: operation preventSilentAccess()
PASS CredentialsContainer must be primary interface of navigator.identity
PASS Stringification of navigator.identity
PASS CredentialsContainer interface: navigator.identity must inherit property "get(optional CredentialRequestOptions)" with the proper type
PASS CredentialsContainer interface: calling get(optional CredentialRequestOptions) on navigator.identity with too few arguments must throw TypeError
PASS CredentialsContainer interface: navigator.identity must inherit property "store(Credential)" with the proper type
PASS CredentialsContainer interface: calling store(Credential) on navigator.identity with too few arguments must throw TypeError
PASS CredentialsContainer interface: navigator.identity must inherit property "create(optional CredentialCreationOptions)" with the proper type
PASS CredentialsContainer interface: calling create(optional CredentialCreationOptions) on navigator.identity with too few arguments must throw TypeError
PASS CredentialsContainer interface: navigator.identity must inherit property "preventSilentAccess()" with the proper type
FAIL PasswordCredential interface: existence and properties of interface object assert_own_property: self does not have own property "PasswordCredential" expected property "PasswordCredential" missing
FAIL PasswordCredential interface object length assert_own_property: self does not have own property "PasswordCredential" expected property "PasswordCredential" missing
FAIL PasswordCredential interface object name assert_own_property: self does not have own property "PasswordCredential" expected property "PasswordCredential" missing
FAIL PasswordCredential interface: existence and properties of interface prototype object assert_own_property: self does not have own property "PasswordCredential" expected property "PasswordCredential" missing
FAIL PasswordCredential interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "PasswordCredential" expected property "PasswordCredential" missing
FAIL PasswordCredential interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "PasswordCredential" expected property "PasswordCredential" missing
FAIL PasswordCredential interface: attribute password assert_own_property: self does not have own property "PasswordCredential" expected property "PasswordCredential" missing
FAIL PasswordCredential interface: attribute name assert_own_property: self does not have own property "PasswordCredential" expected property "PasswordCredential" missing
FAIL PasswordCredential interface: attribute iconURL assert_own_property: self does not have own property "PasswordCredential" expected property "PasswordCredential" missing
FAIL FederatedCredential interface: existence and properties of interface object assert_own_property: self does not have own property "FederatedCredential" expected property "FederatedCredential" missing
FAIL FederatedCredential interface object length assert_own_property: self does not have own property "FederatedCredential" expected property "FederatedCredential" missing
FAIL FederatedCredential interface object name assert_own_property: self does not have own property "FederatedCredential" expected property "FederatedCredential" missing
FAIL FederatedCredential interface: existence and properties of interface prototype object assert_own_property: self does not have own property "FederatedCredential" expected property "FederatedCredential" missing
FAIL FederatedCredential interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "FederatedCredential" expected property "FederatedCredential" missing
FAIL FederatedCredential interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "FederatedCredential" expected property "FederatedCredential" missing
FAIL FederatedCredential interface: attribute provider assert_own_property: self does not have own property "FederatedCredential" expected property "FederatedCredential" missing
FAIL FederatedCredential interface: attribute protocol assert_own_property: self does not have own property "FederatedCredential" expected property "FederatedCredential" missing
FAIL FederatedCredential interface: attribute name assert_own_property: self does not have own property "FederatedCredential" expected property "FederatedCredential" missing
FAIL FederatedCredential interface: attribute iconURL assert_own_property: self does not have own property "FederatedCredential" expected property "FederatedCredential" missing
PASS Navigator interface: attribute credentials
PASS Navigator interface: attribute identity
PASS DigitalCredential interface: existence and properties of interface object
PASS DigitalCredential interface object length
PASS DigitalCredential interface object name
PASS DigitalCredential interface: existence and properties of interface prototype object
PASS DigitalCredential interface: existence and properties of interface prototype object's "constructor" property
PASS DigitalCredential interface: existence and properties of interface prototype object's @@unscopables property
FAIL DigitalCredential interface: attribute protocol assert_true: The prototype object must have a property "protocol" expected true got false
PASS DigitalCredential interface: attribute data

43 changes: 43 additions & 0 deletions LayoutTests/http/wpt/identity/idl.https.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<!DOCTYPE html>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src=/resources/WebIDLParser.js></script>
<script src=/resources/idlharness.js></script>
<script type="text/plain" id="tested">
partial interface Navigator {
[SecureContext, SameObject] readonly attribute CredentialsContainer identity;
};

partial dictionary CredentialRequestOptions {
DigitalCredentialRequestOptions digital;
};

dictionary DigitalCredentialRequestOptions {
sequence<IdentityRequestProvider> providers;
};

dictionary IdentityRequestProvider {
required DOMString protocol;
required DOMString request;
};

[Exposed=Window, SecureContext]
interface DigitalCredential : Credential {
readonly attribute DOMString protocol;
readonly attribute DOMString data;
};
</script>
<script>
"use strict";
idl_test(
['credential-management'],
['dom', 'html', 'url'],
idl_array => {
idl_array.add_idls(document.querySelector('#tested').textContent);
idl_array.add_untested_idls("interface Element {};");
idl_array.add_objects({
CredentialsContainer: ['navigator.identity']
});
}
);
</script>
Loading

0 comments on commit 2dbfef3

Please sign in to comment.