AK+LibWeb: Move generation of random UUIDs into AK

This will let us use this more outside of LibWeb more easily.

Stop handling tiny OOM while we are here.
This commit is contained in:
Timothy Flynn
2026-03-24 08:33:21 -04:00
committed by Tim Flynn
parent 16dffe39a0
commit 58791db818
Notes: github-actions[bot] 2026-03-24 16:07:31 +00:00
14 changed files with 74 additions and 75 deletions

View File

@@ -8,6 +8,7 @@
#include <AK/Platform.h>
#include <AK/Random.h>
#include <AK/String.h>
#include <AK/UFixedBigInt.h>
#include <AK/UFixedBigIntDivision.h>
@@ -89,6 +90,52 @@ u64 get_random_uniform_64(u64 max_bounds)
return random_value % max_bounds;
}
// https://w3c.github.io/webcrypto/#dfn-generate-a-random-uuid
String generate_random_uuid()
{
// 1. Let bytes be a byte sequence of length 16.
u8 bytes[16];
// 2. Fill bytes with cryptographically secure random bytes.
fill_with_random(bytes);
// 3. Set the 4 most significant bits of bytes[6], which represent the UUID version, to 0100.
bytes[6] = (bytes[6] & 0x0f) | 0x40;
// 4. Set the 2 most significant bits of bytes[8], which represent the UUID variant, to 10.
bytes[8] = (bytes[8] & 0x3f) | 0x80;
// 5. Return the string concatenation of «
// hexadecimal representation of bytes[0],
// hexadecimal representation of bytes[1],
// hexadecimal representation of bytes[2],
// hexadecimal representation of bytes[3],
// "-",
// hexadecimal representation of bytes[4],
// hexadecimal representation of bytes[5],
// "-",
// hexadecimal representation of bytes[6],
// hexadecimal representation of bytes[7],
// "-",
// hexadecimal representation of bytes[8],
// hexadecimal representation of bytes[9],
// "-",
// hexadecimal representation of bytes[10],
// hexadecimal representation of bytes[11],
// hexadecimal representation of bytes[12],
// hexadecimal representation of bytes[13],
// hexadecimal representation of bytes[14],
// hexadecimal representation of bytes[15]
// ».
return MUST(String::formatted(
"{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
bytes[0], bytes[1], bytes[2], bytes[3],
bytes[4], bytes[5],
bytes[6], bytes[7],
bytes[8], bytes[9],
bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15]));
}
XorShift128PlusRNG::XorShift128PlusRNG()
{
// Splitmix64 is used as xorshift is sensitive to being seeded with all 0s

View File

@@ -31,6 +31,8 @@ inline T get_random()
u32 get_random_uniform(u32 max_bounds);
u64 get_random_uniform_64(u64 max_bounds);
String generate_random_uuid();
// http://vigna.di.unimi.it/ftp/papers/xorshiftplus.pdf
class XorShift128PlusRNG {
public:
@@ -58,6 +60,7 @@ inline void shuffle(Collection& collection)
#if USING_AK_GLOBALLY
using AK::fill_with_random;
using AK::generate_random_uuid;
using AK::get_random;
using AK::get_random_uniform;
using AK::shuffle;

View File

@@ -6,10 +6,8 @@
*/
#include <AK/Random.h>
#include <AK/StringBuilder.h>
#include <LibJS/Runtime/TypedArray.h>
#include <LibWeb/Bindings/CryptoPrototype.h>
#include <LibWeb/Bindings/ExceptionOrUtils.h>
#include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/Crypto/Crypto.h>
#include <LibWeb/Crypto/SubtleCrypto.h>
@@ -39,6 +37,12 @@ void Crypto::initialize(JS::Realm& realm)
m_subtle = SubtleCrypto::create(realm);
}
void Crypto::visit_edges(Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_subtle);
}
GC::Ref<SubtleCrypto> Crypto::subtle() const
{
return *m_subtle;
@@ -73,70 +77,15 @@ WebIDL::ExceptionOr<GC::Root<WebIDL::ArrayBufferView>> Crypto::get_random_values
}
// https://w3c.github.io/webcrypto/#dfn-Crypto-method-randomUUID
WebIDL::ExceptionOr<String> Crypto::random_uuid() const
String Crypto::random_uuid() const
{
auto& vm = realm().vm();
return TRY_OR_THROW_OOM(vm, generate_random_uuid());
}
void Crypto::visit_edges(Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_subtle);
return generate_random_uuid();
}
// https://w3c.github.io/webcrypto/#dfn-generate-a-random-uuid
ErrorOr<String> generate_random_uuid()
String generate_random_uuid()
{
// 1. Let bytes be a byte sequence of length 16.
u8 bytes[16];
// 2. Fill bytes with cryptographically secure random bytes.
fill_with_random(bytes);
// 3. Set the 4 most significant bits of bytes[6], which represent the UUID version, to 0100.
bytes[6] &= ~(1 << 7);
bytes[6] |= 1 << 6;
bytes[6] &= ~(1 << 5);
bytes[6] &= ~(1 << 4);
// 4. Set the 2 most significant bits of bytes[8], which represent the UUID variant, to 10.
bytes[8] |= 1 << 7;
bytes[8] &= ~(1 << 6);
/* 5. Return the string concatenation of
«
hexadecimal representation of bytes[0],
hexadecimal representation of bytes[1],
hexadecimal representation of bytes[2],
hexadecimal representation of bytes[3],
"-",
hexadecimal representation of bytes[4],
hexadecimal representation of bytes[5],
"-",
hexadecimal representation of bytes[6],
hexadecimal representation of bytes[7],
"-",
hexadecimal representation of bytes[8],
hexadecimal representation of bytes[9],
"-",
hexadecimal representation of bytes[10],
hexadecimal representation of bytes[11],
hexadecimal representation of bytes[12],
hexadecimal representation of bytes[13],
hexadecimal representation of bytes[14],
hexadecimal representation of bytes[15]
».
*/
StringBuilder builder;
TRY(builder.try_appendff("{:02x}{:02x}{:02x}{:02x}-", bytes[0], bytes[1], bytes[2], bytes[3]));
TRY(builder.try_appendff("{:02x}{:02x}-", bytes[4], bytes[5]));
TRY(builder.try_appendff("{:02x}{:02x}-", bytes[6], bytes[7]));
TRY(builder.try_appendff("{:02x}{:02x}-", bytes[8], bytes[9]));
TRY(builder.try_appendff("{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}", bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15]));
return builder.to_string();
return AK::generate_random_uuid();
}
}

