LibWeb: Introduce CredentialInterface to handle credentials metadata

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 commit is contained in:
devgianlu 2025-02-07 16:58:35 +01:00
parent cb2bcb30e4
commit db2e6d0198
3 changed files with 113 additions and 0 deletions

View file

@ -13,6 +13,74 @@
namespace Web::CredentialManagement {
typedef GC::Function<JS::ThrowCompletionOr<GC::Ref<Credential>>(JS::Object const&)> CreateCredentialAlgorithm;
#define CREDENTIAL_INTERFACE(class_name) \
public: \
static class_name const* the() \
{ \
static class_name* instance = nullptr; \
if (!instance) \
instance = new class_name(); \
return instance; \
}
class CredentialInterface {
AK_MAKE_NONCOPYABLE(CredentialInterface);
protected:
CredentialInterface() { }
public:
virtual ~CredentialInterface() = default;
// https://w3c.github.io/webappsec-credential-management/#credential-type-registry-credential-type
virtual String type() const = 0;
// https://w3c.github.io/webappsec-credential-management/#credential-type-registry-options-member-identifier
virtual String options_member_identifier() const = 0;
// https://w3c.github.io/webappsec-credential-management/#credential-type-registry-get-permissions-policy
virtual Optional<String> get_permission_policy() const = 0;
// https://w3c.github.io/webappsec-credential-management/#credential-type-registry-create-permissions-policy
virtual Optional<String> create_permission_policy() const = 0;
// https://w3c.github.io/webappsec-credential-management/#dom-credential-discovery-slot
virtual String discovery() const = 0;
// NOTE: This is not explicitly present in the spec, it is inferred.
virtual bool supports_conditional_user_mediation() const = 0;
// https://w3c.github.io/webappsec-credential-management/#algorithm-create-cred
virtual JS::ThrowCompletionOr<Variant<Empty, GC::Ref<Credential>, GC::Ref<CreateCredentialAlgorithm>>> create(JS::Realm&, URL::Origin const&, CredentialCreationOptions const&, bool) const
{
// 1. Return null.
return Empty {};
}
// https://w3c.github.io/webappsec-credential-management/#algorithm-store-cred
virtual JS::ThrowCompletionOr<void> store(JS::Realm& realm, bool) const
{
// 1. Throw a NotSupportedError.
return throw_completion(WebIDL::NotSupportedError::create(realm, "store"_string));
}
// https://w3c.github.io/webappsec-credential-management/#algorithm-discover-creds
virtual JS::ThrowCompletionOr<Variant<Empty, GC::Ref<Credential>>> discover_from_external_source(JS::Realm&, URL::Origin const&, CredentialRequestOptions const&, bool) const
{
// 1. Return null.
return Empty {};
}
// https://w3c.github.io/webappsec-credential-management/#algorithm-collect-creds
virtual JS::ThrowCompletionOr<Vector<Credential>> collect_from_credential_store(JS::Realm&, URL::Origin const&, CredentialRequestOptions const&, bool) const
{
// 1. Return an empty set.
return Vector<Credential> {};
}
};
class Credential : public Bindings::PlatformObject {
WEB_PLATFORM_OBJECT(Credential, Bindings::PlatformObject);
GC_DECLARE_ALLOCATOR(Credential);
@ -30,6 +98,7 @@ public:
String const& icon_url() const { return m_icon_url; }
virtual String type() const = 0;
virtual CredentialInterface const* interface() const = 0;
protected:
explicit Credential(JS::Realm&);

View file

@ -13,6 +13,24 @@
namespace Web::CredentialManagement {
class FederatedCredentialInterface final : public CredentialInterface {
CREDENTIAL_INTERFACE(FederatedCredentialInterface);
public:
virtual String type() const override { return "federated"_string; }
virtual String options_member_identifier() const override { return "federated"_string; }
virtual Optional<String> get_permission_policy() const override { return {}; }
virtual Optional<String> create_permission_policy() const override { return {}; }
virtual String discovery() const override { return "credential store"_string; }
virtual bool supports_conditional_user_mediation() const override
{
// NOTE: FederatedCredential does not override is_conditional_mediation_available(),
// therefore conditional mediation is not supported.
return false;
}
};
class FederatedCredential final : public Credential {
WEB_PLATFORM_OBJECT(FederatedCredential, Credential);
GC_DECLARE_ALLOCATOR(FederatedCredential);
@ -27,6 +45,10 @@ public:
Optional<String> const& protocol() const { return m_protocol; }
String type() const override { return "federated"_string; }
virtual CredentialInterface const* interface() const override
{
return FederatedCredentialInterface::the();
}
private:
explicit FederatedCredential(JS::Realm&);

View file

@ -14,6 +14,24 @@
namespace Web::CredentialManagement {
class PasswordCredentialInterface final : public CredentialInterface {
CREDENTIAL_INTERFACE(PasswordCredentialInterface);
public:
virtual String type() const override { return "password"_string; }
virtual String options_member_identifier() const override { return "password"_string; }
virtual Optional<String> get_permission_policy() const override { return {}; }
virtual Optional<String> create_permission_policy() const override { return {}; }
virtual String discovery() const override { return "credential store"_string; }
virtual bool supports_conditional_user_mediation() const override
{
// NOTE: PasswordCredential does not override is_conditional_mediation_available(),
// therefore conditional mediation is not supported.
return false;
}
};
class PasswordCredential final : public Credential {
WEB_PLATFORM_OBJECT(PasswordCredential, Credential);
GC_DECLARE_ALLOCATOR(PasswordCredential);
@ -28,6 +46,10 @@ public:
String const& password() const { return m_password; }
String type() const override { return "password"_string; }
virtual CredentialInterface const* interface() const override
{
return PasswordCredentialInterface::the();
}
private:
explicit PasswordCredential(JS::Realm&);