From 98576dacae1ea6fb5369f4aef2cf91426766cb57 Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Sat, 28 Oct 2023 00:38:48 +0800 Subject: [PATCH] Add support for quarantine on macOS --- src/base/CMakeLists.txt | 4 +- src/base/bittorrent/torrentimpl.cpp | 8 ++-- src/base/net/downloadhandlerimpl.cpp | 8 ++-- src/base/utils/misc.cpp | 56 ++++++++++++++++++++++------ src/base/utils/misc.h | 5 ++- 5 files changed, 58 insertions(+), 23 deletions(-) diff --git a/src/base/CMakeLists.txt b/src/base/CMakeLists.txt index 4c5f6c6bd..0b517c7fb 100644 --- a/src/base/CMakeLists.txt +++ b/src/base/CMakeLists.txt @@ -205,9 +205,9 @@ target_link_libraries(qbt_base ) if (CMAKE_SYSTEM_NAME STREQUAL "Darwin") - find_library(IOKit_LIBRARY IOKit) - find_library(Carbon_LIBRARY Carbon) find_library(AppKit_LIBRARY AppKit) + find_library(Carbon_LIBRARY Carbon) + find_library(IOKit_LIBRARY IOKit) target_link_libraries(qbt_base PRIVATE ${AppKit_LIBRARY} diff --git a/src/base/bittorrent/torrentimpl.cpp b/src/base/bittorrent/torrentimpl.cpp index cb548a3ad..f9a7192fb 100644 --- a/src/base/bittorrent/torrentimpl.cpp +++ b/src/base/bittorrent/torrentimpl.cpp @@ -68,9 +68,9 @@ #include "peerinfo.h" #include "sessionimpl.h" -#ifdef Q_OS_WIN +#if defined(Q_OS_MACOS) || defined(Q_OS_WIN) #include "base/utils/misc.h" -#endif +#endif // Q_OS_MACOS || Q_OS_WIN using namespace BitTorrent; @@ -2200,14 +2200,14 @@ void TorrentImpl::handleFileCompletedAlert(const lt::file_completed_alert *p) const Path actualPath = actualFilePath(fileIndex); -#ifdef Q_OS_WIN +#if defined(Q_OS_MACOS) || defined(Q_OS_WIN) // only apply Mark-of-the-Web to new download files if (isDownloading()) { const Path fullpath = actualStorageLocation() / actualPath; Utils::Misc::applyMarkOfTheWeb(fullpath); } -#endif +#endif // Q_OS_MACOS || Q_OS_WIN if (m_session->isAppendExtensionEnabled()) { diff --git a/src/base/net/downloadhandlerimpl.cpp b/src/base/net/downloadhandlerimpl.cpp index 9a9fda377..d0a3e7731 100644 --- a/src/base/net/downloadhandlerimpl.cpp +++ b/src/base/net/downloadhandlerimpl.cpp @@ -150,9 +150,9 @@ void Net::DownloadHandlerImpl::processFinishedDownload() { m_result.filePath = result.value(); -#ifdef Q_OS_WIN +#if defined(Q_OS_MACOS) || defined(Q_OS_WIN) Utils::Misc::applyMarkOfTheWeb(m_result.filePath, m_result.url); -#endif +#endif // Q_OS_MACOS || Q_OS_WIN } else { @@ -166,9 +166,9 @@ void Net::DownloadHandlerImpl::processFinishedDownload() { m_result.filePath = destinationPath; -#ifdef Q_OS_WIN +#if defined(Q_OS_MACOS) || defined(Q_OS_WIN) Utils::Misc::applyMarkOfTheWeb(m_result.filePath, m_result.url); -#endif +#endif // Q_OS_MACOS || Q_OS_WIN } else { diff --git a/src/base/utils/misc.cpp b/src/base/utils/misc.cpp index e558ff745..292bd2417 100644 --- a/src/base/utils/misc.cpp +++ b/src/base/utils/misc.cpp @@ -43,6 +43,7 @@ #ifdef Q_OS_MACOS #include +#include #include #endif @@ -52,6 +53,7 @@ #include #include +#include #include #include #include @@ -620,10 +622,50 @@ QString Utils::Misc::zlibVersionString() } #ifdef Q_OS_WIN +Path Utils::Misc::windowsSystemPath() +{ + static const Path path = []() -> Path + { + WCHAR systemPath[MAX_PATH] = {0}; + GetSystemDirectoryW(systemPath, sizeof(systemPath) / sizeof(WCHAR)); + return Path(QString::fromWCharArray(systemPath)); + }(); + return path; +} +#endif // Q_OS_WIN + +#if defined(Q_OS_MACOS) || defined(Q_OS_WIN) bool Utils::Misc::applyMarkOfTheWeb(const Path &file, const QString &url) { Q_ASSERT(url.isEmpty() || url.startsWith(u"http:") || url.startsWith(u"https:")); +#ifdef Q_OS_MACOS + // References: + // https://searchfox.org/mozilla-central/rev/ffdc4971dc18e1141cb2a90c2b0b776365650270/xpcom/io/CocoaFileUtils.mm#230 + // https://github.com/transmission/transmission/blob/f62f7427edb1fd5c430e0ef6956bbaa4f03ae597/macosx/Torrent.mm#L1945-L1955 + + CFMutableDictionaryRef properties = ::CFDictionaryCreateMutable(kCFAllocatorDefault, 0 + , &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + if (properties == NULL) + return false; + + ::CFDictionarySetValue(properties, kLSQuarantineTypeKey, kLSQuarantineTypeOtherDownload); + if (!url.isEmpty()) + ::CFDictionarySetValue(properties, kLSQuarantineDataURLKey, url.toCFString()); + + const CFStringRef fileString = file.toString().toCFString(); + const CFURLRef fileURL = ::CFURLCreateWithFileSystemPath(kCFAllocatorDefault + , fileString, kCFURLPOSIXPathStyle, false); + + const Boolean success = ::CFURLSetResourcePropertyForKey(fileURL, kCFURLQuarantinePropertiesKey + , properties, NULL); + + ::CFRelease(fileURL); + ::CFRelease(fileString); + ::CFRelease(properties); + + return success; +#elif defined(Q_OS_WIN) const QString zoneIDStream = file.toString() + u":Zone.Identifier"; HANDLE handle = ::CreateFileW(zoneIDStream.toStdWString().c_str(), GENERIC_WRITE , (FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE) @@ -642,16 +684,6 @@ bool Utils::Misc::applyMarkOfTheWeb(const Path &file, const QString &url) ::CloseHandle(handle); return writeResult && (written == zoneID.size()); +#endif } - -Path Utils::Misc::windowsSystemPath() -{ - static const Path path = []() -> Path - { - WCHAR systemPath[MAX_PATH] = {0}; - GetSystemDirectoryW(systemPath, sizeof(systemPath) / sizeof(WCHAR)); - return Path(QString::fromWCharArray(systemPath)); - }(); - return path; -} -#endif // Q_OS_WIN +#endif // Q_OS_MACOS || Q_OS_WIN diff --git a/src/base/utils/misc.h b/src/base/utils/misc.h index 17758d67f..863260ec1 100644 --- a/src/base/utils/misc.h +++ b/src/base/utils/misc.h @@ -95,7 +95,6 @@ namespace Utils::Misc QString languageToLocalizedString(const QString &localeStr); #ifdef Q_OS_WIN - bool applyMarkOfTheWeb(const Path &file, const QString &url = {}); Path windowsSystemPath(); template @@ -105,4 +104,8 @@ namespace Utils::Misc return reinterpret_cast(::GetProcAddress(::LoadLibraryW(path.c_str()), funcName)); } #endif // Q_OS_WIN + +#if defined(Q_OS_MACOS) || defined(Q_OS_WIN) + bool applyMarkOfTheWeb(const Path &file, const QString &url = {}); +#endif // Q_OS_MACOS || Q_OS_WIN }