View File

@@ -25,7 +25,7 @@ public:
GC::Ref<SubtleCrypto> subtle() const;
WebIDL::ExceptionOr<GC::Root<WebIDL::ArrayBufferView>> get_random_values(GC::Root<WebIDL::ArrayBufferView>) const;
WebIDL::ExceptionOr<String> random_uuid() const;
String random_uuid() const;
protected:
virtual void initialize(JS::Realm&) override;
@@ -37,6 +37,6 @@ private:
GC::Ptr<SubtleCrypto> m_subtle;
};
WEB_API ErrorOr<String> generate_random_uuid();
WEB_API String generate_random_uuid();
}

View File

@@ -53,7 +53,7 @@ ErrorOr<Utf16String> generate_new_blob_url()
TRY(result.try_append('/'));
// 9. Generate a UUID [RFC4122] as a string and append it to result.
auto uuid = TRY(Crypto::generate_random_uuid());
auto uuid = Crypto::generate_random_uuid();
TRY(result.try_append(uuid));
// 10. Return result.

View File

@@ -1685,7 +1685,7 @@ void Navigable::begin_navigation(NavigateParams params)
// NOTE: This step is handled in Navigable::navigate()
// 7. Let navigationId be the result of generating a random UUID.
String navigation_id = MUST(Crypto::generate_random_uuid());
auto navigation_id = Crypto::generate_random_uuid();
// FIXME: 8. If the surrounding agent is equal to navigable's active document's relevant agent, then continue these steps.
// Otherwise, queue a global task on the navigation and traversal task source given navigable's active window to continue these steps.

View File

@@ -25,8 +25,8 @@ void SessionHistoryEntry::visit_edges(Cell::Visitor& visitor)
SessionHistoryEntry::SessionHistoryEntry()
: m_classic_history_api_state(MUST(structured_serialize_for_storage(vm(), JS::js_null())))
, m_navigation_api_state(MUST(structured_serialize_for_storage(vm(), JS::js_undefined())))
, m_navigation_api_key(MUST(Crypto::generate_random_uuid()))
, m_navigation_api_id(MUST(Crypto::generate_random_uuid()))
, m_navigation_api_key(Crypto::generate_random_uuid())
, m_navigation_api_id(Crypto::generate_random_uuid())
{
}

