From bb9da0ed8d8fedd7a389a7968235d554a495728a Mon Sep 17 00:00:00 2001 From: Andrew Kaster Date: Tue, 6 Feb 2024 08:25:22 -0700 Subject: [PATCH] Ladybird: Plumb overriding root certificate paths through the chromes --- Ladybird/AppKit/UI/LadybirdWebViewBridge.cpp | 4 +-- Ladybird/AppKit/main.mm | 3 ++ Ladybird/HelperProcess.cpp | 32 ++++++++++++++------ Ladybird/HelperProcess.h | 6 ++-- Ladybird/Qt/WebContentView.cpp | 4 +-- Ladybird/Qt/main.cpp | 3 ++ Ladybird/Types.h | 1 + Ladybird/WebContent/main.cpp | 12 +++++--- Ladybird/WebWorker/main.cpp | 12 +++++--- Userland/Utilities/headless-browser.cpp | 19 ++++++++---- 10 files changed, 63 insertions(+), 33 deletions(-) diff --git a/Ladybird/AppKit/UI/LadybirdWebViewBridge.cpp b/Ladybird/AppKit/UI/LadybirdWebViewBridge.cpp index 463dd483ab3..c29ed6058ac 100644 --- a/Ladybird/AppKit/UI/LadybirdWebViewBridge.cpp +++ b/Ladybird/AppKit/UI/LadybirdWebViewBridge.cpp @@ -52,8 +52,8 @@ WebViewBridge::WebViewBridge(Vector screen_rects, float de on_scroll(to_widget_position(position)); }; - on_request_worker_agent = []() { - auto worker_client = MUST(launch_web_worker_process(MUST(get_paths_for_helper_process("WebWorker"sv)))); + on_request_worker_agent = [this]() { + auto worker_client = MUST(launch_web_worker_process(MUST(get_paths_for_helper_process("WebWorker"sv)), m_web_content_options.certificates)); return worker_client->dup_sockets(); }; } diff --git a/Ladybird/AppKit/main.mm b/Ladybird/AppKit/main.mm index 3d8bc8d44f5..f8ee5969903 100644 --- a/Ladybird/AppKit/main.mm +++ b/Ladybird/AppKit/main.mm @@ -41,6 +41,7 @@ ErrorOr serenity_main(Main::Arguments arguments) Gfx::FontDatabase::set_fixed_width_font_query("Csilla 10 400 0"); Vector raw_urls; + Vector certificates; StringView webdriver_content_ipc_path; bool use_gpu_painting = false; bool debug_web_content = false; @@ -51,6 +52,7 @@ ErrorOr serenity_main(Main::Arguments arguments) args_parser.add_option(webdriver_content_ipc_path, "Path to WebDriver IPC for WebContent", "webdriver-content-path", 0, "path", Core::ArgsParser::OptionHideMode::CommandLineAndMarkdown); args_parser.add_option(use_gpu_painting, "Enable GPU painting", "enable-gpu-painting", 0); args_parser.add_option(debug_web_content, "Wait for debugger to attach to WebContent", "debug-web-content", 0); + args_parser.add_option(certificates, "Path to a certificate file", "certificate", 'C', "certificate"); args_parser.parse(arguments); auto sql_server_paths = TRY(get_paths_for_helper_process("SQLServer"sv)); @@ -73,6 +75,7 @@ ErrorOr serenity_main(Main::Arguments arguments) Ladybird::WebContentOptions web_content_options { .command_line = MUST(command_line_builder.to_string()), .executable_path = MUST(String::from_byte_string(MUST(Core::System::current_executable_path()))), + .certificates = move(certificates), .enable_gpu_painting = use_gpu_painting ? Ladybird::EnableGPUPainting::Yes : Ladybird::EnableGPUPainting::No, .use_lagom_networking = Ladybird::UseLagomNetworking::Yes, .wait_for_debugger = debug_web_content ? Ladybird::WaitForDebugger::Yes : Ladybird::WaitForDebugger::No, diff --git a/Ladybird/HelperProcess.cpp b/Ladybird/HelperProcess.cpp index e4fa22dc18b..0f79a06f703 100644 --- a/Ladybird/HelperProcess.cpp +++ b/Ladybird/HelperProcess.cpp @@ -61,6 +61,11 @@ ErrorOr> launch_web_content_process( arguments.append("--use-gpu-painting"sv); if (web_content_options.wait_for_debugger == Ladybird::WaitForDebugger::Yes) arguments.append("--wait-for-debugger"sv); + Vector certificate_args; + for (auto const& certificate : web_content_options.certificates) { + certificate_args.append(ByteString::formatted("--certificate={}", certificate)); + arguments.append(certificate_args.last().view()); + } result = Core::System::exec(arguments[0], arguments.span(), Core::System::SearchInPath::Yes); if (!result.is_error()) @@ -92,7 +97,7 @@ ErrorOr> launch_web_content_process( } template -ErrorOr> launch_generic_server_process(ReadonlySpan candidate_server_paths, StringView serenity_resource_root, StringView server_name) +ErrorOr> launch_generic_server_process(ReadonlySpan candidate_server_paths, StringView serenity_resource_root, Vector const& certificates, StringView server_name) { int socket_fds[2] {}; TRY(Core::System::socketpair(AF_LOCAL, SOCK_STREAM, 0, socket_fds)); @@ -125,9 +130,16 @@ ErrorOr> launch_generic_server_process(ReadonlySpan certificate_args; + for (auto const& certificate : certificates) { + certificate_args.append(ByteString::formatted("--certificate={}", certificate)); + arguments.append(certificate_args.last().view()); + } result = Core::System::exec(arguments[0], arguments.span(), Core::System::SearchInPath::Yes); if (!result.is_error()) @@ -153,20 +165,20 @@ ErrorOr> launch_generic_server_process(ReadonlySpan> launch_image_decoder_process(ReadonlySpan candidate_image_decoder_paths) { - return launch_generic_server_process(candidate_image_decoder_paths, ""sv, "ImageDecoder"sv); + return launch_generic_server_process(candidate_image_decoder_paths, ""sv, {}, "ImageDecoder"sv); } -ErrorOr> launch_web_worker_process(ReadonlySpan candidate_web_worker_paths) +ErrorOr> launch_web_worker_process(ReadonlySpan candidate_web_worker_paths, Vector const& certificates) { - return launch_generic_server_process(candidate_web_worker_paths, ""sv, "WebWorker"sv); + return launch_generic_server_process(candidate_web_worker_paths, ""sv, certificates, "WebWorker"sv); } -ErrorOr> launch_request_server_process(ReadonlySpan candidate_request_server_paths, StringView serenity_resource_root) +ErrorOr> launch_request_server_process(ReadonlySpan candidate_request_server_paths, StringView serenity_resource_root, Vector const& certificates) { - return launch_generic_server_process(candidate_request_server_paths, serenity_resource_root, "RequestServer"sv); + return launch_generic_server_process(candidate_request_server_paths, serenity_resource_root, certificates, "RequestServer"sv); } -ErrorOr> launch_web_socket_process(ReadonlySpan candidate_web_socket_paths, StringView serenity_resource_root) +ErrorOr> launch_web_socket_process(ReadonlySpan candidate_web_socket_paths, StringView serenity_resource_root, Vector const& certificates) { - return launch_generic_server_process(candidate_web_socket_paths, serenity_resource_root, "WebSocket"sv); + return launch_generic_server_process(candidate_web_socket_paths, serenity_resource_root, certificates, "WebSocket"sv); } diff --git a/Ladybird/HelperProcess.h b/Ladybird/HelperProcess.h index 72272dc291e..ca7c61f3069 100644 --- a/Ladybird/HelperProcess.h +++ b/Ladybird/HelperProcess.h @@ -23,6 +23,6 @@ ErrorOr> launch_web_content_process( Ladybird::WebContentOptions const&); ErrorOr> launch_image_decoder_process(ReadonlySpan candidate_image_decoder_paths); -ErrorOr> launch_web_worker_process(ReadonlySpan candidate_web_worker_paths); -ErrorOr> launch_request_server_process(ReadonlySpan candidate_request_server_paths, StringView serenity_resource_root); -ErrorOr> launch_web_socket_process(ReadonlySpan candidate_web_socket_paths, StringView serenity_resource_root); +ErrorOr> launch_web_worker_process(ReadonlySpan candidate_web_worker_paths, Vector const& certificates); +ErrorOr> launch_request_server_process(ReadonlySpan candidate_request_server_paths, StringView serenity_resource_root, Vector const& certificates); +ErrorOr> launch_web_socket_process(ReadonlySpan candidate_web_socket_paths, StringView serenity_resource_root, Vector const& certificates); diff --git a/Ladybird/Qt/WebContentView.cpp b/Ladybird/Qt/WebContentView.cpp index d4480886da6..99c3e6f95c5 100644 --- a/Ladybird/Qt/WebContentView.cpp +++ b/Ladybird/Qt/WebContentView.cpp @@ -119,8 +119,8 @@ WebContentView::WebContentView(QWidget* window, WebContentOptions const& web_con QToolTip::hideText(); }; - on_request_worker_agent = []() { - auto worker_client = MUST(launch_web_worker_process(MUST(get_paths_for_helper_process("WebWorker"sv)))); + on_request_worker_agent = [this]() { + auto worker_client = MUST(launch_web_worker_process(MUST(get_paths_for_helper_process("WebWorker"sv)), m_web_content_options.certificates)); return worker_client->dup_sockets(); }; } diff --git a/Ladybird/Qt/main.cpp b/Ladybird/Qt/main.cpp index 18134f877ca..9bed495a00c 100644 --- a/Ladybird/Qt/main.cpp +++ b/Ladybird/Qt/main.cpp @@ -105,6 +105,7 @@ ErrorOr serenity_main(Main::Arguments arguments) Vector raw_urls; StringView webdriver_content_ipc_path; + Vector certificates; bool enable_callgrind_profiling = false; bool disable_sql_database = false; bool enable_qt_networking = false; @@ -120,6 +121,7 @@ ErrorOr serenity_main(Main::Arguments arguments) args_parser.add_option(enable_qt_networking, "Enable Qt as the backend networking service", "enable-qt-networking", 0); args_parser.add_option(use_gpu_painting, "Enable GPU painting", "enable-gpu-painting", 0); args_parser.add_option(debug_web_content, "Wait for debugger to attach to WebContent", "debug-web-content", 0); + args_parser.add_option(certificates, "Path to a certificate file", "certificate", 'C', "certificate"); args_parser.parse(arguments); RefPtr database; @@ -148,6 +150,7 @@ ErrorOr serenity_main(Main::Arguments arguments) Ladybird::WebContentOptions web_content_options { .command_line = MUST(command_line_builder.to_string()), .executable_path = MUST(String::from_byte_string(MUST(Core::System::current_executable_path()))), + .certificates = move(certificates), .enable_callgrind_profiling = enable_callgrind_profiling ? Ladybird::EnableCallgrindProfiling::Yes : Ladybird::EnableCallgrindProfiling::No, .enable_gpu_painting = use_gpu_painting ? Ladybird::EnableGPUPainting::Yes : Ladybird::EnableGPUPainting::No, .use_lagom_networking = enable_qt_networking ? Ladybird::UseLagomNetworking::No : Ladybird::UseLagomNetworking::Yes, diff --git a/Ladybird/Types.h b/Ladybird/Types.h index 03373c245b4..ee1e266f1d0 100644 --- a/Ladybird/Types.h +++ b/Ladybird/Types.h @@ -38,6 +38,7 @@ enum class WaitForDebugger { struct WebContentOptions { String command_line; String executable_path; + Vector certificates; EnableCallgrindProfiling enable_callgrind_profiling { EnableCallgrindProfiling::No }; EnableGPUPainting enable_gpu_painting { EnableGPUPainting::No }; IsLayoutTestMode is_layout_test_mode { IsLayoutTestMode::No }; diff --git a/Ladybird/WebContent/main.cpp b/Ladybird/WebContent/main.cpp index 1eed83da86e..ec881fcdb43 100644 --- a/Ladybird/WebContent/main.cpp +++ b/Ladybird/WebContent/main.cpp @@ -47,7 +47,7 @@ static ErrorOr load_content_filters(); static ErrorOr load_autoplay_allowlist(); -static ErrorOr initialize_lagom_networking(); +static ErrorOr initialize_lagom_networking(Vector const& certificates); ErrorOr serenity_main(Main::Arguments arguments) { @@ -78,6 +78,7 @@ ErrorOr serenity_main(Main::Arguments arguments) StringView command_line {}; StringView executable_path {}; + Vector certificates; int webcontent_fd_passing_socket { -1 }; bool is_layout_test_mode = false; bool use_lagom_networking = false; @@ -87,6 +88,7 @@ ErrorOr serenity_main(Main::Arguments arguments) Core::ArgsParser args_parser; args_parser.add_option(command_line, "Chrome process command line", "command-line", 0, "command_line"); args_parser.add_option(executable_path, "Chrome process executable path", "executable-path", 0, "executable_path"); + args_parser.add_option(certificates, "Path to a certificate file", "certificate", 'C', "certificate"); args_parser.add_option(webcontent_fd_passing_socket, "File descriptor of the passing socket for the WebContent connection", "webcontent-fd-passing-socket", 'c', "webcontent_fd_passing_socket"); args_parser.add_option(is_layout_test_mode, "Is layout test mode", "layout-test-mode", 0); args_parser.add_option(use_lagom_networking, "Enable Lagom servers for networking", "use-lagom-networking", 0); @@ -112,7 +114,7 @@ ErrorOr serenity_main(Main::Arguments arguments) } else #endif { - TRY(initialize_lagom_networking()); + TRY(initialize_lagom_networking(certificates)); } Web::HTML::Window::set_internals_object_exposed(is_layout_test_mode); @@ -196,14 +198,14 @@ static ErrorOr load_autoplay_allowlist() return {}; } -static ErrorOr initialize_lagom_networking() +static ErrorOr initialize_lagom_networking(Vector const& certificates) { auto candidate_request_server_paths = TRY(get_paths_for_helper_process("RequestServer"sv)); - auto request_server_client = TRY(launch_request_server_process(candidate_request_server_paths, s_serenity_resource_root)); + auto request_server_client = TRY(launch_request_server_process(candidate_request_server_paths, s_serenity_resource_root, certificates)); Web::ResourceLoader::initialize(TRY(WebView::RequestServerAdapter::try_create(move(request_server_client)))); auto candidate_web_socket_paths = TRY(get_paths_for_helper_process("WebSocket"sv)); - auto web_socket_client = TRY(launch_web_socket_process(candidate_web_socket_paths, s_serenity_resource_root)); + auto web_socket_client = TRY(launch_web_socket_process(candidate_web_socket_paths, s_serenity_resource_root, certificates)); Web::WebSockets::WebSocketClientManager::initialize(TRY(WebView::WebSocketClientManagerAdapter::try_create(move(web_socket_client)))); return {}; diff --git a/Ladybird/WebWorker/main.cpp b/Ladybird/WebWorker/main.cpp index 51c382e85a4..108bd145374 100644 --- a/Ladybird/WebWorker/main.cpp +++ b/Ladybird/WebWorker/main.cpp @@ -26,7 +26,7 @@ #include #include -static ErrorOr initialize_lagom_networking(); +static ErrorOr initialize_lagom_networking(Vector const& certificates); ErrorOr serenity_main(Main::Arguments arguments) { @@ -34,10 +34,12 @@ ErrorOr serenity_main(Main::Arguments arguments) int fd_passing_socket { -1 }; StringView serenity_resource_root; + Vector certificates; Core::ArgsParser args_parser; args_parser.add_option(fd_passing_socket, "File descriptor of the fd passing socket", "fd-passing-socket", 'c', "fd-passing-socket"); args_parser.add_option(serenity_resource_root, "Absolute path to directory for serenity resources", "serenity-resource-root", 'r', "serenity-resource-root"); + args_parser.add_option(certificates, "Path to a certificate file", "certificate", 'C', "certificate"); args_parser.parse(arguments); platform_init(); @@ -47,7 +49,7 @@ ErrorOr serenity_main(Main::Arguments arguments) Web::Platform::FontPlugin::install(*new Web::Platform::FontPluginSerenity); - TRY(initialize_lagom_networking()); + TRY(initialize_lagom_networking(certificates)); VERIFY(fd_passing_socket >= 0); @@ -59,14 +61,14 @@ ErrorOr serenity_main(Main::Arguments arguments) return event_loop.exec(); } -static ErrorOr initialize_lagom_networking() +static ErrorOr initialize_lagom_networking(Vector const& certificates) { auto candidate_request_server_paths = TRY(get_paths_for_helper_process("RequestServer"sv)); - auto request_server_client = TRY(launch_request_server_process(candidate_request_server_paths, s_serenity_resource_root)); + auto request_server_client = TRY(launch_request_server_process(candidate_request_server_paths, s_serenity_resource_root, certificates)); Web::ResourceLoader::initialize(TRY(WebView::RequestServerAdapter::try_create(move(request_server_client)))); auto candidate_web_socket_paths = TRY(get_paths_for_helper_process("WebSocket"sv)); - auto web_socket_client = TRY(launch_web_socket_process(candidate_web_socket_paths, s_serenity_resource_root)); + auto web_socket_client = TRY(launch_web_socket_process(candidate_web_socket_paths, s_serenity_resource_root, certificates)); Web::WebSockets::WebSocketClientManager::initialize(TRY(WebView::WebSocketClientManagerAdapter::try_create(move(web_socket_client)))); return {}; diff --git a/Userland/Utilities/headless-browser.cpp b/Userland/Utilities/headless-browser.cpp index b0857149ad9..9a2a449f320 100644 --- a/Userland/Utilities/headless-browser.cpp +++ b/Userland/Utilities/headless-browser.cpp @@ -62,7 +62,7 @@ static StringView s_current_test_path; class HeadlessWebContentView final : public WebView::ViewImplementation { public: - static ErrorOr> create(Core::AnonymousBuffer theme, Gfx::IntSize const& window_size, String const& command_line, StringView web_driver_ipc_path, Ladybird::IsLayoutTestMode is_layout_test_mode = Ladybird::IsLayoutTestMode::No) + static ErrorOr> create(Core::AnonymousBuffer theme, Gfx::IntSize const& window_size, String const& command_line, StringView web_driver_ipc_path, Ladybird::IsLayoutTestMode is_layout_test_mode = Ladybird::IsLayoutTestMode::No, Vector const& certificates = {}) { #if defined(AK_OS_SERENITY) auto database = TRY(WebView::Database::create()); @@ -73,16 +73,18 @@ public: auto cookie_jar = TRY(WebView::CookieJar::create(*database)); - auto view = TRY(adopt_nonnull_own_or_enomem(new (nothrow) HeadlessWebContentView(move(database), move(cookie_jar)))); + auto view = TRY(adopt_nonnull_own_or_enomem(new (nothrow) HeadlessWebContentView(move(database), move(cookie_jar), certificates))); #if defined(AK_OS_SERENITY) view->m_client_state.client = TRY(WebView::WebContentClient::try_create(*view)); (void)command_line; + (void)certificates; (void)is_layout_test_mode; #else Ladybird::WebContentOptions web_content_options { .command_line = command_line, .executable_path = MUST(String::from_byte_string(MUST(Core::System::current_executable_path()))), + .certificates = certificates, .is_layout_test_mode = is_layout_test_mode, }; @@ -151,9 +153,10 @@ public: } private: - HeadlessWebContentView(NonnullRefPtr database, WebView::CookieJar cookie_jar) + HeadlessWebContentView(NonnullRefPtr database, WebView::CookieJar cookie_jar, Vector certificates) : m_database(move(database)) , m_cookie_jar(move(cookie_jar)) + , m_certificates(move(certificates)) { on_scroll_to_point = [this](auto position) { m_viewport_rect.set_location(position); @@ -176,11 +179,12 @@ private: m_cookie_jar.set_cookie(url, cookie, source); }; - on_request_worker_agent = []() { + on_request_worker_agent = [this]() { #if defined(AK_OS_SERENITY) auto worker_client = MUST(Web::HTML::WebWorkerClient::try_create()); + (void)this; #else - auto worker_client = MUST(launch_web_worker_process(MUST(get_paths_for_helper_process("WebWorker"sv)))); + auto worker_client = MUST(launch_web_worker_process(MUST(get_paths_for_helper_process("WebWorker"sv)), m_certificates)); #endif return worker_client->dup_sockets(); }; @@ -199,6 +203,7 @@ private: NonnullRefPtr m_database; WebView::CookieJar m_cookie_jar; + Vector m_certificates; }; static ErrorOr> load_page_for_screenshot_and_exit(Core::EventLoop& event_loop, HeadlessWebContentView& view, int screenshot_timeout) @@ -598,6 +603,7 @@ ErrorOr serenity_main(Main::Arguments arguments) bool is_layout_test_mode = false; StringView test_root_path; ByteString test_glob; + Vector certificates; Core::ArgsParser args_parser; args_parser.set_general_help("This utility runs the Browser in headless mode."); @@ -610,6 +616,7 @@ ErrorOr serenity_main(Main::Arguments arguments) args_parser.add_option(resources_folder, "Path of the base resources folder (defaults to /res)", "resources", 'r', "resources-root-path"); args_parser.add_option(web_driver_ipc_path, "Path to the WebDriver IPC socket", "webdriver-ipc-path", 0, "path"); args_parser.add_option(is_layout_test_mode, "Enable layout test mode", "layout-test-mode", 0); + args_parser.add_option(certificates, "Path to a certificate file", "certificate", 'C', "certificate"); args_parser.add_positional_argument(raw_url, "URL to open", "url", Core::ArgsParser::Required::No); args_parser.parse(arguments); @@ -632,7 +639,7 @@ ErrorOr serenity_main(Main::Arguments arguments) StringBuilder command_line_builder; command_line_builder.join(' ', arguments.strings); - auto view = TRY(HeadlessWebContentView::create(move(theme), window_size, MUST(command_line_builder.to_string()), web_driver_ipc_path, is_layout_test_mode ? Ladybird::IsLayoutTestMode::Yes : Ladybird::IsLayoutTestMode::No)); + auto view = TRY(HeadlessWebContentView::create(move(theme), window_size, MUST(command_line_builder.to_string()), web_driver_ipc_path, is_layout_test_mode ? Ladybird::IsLayoutTestMode::Yes : Ladybird::IsLayoutTestMode::No, certificates)); if (!test_root_path.is_empty()) { test_glob = ByteString::formatted("*{}*", test_glob);