1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 08:27:45 +00:00

Ladybird/AppKit: Sanitize user-provided URLs with LibWebView

This commit is contained in:
Timothy Flynn 2023-10-13 11:04:07 -04:00 committed by Tim Flynn
parent f023e37de7
commit aa5cd24c90
7 changed files with 58 additions and 95 deletions

View file

@ -9,6 +9,7 @@
#include <AK/Optional.h> #include <AK/Optional.h>
#include <AK/StringView.h> #include <AK/StringView.h>
#include <AK/URL.h> #include <AK/URL.h>
#include <AK/Vector.h>
#include <LibWeb/CSS/PreferredColorScheme.h> #include <LibWeb/CSS/PreferredColorScheme.h>
#include <LibWeb/HTML/ActivateTab.h> #include <LibWeb/HTML/ActivateTab.h>
#include <LibWebView/CookieJar.h> #include <LibWebView/CookieJar.h>
@ -20,7 +21,8 @@
@interface ApplicationDelegate : NSObject <NSApplicationDelegate> @interface ApplicationDelegate : NSObject <NSApplicationDelegate>
- (nullable instancetype)init:(Optional<URL>)initial_url - (nullable instancetype)init:(Vector<URL>)initial_urls
newTabPageURL:(URL)new_tab_page_url
withCookieJar:(WebView::CookieJar)cookie_jar withCookieJar:(WebView::CookieJar)cookie_jar
webdriverContentIPCPath:(StringView)webdriver_content_ipc_path; webdriverContentIPCPath:(StringView)webdriver_content_ipc_path;

View file

