2020-01-18 08:38:21 +00:00
/*
2021-01-30 22:05:21 +00:00
* Copyright ( c ) 2018 - 2021 , Andreas Kling < kling @ serenityos . org >
2022-08-13 13:48:31 +00:00
* Copyright ( c ) 2022 , Sam Atkins < atkinssj @ serenityos . org >
2022-10-06 08:34:25 +00:00
* Copyright ( c ) 2022 , the SerenityOS developers .
2020-01-18 08:38:21 +00:00
*
2021-04-22 08:24:48 +00:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-01-18 08:38:21 +00:00
*/
2022-01-11 03:06:11 +00:00
# include <Applications/Browser/Browser.h>
# include <Applications/Browser/BrowserWindow.h>
# include <Applications/Browser/Tab.h>
# include <Applications/Browser/WindowActions.h>
2023-06-01 12:21:06 +00:00
# include <Applications/BrowserSettings/Defaults.h>
2021-08-25 22:18:42 +00:00
# include <LibConfig/Client.h>
2020-05-27 19:57:30 +00:00
# include <LibCore/ArgsParser.h>
2022-08-13 13:48:31 +00:00
# include <LibCore/FileWatcher.h>
2020-08-05 15:40:03 +00:00
# include <LibCore/StandardPaths.h>
2021-11-23 09:59:50 +00:00
# include <LibCore/System.h>
2021-01-03 11:10:34 +00:00
# include <LibDesktop/Launcher.h>
2020-02-06 19:33:02 +00:00
# include <LibGUI/Application.h>
# include <LibGUI/BoxLayout.h>
2020-11-02 19:30:17 +00:00
# include <LibGUI/Icon.h>
2020-04-23 19:14:31 +00:00
# include <LibGUI/TabWidget.h>
2021-11-22 18:47:14 +00:00
# include <LibMain/Main.h>
2022-04-30 10:06:30 +00:00
# include <LibWeb/Loader/ResourceLoader.h>
2023-08-31 11:07:07 +00:00
# include <LibWebView/CookieJar.h>
# include <LibWebView/Database.h>
2022-10-12 21:51:37 +00:00
# include <LibWebView/OutOfProcessWebView.h>
2022-04-30 10:06:30 +00:00
# include <LibWebView/RequestServerAdapter.h>
2023-10-19 19:52:06 +00:00
# include <LibWebView/SearchEngine.h>
2023-10-13 14:31:52 +00:00
# include <LibWebView/URL.h>
2021-03-12 16:29:37 +00:00
# include <unistd.h>
2019-10-05 08:19:12 +00:00
2020-05-10 09:18:47 +00:00
namespace Browser {
2022-12-04 18:02:33 +00:00
DeprecatedString g_search_engine ;
DeprecatedString g_home_url ;
DeprecatedString g_new_tab_url ;
2023-04-21 11:54:56 +00:00
Vector < String > g_content_filters ;
2022-02-01 10:17:37 +00:00
bool g_content_filters_enabled { true } ;
2023-04-17 17:37:36 +00:00
Vector < String > g_autoplay_allowlist ;
bool g_autoplay_allowed_on_all_websites { false } ;
2022-12-04 18:02:33 +00:00
Vector < DeprecatedString > g_proxies ;
HashMap < DeprecatedString , size_t > g_proxy_mappings ;
2022-01-11 03:06:11 +00:00
IconBag g_icon_bag ;
2022-12-04 18:02:33 +00:00
DeprecatedString g_webdriver_content_ipc_path ;
2020-08-05 15:40:03 +00:00
2020-05-10 09:18:47 +00:00
}
2020-04-25 15:20:23 +00:00
2022-01-20 11:17:52 +00:00
static ErrorOr < void > load_content_filters ( )
{
2023-04-21 11:54:56 +00:00
auto file = TRY ( Core : : File : : open ( TRY ( String : : formatted ( " {}/BrowserContentFilters.txt " , Core : : StandardPaths : : config_directory ( ) ) ) , Core : : File : : OpenMode : : Read ) ) ;
2023-05-03 22:45:18 +00:00
auto ad_filter_list = TRY ( Core : : InputBufferedFile : : create ( move ( file ) ) ) ;
2022-01-20 17:47:39 +00:00
auto buffer = TRY ( ByteBuffer : : create_uninitialized ( 4096 ) ) ;
2023-04-21 11:36:40 +00:00
Browser : : g_content_filters . clear_with_capacity ( ) ;
2022-01-20 17:47:39 +00:00
while ( TRY ( ad_filter_list - > can_read_line ( ) ) ) {
2022-04-15 13:52:33 +00:00
auto line = TRY ( ad_filter_list - > read_line ( buffer ) ) ;
2023-04-21 11:54:56 +00:00
if ( line . is_empty ( ) )
continue ;
auto pattern = TRY ( String : : from_utf8 ( line ) ) ;
TRY ( Browser : : g_content_filters . try_append ( move ( pattern ) ) ) ;
2022-01-20 11:17:52 +00:00
}
return { } ;
}
2023-04-17 17:37:36 +00:00
static ErrorOr < void > load_autoplay_allowlist ( )
{
auto file = TRY ( Core : : File : : open ( TRY ( String : : formatted ( " {}/BrowserAutoplayAllowlist.txt " , Core : : StandardPaths : : config_directory ( ) ) ) , Core : : File : : OpenMode : : Read ) ) ;
2023-05-03 22:45:18 +00:00
auto allowlist = TRY ( Core : : InputBufferedFile : : create ( move ( file ) ) ) ;
2023-04-17 17:37:36 +00:00
auto buffer = TRY ( ByteBuffer : : create_uninitialized ( 4096 ) ) ;
Browser : : g_autoplay_allowlist . clear_with_capacity ( ) ;
while ( TRY ( allowlist - > can_read_line ( ) ) ) {
auto line = TRY ( allowlist - > read_line ( buffer ) ) ;
if ( line . is_empty ( ) )
continue ;
auto domain = TRY ( String : : from_utf8 ( line ) ) ;
TRY ( Browser : : g_autoplay_allowlist . try_append ( move ( domain ) ) ) ;
}
return { } ;
}
2021-11-22 18:47:14 +00:00
ErrorOr < int > serenity_main ( Main : : Arguments arguments )
2019-10-05 08:19:12 +00:00
{
2020-03-31 11:01:55 +00:00
if ( getuid ( ) = = 0 ) {
2020-10-25 16:46:16 +00:00
warnln ( " Refusing to run as root " ) ;
2020-03-31 11:01:55 +00:00
return 1 ;
}
2022-10-12 09:50:33 +00:00
TRY ( Core : : System : : pledge ( " stdio recvfd sendfd unix fattr cpath rpath wpath proc exec " ) ) ;
2020-01-11 19:50:27 +00:00
2023-10-13 14:31:52 +00:00
Vector < StringView > specified_urls ;
2020-05-27 19:57:30 +00:00
Core : : ArgsParser args_parser ;
2022-08-13 13:48:31 +00:00
args_parser . add_positional_argument ( specified_urls , " URLs to open " , " url " , Core : : ArgsParser : : Required : : No ) ;
2023-09-03 13:14:56 +00:00
args_parser . add_option ( Browser : : g_webdriver_content_ipc_path , " Path to WebDriver IPC for WebContent " , " webdriver-content-path " , 0 , " path " , Core : : ArgsParser : : OptionHideMode : : CommandLineAndMarkdown ) ;
2022-10-12 09:50:33 +00:00
2021-11-23 00:03:05 +00:00
args_parser . parse ( arguments ) ;
2020-05-27 19:57:30 +00:00
2023-05-05 04:24:53 +00:00
auto app = TRY ( GUI : : Application : : create ( arguments ) ) ;
2019-10-05 08:19:12 +00:00
2022-02-11 16:33:09 +00:00
Config : : pledge_domain ( " Browser " ) ;
2022-01-31 20:40:48 +00:00
Config : : monitor_domain ( " Browser " ) ;
2021-08-25 22:18:42 +00:00
2021-01-03 11:10:34 +00:00
// Connect to LaunchServer immediately and let it know that we won't ask for anything other than opening
// the user's downloads directory.
// FIXME: This should go away with a standalone download manager at some point.
2022-09-28 23:30:58 +00:00
TRY ( Desktop : : Launcher : : add_allowed_url ( URL : : create_with_file_scheme ( Core : : StandardPaths : : downloads_directory ( ) ) ) ) ;
2021-11-23 23:23:00 +00:00
TRY ( Desktop : : Launcher : : seal_allowlist ( ) ) ;
2021-01-03 11:10:34 +00:00
2022-09-06 06:04:06 +00:00
TRY ( Core : : System : : unveil ( " /tmp/session/%sid/portal/filesystemaccess " , " rw " ) ) ;
TRY ( Core : : System : : unveil ( " /tmp/session/%sid/portal/filesystemaccess " , " rw " ) ) ;
TRY ( Core : : System : : unveil ( " /tmp/session/%sid/portal/image " , " rw " ) ) ;
TRY ( Core : : System : : unveil ( " /tmp/session/%sid/portal/webcontent " , " rw " ) ) ;
TRY ( Core : : System : : unveil ( " /tmp/session/%sid/portal/request " , " rw " ) ) ;
2022-10-27 16:56:22 +00:00
TRY ( Core : : System : : unveil ( " /tmp/session/%sid/portal/sql " , " rw " ) ) ;
2021-11-23 09:59:50 +00:00
TRY ( Core : : System : : unveil ( " /home " , " rwc " ) ) ;
TRY ( Core : : System : : unveil ( " /res " , " r " ) ) ;
TRY ( Core : : System : : unveil ( " /etc/passwd " , " r " ) ) ;
2022-01-20 17:27:56 +00:00
TRY ( Core : : System : : unveil ( " /etc/timezone " , " r " ) ) ;
2022-01-31 20:55:26 +00:00
TRY ( Core : : System : : unveil ( " /bin/BrowserSettings " , " x " ) ) ;
2022-10-06 08:34:25 +00:00
TRY ( Core : : System : : unveil ( " /bin/Browser " , " x " ) ) ;
2021-11-23 09:59:50 +00:00
TRY ( Core : : System : : unveil ( nullptr , nullptr ) ) ;
2020-03-26 19:06:23 +00:00
2022-04-30 10:06:30 +00:00
Web : : ResourceLoader : : initialize ( TRY ( WebView : : RequestServerAdapter : : try_create ( ) ) ) ;
2022-07-11 17:32:29 +00:00
auto app_icon = GUI : : Icon : : default_icon ( " app-browser " sv ) ;
2020-11-02 19:30:17 +00:00
2023-06-01 12:21:06 +00:00
Browser : : g_home_url = Config : : read_string ( " Browser " sv , " Preferences " sv , " Home " sv , Browser : : default_homepage_url ) ;
Browser : : g_new_tab_url = Config : : read_string ( " Browser " sv , " Preferences " sv , " NewTab " sv , Browser : : default_new_tab_url ) ;
2023-10-19 19:52:06 +00:00
Browser : : g_search_engine = Config : : read_string ( " Browser " sv , " Preferences " sv , " SearchEngine " sv , WebView : : default_search_engine ( ) . query_url ) ;
2023-06-01 12:21:06 +00:00
Browser : : g_content_filters_enabled = Config : : read_bool ( " Browser " sv , " Preferences " sv , " EnableContentFilters " sv , Browser : : default_enable_content_filters ) ;
Browser : : g_autoplay_allowed_on_all_websites = Config : : read_bool ( " Browser " sv , " Preferences " sv , " AllowAutoplayOnAllWebsites " sv , Browser : : default_allow_autoplay_on_all_websites ) ;
2020-04-25 03:25:11 +00:00
2022-01-11 03:06:11 +00:00
Browser : : g_icon_bag = TRY ( Browser : : IconBag : : try_create ( ) ) ;
2023-08-31 11:07:07 +00:00
auto database = TRY ( WebView : : Database : : create ( ) ) ;
2022-01-20 11:17:52 +00:00
TRY ( load_content_filters ( ) ) ;
2023-04-17 17:37:36 +00:00
TRY ( load_autoplay_allowlist ( ) ) ;
2021-01-05 17:12:29 +00:00
2022-07-11 17:32:29 +00:00
for ( auto & group : Config : : list_groups ( " Browser " sv ) ) {
if ( ! group . starts_with ( " Proxy: " sv ) )
2022-04-07 21:16:47 +00:00
continue ;
2022-07-11 17:32:29 +00:00
for ( auto & key : Config : : list_keys ( " Browser " sv , group ) ) {
2022-04-07 21:16:47 +00:00
auto proxy_spec = group . substring_view ( 6 ) ;
auto existing_proxy = Browser : : g_proxies . find ( proxy_spec ) ;
if ( existing_proxy . is_end ( ) )
Browser : : g_proxies . append ( proxy_spec ) ;
Browser : : g_proxy_mappings . set ( key , existing_proxy . index ( ) ) ;
}
}
2023-10-13 14:31:52 +00:00
Vector < URL > initial_urls ;
2022-08-13 13:48:31 +00:00
2023-10-13 14:31:52 +00:00
for ( auto specified_url : specified_urls ) {
if ( auto url = WebView : : sanitize_url ( specified_url ) ; url . has_value ( ) )
initial_urls . append ( url . release_value ( ) ) ;
}
if ( initial_urls . is_empty ( ) )
initial_urls . append ( Browser : : g_home_url ) ;
2020-04-24 12:06:17 +00:00
2023-08-31 11:07:07 +00:00
auto cookie_jar = TRY ( WebView : : CookieJar : : create ( * database ) ) ;
2023-10-13 14:31:52 +00:00
auto window = Browser : : BrowserWindow : : construct ( cookie_jar , initial_urls ) ;
2022-10-12 09:50:33 +00:00
2022-01-31 19:43:18 +00:00
auto content_filters_watcher = TRY ( Core : : FileWatcher : : create ( ) ) ;
content_filters_watcher - > on_change = [ & ] ( Core : : FileWatcherEvent const & ) {
dbgln ( " Reloading content filters because config file changed " ) ;
auto error = load_content_filters ( ) ;
if ( error . is_error ( ) ) {
dbgln ( " Reloading content filters failed: {} " , error . release_error ( ) ) ;
return ;
}
2022-02-01 10:17:37 +00:00
window - > content_filters_changed ( ) ;
2022-01-31 19:43:18 +00:00
} ;
2022-12-04 18:02:33 +00:00
TRY ( content_filters_watcher - > add_watch ( DeprecatedString : : formatted ( " {}/BrowserContentFilters.txt " , Core : : StandardPaths : : config_directory ( ) ) , Core : : FileWatcherEvent : : Type : : ContentModified ) ) ;
2022-01-31 19:43:18 +00:00
2023-04-17 17:37:36 +00:00
auto autoplay_allowlist_watcher = TRY ( Core : : FileWatcher : : create ( ) ) ;
autoplay_allowlist_watcher - > on_change = [ & ] ( Core : : FileWatcherEvent const & ) {
dbgln ( " Reloading autoplay allowlist because config file changed " ) ;
if ( auto error = load_autoplay_allowlist ( ) ; error . is_error ( ) ) {
dbgln ( " Reloading autoplay allowlist failed: {} " , error . release_error ( ) ) ;
return ;
}
window - > autoplay_allowlist_changed ( ) ;
} ;
TRY ( autoplay_allowlist_watcher - > add_watch ( DeprecatedString : : formatted ( " {}/BrowserAutoplayAllowlist.txt " , Core : : StandardPaths : : config_directory ( ) ) , Core : : FileWatcherEvent : : Type : : ContentModified ) ) ;
2021-04-17 20:08:06 +00:00
app - > on_action_enter = [ & ] ( GUI : : Action & action ) {
2021-05-17 21:15:20 +00:00
if ( auto * browser_window = dynamic_cast < Browser : : BrowserWindow * > ( app - > active_window ( ) ) ) {
auto * tab = static_cast < Browser : : Tab * > ( browser_window - > tab_widget ( ) . active_widget ( ) ) ;
if ( ! tab )
return ;
tab - > action_entered ( action ) ;
}
2021-04-17 20:08:06 +00:00
} ;
app - > on_action_leave = [ & ] ( auto & action ) {
2021-05-17 21:15:20 +00:00
if ( auto * browser_window = dynamic_cast < Browser : : BrowserWindow * > ( app - > active_window ( ) ) ) {
auto * tab = static_cast < Browser : : Tab * > ( browser_window - > tab_widget ( ) . active_widget ( ) ) ;
if ( ! tab )
return ;
tab - > action_left ( action ) ;
}
2020-04-25 15:20:23 +00:00
} ;
2020-04-24 12:06:17 +00:00
window - > show ( ) ;
2019-10-05 08:19:12 +00:00
2022-11-01 19:43:53 +00:00
window - > broadcast_window_position ( window - > position ( ) ) ;
window - > broadcast_window_size ( window - > size ( ) ) ;
2020-07-04 12:05:19 +00:00
return app - > exec ( ) ;
2019-10-05 08:19:12 +00:00
}