Files
ladybird/Libraries/LibURL/Origin.cpp
Shannon Booth 89dbdd3411 LibURL: Add domain concept to URL::Origin to fix same-origin-domain
The same-origin domain check always returned true if only the scheme
matched. This was because of missing steps to check for the origin's
domain, which didn't exist. Add this concept to URL::Origin, even
though we do not use it at this stage in document.domain setter.

Co-Authored-By: Luke Wilde <luke@ladybird.org>
2025-12-30 13:02:10 +01:00

92 lines
2.4 KiB
C++

/*
* Copyright (c) 2024-2025, Shannon Booth <shannon@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibCrypto/SecureRandom.h>
#include <LibURL/Origin.h>
#include <LibURL/Parser.h>
#include <LibURL/Site.h>
namespace URL {
Origin Origin::create_opaque()
{
return Origin { Crypto::get_secure_random<Nonce>() };
}
// https://html.spec.whatwg.org/multipage/browsers.html#same-site
bool Origin::is_same_site(Origin const& other) const
{
// 1. Let siteA be the result of obtaining a site given A.
auto site_a = Site::obtain(*this);
// 2. Let siteB be the result of obtaining a site given B.
auto site_b = Site::obtain(other);
// 3. If siteA is same site with siteB, then return true.
if (site_a.is_same_site(site_b))
return true;
// 4. Return false.
return false;
}
// https://html.spec.whatwg.org/multipage/origin.html#ascii-serialisation-of-an-origin
String Origin::serialize() const
{
// 1. If origin is an opaque origin, then return "null"
if (is_opaque())
return "null"_string;
// 2. Otherwise, let result be origin's scheme.
StringBuilder result;
result.append(scheme().value_or(String {}));
// 3. Append "://" to result.
result.append("://"sv);
// 4. Append origin's host, serialized, to result.
result.append(host().serialize());
// 5. If origin's port is non-null, append a U+003A COLON character (:), and origin's port, serialized, to result.
if (port().has_value()) {
result.append(':');
result.append(String::number(*port()));
}
// 6. Return result
return result.to_string_without_validation();
}
}
namespace AK {
unsigned Traits<URL::Origin>::hash(URL::Origin const& origin)
{
if (origin.is_opaque()) {
auto const& nonce = origin.nonce();
// Random data, so the first u32 is as good as hashing the entire thing.
return (static_cast<u32>(nonce[0]) << 24)
| (static_cast<u32>(nonce[1]) << 16)
| (static_cast<u32>(nonce[2]) << 8)
| (static_cast<u32>(nonce[3]));
}
unsigned hash = origin.scheme().value_or(String {}).hash();
if (origin.port().has_value())
hash = pair_int_hash(hash, *origin.port());
hash = pair_int_hash(hash, origin.host().serialize().hash());
if (origin.domain().has_value())
hash = pair_int_hash(hash, origin.domain()->hash());
return hash;
}
} // namespace AK