@ -4,15 +4,12 @@
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
#include <BrowserSettings/Defaults.h>
#import <Application/ApplicationDelegate.h> #import <Application/ApplicationDelegate.h>
#import <LibWebView/UserAgent.h> #import <LibWebView/UserAgent.h>
#import <UI/LadybirdWebView.h> #import <UI/LadybirdWebView.h>
#import <UI/Tab.h> #import <UI/Tab.h>
#import <UI/TabController.h> #import <UI/TabController.h>
#import <Utilities/Conversions.h> #import <Utilities/Conversions.h>
#import <Utilities/URL.h>
#if !__has_feature(objc_arc) #if !__has_feature(objc_arc)
# error "This project requires ARC" # error "This project requires ARC"
@ -20,7 +17,7 @@
@interface ApplicationDelegate () @interface ApplicationDelegate ()
{ {
Optional<URL> m_initial_url; Vector<URL> m_initial_urls;
URL m_new_tab_page_url; URL m_new_tab_page_url;
// This will always be populated, but we cannot have a non-default constructible instance variable. // This will always be populated, but we cannot have a non-default constructible instance variable.
@ -47,7 +44,8 @@
@implementation ApplicationDelegate @implementation ApplicationDelegate
- (instancetype)init:(Optional<URL>)initial_url - (instancetype)init:(Vector<URL>)initial_urls
newTabPageURL:(URL)new_tab_page_url
withCookieJar:(WebView::CookieJar)cookie_jar withCookieJar:(WebView::CookieJar)cookie_jar
webdriverContentIPCPath:(StringView)webdriver_content_ipc_path webdriverContentIPCPath:(StringView)webdriver_content_ipc_path
{ {
@ -66,8 +64,8 @@
self.managed_tabs = [[NSMutableArray alloc] init]; self.managed_tabs = [[NSMutableArray alloc] init];
m_initial_url = move(initial_url); m_initial_urls = move(initial_urls);
m_new_tab_page_url = Ladybird::rebase_url_on_serenity_resource_root(Browser::default_new_tab_url); m_new_tab_page_url = move(new_tab_page_url);
m_cookie_jar = move(cookie_jar); m_cookie_jar = move(cookie_jar);
@ -481,9 +479,19 @@
- (void)applicationDidFinishLaunching:(NSNotification*)notification - (void)applicationDidFinishLaunching:(NSNotification*)notification
{ {
[self createNewTab:m_initial_url Tab* tab = nil;
fromTab:nil
activateTab:Web::HTML::ActivateTab::Yes]; for (auto const& url : m_initial_urls) {
auto activate_tab = tab == nil ? Web::HTML::ActivateTab::Yes : Web::HTML::ActivateTab::No;
auto* controller = [self createNewTab:url
fromTab:tab
activateTab:activate_tab];
tab = (Tab*)[controller window];
}
m_initial_urls.clear();
} }
- (void)applicationWillTerminate:(NSNotification*)notification - (void)applicationWillTerminate:(NSNotification*)notification

View file

@ -5,6 +5,7 @@
*/ */
#include <LibWebView/History.h> #include <LibWebView/History.h>
#include <LibWebView/URL.h>
#import <Application/ApplicationDelegate.h> #import <Application/ApplicationDelegate.h>
#import <LibWeb/Loader/ResourceLoader.h> #import <LibWeb/Loader/ResourceLoader.h>
@ -13,7 +14,6 @@
#import <UI/Tab.h> #import <UI/Tab.h>
#import <UI/TabController.h> #import <UI/TabController.h>
#import <Utilities/Conversions.h> #import <Utilities/Conversions.h>
#import <Utilities/URL.h>
#if !__has_feature(objc_arc) #if !__has_feature(objc_arc)
# error "This project requires ARC" # error "This project requires ARC"
@ -600,9 +600,11 @@ enum class IsHistoryNavigation {
return NO; return NO;
} }
auto* url_string = [[text_view textStorage] string]; auto url_string = Ladybird::ns_string_to_string([[text_view textStorage] string]);
auto url = Ladybird::sanitize_url(url_string);
[self loadURL:url]; if (auto url = WebView::sanitize_url(url_string); url.has_value()) {
[self loadURL:*url];
}
[self.window makeFirstResponder:nil]; [self.window makeFirstResponder:nil];
return YES; return YES;

View file

@ -1,21 +0,0 @@
/*
* Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/StringView.h>
#include <AK/URL.h>
#import <System/Cocoa.h>
namespace Ladybird {
URL sanitize_url(NSString*);
URL sanitize_url(StringView);
URL rebase_url_on_serenity_resource_root(StringView);
}

View file

@ -1,51 +0,0 @@
/*
* Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/DeprecatedString.h>
#include <AK/String.h>
#include <AK/Vector.h>
#include <Ladybird/Utilities.h>
#include <LibFileSystem/FileSystem.h>
#import <Utilities/URL.h>
namespace Ladybird {
URL sanitize_url(StringView url_string)
{
if (url_string.starts_with('/') || FileSystem::exists(url_string))
return MUST(String::formatted("file://{}", MUST(FileSystem::real_path(url_string))));
URL url { url_string };
if (!url.is_valid())
url = MUST(String::formatted("https://{}", url_string));
return url;
}
URL sanitize_url(NSString* url_string)
{
auto const* utf8 = [url_string UTF8String];
return sanitize_url({ utf8, strlen(utf8) });
}
URL rebase_url_on_serenity_resource_root(StringView url_string)
{
URL url { url_string };
Vector<DeprecatedString> paths;
for (auto segment : s_serenity_resource_root.split('/'))
paths.append(move(segment));
for (size_t i = 0; i < url.path_segment_count(); ++i)
paths.append(url.path_segment_at_index(i));
url.set_paths(move(paths));
return url;
}
}

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
#include <BrowserSettings/Defaults.h>
#include <Ladybird/Utilities.h> #include <Ladybird/Utilities.h>
#include <LibCore/ArgsParser.h> #include <LibCore/ArgsParser.h>
#include <LibCore/EventLoop.h> #include <LibCore/EventLoop.h>
@ -11,18 +12,34 @@
#include <LibMain/Main.h> #include <LibMain/Main.h>
#include <LibWebView/CookieJar.h> #include <LibWebView/CookieJar.h>
#include <LibWebView/Database.h> #include <LibWebView/Database.h>
#include <LibWebView/URL.h>
#import <Application/Application.h> #import <Application/Application.h>
#import <Application/ApplicationDelegate.h> #import <Application/ApplicationDelegate.h>
#import <Application/EventLoopImplementation.h> #import <Application/EventLoopImplementation.h>
#import <UI/Tab.h> #import <UI/Tab.h>
#import <UI/TabController.h> #import <UI/TabController.h>
#import <Utilities/URL.h>
#if !__has_feature(objc_arc) #if !__has_feature(objc_arc)
# error "This project requires ARC" # error "This project requires ARC"
#endif #endif
static URL rebase_url_on_serenity_resource_root(StringView url_string)
{
URL url { url_string };
Vector<DeprecatedString> paths;
for (auto segment : s_serenity_resource_root.split('/'))
paths.append(move(segment));
for (size_t i = 0; i < url.path_segment_count(); ++i)
paths.append(url.path_segment_at_index(i));
url.set_paths(move(paths));
return url;
}
ErrorOr<int> serenity_main(Main::Arguments arguments) ErrorOr<int> serenity_main(Main::Arguments arguments)
{ {
[Application sharedApplication]; [Application sharedApplication];
@ -36,12 +53,12 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
Gfx::FontDatabase::set_default_font_query("Katica 10 400 0"); Gfx::FontDatabase::set_default_font_query("Katica 10 400 0");
Gfx::FontDatabase::set_fixed_width_font_query("Csilla 10 400 0"); Gfx::FontDatabase::set_fixed_width_font_query("Csilla 10 400 0");
StringView url; Vector<StringView> raw_urls;
StringView webdriver_content_ipc_path; StringView webdriver_content_ipc_path;
Core::ArgsParser args_parser; Core::ArgsParser args_parser;
args_parser.set_general_help("The Ladybird web browser"); args_parser.set_general_help("The Ladybird web browser");
args_parser.add_positional_argument(url, "URL to open", "url", Core::ArgsParser::Required::No); args_parser.add_positional_argument(raw_urls, "URLs to open", "url", Core::ArgsParser::Required::No);
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(webdriver_content_ipc_path, "Path to WebDriver IPC for WebContent", "webdriver-content-path", 0, "path", Core::ArgsParser::OptionHideMode::CommandLineAndMarkdown);
args_parser.parse(arguments); args_parser.parse(arguments);
@ -49,12 +66,19 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
auto database = TRY(WebView::Database::create(move(sql_server_paths))); auto database = TRY(WebView::Database::create(move(sql_server_paths)));
auto cookie_jar = TRY(WebView::CookieJar::create(*database)); auto cookie_jar = TRY(WebView::CookieJar::create(*database));
Optional<URL> initial_url; auto new_tab_page_url = rebase_url_on_serenity_resource_root(Browser::default_new_tab_url);
if (auto parsed_url = Ladybird::sanitize_url(url); parsed_url.is_valid()) { Vector<URL> initial_urls;
initial_url = move(parsed_url);
for (auto const& raw_url : raw_urls) {
if (auto url = WebView::sanitize_url(raw_url); url.has_value())
initial_urls.append(url.release_value());
} }
auto* delegate = [[ApplicationDelegate alloc] init:move(initial_url) if (initial_urls.is_empty())
initial_urls.append(new_tab_page_url);
auto* delegate = [[ApplicationDelegate alloc] init:move(initial_urls)
newTabPageURL:move(new_tab_page_url)
withCookieJar:move(cookie_jar) withCookieJar:move(cookie_jar)
webdriverContentIPCPath:webdriver_content_ipc_path]; webdriverContentIPCPath:webdriver_content_ipc_path];

View file

@ -145,7 +145,6 @@ elseif (APPLE)
AppKit/UI/TabController.mm AppKit/UI/TabController.mm
AppKit/Utilities/Conversions.mm AppKit/Utilities/Conversions.mm
AppKit/Utilities/NSString+Ladybird.mm AppKit/Utilities/NSString+Ladybird.mm
AppKit/Utilities/URL.mm
) )
target_include_directories(ladybird PRIVATE AppKit) target_include_directories(ladybird PRIVATE AppKit)
target_link_libraries(ladybird PRIVATE ${COCOA_LIBRARY} LibUnicode) target_link_libraries(ladybird PRIVATE ${COCOA_LIBRARY} LibUnicode)