1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 15:47:44 +00:00

LaunchServer+LibDesktop: Add unveil-like mechanism for LaunchServer

Clients of LaunchServer can now provide a list of allowed handlers,
optionally with a specific set of URLs. The list can be sealed to
prevent future additions to it.

If LaunchServer receives a request to open something not on the allowed
handlers list, it will disconnect the client immediately.

The main idea here is to allow otherwise restricted programs to launch
specific things, e.g "Help" to open their manual, or "Browser" to load
the SerenityOS home page. :^)
This commit is contained in:
Andreas Kling 2021-01-03 11:39:33 +01:00
parent 8b2e7628fa
commit 1f1763c37a
5 changed files with 123 additions and 6 deletions

View file

@ -72,10 +72,45 @@ private:
virtual void handle(const Messages::LaunchClient::Dummy&) override { }
};
static LaunchServerConnection& connection()
{
static auto connection = LaunchServerConnection::construct();
return connection;
}
bool Launcher::add_allowed_handler_with_any_url(const String& handler)
{
auto response = connection().send_sync<Messages::LaunchServer::AddAllowedHandlerWithAnyURL>(handler);
if (!response) {
dbgln("Launcher::add_allowed_handler_with_any_url: Failed");
return false;
}
return true;
}
bool Launcher::add_allowed_handler_with_only_specific_urls(const String& handler, const Vector<URL>& urls)
{
auto response = connection().send_sync<Messages::LaunchServer::AddAllowedHandlerWithOnlySpecificURLs>(handler, urls);
if (!response) {
dbgln("Launcher::add_allowed_handler_with_only_specific_urls: Failed");
return false;
}
return true;
}
bool Launcher::seal_allowed_handler_list()
{
auto response = connection().send_sync<Messages::LaunchServer::SealAllowedHandlersList>();
if (!response) {
dbgln("Launcher::seal_allowed_handler_list: Failed");
return false;
}
return true;
}
bool Launcher::open(const URL& url, const String& handler_name)
{
auto connection = LaunchServerConnection::construct();
return connection->send_sync<Messages::LaunchServer::OpenURL>(url, handler_name)->response();
return connection().send_sync<Messages::LaunchServer::OpenURL>(url, handler_name)->response();
}
bool Launcher::open(const URL& url, const Details& details)
@ -86,14 +121,12 @@ bool Launcher::open(const URL& url, const Details& details)
Vector<String> Launcher::get_handlers_for_url(const URL& url)
{
auto connection = LaunchServerConnection::construct();
return connection->send_sync<Messages::LaunchServer::GetHandlersForURL>(url.to_string())->handlers();
return connection().send_sync<Messages::LaunchServer::GetHandlersForURL>(url.to_string())->handlers();
}
auto Launcher::get_handlers_with_details_for_url(const URL& url) -> NonnullRefPtrVector<Details>
{
auto connection = LaunchServerConnection::construct();
auto details = connection->send_sync<Messages::LaunchServer::GetHandlersWithDetailsForURL>(url.to_string())->handlers_details();
auto details = connection().send_sync<Messages::LaunchServer::GetHandlersWithDetailsForURL>(url.to_string())->handlers_details();
NonnullRefPtrVector<Details> handlers_with_details;
for (auto& value : details) {
handlers_with_details.append(Details::from_details_str(value));

View file

@ -51,6 +51,9 @@ public:
static NonnullRefPtr<Details> from_details_str(const String&);
};
[[nodiscard]] static bool add_allowed_handler_with_any_url(const String& handler);
[[nodiscard]] static bool add_allowed_handler_with_only_specific_urls(const String& handler, const Vector<URL>&);
[[nodiscard]] static bool seal_allowed_handler_list();
static bool open(const URL&, const String& handler_name = {});
static bool open(const URL&, const Details& details);
static Vector<String> get_handlers_for_url(const URL&);

View file

@ -55,6 +55,22 @@ OwnPtr<Messages::LaunchServer::GreetResponse> ClientConnection::handle(const Mes
OwnPtr<Messages::LaunchServer::OpenURLResponse> ClientConnection::handle(const Messages::LaunchServer::OpenURL& request)
{
if (!m_allowed_handlers.is_empty()) {
bool allowed = false;
for (auto& allowed_handler : m_allowed_handlers) {
if (allowed_handler.handler_name == request.handler_name()
&& (allowed_handler.any_url || allowed_handler.urls.contains_slow(request.url()))) {
allowed = true;
break;
}
}
if (!allowed) {
// You are not on the list, go home!
did_misbehave(String::formatted("Client requested a combination of handler/URL that was not on the list: '{}' with '{}'", request.handler_name(), request.url()).characters());
return nullptr;
}
}
URL url(request.url());
auto result = Launcher::the().open_url(url, request.handler_name());
return make<Messages::LaunchServer::OpenURLResponse>(result);
@ -74,4 +90,53 @@ OwnPtr<Messages::LaunchServer::GetHandlersWithDetailsForURLResponse> ClientConne
return make<Messages::LaunchServer::GetHandlersWithDetailsForURLResponse>(result);
}
OwnPtr<Messages::LaunchServer::AddAllowedHandlerWithAnyURLResponse> ClientConnection::handle(const Messages::LaunchServer::AddAllowedHandlerWithAnyURL& request)
{
if (m_allowed_handler_list_is_sealed) {
did_misbehave("Got request to add more allowed handlers after list was sealed");
return nullptr;
}
if (request.handler_name().is_empty()) {
did_misbehave("Got request to allow empty handler name");
return nullptr;
}
m_allowed_handlers.empend(request.handler_name(), true, Vector<URL>());
return make<Messages::LaunchServer::AddAllowedHandlerWithAnyURLResponse>();
}
OwnPtr<Messages::LaunchServer::AddAllowedHandlerWithOnlySpecificURLsResponse> ClientConnection::handle(const Messages::LaunchServer::AddAllowedHandlerWithOnlySpecificURLs& request)
{
if (m_allowed_handler_list_is_sealed) {
did_misbehave("Got request to add more allowed handlers after list was sealed");
return nullptr;
}
if (request.handler_name().is_empty()) {
did_misbehave("Got request to allow empty handler name");
return nullptr;
}
if (request.urls().is_empty()) {
did_misbehave("Got request to allow empty URL list");
return nullptr;
}
m_allowed_handlers.empend(request.handler_name(), false, request.urls());
return make<Messages::LaunchServer::AddAllowedHandlerWithOnlySpecificURLsResponse>();
}
OwnPtr<Messages::LaunchServer::SealAllowedHandlersListResponse> ClientConnection::handle(const Messages::LaunchServer::SealAllowedHandlersList&)
{
if (m_allowed_handler_list_is_sealed) {
did_misbehave("Got more than one request to seal the allowed handlers list");
return nullptr;
}
return make<Messages::LaunchServer::SealAllowedHandlersListResponse>();
}
}

View file

@ -47,5 +47,17 @@ private:
virtual OwnPtr<Messages::LaunchServer::OpenURLResponse> handle(const Messages::LaunchServer::OpenURL&) override;
virtual OwnPtr<Messages::LaunchServer::GetHandlersForURLResponse> handle(const Messages::LaunchServer::GetHandlersForURL&) override;
virtual OwnPtr<Messages::LaunchServer::GetHandlersWithDetailsForURLResponse> handle(const Messages::LaunchServer::GetHandlersWithDetailsForURL&) override;
virtual OwnPtr<Messages::LaunchServer::AddAllowedHandlerWithAnyURLResponse> handle(const Messages::LaunchServer::AddAllowedHandlerWithAnyURL&) override;
virtual OwnPtr<Messages::LaunchServer::AddAllowedHandlerWithOnlySpecificURLsResponse> handle(const Messages::LaunchServer::AddAllowedHandlerWithOnlySpecificURLs&) override;
virtual OwnPtr<Messages::LaunchServer::SealAllowedHandlersListResponse> handle(const Messages::LaunchServer::SealAllowedHandlersList&) override;
struct AllowedHandler {
String handler_name;
bool any_url { false };
Vector<URL> urls;
};
Vector<AllowedHandler> m_allowed_handlers;
bool m_allowed_handler_list_is_sealed { false };
};
}

View file

@ -4,4 +4,8 @@ endpoint LaunchServer = 101
OpenURL(URL url, String handler_name) => (bool response)
GetHandlersForURL(URL url) => (Vector<String> handlers)
GetHandlersWithDetailsForURL(URL url) => (Vector<String> handlers_details)
AddAllowedHandlerWithAnyURL(String handler_name) => ()
AddAllowedHandlerWithOnlySpecificURLs(String handler_name, Vector<URL> urls) => ()
SealAllowedHandlersList() => ()
}