ladybird/Libraries/LibURL/Origin.h
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

138 lines
4.2 KiB
C++

/*
* Copyright (c) 2020, Andreas Kling <andreas@ladybird.org>
* Copyright (c) 2022, Linus Groh <linusg@serenityos.org>
* Copyright (c) 2025, Shannon Booth <shannon@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/ByteString.h>
#include <LibURL/Forward.h>
#include <LibURL/Host.h>
namespace URL {
// https://html.spec.whatwg.org/multipage/browsers.html#concept-origin
class Origin {
public:
using Nonce = Array<u8, 16>;
explicit Origin(Nonce nonce)
: m_state(move(nonce))
{
}
static Origin create_opaque();
Origin(Optional<String> const& scheme, Host const& host, Optional<u16> port, Optional<String> domain = {})
: m_state(Tuple {
.scheme = scheme,
.host = host,
.port = move(port),
.domain = move(domain),
})
{
}
// https://html.spec.whatwg.org/multipage/origin.html#concept-origin-opaque
bool is_opaque() const { return m_state.has<Nonce>(); }
Optional<String> const& scheme() const { return m_state.get<Tuple>().scheme; }
Host const& host() const { return m_state.get<Tuple>().host; }
Optional<u16> port() const { return m_state.get<Tuple>().port; }
Optional<String> domain() const { return m_state.get<Tuple>().domain; }
Nonce const& nonce() const { return m_state.get<Nonce>(); }
// https://html.spec.whatwg.org/multipage/origin.html#same-origin
bool is_same_origin(Origin const& other) const
{
// 1. If A and B are the same opaque origin, then return true.
if (is_opaque() && other.is_opaque())
return nonce() == other.nonce();
// 2. If A and B are both tuple origins and their schemes, hosts, and port are identical, then return true.
if (!is_opaque() && !other.is_opaque()
&& scheme() == other.scheme()
&& host() == other.host()
&& port() == other.port()) {
return true;
}
// 3. Return false.
return false;
}
// https://html.spec.whatwg.org/multipage/origin.html#same-origin-domain
bool is_same_origin_domain(Origin const& other) const
{
// 1. If A and B are the same opaque origin, then return true.
if (is_opaque() && other.is_opaque())
return nonce() == other.nonce();
// 2. If A and B are both tuple origins, run these substeps:
if (!is_opaque() && !other.is_opaque()) {
// 1. If A and B's schemes are identical, and their domains are identical and non-null, then return true.
if (domain().has_value()
&& domain() == other.domain()
&& scheme() == other.scheme())
return true;
// 2. Otherwise, if A and B are same origin and their domains are identical and null, then return true.
if (!domain().has_value()
&& !other.domain().has_value()
&& is_same_origin(other))
return true;
}
// 3. Return false.
return false;
}
// https://html.spec.whatwg.org/multipage/browsers.html#same-site
bool is_same_site(Origin const&) const;
// https://html.spec.whatwg.org/multipage/origin.html#ascii-serialisation-of-an-origin
String serialize() const;
// https://html.spec.whatwg.org/multipage/origin.html#concept-origin-effective-domain
Optional<Host> effective_domain() const
{
// 1. If origin is an opaque origin, then return null.
if (is_opaque())
return {};
// 2. If origin's domain is non-null, then return origin's domain.
auto const& tuple = m_state.get<Tuple>();
if (tuple.domain.has_value())
return Host { tuple.domain.value() };
// 3. Return origin's host.
return m_state.get<Tuple>().host;
}
bool operator==(Origin const& other) const { return is_same_origin(other); }
private:
struct Tuple {
Optional<String> scheme;
Host host;
Optional<u16> port;
Optional<String> domain;
};
Variant<Tuple, Nonce> m_state;
};
}
namespace AK {
template<>
struct Traits<URL::Origin> : public DefaultTraits<URL::Origin> {
static unsigned hash(URL::Origin const& origin);
};
} // namespace AK