Commit e4f5bbcf authored by Kathleen Brade's avatar Kathleen Brade Committed by Matthew Finkel
Browse files

Bug 13252: Do not store data in the app bundle

When --enable-tor-browser-data-outside-app-dir is enabled,
all user data is stored in a directory named
TorBrowser-Data which is located next to the application directory.

Display an informative error message if the TorBrowser-Data
directory cannot be created due to an "access denied" or a
"read only volume" error.

On Mac OS, add support for the --invisible command line option which
is used by the meek-http-helper to avoid showing an icon for the
helper browser on the dock.
parent 5fb7652b
......@@ -2373,6 +2373,8 @@ static nsresult ProfileMissingDialog(nsINativeAppSupport* aNative) {
}
}
// If aUnlocker is NULL, it is also OK for the following arguments to be NULL:
// aProfileDir, aProfileLocalDir, aResult.
static ReturnAbortOnError ProfileErrorDialog(nsIFile* aProfileDir,
nsIFile* aProfileLocalDir,
ProfileStatus aStatus,
......@@ -2381,17 +2383,19 @@ static ReturnAbortOnError ProfileErrorDialog(nsIFile* aProfileDir,
nsIProfileLock** aResult) {
nsresult rv;
bool exists;
aProfileDir->Exists(&exists);
if (!exists) {
return ProfileMissingDialog(aNative);
if (aProfileDir) {
bool exists;
aProfileDir->Exists(&exists);
if (!exists) {
return ProfileMissingDialog(aNative);
}
}
ScopedXPCOMStartup xpcom;
rv = xpcom.Initialize();
NS_ENSURE_SUCCESS(rv, rv);
mozilla::Telemetry::WriteFailedProfileLock(aProfileDir);
if (aProfileDir) mozilla::Telemetry::WriteFailedProfileLock(aProfileDir);
rv = xpcom.SetWindowCreator(aNative);
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
......@@ -2481,7 +2485,8 @@ static ReturnAbortOnError ProfileErrorDialog(nsIFile* aProfileDir,
}
} else {
#ifdef MOZ_WIDGET_ANDROID
if (java::GeckoAppShell::UnlockProfile()) {
if (aProfileDir && aProfileLocalDir && aResult &&
java::GeckoAppShell::UnlockProfile()) {
return NS_LockProfilePath(aProfileDir, aProfileLocalDir, nullptr,
aResult);
}
......@@ -2590,6 +2595,23 @@ static ReturnAbortOnError ShowProfileManager(
return LaunchChild(false);
}
#ifdef TOR_BROWSER_DATA_OUTSIDE_APP_DIR
static ProfileStatus CheckTorBrowserDataWriteAccess(nsIFile* aAppDir) {
// Check whether we can write to the directory that will contain
// TorBrowser-Data.
nsCOMPtr<nsIFile> tbDataDir;
RefPtr<nsXREDirProvider> dirProvider = nsXREDirProvider::GetSingleton();
if (!dirProvider) return PROFILE_STATUS_OTHER_ERROR;
nsresult rv =
dirProvider->GetTorBrowserUserDataDir(getter_AddRefs(tbDataDir));
NS_ENSURE_SUCCESS(rv, PROFILE_STATUS_OTHER_ERROR);
nsCOMPtr<nsIFile> tbDataDirParent;
rv = tbDataDir->GetParent(getter_AddRefs(tbDataDirParent));
NS_ENSURE_SUCCESS(rv, PROFILE_STATUS_OTHER_ERROR);
return nsToolkitProfileService::CheckProfileWriteAccess(tbDataDirParent);
}
#endif
static bool gDoMigration = false;
static bool gDoProfileReset = false;
static nsCOMPtr<nsIToolkitProfile> gResetOldProfile;
......@@ -3614,6 +3636,14 @@ int XREMain::XRE_mainInit(bool* aExitFlag) {
if (PR_GetEnv("XRE_MAIN_BREAK")) NS_BREAK();
#endif
#if defined(XP_MACOSX) && defined(TOR_BROWSER_DATA_OUTSIDE_APP_DIR)
bool hideDockIcon = (CheckArg("invisible") == ARG_FOUND);
if (hideDockIcon) {
ProcessSerialNumber psn = {0, kCurrentProcess};
TransformProcessType(&psn, kProcessTransformToBackgroundApplication);
}
#endif
IncreaseDescriptorLimits();
#ifdef USE_GLX_TEST
......@@ -4466,7 +4496,34 @@ int XREMain::XRE_mainStartup(bool* aExitFlag) {
return 0;
}
#if (defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID)) || \
defined(TOR_BROWSER_DATA_OUTSIDE_APP_DIR)
nsCOMPtr<nsIFile> exeFile, exeDir;
bool persistent;
rv = mDirProvider.GetFile(XRE_EXECUTABLE_FILE, &persistent,
getter_AddRefs(exeFile));
NS_ENSURE_SUCCESS(rv, 1);
rv = exeFile->GetParent(getter_AddRefs(exeDir));
NS_ENSURE_SUCCESS(rv, 1);
#endif
rv = NS_NewToolkitProfileService(getter_AddRefs(mProfileSvc));
#ifdef TOR_BROWSER_DATA_OUTSIDE_APP_DIR
if (NS_FAILED(rv)) {
// NS_NewToolkitProfileService() returns a generic NS_ERROR_FAILURE error
// if creation of the TorBrowser-Data directory fails due to access denied
// or because of a read-only disk volume. Do an extra check here to detect
// these errors so we can display an informative error message.
ProfileStatus status = CheckTorBrowserDataWriteAccess(exeDir);
if ((PROFILE_STATUS_ACCESS_DENIED == status) ||
(PROFILE_STATUS_READ_ONLY == status)) {
ProfileErrorDialog(nullptr, nullptr, status, nullptr, mNativeApp,
nullptr);
return 1;
}
}
#endif
if (rv == NS_ERROR_FILE_ACCESS_DENIED) {
PR_fprintf(PR_STDERR,
"Error: Access was denied while trying to open files in "
......@@ -4535,7 +4592,6 @@ int XREMain::XRE_mainStartup(bool* aExitFlag) {
#if defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID)
// Check for and process any available updates
nsCOMPtr<nsIFile> updRoot;
bool persistent;
rv = mDirProvider.GetFile(XRE_UPDATE_ROOT_DIR, &persistent,
getter_AddRefs(updRoot));
// XRE_UPDATE_ROOT_DIR may fail. Fallback to appDir if failed
......@@ -4571,12 +4627,6 @@ int XREMain::XRE_mainStartup(bool* aExitFlag) {
if (CheckArg("test-process-updates")) {
SaveToEnv("MOZ_TEST_PROCESS_UPDATES=1");
}
nsCOMPtr<nsIFile> exeFile, exeDir;
rv = mDirProvider.GetFile(XRE_EXECUTABLE_FILE, &persistent,
getter_AddRefs(exeFile));
NS_ENSURE_SUCCESS(rv, 1);
rv = exeFile->GetParent(getter_AddRefs(exeDir));
NS_ENSURE_SUCCESS(rv, 1);
ProcessUpdates(mDirProvider.GetGREDir(), exeDir, updRoot, gRestartArgc,
gRestartArgv, mAppData->version);
if (EnvHasValue("MOZ_TEST_PROCESS_UPDATES")) {
......
......@@ -48,6 +48,8 @@
#include "mozilla/XREAppData.h"
#include "nsPrintfCString.h"
#include "TorFileUtils.h"
#include <stdlib.h>
#ifdef XP_WIN
......@@ -1401,34 +1403,18 @@ nsresult nsXREDirProvider::GetUserDataDirectoryHome(nsIFile** aFile,
return gDataDirHome->Clone(aFile);
}
nsresult rv = GetAppDir()->Clone(getter_AddRefs(localDir));
nsresult rv = GetTorBrowserUserDataDir(getter_AddRefs(localDir));
NS_ENSURE_SUCCESS(rv, rv);
int levelsToRemove = 1; // In FF21+, appDir points to browser subdirectory.
#if defined(XP_MACOSX)
levelsToRemove += 2;
#endif
while (localDir && (levelsToRemove > 0)) {
// When crawling up the hierarchy, components named "." do not count.
nsAutoCString removedName;
rv = localDir->GetNativeLeafName(removedName);
NS_ENSURE_SUCCESS(rv, rv);
bool didRemove = !removedName.Equals(".");
// Remove a directory component.
nsCOMPtr<nsIFile> parentDir;
rv = localDir->GetParent(getter_AddRefs(parentDir));
NS_ENSURE_SUCCESS(rv, rv);
localDir = parentDir;
if (didRemove) --levelsToRemove;
}
if (!localDir) return NS_ERROR_FAILURE;
rv = localDir->AppendRelativeNativePath("TorBrowser" XPCOM_FILE_PATH_SEPARATOR
"Data" XPCOM_FILE_PATH_SEPARATOR
#if !defined(ANDROID)
# ifdef TOR_BROWSER_DATA_OUTSIDE_APP_DIR
rv = localDir->AppendNative("Browser"_ns);
# else
rv = localDir->AppendRelativeNativePath("Data" XPCOM_FILE_PATH_SEPARATOR
"Browser"_ns);
# endif
NS_ENSURE_SUCCESS(rv, rv);
#endif
if (aLocal) {
rv = localDir->AppendNative("Caches"_ns);
......@@ -1534,6 +1520,15 @@ nsresult nsXREDirProvider::GetUserDataDirectory(nsIFile** aFile, bool aLocal) {
return NS_OK;
}
nsresult nsXREDirProvider::GetTorBrowserUserDataDir(nsIFile** aFile) {
NS_ENSURE_ARG_POINTER(aFile);
nsCOMPtr<nsIFile> exeFile;
bool per = false;
nsresult rv = GetFile(XRE_EXECUTABLE_FILE, &per, getter_AddRefs(exeFile));
NS_ENSURE_SUCCESS(rv, rv);
return TorBrowser_GetUserDataDir(exeFile, aFile);
}
nsresult nsXREDirProvider::EnsureDirectoryExists(nsIFile* aDirectory) {
nsresult rv = aDirectory->Create(nsIFile::DIRECTORY_TYPE, 0700);
......
......@@ -113,6 +113,12 @@ class nsXREDirProvider final : public nsIDirectoryServiceProvider2,
*/
nsresult GetProfileDir(nsIFile** aResult);
/**
* Get the TorBrowser user data directory by calling the
* TorBrowser_GetUserDataDir() utility function.
*/
nsresult GetTorBrowserUserDataDir(nsIFile** aFile);
protected:
nsresult GetFilesInternal(const char* aProperty,
nsISimpleEnumerator** aResult);
......
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "TorFileUtils.h"
#include "nsString.h"
#ifdef MOZ_WIDGET_COCOA
# include <Carbon/Carbon.h>
# include "nsILocalFileMac.h"
#endif
static nsresult GetAppRootDir(nsIFile* aExeFile, nsIFile** aFile);
//-----------------------------------------------------------------------------
nsresult TorBrowser_GetUserDataDir(nsIFile* aExeFile, nsIFile** aFile) {
NS_ENSURE_ARG_POINTER(aFile);
nsCOMPtr<nsIFile> tbDataDir;
#ifdef TOR_BROWSER_DATA_OUTSIDE_APP_DIR
nsAutoCString tbDataLeafName("TorBrowser-Data"_ns);
nsCOMPtr<nsIFile> appRootDir;
nsresult rv = GetAppRootDir(aExeFile, getter_AddRefs(appRootDir));
NS_ENSURE_SUCCESS(rv, rv);
# ifndef XP_MACOSX
// On all platforms except Mac OS, we always operate in a "portable" mode
// where the TorBrowser-Data directory is located next to the application.
rv = appRootDir->GetParent(getter_AddRefs(tbDataDir));
NS_ENSURE_SUCCESS(rv, rv);
rv = tbDataDir->AppendNative(tbDataLeafName);
NS_ENSURE_SUCCESS(rv, rv);
# else
// For Mac OS, determine whether we should store user data in the OS's
// standard location (i.e., under ~/Library/Application Support). We use
// the OS location if (1) the application is installed in a directory whose
// path contains "/Applications" or (2) the TorBrowser-Data directory does
// not exist and cannot be created (which probably means we lack write
// permission to the directory that contains the application).
nsAutoString appRootPath;
rv = appRootDir->GetPath(appRootPath);
NS_ENSURE_SUCCESS(rv, rv);
bool useOSLocation =
(appRootPath.Find("/Applications", true /* ignore case */) >= 0);
if (!useOSLocation) {
// We hope to use the portable (aka side-by-side) approach, but before we
// commit to that, let's ensure that we can create the TorBrowser-Data
// directory. If it already exists, we will try to use it; if not and we
// fail to create it, we will switch to ~/Library/Application Support.
rv = appRootDir->GetParent(getter_AddRefs(tbDataDir));
NS_ENSURE_SUCCESS(rv, rv);
rv = tbDataDir->AppendNative(tbDataLeafName);
NS_ENSURE_SUCCESS(rv, rv);
bool exists = false;
rv = tbDataDir->Exists(&exists);
if (NS_SUCCEEDED(rv) && !exists)
rv = tbDataDir->Create(nsIFile::DIRECTORY_TYPE, 0700);
useOSLocation = NS_FAILED(rv);
}
if (useOSLocation) {
// We are using ~/Library/Application Support/TorBrowser-Data. We do not
// need to create that directory here because the code in nsXREDirProvider
// will do so (and the user should always have write permission for
// ~/Library/Application Support; if they do not we have no more options).
FSRef fsRef;
OSErr err = ::FSFindFolder(kUserDomain, kApplicationSupportFolderType,
kCreateFolder, &fsRef);
NS_ENSURE_FALSE(err, NS_ERROR_FAILURE);
// To convert the FSRef returned by FSFindFolder() into an nsIFile that
// points to ~/Library/Application Support, we first create an empty
// nsIFile object (no path) and then use InitWithFSRef() to set the
// path.
rv = NS_NewNativeLocalFile(""_ns, true, getter_AddRefs(tbDataDir));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsILocalFileMac> dirFileMac = do_QueryInterface(tbDataDir);
if (!dirFileMac) return NS_ERROR_UNEXPECTED;
rv = dirFileMac->InitWithFSRef(&fsRef);
NS_ENSURE_SUCCESS(rv, rv);
rv = tbDataDir->AppendNative(tbDataLeafName);
NS_ENSURE_SUCCESS(rv, rv);
}
# endif
#elif defined(ANDROID)
// Tor Browser Android stores data in the app home directory.
const char* homeDir = getenv("HOME");
if (!homeDir || !*homeDir) return NS_ERROR_FAILURE;
nsresult rv = NS_NewNativeLocalFile(nsDependentCString(homeDir), true,
getter_AddRefs(tbDataDir));
#else
// User data is embedded within the application directory (i.e.,
// TOR_BROWSER_DATA_OUTSIDE_APP_DIR is not defined).
nsresult rv = GetAppRootDir(aExeFile, getter_AddRefs(tbDataDir));
NS_ENSURE_SUCCESS(rv, rv);
rv = tbDataDir->AppendNative("TorBrowser"_ns);
NS_ENSURE_SUCCESS(rv, rv);
#endif
tbDataDir.forget(aFile);
return NS_OK;
}
static nsresult GetAppRootDir(nsIFile* aExeFile, nsIFile** aFile) {
NS_ENSURE_ARG_POINTER(aExeFile);
NS_ENSURE_ARG_POINTER(aFile);
nsCOMPtr<nsIFile> appRootDir = aExeFile;
int levelsToRemove = 1; // Remove firefox (the executable file).
#if defined(XP_MACOSX)
levelsToRemove += 2; // On Mac OS, we must also remove Contents/MacOS.
#endif
while (appRootDir && (levelsToRemove > 0)) {
// When crawling up the hierarchy, components named "." do not count.
nsAutoCString removedName;
nsresult rv = appRootDir->GetNativeLeafName(removedName);
NS_ENSURE_SUCCESS(rv, rv);
bool didRemove = !removedName.Equals(".");
// Remove a directory component.
nsCOMPtr<nsIFile> parentDir;
rv = appRootDir->GetParent(getter_AddRefs(parentDir));
NS_ENSURE_SUCCESS(rv, rv);
appRootDir = parentDir;
if (didRemove) --levelsToRemove;
}
if (!appRootDir) return NS_ERROR_FAILURE;
appRootDir.forget(aFile);
return NS_OK;
}
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef TorFileUtils_h__
#define TorFileUtils_h__
#include "nsIFile.h"
/**
* TorBrowser_GetUserDataDir
*
* Retrieve the Tor Browser user data directory.
* When built with --enable-tor-browser-data-outside-app-dir, the directory
* is next to the application directory, except on Mac OS where it may be
* there or it may be at ~/Library/Application Support/TorBrowser-Data (the
* latter location is used if the .app bundle is in a directory whose path
* contains /Applications or if we lack write access to the directory that
* contains the .app).
* When built without --enable-tor-browser-data-outside-app-dir, this
* directory is TorBrowser.app/TorBrowser.
*
* @param aExeFile The firefox executable.
* @param aFile Out parameter that is set to the Tor Browser user data
* directory.
* @return NS_OK on success. Error otherwise.
*/
extern nsresult TorBrowser_GetUserDataDir(nsIFile* aExeFile, nsIFile** aFile);
#endif // !TorFileUtils_h__
......@@ -86,6 +86,7 @@ EXPORTS += [
"nsUnicharInputStream.h",
"nsWildCard.h",
"SpecialSystemDirectory.h",
"TorFileUtils.h",
]
EXPORTS.mozilla += [
......@@ -135,6 +136,10 @@ UNIFIED_SOURCES += [
"SpecialSystemDirectory.cpp",
]
SOURCES += [
"TorFileUtils.cpp",
]
if CONFIG["MOZ_WIDGET_TOOLKIT"] == "cocoa":
SOURCES += [
"CocoaFileUtils.mm",
......
......@@ -28,6 +28,8 @@
# include <sys/param.h>
#endif
#include "TorFileUtils.h"
// WARNING: These hard coded names need to go away. They need to
// come from localizable resources
......@@ -234,8 +236,14 @@ nsresult nsAppFileLocationProvider::CloneMozBinDirectory(nsIFile** aLocalFile) {
// GetProductDirectory - Gets the directory which contains the application data
// folder
//
#ifdef TOR_BROWSER_DATA_OUTSIDE_APP_DIR
// UNIX and WIN : <App Folder>/../TorBrowser-Data/Browser
// Mac : <App Folder>/../../../TorBrowser-Data/Browser OR
// ~/Library/Application Support/TorBrowser-Data/Browser
#else
// UNIX and WIN : <App Folder>/TorBrowser/Data/Browser
// Mac : <App Folder>/../../TorBrowser/Data/Browser
#endif
//----------------------------------------------------------------------------------------
nsresult nsAppFileLocationProvider::GetProductDirectory(nsIFile** aLocalFile,
bool aLocal) {
......@@ -243,42 +251,25 @@ nsresult nsAppFileLocationProvider::GetProductDirectory(nsIFile** aLocalFile,
return NS_ERROR_INVALID_ARG;
}
nsresult rv;
nsresult rv = NS_ERROR_UNEXPECTED;
bool exists;
nsCOMPtr<nsIFile> localDir;
nsCOMPtr<nsIFile> localDir, exeFile;
rv = CloneMozBinDirectory(getter_AddRefs(localDir));
nsCOMPtr<nsIProperties> directoryService(
do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv));
NS_ENSURE_SUCCESS(rv, rv);
rv = directoryService->Get(XRE_EXECUTABLE_FILE, NS_GET_IID(nsIFile),
getter_AddRefs(exeFile));
NS_ENSURE_SUCCESS(rv, rv);
rv = TorBrowser_GetUserDataDir(exeFile, getter_AddRefs(localDir));
NS_ENSURE_SUCCESS(rv, rv);
int levelsToRemove = 1; // In FF21+, bin dir points to browser subdirectory.
#if defined(XP_MACOSX)
levelsToRemove += 2;
#endif
while (localDir && (levelsToRemove > 0)) {
// When crawling up the hierarchy, components named "." do not count.
nsAutoCString removedName;
rv = localDir->GetNativeLeafName(removedName);
NS_ENSURE_SUCCESS(rv, rv);
bool didRemove = !removedName.Equals(".");
// Remove a directory component.
nsCOMPtr<nsIFile> parentDir;
rv = localDir->GetParent(getter_AddRefs(parentDir));
NS_ENSURE_SUCCESS(rv, rv);
localDir = parentDir;
if (didRemove) {
--levelsToRemove;
}
}
if (!localDir) {
return NS_ERROR_FAILURE;
}
rv = localDir->AppendRelativeNativePath("TorBrowser" XPCOM_FILE_PATH_SEPARATOR
"Data" XPCOM_FILE_PATH_SEPARATOR
#ifdef TOR_BROWSER_DATA_OUTSIDE_APP_DIR
rv = localDir->AppendNative("Browser"_ns);
#else
rv = localDir->AppendRelativeNativePath("Data" XPCOM_FILE_PATH_SEPARATOR
"Browser"_ns);
#endif
NS_ENSURE_SUCCESS(rv, rv);
if (aLocal) {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment