diff options
author | Be <be@mixxx.org> | 2020-12-05 02:14:11 -0600 |
---|---|---|
committer | Be <be@mixxx.org> | 2020-12-05 19:23:15 -0600 |
commit | b66dd0195157908691a649ec4403403fe8f0319a (patch) | |
tree | e0600ace96f51f73248d0de635e1a0083c7b7006 /src | |
parent | b5e172912d87e3dd5f09c4794fbacaa38e4d5884 (diff) |
migrate old settings path into sandbox on macOS
Diffstat (limited to 'src')
-rw-r--r-- | src/main.cpp | 9 | ||||
-rw-r--r-- | src/mixxx.cpp | 18 | ||||
-rw-r--r-- | src/util/sandbox.cpp | 86 | ||||
-rw-r--r-- | src/util/sandbox.h | 2 |
4 files changed, 106 insertions, 9 deletions
diff --git a/src/main.cpp b/src/main.cpp index 0e3bf3d62e..9828c58462 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -101,17 +101,8 @@ int main(int argc, char * argv[]) { // the main thread. Bug #1748636. ErrorDialogHandler::instance(); - mixxx::Logging::initialize(args.getSettingsPath(), - args.getLogLevel(), - args.getLogFlushLevel(), - args.getDebugAssertBreak()); - MixxxApplication app(argc, argv); - VERIFY_OR_DEBUG_ASSERT(SoundSourceProxy::registerProviders()) { - qCritical() << "Failed to register any SoundSource providers"; - return kFatalErrorOnStartupExitCode; - } #ifdef __APPLE__ QDir dir(QApplication::applicationDirPath()); diff --git a/src/mixxx.cpp b/src/mixxx.cpp index 3f3a4bfa07..6166b95797 100644 --- a/src/mixxx.cpp +++ b/src/mixxx.cpp @@ -168,6 +168,24 @@ MixxxMainWindow::MixxxMainWindow(QApplication* pApp, const CmdlineArgs& args) m_runtime_timer.start(); mixxx::Time::start(); + QString settingsPath = args.getSettingsPath(); +#ifdef __APPLE__ + if (!args.getSettingsPathSet()) { + settingsPath = Sandbox::migrateOldSettings(); + } +#endif + + mixxx::Logging::initialize( + settingsPath, + args.getLogLevel(), + args.getLogFlushLevel(), + args.getDebugAssertBreak()); + + VERIFY_OR_DEBUG_ASSERT(SoundSourceProxy::registerProviders()) { + qCritical() << "Failed to register any SoundSource providers"; + return; + } + Version::logBuildDetails(); // Only record stats in developer mode. diff --git a/src/util/sandbox.cpp b/src/util/sandbox.cpp index e229a927fa..d9424114b0 100644 --- a/src/util/sandbox.cpp +++ b/src/util/sandbox.cpp @@ -359,6 +359,92 @@ SecurityTokenPointer Sandbox::openTokenFromBookmark(const QString& canonicalPath return SecurityTokenPointer(); } +QString Sandbox::migrateOldSettings() { + // QStandardPaths::DataLocation returns a different location depending on whether the build + // is signed (and therefore sandboxed with the hardened runtime), so use the absolute path + // that the sandbox uses regardless of whether this build is actually sandboxed. + // Otherwise, developers would need to run with --settingsPath every time or symlink + // to use the same settings directory with signed and unsigned builds. + + // QDir::homePath returns a path inside the sandbox. + QString homePath = QLatin1String("/Users/") + qgetenv("USER"); + + QString sandboxedPath = homePath + + QLatin1String( + "/Library/Containers/org.mixxx.mixxx/Data/Library/Application Support/Mixxx"); + QDir sandboxedSettings(sandboxedPath); + + if (sandboxedSettings.exists() && !sandboxedSettings.isEmpty()) { + return sandboxedPath; + } + + // Because Mixxx cannot test if the old path exists before getting permission to access it + // outside the sandbox, unfortunately it is necessary to annoy the user with this popup + // even if they are installing Mixxx >= 2.3.0 without having installed an old version of Mixxx. + QString title = QObject::tr("Upgrading old Mixxx settings"); + QString oldPath = homePath + QLatin1String("/Library/Application Support/Mixxx"); + QMessageBox::information(nullptr, + title, + QObject::tr( + "Due to Mac sandboxing, Mixxx needs your permission to " + "access your music library " + "and settings from Mixxx versions before 2.3.0. After " + "clicking OK, you will see a file picker. " + "To give Mixxx permission, press the Ok button in the file " + "picker." + "\n\n" + "If you do not want to grant Mixxx access click Cancel on " + "the file picker.")); + QString result = QFileDialog::getExistingDirectory( + nullptr, + title, + oldPath); + if (result != oldPath) { + qInfo() << "Sandbox::migrateOldSettings: User declined to migrate " + "old settings from" + << oldPath << "User selected" << result; + return sandboxedPath; + } + + // Sandbox::askForAccess cannot be used here because it depends on settings being + // initialized. There is no need to store the bookmark anyway because this is a + // one time process. +#ifdef __APPLE__ + CFURLRef url = CFURLCreateWithFileSystemPath( + kCFAllocatorDefault, QStringToCFString(oldPath), kCFURLPOSIXPathStyle, true); + if (url) { + CFErrorRef error = NULL; + CFDataRef bookmark = CFURLCreateBookmarkData( + kCFAllocatorDefault, + url, + kCFURLBookmarkCreationWithSecurityScope, + nil, + nil, + &error); + CFRelease(url); + if (bookmark) { + QFile oldSettings(oldPath); + if (oldSettings.rename(sandboxedPath)) { + qInfo() << "Sandbox::migrateOldSettings: Successfully " + "migrated old settings from" + << oldPath << "to new path" << sandboxedPath; + } else { + qWarning() << "Sandbox::migrateOldSettings: Failed to migrate " + "old settings from" + << oldPath << "to new path" << sandboxedPath; + } + } else { + qWarning() << "Sandbox::migrateOldSettings: Failed to access old " + "settings path" + << oldPath << "Cannot migrate to new path" + << sandboxedPath; + } + CFRelease(bookmark); + } +#endif + return sandboxedPath; +} + #ifdef __APPLE__ SandboxSecurityToken::SandboxSecurityToken(const QString& path, CFURLRef url) : m_path(path), diff --git a/src/util/sandbox.h b/src/util/sandbox.h index 404a093bed..4076a44c1e 100644 --- a/src/util/sandbox.h +++ b/src/util/sandbox.h @@ -32,6 +32,8 @@ class Sandbox { static void initialize(const QString& permissionsFile); static void shutdown(); + static QString migrateOldSettings(); + // Returns true if we are in a sandbox. static bool enabled() { return s_bInSandbox; |