Bug 1411579 - add system handler when Firefox runs in flatpak; r=stransky

Firefox in Flatpak sandboxed environment does not get the list
of installed applications on the system because application should
know about the environment as little as possible. Introducing
nsFlatpakHandlerApp which forwards requests for opening downloaded files
to the system by utilizing gtk_show_uri fuction.

This changeset also removes nsIGIOMimeApp::Launch method from the interface
because it can be fully replaced with LaunchWithUri from nsIHandlerApp
interface.

The TMPDIR where files are downloaded when user choose to open them
needs to be accessible from sandbox and host. The default settings
TMPDIR=/tmp is accessible only to the sandbox.

To workaround for is to set TMPDIR environment variable to
$XDG_CACHE_HOME/tmp before executing Firefox.

MozReview-Commit-ID: CSBv0QcETpd

--HG--
extra : rebase_source : 8155c33fa9c402d2668bdfb07094ba6758fe6203
This commit is contained in:
Jan Horak 2018-01-12 16:32:53 +01:00
Родитель 927ea89c0d
Коммит e55996cc86
6 изменённых файлов: 149 добавлений и 42 удалений

Просмотреть файл

@ -229,8 +229,10 @@ nsGNOMEShellService::IsDefaultBrowser(bool aStartupCheck,
if (giovfs) {
handler.Truncate();
nsCOMPtr<nsIHandlerApp> handlerApp;
giovfs->GetAppForURIScheme(nsDependentCString(appProtocols[i].name),
getter_AddRefs(gioApp));
getter_AddRefs(handlerApp));
gioApp = do_QueryInterface(handlerApp);
if (!gioApp)
return NS_OK;
@ -571,10 +573,10 @@ nsGNOMEShellService::OpenApplication(int32_t aApplication)
nsCOMPtr<nsIGIOService> giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID);
if (giovfs) {
nsCOMPtr<nsIGIOMimeApp> gioApp;
giovfs->GetAppForURIScheme(scheme, getter_AddRefs(gioApp));
if (gioApp)
return gioApp->Launch(EmptyCString());
nsCOMPtr<nsIHandlerApp> handlerApp;
giovfs->GetAppForURIScheme(scheme, getter_AddRefs(handlerApp));
if (handlerApp)
return handlerApp->LaunchWithURI(nullptr, nullptr);
}
nsCOMPtr<nsIGConfService> gconf = do_GetService(NS_GCONFSERVICE_CONTRACTID);

Просмотреть файл