View File

@@ -21,8 +21,8 @@ IDBDatabase::IDBDatabase(JS::Realm& realm, Database& db)
: EventTarget(realm)
, m_name(db.name())
, m_associated_database(db)
, m_uuid(Crypto::generate_random_uuid())
{
m_uuid = MUST(Crypto::generate_random_uuid());
db.associate(*this);
m_object_store_set = Vector<GC::Ref<ObjectStore>> { db.object_stores() };
}

View File

@@ -25,8 +25,8 @@ IDBRequest::~IDBRequest() = default;
IDBRequest::IDBRequest(JS::Realm& realm, IDBRequestSource source)
: EventTarget(realm)
, m_source(source)
, m_uuid(Crypto::generate_random_uuid())
{
m_uuid = MUST(Crypto::generate_random_uuid());
}
void IDBRequest::initialize(JS::Realm& realm)

View File

@@ -26,8 +26,8 @@ IDBTransaction::IDBTransaction(JS::Realm& realm, GC::Ref<IDBDatabase> connection
, m_mode(mode)
, m_durability(durability)
, m_scope(move(scopes))
, m_uuid(Crypto::generate_random_uuid())
{
m_uuid = MUST(Crypto::generate_random_uuid());
connection->add_transaction(*this);
}

View File

@@ -1365,7 +1365,7 @@ GC_DEFINE_ALLOCATOR(ActionExecutor);
void wait_for_an_action_queue_token(InputState& input_state)
{
// 1. Let token be a new unique identifier.
auto token = MUST(Crypto::generate_random_uuid());
auto token = Crypto::generate_random_uuid();
// 2. Enqueue token in input state's actions queue.
input_state.actions_queue.append(token);

View File

@@ -629,7 +629,7 @@ void ViewImplementation::initialize_client(CreateNewClient create_new_client)
m_client_state.client->register_view(m_client_state.page_index, *this);
}
m_client_state.client_handle = MUST(Web::Crypto::generate_random_uuid());
m_client_state.client_handle = Web::Crypto::generate_random_uuid();
client().async_set_window_handle(m_client_state.page_index, m_client_state.client_handle);
client().async_set_zoom_level(m_client_state.page_index, m_zoom_level);
client().async_set_viewport(m_client_state.page_index, viewport_size(), m_device_pixel_ratio, m_is_fullscreen);

View File

@@ -1716,7 +1716,7 @@ Web::WebDriver::Response WebDriverConnection::element_click_impl(StringView elem
};
// 3. Let input id be a the result of generating a UUID.
auto input_id = MUST(Web::Crypto::generate_random_uuid());
auto input_id = Web::Crypto::generate_random_uuid();
// 4. Let source be the result of create an input source with input state, and "pointer".
auto source = Web::WebDriver::create_input_source(input_state, Web::WebDriver::InputSourceType::Pointer, Web::WebDriver::PointerInputSource::Subtype::Mouse);
@@ -2035,7 +2035,7 @@ Web::WebDriver::Response WebDriverConnection::element_send_keys_impl(StringView
auto& input_state = Web::WebDriver::get_input_state(*current_top_level_browsing_context());
// 10. Let input id be a the result of generating a UUID.
auto input_id = MUST(Web::Crypto::generate_random_uuid());
auto input_id = Web::Crypto::generate_random_uuid();
// 11. Let source be the result of create an input source with input state, and "key".
auto source = Web::WebDriver::create_input_source(input_state, Web::WebDriver::InputSourceType::Key, {});

View File

@@ -35,7 +35,7 @@ static HashMap<String, NonnullRefPtr<Session>> s_http_sessions;
ErrorOr<NonnullRefPtr<Session>> Session::create(NonnullRefPtr<Client> client, JsonObject& capabilities, Web::WebDriver::SessionFlags flags)
{
// 1. Let session id be the result of generating a UUID.
auto session_id = MUST(Web::Crypto::generate_random_uuid());
auto session_id = Web::Crypto::generate_random_uuid();
// 2. Let session be a new session with session ID session id, and HTTP flag flags contains "http".
auto session = adopt_ref(*new Session(client, capabilities, move(session_id), flags));