From 7838eab34158bcb317fad5d00ae50691b0e9e02f Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Fri, 3 Sep 2021 10:16:36 +0100 Subject: [PATCH] WebContent: Implement ConsoleGlobalObject which proxies to WindowObject ConsoleGlobalObject is used as the global object when running javascript from the Browser console. This lets us implement console-only functions and variables (like `$0`) without exposing them to webpage content. It passes other calls over to the usual WindowObject so any code that would have worked in the webpage will still work in the console. :^) --- Userland/Services/WebContent/CMakeLists.txt | 1 + .../Services/WebContent/ClientConnection.cpp | 1 - .../Services/WebContent/ClientConnection.h | 2 + .../WebContent/ConsoleGlobalObject.cpp | 90 +++++++++++++++++++ .../Services/WebContent/ConsoleGlobalObject.h | 43 +++++++++ Userland/Services/WebContent/Forward.h | 1 + .../WebContent/WebContentConsoleClient.cpp | 19 +++- .../WebContent/WebContentConsoleClient.h | 9 +- 8 files changed, 156 insertions(+), 10 deletions(-) create mode 100644 Userland/Services/WebContent/ConsoleGlobalObject.cpp create mode 100644 Userland/Services/WebContent/ConsoleGlobalObject.h diff --git a/Userland/Services/WebContent/CMakeLists.txt b/Userland/Services/WebContent/CMakeLists.txt index a1886c6b63..235829e0ca 100644 --- a/Userland/Services/WebContent/CMakeLists.txt +++ b/Userland/Services/WebContent/CMakeLists.txt @@ -8,6 +8,7 @@ compile_ipc(WebContentClient.ipc WebContentClientEndpoint.h) set(SOURCES ClientConnection.cpp + ConsoleGlobalObject.cpp main.cpp PageHost.cpp WebContentConsoleClient.cpp diff --git a/Userland/Services/WebContent/ClientConnection.cpp b/Userland/Services/WebContent/ClientConnection.cpp index 64fbf46b82..031ae6307b 100644 --- a/Userland/Services/WebContent/ClientConnection.cpp +++ b/Userland/Services/WebContent/ClientConnection.cpp @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/Userland/Services/WebContent/ClientConnection.h b/Userland/Services/WebContent/ClientConnection.h index 8dba21858c..f4b6494048 100644 --- a/Userland/Services/WebContent/ClientConnection.h +++ b/Userland/Services/WebContent/ClientConnection.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -72,6 +73,7 @@ private: WeakPtr m_interpreter; OwnPtr m_console_client; + JS::Handle m_console_global_object; }; } diff --git a/Userland/Services/WebContent/ConsoleGlobalObject.cpp b/Userland/Services/WebContent/ConsoleGlobalObject.cpp new file mode 100644 index 0000000000..2e16ea6aa9 --- /dev/null +++ b/Userland/Services/WebContent/ConsoleGlobalObject.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2021, Sam Atkins + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "ConsoleGlobalObject.h" +#include +#include +#include + +namespace WebContent { + +ConsoleGlobalObject::ConsoleGlobalObject(Web::Bindings::WindowObject& parent_object) + : m_window_object(&parent_object) +{ +} + +ConsoleGlobalObject::~ConsoleGlobalObject() +{ +} + +void ConsoleGlobalObject::visit_edges(Visitor& visitor) +{ + Base::visit_edges(visitor); + visitor.visit(m_window_object); +} + +JS::Object* ConsoleGlobalObject::internal_get_prototype_of() const +{ + return m_window_object->internal_get_prototype_of(); +} + +bool ConsoleGlobalObject::internal_set_prototype_of(JS::Object* prototype) +{ + return m_window_object->internal_set_prototype_of(prototype); +} + +bool ConsoleGlobalObject::internal_is_extensible() const +{ + return m_window_object->internal_is_extensible(); +} + +bool ConsoleGlobalObject::internal_prevent_extensions() +{ + return m_window_object->internal_prevent_extensions(); +} + +Optional ConsoleGlobalObject::internal_get_own_property(JS::PropertyName const& property_name) const +{ + if (auto result = m_window_object->internal_get_own_property(property_name); result.has_value()) + return result; + + return Base::internal_get_own_property(property_name); +} + +bool ConsoleGlobalObject::internal_define_own_property(JS::PropertyName const& property_name, JS::PropertyDescriptor const& descriptor) +{ + return m_window_object->internal_define_own_property(property_name, descriptor); +} + +bool ConsoleGlobalObject::internal_has_property(JS::PropertyName const& property_name) const +{ + return Object::internal_has_property(property_name) || m_window_object->internal_has_property(property_name); +} + +JS::Value ConsoleGlobalObject::internal_get(JS::PropertyName const& property_name, JS::Value receiver) const +{ + if (m_window_object->has_own_property(property_name)) + return m_window_object->internal_get(property_name, (receiver == this) ? m_window_object : receiver); + + return Base::internal_get(property_name, receiver); +} + +bool ConsoleGlobalObject::internal_set(JS::PropertyName const& property_name, JS::Value value, JS::Value receiver) +{ + return m_window_object->internal_set(property_name, value, (receiver == this) ? m_window_object : receiver); +} + +bool ConsoleGlobalObject::internal_delete(JS::PropertyName const& property_name) +{ + return m_window_object->internal_delete(property_name); +} + +JS::MarkedValueList ConsoleGlobalObject::internal_own_property_keys() const +{ + return m_window_object->internal_own_property_keys(); +} + +} diff --git a/Userland/Services/WebContent/ConsoleGlobalObject.h b/Userland/Services/WebContent/ConsoleGlobalObject.h new file mode 100644 index 0000000000..03ec211f84 --- /dev/null +++ b/Userland/Services/WebContent/ConsoleGlobalObject.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2021, Sam Atkins + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include + +namespace Web::Bindings { +class WindowObject; +} + +namespace WebContent { + +class ConsoleGlobalObject final : public JS::GlobalObject { + JS_OBJECT(ConsoleGlobalObject, JS::GlobalObject); + +public: + ConsoleGlobalObject(Web::Bindings::WindowObject&); + virtual ~ConsoleGlobalObject() override; + + virtual Object* internal_get_prototype_of() const override; + virtual bool internal_set_prototype_of(Object* prototype) override; + virtual bool internal_is_extensible() const override; + virtual bool internal_prevent_extensions() override; + virtual Optional internal_get_own_property(JS::PropertyName const& name) const override; + virtual bool internal_define_own_property(JS::PropertyName const& name, JS::PropertyDescriptor const& descriptor) override; + virtual bool internal_has_property(JS::PropertyName const& name) const override; + virtual JS::Value internal_get(JS::PropertyName const&, JS::Value) const override; + virtual bool internal_set(JS::PropertyName const&, JS::Value value, JS::Value receiver) override; + virtual bool internal_delete(JS::PropertyName const& name) override; + virtual JS::MarkedValueList internal_own_property_keys() const override; + +private: + virtual void visit_edges(Visitor&) override; + + Web::Bindings::WindowObject* m_window_object; +}; + +} diff --git a/Userland/Services/WebContent/Forward.h b/Userland/Services/WebContent/Forward.h index 43a28f89cc..ed9cc8aab1 100644 --- a/Userland/Services/WebContent/Forward.h +++ b/Userland/Services/WebContent/Forward.h @@ -9,6 +9,7 @@ namespace WebContent { class ClientConnection; +class ConsoleGlobalObject; class PageHost; class WebContentConsoleClient; diff --git a/Userland/Services/WebContent/WebContentConsoleClient.cpp b/Userland/Services/WebContent/WebContentConsoleClient.cpp index 7a3fbe6bb2..b3a9c0ef9d 100644 --- a/Userland/Services/WebContent/WebContentConsoleClient.cpp +++ b/Userland/Services/WebContent/WebContentConsoleClient.cpp @@ -1,6 +1,7 @@ /* * Copyright (c) 2021, Brandon Scott * Copyright (c) 2020, Hunter Salyer + * Copyright (c) 2021, Sam Atkins * * SPDX-License-Identifier: BSD-2-Clause */ @@ -9,10 +10,22 @@ #include #include #include -#include +#include +#include namespace WebContent { +WebContentConsoleClient::WebContentConsoleClient(JS::Console& console, WeakPtr interpreter, ClientConnection& client) + : ConsoleClient(console) + , m_client(client) + , m_interpreter(interpreter) +{ + JS::DeferGC defer_gc(m_interpreter->heap()); + auto console_global_object = m_interpreter->heap().allocate_without_global_object(static_cast(m_interpreter->global_object())); + console_global_object->initialize_global_object(); + m_console_global_object = JS::make_handle(console_global_object); +} + void WebContentConsoleClient::handle_input(const String& js_source) { auto parser = JS::Parser(JS::Lexer(js_source)); @@ -24,9 +37,9 @@ void WebContentConsoleClient::handle_input(const String& js_source) auto hint = error.source_location_hint(js_source); if (!hint.is_empty()) output_html.append(String::formatted("
{}
", escape_html_entities(hint))); - m_interpreter->vm().throw_exception(m_interpreter->global_object(), error.to_string()); + m_interpreter->vm().throw_exception(*m_console_global_object.cell(), error.to_string()); } else { - m_interpreter->run(m_interpreter->global_object(), *program); + m_interpreter->run(*m_console_global_object.cell(), *program); } if (m_interpreter->exception()) { diff --git a/Userland/Services/WebContent/WebContentConsoleClient.h b/Userland/Services/WebContent/WebContentConsoleClient.h index ef43a7beab..3fbeb18062 100644 --- a/Userland/Services/WebContent/WebContentConsoleClient.h +++ b/Userland/Services/WebContent/WebContentConsoleClient.h @@ -17,12 +17,7 @@ namespace WebContent { class WebContentConsoleClient final : public JS::ConsoleClient { public: - WebContentConsoleClient(JS::Console& console, WeakPtr interpreter, ClientConnection& client) - : ConsoleClient(console) - , m_client(client) - , m_interpreter(interpreter) - { - } + WebContentConsoleClient(JS::Console&, WeakPtr, ClientConnection&); void handle_input(const String& js_source); @@ -40,6 +35,8 @@ private: ClientConnection& m_client; WeakPtr m_interpreter; + JS::Handle m_console_global_object; + void clear_output(); void print_html(const String& line); };