Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LibWeb: Implement most CredentialsContainer methods #3495

Open
wants to merge 7 commits into
base: master
Choose a base branch
from

Conversation

devgianlu
Copy link
Contributor

@devgianlu devgianlu commented Feb 7, 2025

This PR mplements get, store, create on CredentialsContainer.

Notably, it also introduces the CredentialInterface abstract class to deal with credentials internal methods and metadata. It has been implemented as a singleton for each credential type. This is the design that I managed to come up with, any suggestion is appreciated.

The spec isn't the best and contains some bugs:

  • The options.signal && options.signal->aborted() check in get and create is not deferred therefore fails two WPT tests
  • The interfaces.size() < 1 check in create is custom and avoids an out of bound access in the next step -> Spec issue
  • The CredentialRequestOptions IDL dictionary has a default value for password which renders the credential type always active. I think we are supposed to reject it when computing the relevant credential interface objects if password is false, but that's not specified

I'll create some spec issues and link them here even if the repository has been inactive for the last 6 months.

Lastly, I am unsure how to check If settings’s relevant global object has no associated Document so I've left two TODOs.

@devgianlu devgianlu force-pushed the credentials-cont branch 3 times, most recently from 795803e to 243df11 Compare February 7, 2025 18:28
The introduction of the abstract `CredentialInterface` class serves to
implement what is mentioned in the spec as "interface objects". It is
not possible to implement this perfectly to spec in Ladybird so let's
make use of a custom abstraction.
This is probably a spec bug. If the property has a default value it will
always be populated in the `CredentialRequestOptions` dictionary making
that credential type always active.
Copy link
Contributor

@konradekk konradekk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nits: some minor naming suggestions

for (auto& interface : relevant_credential_interface_objects(options)) {
// 1. Let r be the result of executing interface’s [[CollectFromCredentialStore]](origin, options, sameOriginWithAncestors)
// internal method on origin, options, and sameOriginWithAncestors. If that threw an exception, rethrow that exception.
auto maybe_r = interface->collect_from_credential_store(realm, origin, options, same_origin_with_ancestors);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider using possible_result instead of maybe_r?

if (maybe_r.is_error())
return maybe_r.error();

auto r = maybe_r.release_value();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider using result instead of r?

// TODO: 2. Assert: r is a list of interface objects.

// 3. For each c in r:
for (auto& c : r) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider using credential instead of c?

// If that threw an exception:
if (maybe_result.is_error()) {
// 1. Let e be the thrown exception.
auto e = maybe_result.error_value();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider using exception instead of e?

// 9. React to p:
auto on_completion = GC::create_function(realm().heap(), [&settings, &credential](JS::Value) -> WebIDL::ExceptionOr<JS::Value> {
// 1. Remove credential’s [[type]] from settings’ active credential types.
settings.active_credential_types().remove_first_matching([&](auto& v) { return v == credential.type(); });
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider using type instead of v?

Comment on lines 428 to 444
// 1. Let r be the result of executing interfaces[0]'s [[Create]](origin, options, sameOriginWithAncestors)
// internal method on origin, options, and sameOriginWithAncestors.
auto maybe_r = interfaces[0]->create(realm(), origin, options, same_origin_with_ancestors);
// If that threw an exception:
if (maybe_r.is_error()) {
// 1. Let e be the thrown exception.
auto e = maybe_r.error_value();
// 2. Queue a task on global’s DOM manipulation task source to run the following substeps:
queue_global_task(HTML::Task::Source::DOMManipulation, global, GC::create_function(document.heap(), [&] {
// 1. Reject p with e.
WebIDL::reject_promise(realm(), *promise, e);
}));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above with more descriptive names

return;
}

auto r = maybe_r.release_value();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

… and also here

Implement `get`, `store`, `create` on `CredentialsContainer`. Some
pieces that we don't support yet, like permissions and custom user
interactions, are left as TODO.

The `rejects when aborted after the promise creation` tests are broken
because the spec says to check the aborted signal synchronously.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants