2020-01-18 11:38:21 +03:00
/*
2021-01-31 01:05:21 +03:00
* Copyright ( c ) 2018 - 2021 , Andreas Kling < kling @ serenityos . org >
2022-08-13 16:48:31 +03:00
* Copyright ( c ) 2022 , Sam Atkins < atkinssj @ serenityos . org >
2022-10-06 11:34:25 +03:00
* Copyright ( c ) 2022 , the SerenityOS developers .
2020-01-18 11:38:21 +03:00
*
2021-04-22 11:24:48 +03:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-01-18 11:38:21 +03:00
*/
2022-01-11 06:06:11 +03:00
# include <Applications/Browser/Browser.h>
# include <Applications/Browser/BrowserWindow.h>
# include <Applications/Browser/Tab.h>
# include <Applications/Browser/WindowActions.h>
2023-06-01 15:21:06 +03:00
# include <Applications/BrowserSettings/Defaults.h>
2021-08-26 01:18:42 +03:00
# include <LibConfig/Client.h>
2020-05-27 22:57:30 +03:00
# include <LibCore/ArgsParser.h>
2022-08-13 16:48:31 +03:00
# include <LibCore/FileWatcher.h>
2020-08-05 18:40:03 +03:00
# include <LibCore/StandardPaths.h>
2021-11-23 12:59:50 +03:00
# include <LibCore/System.h>
2021-01-03 14:10:34 +03:00
# include <LibDesktop/Launcher.h>
2020-02-06 22:33:02 +03:00
# include <LibGUI/Application.h>
# include <LibGUI/BoxLayout.h>
2020-11-02 22:30:17 +03:00
# include <LibGUI/Icon.h>
2020-04-23 22:14:31 +03:00
# include <LibGUI/TabWidget.h>
2021-11-22 21:47:14 +03:00
# include <LibMain/Main.h>
2022-04-30 13:06:30 +03:00
# include <LibWeb/Loader/ResourceLoader.h>
2023-08-31 14:07:07 +03:00
# include <LibWebView/CookieJar.h>
# include <LibWebView/Database.h>
2022-10-13 00:51:37 +03:00
# include <LibWebView/OutOfProcessWebView.h>
2022-04-30 13:06:30 +03:00
# include <LibWebView/RequestServerAdapter.h>
2023-10-19 22:52:06 +03:00
# include <LibWebView/SearchEngine.h>
2023-10-13 17:31:52 +03:00
# include <LibWebView/URL.h>
2021-03-12 19:29:37 +03:00
# include <unistd.h>
2019-10-05 11:19:12 +03:00
2020-05-10 12:18:47 +03:00
namespace Browser {
2023-12-16 17:19:34 +03:00
ByteString g_search_engine ;
ByteString g_home_url ;
ByteString g_new_tab_url ;
2023-04-21 14:54:56 +03:00
Vector < String > g_content_filters ;
2022-02-01 13:17:37 +03:00
bool g_content_filters_enabled { true } ;
2023-04-17 20:37:36 +03:00
Vector < String > g_autoplay_allowlist ;
bool g_autoplay_allowed_on_all_websites { false } ;
2023-12-16 17:19:34 +03:00
Vector < ByteString > g_proxies ;
HashMap < ByteString , size_t > g_proxy_mappings ;
2022-01-11 06:06:11 +03:00
IconBag g_icon_bag ;
2023-12-16 17:19:34 +03:00
ByteString g_webdriver_content_ipc_path ;
2020-08-05 18:40:03 +03:00
2020-05-10 12:18:47 +03:00
}
2020-04-25 18:20:23 +03:00
2022-01-20 14:17:52 +03:00
static ErrorOr < void > load_content_filters ( )
{
2023-04-21 14:54:56 +03:00
auto file = TRY ( Core : : File : : open ( TRY ( String : : formatted ( " {}/BrowserContentFilters.txt " , Core : : StandardPaths : : config_directory ( ) ) ) , Core : : File : : OpenMode : : Read ) ) ;
2023-05-04 01:45:18 +03:00
auto ad_filter_list = TRY ( Core : : InputBufferedFile : : create ( move ( file ) ) ) ;
2022-01-20 20:47:39 +03:00
auto buffer = TRY ( ByteBuffer : : create_uninitialized ( 4096 ) ) ;
2023-04-21 14:36:40 +03:00
Browser : : g_content_filters . clear_with_capacity ( ) ;
2022-01-20 20:47:39 +03:00
while ( TRY ( ad_filter_list - > can_read_line ( ) ) ) {
2022-04-15 16:52:33 +03:00
auto line = TRY ( ad_filter_list - > read_line ( buffer ) ) ;
2023-04-21 14:54:56 +03: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 14:17:52 +03:00
}
return { } ;
}
2023-04-17 20:37:36 +03: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-04 01:45:18 +03:00
auto allowlist = TRY ( Core : : InputBufferedFile : : create ( move ( file ) ) ) ;
2023-04-17 20:37:36 +03: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 21:47:14 +03:00
ErrorOr < int > serenity_main ( Main : : Arguments arguments )
2019-10-05 11:19:12 +03:00
{
2020-03-31 14:01:55 +03:00
if ( getuid ( ) = = 0 ) {
2020-10-25 19:46:16 +03:00
warnln ( " Refusing to run as root " ) ;
2020-03-31 14:01:55 +03:00
return 1 ;
}
2022-10-12 12:50:33 +03:00
TRY ( Core : : System : : pledge ( " stdio recvfd sendfd unix fattr cpath rpath wpath proc exec " ) ) ;
2020-01-11 22:50:27 +03:00
2023-10-13 17:31:52 +03:00
Vector < StringView > specified_urls ;
2020-05-27 22:57:30 +03:00
Core : : ArgsParser args_parser ;
2022-08-13 16:48:31 +03:00
args_parser . add_positional_argument ( specified_urls , " URLs to open " , " url " , Core : : ArgsParser : : Required : : No ) ;
2023-09-03 16:14:56 +03: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 12:50:33 +03:00
2021-11-23 03:03:05 +03:00
args_parser . parse ( arguments ) ;
2020-05-27 22:57:30 +03:00
2023-05-05 07:24:53 +03:00
auto app = TRY ( GUI : : Application : : create ( arguments ) ) ;
2019-10-05 11:19:12 +03:00
2022-02-11 19:33:09 +03:00
Config : : pledge_domain ( " Browser " ) ;
2022-01-31 23:40:48 +03:00
Config : : monitor_domain ( " Browser " ) ;
2021-08-26 01:18:42 +03:00
2021-01-03 14:10:34 +03: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-29 02:30:58 +03:00
TRY ( Desktop : : Launcher : : add_allowed_url ( URL : : create_with_file_scheme ( Core : : StandardPaths : : downloads_directory ( ) ) ) ) ;
2021-11-24 02:23:00 +03:00
TRY ( Desktop : : Launcher : : seal_allowlist ( ) ) ;
2021-01-03 14:10:34 +03:00
2022-09-06 09:04:06 +03: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 19:56:22 +03:00
TRY ( Core : : System : : unveil ( " /tmp/session/%sid/portal/sql " , " rw " ) ) ;
2021-11-23 12:59:50 +03:00
TRY ( Core : : System : : unveil ( " /home " , " rwc " ) ) ;
TRY ( Core : : System : : unveil ( " /res " , " r " ) ) ;
TRY ( Core : : System : : unveil ( " /etc/passwd " , " r " ) ) ;
2022-01-20 20:27:56 +03:00
TRY ( Core : : System : : unveil ( " /etc/timezone " , " r " ) ) ;
2022-01-31 23:55:26 +03:00
TRY ( Core : : System : : unveil ( " /bin/BrowserSettings " , " x " ) ) ;
2022-10-06 11:34:25 +03:00
TRY ( Core : : System : : unveil ( " /bin/Browser " , " x " ) ) ;
2021-11-23 12:59:50 +03:00
TRY ( Core : : System : : unveil ( nullptr , nullptr ) ) ;
2020-03-26 22:06:23 +03:00
2022-04-30 13:06:30 +03:00
Web : : ResourceLoader : : initialize ( TRY ( WebView : : RequestServerAdapter : : try_create ( ) ) ) ;
2022-07-11 20:32:29 +03:00
auto app_icon = GUI : : Icon : : default_icon ( " app-browser " sv ) ;
2020-11-02 22:30:17 +03:00
2023-12-23 23:47:58 +03: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 22:52:06 +03:00
Browser : : g_search_engine = Config : : read_string ( " Browser " sv , " Preferences " sv , " SearchEngine " sv , WebView : : default_search_engine ( ) . query_url ) ;
2023-06-01 15:21:06 +03: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 06:25:11 +03:00
2022-01-11 06:06:11 +03:00
Browser : : g_icon_bag = TRY ( Browser : : IconBag : : try_create ( ) ) ;
2023-08-31 14:07:07 +03:00
auto database = TRY ( WebView : : Database : : create ( ) ) ;
2022-01-20 14:17:52 +03:00
TRY ( load_content_filters ( ) ) ;
2023-04-17 20:37:36 +03:00
TRY ( load_autoplay_allowlist ( ) ) ;
2021-01-05 20:12:29 +03:00
2022-07-11 20:32:29 +03:00
for ( auto & group : Config : : list_groups ( " Browser " sv ) ) {
if ( ! group . starts_with ( " Proxy: " sv ) )
2022-04-08 00:16:47 +03:00
continue ;
2022-07-11 20:32:29 +03:00
for ( auto & key : Config : : list_keys ( " Browser " sv , group ) ) {
2022-04-08 00:16:47 +03: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 17:31:52 +03:00
Vector < URL > initial_urls ;
2022-08-13 16:48:31 +03:00
2023-10-13 17:31:52 +03: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 15:06:17 +03:00
2023-08-31 14:07:07 +03:00
auto cookie_jar = TRY ( WebView : : CookieJar : : create ( * database ) ) ;
2023-10-13 17:31:52 +03:00
auto window = Browser : : BrowserWindow : : construct ( cookie_jar , initial_urls ) ;
2022-10-12 12:50:33 +03:00
2022-01-31 22:43:18 +03: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 13:17:37 +03:00
window - > content_filters_changed ( ) ;
2022-01-31 22:43:18 +03:00
} ;
2023-12-16 17:19:34 +03:00
TRY ( content_filters_watcher - > add_watch ( ByteString : : formatted ( " {}/BrowserContentFilters.txt " , Core : : StandardPaths : : config_directory ( ) ) , Core : : FileWatcherEvent : : Type : : ContentModified ) ) ;
2022-01-31 22:43:18 +03:00
2023-04-17 20:37:36 +03: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 ( ) ;
} ;
2023-12-16 17:19:34 +03:00
TRY ( autoplay_allowlist_watcher - > add_watch ( ByteString : : formatted ( " {}/BrowserAutoplayAllowlist.txt " , Core : : StandardPaths : : config_directory ( ) ) , Core : : FileWatcherEvent : : Type : : ContentModified ) ) ;
2023-04-17 20:37:36 +03:00
2021-04-17 23:08:06 +03:00
app - > on_action_enter = [ & ] ( GUI : : Action & action ) {
2021-05-18 00:15:20 +03: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 23:08:06 +03:00
} ;
app - > on_action_leave = [ & ] ( auto & action ) {
2021-05-18 00:15:20 +03: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 18:20:23 +03:00
} ;
2020-04-24 15:06:17 +03:00
window - > show ( ) ;
2019-10-05 11:19:12 +03:00
2022-11-01 22:43:53 +03:00
window - > broadcast_window_position ( window - > position ( ) ) ;
window - > broadcast_window_size ( window - > size ( ) ) ;
2020-07-04 15:05:19 +03:00
return app - > exec ( ) ;
2019-10-05 11:19:12 +03:00
}