diff --git a/Tests/LibWeb/Text/expected/HTML/StructuredClone-serializable-objects.txt b/Tests/LibWeb/Text/expected/HTML/StructuredClone-serializable-objects.txt index 45ee28cd2d2..c383c69d915 100644 --- a/Tests/LibWeb/Text/expected/HTML/StructuredClone-serializable-objects.txt +++ b/Tests/LibWeb/Text/expected/HTML/StructuredClone-serializable-objects.txt @@ -20,3 +20,8 @@ instanceOf DOMRectReadOnly: true DOMRectReadOnly: {"x":10,"y":20,"width":30,"height":40,"top":20,"right":40,"bottom":60,"left":10} instanceOf DOMRect: true DOMRect: {"x":10,"y":20,"width":30,"height":40,"top":20,"right":40,"bottom":60,"left":10} +instanceOf CryptoKey: true +CryptoKey.type: "secret" +CryptoKey.extractable: false +CryptoKey.algorithm: {"name":"PBKDF2"} +CryptoKey.usages: ["deriveKey","deriveBits"] diff --git a/Tests/LibWeb/Text/input/HTML/StructuredClone-serializable-objects.html b/Tests/LibWeb/Text/input/HTML/StructuredClone-serializable-objects.html index f748cf773e3..9c1726c06a0 100644 --- a/Tests/LibWeb/Text/input/HTML/StructuredClone-serializable-objects.html +++ b/Tests/LibWeb/Text/input/HTML/StructuredClone-serializable-objects.html @@ -43,6 +43,20 @@ println(`instanceOf DOMRect: ${domRect instanceof DOMRect}`); println(`DOMRect: ${JSON.stringify(domRect)}`); + let cryptoKey = await window.crypto.subtle.importKey( + "raw", + new TextEncoder().encode("password"), + { name: "PBKDF2" }, + false, + ["deriveBits", "deriveKey"] + ); + let clonedCryptoKey = structuredClone(cryptoKey); + println(`instanceOf CryptoKey: ${clonedCryptoKey instanceof CryptoKey}`); + println(`CryptoKey.type: ${JSON.stringify(clonedCryptoKey.type)}`); + println(`CryptoKey.extractable: ${JSON.stringify(clonedCryptoKey.extractable)}`); + println(`CryptoKey.algorithm: ${JSON.stringify(clonedCryptoKey.algorithm)}`); + println(`CryptoKey.usages: ${JSON.stringify(clonedCryptoKey.usages)}`); + done(); }); diff --git a/Userland/Libraries/LibWeb/Crypto/CryptoKey.cpp b/Userland/Libraries/LibWeb/Crypto/CryptoKey.cpp index d70919db072..c6f8582f314 100644 --- a/Userland/Libraries/LibWeb/Crypto/CryptoKey.cpp +++ b/Userland/Libraries/LibWeb/Crypto/CryptoKey.cpp @@ -20,6 +20,11 @@ JS::NonnullGCPtr CryptoKey::create(JS::Realm& realm, InternalKeyData return realm.heap().allocate(realm, realm, move(key_data)); } +JS::NonnullGCPtr CryptoKey::create(JS::Realm& realm) +{ + return realm.heap().allocate(realm, realm); +} + CryptoKey::CryptoKey(JS::Realm& realm, InternalKeyData key_data) : PlatformObject(realm) , m_algorithm(Object::create(realm, nullptr)) @@ -28,6 +33,14 @@ CryptoKey::CryptoKey(JS::Realm& realm, InternalKeyData key_data) { } +CryptoKey::CryptoKey(JS::Realm& realm) + : PlatformObject(realm) + , m_algorithm(Object::create(realm, nullptr)) + , m_usages(Object::create(realm, nullptr)) + , m_key_data(MUST(ByteBuffer::create_uninitialized(0))) +{ +} + CryptoKey::~CryptoKey() { m_key_data.visit( @@ -110,4 +123,55 @@ JS_DEFINE_NATIVE_FUNCTION(CryptoKeyPair::private_key_getter) return TRY(Bindings::throw_dom_exception_if_needed(vm, [&] { return impl->private_key(); })); } +WebIDL::ExceptionOr CryptoKey::serialization_steps(HTML::SerializationRecord& serialized, bool for_storage, HTML::SerializationMemory& memory) +{ + auto& vm = this->vm(); + + // 1. Set serialized.[[Type]] to the [[type]] internal slot of value. + HTML::serialize_primitive_type(serialized, static_cast(m_type)); + + // 2. Set serialized.[[Extractable]] to the [[extractable]] internal slot of value. + HTML::serialize_primitive_type(serialized, m_extractable); + + // 3. Set serialized.[[Algorithm]] to the sub-serialization of the [[algorithm]] internal slot of value. + auto serialized_algorithm = TRY(HTML::structured_serialize_internal(vm, m_algorithm, for_storage, memory)); + serialized.extend(move(serialized_algorithm)); + + // 4. Set serialized.[[Usages]] to the sub-serialization of the [[usages]] internal slot of value. + auto serialized_usages = TRY(HTML::structured_serialize_internal(vm, m_usages, for_storage, memory)); + serialized.extend(move(serialized_usages)); + + // FIXME: 5. Set serialized.[[Handle]] to the [[handle]] internal slot of value. + + return {}; +} + +WebIDL::ExceptionOr CryptoKey::deserialization_steps(ReadonlySpan const& serialized, size_t& position, HTML::DeserializationMemory& memory) +{ + auto& vm = this->vm(); + auto& realm = this->realm(); + + // 1. Initialize the [[type]] internal slot of value to serialized.[[Type]]. + m_type = static_cast(HTML::deserialize_primitive_type(serialized, position)); + + // 2. Initialize the [[extractable]] internal slot of value to serialized.[[Extractable]]. + m_extractable = HTML::deserialize_primitive_type(serialized, position); + + // 3. Initialize the [[algorithm]] internal slot of value to the sub-deserialization of serialized.[[Algorithm]]. + auto deserialized_record = TRY(HTML::structured_deserialize_internal(vm, serialized, realm, memory, position)); + if (deserialized_record.value.has_value()) + m_algorithm = deserialized_record.value.release_value().as_object(); + position = deserialized_record.position; + + // 4. Initialize the [[usages]] internal slot of value to the sub-deserialization of serialized.[[Usages]]. + deserialized_record = TRY(HTML::structured_deserialize_internal(vm, serialized, realm, memory, position)); + if (deserialized_record.value.has_value()) + m_usages = deserialized_record.value.release_value().as_object(); + position = deserialized_record.position; + + // FIXME: 5. Initialize the [[handle]] internal slot of value to serialized.[[Handle]]. + + return {}; +} + } diff --git a/Userland/Libraries/LibWeb/Crypto/CryptoKey.h b/Userland/Libraries/LibWeb/Crypto/CryptoKey.h index 48d1185a900..2b9fa2bc5b0 100644 --- a/Userland/Libraries/LibWeb/Crypto/CryptoKey.h +++ b/Userland/Libraries/LibWeb/Crypto/CryptoKey.h @@ -12,11 +12,14 @@ #include #include #include +#include #include namespace Web::Crypto { -class CryptoKey final : public Bindings::PlatformObject { +class CryptoKey final + : public Bindings::PlatformObject + , public Bindings::Serializable { WEB_PLATFORM_OBJECT(CryptoKey, Bindings::PlatformObject); JS_DECLARE_ALLOCATOR(CryptoKey); @@ -24,6 +27,7 @@ public: using InternalKeyData = Variant, ::Crypto::PK::RSAPrivateKey<>>; [[nodiscard]] static JS::NonnullGCPtr create(JS::Realm&, InternalKeyData); + [[nodiscard]] static JS::NonnullGCPtr create(JS::Realm&); virtual ~CryptoKey() override; @@ -41,8 +45,14 @@ public: InternalKeyData const& handle() const { return m_key_data; } + virtual StringView interface_name() const override { return "CryptoKey"sv; } + virtual WebIDL::ExceptionOr serialization_steps(HTML::SerializationRecord& record, bool for_storage, HTML::SerializationMemory&) override; + virtual WebIDL::ExceptionOr deserialization_steps(ReadonlySpan const& record, size_t& position, HTML::DeserializationMemory&) override; + private: CryptoKey(JS::Realm&, InternalKeyData); + explicit CryptoKey(JS::Realm&); + virtual void initialize(JS::Realm&) override; virtual void visit_edges(Visitor&) override; diff --git a/Userland/Libraries/LibWeb/HTML/StructuredSerialize.cpp b/Userland/Libraries/LibWeb/HTML/StructuredSerialize.cpp index 750bad8b105..7030f6efef0 100644 --- a/Userland/Libraries/LibWeb/HTML/StructuredSerialize.cpp +++ b/Userland/Libraries/LibWeb/HTML/StructuredSerialize.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -984,6 +985,8 @@ private: return Geometry::DOMRectReadOnly::create(realm); if (interface_name == "DOMRect"sv) return Geometry::DOMRect::create(realm); + if (interface_name == "CryptoKey"sv) + return Crypto::CryptoKey::create(realm); VERIFY_NOT_REACHED(); }