@ -13,6 +13,7 @@
#include "nsComponentManagerUtils.h"
#include "nsArray.h"
#include "nsIFile.h"
#include "nsPrintfCString.h"
#include <gio/gio.h>
#include <gtk/gtk.h>
@ -21,6 +22,93 @@
#include <dbus/dbus-glib-lowlevel.h>
#endif
// We use the same code as gtk_should_use_portal() to detect if we're in flatpak env
// https://github.com/GNOME/gtk/blob/e0ce028c88858b96aeda9e41734a39a3a04f705d/gtk/gtkprivate.c#L272
static bool GetShouldUseFlatpakPortal() {
bool shouldUsePortal;
char *path;
path = g_build_filename(g_get_user_runtime_dir(), "flatpak-info", nullptr);
if (g_file_test(path, G_FILE_TEST_EXISTS)) {
shouldUsePortal = true;
} else {
shouldUsePortal = (g_getenv("GTK_USE_PORTAL") != nullptr);
}
g_free(path);
return shouldUsePortal;
}
static bool ShouldUseFlatpakPortal() {
static bool sShouldUseFlatpakPortal = GetShouldUseFlatpakPortal();
return sShouldUseFlatpakPortal;
}
class nsFlatpakHandlerApp : public nsIHandlerApp
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIHANDLERAPP
nsFlatpakHandlerApp() = default;
private:
virtual ~nsFlatpakHandlerApp() = default;
};
NS_IMPL_ISUPPORTS(nsFlatpakHandlerApp, nsIHandlerApp)
NS_IMETHODIMP
nsFlatpakHandlerApp::GetName(nsAString& aName)
{
aName.AssignLiteral("System Handler");
return NS_OK;
}
NS_IMETHODIMP
nsFlatpakHandlerApp::SetName(const nsAString& aName)
{
// We don't implement SetName because flatpak system handler name is fixed
return NS_OK;
}
NS_IMETHODIMP
nsFlatpakHandlerApp::GetDetailedDescription(nsAString& aDetailedDescription)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsFlatpakHandlerApp::SetDetailedDescription(const nsAString& aDetailedDescription)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsFlatpakHandlerApp::Equals(nsIHandlerApp* aHandlerApp, bool* _retval)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsFlatpakHandlerApp::LaunchWithURI(nsIURI* aUri, nsIInterfaceRequestor* aRequestor)
{
nsCString spec;
aUri->GetSpec(spec);
GError *error = nullptr;
// The TMPDIR where files are downloaded when user choose to open them
// needs to be accessible from sandbox and host. The default settings
// TMPDIR=/tmp is accessible only to the sandbox. That can be the reason
// why the gtk_show_uri fails there.
// The workaround is to set TMPDIR environment variable in sandbox to
// $XDG_CACHE_HOME/tmp before executing Firefox.
gtk_show_uri(nullptr, spec.get(), GDK_CURRENT_TIME, &error);
if (error) {
NS_WARNING(nsPrintfCString("Cannot launch flatpak handler: %s",
error->message).get());
g_error_free(error);
return NS_ERROR_FAILURE;
}
return NS_OK;
}
/**
* Get command without any additional arguments
@ -100,25 +188,6 @@ nsGIOMimeApp::GetExpectsURIs(int32_t* aExpects)
return NS_OK;
}
NS_IMETHODIMP
nsGIOMimeApp::Launch(const nsACString& aUri)
{
GList uris = { 0 };
nsPromiseFlatCString flatUri(aUri);
uris.data = const_cast<char*>(flatUri.get());
GError *error = nullptr;
gboolean result = g_app_info_launch_uris(mApp, &uris, nullptr, &error);
if (!result) {
g_warning("Cannot launch application: %s", error->message);
g_error_free(error);
return NS_ERROR_FAILURE;
}
return NS_OK;
}
NS_IMETHODIMP
nsGIOMimeApp::GetDetailedDescription(nsAString& aDetailedDescription)
{
@ -179,9 +248,22 @@ nsGIOMimeApp::Equals(nsIHandlerApp* aHandlerApp, bool* _retval)
NS_IMETHODIMP
nsGIOMimeApp::LaunchWithURI(nsIURI* aUri, nsIInterfaceRequestor* aRequestor)
{
nsCString uri_string;
aUri->GetSpec(uri_string);
return Launch(uri_string);
GList uris = { 0 };
nsCString spec;
aUri->GetSpec(spec);
//nsPromiseFlatCString flatUri(aUri);
uris.data = const_cast<char*>(spec.get());
GError *error = nullptr;
gboolean result = g_app_info_launch_uris(mApp, &uris, nullptr, &error);
if (!result) {
g_warning("Cannot launch application: %s", error->message);
g_error_free(error);
return NS_ERROR_FAILURE;
}
return NS_OK;
}
class GIOUTF8StringEnumerator final : public nsIUTF8StringEnumerator
@ -367,10 +449,19 @@ nsGIOService::GetMimeTypeFromExtension(const nsACString& aExtension,
// -----------------------------------------------------------------------------
NS_IMETHODIMP
nsGIOService::GetAppForURIScheme(const nsACString& aURIScheme,
nsIGIOMimeApp** aApp)
nsIHandlerApp** aApp)
{
*aApp = nullptr;
// Application in flatpak sandbox does not have access to the list
// of installed applications on the system. We use generic
// nsFlatpakHandlerApp which forwards launch call to the system.
if (ShouldUseFlatpakPortal()) {
nsFlatpakHandlerApp *mozApp = new nsFlatpakHandlerApp();
NS_ADDREF(*aApp = mozApp);
return NS_OK;
}
GAppInfo *app_info = g_app_info_get_default_for_uri_scheme(
PromiseFlatCString(aURIScheme).get());
if (app_info) {
@ -386,6 +477,13 @@ NS_IMETHODIMP
nsGIOService::GetAppsForURIScheme(const nsACString& aURIScheme,
nsIMutableArray** aResult)
{
// We don't need to return the nsFlatpakHandlerApp here because
// it would be skipped by the callers anyway.
// The preferred handler is provided by GetAppForURIScheme.
// This method returns all possible application handlers
// including preferred one. The callers skips the preferred
// handler in this list to avoid duplicate records in the list
// they create.
nsCOMPtr<nsIMutableArray> handlersArray =
do_CreateInstance(NS_ARRAY_CONTRACTID);
@ -411,9 +509,18 @@ nsGIOService::GetAppsForURIScheme(const nsACString& aURIScheme,
NS_IMETHODIMP
nsGIOService::GetAppForMimeType(const nsACString& aMimeType,
nsIGIOMimeApp** aApp)
nsIHandlerApp** aApp)
{
*aApp = nullptr;
// Flatpak does not reveal installed application to the sandbox,
// we need to create generic system handler.
if (ShouldUseFlatpakPortal()) {
nsFlatpakHandlerApp *mozApp = new nsFlatpakHandlerApp();
NS_ADDREF(*aApp = mozApp);
return NS_OK;
}
char *content_type =
g_content_type_from_mime_type(PromiseFlatCString(aMimeType).get());
if (!content_type)

Просмотреть файл

@ -18,7 +18,7 @@ nsGNOMERegistry::HandlerExists(const char *aProtocolScheme)
return false;
}
nsCOMPtr<nsIGIOMimeApp> app;
nsCOMPtr<nsIHandlerApp> app;
return NS_SUCCEEDED(giovfs->GetAppForURIScheme(nsDependentCString(aProtocolScheme),
getter_AddRefs(app)));
}
@ -44,7 +44,7 @@ nsGNOMERegistry::GetAppDescForScheme(const nsACString& aScheme,
if (!giovfs)
return;
nsCOMPtr<nsIGIOMimeApp> app;
nsCOMPtr<nsIHandlerApp> app;
if (NS_FAILED(giovfs->GetAppForURIScheme(aScheme, getter_AddRefs(app))))
return;
@ -90,12 +90,12 @@ nsGNOMERegistry::GetFromType(const nsACString& aMIMEType)
return nullptr;
}
nsCOMPtr<nsIGIOMimeApp> gioHandlerApp;
if (NS_FAILED(giovfs->GetAppForMimeType(aMIMEType, getter_AddRefs(gioHandlerApp))) ||
!gioHandlerApp) {
nsCOMPtr<nsIHandlerApp> handlerApp;
if (NS_FAILED(giovfs->GetAppForMimeType(aMIMEType, getter_AddRefs(handlerApp))) ||
!handlerApp) {
return nullptr;
}
gioHandlerApp->GetName(name);
handlerApp->GetName(name);
giovfs->GetDescriptionForMimeType(aMIMEType, description);
mimeInfo->SetDefaultDescription(name);

Просмотреть файл

@ -76,14 +76,12 @@ nsMIMEInfoUnix::LaunchDefaultWithFile(nsIFile *aFile)
nsCOMPtr<nsIURI> uri;
rv = ioservice->NewFileURI(aFile, getter_AddRefs(uri));
NS_ENSURE_SUCCESS(rv, rv);
nsAutoCString uriSpec;
uri->GetSpec(uriSpec);
nsCOMPtr<nsIGIOMimeApp> app;
nsCOMPtr<nsIHandlerApp> app;
if (NS_FAILED(giovfs->GetAppForMimeType(mSchemeOrType, getter_AddRefs(app))) || !app) {
return NS_ERROR_FILE_NOT_FOUND;
}
return app->Launch(uriSpec);
return app->LaunchWithURI(uri, nullptr);
}

Просмотреть файл

@ -391,6 +391,7 @@ STUB(gtk_separator_menu_item_new)
STUB(gtk_separator_tool_item_new)
STUB(gtk_settings_get_default)
STUB(gtk_settings_get_for_screen)
STUB(gtk_show_uri)
STUB(gtk_socket_add_id)
STUB(gtk_socket_get_id)
STUB(gtk_socket_get_type)

Просмотреть файл

@ -26,7 +26,6 @@ interface nsIGIOMimeApp : nsIHandlerApp
readonly attribute long expectsURIs; // see constants above
readonly attribute nsIUTF8StringEnumerator supportedURISchemes;
void launch(in AUTF8String uri);
void setAsDefaultForMimeType(in AUTF8String mimeType);
void setAsDefaultForFileExtensions(in AUTF8String extensions);
void setAsDefaultForURIScheme(in AUTF8String uriScheme);
@ -56,13 +55,13 @@ interface nsIGIOService : nsISupports
AUTF8String getMimeTypeFromExtension(in AUTF8String extension);
/* Obtain the preferred application for opening a given URI scheme */
nsIGIOMimeApp getAppForURIScheme(in AUTF8String aURIScheme);
nsIHandlerApp getAppForURIScheme(in AUTF8String aURIScheme);
/* Obtain list of application capable of opening given URI scheme */
nsIMutableArray getAppsForURIScheme(in AUTF8String aURIScheme);
/* Obtain the preferred application for opening a given MIME type */
nsIGIOMimeApp getAppForMimeType(in AUTF8String mimeType);
nsIHandlerApp getAppForMimeType(in AUTF8String mimeType);
/* Create application info for given command and name */
nsIGIOMimeApp createAppFromCommand(in AUTF8String cmd,