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();
}