From 1c7b95914e138fbbea423904cbdd0bc0c7b22eb8 Mon Sep 17 00:00:00 2001 From: DavidXanatos <3890945+DavidXanatos@users.noreply.github.com> Date: Sat, 1 Jul 2023 18:54:53 +0200 Subject: [PATCH] 1.10.0 --- Sandboxie/common/my_version.h | 4 +- Sandboxie/common/win32_ntddk.h | 5 + .../MiscHelpers/Archive/ArchiveFS.cpp | 30 +- SandboxiePlus/MiscHelpers/Archive/ArchiveFS.h | 5 +- SandboxiePlus/MiscHelpers/Common/Common.cpp | 2 +- SandboxiePlus/MiscHelpers/Common/Finder.cpp | 4 +- SandboxiePlus/QSbieAPI/Helpers/DbgHelper.cpp | 91 +- SandboxiePlus/QSbieAPI/Helpers/DbgHelper.h | 5 + SandboxiePlus/QSbieAPI/Helpers/NtIO.cpp | 4 +- .../QSbieAPI/Sandboxie/BoxedProcess.cpp | 22 +- .../QSbieAPI/Sandboxie/BoxedProcess.h | 6 +- SandboxiePlus/QSbieAPI/Sandboxie/SandBox.cpp | 15 +- SandboxiePlus/QSbieAPI/Sandboxie/SandBox.h | 2 +- SandboxiePlus/QSbieAPI/Sandboxie/SbieIni.cpp | 2 +- .../QSbieAPI/Sandboxie/SbieTemplates.cpp | 316 +++-- .../QSbieAPI/Sandboxie/SbieTemplates.h | 31 +- SandboxiePlus/QSbieAPI/SbieAPI.cpp | 110 +- SandboxiePlus/QSbieAPI/SbieAPI.h | 17 +- SandboxiePlus/QSbieAPI/SbieStatus.h | 6 + SandboxiePlus/QSbieAPI/SbieUtils.cpp | 54 +- SandboxiePlus/QSbieAPI/SbieUtils.h | 4 +- SandboxiePlus/SandMan/AddonManager.cpp | 444 ++++++ SandboxiePlus/SandMan/AddonManager.h | 64 + SandboxiePlus/SandMan/Engine/BoxEngine.cpp | 386 +++++ SandboxiePlus/SandMan/Engine/BoxEngine.h | 132 ++ SandboxiePlus/SandMan/Engine/BoxObject.cpp | 106 ++ SandboxiePlus/SandMan/Engine/BoxObject.h | 134 ++ SandboxiePlus/SandMan/Engine/IniObject.cpp | 69 + SandboxiePlus/SandMan/Engine/IniObject.h | 147 ++ SandboxiePlus/SandMan/Engine/JSEngineExt.cpp | 120 ++ SandboxiePlus/SandMan/Engine/JSEngineExt.h | 71 + SandboxiePlus/SandMan/Engine/SbieObject.cpp | 212 +++ SandboxiePlus/SandMan/Engine/SbieObject.h | 161 +++ SandboxiePlus/SandMan/Engine/SysObject.cpp | 668 +++++++++ SandboxiePlus/SandMan/Engine/SysObject.h | 57 + .../SandMan/Engine/V4ScriptDebuggerApi.h | 83 ++ SandboxiePlus/SandMan/Engine/WizardObject.h | 58 + SandboxiePlus/SandMan/Forms/NewBoxWindow.ui | 120 -- SandboxiePlus/SandMan/Forms/SettingsWindow.ui | 1145 ++++++++------- SandboxiePlus/SandMan/Helpers/WinAdmin.cpp | 2 +- SandboxiePlus/SandMan/Models/SbieModel.cpp | 23 +- SandboxiePlus/SandMan/OnlineUpdater.cpp | 202 ++- SandboxiePlus/SandMan/OnlineUpdater.h | 12 +- .../SandMan/Resources/Actions/CPU.png | Bin 0 -> 2064 bytes .../SandMan/Resources/Actions/Control3.png | Bin 0 -> 1311 bytes .../SandMan/Resources/Actions/Control4.png | Bin 0 -> 1861 bytes .../SandMan/Resources/Actions/EthCable.png | Bin 0 -> 1206 bytes .../SandMan/Resources/Actions/EthPlug.png | Bin 0 -> 1659 bytes .../SandMan/Resources/Actions/EthSocket.png | Bin 0 -> 1253 bytes .../SandMan/Resources/Actions/EthSocket2.png | Bin 0 -> 1267 bytes .../SandMan/Resources/Actions/FirstAid.png | Bin 0 -> 1439 bytes .../SandMan/Resources/Actions/Forum.png | Bin 0 -> 2385 bytes .../SandMan/Resources/Actions/Help.png | Bin 0 -> 1675 bytes .../SandMan/Resources/Actions/NetCard.png | Bin 0 -> 2157 bytes .../SandMan/Resources/Actions/Network3.png | Bin 0 -> 2473 bytes .../SandMan/Resources/Actions/Network5.png | Bin 0 -> 1779 bytes .../SandMan/Resources/Actions/NetworkMgr.png | Bin 0 -> 2655 bytes .../SandMan/Resources/Actions/Pipe.png | Bin 0 -> 791 bytes .../SandMan/Resources/Actions/Proxy1.png | Bin 0 -> 1941 bytes .../SandMan/Resources/Actions/Proxy2.png | Bin 0 -> 2066 bytes .../SandMan/Resources/Actions/RAM.png | Bin 0 -> 1627 bytes .../SandMan/Resources/Actions/RamDisk.png | Bin 0 -> 722 bytes .../SandMan/Resources/Actions/Security2.png | Bin 0 -> 2333 bytes .../SandMan/Resources/Actions/SourceCode.png | Bin 0 -> 1500 bytes .../SandMan/Resources/Actions/Warning.png | Bin 0 -> 1337 bytes SandboxiePlus/SandMan/Resources/SandMan.qrc | 21 + SandboxiePlus/SandMan/SandMan.cpp | 252 +++- SandboxiePlus/SandMan/SandMan.h | 29 +- SandboxiePlus/SandMan/SandMan.pri | 31 +- SandboxiePlus/SandMan/SandMan.qc.pro | 2 +- SandboxiePlus/SandMan/SandMan.vcxproj | 45 +- SandboxiePlus/SandMan/SandMan.vcxproj.filters | 69 +- SandboxiePlus/SandMan/SandManRecovery.cpp | 26 +- SandboxiePlus/SandMan/SandManTray.cpp | 7 +- SandboxiePlus/SandMan/SbiePlusAPI.cpp | 59 +- SandboxiePlus/SandMan/SbiePlusAPI.h | 14 +- SandboxiePlus/SandMan/Views/FileView.cpp | 5 +- SandboxiePlus/SandMan/Views/SbieView.cpp | 111 +- SandboxiePlus/SandMan/Views/SbieView.h | 4 +- SandboxiePlus/SandMan/Views/TraceView.cpp | 75 +- SandboxiePlus/SandMan/Views/TraceView.h | 4 + .../SandMan/Windows/NewBoxWindow.cpp | 126 -- SandboxiePlus/SandMan/Windows/NewBoxWindow.h | 24 - .../SandMan/Windows/OptionsWindow.cpp | 2 +- .../SandMan/Windows/RecoveryWindow.cpp | 2 +- .../SandMan/Windows/SelectBoxWindow.cpp | 219 +-- .../SandMan/Windows/SelectBoxWindow.h | 38 +- .../SandMan/Windows/SettingsWindow.cpp | 256 ++-- .../SandMan/Windows/SettingsWindow.h | 14 +- .../SandMan/Windows/SnapshotsWindow.cpp | 4 +- .../SandMan/Windows/SupportDialog.cpp | 51 +- .../SandMan/Wizards/BoxAssistant.cpp | 1238 +++++++++++++++++ SandboxiePlus/SandMan/Wizards/BoxAssistant.h | 339 +++++ .../SandMan/Wizards/NewBoxWizard.cpp | 9 +- SandboxiePlus/SandMan/Wizards/SetupWizard.cpp | 274 +++- SandboxiePlus/SandMan/Wizards/SetupWizard.h | 47 +- .../SandMan/Wizards/TemplateWizard.cpp | 2 +- SandboxiePlus/SandMan/main.cpp | 26 +- SandboxiePlus/version.h | 4 +- .../{UpdUtil => }/Common/WebUtils.cpp | 11 +- .../{UpdUtil => }/Common/WebUtils.h | 0 SandboxieTools/{UpdUtil => }/Common/base64.c | 0 SandboxieTools/{UpdUtil => }/Common/dirent.h | 0 .../{UpdUtil => }/Common/helpers.cpp | 50 +- SandboxieTools/{UpdUtil => }/Common/helpers.h | 37 +- .../{UpdUtil => }/Common/json/JSON.cpp | 0 .../{UpdUtil => }/Common/json/JSON.h | 0 .../{UpdUtil => }/Common/json/JSONValue.cpp | 0 .../{UpdUtil => }/Common/json/JSONValue.h | 0 SandboxieTools/{UpdUtil => }/Common/verify.c | 54 +- SandboxieTools/UpdUtil/UpdUtil.cpp | 35 +- SandboxieTools/UpdUtil/UpdUtil.vcxproj | 22 +- .../UpdUtil/UpdUtil.vcxproj.filters | 50 +- 113 files changed, 7176 insertions(+), 1663 deletions(-) create mode 100644 SandboxiePlus/SandMan/AddonManager.cpp create mode 100644 SandboxiePlus/SandMan/AddonManager.h create mode 100644 SandboxiePlus/SandMan/Engine/BoxEngine.cpp create mode 100644 SandboxiePlus/SandMan/Engine/BoxEngine.h create mode 100644 SandboxiePlus/SandMan/Engine/BoxObject.cpp create mode 100644 SandboxiePlus/SandMan/Engine/BoxObject.h create mode 100644 SandboxiePlus/SandMan/Engine/IniObject.cpp create mode 100644 SandboxiePlus/SandMan/Engine/IniObject.h create mode 100644 SandboxiePlus/SandMan/Engine/JSEngineExt.cpp create mode 100644 SandboxiePlus/SandMan/Engine/JSEngineExt.h create mode 100644 SandboxiePlus/SandMan/Engine/SbieObject.cpp create mode 100644 SandboxiePlus/SandMan/Engine/SbieObject.h create mode 100644 SandboxiePlus/SandMan/Engine/SysObject.cpp create mode 100644 SandboxiePlus/SandMan/Engine/SysObject.h create mode 100644 SandboxiePlus/SandMan/Engine/V4ScriptDebuggerApi.h create mode 100644 SandboxiePlus/SandMan/Engine/WizardObject.h delete mode 100644 SandboxiePlus/SandMan/Forms/NewBoxWindow.ui create mode 100644 SandboxiePlus/SandMan/Resources/Actions/CPU.png create mode 100644 SandboxiePlus/SandMan/Resources/Actions/Control3.png create mode 100644 SandboxiePlus/SandMan/Resources/Actions/Control4.png create mode 100644 SandboxiePlus/SandMan/Resources/Actions/EthCable.png create mode 100644 SandboxiePlus/SandMan/Resources/Actions/EthPlug.png create mode 100644 SandboxiePlus/SandMan/Resources/Actions/EthSocket.png create mode 100644 SandboxiePlus/SandMan/Resources/Actions/EthSocket2.png create mode 100644 SandboxiePlus/SandMan/Resources/Actions/FirstAid.png create mode 100644 SandboxiePlus/SandMan/Resources/Actions/Forum.png create mode 100644 SandboxiePlus/SandMan/Resources/Actions/Help.png create mode 100644 SandboxiePlus/SandMan/Resources/Actions/NetCard.png create mode 100644 SandboxiePlus/SandMan/Resources/Actions/Network3.png create mode 100644 SandboxiePlus/SandMan/Resources/Actions/Network5.png create mode 100644 SandboxiePlus/SandMan/Resources/Actions/NetworkMgr.png create mode 100644 SandboxiePlus/SandMan/Resources/Actions/Pipe.png create mode 100644 SandboxiePlus/SandMan/Resources/Actions/Proxy1.png create mode 100644 SandboxiePlus/SandMan/Resources/Actions/Proxy2.png create mode 100644 SandboxiePlus/SandMan/Resources/Actions/RAM.png create mode 100644 SandboxiePlus/SandMan/Resources/Actions/RamDisk.png create mode 100644 SandboxiePlus/SandMan/Resources/Actions/Security2.png create mode 100644 SandboxiePlus/SandMan/Resources/Actions/SourceCode.png create mode 100644 SandboxiePlus/SandMan/Resources/Actions/Warning.png delete mode 100644 SandboxiePlus/SandMan/Windows/NewBoxWindow.cpp delete mode 100644 SandboxiePlus/SandMan/Windows/NewBoxWindow.h create mode 100644 SandboxiePlus/SandMan/Wizards/BoxAssistant.cpp create mode 100644 SandboxiePlus/SandMan/Wizards/BoxAssistant.h rename SandboxieTools/{UpdUtil => }/Common/WebUtils.cpp (95%) rename SandboxieTools/{UpdUtil => }/Common/WebUtils.h (100%) rename SandboxieTools/{UpdUtil => }/Common/base64.c (100%) rename SandboxieTools/{UpdUtil => }/Common/dirent.h (100%) rename SandboxieTools/{UpdUtil => }/Common/helpers.cpp (53%) rename SandboxieTools/{UpdUtil => }/Common/helpers.h (78%) rename SandboxieTools/{UpdUtil => }/Common/json/JSON.cpp (100%) rename SandboxieTools/{UpdUtil => }/Common/json/JSON.h (100%) rename SandboxieTools/{UpdUtil => }/Common/json/JSONValue.cpp (100%) rename SandboxieTools/{UpdUtil => }/Common/json/JSONValue.h (100%) rename SandboxieTools/{UpdUtil => }/Common/verify.c (95%) diff --git a/Sandboxie/common/my_version.h b/Sandboxie/common/my_version.h index 6472158e..6ba07144 100644 --- a/Sandboxie/common/my_version.h +++ b/Sandboxie/common/my_version.h @@ -21,8 +21,8 @@ #ifndef _MY_VERSION_H #define _MY_VERSION_H -#define MY_VERSION_BINARY 5,64,8 -#define MY_VERSION_STRING "5.64.8" +#define MY_VERSION_BINARY 5,65,0 +#define MY_VERSION_STRING "5.65.0" #define MY_ABI_VERSION 0x56000 // These #defines are used by either Resource Compiler or NSIS installer diff --git a/Sandboxie/common/win32_ntddk.h b/Sandboxie/common/win32_ntddk.h index 99a846da..ba9f99ba 100644 --- a/Sandboxie/common/win32_ntddk.h +++ b/Sandboxie/common/win32_ntddk.h @@ -586,6 +586,11 @@ typedef struct _FILE_POSITION_INFORMATION { LARGE_INTEGER CurrentByteOffset; } FILE_POSITION_INFORMATION, *PFILE_POSITION_INFORMATION; +// FileEndOfFileInformation +typedef struct _FILE_END_OF_FILE_INFORMATION { + LARGE_INTEGER EndOfFile; +} FILE_END_OF_FILE_INFORMATION, *PFILE_END_OF_FILE_INFORMATION; + // FileStreamInformation typedef struct _FILE_STREAM_INFORMATION { ULONG NextEntryOffset; diff --git a/SandboxiePlus/MiscHelpers/Archive/ArchiveFS.cpp b/SandboxiePlus/MiscHelpers/Archive/ArchiveFS.cpp index d446ee27..42b54547 100644 --- a/SandboxiePlus/MiscHelpers/Archive/ArchiveFS.cpp +++ b/SandboxiePlus/MiscHelpers/Archive/ArchiveFS.cpp @@ -198,8 +198,10 @@ QDateTime C7zFileEngine::fileTime(FileTime time) const void C7zFileEngine::setFileName(const QString& file) { - int pos = file.indexOf(":") + 2; + int pos = file.indexOf(":") + 1; _filename = file.mid(pos); + while (_filename.left(1) == "\\" || _filename.left(1) == "/") + _filename.remove(0, 1); if (_filename.isEmpty()) { // root _flags = ExistsFlag | DirectoryType | ReadOwnerPerm | ReadUserPerm | ReadGroupPerm | ReadOtherPerm; @@ -268,20 +270,34 @@ bool C7zFileEngine::supportsExtension(Extension extension) const // C7zFileEngineHandler // -C7zFileEngineHandler::C7zFileEngineHandler(const QString& ArchivePath, const QString& Scheme, QObject* parent) +C7zFileEngineHandler::C7zFileEngineHandler(const QString& Scheme, QObject* parent) : QObject(parent), m_pArchive(NULL) { - CArchive* pArchive = new CArchive(ArchivePath); - if (pArchive->Open() > 0) - m_pArchive = pArchive; - else - delete pArchive; m_Scheme = Scheme + ":"; } C7zFileEngineHandler::~C7zFileEngineHandler() +{ + Close(); +} + +bool C7zFileEngineHandler::Open(const QString& ArchivePath) +{ + Close(); + + CArchive* pArchive = new CArchive(ArchivePath); + if (pArchive->Open() <= 0) { + delete pArchive; + return false; + } + m_pArchive = pArchive; + return true; +} + +void C7zFileEngineHandler::Close() { delete m_pArchive; + m_pArchive = NULL; } QAbstractFileEngine* C7zFileEngineHandler::create(const QString& filename) const diff --git a/SandboxiePlus/MiscHelpers/Archive/ArchiveFS.h b/SandboxiePlus/MiscHelpers/Archive/ArchiveFS.h index 72d76ec6..9e7ced82 100644 --- a/SandboxiePlus/MiscHelpers/Archive/ArchiveFS.h +++ b/SandboxiePlus/MiscHelpers/Archive/ArchiveFS.h @@ -73,9 +73,12 @@ private: class MISCHELPERS_EXPORT C7zFileEngineHandler : public QObject, public QAbstractFileEngineHandler { public: - C7zFileEngineHandler(const QString& ArchivePath, const QString& Scheme, QObject* parent = NULL); + C7zFileEngineHandler(const QString& Scheme, QObject* parent = NULL); ~C7zFileEngineHandler(); + bool Open(const QString& ArchivePath); + void Close(); + bool IsOpen() { return m_pArchive != NULL; } QString Prefix() { return m_Scheme; } diff --git a/SandboxiePlus/MiscHelpers/Common/Common.cpp b/SandboxiePlus/MiscHelpers/Common/Common.cpp index 630cac48..1e5ca18f 100644 --- a/SandboxiePlus/MiscHelpers/Common/Common.cpp +++ b/SandboxiePlus/MiscHelpers/Common/Common.cpp @@ -616,7 +616,7 @@ void SafeShow(QWidget* pWidget) { if (Lock == false) { Lock = true; pWidget->show(); - QApplication::processEvents(QEventLoop::ExcludeSocketNotifiers | QEventLoop::ExcludeSocketNotifiers); + QApplication::processEvents(QEventLoop::ExcludeSocketNotifiers); Lock = false; } else pWidget->show(); diff --git a/SandboxiePlus/MiscHelpers/Common/Finder.cpp b/SandboxiePlus/MiscHelpers/Common/Finder.cpp index 3aa27381..72e36e61 100644 --- a/SandboxiePlus/MiscHelpers/Common/Finder.cpp +++ b/SandboxiePlus/MiscHelpers/Common/Finder.cpp @@ -36,8 +36,8 @@ CFinder::CFinder(QObject* pFilterTarget, QWidget *parent, int iOptions) m_pSearchLayout->setAlignment(Qt::AlignLeft); m_pSearch = new QLineEdit(); - m_pSearch->setMinimumWidth(150); - m_pSearch->setMaximumWidth(350); + m_pSearch->setMinimumWidth(200); + //m_pSearch->setMaximumWidth(400); m_pSearchLayout->addWidget(m_pSearch); QObject::connect(m_pSearch, SIGNAL(textChanged(QString)), this, SLOT(OnText())); QObject::connect(m_pSearch, SIGNAL(returnPressed()), this, SLOT(OnReturn())); diff --git a/SandboxiePlus/QSbieAPI/Helpers/DbgHelper.cpp b/SandboxiePlus/QSbieAPI/Helpers/DbgHelper.cpp index 840ecf15..5bb34dcd 100644 --- a/SandboxiePlus/QSbieAPI/Helpers/DbgHelper.cpp +++ b/SandboxiePlus/QSbieAPI/Helpers/DbgHelper.cpp @@ -73,7 +73,7 @@ void CSymbolProvider::run() while (m_bRunning) { - quint64 OldTime = GetTickCount64() - 3000; // cleanup everything older than 3 sec + quint64 OldTime = GetTickCount64() - 3000; // cleanup everythign older than 3 sec if (LastCleanUp < OldTime) { QMutexLocker Lock(&m_SymLock); @@ -108,6 +108,8 @@ void CSymbolProvider::run() } } +extern "C" BOOL CALLBACK SymbolCallbackFunction(HANDLE ProcessHandle, ULONG ActionCode, ULONG64 CallbackData, ULONG64 UserContext); + QString CSymbolProvider::Resolve(quint64 pid, quint64 Address) { QMutexLocker Lock(&m_SymLock); @@ -115,6 +117,8 @@ QString CSymbolProvider::Resolve(quint64 pid, quint64 Address) SWorker& Worker = m_Workers[pid]; if (Worker.handle == 0) { + Worker.pProvider = this; + static ACCESS_MASK accesses[] = { //STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xfff, // pre-Vista full access @@ -128,12 +132,12 @@ QString CSymbolProvider::Resolve(quint64 pid, quint64 Address) break; } - static QAtomicInt FakeHandle = 1; // real handles are divisible by 4 + static QAtomicInt FakeHandle = 1; // real handles are divisable b 4 if (Worker.handle == (quint64)INVALID_HANDLE_VALUE) Worker.handle = FakeHandle.fetchAndAddAcquire(4); __sys_SymInitialize((HANDLE)Worker.handle, NULL, TRUE); - //__sys_SymRegisterCallbackW64((HANDLE)Worker.handle, SymbolCallbackFunction, (ULONG64)&Worker); + __sys_SymRegisterCallbackW64((HANDLE)Worker.handle, SymbolCallbackFunction, (ULONG64)&Worker); __sys_SymSetSearchPathW((HANDLE)Worker.handle, m_SymPath.toStdWString().c_str()); } Worker.last = GetTickCount64(); @@ -174,6 +178,8 @@ QString CSymbolProvider::Resolve(quint64 pid, quint64 Address) void CSymbolProvider::ResolveAsync(quint64 pid, quint64 Address, QObject* receiver, const char* member) { CSymbolProvider* This = CSymbolProvider::Instance(); + if (!This) + return; if (!QAbstractEventDispatcher::instance(QThread::currentThread())) { qWarning("CSymbolProvider::ResolveAsync() called with no event dispatcher"); @@ -188,7 +194,7 @@ void CSymbolProvider::ResolveAsync(quint64 pid, quint64 Address, QObject* receiv This->m_JobQueue.append(pJob); } -/*extern "C" BOOL CALLBACK SymbolCallbackFunction(HANDLE ProcessHandle, ULONG ActionCode, ULONG64 CallbackData, ULONG64 UserContext) +extern "C" BOOL CALLBACK SymbolCallbackFunction(HANDLE ProcessHandle, ULONG ActionCode, ULONG64 CallbackData, ULONG64 UserContext) { CSymbolProvider::SWorker* pWorker = (CSymbolProvider::SWorker*)UserContext; @@ -196,7 +202,7 @@ void CSymbolProvider::ResolveAsync(quint64 pid, quint64 Address, QObject* receiv { case CBA_DEFERRED_SYMBOL_LOAD_START: { - PIMAGEHLP_DEFERRED_SYMBOL_LOADW64 callbackData = (PIMAGEHLP_DEFERRED_SYMBOL_LOADW64)CallbackData; + /*PIMAGEHLP_DEFERRED_SYMBOL_LOADW64 callbackData = (PIMAGEHLP_DEFERRED_SYMBOL_LOADW64)CallbackData; IMAGEHLP_MODULEW64 ModuleInfo; ModuleInfo.SizeOfStruct = sizeof(ModuleInfo); @@ -238,25 +244,26 @@ void CSymbolProvider::ResolveAsync(quint64 pid, quint64 Address, QObject* receiv return TRUE; } - } + }*/ } - return FALSE; + break; case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE: { - PIMAGEHLP_DEFERRED_SYMBOL_LOADW64 callbackData = (PIMAGEHLP_DEFERRED_SYMBOL_LOADW64)CallbackData; + /*PIMAGEHLP_DEFERRED_SYMBOL_LOADW64 callbackData = (PIMAGEHLP_DEFERRED_SYMBOL_LOADW64)CallbackData; if (callbackData->hFile) { NtClose(callbackData->hFile); callbackData->hFile = NULL; } + return TRUE;*/ } - return TRUE; + break; case CBA_READ_MEMORY: { PIMAGEHLP_CBA_READ_MEMORY callbackData = (PIMAGEHLP_CBA_READ_MEMORY)CallbackData; - if ((pWorker->handle & 1) == 0) + /*if ((pWorker->handle & 1) == 0) { if (NT_SUCCESS(NtReadVirtualMemory( ProcessHandle, @@ -268,19 +275,56 @@ void CSymbolProvider::ResolveAsync(quint64 pid, quint64 Address, QObject* receiv { return TRUE; } - } + }*/ } - return FALSE; + break; case CBA_DEFERRED_SYMBOL_LOAD_CANCEL: { - if (pWorker->last == 0) // terminating - return TRUE; + //if (pWorker->last == 0) // terminating + // return TRUE; + } + break; + case CBA_XML_LOG: + { + PWSTR callbackData = (PWSTR)CallbackData; + QString data = QString::fromWCharArray(callbackData); + //qDebug() << data; + + QVariantMap result; + QXmlStreamReader xmlReader(data); + while (!xmlReader.atEnd() && !xmlReader.hasError()) { + QXmlStreamReader::TokenType token = xmlReader.readNext(); + if (token == QXmlStreamReader::StartElement) { + QString elementName = xmlReader.name().toString(); + QVariantMap attributes; + QXmlStreamAttributes xmlAttributes = xmlReader.attributes(); + for (const auto& attribute : xmlAttributes) { + attributes.insert(attribute.name().toString(), attribute.value().toString()); + } + + result.insert(elementName, attributes); + } + } + + QString Message; + if (!result.value("Activity").toMap()["details"].toString().isEmpty()) + Message = result.value("Activity").toMap()["details"].toString(); + //if (!result.value("Log").toMap()["message"].toString().isEmpty()) + // Message = result.value("Log").toMap()["message"].toString(); + if (!result.value("Progress").toMap()["percent"].toString().isEmpty()) + Message = pWorker->LastMessage + QString(" (%1%)").arg(result.value("Progress").toMap()["percent"].toString()); + else if (!Message.isEmpty()) + pWorker->LastMessage = Message; + if(!Message.isEmpty() || result.isEmpty()) + emit pWorker->pProvider->StatusChanged(Message); + + break; } break; } return FALSE; -}*/ +} bool MyBeginInitOnce(QAtomicInt& InitOnce) { @@ -298,11 +342,6 @@ bool MyBeginInitOnce(QAtomicInt& InitOnce) } } -void MyEndInitOnce(QAtomicInt& InitOnce) -{ - InitOnce = 1; -} - CSymbolProvider* CSymbolProvider::Instance() { static QAtomicInt InitOnce = 0; @@ -310,6 +349,7 @@ CSymbolProvider* CSymbolProvider::Instance() if (MyBeginInitOnce(InitOnce)) { HMODULE DbgHelpMod = LoadLibrary(L"dbghelp.dll"); + __sys_SymFromAddr = (P_SymFromAddr)GetProcAddress(DbgHelpMod, "SymFromAddr"); __sys_SymGetModuleInfoW64 = (P_SymGetModuleInfoW64)GetProcAddress(DbgHelpMod, "SymGetModuleInfoW64"); __sys_SymSetOptions = (P_SymSetOptions)GetProcAddress(DbgHelpMod, "SymSetOptions"); @@ -319,6 +359,13 @@ CSymbolProvider* CSymbolProvider::Instance() __sys_SymCleanup = (P_SymCleanup)GetProcAddress(DbgHelpMod, "SymCleanup"); __sys_SymRegisterCallbackW64 = (P_SymRegisterCallbackW64)GetProcAddress(DbgHelpMod, "SymRegisterCallbackW64"); + if (!__sys_SymSetOptions) { + if (DbgHelpMod) + FreeLibrary(DbgHelpMod); + InitOnce = 0; + return NULL; + } + __sys_SymSetOptions( __sys_SymGetOptions() | SYMOPT_UNDNAME | SYMOPT_AUTO_PUBLICS | SYMOPT_CASE_INSENSITIVE | SYMOPT_DEFERRED_LOADS | @@ -328,8 +375,8 @@ CSymbolProvider* CSymbolProvider::Instance() g_SymbolProvider = new CSymbolProvider(); - MyEndInitOnce(InitOnce); + InitOnce = 1; } return g_SymbolProvider; -} +} \ No newline at end of file diff --git a/SandboxiePlus/QSbieAPI/Helpers/DbgHelper.h b/SandboxiePlus/QSbieAPI/Helpers/DbgHelper.h index b7b1beb6..17cfeb85 100644 --- a/SandboxiePlus/QSbieAPI/Helpers/DbgHelper.h +++ b/SandboxiePlus/QSbieAPI/Helpers/DbgHelper.h @@ -24,8 +24,13 @@ public: SWorker() : last(-1), handle(0) {} quint64 last; quint64 handle; + CSymbolProvider* pProvider; + QString LastMessage; }; +signals: + void StatusChanged(const QString& Message); + protected: //void timerEvent(QTimerEvent* pEvent); //int m_uTimerID; diff --git a/SandboxiePlus/QSbieAPI/Helpers/NtIO.cpp b/SandboxiePlus/QSbieAPI/Helpers/NtIO.cpp index 06002097..af59052c 100644 --- a/SandboxiePlus/QSbieAPI/Helpers/NtIO.cpp +++ b/SandboxiePlus/QSbieAPI/Helpers/NtIO.cpp @@ -170,8 +170,10 @@ NTSTATUS NtIo_DeleteFolderRecursively(POBJECT_ATTRIBUTES objattrs, bool (*cb)(co NTSTATUS status = NtIo_DeleteFolderRecursivelyImpl(objattrs, cb, param); - if (NT_SUCCESS(status)) + if (NT_SUCCESS(status)) { + NtIo_RemoveJunction(objattrs); status = NtDeleteFile(objattrs); + } return status; } diff --git a/SandboxiePlus/QSbieAPI/Sandboxie/BoxedProcess.cpp b/SandboxiePlus/QSbieAPI/Sandboxie/BoxedProcess.cpp index 2336e1aa..62d77031 100644 --- a/SandboxiePlus/QSbieAPI/Sandboxie/BoxedProcess.cpp +++ b/SandboxiePlus/QSbieAPI/Sandboxie/BoxedProcess.cpp @@ -31,15 +31,17 @@ typedef long NTSTATUS; #include -//struct SBoxedProcess -//{ -//}; +struct SBoxedProcess +{ + HANDLE Handle; +}; CBoxedProcess::CBoxedProcess(quint32 ProcessId, class CSandBox* pBox) { m_pBox = pBox; - //m = new SBoxedProcess; + m = new SBoxedProcess; + m->Handle = NULL; m_ProcessId = ProcessId; @@ -48,6 +50,7 @@ CBoxedProcess::CBoxedProcess(quint32 ProcessId, class CSandBox* pBox) m_ProcessFlags = 0; m_ImageType = -1; + m_ReturnCode = STATUS_PENDING; m_uTerminated = 0; //m_bSuspended = IsSuspended(); @@ -57,7 +60,9 @@ CBoxedProcess::CBoxedProcess(quint32 ProcessId, class CSandBox* pBox) CBoxedProcess::~CBoxedProcess() { - //delete m; + if (m->Handle) + NtClose(m->Handle); + delete m; } @@ -225,10 +230,10 @@ bool CBoxedProcess::InitProcessInfo() ProcessHandle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, (DWORD)m_ProcessId); if (ProcessHandle == NULL) return false; + m->Handle = ProcessHandle; InitProcessInfoImpl(ProcessHandle); - NtClose(ProcessHandle); return true; } @@ -300,6 +305,11 @@ SB_STATUS CBoxedProcess::Terminate() void CBoxedProcess::SetTerminated() { m_uTerminated = ::GetTickCount64(); + + DWORD ExitCode = 0; + if (m->Handle) + GetExitCodeProcess(m->Handle, &ExitCode); + m_ReturnCode = ExitCode; } bool CBoxedProcess::IsTerminated(quint64 forMs) const diff --git a/SandboxiePlus/QSbieAPI/Sandboxie/BoxedProcess.h b/SandboxiePlus/QSbieAPI/Sandboxie/BoxedProcess.h index 8ce5a645..6f812848 100644 --- a/SandboxiePlus/QSbieAPI/Sandboxie/BoxedProcess.h +++ b/SandboxiePlus/QSbieAPI/Sandboxie/BoxedProcess.h @@ -40,6 +40,7 @@ public: virtual QDateTime GetTimeStamp() const { return m_StartTime; } virtual quint32 GetProcessFlags() const { return m_ProcessFlags; } virtual quint32 GetImageType() const { return m_ImageType; } + virtual quint32 GetReturnCode() const { return m_ReturnCode; } virtual SB_STATUS Terminate(); virtual bool IsTerminated(quint64 forMs = 0) const; @@ -74,6 +75,7 @@ protected: QString m_CommandLine; quint32 m_SessionId; QDateTime m_StartTime; + quint32 m_ReturnCode; quint64 m_uTerminated; //bool m_bSuspended; bool m_bIsWoW64; @@ -86,8 +88,8 @@ protected: QHash m_Symbols; -//private: -// struct SBoxedProcess* m; +private: + struct SBoxedProcess* m; }; typedef QSharedPointer CBoxedProcessPtr; diff --git a/SandboxiePlus/QSbieAPI/Sandboxie/SandBox.cpp b/SandboxiePlus/QSbieAPI/Sandboxie/SandBox.cpp index cab33b71..58d52990 100644 --- a/SandboxiePlus/QSbieAPI/Sandboxie/SandBox.cpp +++ b/SandboxiePlus/QSbieAPI/Sandboxie/SandBox.cpp @@ -134,13 +134,13 @@ void CSandBox::SetBoxPaths(const QString& FilePath, const QString& RegPath, cons m_IpcPath = IpcPath; } -SB_STATUS CSandBox::RunStart(const QString& Command, bool Elevated, const QString& WorkingDir) +SB_STATUS CSandBox::RunStart(const QString& Command, bool Elevated) { #ifdef _DEBUG if ((QGuiApplication::queryKeyboardModifiers() & Qt::ControlModifier) != 0) return RunSandboxed(Command); #endif - return m_pAPI->RunStart(m_Name, Command, Elevated, WorkingDir); + return m_pAPI->RunStart(m_Name, Command, Elevated); } SB_STATUS CSandBox::RunSandboxed(const QString& Command) @@ -230,6 +230,9 @@ SB_STATUS CSandBox__MoveFolder(const QString& SourcePath, const QString& ParentF SB_STATUS CSandBox::RenameBox(const QString& NewName) { + if (GetActiveProcessCount() > 0) + return SB_ERR(SB_RemNotStopped); + if (NewName.compare(m_Name, Qt::CaseInsensitive) == 0) return SB_OK; @@ -244,9 +247,11 @@ SB_STATUS CSandBox::RenameBox(const QString& NewName) QString Name = FilePath.takeLast(); if (Name.compare(m_Name, Qt::CaseInsensitive) == 0) { - Status = CSandBox__MoveFolder(m_FilePath, FilePath.join("\\"), NewName); - if (Status.IsError()) - return Status; + //Status = CSandBox__MoveFolder(m_FilePath, FilePath.join("\\"), NewName); + //if (Status.IsError()) + // return Status; + if(!QDir().rename(m_FilePath, FilePath.join("\\") + "\\" + NewName)) + return SB_ERR(SB_FailedMoveDir, QVariantList() << m_FilePath << (FilePath.join("\\") + "\\" + NewName), 0xC0000001 /*STATUS_UNSUCCESSFUL*/); QString FileRootPath = GetText("FileRootPath"); if (!FileRootPath.isEmpty()) diff --git a/SandboxiePlus/QSbieAPI/Sandboxie/SandBox.h b/SandboxiePlus/QSbieAPI/Sandboxie/SandBox.h index 0299ef8e..ad0bac26 100644 --- a/SandboxiePlus/QSbieAPI/Sandboxie/SandBox.h +++ b/SandboxiePlus/QSbieAPI/Sandboxie/SandBox.h @@ -51,7 +51,7 @@ public: virtual int GetActiveProcessCount() const { return m_ActiveProcessCount; } - virtual SB_STATUS RunStart(const QString& Command, bool Elevated = false, const QString& WorkingDir = QString()); + virtual SB_STATUS RunStart(const QString& Command, bool Elevated = false); virtual SB_STATUS RunSandboxed(const QString& Command); virtual SB_STATUS TerminateAll(); diff --git a/SandboxiePlus/QSbieAPI/Sandboxie/SbieIni.cpp b/SandboxiePlus/QSbieAPI/Sandboxie/SbieIni.cpp index a31acd03..eb5c4a7a 100644 --- a/SandboxiePlus/QSbieAPI/Sandboxie/SbieIni.cpp +++ b/SandboxiePlus/QSbieAPI/Sandboxie/SbieIni.cpp @@ -104,7 +104,7 @@ __int64 CSbieIni::GetNum64(const QString& Setting, __int64 Default, bool bWithGl { QString StrValue = GetText(Setting, QString(), bWithGlobal, true, withTemplates); bool ok; - __int64 Value = StrValue.toULongLong(&ok); + __int64 Value = StrValue.toLongLong(&ok); if (!ok) return Default; return Value; } diff --git a/SandboxiePlus/QSbieAPI/Sandboxie/SbieTemplates.cpp b/SandboxiePlus/QSbieAPI/Sandboxie/SbieTemplates.cpp index 93d8cc77..2bc46b4d 100644 --- a/SandboxiePlus/QSbieAPI/Sandboxie/SbieTemplates.cpp +++ b/SandboxiePlus/QSbieAPI/Sandboxie/SbieTemplates.cpp @@ -18,6 +18,7 @@ #include "stdafx.h" #include "SbieTemplates.h" #include "../SbieAPI.h" +#include "../SbieUtils.h" #include #define WIN32_NO_STATUS @@ -38,23 +39,116 @@ CSbieTemplates::CSbieTemplates(CSbieAPI* pAPI, QObject* paretn) InitExpandPaths(true); } -bool CSbieTemplates::RunCheck() +void CSbieTemplates::RunCheck() { CollectObjects(); CollectClasses(); CollectServices(); CollectProducts(); + CollectTemplates(); + QStringList Used = m_pAPI->GetGlobalSettings()->GetTextList("Template", false); + QStringList Rejected = m_pAPI->GetGlobalSettings()->GetTextList("TemplateReject", false); + + for(QMap::iterator I = m_Templates.begin(); I != m_Templates.end(); ++I) + { + int Value = eNone; + if (Used.contains(I.key(), Qt::CaseInsensitive)) + Value |= eEnabled; + if (CheckTemplate(I.key())) + Value |= eRequired; + if (Rejected.contains(I.key() , Qt::CaseInsensitive)) + Value |= eDisabled; + I.value() = Value; + } +} + +void CSbieTemplates::CollectTemplates() +{ + m_Templates.clear(); + + QStringList Templates; + Templates.append(GetTemplateNames("EmailReader")); + Templates.append(GetTemplateNames("Print")); + Templates.append(GetTemplateNames("Security")); + Templates.append(GetTemplateNames("Desktop")); + Templates.append(GetTemplateNames("Download")); + Templates.append(GetTemplateNames("Misc")); + Templates.append(GetTemplateNames("WebBrowser")); + Templates.append(GetTemplateNames("MediaPlayer")); + Templates.append(GetTemplateNames("TorrentClient")); + + foreach(const QString& Template, Templates) + m_Templates.insert(Template, 0); +} + +void CSbieTemplates::SetCheckResult(const QStringList& Result) +{ + CollectTemplates(); + + QStringList Used = m_pAPI->GetGlobalSettings()->GetTextList("Template", false); + QStringList Rejected = m_pAPI->GetGlobalSettings()->GetTextList("TemplateReject", false); + + for(QMap::iterator I = m_Templates.begin(); I != m_Templates.end(); ++I) + { + int Value = eNone; + if (Used.contains(I.key(), Qt::CaseInsensitive)) + Value |= eEnabled; + if (Result.contains(I.key())) + Value |= eRequired; + if (Rejected.contains(I.key() , Qt::CaseInsensitive)) + Value |= eDisabled; + I.value() = Value; + } +} + +bool CSbieTemplates::GetCheckState() +{ for (QMap::iterator I = m_Templates.begin(); I != m_Templates.end(); ++I) { if ((I.value() & eRequired) != 0 && (I.value() & eConfigured) == 0) return true; } - return false; } +void CSbieTemplates::Reset() +{ + m_Objects.clear(); + m_Classes.clear(); + m_Services.clear(); + m_Products.clear(); +} + +QStringList CSbieTemplates::GetObjects() +{ + if (m_Objects.isEmpty()) + CollectObjects(); + return m_Objects; +} + +QStringList CSbieTemplates::GetClasses() +{ + if (m_Classes.isEmpty()) + CollectClasses(); + return m_Classes; +} + +QStringList CSbieTemplates::GetServices() +{ + if (m_Services.isEmpty()) + CollectServices(); + return m_Services; +} + +QStringList CSbieTemplates::GetProducts() +{ + if (m_Products.isEmpty()) + CollectProducts(); + return m_Products; +} + void CSbieTemplates::CollectObjects() { m_Objects.clear(); @@ -127,7 +221,7 @@ void CSbieTemplates::CollectObjects() if (i == 0) objdirs.append(objpath); else - m_Objects.push_back(objpath.toLower().toStdWString()); + m_Objects.append(objpath.toLower()); } } @@ -147,7 +241,7 @@ void CSbieTemplates::CollectClasses() if (clsnm[0] && wcsncmp(clsnm, L"Sandbox:", 8) != 0) { _wcslwr(clsnm); - ((CSbieTemplates*)lparam)->m_Classes.push_back(clsnm); + ((CSbieTemplates*)lparam)->m_Classes.append(QString::fromWCharArray(clsnm)); } return TRUE; @@ -177,7 +271,7 @@ void CSbieTemplates::CollectServices() for (ULONG i = 0; i < num; ++i) { _wcslwr(info[i].lpServiceName); - m_Services.push_back(info[i].lpServiceName); + m_Services.append(QString::fromWCharArray(info[i].lpServiceName)); } if (ret) @@ -215,7 +309,7 @@ void CSbieTemplates::CollectProducts() rc = RegEnumKeyEx(hkey, index, name, &name_len, NULL, NULL, NULL, NULL); if (rc == 0) { _wcslwr(name); - m_Products.push_back(name); + m_Products.append(QString::fromWCharArray(name)); } } @@ -261,79 +355,6 @@ QStringList CSbieTemplates::GetTemplateNames(const QString& forClass) return list; } -void CSbieTemplates::CollectTemplates() -{ - m_Templates.clear(); - - QStringList Templates; - Templates.append(GetTemplateNames("EmailReader")); - Templates.append(GetTemplateNames("Print")); - Templates.append(GetTemplateNames("Security")); - Templates.append(GetTemplateNames("Desktop")); - Templates.append(GetTemplateNames("Download")); - Templates.append(GetTemplateNames("Misc")); - Templates.append(GetTemplateNames("WebBrowser")); - Templates.append(GetTemplateNames("MediaPlayer")); - Templates.append(GetTemplateNames("TorrentClient")); - - foreach(const QString& Template, Templates) - m_Templates.insert(Template, 0); - - QStringList Used = m_pAPI->GetGlobalSettings()->GetTextList("Template", false); - QStringList Rejected = m_pAPI->GetGlobalSettings()->GetTextList("TemplateReject", false); - - for(QMap::iterator I = m_Templates.begin(); I != m_Templates.end(); ++I) - { - int Value = eNone; - if (Used.contains(I.key(), Qt::CaseInsensitive)) - Value |= eEnabled; - if (CheckTemplate(I.key())) - Value |= eRequired; - if (Rejected.contains(I.key() , Qt::CaseInsensitive)) - Value |= eDisabled; - I.value() = Value; - } -} - -template -const T* wildcmpex(const T* Wild, const T* Str) -{ - const T *cp = NULL, *mp = NULL; - - while ((*Str) && (*Wild != '*')) - { - if ((*Wild != *Str) && (*Wild != '?')) - return NULL; - Wild++; - Str++; - } - - while (*Str) - { - if (*Wild == '*') - { - if (!*++Wild) - return Str; - mp = Wild; - cp = Str + 1; - } - else if ((*Wild == *Str) || (*Wild == '?')) - { - Wild++; - Str++; - } - else - { - Wild = mp; - Str = cp++; - } - } - - while (*Wild == '*') - Wild++; - return *Wild ? NULL : Str; -} - bool CSbieTemplates::CheckTemplate(const QString& Name) { QSharedPointer pTemplate = QSharedPointer(new CSbieIni("Template_" + Name, m_pAPI)); @@ -345,71 +366,54 @@ bool CSbieTemplates::CheckTemplate(const QString& Name) if (!(scanIpc || scanWin || scanSvc)) return false; - std::list Keys, Files; QList> settings = pTemplate->GetIniSection(0, true); for(QList>::iterator I = settings.begin(); I != settings.end(); ++I) { QString setting = I->first; - - std::list *List = NULL; - if (scanIpc && setting.compare("OpenIpcPath", Qt::CaseInsensitive) == 0) - List = &m_Objects; - else if (scanSvc && setting.compare("Tmpl.ScanIpc", Qt::CaseInsensitive) == 0) - List = &m_Objects; - else if (scanWin && setting.compare("OpenWinClass", Qt::CaseInsensitive) == 0) - List = &m_Classes; - else if (scanSvc && setting.compare("Tmpl.ScanWinClass", Qt::CaseInsensitive) == 0) - List = &m_Classes; - else if (scanSvc && setting.compare("Tmpl.ScanService", Qt::CaseInsensitive) == 0) - List = &m_Services; - else if (scanSvc && setting.compare("Tmpl.ScanProduct", Qt::CaseInsensitive) == 0) - List = &m_Products; - else if (scanSvc && setting.compare("Tmpl.ScanKey", Qt::CaseInsensitive) == 0) - List = &Keys; - else if (scanSvc && setting.compare("Tmpl.ScanFile", Qt::CaseInsensitive) == 0) - List = &Files; - else - continue; - QString value = I->second; - if(!value.isEmpty()) + + if (scanIpc && ((setting.compare("OpenIpcPath", Qt::CaseInsensitive) == 0) || setting.compare("Tmpl.ScanIpc", Qt::CaseInsensitive) == 0)) { - if (List == &Keys) { - if (CheckRegistryKey(value)) - return true; + if (value.compare("\\RPC Control\\epmapper") == 0) continue; - } - else if (List == &Files) { - if (CheckFile(value)) - return true; + if (value.compare("\\RPC Control\\OLE*") == 0) + continue; + if (value.compare("\\RPC Control\\LRPC*") == 0) + continue; + if (value.compare("*\\BaseNamedObjects*\\NamedBuffer*mAH*Process*API*") == 0) continue; - } + if (CheckObjects(value)) + return true; + } + else if (scanWin && ((setting.compare("OpenWinClass", Qt::CaseInsensitive) == 0 || setting.compare("Tmpl.ScanWinClass", Qt::CaseInsensitive) == 0))) + { // skip to unspecific entries - if (List == &m_Classes) - { - if(value.left(2).compare("*:") == 0) - continue; - } - if (List == &m_Objects) - { - if (value.compare("\\RPC Control\\epmapper") == 0) - continue; - if (value.compare("\\RPC Control\\OLE*") == 0) - continue; - if (value.compare("\\RPC Control\\LRPC*") == 0) - continue; - if (value.compare("*\\BaseNamedObjects*\\NamedBuffer*mAH*Process*API*") == 0) - continue; - } - // + if(value.left(2).compare("*:") == 0) + continue; - std::wstring wild = value.toLower().toStdWString(); - for (std::list::iterator I = List->begin(); I != List->end(); ++I) - { - if (wildcmpex(wild.c_str(), I->c_str()) != NULL) - return true; - } + if (CheckClasses(value)) + return true; + } + else if (scanSvc && setting.compare("Tmpl.ScanService", Qt::CaseInsensitive) == 0) + { + if (CheckServices(value)) + return true; + } + else if (scanSvc && setting.compare("Tmpl.ScanProduct", Qt::CaseInsensitive) == 0) + { + if (CheckProducts(value)) + return true; + } + else if (scanSvc && setting.compare("Tmpl.ScanKey", Qt::CaseInsensitive) == 0) + { + if (CheckRegistryKey(value)) + return true; + } + else if (scanSvc && setting.compare("Tmpl.ScanFile", Qt::CaseInsensitive) == 0) + { + if (CheckFile(ExpandPath(value))) + return true; } } @@ -437,12 +441,56 @@ bool CSbieTemplates::CheckRegistryKey(const QString& Value) bool CSbieTemplates::CheckFile(const QString& Value) { - std::wstring path = ExpandPath(Value).toStdWString(); + std::wstring path = Value.toStdWString(); if (GetFileAttributes(path.c_str()) != INVALID_FILE_ATTRIBUTES) return true; return false; } +bool CSbieTemplates::CheckClasses(const QString& value) +{ + QString Value = value.toLower(); + for (auto I = m_Classes.begin(); I != m_Classes.end(); ++I) + { + if (CSbieUtils::WildCompare(Value, *I)) + return true; + } + return false; +} + +bool CSbieTemplates::CheckServices(const QString& value) +{ + QString Value = value.toLower(); + for (auto I = m_Services.begin(); I != m_Services.end(); ++I) + { + if (CSbieUtils::WildCompare(Value, *I)) + return true; + } + return false; +} + +bool CSbieTemplates::CheckProducts(const QString& value) +{ + QString Value = value.toLower(); + for (auto I = m_Products.begin(); I != m_Products.end(); ++I) + { + if (CSbieUtils::WildCompare(Value, *I)) + return true; + } + return false; +} + +bool CSbieTemplates::CheckObjects(const QString& value) +{ + QString Value = value.toLower(); + for (auto I = m_Objects.begin(); I != m_Objects.end(); ++I) + { + if (CSbieUtils::WildCompare(Value, *I)) + return true; + } + return false; +} + void CSbieTemplates::InitExpandPaths(bool WithUser) { std::wstring keyPath(L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\"); diff --git a/SandboxiePlus/QSbieAPI/Sandboxie/SbieTemplates.h b/SandboxiePlus/QSbieAPI/Sandboxie/SbieTemplates.h index 6c703c6b..e6a00025 100644 --- a/SandboxiePlus/QSbieAPI/Sandboxie/SbieTemplates.h +++ b/SandboxiePlus/QSbieAPI/Sandboxie/SbieTemplates.h @@ -11,7 +11,9 @@ class QSBIEAPI_EXPORT CSbieTemplates : public QObject public: CSbieTemplates(class CSbieAPI* pAPI, QObject* paretn = 0); - bool RunCheck(); + void RunCheck(); + void SetCheckResult(const QStringList& Result); + bool GetCheckState(); enum EStates { @@ -22,8 +24,24 @@ public: eConfigured = eEnabled | eDisabled }; + void Reset(); + + QStringList GetObjects(); + QStringList GetClasses(); + QStringList GetServices(); + QStringList GetProducts(); QMap GetTemplates() { return m_Templates; } + + QString ExpandPath(QString path); + + bool CheckRegistryKey(const QString& Value); + bool CheckFile(const QString& Value); + bool CheckClasses(const QString& Value); + bool CheckServices(const QString& Value); + bool CheckProducts(const QString& Value); + bool CheckObjects(const QString& Value); + protected: void CollectObjects(); void CollectClasses(); @@ -34,16 +52,13 @@ protected: QStringList GetTemplateNames(const QString& forClass); bool CheckTemplate(const QString& Name); - bool CheckRegistryKey(const QString& Value); - bool CheckFile(const QString& Value); void InitExpandPaths(bool WithUser); - QString ExpandPath(QString path); - std::list m_Objects; - std::list m_Classes; - std::list m_Services; - std::list m_Products; + QStringList m_Objects; + QStringList m_Classes; + QStringList m_Services; + QStringList m_Products; QMap m_Templates; diff --git a/SandboxiePlus/QSbieAPI/SbieAPI.cpp b/SandboxiePlus/QSbieAPI/SbieAPI.cpp index efc9e44c..ca7c3656 100644 --- a/SandboxiePlus/QSbieAPI/SbieAPI.cpp +++ b/SandboxiePlus/QSbieAPI/SbieAPI.cpp @@ -133,8 +133,8 @@ CSbieAPI::CSbieAPI(QObject* parent) : QThread(parent) { m = new SSbieAPI(); - m_pGlobalSection = new CSbieIni("GlobalSettings", this, this); - m_pUserSection = new CSbieIni("UserSettings", this, this); // dummy + m_pGlobalSection = QSharedPointer(new CSbieIni("GlobalSettings", this)); + m_pUserSection = QSharedPointer(new CSbieIni("UserSettings", this)); // dummy m_IniReLoad = false; m_bReloadPending = false; @@ -324,7 +324,7 @@ SB_STATUS CSbieAPI::Connect(bool takeOver, bool withQueue) if (m_UserName.isEmpty()) { QString UserSection = GetUserSection(&m_UserName); if(!UserSection.isEmpty()) - m_pUserSection = new CSbieIni(UserSection, this, this); + m_pUserSection = QSharedPointer(new CSbieIni(UserSection, this)); } if (m_UserDir.isEmpty()) { @@ -745,20 +745,6 @@ SB_STATUS CSbieAPI::CallServer(void* req, SScopedVoid* prpl) const return Status; } -/*void CSbieAPI::OnMonitorEntry(quint32 ProcessId, quint32 Type, const QString& Value) -{ - QMap::iterator I = m_BoxedProxesses.find(ProcessId); - if (I == m_BoxedProxesses.end()) - { - UpdateProcesses(true); - I = m_BoxedProxesses.find(ProcessId); - } - if (I == m_BoxedProxesses.end()) - return; - - I.value()->AddResourceEntry(Type, Value); -}*/ - QString CSbieAPI::GetVersion() { WCHAR out_version[16]; @@ -1033,7 +1019,7 @@ QString CSbieAPI::GetUserSection(QString* pUserName, bool* pIsAdmin) const return UserSection; } -SB_STATUS CSbieAPI::RunStart(const QString& BoxName, const QString& Command, bool Elevated, const QString& WorkingDir, QProcess* pProcess) +SB_RESULT(quint32) CSbieAPI::RunStart(const QString& BoxName, const QString& Command, bool Elevated, const QString& WorkingDir, QProcess* pProcess) { if (m_SbiePath.isEmpty()) return SB_ERR(SB_PathFail); @@ -1106,7 +1092,7 @@ SB_STATUS CSbieAPI::RunStart(const QString& BoxName, const QString& Command, boo if(pid == 0) return SB_ERR(); - return SB_OK; + return CSbieResult((quint32)pid); } QString CSbieAPI::GetStartPath() const @@ -1144,7 +1130,7 @@ SB_STATUS CSbieAPI::ReloadBoxes(bool bForceUpdate) m_SandBoxes.insert(BoxName.toLower(), pBox); emit BoxAdded(pBox); } - UpdateBoxPaths(pBox); + UpdateBoxPaths(pBox.data()); pBox->m_IsEnabled = bIsEnabled; @@ -1346,6 +1332,18 @@ SB_STATUS CSbieAPI::ValidateName(const QString& BoxName) return SB_OK; } +QString CSbieAPI::MkNewName(QString Name) +{ + Name.replace(QRegularExpression("[<>:\"/\\\\|?*\\[\\]]"), "-").replace(" ", "_"); + for (int i=0;; i++) { + QString NewName = Name; + if (i > 0) NewName.append("_" + QString::number(i)); + if (m_SandBoxes.contains(NewName.toLower())) + continue; + return NewName; + } +} + SB_STATUS CSbieAPI::CreateBox(const QString& BoxName, bool bReLoad) { SB_STATUS Status = ValidateName(BoxName); @@ -1390,7 +1388,7 @@ SB_STATUS CSbieAPI__GetProcessPIDs(SSbieAPI* m, const QString& BoxName, bool bAl return SB_OK; } -SB_STATUS CSbieAPI::UpdateProcesses(bool bKeep, bool bAllSessions) +SB_STATUS CSbieAPI::UpdateProcesses(int iKeep, bool bAllSessions) { ULONG count = 0; SB_STATUS Status = CSbieAPI__GetProcessPIDs(m, "", bAllSessions, NULL, &count); // query count @@ -1427,6 +1425,7 @@ SB_STATUS CSbieAPI::UpdateProcesses(bool bKeep, bool bAllSessions) if (pBox->m_ActiveProcessCount == 0) { pBox->m_ActiveProcessCount = 1; pBox->OpenBox(); + m_bBoxesDirty = true; emit BoxOpened(pBox); } @@ -1447,7 +1446,7 @@ SB_STATUS CSbieAPI::UpdateProcesses(bool bKeep, bool bAllSessions) pProcess->SetTerminated(); pProcess->m_pBox->m_ActiveProcessDirty = true; } - else if (!bKeep && pProcess->IsTerminated(1500)) { // keep for at least 1.5 seconds + else if (iKeep != -1 && pProcess->IsTerminated(iKeep)) { pProcess->m_pBox->m_ProcessList.remove(pProcess->m_ProcessId); m_BoxedProxesses.remove(pProcess->m_ProcessId); } @@ -1467,6 +1466,7 @@ SB_STATUS CSbieAPI::UpdateProcesses(bool bKeep, bool bAllSessions) pBox->m_ActiveProcessCount = ActiveProcessCount; if (WasBoxClosed) { pBox->CloseBox(); + m_bBoxesDirty = true; emit BoxClosed(pBox); } } @@ -1476,69 +1476,6 @@ SB_STATUS CSbieAPI::UpdateProcesses(bool bKeep, bool bAllSessions) return SB_OK; } -/*SB_STATUS CSbieAPI::UpdateProcesses(bool bKeep) -{ - foreach(const CSandBoxPtr& pBox, m_SandBoxes) - UpdateProcesses(bKeep, pBox); - return SB_OK; -} - -SB_STATUS CSbieAPI::UpdateProcesses(bool bKeep, const CSandBoxPtr& pBox) -{ - ULONG count = 0; - SB_STATUS Status = CSbieAPI__GetProcessPIDs(m, pBox->GetName(), NULL, &count); // query the count - if (Status.IsError()) - return Status; - - count += 128; // add some extra space - ULONG* boxed_pids = new ULONG[count]; - - Status = CSbieAPI__GetProcessPIDs(m, pBox->GetName(), boxed_pids, &count); // query the count - if (Status.IsError()) - goto finish; - - QMap OldProcessList = pBox->m_ProcessList; - - for (int i=0; i < count; i++) - { - quint32 ProcessId = boxed_pids[i]; - - CBoxedProcessPtr pProcess = OldProcessList.take(ProcessId); - if (!pProcess) - { - pProcess = CBoxedProcessPtr(NewBoxedProcess(ProcessId, pBox.data())); - pBox->m_ProcessList.insert(ProcessId, pProcess); - m_BoxedProxesses.insert(ProcessId, pProcess); - - UpdateProcessInfo(pProcess); - pProcess->InitProcessInfo(); - } - - pProcess->InitProcessInfoEx(); - } - - foreach(const CBoxedProcessPtr& pProcess, OldProcessList) - { - if (!pProcess->IsTerminated()) - pProcess->SetTerminated(); - else if (!bKeep && pProcess->IsTerminated(1500)) { // keep for at least 1.5 seconds - pBox->m_ProcessList.remove(pProcess->m_ProcessId); - m_BoxedProxesses.remove(pProcess->m_ProcessId); - } - } - - bool WasBoxClosed = pBox->m_ActiveProcessCount > 0 && count == 0; - pBox->m_ActiveProcessCount = count; - if (WasBoxClosed) { - pBox->CloseBox(); - emit BoxClosed(pBox->GetName()); - } - -finish: - delete[] boxed_pids; - return Status; -}*/ - bool CSbieAPI::HasProcesses(const QString& BoxName) { ULONG count; @@ -1576,7 +1513,7 @@ SB_STATUS CSbieAPI__QueryBoxPath(SSbieAPI* m, const WCHAR *box_name, WCHAR *out_ return SB_OK; } -SB_STATUS CSbieAPI::UpdateBoxPaths(const CSandBoxPtr& pSandBox) +SB_STATUS CSbieAPI::UpdateBoxPaths(CSandBox* pSandBox) { std::wstring boxName = pSandBox->GetName().toStdWString(); @@ -2380,6 +2317,7 @@ CBoxedProcessPtr CSbieAPI::OnProcessBoxed(quint32 ProcessId, const QString& Path if (pBox->m_ActiveProcessCount == 0) { pBox->m_ActiveProcessCount = 1; pBox->OpenBox(); + m_bBoxesDirty = true; emit BoxOpened(pBox); } diff --git a/SandboxiePlus/QSbieAPI/SbieAPI.h b/SandboxiePlus/QSbieAPI/SbieAPI.h index c53dae21..f2ed443a 100644 --- a/SandboxiePlus/QSbieAPI/SbieAPI.h +++ b/SandboxiePlus/QSbieAPI/SbieAPI.h @@ -60,10 +60,10 @@ public: virtual SB_STATUS ReloadBoxes(bool bForceUpdate = false); static SB_STATUS ValidateName(const QString& BoxName); + virtual QString MkNewName(QString Name); virtual SB_STATUS CreateBox(const QString& BoxName, bool bReLoad = true); - virtual SB_STATUS UpdateProcesses(bool bKeep, bool bAllSessions); - //virtual SB_STATUS UpdateProcesses(bool bKeep, const CSandBoxPtr& pBox); + virtual SB_STATUS UpdateProcesses(int iKeep, bool bAllSessions); virtual QMap GetAllBoxes() { return m_SandBoxes; } virtual QMap GetAllProcesses() { return m_BoxedProxesses; } @@ -98,8 +98,8 @@ public: virtual QString SbieIniGetEx(const QString& Section, const QString& Setting); virtual SB_STATUS SbieIniSet(const QString& Section, const QString& Setting, const QString& Value, ESetMode Mode = eIniUpdate, bool bRefresh = true); virtual bool IsBox(const QString& BoxName, bool& bIsEnabled); - virtual CSbieIni* GetGlobalSettings() const { return m_pGlobalSection; } - virtual CSbieIni* GetUserSettings() const { return m_pUserSection; } + virtual QSharedPointer GetGlobalSettings() const { return m_pGlobalSection; } + virtual QSharedPointer GetUserSettings() const { return m_pUserSection; } virtual QString GetCurrentUserName() const { return m_UserName; } virtual QString GetCurrentUserSid() const { return m_UserSid; } virtual bool IsConfigLocked(); @@ -140,7 +140,7 @@ public: virtual QString GetSbieMsgStr(quint32 code, quint32 Lang = 1033); - virtual SB_STATUS RunStart(const QString& BoxName, const QString& Command, bool Elevated = false, const QString& WorkingDir = QString(), QProcess* pProcess = NULL); + virtual SB_RESULT(quint32) RunStart(const QString& BoxName, const QString& Command, bool Elevated = false, const QString& WorkingDir = QString(), QProcess* pProcess = NULL); virtual QString GetStartPath() const; virtual quint32 GetSessionID() const; @@ -181,7 +181,6 @@ signals: void QueuedRequest(quint32 ClientPid, quint32 ClientTid, quint32 RequestId, const QVariantMap& Data); protected slots: - //virtual void OnMonitorEntry(quint32 ProcessId, quint32 Type, const QString& Value); virtual void OnIniChanged(const QString &path); virtual void OnReloadConfig(); virtual CBoxedProcessPtr OnProcessBoxed(quint32 ProcessId, const QString& Path, const QString& Box, quint32 ParentId, const QString& CmdLine); @@ -210,7 +209,7 @@ protected: virtual SB_STATUS RunSandboxed(const QString& BoxName, const QString& Command, QString WrkDir = QString(), quint32 Flags = 0); - virtual SB_STATUS UpdateBoxPaths(const CSandBoxPtr& pSandBox); + virtual SB_STATUS UpdateBoxPaths(CSandBox* pSandBox); virtual SB_STATUS UpdateProcessInfo(const CBoxedProcessPtr& pProcess); virtual void GetUserPaths(); @@ -251,8 +250,8 @@ protected: bool m_bWithQueue; bool m_bTerminate; - CSbieIni* m_pGlobalSection; - CSbieIni* m_pUserSection; + QSharedPointerm_pGlobalSection; + QSharedPointerm_pUserSection; QString m_UserName; QString m_UserSid; diff --git a/SandboxiePlus/QSbieAPI/SbieStatus.h b/SandboxiePlus/QSbieAPI/SbieStatus.h index 597e00aa..3ccc3c3e 100644 --- a/SandboxiePlus/QSbieAPI/SbieStatus.h +++ b/SandboxiePlus/QSbieAPI/SbieStatus.h @@ -29,9 +29,11 @@ enum ESbieMsgCodes SB_DeleteProtect, SB_DeleteNotEmpty, SB_DeleteError, + SB_RemNotStopped, //SB_RemNotEmpty, SB_DelNotEmpty, SB_FailedMoveDir, + SB_FailedMoveImage, SB_SnapMkDirFail, SB_SnapCopyDatFail, SB_SnapNotFound, @@ -46,6 +48,10 @@ enum ESbieMsgCodes SB_NameExists, SB_PasswordBad, SB_Canceled, + SB_DeleteNoMount, + + SB_OtherError, + SB_LastError }; diff --git a/SandboxiePlus/QSbieAPI/SbieUtils.cpp b/SandboxiePlus/QSbieAPI/SbieUtils.cpp index 7dedf730..59cc55f6 100644 --- a/SandboxiePlus/QSbieAPI/SbieUtils.cpp +++ b/SandboxiePlus/QSbieAPI/SbieUtils.cpp @@ -16,6 +16,54 @@ typedef long NTSTATUS; #include "SbieAPI.h" +template +__forceinline bool charIsNull(const T* v) { return *v == 0; } +__forceinline bool charIsNull(const QChar* v) { return v->isNull(); } + +template +bool wildcmpex(const T* Wild, const T* Str) +{ + const T *cp = NULL, *mp = NULL; + + while (!charIsNull(Str) && (*Wild != '*')) + { + if ((*Wild != *Str) && (*Wild != '?')) + return false; + Wild++; + Str++; + } + + while (!charIsNull(Str)) + { + if (*Wild == '*') + { + if (charIsNull(++Wild)) + return Str; + mp = Wild; + cp = Str + 1; + } + else if ((*Wild == *Str) || (*Wild == '?')) + { + Wild++; + Str++; + } + else + { + Wild = mp; + Str = cp++; + } + } + + while (*Wild == '*') + Wild++; + return charIsNull(Wild); +} + +bool CSbieUtils::WildCompare(const QString& L, const QString& R) +{ + return wildcmpex(L.data(), R.data()); +} + int GetServiceStatus(const wchar_t* name) { SC_HANDLE scm = OpenSCManager(nullptr, nullptr, SC_MANAGER_ENUMERATE_SERVICE); @@ -442,10 +490,8 @@ void CSbieUtils::RemoveContextMenu2() ////////////////////////////////////////////////////////////////////////////// // Shortcuts -bool CSbieUtils::CreateShortcut(CSbieAPI* pApi, QString LinkPath, const QString &LinkName, const QString &boxname, const QString &arguments, const QString &iconPath, int iconIndex, const QString &workdir, bool bRunElevated) +bool CSbieUtils::CreateShortcut(const QString& StartExe, QString LinkPath, const QString &LinkName, const QString &boxname, const QString &arguments, const QString &iconPath, int iconIndex, const QString &workdir, bool bRunElevated) { - QString StartExe = pApi->GetStartPath(); - QString StartArgs; if (bRunElevated) StartArgs += "/elevated "; @@ -475,7 +521,7 @@ bool CSbieUtils::CreateShortcut(CSbieAPI* pApi, QString LinkPath, const QString if (!workdir.isEmpty()) pShellLink->SetWorkingDirectory(workdir.toStdWString().c_str()); if (!LinkName.isEmpty()) { - QString desc = QString("%1 [%2]").arg(LinkName).arg(boxname.isEmpty() ? pApi->GetGlobalSettings()->GetText("DefaultBox", "DefaultBox") : boxname); + QString desc = QString("%1 [%2]").arg(LinkName).arg(boxname); pShellLink->SetDescription(desc.toStdWString().c_str()); } diff --git a/SandboxiePlus/QSbieAPI/SbieUtils.h b/SandboxiePlus/QSbieAPI/SbieUtils.h index 01dfca88..c0c38933 100644 --- a/SandboxiePlus/QSbieAPI/SbieUtils.h +++ b/SandboxiePlus/QSbieAPI/SbieUtils.h @@ -16,6 +16,8 @@ public: eAll = 0xFF }; + static bool WildCompare(const QString& L, const QString& R); + static SB_STATUS DoAssist(); static SB_RESULT(void*) Start(EComponent Component); @@ -34,7 +36,7 @@ public: static void AddContextMenu2(const QString& StartPath, const QString& RunStr, const QString& IconPath = QString()); static void RemoveContextMenu2(); - static bool CreateShortcut(class CSbieAPI* pApi, QString LinkPath, const QString &LinkName, const QString &boxname, const QString &arguments, const QString &iconPath = QString(), int iconIndex = 0, const QString &workdir = QString(), bool bRunElevated = false); + static bool CreateShortcut(const QString& StartExe, QString LinkPath, const QString &LinkName, const QString &boxname, const QString &arguments, const QString &iconPath = QString(), int iconIndex = 0, const QString &workdir = QString(), bool bRunElevated = false); static bool GetStartMenuShortcut(class CSbieAPI* pApi, QString &BoxName, QString &LinkPath, QString &IconPath, quint32& IconIndex, QString &WorkDir); static CSbieProgressPtr RunCommand(const QString& Command, bool noGui = false); diff --git a/SandboxiePlus/SandMan/AddonManager.cpp b/SandboxiePlus/SandMan/AddonManager.cpp new file mode 100644 index 00000000..a49f766b --- /dev/null +++ b/SandboxiePlus/SandMan/AddonManager.cpp @@ -0,0 +1,444 @@ +#include "stdafx.h" +#include "AddonManager.h" +#include "SandMan.h" +#include "OnlineUpdater.h" +#include "../MiscHelpers/Common/Common.h" +#include "../MiscHelpers/Common/OtherFunctions.h" +#include +#include +#include +#include "QSbieAPI/Sandboxie/SbieTemplates.h" +#include +#include "../MiscHelpers/Archive/Archive.h" + + +#include + +CAddonManager::CAddonManager(QObject* parent) + : QObject(parent) +{ + +} + +void CAddonManager::UpdateAddons() +{ + theGUI->m_pUpdater->GetUpdates(this, SLOT(OnUpdateData(const QVariantMap&, const QVariantMap&))); +} + +void CAddonManager::OnUpdateData(const QVariantMap& Data, const QVariantMap& Params) +{ + if (Data.isEmpty() || Data["error"].toBool()) + return; + + QVariantMap Addons = Data["addons"].toMap(); + + QJsonDocument doc(QJsonValue::fromVariant(Addons).toObject()); + WriteStringToFile(theConf->GetConfigDir() + "/addons.json", doc.toJson()); + + LoadAddons(); + emit DataUpdated(); +} + +QList CAddonManager::GetAddons() +{ + if (m_Addons.isEmpty()) { + if (!LoadAddons()) + UpdateAddons(); + } + else { + foreach(const CAddonPtr& pAddon, m_Addons) + pAddon->Installed = CheckAddon(pAddon); + } + return m_Addons; +} + +bool CAddonManager::LoadAddons() +{ + m_Addons.clear(); + + QString AddonPath = theConf->GetConfigDir() + "/addons.json"; + QVariantMap Data = QJsonDocument::fromJson(ReadFileAsString(AddonPath).toUtf8()).toVariant().toMap(); + foreach(const QVariant vAddon, Data["list"].toList()) { + CAddonPtr pAddon = CAddonPtr(new CAddon(vAddon.toMap())); + pAddon->Installed = CheckAddon(pAddon); + m_Addons.append(pAddon); + } + + return !m_Addons.isEmpty(); +} + +CAddonPtr CAddonManager::GetAddon(const QString& Id) +{ + if (m_Addons.isEmpty()) + LoadAddons(); + + foreach(const CAddonPtr& pAddon, m_Addons) { + if (pAddon->Id.compare(Id, Qt::CaseInsensitive) == 0) { + pAddon->Installed = CheckAddon(pAddon); + return pAddon; + } + } + return CAddonPtr(); +} + +bool CAddonManager::HasAddon(const QString& Id) +{ + CAddonPtr pAddon = GetAddon("FileChecker"); + return pAddon && pAddon->Installed; +} + +bool CAddonManager::CheckAddon(const CAddonPtr& pAddon) +{ + QString Key = pAddon->GetSpecificEntry("uninstall_key").toString(); + if (!Key.isEmpty()) { + QSettings settings(Key, QSettings::NativeFormat); + QString Uninstall = settings.value("UninstallString").toString(); + return !Uninstall.isEmpty(); + } + + QStringList Files = pAddon->GetSpecificEntry("files").toStringList(); + foreach(const QString & File, Files) { + if (theGUI->GetCompat()->CheckFile(ExpandPath(File))) + return true; + } + return false; +} + +SB_PROGRESS CAddonManager::TryInstallAddon(const QString& Id, QWidget* pParent, const QString& Prompt) +{ + if (QMessageBox("Sandboxie-Plus", Prompt.isEmpty() ? tr("Do you want to download and install %1?").arg(Id) : Prompt, + QMessageBox::Question, QMessageBox::Yes | QMessageBox::Default, QMessageBox::No | QMessageBox::Escape, QMessageBox::NoButton, pParent ? pParent : theGUI).exec() != QMessageBox::Yes) + return SB_ERR(SB_OtherError); + + SB_PROGRESS Status = InstallAddon(Id); + if (Status.GetStatus() == OP_ASYNC) + theGUI->AddAsyncOp(Status.GetValue(), false, tr("Installing: %1").arg(Id), pParent); + else + theGUI->CheckResults(QList() << Status, pParent); + return Status; +} + +SB_PROGRESS CAddonManager::InstallAddon(const QString& Id) +{ + CAddonPtr pAddon = GetAddon(Id); + if (!pAddon) + return SB_ERR(SB_OtherError, QVariantList() << tr("Addon not found, please try updating the addon list in the global settings!")); + if (pAddon->Installed) + return SB_ERR(SB_OtherError, QVariantList() << tr("Addon already installed!")); + + QString Entry; + QString Url = pAddon->GetSpecificEntry("download", &Entry).toString(); + if (Url.isEmpty()) + return SB_ERR(SB_OtherError, QVariantList() << tr("Addon has no download url, addon may not be available for your platform.")); + + QVariantMap Params; + Params["name"] = Id; + Params["path"] = theGUI->m_pUpdater->GetUpdateDir(true) + "/" + QUrl(Url).fileName(); + Params["signature"] = pAddon->Data.value(Entry + "_sig"); + theGUI->m_pUpdater->DownloadFile(Url, this, SLOT(OnAddonDownloaded(const QString&, const QVariantMap&)), Params); + + pAddon->pProgress = CSbieProgressPtr(new CSbieProgress()); + connect(pAddon->pProgress.data(), SIGNAL(Finished()), this, SIGNAL(AddonInstalled())); + pAddon->pProgress->ShowMessage(tr("Downloading Addon %1").arg(pAddon->Id)); + return SB_PROGRESS(OP_ASYNC, pAddon->pProgress); +} + +extern "C" NTSTATUS VerifyFileSignatureImpl(const wchar_t* FilePath, PVOID Signature, ULONG SignatureSize); + +void CAddonManager::OnAddonDownloaded(const QString& Path, const QVariantMap& Params) +{ + CAddonPtr pAddon = GetAddon(Params["name"].toString()); + + QByteArray Signature = QByteArray::fromBase64(Params["signature"].toByteArray()); + + if (VerifyFileSignatureImpl(QString(Path).replace("/","\\").toStdWString().c_str(), Signature.data(), Signature.size()) < 0) { // !NT_SUCCESS + pAddon->pProgress->Finish(SB_ERR(SB_OtherError, QVariantList() << tr("Download signature is not valid!"))); + pAddon->pProgress.create(); + return; + } + + pAddon->pProgress->ShowMessage(tr("Installing Addon %1").arg(pAddon->Id)); + + QtConcurrent::run(CAddonManager::InstallAddonAsync, Path, pAddon); +} + +void CAddonManager::InstallAddonAsync(const QString& FilePath, CAddonPtr pAddon) +{ + SB_STATUS Status = SB_OK; + + CArchive Archive(FilePath); + + if (Archive.Open() == 1) + { + QString FileDir = Split2(FilePath, ".", true).first.replace("/", "\\"); + if (Archive.Extract(FileDir)) { + + QString Cmd = pAddon->GetSpecificEntry("installer").toString(); + QString Path = ExpandPath(pAddon->GetSpecificEntry("install_path").toString()); + if (!Cmd.isEmpty() && QFile::exists(FileDir + Cmd)) + { + pAddon->pProgress->ShowMessage(tr("Running Installer for %1").arg(pAddon->Id)); + + std::wstring sbiehome = theAPI->GetSbiePath().toStdWString(); + std::wstring plusdata = theConf->GetConfigDir().toStdWString(); + + LPWCH environmentStrings = GetEnvironmentStrings(); + + DWORD environmentLen = 0; + for (LPWCH current = environmentStrings; *current; current += wcslen(current) + 1) + environmentLen += wcslen(current) + 1; + + LPWCH modifiedEnvironment = (LPWCH)LocalAlloc(0, (environmentLen + sbiehome.length() + 1 + plusdata.length() + 1 + 1) * sizeof(wchar_t)); + memcpy(modifiedEnvironment, environmentStrings, (environmentLen + 1) * sizeof(wchar_t)); + + FreeEnvironmentStrings(environmentStrings); + + LPWCH modifiedEnvironmentEnd = modifiedEnvironment + environmentLen; + + wcscpy(modifiedEnvironmentEnd, L"SBIEHOME="); + wcscat(modifiedEnvironmentEnd, sbiehome.c_str()); + modifiedEnvironmentEnd += wcslen(modifiedEnvironmentEnd) + 1; + + wcscpy(modifiedEnvironmentEnd, L"PLUSDATA="); + wcscat(modifiedEnvironmentEnd, plusdata.c_str()); + modifiedEnvironmentEnd += wcslen(modifiedEnvironmentEnd) + 1; + + *modifiedEnvironmentEnd = 0; + + STARTUPINFO si = { sizeof(si), 0 }; + PROCESS_INFORMATION pi = { 0 }; + if (CreateProcessW(NULL, (wchar_t*)(FileDir + Cmd).toStdWString().c_str(), NULL, NULL, FALSE, CREATE_UNICODE_ENVIRONMENT, modifiedEnvironment, NULL, &si, &pi)) + { + while (WaitForSingleObject(pi.hProcess, 1000) == WAIT_TIMEOUT && !pAddon->pProgress->IsCanceled()); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + } + else + Status = SB_ERR(SB_OtherError, QVariantList() << tr("Failes to start installer (%1)!").arg(GetLastError())); + + LocalFree(modifiedEnvironment); + } + else if (!Path.isEmpty()) + { + pAddon->pProgress->ShowMessage(tr("Copying Files for %1").arg(pAddon->Id)); + + std::wstring from; + foreach(const QString & file, ListDir(FileDir)) { + QString File = QString(file).replace("/", "\\"); + from.append((FileDir + "\\" + File).toStdWString()); + from.append(L"\0", 1); + } + from.append(L"\0", 1); + + std::wstring to; + to.append(Path.toStdWString()); + to.append(L"\0", 1); + + SHFILEOPSTRUCT SHFileOp; + memset(&SHFileOp, 0, sizeof(SHFILEOPSTRUCT)); + SHFileOp.hwnd = NULL; + SHFileOp.wFunc = FO_MOVE; + SHFileOp.pFrom = from.c_str(); + SHFileOp.pTo = to.c_str(); + SHFileOp.fFlags = FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR; + + SHFileOperation(&SHFileOp); + } + + QDir(FileDir).removeRecursively(); + } + else + Status = SB_ERR(SB_OtherError, QVariantList() << tr("Failes to unpack addon!")); + Archive.Close(); + } + + QFile::remove(FilePath); + + if (!Status.IsError()) { + pAddon->Installed = CheckAddon(pAddon); + if (!pAddon->Installed) + Status = SB_ERR(SB_OtherError, QVariantList() << tr("Addon Instalation Failed!")); + } + pAddon->pProgress->Finish(Status); + pAddon->pProgress.create(); +} + +SB_PROGRESS CAddonManager::TryRemoveAddon(const QString& Id, QWidget* pParent) +{ + if (QMessageBox("Sandboxie-Plus", tr("Do you want to remove %1?").arg(Id), + QMessageBox::Question, QMessageBox::Yes | QMessageBox::Default, QMessageBox::No | QMessageBox::Escape, QMessageBox::NoButton, pParent ? pParent : theGUI).exec() != QMessageBox::Yes) + return SB_ERR(SB_OtherError); + + SB_PROGRESS Status = RemoveAddon(Id); + if (Status.GetStatus() == OP_ASYNC) + theGUI->AddAsyncOp(Status.GetValue(), false, tr("Removing: %1").arg(Id), pParent); + else + theGUI->CheckResults(QList() << Status, pParent); + return Status; +} + +SB_PROGRESS CAddonManager::RemoveAddon(const QString& Id) +{ + CAddonPtr pAddon = GetAddon(Id); + if (!pAddon) + return SB_ERR(SB_OtherError, QVariantList() << tr("Addon not found!")); + + pAddon->pProgress = CSbieProgressPtr(new CSbieProgress()); + QtConcurrent::run(CAddonManager::RemoveAddonAsync, pAddon); + return SB_PROGRESS(OP_ASYNC, pAddon->pProgress); +} + +void CAddonManager::CleanupPath(const QString& Path) +{ + StrPair PathName = Split2(Path, "\\", true); + if (ListDir(PathName.first).isEmpty()) + { + QDir().rmdir(PathName.first); + //qDebug() << "delete dir" << PathName.first; + CleanupPath(PathName.first); + } +} + +void CAddonManager::RemoveAddonAsync(CAddonPtr pAddon) +{ + SB_STATUS Status = SB_OK; + + QString Key = pAddon->GetSpecificEntry("uninstall_key").toString(); + if (!Key.isEmpty()) + { + QSettings settings(Key, QSettings::NativeFormat); + QString Cmd = settings.value("UninstallString").toString(); + + pAddon->pProgress->ShowMessage(tr("Running Uninstaller for %1").arg(pAddon->Id)); + + STARTUPINFO si = { sizeof(si), 0 }; + PROCESS_INFORMATION pi = { 0 }; + if (CreateProcessW(NULL, (wchar_t*)Cmd.toStdWString().c_str(), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) + { + while (WaitForSingleObject(pi.hProcess, 1000) == WAIT_TIMEOUT && !pAddon->pProgress->IsCanceled()); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + } + else + Status = SB_ERR(SB_OtherError, QVariantList() << tr("Failes to start uninstaller!")); + } + else + { + QStringList Files = pAddon->GetSpecificEntry("files").toStringList(); + //foreach(const QString & File, Files) { + // pAddon->pProgress->ShowMessage(tr("Removing %1").arg(File)); + // QString FilePath = ExpandPath(File); + // QFile::remove(FilePath); + // CleanupPath(FilePath); + //} + + std::wstring from; + foreach(const QString & File, Files) { + QString FilePath = ExpandPath(File); + if (QFile::exists(FilePath)) { + from.append(FilePath.toStdWString()); + from.append(L"\0", 1); + } + } + from.append(L"\0", 1); + + SHFILEOPSTRUCT SHFileOp; + memset(&SHFileOp, 0, sizeof(SHFILEOPSTRUCT)); + SHFileOp.hwnd = NULL; + SHFileOp.wFunc = FO_DELETE; + SHFileOp.pFrom = from.c_str(); + SHFileOp.pTo = NULL; + SHFileOp.fFlags = FOF_NOCONFIRMATION; + + SHFileOperation(&SHFileOp); + } + + if (!Status.IsError()) { + pAddon->Installed = CheckAddon(pAddon); + if (pAddon->Installed) + Status = SB_ERR(SB_OtherError, QVariantList() << tr("Addon Removal Failed!")); + } + pAddon->pProgress->Finish(Status); + pAddon->pProgress.create(); +} + +QString CAddonManager::ExpandPath(QString Path) +{ + Path.replace("%SbieHome%", theAPI->GetSbiePath(), Qt::CaseInsensitive); + Path.replace("%PlusData%", theConf->GetConfigDir(), Qt::CaseInsensitive); + + return theGUI->GetCompat()->ExpandPath(Path); +} + +QString GetArch() +{ + SYSTEM_INFO systemInfo; + GetSystemInfo(&systemInfo); + switch (systemInfo.wProcessorArchitecture) + { + case PROCESSOR_ARCHITECTURE_INTEL: return "x86"; + case PROCESSOR_ARCHITECTURE_AMD64: return "x64"; + case PROCESSOR_ARCHITECTURE_ARM64: return "a64"; + } + return "???"; +} + +QVariant CAddon::GetSpecificEntry(const QString& Name, QString* pName) +{ +#ifdef _M_ARM64 + QString arch = "a64"; +#elif _WIN64 + QString arch = "x64"; +#else + QString arch = "x86"; +#endif + + // + // First we check the qt cpecific entry for our version of qt and platform + // + + QString qt = QString("qt%1_%2_%3_%4").arg(QT_VERSION_MAJOR).arg(QT_VERSION_MINOR).arg(QT_VERSION_PATCH).arg(arch); +#ifdef _DEBUG + qt.append("d"); +#endif // _DEBUG + if (Data.contains(Name + "_" + qt)) { + if (pName) *pName = Name + "_" + qt; + return Data[Name + "_" + qt]; + } + + // + // Second we check the actual architecture + // + + QString match = Data["match_arch"].toString(); + if (match != "agent") + arch = GetArch(); + if (Data.contains(Name + "_" + arch)) { + if (pName) *pName = Name + "_" + arch; + return Data[Name + "_" + arch]; + } + + // + // last we try the unsoecific entry + // + + if (Data.contains(Name)) { + if (pName) *pName = Name; + return Data[Name]; + } + + return QString(); +} + +QString CAddon::GetLocalizedEntry(const QString& Name) +{ + if (Data.contains(Name + "_" + theGUI->m_Language)) + return Data[Name + "_" + theGUI->m_Language].toString(); + + QString LangAux = theGUI->m_Language; // Short version as fallback + LangAux.truncate(LangAux.lastIndexOf('_')); + if (Data.contains(Name + "_" + LangAux)) + return Data[Name + "_" + LangAux].toString(); + + return Data[Name].toString(); +} \ No newline at end of file diff --git a/SandboxiePlus/SandMan/AddonManager.h b/SandboxiePlus/SandMan/AddonManager.h new file mode 100644 index 00000000..3720ec73 --- /dev/null +++ b/SandboxiePlus/SandMan/AddonManager.h @@ -0,0 +1,64 @@ +#pragma once +#include +#include "../QSbieAPI/SbieStatus.h" + + +class CAddon : public QObject +{ +public: + CAddon(const QVariantMap& Data) : Installed(false), Data(Data) + { + Id = Data["id"].toString(); + } + QString Id; + QVariantMap Data; + bool Installed; + CSbieProgressPtr pProgress; + + QVariant GetSpecificEntry(const QString& Name, QString* pName = NULL); + QString GetLocalizedEntry(const QString& Name); +}; + +typedef QSharedPointer CAddonPtr; + +class CAddonManager : public QObject +{ + Q_OBJECT +public: + CAddonManager(QObject* parent = NULL); + + bool LoadAddons(); + + void UpdateAddons(); + + QList GetAddons(); + + CAddonPtr GetAddon(const QString& Id); + bool HasAddon(const QString& Id); + + SB_PROGRESS TryInstallAddon(const QString& Id, QWidget* pParent, const QString& Prompt = QString()); + SB_PROGRESS InstallAddon(const QString& Id); + SB_PROGRESS TryRemoveAddon(const QString& Id, QWidget* pParent); + SB_PROGRESS RemoveAddon(const QString& Id); + +signals: + void DataUpdated(); + void AddonInstalled(); + +private slots: + void OnUpdateData(const QVariantMap& Data, const QVariantMap& Params); + void OnAddonDownloaded(const QString& Path, const QVariantMap& Params); + +protected: + static bool CheckAddon(const CAddonPtr& pAddon); + + static void CleanupPath(const QString& Path); + + static void InstallAddonAsync(const QString& FilePath, CAddonPtr pAddon); + static void RemoveAddonAsync(CAddonPtr pAddon); + + static QString ExpandPath(QString Path); + + QList m_Addons; +}; + diff --git a/SandboxiePlus/SandMan/Engine/BoxEngine.cpp b/SandboxiePlus/SandMan/Engine/BoxEngine.cpp new file mode 100644 index 00000000..2f464e4d --- /dev/null +++ b/SandboxiePlus/SandMan/Engine/BoxEngine.cpp @@ -0,0 +1,386 @@ +#include "stdafx.h" +#include "BoxEngine.h" +#include "../../QSbieAPI/SbieUtils.h" + +#include "BoxObject.h" +#include "SbieObject.h" +#include "IniObject.h" +#include "SysObject.h" +#include "WizardObject.h" + +#include "../Wizards/BoxAssistant.h" + +#include +#include + +int CBoxEngine::m_InstanceCount = 0; + +CBoxEngine::CBoxEngine(QObject* parent) : QThread(parent) +{ + m_InstanceCount++; + + m_State = eUnknown; + m_pEngine = NULL; + m_pDebuggerBackend = NULL; + + //static QQmlDebuggingEnabler qQmlEnableDebuggingHelper(false); + //QQmlDebuggingEnabler::startTcpDebugServer(1234, QQmlDebuggingEnabler::WaitForClient); +} + +CBoxEngine::~CBoxEngine() +{ + m_Mutex.lock(); + if (m_State == eQuery || m_State == eReady) + Continue(true, eCanceled); + else { + if (m_State == eRunning || m_State == eRunningAsync) + m_State = eCanceled; + m_Mutex.unlock(); + } + + if (!wait(30 * 1000)) { + qDebug() << "Failed to terminate Box Engine"; + return; + } + + m_InstanceCount--; +} + +QV4::ReturnedValue method_translate(const QV4::FunctionObject *b, const QV4::Value *v, const QV4::Value *argv, int argc) +{ + QV4::Scope scope(b); + QV4::ExecutionEngine *v4 = scope.engine; + + CBoxEngine* pEngine = qobject_cast(CJSEngineExt::getEngineByHandle(v4)->thread()); + CBoxAssistant* Wizard = qobject_cast(pEngine->parent()); // todo make teranslation work also for system scripts + + QString Result; + for (int i = 0; i < argc; i++) { + if (i == 0) Result = (Wizard ? Wizard->Tr(argv[i].toQStringNoThrow()) : argv[i].toQStringNoThrow()); + else Result = Result.arg(argv[i].toQStringNoThrow()); + } + + return QV4::Encode(scope.engine->newString(Result)); +} + +QV4::ReturnedValue method_print(const QV4::FunctionObject *b, const QV4::Value *v, const QV4::Value *argv, int argc) +{ + QV4::Scope scope(b); + QV4::ExecutionEngine *v4 = scope.engine; + + QString Result; + for (int i = 0; i < argc; i++) { + if (i > 0) Result.append(" "); + Result.append(argv[i].toQStringNoThrow()); + } + CBoxEngine* pEngine = qobject_cast(CJSEngineExt::getEngineByHandle(v4)->thread()); + pEngine->AppendLog(Result); + + return QV4::Encode::undefined(); +} + +QV4::ReturnedValue method_wcmp(const QV4::FunctionObject *b, const QV4::Value *v, const QV4::Value *argv, int argc) +{ + QV4::Scope scope(b); + QV4::ExecutionEngine *v4 = scope.engine; + + if (argc < 2) + return QV4::Encode::undefined(); + + return QV4::Encode(CSbieUtils::WildCompare(argv[0].toQStringNoThrow(), argv[1].toQStringNoThrow())); +} + +void CBoxEngine::init() +{ + QV4::Scope scope(m_pEngine->handle()); + scope.engine->globalObject->defineDefaultProperty(QStringLiteral("tr"), method_translate); + scope.engine->globalObject->defineDefaultProperty(QStringLiteral("print"), method_print); + scope.engine->globalObject->defineDefaultProperty(QStringLiteral("wildCompare"), method_wcmp); + + m_pEngine->globalObject().setProperty("system", m_pEngine->newQObject(new JSysObject(this))); + m_pEngine->globalObject().setProperty("sbie", m_pEngine->newQObject(new JSbieObject(new CSbieObject(this), this))); +} + +bool CBoxEngine::RunScript(const QString& Script, const QString& Name) +{ + if (isRunning()) + return false; + + m_Script = Script; + m_Name = Name; + m_State = eRunning; + + if(!m_pEngine) m_pEngine = new CJSEngineExt(); // the engine lives in its own thread + //m_pEngine->installExtensions(QJSEngine::ConsoleExtension); + + init(); + + m_pEngine->moveToThread(this); + + ////////////////////////////////////////////////////////////////////// + // + // !!! CAUTION Multi Threading !!! + // + // Note: The engine runs in its own thread but the rest of SandMan + // is mostly single threaded, also QSbieAPI is not hread safe so + // access to it must be synchronized. We solve this by executing + // all calls to theGUI and/or theAPI in the main thread through + // the use of QT's slot system, we wrap all calls from the engine + // in blocking QMetaObject::invokeMethod calls targeting to objects + // which belong the main thread hence thay need to be created in + // the main thread and passed to the caller from there. + // + // + + start(); + + //return Wait(); + return true; // fully async operation +} + +void CBoxEngine::run() +{ + //QElapsedTimer timer; + //timer.start(); + + //auto ret = m_pEngine->evaluateScript("(()=>{" + m_Script + "})()", m_Name); + auto ret = m_pEngine->evaluateScript(m_Script, m_Name); + + //qDebug() << "CBoxEngine::run took" << timer.elapsed() << "ms"; + + if (IsRunning()) { + if (ret.isError()) { + QString Error = tr("Uncaught exception at line %1: %2").arg(ret.property("lineNumber").toInt()).arg(ret.toString()); + AppendLog(Error); + SetState(eError, Error); + } + else + SetState(eCompleted); + } + + m_Result = m_pEngine->globalObject().property("result").toVariant(); + + delete m_pEngine; + m_pEngine = NULL; +} + +//bool CBoxEngine::Wait() +//{ +// while (m_State == eRunning) +// QCoreApplication::processEvents(); // keep the main thread going +// return true; +//} + +bool CBoxEngine::SetResult(const QVariantMap& Result) +{ + m_Mutex.lock(); + m_Data = Result; + return Continue(true); +} + +bool CBoxEngine::Continue(bool bLocked, EState State) +{ + Q_ASSERT(!IsRunning()); + + if (!bLocked) m_Mutex.lock(); + + // Note: we set the state directly and the engine thread emits set state from WaitLocked + + m_State = State; + m_Wait.wakeOne(); + m_Mutex.unlock(); + + //return Wait(); + return true; // fully async operation +} + +void CBoxEngine::SetState(EState state, const QString& Text) +{ + m_State = state; + emit StateChanged(state, Text); +} + +bool CBoxEngine::TestRunning() { + + // WARNING: call this function only from the engine thread itself !!! + + if (!IsRunning()) { + m_pEngine->throwError(QString("Canceled")); + return false; + } + return true; +} + +bool CBoxEngine::WaitLocked() { + + // WARNING: call this function only from the engine thread itself !!! + + m_Wait.wait(&m_Mutex); + + emit StateChanged(m_State); + + return TestRunning(); +} + +void CBoxEngine::AppendLog(const QString& Line) +{ + qDebug() << "BoxEngine Log:" << Line; + + emit LogMessage(Line); + + //QMutexLocker Locker(&m_Mutex); + //m_Log += Line + "\n"; +} + +QObject* CBoxEngine::GetDebuggerBackend() +{ + if(!m_pEngine) + m_pEngine = new CJSEngineExt(); + if (!m_pDebuggerBackend) { + m_pDebuggerBackend = newV4ScriptDebuggerBackendDynamic(m_pEngine); + if (m_pDebuggerBackend) { + QMetaObject::invokeMethod(m_pDebuggerBackend, "pause", Qt::DirectConnection); + m_pDebuggerBackend->setParent(this); + } + } + return m_pDebuggerBackend; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// CWizardEngine +// + +CWizardEngine::CWizardEngine(QObject* parent) + : CBoxEngine(parent) +{ +} + +CWizardEngine::~CWizardEngine() +{ + foreach(const SBoxShadow& pShadow, m_Shadows) { + if (pShadow.pShadow) { + if (pShadow.iApplyChanges == 2) + continue; // this is a new added entry keep it + CSandBoxPtr pBox = pShadow.pShadow.objectCast(); + if(!pBox.isNull()) pBox->TerminateAll(); + pShadow.pShadow->RemoveSection(); + } + } + theAPI->ReloadBoxes(true); +} + +bool CWizardEngine::ApplyShadowChanges() +{ + for (auto I = m_Shadows.begin(); I != m_Shadows.end(); ++I) { + if (I->iApplyChanges != 1) + continue; + + if (I->pOriginal.isNull()) { + // This is a new box or tamplete not a copy, just clear shadow flag + I->pShadow->DelValue("IsShadow", "y"); + I->iApplyChanges = 2; + continue; + } + + QList> New = I->pShadow->GetIniSection(); + QList> Old = I->pOriginal->GetIniSection(); + + // discard unchanged + for (auto I = New.begin(); I != New.end();) { + auto II = I++; + for (auto J = Old.begin(); J != Old.end();) { + auto JJ = J++; + if (II->first == JJ->first && II->second == JJ->second) { + I = New.erase(II); + J = Old.erase(JJ); + break; + } + } + } + + // apply changed + foreach(auto & O, Old) + I->pOriginal->DelValue(O.first, O.second); + foreach(auto & N, New) { + if (N.first == "FileRootPath" || N.first == "IsShadow") + continue; // skip + if(N.first == "Template" && IsNoAppliedShadow("Template_" + N.second)) + continue; // don't copy not applied shadow templates + I->pOriginal->AppendText(N.first, N.second); + } + } + + theAPI->CommitIniChanges(); + + return true; +} + +void CWizardEngine::init() +{ + CBoxEngine::init(); + + m_pEngine->globalObject().setProperty("wizard", m_pEngine->newQObject(new JWizardObject(this))); +} + +void CWizardEngine::SetState(EState state, const QString& Text) +{ + if (state == eError) + m_Report["Error"] = Text; + CBoxEngine::SetState(state, Text); +} + +QSharedPointer CWizardEngine::MakeShadow(const QSharedPointer& pIni) +{ + SBoxShadow& pShadow = m_Shadows[pIni->GetName().toLower()]; + if (!pShadow.pShadow) { + QString ShadowName = pIni->GetName(); + QString Suffix = tr("_Shadow"); + ShadowName.truncate(32 - (Suffix.length() + 3)); // BOXNAME_COUNT + ShadowName = theAPI->MkNewName(ShadowName.append(Suffix)); + + QList> Settings = pIni->GetIniSection(); + for (QList>::iterator I = Settings.begin(); I != Settings.end(); ++I) + theAPI->SbieIniSet(ShadowName, I->first, I->second, CSbieAPI::eIniInsert, false); + + CSandBoxPtr pBox = pIni.objectCast(); + if(!pBox.isNull()) + theAPI->SbieIniSet(ShadowName, "FileRootPath", pBox->GetFileRoot(), CSbieAPI::eIniUpdate, false); + theAPI->SbieIniSet(ShadowName, "IsShadow", "y", CSbieAPI::eIniUpdate, false); + + theAPI->CommitIniChanges(); + theAPI->ReloadBoxes(true); + + pShadow.pOriginal = pIni; + if (pBox) + pShadow.pShadow = theAPI->GetBoxByName(ShadowName); + else + pShadow.pShadow = QSharedPointer(new CSbieIni(ShadowName, theAPI)); + } + return pShadow.pShadow; +} + +void CWizardEngine::AddShadow(const QSharedPointer& pIni) +{ + SBoxShadow& pShadow = m_Shadows[pIni->GetName().toLower()]; + if (!pShadow.pShadow) { + + pIni->SetText("IsShadow", "y"); + + pShadow.pShadow = pIni; + } +} + +void CWizardEngine::SetApplyShadow(const QString& OriginalName, bool bApply) +{ + auto I = m_Shadows.find(OriginalName.toLower()); + if(I != m_Shadows.end()) + I->iApplyChanges = bApply ? 1 : 0; +} + +bool CWizardEngine::IsNoAppliedShadow(const QString& OriginalName) +{ + auto I = m_Shadows.find(OriginalName.toLower()); + if (I != m_Shadows.end()) + return I->iApplyChanges == 0; + return false; +} \ No newline at end of file diff --git a/SandboxiePlus/SandMan/Engine/BoxEngine.h b/SandboxiePlus/SandMan/Engine/BoxEngine.h new file mode 100644 index 00000000..7a8a1df5 --- /dev/null +++ b/SandboxiePlus/SandMan/Engine/BoxEngine.h @@ -0,0 +1,132 @@ +#pragma once +#include +#include +#include "../../QSbieAPI/SbieAPI.h" + +#include "JSEngineExt.h" + +class CBoxEngine : public QThread +{ + Q_OBJECT +public: + CBoxEngine(QObject* parent = NULL); + ~CBoxEngine(); + + bool RunScript(const QString& Script, const QString& Name); + + enum EState { + eUnknown, + + eRunning, + eRunningAsync, + eReady, + eQuery, + + eCompleted, + eSuccess, + eFailed, + eError, + eCanceled + }; + + EState GetState() const { return m_State; } + + bool IsRunning() const { return m_State == eRunning || m_State == eRunningAsync; } + bool Continue() { return Continue(false); } + + bool HasFailed() const { return m_State == eFailed; } + bool HasError() const { return m_State == eError; } + + bool IsReady() const { return m_State == eReady; } + bool HasQuery() const { return m_State == eQuery; } + QVariantMap GetQuery() const { QMutexLocker Locker(&m_Mutex); return m_State == eQuery ? m_Data : QVariantMap(); } + bool SetResult(const QVariantMap& Result); + QVariant GetResult() const { return m_Result; } + + void AppendLog(const QString& Line); + //QString GetLog() const { QMutexLocker Locker(&m_Mutex); return m_Log; } + + static int GetInstanceCount() { return m_InstanceCount; } + + QObject* GetDebuggerBackend(); + +signals: + + void StateChanged(int state, const QString& Text = ""); + + void BoxUsed(const CSandBoxPtr& pBox); + + void LogMessage(const QString& Line); + +protected: + friend class JSysObject; + friend class JSbieObject; + friend class JIniObject; + friend class JConfObject; + friend class JBoxObject; + friend class JBoxWObject; + + virtual void init(); + virtual void run(); + //virtual bool Wait(); + virtual bool Continue(bool bLocked, EState State = eRunning); + + virtual void SetState(EState state, const QString& Text = ""); + bool TestRunning(); + bool WaitLocked(); + + CJSEngineExt* m_pEngine; + QObject* m_pDebuggerBackend; + QString m_Script; + QString m_Name; + QVariant m_Result; + + mutable QMutex m_Mutex; + QWaitCondition m_Wait; + QVariantMap m_Data; + EState m_State; + + //QString m_Log; + + static int m_InstanceCount; +}; + +////////////////////////////////////////////////////////////////////////////////////////// +// CWizardEngine +// + +class CWizardEngine : public CBoxEngine +{ + Q_OBJECT +public: + CWizardEngine(QObject* parent = NULL); + ~CWizardEngine(); + + QVariantMap GetReport() { return m_Report; } + + bool ApplyShadowChanges(); + + QSharedPointer MakeShadow(const QSharedPointer& pIni); + void AddShadow(const QSharedPointer& pIni); + void SetApplyShadow(const QString& OriginalName, bool bApply = true); + bool IsNoAppliedShadow(const QString& OriginalName); + +protected: + friend class JWizardObject; + + virtual void init(); + + virtual void SetState(EState state, const QString& Text = ""); + + QVariantMap m_Report; + + struct SBoxShadow { + SBoxShadow() : iApplyChanges(0) {} + QSharedPointer pShadow; + QSharedPointer pOriginal; + int iApplyChanges; + }; + + QMap m_Shadows; +}; + diff --git a/SandboxiePlus/SandMan/Engine/BoxObject.cpp b/SandboxiePlus/SandMan/Engine/BoxObject.cpp new file mode 100644 index 00000000..9cb5837d --- /dev/null +++ b/SandboxiePlus/SandMan/Engine/BoxObject.cpp @@ -0,0 +1,106 @@ +#include "stdafx.h" +#include "BoxObject.h" +#include "../SandMan.h" +#include "../Views/SbieView.h" +#include "../Windows/SettingsWindow.h" +#include "../QSbieAPI/SbieUtils.h" + + +quint32 CBoxObject::StartTask(const QString& Command, const QVariantMap& Options) +{ + SB_RESULT(quint32) result = theGUI->RunStart(getName(), Command, Options["elevalted"].toBool(), Options["directory"].toString()); + return result.IsError() ? -1 : result.GetValue(); +} + +QVariantList CBoxObject::ListTasks() +{ + QVariantList List; + foreach(const CBoxedProcessPtr& pProcess, m_pIni.objectCast()->GetProcessList()) + List.append(TaskInfo(pProcess)); + return List; +} + +bool CBoxObject::StopTask(quint32 pid) +{ + CBoxedProcessPtr pProcess = m_pIni.objectCast()->GetProcessList().value(pid); + if (!pProcess) + return false; + SB_STATUS Status = pProcess->Terminate(); + return !Status.IsError(); +} + +bool CBoxObject::Terminate() +{ + SB_STATUS Status = m_pIni.objectCast()->TerminateAll(); + return !Status.IsError(); +} + +QVariantMap CBoxObject::TaskInfo(quint32 pid) +{ + return TaskInfo(m_pIni.objectCast()->GetProcessList().value(pid)); +} + +QVariantMap CBoxObject::TaskInfo(const CBoxedProcessPtr& pProcess) +{ + QVariantMap Info; + Info["pid"] = pProcess->GetProcessId(); + Info["parentId"] = pProcess->GetParendPID(); + Info["name"] = pProcess->GetProcessName(); + Info["commandline"] = pProcess->GetCommandLine(); + Info["fileName"] = pProcess->GetFileName(); + Info["timeStamp"] = pProcess->GetTimeStamp(); + Info["flags"] = pProcess->GetProcessFlags(); + Info["type"] = pProcess->GetImageType(); + if (pProcess->IsTerminated()) { + Info["isRunning"] = false; + Info["returnCode"] = pProcess->GetReturnCode(); + } else + Info["isRunning"] = true; + return Info; +} + +bool CBoxObject::DeleteContent() +{ + SB_STATUS Status = theGUI->DeleteBoxContent(m_pIni.objectCast(), CSandMan::eCleanUp); + return !Status.IsError(); +} + +bool CBoxObject::RemoveSandbox() +{ + SB_STATUS Status = theGUI->DeleteBoxContent(m_pIni.objectCast(), CSandMan::eForDelete); + if (Status.GetMsgCode() == SB_Canceled) + return false; + Status = m_pIni.objectCast()->RemoveBox(); + return !Status.IsError(); +} + +bool CBoxObject::MakeShortcut(const QString& Target, const QVariantMap& Options) +{ + QString Location = Options["location"].toString(); + QStandardPaths::StandardLocation location = (QStandardPaths::StandardLocation)-1; + if (Location.compare("desktop", Qt::CaseInsensitive) == 0) + location = QStandardPaths::DesktopLocation; + else if (Location.compare("startmenu", Qt::CaseInsensitive) == 0) + location = QStandardPaths::ApplicationsLocation; + else if (Location.compare("documents", Qt::CaseInsensitive) == 0) + location = QStandardPaths::DocumentsLocation; + if (location != -1) { + QString Name = Options["name"].toString(); + QString Path = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation).replace("/", "\\"); + if (Target == "default_browser") + Path += "\\" + CSettingsWindow::tr("Sandboxed Web Browser") + ".lnk"; + else if (!Name.isEmpty()) + Path += "\\" + Name + ".lnk"; + else + return false; + QString StartExe = theAPI->GetSbiePath() + "\\SandMan.exe"; + return CSbieUtils::CreateShortcut(StartExe, Path, "", getName(), Target); + } + return CSbieView::CreateShortcut(Target, getName(), Options["iconPath"].toString(), Options["iconIndex"].toInt(), Options["workDir"].toString()); +} + +void CSBoxObject::ApplyChanges(bool bApply) +{ + CWizardEngine* pEngine = qobject_cast(parent()); + pEngine->SetApplyShadow(m_OriginalName, bApply); +} \ No newline at end of file diff --git a/SandboxiePlus/SandMan/Engine/BoxObject.h b/SandboxiePlus/SandMan/Engine/BoxObject.h new file mode 100644 index 00000000..9663b49d --- /dev/null +++ b/SandboxiePlus/SandMan/Engine/BoxObject.h @@ -0,0 +1,134 @@ +#pragma once +#include "IniObject.h" + +class CBoxObject : public CIniObject +{ + Q_OBJECT +public: + CBoxObject(const QSharedPointer& pBox, QObject* parent) + : CIniObject(pBox, parent) {} + +public slots: + + QString GetFileRoot() { return m_pIni.objectCast()->GetFileRoot(); } + QString GetRegRoot() { return m_pIni.objectCast()->GetRegRoot(); } + + quint32 StartTask(const QString& Command, const QVariantMap& Options); + QVariantList ListTasks(); + bool StopTask(quint32 pid); + bool Terminate(); + QVariantMap TaskInfo(quint32 pid); + + bool DeleteContent(); + + bool RemoveSandbox(); + + + bool MakeShortcut(const QString& Target, const QVariantMap& Options); + +protected: + QVariantMap TaskInfo(const CBoxedProcessPtr& pProcess); + +}; + + +class CSBoxObject : public CBoxObject +{ + Q_OBJECT +public: + CSBoxObject(const QSharedPointer& pBox, const QString& OriginalName, QObject* parent) + : CBoxObject(pBox, parent), m_OriginalName(OriginalName) { } + +public slots: + + void ApplyChanges(bool bApply); + +protected: + QString m_OriginalName; +}; + +////////////////////////////////////////////////////////////////////////////////////////// +// JBoxObject +// + +class JBoxObject : public JIniObject +{ + Q_OBJECT +public: + JBoxObject(CBoxObject* pObject, CBoxEngine* pEngine) + : JIniObject(pObject, pEngine) {} + ~JBoxObject() { QMetaObject::invokeMethod(m_pObject, "deleteLater"); } + + Q_INVOKABLE QJSValue getFileRoot(){ + QString Text; + QMetaObject::invokeMethod(m_pObject, "GetFileRoot", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, Text)); + return Text; + } + Q_INVOKABLE QJSValue getRegRoot(){ + QString Text; + QMetaObject::invokeMethod(m_pObject, "GetRegRoot", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, Text)); + return Text; + } + + Q_INVOKABLE QJSValue startTask(const QString& Command, const QVariantMap& Options = QVariantMap()){ + quint32 pid; + QMetaObject::invokeMethod(m_pObject, "StartTask", Qt::BlockingQueuedConnection, Q_RETURN_ARG(quint32, pid), Q_ARG(QString, Command), Q_ARG(const QVariantMap&, Options)); + return pid; + } + Q_INVOKABLE QJSValue listTasks(){ + QVariantList List; + QMetaObject::invokeMethod(m_pObject, "ListTasks", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QVariantList, List)); + return m_pEngine->m_pEngine->toScriptValue(List); + } + Q_INVOKABLE QJSValue stopTask(quint32 pid){ + bool Success; + QMetaObject::invokeMethod(m_pObject, "StopTask", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, Success), Q_RETURN_ARG(quint32, pid)); + return Success; + } + Q_INVOKABLE QJSValue terminate(){ + bool Success; + QMetaObject::invokeMethod(m_pObject, "Terminate", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, Success)); + return Success; + } + Q_INVOKABLE QJSValue taskInfo(quint32 pid) { + QVariantMap Info; + QMetaObject::invokeMethod(m_pObject, "TaskInfo", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QVariantMap, Info)); + return m_pEngine->m_pEngine->toScriptValue(Info); + } + + Q_INVOKABLE QJSValue deleteContent() { + bool Success; + QMetaObject::invokeMethod(m_pObject, "DeleteContent", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, Success)); + return Success; + } + + Q_INVOKABLE QJSValue removeSandbox() { + bool Success; + QMetaObject::invokeMethod(m_pObject, "RemoveSandbox", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, Success)); + return Success; + } + + + Q_INVOKABLE QJSValue makeShortcut(const QString& Target, const QVariantMap& Options = QVariantMap()) { + bool Success; + QMetaObject::invokeMethod(m_pObject, "MakeShortcut", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, Success), Q_ARG(QString, Target), Q_ARG(const QVariantMap&, Options)); + return Success; + } + +}; + +////////////////////////////////////////////////////////////////////////////////////////// +// JSBoxObject - Box Shadow Object +// + +class JSBoxObject : public JBoxObject +{ + Q_OBJECT +public: + JSBoxObject(CBoxObject* pObject, CBoxEngine* pEngine) + : JBoxObject(pObject, pEngine) {} + + Q_INVOKABLE void applyChanges(bool bApply = true) { + QMetaObject::invokeMethod(m_pObject, "ApplyChanges", Qt::BlockingQueuedConnection, Q_ARG(bool, bApply)); + } +}; diff --git a/SandboxiePlus/SandMan/Engine/IniObject.cpp b/SandboxiePlus/SandMan/Engine/IniObject.cpp new file mode 100644 index 00000000..7558f0e7 --- /dev/null +++ b/SandboxiePlus/SandMan/Engine/IniObject.cpp @@ -0,0 +1,69 @@ +#include "stdafx.h" +#include "IniObject.h" +#include "../SandMan.h" +#include "../Views/SbieView.h" + +QString CIniObject::getName() const { + if (!m_pIni) return ""; // no m_pIni means plus config + return m_pIni->GetName(); +} + +QVariantMap CIniObject::getIniSection(const QVariantMap& Options) { + if (!m_pIni) return QVariantMap(); + + QMultiMap Map; + auto Section = m_pIni->GetIniSection(0,m_WithTemplate || Options["withTemplate"].toBool()); + for (auto I = Section.begin(); I != Section.end(); ++I) + Map.insert(I->first, I->second); + + QVariantMap Data; + foreach(const QString & Key, Map.uniqueKeys()) + Data[Key] = Map.values(Key); + return Data; +} + +bool CIniObject::setIniValue(const QString& Setting, const QVariant& Value) { + if (!m_pIni) return theConf->SetValue(Setting, Value); + return !m_pIni->SetText(Setting, Value.toString()).IsError(); +} + +bool CIniObject::insertIniValue(const QString& Setting, const QString& Value) { + if (!m_pIni) return false; + return !m_pIni->InsertText(Setting, Value).IsError(); +} + +bool CIniObject::appendIniValue(const QString& Setting, const QString& Value) { + if (!m_pIni) return false; + return !m_pIni->AppendText(Setting, Value).IsError(); +} + +bool CIniObject::delIniValue(const QString& Setting, const QString& Value) { + if (!m_pIni) { theConf->DelValue(Setting); return true; } + return !m_pIni->DelValue(Setting, Value).IsError(); +} + +QStringList CIniObject::getIniValues(const QString& Setting, const QVariantMap& Options) { + if (!m_pIni) return QStringList(); + return m_pIni->GetTextList(Setting, m_WithTemplate || Options["withTemplate"].toBool(), Options["expand"].toBool(), Options["withGlobal"].toBool()); +} + +QVariant CIniObject::getIniValue(const QString& Setting, const QVariantMap& Options) { + if (!m_pIni) return theConf->GetValue(Setting); + if(Options["type"] == "bool") + return m_pIni->GetBool(Setting, Options["default"].toBool(), Options["withGlobal"].toBool(), m_WithTemplate || Options["withTemplate"].toBool()); + QString Text = m_pIni->GetText(Setting, Options["default"].toString(), Options["withGlobal"].toBool(), !Options["expand"].toBool(), m_WithTemplate || Options["withTemplate"].toBool()); + if (Options["type"] == "number") + return Text.toLongLong(); + return Text; +} + +bool CIniObject::removeSection() { + SB_STATUS Status = m_pIni->RemoveSection(); + return !Status.IsError(); +} + + +void CSTmplObject::ApplyChanges(bool bApply) { + CWizardEngine* pEngine = qobject_cast(parent()); + pEngine->SetApplyShadow(m_OriginalName, bApply); +} \ No newline at end of file diff --git a/SandboxiePlus/SandMan/Engine/IniObject.h b/SandboxiePlus/SandMan/Engine/IniObject.h new file mode 100644 index 00000000..0a5ef26d --- /dev/null +++ b/SandboxiePlus/SandMan/Engine/IniObject.h @@ -0,0 +1,147 @@ +#pragma once +#include "BoxEngine.h" +#include "../SbiePlusAPI.h" +#include "../../MiscHelpers/Common/Settings.h" + +class CIniObject : public QObject +{ + Q_OBJECT +public: + CIniObject(const QSharedPointer& pIni, bool WithTemplate, QObject* parent) : QObject(parent), m_pIni(pIni), m_WithTemplate(WithTemplate) {} + CIniObject(const QSharedPointer& pIni, QObject* parent) : CIniObject(pIni, false, parent) {} + +public slots: + + virtual QString getName() const; + + virtual QVariantMap getIniSection(const QVariantMap& Options = QVariantMap()); + + virtual bool setIniValue(const QString& Setting, const QVariant& Value); + virtual bool insertIniValue(const QString& Setting, const QString& Value); + virtual bool appendIniValue(const QString& Setting, const QString& Value); + virtual bool delIniValue(const QString& Setting, const QString& Value = ""); + virtual QStringList getIniValues(const QString& Setting, const QVariantMap& Options = QVariantMap()); + virtual QVariant getIniValue(const QString& Setting, const QVariantMap& Options = QVariantMap()); + + virtual bool removeSection(); + +protected: + QSharedPointer m_pIni; + bool m_WithTemplate; +}; + + +class CSTmplObject : public CIniObject +{ + Q_OBJECT +public: + CSTmplObject(const QSharedPointer& pIni, const QString& OriginalName, QObject* parent) + : CIniObject(pIni, parent), m_OriginalName(OriginalName) { } + +public slots: + + void ApplyChanges(bool bApply); + +protected: + QString m_OriginalName; +}; + +////////////////////////////////////////////////////////////////////////////////////////// +// JIniObject +// + +class JIniObject : public QObject +{ + Q_OBJECT +public: + JIniObject(CIniObject* pObject, CBoxEngine* pEngine) + : m_pObject(pObject), m_pEngine(pEngine) {} + ~JIniObject() { QMetaObject::invokeMethod(m_pObject, "deleteLater"); } + + Q_INVOKABLE virtual QJSValue getName() const { + QString Name; + QMetaObject::invokeMethod(m_pObject, "getName", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, Name)); + return Name; + } + + Q_INVOKABLE virtual QJSValue getIniSection(const QVariantMap& Options = QVariantMap()) { + QVariantMap Data; + QMetaObject::invokeMethod(m_pObject, "getIniSection", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QVariantMap, Data), Q_ARG(const QVariantMap&, Options)); + return m_pEngine->m_pEngine->toScriptValue(Data); + } + + Q_INVOKABLE virtual bool setIniValue(const QString& Setting, const QVariant& Value) { + bool Success; + QMetaObject::invokeMethod(m_pObject, "setIniValue", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, Success), Q_ARG(QString, Setting), Q_ARG(QVariant, Value)); + return Success; + } + Q_INVOKABLE virtual bool insertIniValue(const QString& Setting, const QString& Value) { + bool Success; + QMetaObject::invokeMethod(m_pObject, "insertIniValue", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, Success), Q_ARG(QString, Setting), Q_ARG(QString, Value)); + return Success; + } + Q_INVOKABLE virtual bool appendIniValue(const QString& Setting, const QString& Value) { + bool Success; + QMetaObject::invokeMethod(m_pObject, "appendIniValue", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, Success), Q_ARG(QString, Setting), Q_ARG(QString, Value)); + return Success; + } + Q_INVOKABLE virtual bool delIniValue(const QString& Setting, const QString& Value = "") { + bool Success; + QMetaObject::invokeMethod(m_pObject, "delIniValue", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, Success), Q_ARG(QString, Setting), Q_ARG(QString, Value)); + return Success; + } + Q_INVOKABLE virtual QJSValue getIniValues(const QString& Setting, const QVariantMap& Options = QVariantMap()) { + QStringList List; + QMetaObject::invokeMethod(m_pObject, "getIniValues", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QStringList, List), Q_ARG(QString, Setting), Q_ARG(const QVariantMap&, Options)); + return m_pEngine->m_pEngine->toScriptValue(List); + } + Q_INVOKABLE virtual QJSValue getIniValue(const QString& Setting, const QVariantMap& Options = QVariantMap()) { + QVariant Value; + QMetaObject::invokeMethod(m_pObject, "getIniValue", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QVariant, Value), Q_ARG(QString, Setting), Q_ARG(const QVariantMap&, Options)); + return m_pEngine->m_pEngine->toScriptValue(Value); + } + + Q_INVOKABLE virtual bool removeSection() { + bool Success; + QMetaObject::invokeMethod(m_pObject, "removeSection", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, Success)); + return Success; + } + +protected: + CBoxEngine* m_pEngine; + CIniObject* m_pObject; +}; + +////////////////////////////////////////////////////////////////////////////////////////// +// JTmplObject +// + +class JTmplObject : public JIniObject +{ + Q_OBJECT +public: + JTmplObject(CIniObject* pObject, CBoxEngine* pEngine) + : JIniObject(pObject, pEngine) {} + + Q_INVOKABLE virtual QJSValue getName() const { + QString Name; + QMetaObject::invokeMethod(m_pObject, "GetName", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, Name)); + return Name.mid(9); + } +}; + +////////////////////////////////////////////////////////////////////////////////////////// +// JSTmplObject +// + +class JSTmplObject : public JTmplObject +{ + Q_OBJECT +public: + JSTmplObject(CIniObject* pObject, CBoxEngine* pEngine) + : JTmplObject(pObject, pEngine) {} + + Q_INVOKABLE void applyChanges(bool bApply = true) { + QMetaObject::invokeMethod(m_pObject, "ApplyChanges", Qt::BlockingQueuedConnection, Q_ARG(bool, bApply)); + } +}; \ No newline at end of file diff --git a/SandboxiePlus/SandMan/Engine/JSEngineExt.cpp b/SandboxiePlus/SandMan/Engine/JSEngineExt.cpp new file mode 100644 index 00000000..d30f5b8d --- /dev/null +++ b/SandboxiePlus/SandMan/Engine/JSEngineExt.cpp @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** Copyright (C) 2023 David Xanatos (xanasoft.com) All rights reserved. +** Contact: XanatosDavid@gmil.com +** +** +** To use the V4ScriptTools in a commercial project, you must obtain +** an appropriate business use license. +** +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** +** +****************************************************************************/ +#include "stdafx.h" + +#include "JSEngineExt.h" + +#include +#include +#include +#include +#include +#include +#include + +static QMutex g_engineMutex; +static QMap g_engineMap; + +CJSEngineExt* CJSEngineExt::getEngineByHandle(void* handle) +{ + QMutexLocker locker(&g_engineMutex); + return g_engineMap.value(handle); +} + +static QV4::ReturnedValue printCall(const QV4::FunctionObject* b, const QV4::Value* v, const QV4::Value* argv, int argc); +static QV4::ReturnedValue debuggerCall(const QV4::FunctionObject* b, const QV4::Value* v, const QV4::Value* argv, int argc); +static QV4::ReturnedValue evalCall(const QV4::FunctionObject* b, const QV4::Value* v, const QV4::Value* argv, int argc); + +CJSEngineExt::CJSEngineExt(QObject* parent) + : QJSEngine(parent) +{ + QV4::Scope scope(handle()); + + // provide a print function to write to console + scope.engine->globalObject->defineDefaultProperty(QStringLiteral("print"), printCall); + // provide ability to invoke the debugger + scope.engine->globalObject->defineDefaultProperty(QStringLiteral("_debugger"), debuggerCall); + // overwrite the eval function with our own copy which traces the scripts + scope.engine->globalObject->defineDefaultProperty(QStringLiteral("eval"), evalCall); + + QMutexLocker locker(&g_engineMutex); + g_engineMap.insert(handle(), this); +} + +CJSEngineExt::~CJSEngineExt() +{ + QMutexLocker locker(&g_engineMutex); + g_engineMap.remove(handle()); +} + +QJSValue CJSEngineExt::evaluateScript(const QString& program, const QString& fileName, int lineNumber) +{ + QJSValue ret = QJSEngine::evaluate(program, trackScript(program, fileName, lineNumber), lineNumber); + emit evaluateFinished(ret); + return ret; +} + +QString CJSEngineExt::trackScript(const QString& program, const QString& fileName, int lineNumber) +{ + QString Name = QUrl(fileName).fileName(); + QString FileName = Name; + for (int i = 0; m_ScriptIDs.contains(FileName.toLower());) + FileName = Name + " (" + QString::number(++i) + ")"; + m_ScriptIDs.insert(FileName.toLower(), m_Scripts.count()); + m_Scripts.append(SScript{ FileName, lineNumber, program }); + return FileName; +} + +QV4::ReturnedValue printCall(const QV4::FunctionObject* b, const QV4::Value* v, const QV4::Value* argv, int argc) +{ + QV4::Scope scope(b); + QV4::ExecutionEngine* v4 = scope.engine; + + QString Result; + for (int i = 0; i < argc; i++) { + if (i > 0) Result.append(" "); + Result.append(argv[i].toQStringNoThrow()); + } + + QMutexLocker locker(&g_engineMutex); + emit g_engineMap.value(v4)->printTrace(Result); + + return QV4::Encode::undefined(); +} + +QV4::ReturnedValue debuggerCall(const QV4::FunctionObject* b, const QV4::Value* v, const QV4::Value* argv, int argc) +{ + QV4::Scope scope(b); + QV4::ExecutionEngine* v4 = scope.engine; + + QMutexLocker locker(&g_engineMutex); + emit g_engineMap.value(v4)->invokeDebugger(); + + return QV4::Encode::undefined(); +} + +QV4::ReturnedValue evalCall(const QV4::FunctionObject* b, const QV4::Value* v, const QV4::Value* argv, int argc) +{ + // not implemented + + return QV4::Encode::undefined(); +} \ No newline at end of file diff --git a/SandboxiePlus/SandMan/Engine/JSEngineExt.h b/SandboxiePlus/SandMan/Engine/JSEngineExt.h new file mode 100644 index 00000000..bfba2d5d --- /dev/null +++ b/SandboxiePlus/SandMan/Engine/JSEngineExt.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2023 David Xanatos (xanasoft.com) All rights reserved. +** Contact: XanatosDavid@gmil.com +** +** +** To use the V4ScriptTools in a commercial project, you must obtain +** an appropriate business use license. +** +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** +** +****************************************************************************/ + +#ifndef CJSENGINEEXT_H +#define CJSENGINEEXT_H + +#include +#include + +#include "V4ScriptDebuggerApi.h" + +class CJSEngineExt : public QJSEngine, public CV4EngineItf +{ + Q_OBJECT +public: + CJSEngineExt(QObject* parent = NULL); + ~CJSEngineExt(); + + QJSEngine* self() { return this; } + + Q_INVOKABLE QJSValue evaluateScript(const QString& program, const QString& fileName, int lineNumber = 1); + + int getScriptCount() const { return m_Scripts.count(); } + QString getScriptName(qint64 scriptId) const { if (scriptId < m_Scripts.size()) return m_Scripts[scriptId].Name; return QString(); } + QString getScriptSource(qint64 scriptId) const { if (scriptId < m_Scripts.size()) return m_Scripts[scriptId].Source; return QString(); } + int getScriptLineNumber(qint64 scriptId) const { if (scriptId < m_Scripts.size()) return m_Scripts[scriptId].LineNumber; return -1; } + qint64 getScriptId(const QString& fileName) const { return m_ScriptIDs.value(fileName.toLower()); } + + QString trackScript(const QString& program, const QString& fileName, int lineNumber = 1); + + static CJSEngineExt* getEngineByHandle(void* handle); + +signals: + void evaluateFinished(const QJSValue& ret); + void printTrace(const QString& Message); + void invokeDebugger(); + +protected: + struct SScript + { + QString Name; + int LineNumber = 0; + QString Source; + }; + QList m_Scripts; + QMap m_ScriptIDs; + +private: + QJSValue evaluate(const QString& program, const QString& fileName = QString(), int lineNumber = 1) { return QJSValue(); } // dont use this, use evaluateScript instead +}; + +#endif \ No newline at end of file diff --git a/SandboxiePlus/SandMan/Engine/SbieObject.cpp b/SandboxiePlus/SandMan/Engine/SbieObject.cpp new file mode 100644 index 00000000..324bb43b --- /dev/null +++ b/SandboxiePlus/SandMan/Engine/SbieObject.cpp @@ -0,0 +1,212 @@ +#include "stdafx.h" +#include "SbieObject.h" +#include "../SandMan.h" +#include "../Views/SbieView.h" +#include "../Windows/SettingsWindow.h" +#include "../QSbieAPI/SbieUtils.h" + +QJSValue JSbieObject::getVersion() +{ + return CSandMan::GetVersion(); +} + +CBoxObject* CSbieObject::GetBox(const QString& Name) +{ + if (!theAPI->IsConnected()) + return NULL; + + CSandBoxPtr pBox = theAPI->GetBoxByName(Name); + if (!pBox) + return NULL; + CBoxEngine* pEngine = qobject_cast(parent()); + if(pEngine) + emit pEngine->BoxUsed(pBox); + if (CWizardEngine* pEngine = qobject_cast(parent())) { + QSharedPointer pShadow = pEngine->MakeShadow(pBox); + return new CSBoxObject(pShadow, pBox->GetName(), parent()); + } + return new CBoxObject(pBox, parent()); +} + +QStringList CSbieObject::ListBoxes() +{ + QStringList List; + QMap Boxes = theAPI->GetAllBoxes(); + foreach(const CSandBoxPtr& pBox, Boxes) + List.append(pBox->GetName()); + return List; +} + +CBoxObject* CSbieObject::NewBox(const QString& Name) +{ + if (!theAPI->IsConnected()) + return NULL; + + QString BoxName = theAPI->MkNewName(Name); + SB_STATUS Status = theAPI->CreateBox(BoxName, true); + if (Status.IsError()) + return NULL; + + CSandBoxPtr pBox = theAPI->GetBoxByName(BoxName); + if (!pBox) + return NULL; + CBoxEngine* pEngine = qobject_cast(parent()); + if(pEngine) + emit pEngine->BoxUsed(pBox); + if (CWizardEngine* pEngine = qobject_cast(parent())) { + pEngine->AddShadow(pBox); + return new CSBoxObject(pBox, pBox->GetName(), parent()); + } + return new CBoxObject(pBox, parent()); +} + +CIniObject* CSbieObject::GetTemplate(const QString& Name) +{ + if (!theAPI->IsConnected()) + return NULL; + QSharedPointer pTemplate = QSharedPointer(new CSbieIni("Template_" + Name, theAPI)); + if (Name.left(6) == "Local_") { + if (CWizardEngine* pEngine = qobject_cast(parent())) { + QSharedPointer pShadow = pEngine->MakeShadow(pTemplate); + return new CSTmplObject(pShadow, pTemplate->GetName(), parent()); + } + } + return new CIniObject(pTemplate, true, parent()); +} + +QStringList CSbieObject::ListTemplates() +{ + QStringList List; + for (int index = 0; ; index++) + { + QString Name = theAPI->SbieIniGet2("", "", index, false, true, true); + if (Name.isNull()) + break; + + if (Name.left(9).compare("Template_", Qt::CaseInsensitive) != 0) + continue; + + List.append(Name.mid(9)); + } + return List; +} + +CIniObject* CSbieObject::NewTemplate(const QString& Name) +{ + if (!theAPI->IsConnected()) + return NULL; + QSharedPointer pTemplate = QSharedPointer(new CSbieIni("Template_" + Name, theAPI)); + pTemplate->SetText("Tmpl.Title", Name); + pTemplate->SetText("Tmpl.Class", "Local"); + if (CWizardEngine* pEngine = qobject_cast(parent())) { + pEngine->AddShadow(pTemplate); + return new CSTmplObject(pTemplate, pTemplate->GetName(), parent()); + } + return new CIniObject(pTemplate, parent()); +} + +//CIniObject* CSbieObject::GetSection(const QString& Name) +//{ +// if (!theAPI->IsConnected()) +// return NULL; +// QSharedPointer pTemplate = QSharedPointer(new CSbieIni(Name, theAPI)); +// return pTemplate ? new CIniObject(pTemplate, parent()) : NULL; +//} + +CIniObject* CSbieObject::GetGlobal() +{ + if (!theAPI->IsConnected()) + return NULL; + return new CIniObject(theAPI->GetGlobalSettings(), parent()); +} + +CIniObject* CSbieObject::GetConf() +{ + return new CIniObject(NULL, parent()); +} + + +bool CSbieObject::SetupTrace(const QVariantMap& Options) +{ + SB_STATUS Status = theAPI->EnableMonitor(true); + return !Status.IsError(); +} + +QVariantList CSbieObject::ReadTrace(const QVariantMap& Options) +{ + int Start = Options["start"].toInt(); + int Count = Options["count"].toInt(); + + quint32 FilterPid = Options["pid"].toUInt(); + quint32 FilterTid = Options["tid"].toUInt(); + //QList FilterTypes; + void* pCurrentBox = Options.contains("box") ? theAPI->GetBoxByName(Options["box"].toString()).data() : 0; + + QVariantList List; + + const QVector &ResourceLog = theAPI->GetTrace(); + for (int i = Start; i < ResourceLog.count() && (!Count || Count > ResourceLog.count()); i++) + { + const CTraceEntryPtr& pEntry = ResourceLog.at(i); + + if (pCurrentBox != NULL && pCurrentBox != pEntry->GetBoxPtr()) + continue; + + if (FilterPid != 0 && FilterPid != pEntry->GetProcessId()) + continue; + + if (FilterTid != 0 && FilterTid != pEntry->GetThreadId()) + continue; + + //if (!FilterTypes.isEmpty() && !FilterTypes.contains(pEntry->GetType())) + // continue; + + QVariantMap Entry; + Entry["timeStamp"] = pEntry->GetTimeStamp(); + Entry["process"] = pEntry->GetProcessName(); + Entry["pid"] = pEntry->GetProcessId(); + Entry["tid"] = pEntry->GetThreadId(); + Entry["type"] = pEntry->GetTypeStr(); + Entry["status"] = pEntry->GetStautsStr(); + Entry["name"] = pEntry->GetName(); + Entry["message"] = pEntry->GetMessage(); + List.append(Entry); + } + + return List; +} + +void CSbieObject::CleanUp(const QVariantMap& Options) +{ + theAPI->UpdateProcesses(0, theGUI->ShowAllSessions()); +} + +void CSbieObject::ShellInstall(const QVariantMap& Options) +{ + CSettingsWindow::AddContextMenu(Options["legacy"].toBool()); + if (Options["runUnBoxed"].toBool()) { + CSbieUtils::AddContextMenu2(QApplication::applicationDirPath().replace("/", "\\") + "\\Start.exe", + tr("Run &Un-Sandboxed"), + QApplication::applicationDirPath().replace("/", "\\") + "\\Start.exe"); + } +} + +void CSbieObject::ShellRemove() +{ + CSettingsWindow::RemoveContextMenu(); + CSbieUtils::RemoveContextMenu2(); +} + +void CSbieObject::LogMessage(const QVariant& Message, bool bNotify) +{ + if (Message.type() == QVariant::Map) { + QVariantMap Data = Message.toMap(); + theGUI->OnLogSbieMessage(Data["sbiemsg"].toInt(), Data["params"].toStringList(), 4); + } else + theGUI->OnLogMessage(Message.toString(), bNotify); +} + +bool JSbieObject::isCertValid() +{ + return g_CertInfo.valid; +} \ No newline at end of file diff --git a/SandboxiePlus/SandMan/Engine/SbieObject.h b/SandboxiePlus/SandMan/Engine/SbieObject.h new file mode 100644 index 00000000..4e3aca93 --- /dev/null +++ b/SandboxiePlus/SandMan/Engine/SbieObject.h @@ -0,0 +1,161 @@ +#pragma once +#include "BoxEngine.h" +#include "BoxObject.h" + +class CSbieObject : public QObject +{ + Q_OBJECT +public: + CSbieObject(QObject* parent) : QObject(parent) {} + +public slots: + CBoxObject* GetBox(const QString& Name); + QStringList ListBoxes(); + CBoxObject* NewBox(const QString& Name); + + CIniObject* GetTemplate(const QString& Name); + QStringList ListTemplates(); + CIniObject* NewTemplate(const QString& Name); + + //CIniObject* GetSection(const QString& Name); + + CIniObject* GetGlobal(); + CIniObject* GetConf(); + + bool SetupTrace(const QVariantMap& Options); + QVariantList ReadTrace(const QVariantMap& Options); + + void CleanUp(const QVariantMap& Options); + + void ShellInstall(const QVariantMap& Options); + void ShellRemove(); + + void LogMessage(const QVariant& Message, bool bNotify); +}; + +////////////////////////////////////////////////////////////////////////////////////////// +// JSbieObject +// + +class JSbieObject : public QObject +{ + Q_OBJECT +public: + JSbieObject(CSbieObject* pObject, CBoxEngine* pEngine) + : m_pObject(pObject), m_pEngine(pEngine) {} + ~JSbieObject() { QMetaObject::invokeMethod(m_pObject, "deleteLater"); } + + Q_INVOKABLE QJSValue getVersion(); + + static QJSValue makeShadow(QJSValueList args) { + QString result = "Hello, "; + + // Access arguments passed from JavaScript + if (args.length() > 0 && args[0].isString()) { + QString name = args[0].toString(); + result += name; + } + + return QJSValue(result); + } + + Q_INVOKABLE QJSValue getBox(const QString& Name) { + CBoxObject* pObj = NULL; + QMetaObject::invokeMethod(m_pObject, "GetBox", Qt::BlockingQueuedConnection, Q_RETURN_ARG(CBoxObject*, pObj), Q_ARG(QString, Name)); + if(!pObj) + return QJSValue(QJSValue::NullValue); + if(m_pEngine->inherits("CWizardEngine")) + return m_pEngine->m_pEngine->newQObject(new JSBoxObject(pObj, m_pEngine)); + return m_pEngine->m_pEngine->newQObject(new JBoxObject(pObj, m_pEngine)); + + } + Q_INVOKABLE QJSValue listBoxes() { + QStringList List; + QMetaObject::invokeMethod(m_pObject, "ListBoxes", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QStringList, List)); + return m_pEngine->m_pEngine->toScriptValue(List); + } + Q_INVOKABLE QJSValue newBox(const QString& Name) { + CBoxObject* pObj = NULL; + QMetaObject::invokeMethod(m_pObject, "NewBox", Qt::BlockingQueuedConnection, Q_RETURN_ARG(CBoxObject*, pObj), Q_ARG(QString, Name)); + return pObj ? m_pEngine->m_pEngine->newQObject(new JBoxObject(pObj, m_pEngine)) : QJSValue(QJSValue::NullValue); + } + + Q_INVOKABLE QJSValue getTemplate(const QString& Name) { + if (Name.left(6) != "Local_") { + // shortcut for non user defined templates + QSharedPointer pTemplate = QSharedPointer(new CSbieIni("Template_" + Name, theAPI)); + return m_pEngine->m_pEngine->newQObject(new CIniObject(pTemplate, true, m_pEngine->m_pEngine)); + } + CIniObject* pObj = NULL; + QMetaObject::invokeMethod(m_pObject, "GetTemplate", Qt::BlockingQueuedConnection, Q_RETURN_ARG(CIniObject*, pObj), Q_ARG(QString, Name)); + if(!pObj) + return QJSValue::NullValue; + if(m_pEngine->inherits("CWizardEngine")) + return m_pEngine->m_pEngine->newQObject(new JSTmplObject(pObj, m_pEngine)); + return m_pEngine->m_pEngine->newQObject(new JTmplObject(pObj, m_pEngine)); + } + Q_INVOKABLE QJSValue listTemplates() { + QStringList List; + QMetaObject::invokeMethod(m_pObject, "ListTemplates", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QStringList, List)); + return m_pEngine->m_pEngine->toScriptValue(List); + } + Q_INVOKABLE QJSValue newTemplate(const QString& Name) { + CIniObject* pObj = NULL; + QMetaObject::invokeMethod(m_pObject, "NewTemplate", Qt::BlockingQueuedConnection, Q_RETURN_ARG(CIniObject*, pObj), Q_ARG(QString, Name)); + return pObj ? m_pEngine->m_pEngine->newQObject(new JTmplObject(pObj, m_pEngine)) : QJSValue(QJSValue::NullValue); + } + + //Q_INVOKABLE QJSValue GetSection(const QString& Name) { + // CIniObject* pObj = NULL; + // QMetaObject::invokeMethod(m_pObject, "getSection", Qt::BlockingQueuedConnection, Q_RETURN_ARG(CIniObject*, pObj), Q_ARG(QString, Name)); + // return pObj ? m_pEngine->m_pEngine->newQObject(new JIniObject(pObj, m_pEngine)) : QJSValue(QJSValue::NullValue); + //} + + Q_INVOKABLE QJSValue getGlobal() { + CIniObject* pObj = NULL; + QMetaObject::invokeMethod(m_pObject, "GetGlobal", Qt::BlockingQueuedConnection, Q_RETURN_ARG(CIniObject*, pObj)); + return pObj ? m_pEngine->m_pEngine->newQObject(new JIniObject(pObj, m_pEngine)) : QJSValue(QJSValue::NullValue); + } + Q_INVOKABLE QJSValue getConf() { + CIniObject* pObj = NULL; + QMetaObject::invokeMethod(m_pObject, "GetConf", Qt::BlockingQueuedConnection, Q_RETURN_ARG(CIniObject*, pObj)); + return pObj ? m_pEngine->m_pEngine->newQObject(new JIniObject(pObj, m_pEngine)) : QJSValue(QJSValue::NullValue); + } + + + Q_INVOKABLE QJSValue setupTrace(const QVariantMap& Options = QVariantMap()) { + bool Success; + QMetaObject::invokeMethod(m_pObject, "SetupTrace", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, Success), Q_ARG(const QVariantMap&, Options)); + return Success; + } + Q_INVOKABLE QJSValue readTrace(const QVariantMap& Options = QVariantMap()) { + QVariantList List; + QMetaObject::invokeMethod(m_pObject, "ReadTrace", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QVariantList, List), Q_ARG(const QVariantMap&, Options)); + return m_pEngine->m_pEngine->toScriptValue(List); + } + + + Q_INVOKABLE void cleanUp(const QVariantMap& Options = QVariantMap()) { + QMetaObject::invokeMethod(m_pObject, "CleanUp", Qt::BlockingQueuedConnection, Q_ARG(const QVariantMap&, Options)); + } + + + Q_INVOKABLE void shellInstall(const QVariantMap& Options = QVariantMap()) { + QMetaObject::invokeMethod(m_pObject, "ShellInstall", Qt::BlockingQueuedConnection, Q_ARG(const QVariantMap&, Options)); + } + + Q_INVOKABLE void shellRemove() { + QMetaObject::invokeMethod(m_pObject, "ShellRemove", Qt::BlockingQueuedConnection); + } + + + Q_INVOKABLE void logMessage(const QVariant& Message, bool bNotify = false) { + QMetaObject::invokeMethod(m_pObject, "LogMessage", Qt::BlockingQueuedConnection, Q_ARG(const QVariant&, Message), Q_ARG(bool, bNotify)); + } + + Q_INVOKABLE bool isCertValid(); + +protected: + CBoxEngine* m_pEngine; + CSbieObject* m_pObject; +}; \ No newline at end of file diff --git a/SandboxiePlus/SandMan/Engine/SysObject.cpp b/SandboxiePlus/SandMan/Engine/SysObject.cpp new file mode 100644 index 00000000..e8dfd866 --- /dev/null +++ b/SandboxiePlus/SandMan/Engine/SysObject.cpp @@ -0,0 +1,668 @@ +#include "stdafx.h" +#include "SysObject.h" +#include "../SandMan.h" +#include "../QSbieAPI/Sandboxie/SbieTemplates.h" + +#include "..\..\MiscHelpers\Common\Common.h" +#include "..\..\MiscHelpers\Common\OtherFunctions.h" + +#include +#define WIN32_NO_STATUS +typedef long NTSTATUS; +#include +//#include + +#include "..\..\Sandboxie\common\win32_ntddk.h" + +#define MAX_KEY_NAME 255 +#define MAX_VALUE_NAME 16383 +#define MAX_VALUE_DATA 1024000 + +#include +#include + +JSysObject::JSysObject(CBoxEngine* pEngine) + : m_pEngine(pEngine) +{ +} + +void JSysObject::log(const QString& line) +{ + m_pEngine->AppendLog(line); +} + +void JSysObject::sleep(qint64 ms) +{ + for (qint64 i = 0; i < ms && m_pEngine->TestRunning(); i += 10) + QThread::msleep(10); +} + + +// FS +HANDLE openFile(const QString& Path, bool bDir, bool bWrite = false) +{ + NTSTATUS status = STATUS_SUCCESS; + IO_STATUS_BLOCK Iosb; + + std::wstring path = Path.toStdWString(); + if (path.substr(0, 1) != L"\\") // not nt path + path = L"\\??\\" + path; // dos path + OBJECT_ATTRIBUTES objattrs; + UNICODE_STRING uni; + + RtlInitUnicodeString(&uni, path.c_str()); + InitializeObjectAttributes(&objattrs, &uni, OBJ_CASE_INSENSITIVE, NULL, NULL); + + HANDLE handle = NULL; + if (bWrite) + NtCreateFile(&handle, GENERIC_ALL | SYNCHRONIZE, &objattrs, &Iosb, NULL, 0, FILE_SHARE_READ, FILE_OPEN_IF, (bDir ? FILE_DIRECTORY_FILE : 0) | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); + else + NtOpenFile(&handle, GENERIC_READ | SYNCHRONIZE, &objattrs, &Iosb, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, (bDir ? FILE_DIRECTORY_FILE : 0) | FILE_SYNCHRONOUS_IO_NONALERT); + + return handle; +} + +QJSValue JSysObject::listDir(const QString& Path, const QStringList& filter, bool bSubDirs) +{ + QVariantList entries; + + HANDLE handle = openFile(Path, false); + if (handle && handle != INVALID_HANDLE_VALUE) { + + PFILE_BOTH_DIRECTORY_INFORMATION Info = (PFILE_BOTH_DIRECTORY_INFORMATION)malloc(PAGE_SIZE); + + for (NTSTATUS status = STATUS_SUCCESS ; status == STATUS_SUCCESS; ) + { + HANDLE Event; + NtCreateEvent(&Event, GENERIC_ALL, 0, NotificationEvent, FALSE); + IO_STATUS_BLOCK Iosb; + status = NtQueryDirectoryFile(handle, Event, 0, 0, &Iosb, Info, PAGE_SIZE, FileBothDirectoryInformation, TRUE, NULL, FALSE); + if (status == STATUS_PENDING){ + NtWaitForSingleObject(Event, TRUE, 0); + status = Iosb.Status; + } + NtClose(Event); + + if (!NT_SUCCESS(status)) { + if(status == STATUS_NO_MORE_FILES) + status = STATUS_SUCCESS; + break; + } + + QString FileName = QString::fromWCharArray(Info->FileName, Info->FileNameLength / sizeof(wchar_t)); + if (FileName == "." || FileName == "..") + continue; + + QVariantMap entry; + entry["isDir"] = (Info->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? 1 : 0; + entry["name"] = FileName; + entry["path"] = Path + (Path.right(1) != "\\" ? "\\" : "") + FileName; + entries.append(entry); + } + + free(Info); + + CloseHandle(handle); + } + + return m_pEngine->m_pEngine->toScriptValue(entries); +} + +QJSValue JSysObject::mkDir(const QString& Path) +{ + HANDLE handle = openFile(Path, true, true); + if (handle && handle != INVALID_HANDLE_VALUE) { + CloseHandle(handle); + return true; + } + return false; +} + +QJSValue JSysObject::remove(const QString& Path) +{ + std::wstring path = Path.toStdWString(); + if (path.substr(0, 1) != L"\\") // not nt path + path = L"\\??\\" + path; // dos path + OBJECT_ATTRIBUTES objattrs; + UNICODE_STRING uni; + + RtlInitUnicodeString(&uni, path.c_str()); + InitializeObjectAttributes(&objattrs, &uni, OBJ_CASE_INSENSITIVE, NULL, NULL); + + return NT_SUCCESS(NtDeleteFile(&objattrs)); +} + +QJSValue JSysObject::exists(const QString& Path) +{ + HANDLE handle = openFile(Path, false); + if (handle && handle != INVALID_HANDLE_VALUE) { + CloseHandle(handle); + return true; + } + return false; +} + +QJSValue JSysObject::readFile(const QString& Path, quint64 pos, quint64 length) +{ + HANDLE handle = openFile(Path, false); + if (handle && handle != INVALID_HANDLE_VALUE) { + QByteArray Data; + + IO_STATUS_BLOCK Iosb; + if (length == -1) { + FILE_STANDARD_INFORMATION standardInfo; + if (NT_SUCCESS(NtQueryInformationFile(handle, &Iosb, &standardInfo, sizeof(standardInfo), FileStandardInformation))) { + length = standardInfo.EndOfFile.QuadPart; + } + } + + Data.resize(length); + LARGE_INTEGER offset; + offset.QuadPart = pos; + NtReadFile(handle, NULL, NULL, NULL, &Iosb, Data.data(), length, &offset, NULL); + + CloseHandle(handle); + return m_pEngine->m_pEngine->toScriptValue(Data); + + } + return QJSValue::NullValue; +} + +QJSValue JSysObject::writeFile(const QString& Path, const QByteArray& Data, quint64 pos) +{ + HANDLE handle = openFile(Path, false, true); + if (handle && handle != INVALID_HANDLE_VALUE) { + + IO_STATUS_BLOCK Iosb; + if (pos == -1) { // trim + FILE_END_OF_FILE_INFORMATION endOfFileInfo; + endOfFileInfo.EndOfFile.QuadPart = 0; + NtSetInformationFile(handle, &Iosb, &endOfFileInfo, sizeof(endOfFileInfo), FileEndOfFileInformation); + pos = 0; + } + + LARGE_INTEGER offset; + offset.QuadPart = pos; + NtWriteFile(handle, NULL, NULL, NULL, &Iosb, (PVOID)Data.data(), Data.size(), &offset, NULL); + + CloseHandle(handle); + return true; + } + return false; +} + +QJSValue JSysObject::getFileInfo(const QString& Path) +{ + QVariantMap data; + HANDLE handle = openFile(Path, false); + if (handle && handle != INVALID_HANDLE_VALUE) { + IO_STATUS_BLOCK Iosb; + FILE_STANDARD_INFORMATION standardInfo; + if (NT_SUCCESS(NtQueryInformationFile(handle, &Iosb, &standardInfo, sizeof(standardInfo), FileStandardInformation))) { + data["path"] = Path; + data["isDir"] = standardInfo.Directory; + data["size"] = standardInfo.EndOfFile.QuadPart; + } + CloseHandle(handle); + } + return m_pEngine->m_pEngine->toScriptValue(data); +} + + +// REG +HANDLE openRegKey(const QString& Key, bool bWrite = false) +{ + QString Path = Key; + if (Path.left(1) == "\\") + Path.remove(0, 1); + StrPair RootPath = Split2(Path, "\\"); + + HANDLE handle = NULL; + if (RootPath.first.left(5).compare("HKEY_", Qt::CaseInsensitive) == 0) + { + HKEY hRoot = NULL; + if (RootPath.first == "HKEY_CLASSES_ROOT") hRoot = HKEY_CLASSES_ROOT; + else if (RootPath.first == "HKEY_CURRENT_USER") hRoot = HKEY_CURRENT_USER; + else if (RootPath.first == "HKEY_LOCAL_MACHINE") hRoot = HKEY_LOCAL_MACHINE; + else if (RootPath.first == "HKEY_USERS") hRoot = HKEY_USERS; + else if (RootPath.first == "HKEY_PERFORMANCE_DATA") hRoot = HKEY_PERFORMANCE_DATA; + else if (RootPath.first == "HKEY_CURRENT_CONFIG") hRoot = HKEY_CURRENT_CONFIG; + + if (bWrite) + RegCreateKeyEx(hRoot, RootPath.second.toStdWString().c_str(), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, (PHKEY)&handle, NULL); + else + RegOpenKeyEx(hRoot, RootPath.second.toStdWString().c_str(), REG_OPTION_NON_VOLATILE, KEY_READ, (PHKEY)&handle); + } + else + { + std::wstring key = Key.toStdWString(); + OBJECT_ATTRIBUTES objattrs; + UNICODE_STRING uni; + + RtlInitUnicodeString(&uni, key.c_str()); + InitializeObjectAttributes(&objattrs, &uni, OBJ_CASE_INSENSITIVE, NULL, NULL); + + if (bWrite) { + ULONG disposition; + NtCreateKey(&handle, KEY_ALL_ACCESS, &objattrs, 0, NULL, 0, &disposition); + } else + NtOpenKey(&handle, KEY_READ, &objattrs); + } + return handle; +} + +QJSValue JSysObject::listRegKey(const QString& Key) +{ + QVariantList entries; + HANDLE handle = openRegKey(Key); + if (handle && handle != INVALID_HANDLE_VALUE) + { + WCHAR szSubKeyName[MAX_KEY_NAME]; + DWORD dwSubKeyNameSize; + FILETIME ftLastWriteTime; + + for (DWORD dwIndex = 0; ; dwIndex++) + { + dwSubKeyNameSize = ARRAYSIZE(szSubKeyName); + if (RegEnumKeyEx((HKEY)handle, dwIndex, szSubKeyName, &dwSubKeyNameSize, NULL, NULL, NULL, &ftLastWriteTime) != ERROR_SUCCESS) + break; + + QVariantMap entry; + entry["type"] = "REG_KEY"; + entry["name"] = QString::fromWCharArray(szSubKeyName); + entries.append(entry); + } + + WCHAR szValueName[MAX_VALUE_NAME]; + DWORD dwValueNameSize; + DWORD dwType; + std::vector Buff; + Buff.reserve(MAX_VALUE_DATA); + BYTE* lpData = Buff.data(); + DWORD dwDataSize; + + for (DWORD dwIndex = 0; ; dwIndex++) + { + dwValueNameSize = MAX_VALUE_NAME; + dwDataSize = MAX_VALUE_DATA; + if (RegEnumValue((HKEY)handle, dwIndex, szValueName, &dwValueNameSize, NULL, &dwType, lpData, &dwDataSize) != ERROR_SUCCESS) + break; + + QVariantMap entry; + entry["name"] = QString::fromWCharArray(szValueName); + switch (dwType) + { + case REG_NONE: entry["type"] = "REG_NONE"; break; + case REG_SZ: entry["type"] = "REG_SZ"; entry["value"] = QString::fromStdWString((wchar_t*)lpData); break; + case REG_EXPAND_SZ: entry["type"] = "REG_EXPAND_SZ"; entry["value"] = QString::fromStdWString((wchar_t*)lpData); break; + case REG_BINARY: entry["type"] = "REG_BINARY"; entry["value"] = QByteArray((char*)lpData, dwDataSize); break; + case REG_DWORD: entry["type"] = "REG_DWORD"; entry["value"] = *(quint32*)lpData; break; + //case REG_DWORD_BIG_ENDIAN: break; + case REG_MULTI_SZ: {entry["type"] = "REG_MULTI_SZ"; + QStringList List; + for (wchar_t* pStr = (wchar_t*)lpData; *pStr; pStr += wcslen(pStr) + 1) + List.append(QString::fromStdWString((wchar_t*)pStr)); + entry["value"] = List; + break; } + case REG_QWORD: entry["type"] = "REG_QWORD"; entry["value"] = *(quint64*)lpData; + //case REG_LINK: break; + //case REG_RESOURCE_LIST: break; + //case REG_FULL_RESOURCE_DESCRIPTOR: break; + default: entry["type"] = "REG_UNKNOWN"; + } + entries.append(entry); + } + CloseHandle(handle); + } + return m_pEngine->m_pEngine->toScriptValue(entries); +} + +QJSValue JSysObject::setRegValue(const QString& Key, const QString& Name, const QVariant& Value, const QString& Type) +{ + bool bRet = false; + HANDLE handle = openRegKey(Key, true); + if (handle && handle != INVALID_HANDLE_VALUE) + { + DWORD dwType = REG_NONE; + std::vector Buff; + Buff.reserve(MAX_VALUE_DATA); + BYTE* lpData = Buff.data(); + DWORD dwDataSize = 0; + + if (Type.isEmpty()) { + switch (Value.type()) { + case QVariant::String: dwType = REG_SZ; break; + case QVariant::StringList: dwType = REG_MULTI_SZ; break; + case QVariant::ByteArray: dwType = REG_BINARY; break; + case QVariant::Int: + case QVariant::UInt: dwType = REG_DWORD; break; + case QVariant::Double: // lets cast double to QDWORD + case QVariant::ULongLong: + case QVariant::LongLong: dwType = REG_QWORD; break; + } + } + else if (Type.compare("REG_NONE", Qt::CaseInsensitive) == 0) + dwType = REG_NONE; + else if (Type.compare("REG_SZ", Qt::CaseInsensitive) == 0) + dwType = REG_SZ; + else if (Type.compare("REG_EXPAND_SZ", Qt::CaseInsensitive) == 0) + dwType = REG_EXPAND_SZ; + else if (Type.compare("REG_BINARY", Qt::CaseInsensitive) == 0) + dwType = REG_BINARY; + else if (Type.compare("REG_DWORD", Qt::CaseInsensitive) == 0) + dwType = REG_DWORD; + else if (Type.compare("REG_MULTI_SZ", Qt::CaseInsensitive) == 0) + dwType = REG_MULTI_SZ; + else if (Type.compare("REG_QWORD", Qt::CaseInsensitive) == 0) + dwType = REG_QWORD; + + switch (dwType) + { + case REG_SZ: + case REG_EXPAND_SZ: {QString str = Value.toString(); str.toWCharArray((wchar_t*)lpData); dwDataSize = (str.size() + 1) * sizeof(wchar_t); break; } + case REG_BINARY: {QByteArray arr = Value.toByteArray(); memcpy(lpData, arr.data(), arr.size()); dwDataSize = arr.size(); break; } + case REG_DWORD: *(quint32*)lpData = Value.toInt(); dwDataSize = sizeof(qint32); break; + //case REG_DWORD_BIG_ENDIAN: break; + case REG_MULTI_SZ: {BYTE* ptr = lpData; + foreach(const QString& str, Value.toStringList()){ + str.toWCharArray((wchar_t*)ptr); + DWORD len = (str.size() + 1) * sizeof(wchar_t); + ptr += len; + dwDataSize += len; + } + *(wchar_t*)ptr = 0; + dwDataSize += sizeof(wchar_t); + break; } + case REG_QWORD: *(quint32*)lpData = Value.toLongLong(); dwDataSize = sizeof(qint64); break; + //case REG_LINK: break; + //case REG_RESOURCE_LIST: break; + //case REG_FULL_RESOURCE_DESCRIPTOR: break; + } + + bRet = RegSetKeyValue((HKEY)handle, L"", Name.toStdWString().c_str(), dwType, lpData, dwDataSize); + CloseHandle(handle); + } + return bRet; +} + +QJSValue JSysObject::getRegValue(const QString& Key, const QString& Name) +{ + QVariant value; + HANDLE handle = openRegKey(Key, true); + if (handle && handle != INVALID_HANDLE_VALUE) + { + DWORD dwType; + std::vector Buff; + Buff.reserve(MAX_VALUE_DATA); + BYTE* lpData = Buff.data(); + DWORD dwDataSize = MAX_VALUE_DATA; + + if (RegQueryValueEx((HKEY)handle, Name.toStdWString().c_str(), 0, &dwType, lpData, &dwDataSize)) { + switch (dwType) + { + case REG_SZ: value = QString::fromStdWString((wchar_t*)lpData); break; + case REG_EXPAND_SZ: value = QString::fromStdWString((wchar_t*)lpData); break; + case REG_BINARY: value = QByteArray((char*)lpData, dwDataSize); break; + case REG_DWORD: value = *(quint32*)lpData; break; + //case REG_DWORD_BIG_ENDIAN: break; + case REG_MULTI_SZ: {QStringList List; + for (wchar_t* pStr = (wchar_t*)lpData; *pStr; pStr += wcslen(pStr) + 1) + List.append(QString::fromStdWString((wchar_t*)pStr)); + value = List; + break; } + case REG_QWORD: value = *(quint64*)lpData; + //case REG_LINK: break; + //case REG_RESOURCE_LIST: break; + //case REG_FULL_RESOURCE_DESCRIPTOR: break; + } + } + CloseHandle(handle); + } + return m_pEngine->m_pEngine->toScriptValue(value); +} + +QJSValue JSysObject::removeRegKey(const QString& Key) +{ + HANDLE handle = openRegKey(Key, true); + if (handle && handle != INVALID_HANDLE_VALUE) + { + NtDeleteKey(handle); + CloseHandle(handle); + } + return QJSValue(); +} + +QJSValue JSysObject::removeRegValue(const QString& Key, const QString& Name) +{ + HANDLE handle = openRegKey(Key, true); + if (handle && handle != INVALID_HANDLE_VALUE) + { + RegDeleteValue((HKEY)handle, Name.toStdWString().c_str()); + CloseHandle(handle); + } + return QJSValue(); +} + + +// SYS +QJSValue JSysObject::execute(const QString& Path, const QStringList& Arguments, const QVariantMap& Options) +{ + QProcess Process; + if (Options.contains("workingDirectory")) Process.setWorkingDirectory(Options.value("workingDirectory").toString()); + Process.start(Path, Arguments); + while (Process.state() != QProcess::NotRunning && m_pEngine->TestRunning()) { + QCoreApplication::processEvents(); + } + return Process.exitCode(); +} + +QJSValue JSysObject::expand(const QString& name) +{ + return QProcessEnvironment::systemEnvironment().value(name); +} + +// OS +QVariantMap JSysObject::GetOSVersion() +{ + // todo improve this + + RTL_OSVERSIONINFOEXW versionInfo; + memset(&versionInfo, 0, sizeof(RTL_OSVERSIONINFOEXW)); + versionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW); + NTSTATUS(WINAPI *RtlGetVersion)(PRTL_OSVERSIONINFOEXW); + *(void**)&RtlGetVersion = GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlGetVersion"); + if (RtlGetVersion != NULL) + RtlGetVersion(&versionInfo); + else + GetVersionExW((LPOSVERSIONINFOW)&versionInfo); // since windows 10 this one is lying + RtlGetVersion(&versionInfo); + + if (versionInfo.dwMajorVersion == 10 && versionInfo.dwBuildNumber > 22000) + versionInfo.dwMajorVersion = 11; + + QVariantMap ver; + ver["major"] = (quint32)versionInfo.dwMajorVersion; + ver["minor"] = (quint32)versionInfo.dwMinorVersion; + ver["build"] = (quint32)versionInfo.dwBuildNumber; + ver["platform"] = (quint32)versionInfo.dwPlatformId; + return ver; +} + +QJSValue JSysObject::version() +{ + return m_pEngine->m_pEngine->toScriptValue(GetOSVersion()); +} + +QJSValue JSysObject::enumUpdates() +{ + QVariantMap out; + + IUpdateSession *updateSession = NULL; + IUpdateSearcher *updateSearcher = NULL; + ISearchResult *searchResult = NULL; + IUpdateCollection *updates = NULL; + HRESULT res; + int ret = 1; + + res = CoInitializeEx(NULL, 0); + if (FAILED(res)) { + out["error"] = "Failed to initialize COM"; + goto cleanup; + } + + res = CoCreateInstance(CLSID_UpdateSession, NULL, CLSCTX_INPROC_SERVER, IID_IUpdateSession, (LPVOID *)&updateSession); + if (FAILED(res)) { + out["error"] = "Failed to create update session"; + goto cleanup; + } + + res = updateSession->CreateUpdateSearcher(&updateSearcher); + if (FAILED(res)) { + out["error"] = "Failed to create update searcher"; + goto cleanup; + } + + res = updateSearcher->put_IncludePotentiallySupersededUpdates(VARIANT_TRUE); + if (FAILED(res)) { + out["error"] = "Failed to set search options"; + goto cleanup; + } + + {BSTR criteria = SysAllocString(L"IsInstalled=1"); // or IsHidden=1 + res = updateSearcher->Search(criteria, &searchResult); + SysFreeString(criteria);} + if (FAILED(res)) { + out["error"] = "Failed to search for updates"; + goto cleanup; + } + + res = searchResult->get_Updates(&updates); + if (FAILED(res)) { + out["error"] = "Failed to retrieve update list from search result"; + goto cleanup; + } + + LONG updateCount; + res = updates->get_Count(&updateCount); + if (FAILED(res)) { + out["error"] = "Failed to get update count"; + goto cleanup; + } + + {QVariantList list; + for (LONG i = 0L; i < updateCount; ++i) + { + QVariantMap entry; + + IUpdate* update = NULL; + res = updates->get_Item(i, &update); + if (FAILED(res)) + entry["error"] = "Failed to get update item"; + else + { + IStringCollection* updateKBIDs = NULL; + res = update->get_KBArticleIDs(&updateKBIDs); + if (SUCCEEDED(res)) { + LONG kbIDCount; + res = updateKBIDs->get_Count(&kbIDCount); + if (SUCCEEDED(res)) { + QVariantList kb; + for (LONG j = 0L; j < kbIDCount; ++j) { + BSTR kbID; + res = updateKBIDs->get_Item(j, &kbID); + if (FAILED(res)) + continue; + kb.append("KB" + QString::fromWCharArray(kbID)); + SysFreeString(kbID); + } + entry["kb"] = kb; + } + updateKBIDs->Release(); + } + + BSTR updateTitle; + res = update->get_Title(&updateTitle); + if (FAILED(res)) + entry["error"] = "Failed to get update title"; + else { + entry["title"] = QString::fromWCharArray(updateTitle); + SysFreeString(updateTitle); + } + + update->Release(); + } + list.append(entry); + } + out["list"] = list;} + + cleanup: + if (updates != NULL) updates->Release(); + if (searchResult != NULL) searchResult->Release(); + if (updateSearcher != NULL) updateSearcher->Release(); + if (updateSession != NULL) updateSession->Release(); + + CoUninitialize(); + + return m_pEngine->m_pEngine->toScriptValue(out); +} + + +// + +// todo: add sync to usage of GetCompat() + +QJSValue JSysObject::enumClasses() +{ + return m_pEngine->m_pEngine->toScriptValue(theGUI->GetCompat()->GetClasses()); +} + +QJSValue JSysObject::enumServices() +{ + return m_pEngine->m_pEngine->toScriptValue(theGUI->GetCompat()->GetServices()); +} + +QJSValue JSysObject::enumProducts() +{ + return m_pEngine->m_pEngine->toScriptValue(theGUI->GetCompat()->GetProducts()); +} + +QJSValue JSysObject::enumObjects() +{ + return m_pEngine->m_pEngine->toScriptValue(theGUI->GetCompat()->GetObjects()); +} + + +QJSValue JSysObject::expandPath(const QString& path) +{ + return theGUI->GetCompat()->ExpandPath(path); +} + +QJSValue JSysObject::checkFile(const QString& value) +{ + return theGUI->GetCompat()->CheckFile(value); +} + +QJSValue JSysObject::checkRegKey(const QString& value) +{ + return theGUI->GetCompat()->CheckRegistryKey(value); +} + +QJSValue JSysObject::checkClasses(const QString& value) +{ + return theGUI->GetCompat()->CheckClasses(value); +} + +QJSValue JSysObject::checkServices(const QString& value) +{ + return theGUI->GetCompat()->CheckServices(value); +} + +QJSValue JSysObject::checkProducts(const QString& value) +{ + return theGUI->GetCompat()->CheckProducts(value); +} + +QJSValue JSysObject::checkObjects(const QString& value) +{ + return theGUI->GetCompat()->CheckObjects(value); +} diff --git a/SandboxiePlus/SandMan/Engine/SysObject.h b/SandboxiePlus/SandMan/Engine/SysObject.h new file mode 100644 index 00000000..82152064 --- /dev/null +++ b/SandboxiePlus/SandMan/Engine/SysObject.h @@ -0,0 +1,57 @@ +#pragma once +#include "BoxEngine.h" + +class JSysObject : public QObject +{ + Q_OBJECT +public: + JSysObject(CBoxEngine* pEngine); + + Q_INVOKABLE void log(const QString& line); + Q_INVOKABLE void sleep(qint64 ms); + + // FS + Q_INVOKABLE QJSValue listDir(const QString& Path, const QStringList& filter = QStringList(), bool bSubDirs = false); + Q_INVOKABLE QJSValue mkDir(const QString& Path); + Q_INVOKABLE QJSValue remove(const QString& Path); + Q_INVOKABLE QJSValue exists(const QString& Path); + Q_INVOKABLE QJSValue readFile(const QString& Path, quint64 pos = 0, quint64 length = -1); + Q_INVOKABLE QJSValue writeFile(const QString& Path, const QByteArray& Data, quint64 pos = -1); + Q_INVOKABLE QJSValue getFileInfo(const QString& Path); + + + // REG + Q_INVOKABLE QJSValue listRegKey(const QString& Key); + Q_INVOKABLE QJSValue setRegValue(const QString& Key, const QString& Name, const QVariant& Value, const QString& Type = QString()); + Q_INVOKABLE QJSValue getRegValue(const QString& Key, const QString& Name); + Q_INVOKABLE QJSValue removeRegKey(const QString& Key); + Q_INVOKABLE QJSValue removeRegValue(const QString& Key, const QString& Name); + + // SYS + Q_INVOKABLE QJSValue execute(const QString& Path, const QStringList& Arguments, const QVariantMap& Options = QVariantMap()); + Q_INVOKABLE QJSValue expand(const QString& name); + + // OS + static QVariantMap GetOSVersion(); + Q_INVOKABLE QJSValue version(); + Q_INVOKABLE QJSValue enumUpdates(); // this can take quite a while + + // + Q_INVOKABLE QJSValue enumClasses(); + Q_INVOKABLE QJSValue enumServices(); + Q_INVOKABLE QJSValue enumProducts(); + Q_INVOKABLE QJSValue enumObjects(); + + Q_INVOKABLE QJSValue expandPath(const QString& path); + Q_INVOKABLE QJSValue checkFile(const QString& value); + Q_INVOKABLE QJSValue checkRegKey(const QString& value); + Q_INVOKABLE QJSValue checkClasses(const QString& value); + Q_INVOKABLE QJSValue checkServices(const QString& value); + Q_INVOKABLE QJSValue checkProducts(const QString& value); + Q_INVOKABLE QJSValue checkObjects(const QString& value); + + + +protected: + CBoxEngine* m_pEngine; +}; diff --git a/SandboxiePlus/SandMan/Engine/V4ScriptDebuggerApi.h b/SandboxiePlus/SandMan/Engine/V4ScriptDebuggerApi.h new file mode 100644 index 00000000..f58decc3 --- /dev/null +++ b/SandboxiePlus/SandMan/Engine/V4ScriptDebuggerApi.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2023 David Xanatos (xanasoft.com) All rights reserved. +** Contact: XanatosDavid@gmil.com +** +** +** To use the V4ScriptTools in a commercial project, you must obtain +** an appropriate business use license. +** +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** +** +****************************************************************************/ + +#ifndef CV4SCRIPTDEBUGGERAPI_H +#define CV4SCRIPTDEBUGGERAPI_H + +#include +#include +#include + +class CV4EngineItf +{ +public: + virtual QJSEngine* self() = 0; + + virtual int getScriptCount() const = 0; + virtual QString getScriptName(qint64 scriptId) const = 0; + virtual QString getScriptSource(qint64 scriptId) const = 0; + virtual int getScriptLineNumber(qint64 scriptId) const = 0; + virtual qint64 getScriptId(const QString& fileName) const = 0; + + // + // Note: the implementation of this interface must be derived from + // QObject and include the following signals and slots: + // + +//slots: +// QJSValue evaluateScript(const QString& program, const QString& fileName, int lineNumber = 1); +// +//signals: +// void evaluateFinished(const QJSValue& ret); +// void printTrace(const QString& Message); +// void invokeDebugger(); +}; + +typedef QObject* (*pNewV4ScriptDebuggerBackend)(CV4EngineItf* engine); +typedef QObject* (*pNewJSScriptDebuggerFrontend)(); +typedef QMainWindow* (*pNewJSScriptDebugger)(QObject* frontend, QWidget *parent, Qt::WindowFlags flags); + +__forceinline QObject* newV4ScriptDebuggerBackendDynamic(CV4EngineItf* engine) +{ + pNewV4ScriptDebuggerBackend myNewV4ScriptDebuggerBackend = (pNewV4ScriptDebuggerBackend)QLibrary::resolve("V4ScriptDebugger", "newV4ScriptDebuggerBackend"); + if (myNewV4ScriptDebuggerBackend) + return myNewV4ScriptDebuggerBackend(engine); + return NULL; +} + +__forceinline QObject* newJSScriptDebuggerFrontendDynamic() +{ + pNewJSScriptDebuggerFrontend myNewJSScriptDebuggerFrontend = (pNewJSScriptDebuggerFrontend)QLibrary::resolve("V4ScriptDebugger", "newJSScriptDebuggerFrontend"); + if (myNewJSScriptDebuggerFrontend) + return myNewJSScriptDebuggerFrontend(); + return NULL; +} + +__forceinline QMainWindow* newJSScriptDebuggerDynamic(QObject* frontend, QWidget *parent = nullptr, Qt::WindowFlags flags = {}) +{ + pNewJSScriptDebugger myNewJSScriptDebugger = (pNewJSScriptDebugger)QLibrary::resolve("V4ScriptDebugger", "newJSScriptDebugger"); + if (myNewJSScriptDebugger) + return myNewJSScriptDebugger(frontend, parent, flags); + return NULL; +} + +#endif \ No newline at end of file diff --git a/SandboxiePlus/SandMan/Engine/WizardObject.h b/SandboxiePlus/SandMan/Engine/WizardObject.h new file mode 100644 index 00000000..e0766474 --- /dev/null +++ b/SandboxiePlus/SandMan/Engine/WizardObject.h @@ -0,0 +1,58 @@ +#pragma once +#include "BoxEngine.h" + +class JWizardObject : public QObject +{ + Q_OBJECT +public: + JWizardObject(CWizardEngine* pEngine) : m_pEngine(pEngine) {} + + /*Q_INVOKABLE QJSValue showMessageBox(const QString& Type, const QString& Text){ + + //Type = "info_yes_NO_cancel"; + + return "cancel"; + }*/ + + Q_INVOKABLE QJSValue showForm(const QJSValue& form, const QString& Text = ""){ + + QMutexLocker Locker(&m_pEngine->m_Mutex); + if (!m_pEngine->TestRunning()) return QJSValue(); + + QVariantMap Data; + Data["type"] = "form"; + Data["form"] = form.toVariant().toList(); + Data["text"] = Text; + m_pEngine->m_Data = Data; + + m_pEngine->SetState(CBoxEngine::eQuery); + if (!m_pEngine->WaitLocked()) return QJSValue(); + + return m_pEngine->m_pEngine->toScriptValue(m_pEngine->m_Data); + } + + Q_INVOKABLE void showStatus(const QString& Text, bool bWait = false){ + + QMutexLocker Locker(&m_pEngine->m_Mutex); + if (!m_pEngine->TestRunning()) return; + + m_pEngine->SetState(bWait ? CBoxEngine::eReady : CBoxEngine::eRunningAsync, Text); + if(bWait) m_pEngine->WaitLocked(); + } + + Q_INVOKABLE void setResult(bool bSuccess, const QString& Text = "") { + + QMutexLocker Locker(&m_pEngine->m_Mutex); + if (!m_pEngine->TestRunning()) return; + + if(bSuccess) m_pEngine->SetState(CBoxEngine::eSuccess, Text); + else m_pEngine->SetState(CBoxEngine::eFailed, Text); + } + + Q_INVOKABLE void reportAdd(const QString& name, const QString& value) { + m_pEngine->m_Report[name] = value; + } + +protected: + CWizardEngine* m_pEngine; +}; diff --git a/SandboxiePlus/SandMan/Forms/NewBoxWindow.ui b/SandboxiePlus/SandMan/Forms/NewBoxWindow.ui deleted file mode 100644 index ac2506d7..00000000 --- a/SandboxiePlus/SandMan/Forms/NewBoxWindow.ui +++ /dev/null @@ -1,120 +0,0 @@ - - - NewBoxWindow - - - - 0 - 0 - 500 - 328 - - - - - 0 - 0 - - - - - 500 - 300 - - - - - 750 - 600 - - - - SandboxiePlus new box - - - - - - - - 32 - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - Box Type Preset: - - - - - - - Sandbox Name: - - - - - - - - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - - - - - - - - A sandbox isolates your host system from processes running within the box, it prevents them from making permanent changes to other programs and data in your computer. The level of isolation impacts your security as well as the compatibility with applications, hence there will be a different level of isolation depending on the selected Box Type. Sandboxie can also protect your personal data from being accessed by processes running under its supervision. - - - true - - - - - - - Box info - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - true - - - - - - - - - txtName - - - - diff --git a/SandboxiePlus/SandMan/Forms/SettingsWindow.ui b/SandboxiePlus/SandMan/Forms/SettingsWindow.ui index 3239b114..064f4834 100644 --- a/SandboxiePlus/SandMan/Forms/SettingsWindow.ui +++ b/SandboxiePlus/SandMan/Forms/SettingsWindow.ui @@ -6,8 +6,8 @@ 0 0 - 687 - 485 + 627 + 508 @@ -48,7 +48,7 @@ QTabWidget::North - 0 + 4 @@ -324,7 +324,7 @@ - Sandboxie may be issue <a href="sbie://docs/sbiemessages">SBIE Messages</a> to the Message Log and shown them as Popups. Some messages are informational and notify of a common, or in some cases special, event that has occurred, other messages indicate an error condition.<br />You can hide selected SBIE messages from being popped up, using the below list: + Sandboxie may be issue <a href= "sbie://docs/ sbiemessages">SBIE Messages</a> to the Message Log and shown them as Popups. Some messages are informational and notify of a common, or in some cases, special event that has occurred, other messages indicate an error condition.<br />You can hide selected SBIE messages from being popped up, using the below list: true @@ -337,27 +337,13 @@ - Disable SBIE messages popups (they will still be logged to the Messages tab) + Disable SBIE messages popups (SBIE will still be logged to the log tab) false - - - - Show recoverable files as notifications - - - - - - - Show file migration progress when copying large files into a sandbox - - - @@ -368,8 +354,22 @@ + + + + Show file migration progress when copying large files into a sandbox + + + + + + + Show recoverable files as notifications + + + - + Qt::Horizontal @@ -451,7 +451,7 @@ 20 - 40 + 0 @@ -589,7 +589,7 @@ 40 - 20 + 0 @@ -803,7 +803,7 @@ - 0 + 1 @@ -812,56 +812,6 @@ - - - - Use Fusion Theme - - - true - - - - - - - Use large icons in box list * - - - true - - - - - - - * a partially checked checkbox will leave the behavior to be determined by the view mode. - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - Use new config dialog layout * - - - true - - - @@ -872,43 +822,6 @@ - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Don't show icons in menus * - - - true - - - - - - - - 75 - true - true - - - - Interface Options - - - @@ -919,10 +832,70 @@ - - + + + + + 0 + 0 + + + + + 75 + true + true + + - Make Box Icons match the Border Color + Interface Options + + + + + + + Use Fusion Theme + + + true + + + + + + + Don't show icons in menus * + + + true + + + + + + + Show overlay icons for boxes and processes + + + + + + + Use large icons in box list * + + + true + + + + + + + Use new config dialog layout * + + + true @@ -943,10 +916,33 @@ - - + + - Show overlay icons for boxes and processes + Make Box Icons match the Border Color + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + * a partially checked checkbox will leave the behavior to be determined by the view mode. + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter @@ -1010,19 +1006,6 @@ - - - - Qt::Horizontal - - - - 40 - 20 - - - - @@ -1084,6 +1067,110 @@ + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + Addons Manager + + + + + + 0 + + + + Optional Addons + + + + + + + + Sandboxie-Plus offers numerous options and supports a wide range of extensions. On this page, you can configure the integration of addons, plugins, and other third-party components. Optional components can be downloaded from the web, and certain installations may require administrative privileges. + + + true + + + + + + + Remove + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + Name + + + + + Status + + + + + Description + + + + + + + + <a href="sbie://addons">update addon list now</a> + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Install + + + @@ -1098,237 +1185,346 @@ - - - 0 + + + 1 - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - 20 - 16777215 - - - - - - - - - - - - - - - - - - Hotpatches for the installed version, updates to the Templates.ini and translations. - - - Version Updates - - - - - - - - 75 - true - true - - - - This supporter certificate has expired, please <a href="sbie://update/cert">get an updated certificate</a>. - - - true - - - - - - - In the future, don't notify about certificate expiration - - - - - - - - 16777215 - 73 - - - - Enter the support certificate here - - - - - - - - - - - - - - The preview channel contains the latest GitHub pre-releases. - - - Search in the Preview channel - - - - - - - New full versions from the selected release channel. - - - New Versions - - - - - - - The stable channel contains the latest stable GitHub releases. - - - Search in the Stable channel - - - - - - - Supporters of the Sandboxie-Plus project can receive a <a href="https://sandboxie-plus.com/go.php?to=sbie-cert">supporter certificate</a>. It's like a license key but for awesome people using open source software. :-) - - - true - - - - - - - - - - Check periodically for updates of Sandboxie-Plus - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - 75 - true - true - - - - Support Settings - - - - - - - - - - - - - - - - - - - - - - - - :/HelpingHand.png - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 0 - 0 - - - - Keeping Sandboxie up to date with the rolling releases of Windows and compatible with all web browsers is a never-ending endeavor. You can support the development by <a href="https://sandboxie-plus.com/go.php?to=sbie-contribute">directly contributing to the project</a>, showing your support by <a href="https://sandboxie-plus.com/go.php?to=sbie-obtain-cert">purchasing a supporter certificate</a>, becoming a patron by <a href="https://sandboxie-plus.com/go.php?to=patreon">subscribing on Patreon</a>, or through a <a href="https://sandboxie-plus.com/go.php?to=donate">PayPal donation</a>.<br />Your support plays a vital role in the advancement and maintenance of Sandboxie. - - - Qt::RichText - - - true - - - - + + + Sandboxie Support + + + + + + 0 + + + + + Qt::Horizontal + + + + 40 + 0 + + + + + + + + In the future, don't notify about certificate expiration + + + + + + + + + + :/HelpingHand.png + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + + + 75 + true + true + + + + This supporter certificate has expired, please <a href="sbie://update/cert">get an updated certificate</a>. + + + true + + + + + + + + 20 + 16777215 + + + + + + + + + + + Qt::Vertical + + + + 20 + 0 + + + + + + + + Supporters of the Sandboxie-Plus project can receive a <a href="https://sandboxie-plus.com/go.php?to=sbie-cert">supporter certificate</a>. It's like a license key but for awesome people using open source software. :-) + + + true + + + + + + + + 0 + 0 + + + + Keeping Sandboxie up to date with the rolling releases of Windows and compatible with all web browsers is a never-ending endeavor. You can support the development by <a href="https://sandboxie-plus.com/go.php?to=sbie-contribute">directly contributing to the project</a>, showing your support by <a href="https://sandboxie-plus.com/go.php?to=sbie-obtain-cert">purchasing a supporter certificate</a>, becomeing a patron by <a href="https://sandboxie-plus.com/go.php?to=patreon">subscribing on Patreon</a>, or through a <a href="https://sandboxie-plus.com/go.php?to=dontate">PayPal donation</a>.<br />Your support plays a vital role in the advancement and maintenance of Sandboxie. + + + Qt::RichText + + + true + + + + + + + + 16777215 + 73 + + + + Enter the support certificate here + + + + + + + + + + Sandboxie Updater + + + + + + 0 + + + + + New full versions from the selected release channel. + + + New Versions + + + + + + + Keep addon list up to date + + + + + + + Qt::Horizontal + + + + 40 + 0 + + + + + + + + The preview channel contains the latest GitHub pre-releases. + + + Search in the Preview channel + + + + + + + Qt::Vertical + + + + 20 + 0 + + + + + + + + + 75 + true + true + + + + Support Settings + + + + + + + + + + + + + + The stable channel contains the latest stable GitHub releases. + + + Search in the Stable channel + + + + + + + + + + + + + + + + + + + + + + + + + + + + The Insider channel offers early access to new features and bugfixes that will eventually be released to the public, as well as all relevant improvements from the stable channel. +Unlike the preview channel, it does not include untested, potentially breaking, or experimental changes that may not be ready for wider use. + + + Search in the Insider channel + + + + + + + + + + + + + + 20 + 16777215 + + + + + + + + + + + Check periodically for new Sandboxie-Plus versions + + + + + + + + + + + + + + Hotpatches for the installed version, updates to the Templates.ini and translations. + + + Version Updates + + + + + + + Qt::Horizontal + + + + 40 + 0 + + + + + + + + + + + More about the <a href="https://sandboxie-plus.com/go.php?to=sbie-insider">Insider Channel</a> + + + + + + + Keep Troubleshooting scripts up to date + + + + + + + + @@ -1349,29 +1545,9 @@ - - - - Qt::Horizontal - - - - 40 - 20 - - - - - + - - - - Activate Kernel Mode Object Filtering - - - @@ -1385,19 +1561,25 @@ - - + + + + + + + + 23 + 16777215 + + - Sandbox <a href="sbie://docs/keyrootpath">registry root</a>: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - true + ... + + + @@ -1412,6 +1594,29 @@ + + + + + + + Portable root folder + + + + + + + Sandbox <a href="sbie://docs/ipcrootpath">ipc root</a>: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + true + + + @@ -1422,8 +1627,58 @@ - - + + + + Use Windows Filtering Platform to restrict network access + + + + + + + Sandbox <a href="sbie://docs/filerootpath">file system root</a>: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + true + + + + + + + Activate Kernel Mode Object Filtering + + + + + + + Sandbox <a href="sbie://docs/keyrootpath">registry root</a>: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + true + + + + + + + Qt::Vertical + + + + 20 + 40 + + + @@ -1452,94 +1707,35 @@ - - - - - - - Use Windows Filtering Platform to restrict network access - - - - + Hook selected Win32k system calls to enable GPU acceleration (experimental) - - - - - 23 - 16777215 - - + + - ... + Use a Sandboxie login instead of an anonymous token - - - - Sandbox <a href="sbie://docs/ipcrootpath">ipc root</a>: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - true - - - - - - - Portable root folder - - - - - + + - Qt::Vertical + Qt::Horizontal - 20 - 40 + 40 + 20 - - - - Use a Sandboxie login instead of an anonymous token (experimental) - - - - - - - - - - Sandbox <a href="sbie://docs/filerootpath">file system root</a>: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - true - - - - + Qt::Horizontal @@ -1603,20 +1799,6 @@ - - - - Only Administrator user accounts can use Pause Forcing Programs command - - - - - - - Clear password when main window becomes hidden - - - @@ -1631,6 +1813,20 @@ + + + + Only Administrator user accounts can use Pause Forcing Programs command + + + + + + + Clear password when main window becomes hidden + + + @@ -2032,6 +2228,7 @@ + diff --git a/SandboxiePlus/SandMan/Helpers/WinAdmin.cpp b/SandboxiePlus/SandMan/Helpers/WinAdmin.cpp index 1e2b7aa3..52535ac9 100644 --- a/SandboxiePlus/SandMan/Helpers/WinAdmin.cpp +++ b/SandboxiePlus/SandMan/Helpers/WinAdmin.cpp @@ -57,7 +57,7 @@ int RunElevated(const std::wstring& binaryPath, const std::wstring& Params, quin success = GetExitCodeProcess(sei.hProcess, &ExitCode); } CloseHandle(sei.hProcess); - return success ? ExitCode : -103; + return success ? ExitCode : STATUS_PENDING; } } diff --git a/SandboxiePlus/SandMan/Models/SbieModel.cpp b/SandboxiePlus/SandMan/Models/SbieModel.cpp index d5003bf1..a779c214 100644 --- a/SandboxiePlus/SandMan/Models/SbieModel.cpp +++ b/SandboxiePlus/SandMan/Models/SbieModel.cpp @@ -179,7 +179,7 @@ QList CSbieModel::Sync(const QMap& BoxList, cons foreach (const CSandBoxPtr& pBox, BoxList) { - if (!ShowHidden && !pBox->IsEnabled()) + if (!ShowHidden && (!pBox->IsEnabled() /*|| pBox->GetBool("IsShadow")*/)) continue; QVariant ID = pBox->GetName(); @@ -220,8 +220,7 @@ QList CSbieModel::Sync(const QMap& BoxList, cons QMap ProcessList = pBox->GetProcessList(); bool inUse = Sync(pBox, pNode->Path, ProcessList, New, Old, Added); - bool bOpen = pBoxEx->IsOpen(); - bool Busy = pBoxEx->IsBusy(); + bool Busy = pBoxEx->IsBoxBusy(); int boxType = pBoxEx->GetType(); bool boxDel = pBoxEx->IsAutoDelete(); bool boxNoForce = pBoxEx->IsForceDisabled(); @@ -241,10 +240,16 @@ QList CSbieModel::Sync(const QMap& BoxList, cons pNode->BoxIcon = BoxIcon; } } - else if (pNode->inUse != inUse || pNode->bOpen != bOpen || (pNode->busyState || Busy) || pNode->boxType != boxType || pNode->boxColor != boxColor || pNode->boxDel != boxDel || pNode->boxNoForce != boxNoForce || !pNode->BoxIcon.isEmpty()) + else if (pNode->inUse != inUse || + (pNode->busyState || Busy) || + pNode->boxType != boxType || + pNode->boxColor != boxColor || + pNode->boxDel != boxDel || + pNode->boxNoForce != boxNoForce || + !pNode->BoxIcon.isEmpty() + ) { pNode->inUse = inUse; - pNode->bOpen = bOpen; pNode->boxType = boxType; pNode->boxColor = boxColor; pNode->boxDel = boxDel; @@ -398,13 +403,13 @@ bool CSbieModel::Sync(const CSandBoxPtr& pBox, const QList& Path, cons if (OverlayIcons) { if (pProcess->HasSystemToken()) - Icon = theGUI->IconAddOverlay(Icon, ":/Actions/SystemShield.png", 20); + Icon = theGUI->IconAddOverlay(Icon, ":/Actions/SystemShield.png"); else if (pProcess->HasElevatedToken()) - Icon = theGUI->IconAddOverlay(Icon, ":/Actions/AdminShield.png", 20); + Icon = theGUI->IconAddOverlay(Icon, ":/Actions/AdminShield.png"); else if (pProcess->HasAppContainerToken()) - Icon = theGUI->IconAddOverlay(Icon, ":/Actions/AppContainer.png", 20); // AppContainer is also Restricted + Icon = theGUI->IconAddOverlay(Icon, ":/Actions/AppContainer.png"); // AppContainer is also Restricted else if (pProcess->HasRestrictedToken()) - Icon = theGUI->IconAddOverlay(Icon, ":/Actions/Restricted.png", 20); + Icon = theGUI->IconAddOverlay(Icon, ":/Actions/Restricted.png"); } pNode->Icon = Icon; diff --git a/SandboxiePlus/SandMan/OnlineUpdater.cpp b/SandboxiePlus/SandMan/OnlineUpdater.cpp index 456e5a13..50570195 100644 --- a/SandboxiePlus/SandMan/OnlineUpdater.cpp +++ b/SandboxiePlus/SandMan/OnlineUpdater.cpp @@ -13,6 +13,7 @@ #include #include "Helpers/WinAdmin.h" #include +#include #ifdef _DEBUG @@ -21,9 +22,9 @@ #undef VERSION_MJR #define VERSION_MJR 1 #undef VERSION_MIN -#define VERSION_MIN 5 +#define VERSION_MIN 9 #undef VERSION_REV -#define VERSION_REV 3 +#define VERSION_REV 8 #undef VERSION_UPD #define VERSION_UPD 0 @@ -90,7 +91,7 @@ void COnlineUpdater::Process() { time_t NextUpdateCheck = theConf->GetUInt64("Options/NextCheckForUpdates", 0); if (NextUpdateCheck == 0) - theConf->SetValue("Options/NextCheckForUpdates", QDateTime::currentDateTime().addDays(7).toSecsSinceEpoch()); + theConf->SetValue("Options/NextCheckForUpdates", QDateTime::currentDateTime().addDays(3).toSecsSinceEpoch()); else if(QDateTime::currentDateTime().toSecsSinceEpoch() >= NextUpdateCheck) { if (iCheckUpdates == 2) @@ -160,15 +161,34 @@ void COnlineUpdater::GetUpdates(QObject* receiver, const char* member, const QVa // Query.addQueryItem("branch", Branch); //Query.addQueryItem("version", theGUI->GetVersion()); //Query.addQueryItem("version", QString::number(VERSION_MJR) + "." + QString::number(VERSION_MIN) + "." + QString::number(VERSION_REV) + "." + QString::number(VERSION_UPD)); +#ifdef INSIDER_BUILD + Query.addQueryItem("version", QString(__DATE__)); +#else Query.addQueryItem("version", QString::number(VERSION_MJR) + "." + QString::number(VERSION_MIN) + "." + QString::number(VERSION_REV)); +#endif Query.addQueryItem("system", "windows-" + QSysInfo::kernelVersion() + "-" + QSysInfo::currentCpuArchitecture()); Query.addQueryItem("language", QLocale::system().name()); QString UpdateKey = GetArguments(g_Certificate, L'\n', L':').value("UPDATEKEY"); if (UpdateKey.isEmpty()) UpdateKey = theAPI->GetGlobalSettings()->GetText("UpdateKey"); // theConf->GetString("Options/UpdateKey"); + //if (UpdateKey.isEmpty()) + // UpdateKey = "00000000000000000000000000000000"; if (!UpdateKey.isEmpty()) - Query.addQueryItem("update_key", UpdateKey); + UpdateKey += "-"; + + quint64 RandID = 0; + theAPI->GetSecureParam("RandID", &RandID, sizeof(RandID)); + if (!RandID) { + RandID = QRandomGenerator64::global()->generate(); + theAPI->SetSecureParam("RandID", &RandID, sizeof(RandID)); + } + + quint32 Hash = theAPI->GetUserSettings()->GetName().mid(13).toInt(NULL, 16); + quint64 HashID = RandID ^ (quint64((Hash & 0xFFFF) ^ ((Hash >> 16) & 0xFFFF)) << 48); // fold the hash in half and xor it with the first 16 bit of RandID + + UpdateKey += QString::number(HashID, 16).rightJustified(16, '0').toUpper(); + Query.addQueryItem("update_key", UpdateKey); if (Params.contains("channel")) Query.addQueryItem("channel", Params["channel"].toString()); @@ -179,7 +199,9 @@ void COnlineUpdater::GetUpdates(QObject* receiver, const char* member, const QVa Query.addQueryItem("auto", Params["manual"].toBool() ? "0" : "1"); - //QString Test = Query.toString(); +#ifdef _DEBUG + QString Test = Query.toString(); +#endif QUrl Url("https://sandboxie-plus.com/update.php"); Url.setQuery(Query); @@ -204,9 +226,11 @@ void COnlineUpdater::CheckForUpdates(bool bManual) bManual = false; #endif - m_pUpdateProgress = CSbieProgressPtr(new CSbieProgress()); - theGUI->AddAsyncOp(m_pUpdateProgress); - m_pUpdateProgress->ShowMessage(tr("Checking for updates...")); + if (bManual) { + m_pUpdateProgress = CSbieProgressPtr(new CSbieProgress()); + theGUI->AddAsyncOp(m_pUpdateProgress); + m_pUpdateProgress->ShowMessage(tr("Checking for updates...")); + } // clean up old check result m_UpdateData.clear(); @@ -681,6 +705,72 @@ bool COnlineUpdater::RunUpdater(const QStringList& Params, bool bSilent, bool Wa return RunElevated(wFile, wParams, Wait ? INFINITE : 0) == 0; } +void COnlineUpdater::DownloadFile(const QString& Url, QObject* receiver, const char* member, const QVariantMap& Params) +{ + CGetUpdatesJob* pJob = new CGetUpdatesJob(Params, this); + QObject::connect(pJob, SIGNAL(Download(const QString&, const QVariantMap&)), receiver, member, Qt::QueuedConnection); + + if (m_RequestManager == NULL) + m_RequestManager = new CNetworkAccessManager(30 * 1000, this); + + QNetworkRequest Request = QNetworkRequest(Url); + //Request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); + Request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy); + //Request.setRawHeader("Accept-Encoding", "gzip"); + QNetworkReply* pReply = m_RequestManager->get(Request); + connect(pReply, SIGNAL(finished()), this, SLOT(OnFileDownload())); + connect(pReply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(OnDownloadProgress(qint64, qint64))); + + m_JobQueue.insert(pReply, pJob); +} + +void COnlineUpdater::OnFileDownload() +{ + if(!m_pUpdateProgress.isNull()) + m_pUpdateProgress->Progress(-1); + + QNetworkReply* pReply = qobject_cast(sender()); + quint64 Size = pReply->bytesAvailable(); + + CGetUpdatesJob* pJob = m_JobQueue.take(pReply); + if (!pJob) + return; + + QString FilePath = pJob->m_Params["path"].toString(); + if (FilePath.isEmpty()) { + QString Name = pReply->request().url().fileName(); + if (Name.isEmpty() || Name.right(4).compare(".exe", Qt::CaseInsensitive) != 0) + Name = "Sandboxie-Plus-Install.exe"; + FilePath = GetUpdateDir(true) + "/" + Name; + } + + QFile File(FilePath); + if (File.open(QFile::WriteOnly)) { + while (pReply->bytesAvailable() > 0) + File.write(pReply->read(4096)); + File.flush(); + QDateTime Date = pJob->m_Params["setDate"].toDateTime(); + if(Date.isValid()) + File.setFileTime(Date, QFileDevice::FileModificationTime); + File.close(); + } + + pReply->deleteLater(); + + if (!m_pUpdateProgress.isNull()) { + m_pUpdateProgress->Finish(SB_OK); + m_pUpdateProgress.clear(); + } + + if (File.size() != Size) { + QMessageBox::critical(theGUI, "Sandboxie-Plus", tr("Failed to download file from: %1").arg(pReply->request().url().toString())); + return; + } + + emit pJob->Download(FilePath, pJob->m_Params); + pJob->deleteLater(); +} + bool COnlineUpdater::DownloadInstaller(const QVariantMap& Release, bool bAndRun) { if (m_RequestManager == NULL) @@ -699,16 +789,11 @@ bool COnlineUpdater::DownloadInstaller(const QVariantMap& Release, bool bAndRun) theConf->DelValue("Updater/InstallerPath"); } - QNetworkRequest Request = QNetworkRequest(DownloadUrl); - //Request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); - Request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy); - //Request.setRawHeader("Accept-Encoding", "gzip"); - QNetworkReply* pReply = m_RequestManager->get(Request); - pReply->setProperty("run", bAndRun); - pReply->setProperty("version", MakeVersionStr(Release)); - pReply->setProperty("signature", Installer["signature"]); - connect(pReply, SIGNAL(finished()), this, SLOT(OnInstallerDownload())); - connect(pReply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(OnDownloadProgress(qint64, qint64))); + QVariantMap Params; + Params["run"] = bAndRun; + Params["version"] = MakeVersionStr(Release); + Params["signature"] = Installer["signature"]; + DownloadFile(DownloadUrl, this, SLOT(OnInstallerDownload(const QString&, const QVariantMap&)), Params); m_pUpdateProgress = CSbieProgressPtr(new CSbieProgress()); theGUI->AddAsyncOp(m_pUpdateProgress); @@ -717,49 +802,20 @@ bool COnlineUpdater::DownloadInstaller(const QVariantMap& Release, bool bAndRun) return true; } -void COnlineUpdater::OnInstallerDownload() +void COnlineUpdater::OnInstallerDownload(const QString& Path, const QVariantMap& Params) { - if (m_pUpdateProgress.isNull()) - return; + bool bAndRun = Params["run"].toBool(); + QString VersionStr = Params["version"].toString(); + QByteArray Signature = Params["signature"].toByteArray(); - m_pUpdateProgress->Progress(-1); - - QNetworkReply* pReply = qobject_cast(sender()); - bool bAndRun = pReply->property("run").toBool(); - QString VersionStr = pReply->property("version").toString(); - QByteArray Signature = pReply->property("signature").toByteArray(); - quint64 Size = pReply->bytesAvailable(); - QString Name = pReply->request().url().fileName(); - if (Name.isEmpty() || Name.right(4).compare(".exe", Qt::CaseInsensitive) != 0) - Name = "Sandboxie-Plus-Install.exe"; - - QString FilePath = GetUpdateDir(true) + "/" + Name; - - QFile File(FilePath); - if (File.open(QFile::WriteOnly)) { - while (pReply->bytesAvailable() > 0) - File.write(pReply->read(4096)); - File.close(); - } - - QFile SigFile(FilePath + ".sig"); + QFile SigFile(Path + ".sig"); if (SigFile.open(QFile::WriteOnly)) { SigFile.write(QByteArray::fromBase64(Signature)); SigFile.close(); } - pReply->deleteLater(); - - m_pUpdateProgress->Finish(SB_OK); - m_pUpdateProgress.clear(); - - if (File.size() != Size) { - QMessageBox::critical(theGUI, "Sandboxie-Plus", tr("Failed to download installer from: %1").arg(pReply->request().url().toString())); - return; - } - theConf->SetValue("Updater/InstallerVersion", VersionStr); - theConf->SetValue("Updater/InstallerPath", FilePath); + theConf->SetValue("Updater/InstallerPath", Path); if (bAndRun) RunInstaller(false); @@ -811,7 +867,7 @@ bool COnlineUpdater::RunInstaller2(const QString& FilePath, bool bSilent) QStringList Params; Params.append("run_setup"); Params.append(QString(FilePath).replace("/", "\\")); -#ifndef _DEBUG +#ifndef _DEBUG_ Params.append("/embedded"); #else Params.append("/pause"); @@ -925,21 +981,41 @@ int COnlineUpdater::GetCurrentUpdate() return iUpdate; } +quint32 COnlineUpdater::CurrentVersion() +{ + //quint8 myVersion[4] = { VERSION_UPD, VERSION_REV, VERSION_MIN, VERSION_MJR }; // ntohl + quint8 myVersion[4] = { 0, VERSION_REV, VERSION_MIN, VERSION_MJR }; // ntohl + quint32 MyVersion = *(quint32*)&myVersion; + return MyVersion; +} + +quint32 COnlineUpdater::VersionToInt(const QString& VersionStr) +{ + quint32 Version = 0; + QStringList Nums = VersionStr.split("."); + for (int i = 0, Bits = 24; i < Nums.count() && Bits >= 0; i++, Bits -= 8) + Version |= (Nums[i].toInt() & 0xFF) << Bits; + return Version; +} + bool COnlineUpdater::IsVersionNewer(const QString& VersionStr) { if (VersionStr.isEmpty()) return false; - //quint8 myVersion[4] = { VERSION_UPD, VERSION_REV, VERSION_MIN, VERSION_MJR }; // ntohl - quint8 myVersion[4] = { 0, VERSION_REV, VERSION_MIN, VERSION_MJR }; // ntohl - quint32 MyVersion = *(quint32*)&myVersion; +#ifdef INSIDER_BUILD + QString sVersion = VersionStr; + if (sVersion[4] == ' ') sVersion[4] = '0'; + QDateTime VersionDate = QDateTime::fromString(sVersion, "MMM dd yyyy"); + + sVersion = QString(__DATE__); + if (sVersion[4] == ' ') sVersion[4] = '0'; + QDateTime BuildDate = QDateTime::fromString(sVersion, "MMM dd yyyy"); - quint32 Version = 0; - QStringList Nums = VersionStr.split("."); - for (int i = 0, Bits = 24; i < Nums.count() && Bits >= 0; i++, Bits -= 8) - Version |= (Nums[i].toInt() & 0xFF) << Bits; - - return (Version > MyVersion); + return (VersionDate > BuildDate); +#else + return VersionToInt(VersionStr) > CurrentVersion(); +#endif } ///////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/SandboxiePlus/SandMan/OnlineUpdater.h b/SandboxiePlus/SandMan/OnlineUpdater.h index 6161833a..9c7c4ed3 100644 --- a/SandboxiePlus/SandMan/OnlineUpdater.h +++ b/SandboxiePlus/SandMan/OnlineUpdater.h @@ -18,7 +18,8 @@ protected: QVariantMap m_Params; signals: - void UpdateData(const QVariantMap& Data, const QVariantMap& Params); + void UpdateData(const QVariantMap& Data, const QVariantMap& Params); + void Download(const QString& Path, const QVariantMap& Params); }; @@ -31,6 +32,7 @@ public: void Process(); void GetUpdates(QObject* receiver, const char* member, const QVariantMap& Params = QVariantMap()); + void DownloadFile(const QString& Url, QObject* receiver, const char* member, const QVariantMap& Params = QVariantMap()); void UpdateCert(bool bWait = false); @@ -50,15 +52,19 @@ public: QString GetUpdateDir(bool bCreate = false); + static quint32 CurrentVersion(); + static quint32 VersionToInt(const QString& VersionStr); + private slots: void OnUpdateCheck(); + void OnFileDownload(); + void OnDownloadProgress(qint64 bytes, qint64 bytesTotal); + void OnInstallerDownload(const QString& Path, const QVariantMap& Params); void OnUpdateData(const QVariantMap& Data, const QVariantMap& Params); - void OnInstallerDownload(); - void OnPrepareOutput(); void OnPrepareError(); void OnPrepareFinished(int exitCode, QProcess::ExitStatus exitStatus); diff --git a/SandboxiePlus/SandMan/Resources/Actions/CPU.png b/SandboxiePlus/SandMan/Resources/Actions/CPU.png new file mode 100644 index 0000000000000000000000000000000000000000..c8041b5123326914a5ad5a6cb0a25d4dc80719e9 GIT binary patch literal 2064 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 VjQGi-9Yz2E002ovPDHLkV1g)*c8mZ3 literal 0 HcmV?d00001 diff --git a/SandboxiePlus/SandMan/Resources/Actions/Control4.png b/SandboxiePlus/SandMan/Resources/Actions/Control4.png new file mode 100644 index 0000000000000000000000000000000000000000..30667acf7c15d24c00cbb957755b4580a98fc2bd GIT binary patch literal 1861 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 P00000NkvXXu0mjfv?fSB literal 0 HcmV?d00001 diff --git a/SandboxiePlus/SandMan/Resources/Actions/EthSocket2.png b/SandboxiePlus/SandMan/Resources/Actions/EthSocket2.png new file mode 100644 index 0000000000000000000000000000000000000000..212682392b7544c9957b4527019983f5ecad68e2 GIT binary patch literal 1267 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 Dw*Ggi literal 0 HcmV?d00001 diff --git a/SandboxiePlus/SandMan/Resources/Actions/Help.png b/SandboxiePlus/SandMan/Resources/Actions/Help.png new file mode 100644 index 0000000000000000000000000000000000000000..b1a0a80051cbb8fa5d9236ae20fb33068f2c57ab GIT binary patch literal 1675 zcmV;626Xv}P)e+e@g6_ZcgZ!&Pcdq+#l1V^B4S|YWpuU-l=`oZ&G`$w^Mp7OUXS}Bww{)#}x~< zcUzFuWkyn`8Htz8Na&bGLi;qfT{2GjVk8DcH|h+L zjoL$N4%q$cw8zftwhL+fHn<+4M|6W8QS~}RUeJmYnvCvic93^opBY+vgbtDCb%+p8 z4MvIe0WL?RUAM{B4N<2>xLAv@b6QzYjf=Y5@^)Ism8e@rEJLOcBAU7rDAv32hV1OO z)p0_!84%y1LwvIqagr&-N~RFgNIvz95us-ZWD;9yCL3JPome2+P1x3|MO;0N-A!^F z?o;FVfClL|wK&?Z#(@qRu{BaeiIs@1*D^wc)Y>5sR%t%rGbfn0*me^V8)$rYV+vBs z9R96l{#roAT?4k(ND(2{FhT@ZYY<$iF@%d$?B|Sq*sG#>Ar_XFRza*!<`Gf)fEl7(jli-A_?M`@Vh$k}K(;NmMUVZLY0S+p zqF_*ux9Y|aRVzp2SqhQWGJMuaVR5wuyJ|-fD$+1Q1e8v|uUL7D`Bj|FE%wEnXx8B! zi2{3?6o{!)BBoL2&|yqvj9WLkpA8|#Qw5#E#mzK8O(F@4v1%qOZcEchTuvSON0_W`IN-@ z8R<3;xDv5fB7^OTBZ8dyk`B{HTKkx;nC9t2L$O{ z$F32?7=o+R>=F4iyz}TG=a5eGU02*{mB?2e?!#Raf=lJxwp0FdL>>jtT*~>@dLG&EdQXIj)cCeX<$#b*&p}u? z!W-e0OTiA~lX&b-Z_VE36O}NqHkYf1u!TYTSAIO=veA;Qg`_sqt>z z7={ghuKZn=TM(3gk2k_IXB_T1ihWKYBmpGh8K37Vxd3jd7)Nl46vCoW1f6*R;h9kc z70Y=eJWeSV-E$dSQAm*lkPl+z0$8nvu$+dljJALBM~uTQOMXMZw6?YwkMKnVm(z$Z z9l^1_31kjT;yv*w0t=-GELCwvxMwTio~by@7(${;5@T{+iK+=CRosX6rAs22=AXAI z;9n@`jBv}6+q|=BF9Dk(Su7_62@1+-9Q{YvBGpIP;Fouw+e&09;FhUKXN9ms>dc<;^h`wtb~6N&Gk%RQ-*_xcvX=E z(5Hyr=UYIhlgNgo9p0zu!OeNpAbFmWmz_t>c)EMG{6mjSsqZVlWTQ4}qXcVFe*+NJ V9i>IF?;HRC002ovPDHLkV1j!H7sdbp literal 0 HcmV?d00001 diff --git a/SandboxiePlus/SandMan/Resources/Actions/NetCard.png b/SandboxiePlus/SandMan/Resources/Actions/NetCard.png new file mode 100644 index 0000000000000000000000000000000000000000..09da6cfc14a4f5bcda3987bccecf5e868238e5f7 GIT binary patch literal 2157 zcmV-z2$J`SP)NW%iSZy^GxC0-b1xdhknK`;`D_Gryr#=XRzg7?{m-Qd%Yf35h5Z|GJP7G z@ANE>`5qL`9zx+v0<(vfe~lkV;hmnZlZ!ZfD7p163g-@gKeLBXaJ>uL2V1c7gJy;u zSDH{{ZbiY(1IxS452RrB&_7s3jP{X`$>GDE8z;b>J`hI%#mph9IL7n=Y}2$rCX+!b zl|mwspuWByVzC&tjrG_x-Wi|&teH8ugou3vD)%MSxKAzMBq}_|!5!NN?({)$Z-?1* zb3cC3*ThU-BoaX=6ha^nphhZ0{#YlI8%6ZtWwbufVDrpjRNuRZ_6J&Qojr<@J7>`G zP>1bv#~0NkW%@u85t}z;w2y$n=7nJa0@o?zPjz9_^nMzuUHpNHo;aV+M_pYVYHMpz zQ&WRVQ7!UDJD6OGE!Vmcygh;W`FRLD$3aYa>2}k|1zf&PVs35@J!1pl-ip;M$*pd7 z5kpkO=8c!IdT8YKv&fs+hy0t}Gdtv6 zx?7-7C?J>1Y1o#eSS*G_dj!SPy-aO#x{`=kJs~y$eFT~PEOM`RB5$fI%)~wvy|17r zURha*ii!%9mzSfgtPFdq%aP-6V{$+L^A~7uZ)X)qT$(1630EHbW8)-;T|{s7gcb@c zl+at;klD^4=i1xIo!l2@q7(U~8oN|A*d?vPP6-b?>MLos9u^=c(9Y!gp3bAGrI`^} z_!JiIErCFQ_q2WJy04Fo6QLl`iTv@nz9b?RPl!!`LT7P9YCVIT(GL2lFpPB|XQUMy zz47Gu+K@Z`Hj`I8)dO*(d`SU*WS^B^Xa#qoi>b}K-U(ih3QDCCVx<&CL~HcB)ee zZ@kvQE~2AESOlU-%%_ppFP^1OvD{x6QIyiBIGG#`C5=Y+QyJI(t-_k)grQ-jmQqP#^u(^MT-R3 zPP}a=CGlhUT2QR6L^-blyQ)i(eU2aQ54I&2VH41jPMUh+6tcX{$O^QE@wH%+MhS^p zvFJ3~+bzKcMjtLY?3q?2ll#dZe@AcDr35M>$G29i#kmKL*f>d8 z?{7*j!X}_095f>139NTDV*N-{7H zubLLW@n9BDo;*Q`>o9D0$ME>^V@Q0baru^&ZttHQh^twe#-&9P1t^A1b_n(FAj8ps z40mG~M*|Aq6~!%+=pEi$Q-O7aJeC`wDA0{vW4&~Hv%eF2$B$vXM~(cEc9f1EN4B?l zQB87G>>?V{8DbNNBGetjI-3IPoDE^@O5~mw#x0G~(o&R^l;BN48PZMCSnmG=M?(@3 z!X9E1pfTFO*B(W>RgQFrl3}e$imXclO zW0GKvS%x&T?3*>D>}(n-J+>5UNZBs}@b8d*GSl zg6FLS-&anzmBGDCU9po7*IWTkO#G7RTVs~7iwqj9AvS?1wL?8fGm4Q$O0b%c1Ubuz z;GUmT`BA?5CvY>OQ^3@zg1hOy&mN{T zeXGg(?-5B57}Q&6Y6g3-S}($CQ$13R_1KPOI`DK*Sr4y z@hXeTztiowo#*`KQx0+J+E&-4$s!lk*54{{M(f1h-R{4Ayvln2R~c^V^Q$`HLC$>J zE6GJz1St9`wB&o7l@R?pONdnvFF11sm6Z+*v6Pd6r`OT00000NkvXXu0mjf*+Umh literal 0 HcmV?d00001 diff --git a/SandboxiePlus/SandMan/Resources/Actions/Network3.png b/SandboxiePlus/SandMan/Resources/Actions/Network3.png new file mode 100644 index 0000000000000000000000000000000000000000..e9c85f79bd26a591906b7ce58e49809fd0c18520 GIT binary patch literal 2473 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 nJGC#7gK;np#=$uBx{m(`)&4Q5rRokf;ik zC`cgw&=vs^233j*qDVkfse;f7A|gh zUDtN(-Sv9sp7ZfzcGuqLZ0eDSkUwcX6SCC6f0)m?WTw6p)>!<(`$HDSdjnx_l z5FwQ6gk`^JBL6&drd{$a_Y>%aLA>((z(l5F|EUC2f^~@!B8nebIDCiA^LYSm1w&Q1&Jn08M1x;D6@{weI#+kr(ggrC_?qiQ zfAHquxw~%b+nfy28A#-{f1T}cOo>Di;O{}_{Ytr^>6Wb`d{Cv%$QD3UA)+`v<@{p% z4g62#d1J7a;JpC49b;a2Wq9}_ySlq`iy{(hiQLBmiHW#;>aHzY=4#2UIe2L&RUcF~ z@kEpmA%1njzPSIMEk|m}ygoQ`pvBlEV7e0-d;!287Da?WZ()159ti+Y>&z(ya~WbJ zIa8Qo0s2!_X`ck<(iS2L5OwwK=-W6skW9S*pdY~YMH7KR90ZKPR6|9}pFXpoR zQ0n-VTI)vTv5V?1KhfAUCJ6wlRg=rr6KN8oyVqsg_Kkj8VZW)uPC#J^KnW_K^j~m) zAMZjUzs95MvSHZ|jR*itKD6!vfFFmcvsr|;ApNhgMC4jS)jRUBrzcnDqS4Lp0KmiG z^mN;b2=I2sY}owN)F(W6h=|%qe){y#1NEol4}wikGv4ZEdc-j#J>5jUy}2ue|%+H7^#gFLN#H$xl=@VOj_`21H6fgGkK4jX7{*4orj);RXf169x$Y z0KI-uU2hyB5;bs(HskYSaAO9MC?KNCVEORE%gbELinfD9_bn@sxIR+X=IEIWQvaR? z$@Z{#sIpy^==g9P9XH16%B3efocP-~RLgCb5uwgMzDDrn6sn6EdO1Y2Je10t$Y zxFf-?NXlitk8}GS<8+i-Gkc%qE_QpUX6KEfF0jxhZ+%eHdrH zq{HI;U3eMuIfeLcI35-e6+2D<=abWT`}9nC3ZQ;9MwJk&MQTI z`WEw<)RaE<(_?tf^BH@XiJZZ~a6=RvI2&utMz)a=7ap+pR@=Y2)qH(C!)G6QgTM5n zCJ$hA2tVI^<*IZKoJ>78kW6vlWGcK>yh$8QrXC$grZ_NoZhw&M|4sC}MC4jSs5$#h zznk6Y(0)S{oeF{$@QV-%C`zpbQI0Xw_Z)cJytWtR-YsVpPD1J6OG?aXoEpBn!zXR9QFiIF=k* zufUi5|D01ngA63%M!jcjzU7Aix?7A*9!(Da8Ahioc+WKq2Vd(`&zV z=gD(-R-UJtRRt2O09?wN>>n3RYJ5`$Rk4)yx z5g1mt-iRE@;~I%Rb6fBFiDt$aS~GOb!Am^GtmD^jp zt#GvnZTdArwFGQlF*TMic0R!ce~SAyFMcR)!pqFUYlb@Jl;m|bJ1vRhFO3DXrvX*Y zs+hpps9A*i!9d&N7eA*~zpvnO|6>9A%~5LMV}VjGlcw-7{H*7%VcK895|&UO{{?gF V()Eyc)AaxV002ovPDHLkV1mgtR<-~D literal 0 HcmV?d00001 diff --git a/SandboxiePlus/SandMan/Resources/Actions/NetworkMgr.png b/SandboxiePlus/SandMan/Resources/Actions/NetworkMgr.png new file mode 100644 index 0000000000000000000000000000000000000000..82e098e6596d2ca4ae51b5d9a122a175a41e20e0 GIT binary patch literal 2655 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 V6lAZ}auNUl002ovPDHLkV1j-1WlsPA literal 0 HcmV?d00001 diff --git a/SandboxiePlus/SandMan/Resources/Actions/Proxy1.png b/SandboxiePlus/SandMan/Resources/Actions/Proxy1.png new file mode 100644 index 0000000000000000000000000000000000000000..f0cd74748f96b8a692157614c3611bdd30c9e522 GIT binary patch literal 1941 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 literal 0 HcmV?d00001 diff --git a/SandboxiePlus/SandMan/Resources/Actions/RAM.png b/SandboxiePlus/SandMan/Resources/Actions/RAM.png new file mode 100644 index 0000000000000000000000000000000000000000..438912f406d11975e5b4caf7a06e51acf858be49 GIT binary patch literal 1627 zcmV-h2Bi6kP)Jx99I#?Kd*nx?9A?t$CHgrBJm^kt{sPnT!I8bLgWzn zmWclVB)G<$K;g!L9LR}NA|!XZTB$Xen8CuNbfk)mvv2)qBNp#Dg?<42GC}a@j;`LZ)7SHGCj05Y8VBr%}3rxYFP?)jjGmruI3Me7yo#x6392+{^>8! z`qzlKB7g`Y0s?|0zYF{+Bmdjhqk{kW>_#H;%h8LQFPqri48%{KS6W_2aHdHU3*yum ziL)HPR)!UX5ld=018G28d`!>=l(8rXIKZ?1Gw0qp`P1ziFlCtCFIbBC0BkZ+0Qm2hzeh$#He zUJaRBjdXuSU>UAr#_Ow*2z;~hib@s7)XHJB=0e*8mBbN5_=h3QvE1CAff@s{q36K9dz>#u& zt>D`Cgt+TW!AF{}-HbW2Yc%YMFkSDSiTU7y2IUm0kq({=NNEp?pvDn#99IHyCkk|y zMK{n$6jQwe+&~c}PDBgtL=(pq$N}%J)eR=P!ZFIVR<_I(wbr#jv^Mq5dcRJ8s^ca4 zDzOpQ0?`@}r{)GM9QLxqB_e38sUk^wUzwhsqYt3%sh<3<_o4D}rQK5oB-@p{>gHEO zV^;%Yens*Q@2%=J)qq?@%C9;d$MsHPJ(JyeKqS3dO>4~qQaz7mffz7_!K1aVEqf}n zX2QJIvK*%R^*&T>HDLB;CO3GL5T5qa43_j^Mh=KBRwLck^6b_&0yu8eDCRD?>_9-fU#e!3aCr6W`&pCQYA8s>;c=YDN5Q} z7kY3^MBmZFX=%U!McJ}>L})PC~VQl=v!h?3*K7J+zU{e*}- zT-=zpiS_N&$m;f0$;#~CqpiI({-Ux?>yP&N!MAofI`HT;0!GrL*9|!6H(5~u!>B>8 z7tlX$(9$8}$m8@w5tG0n9tqnYclgVVGrtA+{)JC2Z+ztr?y_R35z{~PXt@y+<N0pHrtJHn-N;{%|E1pB?kevzCqe`R}~X)93fNcD>8` zTA!U!mnYBlxqiFL+2uYvgDy{=?{n+lt32u+^Pgdxv+H9H22EPyfbXvF$xE+q{|r#C z{n)+SZpKX74Ib)*+`if7k<~FDovd*Ft3$4BcUV6);O23Mr#1$>d!xffXTZ&)6`r~{ zq_=v)uin@wttR9rdo&}gdOONsCq~Pqj*|4go@>h(sj}si&X6dTTg>!7cU42@%R*Ls zH_RdhqP2ddp!6Ue{;zDlY8EMwD_5?(3A|jfpD>x%u-; zmoB{($MFw=-tNKjH$s}}JhXa2yId)nj z<&Xb%tJ6NXPx#1ZP1_K>z@;j|==^1poj5IZ#YgMTUlk0001>pro0ZX0o!fnVFfuz`)GR%-7e~ zmX?;?-Q8wpW_NdY`1ttD%$f1=@#^a8D0s~1zK~zXf?bO?D!Y~j7 z(DfyO1c!_N|6@C|Ysba`sy?(&U8D$=JDjy?tQ4c?>tJ3JR%!xf>dZ^R1d?WaXAZ0@j_!o>(GtrTiFG;Br%QPmVuGJ;MzG!|khV-7$g+qD{tvEO4U zC5OPdom@6GmSU!)?1l;M8eB&#rx~LCK1Z#TT#`yIBsHhrvSO%8rGy9JE#lFdM{>E`+Ew$4Z_sJwkWNAjVP%?t9~`~}JR3rrq%t5@9fNdN!<07*qoM6N<$ Eg3Rwt)c^nh literal 0 HcmV?d00001 diff --git a/SandboxiePlus/SandMan/Resources/Actions/Security2.png b/SandboxiePlus/SandMan/Resources/Actions/Security2.png new file mode 100644 index 0000000000000000000000000000000000000000..19bd255dcd33df50a679076de7cff85ae58bed07 GIT binary patch literal 2333 zcmV+&3F7vNP)rM!oSV4%zZ6+?v)E#={W;tUMX z5jz-YtF$9f$8ics2a0xhrD!b`6|9bfICMlxQ;KbQC`q*i$pAt@ED4lHlADB^d(S!h zoV{0n+(*uR--KxYuqNluK4-1H*7xnT*WUY_0C(h$+>um5UxiaXRoWYb?*q6OK)>Ka zRS#%20N$Z7H*R)y%q}Iu7fQMzkhKQHKLy|ca{?m>koq;Uv5rPG`noE1ml5IG((eLz z1K|FM#m|u+$34}7X)%qx@z<`1f7?X(^S(VG>@@%{1E94lVj6MeBJAFVM|*}w-@I`< zI66&)Kl?@*T4fx=N}d;&}j(3BSzHA46PlcvD#9Ff}6?Erq*2{7^Y z5t|NYD~xnIeY^R`$*{VUDMHdOF@a=YaQlRl*)#g50-BCU*MjM!JtxX;jHD)_V!U=_ zDkK2(RS*bEnvAIb|L8Lk+Qmw0A`vH@1J4YokWK?YlssEW2}ByHcZxJqi=+E@fPii? znp!n{c|8{ZV`v{giVA?-Yywe+;4`0D85Da5rw%K?7hrr)(;K^wl%h>1D5a3)mU#TZ zYnWZ`MPXh$ne_g{KdD)zuaR&{GMxLSU>y8cPwYI@7fLBGD=;&36L{s1rO5I~%r3u$ z98Wp|$+DGLw3J#VD{3&9+pn;54hIcBZ_|OjAD4zmaO4VhXS{i+Cjz>P*k|mY*y=nH zpfwZl;b%$#tv(Gmn%!XLI5NzPh87JC&2A{^959D}XN+)z0aj>E1vFi;*CE5X93FK| zV*mHu6`cafG zgT>B>9{sqfhDf$Fptkcwlyw+j8M|mW!M6ttHVSfqCDZDWhcTp&MA<-pgvjVY0gUKx2bbN1qmSqqj%*QQ zXF8a1#lG~JRYRnOT|_7YfG6LR^x~{tT$rsB;2;!DHs(H9FRU0+%19e;_kR8}l^RfZm&R&f8|jjd}hIbFnMge5i+;XVMx0E#W;D*Dse@zkNI5E{v-8d2%( z6BYXYa}zXMxr)Ph08G*#H^t(PC&CyOYAjT64^eOrsl7SuE?c?3h$7$|#3Y5Qp`8pt zrnQgu&#;v1!l{Ol!^1ehyf9=mJQjC~eT1$#)3;%2;bY8n41g<>^OuW&aYOyseI$5j zyl1!$7ln-D>|>k+n|2o2k8NDP@k01<#nY<>Bt`4InRA_cyHD4i7g|mcT3Vmm_vk$@ zI`#5cx3xrgJ|UP80jC5E;A*1=W=6kW3VB(n?VSTe;5GDsvCgSpaPZ`FMo#_)&5)zqJul5LC&J~7)rCXMiuEEt4^R7DLlKQCNZ2~RK1Pp-4QAE?y*@td| ze|xkC^!Y^X+DET&Kf|;yS*G#`Q^GRjyT{85=ZE!CH6nC5To@9TVMCb8qqiA@oO&X# zX16`jzFSL@YzTW*IgM zL&7rU39F^}Q^W{Of$>t!BfD<;i#k-eQ3R6MU-uPbTg}{EGzCUnT;={$nDVpWKufj^ z^=eWgfBRO>%eG;UH*`5Wr`dnsnRz5)9Rk3ATTA>KkIY3=pwOG@d=v#f%`)o^6trxq znTPBCqCldURl~>>dhSHqv}Rj6kE@+g@`_U*w`$c)E;<3=L?UNSX*Kil!qNGE-ZcGp z1Hts2+x#f;$*+zt{G!DySdc1a^+eJE>`$aic|>`*p65)zC|5mr#=JX`zE#f?WCW&x zd0zx<2BROHEq;bzVOLwPQW_=>Z-f?oa`&{FIU9VNH4}Jz@sv^Qt05h2} z69BA&?hqDWg;pwIsu=(h5=lC>EYm(}89@h9x1^`7@m+vl4PLa3ff+lttpC8-=kvya zSbcc$MOOS)1bqBdd+!$?ExvfJDSDHBy>k8g#A+r$+rn{NElqobVJQ*9VHtMPcao$T z`EX?R=JJnyUd!asmf+pHpZ`fsGFzwkMUHe$H5T!q+khu%dqDQ-L9?uM@iD-eDbpvk*Wq>&jftJ?o;)>ydPD_&RPio zFvVt?g@j9MDmgwOuNnxx+@+GtzQzNXbA@{dg}arBQ&q$0RwjLdz{R@smeDe!iMwfj zjIn(WyoSXV0ss9eQQ}k-T4Nm4Fh9BjYP-EXki53vIygr zEMFCc!5miBySdeR$rLCtZRwp<jY6@%?hBaB3>cFY$;-6zJsq{TN zE^C>!4?pq0U>f#J+f;{rcJa?H&ZLC9{vEj^UxWM)VTK%(dk3J300000NkvXXu0mjf D%==b7 literal 0 HcmV?d00001 diff --git a/SandboxiePlus/SandMan/Resources/Actions/SourceCode.png b/SandboxiePlus/SandMan/Resources/Actions/SourceCode.png new file mode 100644 index 0000000000000000000000000000000000000000..40b059268a28b3075996d53c7d6c8db43b205e1d GIT binary patch literal 1500 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 literal 0 HcmV?d00001 diff --git a/SandboxiePlus/SandMan/Resources/SandMan.qrc b/SandboxiePlus/SandMan/Resources/SandMan.qrc index b3e1540c..ef0fde97 100644 --- a/SandboxiePlus/SandMan/Resources/SandMan.qrc +++ b/SandboxiePlus/SandMan/Resources/SandMan.qrc @@ -150,10 +150,31 @@ Actions/Windows.png Actions/Interface.png Actions/Notification.png + Actions/Network2.png + Actions/NetworkMgr.png + Actions/EthSocket.png + Actions/EthSocket2.png + Actions/NetCard.png + Actions/EthCable.png + Actions/EthPlug.png + Actions/Network3.png + Actions/LockOpen.png + Actions/LockClosed.png + Actions/RamDisk.png + Actions/BoxConfig.png + Actions/FirstAid.png + Actions/Forum.png + Actions/Help.png Actions/Stack.png + Actions/Warning.png Actions/PauseForce.png Actions/DisableMessagePopup.png Actions/DisableRecovery.png + Actions/Plugin.png + Actions/Plugins.png + Actions/AntiVir.png + Actions/SourceCode.png + Actions/Qube.png Boxes/sandbox-b-empty.png diff --git a/SandboxiePlus/SandMan/SandMan.cpp b/SandboxiePlus/SandMan/SandMan.cpp index b838d8d7..5dfb6cd4 100644 --- a/SandboxiePlus/SandMan/SandMan.cpp +++ b/SandboxiePlus/SandMan/SandMan.cpp @@ -36,6 +36,9 @@ #include "Helpers/FullScreen.h" #include "Helpers/WinHelper.h" #include "../QSbieAPI/Helpers/DbgHelper.h" +#include "Wizards/BoxAssistant.h" +#include "Engine/BoxEngine.h" +#include "AddonManager.h" CSbiePlusAPI* theAPI = NULL; @@ -174,7 +177,12 @@ CSandMan::CSandMan(QWidget *parent) connect(theAPI, SIGNAL(BoxClosed(const CSandBoxPtr&)), this, SLOT(OnBoxClosed(const CSandBoxPtr&))); connect(theAPI, SIGNAL(BoxCleaned(CSandBoxPlus*)), this, SLOT(OnBoxCleaned(CSandBoxPlus*))); + +#ifdef INSIDER_BUILD + QString appTitle = tr("Sandboxie-Plus Insider [%1]").arg(QString(__DATE__)); +#else QString appTitle = tr("Sandboxie-Plus v%1").arg(GetVersion()); +#endif this->setWindowTitle(appTitle); @@ -185,12 +193,15 @@ CSandMan::CSandMan(QWidget *parent) m_SbieTemplates = new CSbieTemplates(theAPI, this); + m_bConnectPending = false; m_bStopPending = false; m_pUpdater = new COnlineUpdater(this); + m_AddonManager = new CAddonManager(this); + m_pMainWidget = new QWidget(this); @@ -277,6 +288,8 @@ CSandMan::CSandMan(QWidget *parent) HandleMaintenance(Status); } + connect(CSymbolProvider::Instance(), SIGNAL(StatusChanged(const QString&)), this, SLOT(OnSymbolStatus(const QString&))); + //qApp->setWindowIcon(GetIcon("IconEmptyDC", false)); } @@ -452,8 +465,9 @@ void CSandMan::CreateHelpMenu(bool bAdvanced) // m_pMenuBar->addAction(m_pSupport); //} m_pContribution = m_pMenuHelp->addAction(CSandMan::GetIcon("Support"), tr("Contribute to Sandboxie-Plus"), this, SLOT(OnHelp())); - m_pManual = m_pMenuHelp->addAction(tr("Online Documentation"), this, SLOT(OnHelp())); - m_pForum = m_pMenuHelp->addAction(tr("Visit Support Forum"), this, SLOT(OnHelp())); + m_pBoxAssistant = m_pMenuHelp->addAction(CSandMan::GetIcon("FirstAid"), tr("Troubleshooting Wizard"), this, SLOT(OnBoxAssistant())); + m_pManual = m_pMenuHelp->addAction(CSandMan::GetIcon("Help"), tr("Online Documentation"), this, SLOT(OnHelp())); + m_pForum = m_pMenuHelp->addAction(CSandMan::GetIcon("Forum"), tr("Visit Support Forum"), this, SLOT(OnHelp())); m_pMenuHelp->addSeparator(); m_pUpdate = m_pMenuHelp->addAction(CSandMan::GetIcon("Update"), tr("Check for Updates"), this, SLOT(CheckForUpdates())); m_pMenuHelp->addSeparator(); @@ -1476,6 +1490,13 @@ bool CSandMan::IsFullyPortable() return false; } +bool CSandMan::KeepTerminated() +{ + if (CBoxEngine::GetInstanceCount() > 0) + return true; + return m_pKeepTerminated && m_pKeepTerminated->isChecked(); +} + bool CSandMan::IsSilentMode() { if (!theConf->GetBool("Options/CheckSilentMode", true)) @@ -1528,11 +1549,20 @@ void CSandMan::OnMessage(const QString& MsgData) } } + for (int i = 1; i < Messages.length(); i++) { + if (Messages[i].left(3) == "In:") { + BoxName = Messages[i].mid(3); + break; + } + } + CSupportDialog::CheckSupport(true); - if (theConf->GetBool("Options/RunInDefaultBox", false) && (QGuiApplication::queryKeyboardModifiers() & Qt::ControlModifier) == 0) { - theAPI->RunStart(theAPI->GetGlobalSettings()->GetText("DefaultBox", "DefaultBox"), CmdLine, false, WrkDir); - } + if (BoxName.isEmpty() && theConf->GetBool("Options/RunInDefaultBox", false) && (QGuiApplication::queryKeyboardModifiers() & Qt::ControlModifier) == 0) + BoxName = theAPI->GetGlobalSettings()->GetText("DefaultBox", "DefaultBox"); + + if (!BoxName.isEmpty()) + RunStart(BoxName, CmdLine, false, WrkDir); else RunSandboxed(QStringList(CmdLine), BoxName, WrkDir); } @@ -1567,12 +1597,19 @@ bool CSandMan::RunSandboxed(const QStringList& Commands, QString BoxName, const { if (BoxName.isEmpty()) BoxName = theAPI->GetGlobalSettings()->GetText("DefaultBox", "DefaultBox"); - CSelectBoxWindow* pSelectBoxWindow = new CSelectBoxWindow(Commands, BoxName, WrkDir); + CSelectBoxWindow* pSelectBoxWindow = new CSelectBoxWindow(Commands, BoxName, WrkDir, g_GUIParent); connect(this, SIGNAL(Closed()), pSelectBoxWindow, SLOT(close())); //pSelectBoxWindow->show(); return SafeExec(pSelectBoxWindow) == 1; } +SB_RESULT(quint32) CSandMan::RunStart(const QString& BoxName, const QString& Command, bool Elevated, const QString& WorkingDir, QProcess* pProcess) +{ + auto pBoxEx = theAPI->GetBoxByName(BoxName).objectCast(); + + return theAPI->RunStart(BoxName, Command, Elevated, WorkingDir, pProcess); +} + void CSandMan::dropEvent(QDropEvent* e) { QStringList Commands; @@ -1602,7 +1639,7 @@ void CSandMan::timerEvent(QTimerEvent* pEvent) { SB_STATUS Status = theAPI->ReloadBoxes(); - theAPI->UpdateProcesses(KeepTerminated(), ShowAllSessions()); + UpdateProcesses(); bForceProcessDisabled = theAPI->AreForceProcessDisabled(); m_pDisableForce->setChecked(bForceProcessDisabled); @@ -1746,16 +1783,33 @@ void CSandMan::OnBoxSelected() SB_STATUS CSandMan::DeleteBoxContent(const CSandBoxPtr& pBox, EDelMode Mode, bool DeleteSnapshots) { SB_STATUS Ret = SB_OK; - m_iDeletingContent++; if (Mode != eAuto) { Ret = pBox->TerminateAll(); - theAPI->UpdateProcesses(KeepTerminated(), ShowAllSessions()); if (Ret.IsError()) - goto finish; + return Ret; } + auto pBoxEx = pBox.objectCast(); + if (Mode != eForDelete) { + + // + // shedule async OnBoxDelete triggers and clean up + // + + if (theConf->GetBool("Options/UseAsyncBoxOps", false) || theGUI->IsSilentMode()) + return pBoxEx->DeleteContentAsync(DeleteSnapshots); + } + + m_iDeletingContent++; + + if (Mode != eForDelete) { + + // + // execute OnBoxDelete triggers + // + foreach(const QString & Value, pBox->GetTextList("OnBoxDelete", true, false, true)) { QString Value2 = pBox->Expand(Value); CSbieProgressPtr pProgress = CSbieUtils::RunCommand(Value2, true); @@ -1770,6 +1824,10 @@ SB_STATUS CSandMan::DeleteBoxContent(const CSandBoxPtr& pBox, EDelMode Mode, boo } { + // + // delete content synchroniusly + // + SB_PROGRESS Status; if (Mode != eForDelete && !DeleteSnapshots && pBox->HasSnapshots()) { // in auto delete mode always return to last snapshot QString Current; @@ -1791,6 +1849,11 @@ finish: return Ret; } +void CSandMan::UpdateProcesses() +{ + theAPI->UpdateProcesses(KeepTerminated() ? -1 : 1500, ShowAllSessions()); // keep for 1.5 sec +} + void CSandMan::OnBoxAdded(const CSandBoxPtr& pBox) { connect(pBox.data(), SIGNAL(StartMenuChanged()), this, SLOT(OnStartMenuChanged())); @@ -1936,7 +1999,8 @@ void CSandMan::SyncStartMenu() } else OnLogMessage(tr("Added Shortcut to: %1").arg(Key)); QDir().mkpath(Folder); - CSbieUtils::CreateShortcut(theAPI, Location + Link.Name, + QString StartExe = theAPI->GetSbiePath() + "\\SandMan.exe"; + CSbieUtils::CreateShortcut(StartExe, Location + Link.Name, Link.Name, pBoxEx->GetName(), Link.Target, Link.Icon.isEmpty() ? Link.Target : Link.Icon, Link.IconIndex); } } @@ -1968,14 +2032,7 @@ void CSandMan::OnBoxClosed(const CSandBoxPtr& pBox) if (theConf->GetBool("Options/AutoBoxOpsNotify", false)) OnLogMessage(tr("Auto deleting content of %1").arg(pBox->GetName()), true); - if (theConf->GetBool("Options/UseAsyncBoxOps", false) || IsSilentMode()) - { - auto pBoxEx = pBox.objectCast(); - SB_STATUS Status = pBoxEx->DeleteContentAsync(DeleteSnapshots); - CheckResults(QList() << Status); - } - else - DeleteBoxContent(pBox, eAuto, DeleteSnapshots); + DeleteBoxContent(pBox, eAuto, DeleteSnapshots); } } } @@ -1994,7 +2051,12 @@ void CSandMan::OnBoxCleaned(CSandBoxPlus* pBoxEx) void CSandMan::OnStatusChanged() { +#ifdef INSIDER_BUILD + QString appTitle = tr("Sandboxie-Plus Insider [%1]").arg(QString(__DATE__)); +#else QString appTitle = tr("Sandboxie-Plus v%1").arg(GetVersion()); +#endif + if (theAPI->IsConnected()) { bool bPortable = IsFullyPortable(); @@ -2041,12 +2103,12 @@ void CSandMan::OnStatusChanged() QString cmd = CSbieUtils::GetContextMenuStartCmd(); if (!cmd.isEmpty() && !cmd.contains("SandMan.exe", Qt::CaseInsensitive)) - CSettingsWindow__AddContextMenu(); + CSettingsWindow::AddContextMenu(); } m_pBoxView->Clear(); - - OnIniReloaded(); + m_pBoxView->ReloadUserConfig(); + m_pPopUpWindow->ReloadHiddenMessages(); theAPI->WatchIni(true, theConf->GetBool("Options/WatchIni", true)); @@ -2107,7 +2169,7 @@ void CSandMan::OnStatusChanged() // clean up Auto Delete boxes after reboot // - theAPI->UpdateProcesses(false, ShowAllSessions()); + theAPI->UpdateProcesses(0, ShowAllSessions()); foreach(const CSandBoxPtr & pBox, AllBoxes) { if (pBox->GetActiveProcessCount() == 0) @@ -2119,21 +2181,16 @@ void CSandMan::OnStatusChanged() if (isVisible()) CheckSupport(); - int WizardLevel = theConf->GetBool("Options/WizardLevel", 0); - if (WizardLevel == 0) { - if (!CSetupWizard::ShowWizard()) // if user canceled mark that and not show again - theConf->SetValue("Options/WizardLevel", -1); + int WizardLevel = abs(theConf->GetBool("Options/WizardLevel", 0)); + if (WizardLevel < (theConf->GetInt("Options/CheckForUpdates", 2) != 1 ? SETUP_LVL_2 : SETUP_LVL_1)) { + if (!CSetupWizard::ShowWizard(WizardLevel)) { // if user canceled mark that and not show again, untill there is somethign new + if(QMessageBox::question(NULL, "Sandboxie-Plus", tr("Do you want the setup wizard to be omited?"), QMessageBox::Yes, QMessageBox::No | QMessageBox::Default) == QMessageBox::Yes) + theConf->SetValue("Options/WizardLevel", -SETUP_LVL_CURRENT); + } } if (theConf->GetBool("Options/AutoRunSoftCompat", true)) - { - if (m_SbieTemplates->RunCheck()) - { - CSettingsWindow* pSettingsWindow = new CSettingsWindow(this); - connect(pSettingsWindow, SIGNAL(OptionsChanged(bool)), this, SLOT(UpdateSettings(bool))); - pSettingsWindow->showTab(CSettingsWindow::eSoftCompat); - } - } + CheckCompat(this, "OpenCompat"); } else { @@ -2151,6 +2208,48 @@ void CSandMan::OnStatusChanged() UpdateState(); } +void CSandMan::CheckCompat(QObject* receiver, const char* member) +{ + QElapsedTimer* timer = new QElapsedTimer(); + timer->start(); + + C7zFileEngineHandler IssueFS("issue"); + QFile File(CBoxAssistant::GetIssueDir(IssueFS) + "AppCompatibility.js"); + if (File.open(QFile::ReadOnly)) { + CBoxEngine* pEngine = new CBoxEngine(this); + pEngine->RunScript(File.readAll(), "AppCompatibility.js"); // note: script runs asynchroniusly + QPointer pObj = receiver; // QPointer tracks lifetime of receiver + connect(pEngine, &CBoxEngine::finished, this, [pEngine, this, timer, pObj, member]() { + + m_SbieTemplates->SetCheckResult(pEngine->GetResult().toStringList()); + + qDebug() << "Compatibility Check took" << timer->elapsed() << "ms"; + delete timer; + pEngine->deleteLater(); // script done + + if(pObj) QMetaObject::invokeMethod(pObj, member); + }); + return; + } + + m_SbieTemplates->RunCheck(); + + qDebug() << "Template Check took" << timer->elapsed() << "ms"; + delete timer; + + QMetaObject::invokeMethod(receiver, member); +} + +void CSandMan::OpenCompat() +{ + if (m_SbieTemplates->GetCheckState()) + { + CSettingsWindow* pSettingsWindow = new CSettingsWindow(this); + connect(pSettingsWindow, SIGNAL(OptionsChanged(bool)), this, SLOT(UpdateSettings(bool))); + pSettingsWindow->showTab(CSettingsWindow::eSoftCompat); + } +} + void CSandMan::UpdateState() { bool isConnected = theAPI->IsConnected(); @@ -2390,6 +2489,13 @@ void CSandMan::OnLogSbieMessage(quint32 MsgCode, const QStringList& MsgData, qui m_pPopUpWindow->AddLogMessage(Message, MsgCode, MsgData, ProcessId); } +void CSandMan::SaveMessageLog(QIODevice* pFile) +{ + QList Rows = m_pMessageLog->DumpPanel(); + foreach(const QStringList& Row, Rows) + pFile->write(Row.join("\t").toLatin1() + "\n"); +} + bool CSandMan::CheckCertificate(QWidget* pWidget) { if (g_CertInfo.valid) @@ -2773,7 +2879,7 @@ void CSandMan::HandleMaintenance(SB_RESULT(void*) Status) QMessageBox::warning(this, tr("Sandboxie-Plus - Error"), tr("Failed to start required Sandboxie components")); OnLogMessage(tr("Maintenance operation failed (%1)").arg((quint32)dwStatus)); - CheckResults(QList() << SB_ERR(dwStatus)); + CheckResults(QList() << SB_ERR(dwStatus), this); } else { @@ -2782,7 +2888,7 @@ void CSandMan::HandleMaintenance(SB_RESULT(void*) Status) QTimer::singleShot(1000, [this]() { SB_STATUS Status = this->ConnectSbieImpl(); - CheckResults(QList() << Status); + CheckResults(QList() << Status, this); if (Status.IsError()) theAPI->LoadEventLog(); }); @@ -2803,7 +2909,7 @@ void CSandMan::HandleMaintenance(SB_RESULT(void*) Status) return; } - CheckResults(QList() << Status); + CheckResults(QList() << Status, this); } void CSandMan::OnViewMode(QAction* pAction) @@ -2856,7 +2962,7 @@ void CSandMan::OnCleanUp() if(m_pRecoveryLog) m_pRecoveryLog->GetTree()->clear(); if (sender() == m_pCleanUpProcesses || sender() == m_pCleanUpButton) - theAPI->UpdateProcesses(false, ShowAllSessions()); + theAPI->UpdateProcesses(0, ShowAllSessions()); } void CSandMan::OnProcView() @@ -2990,8 +3096,6 @@ void CSandMan::OnResetMsgs() theConf->DelValue("Options/PortableStart"); theConf->DelValue("Options/PortableRootDir"); - theConf->DelValue("Options/CheckForUpdates"); - theConf->DelValue("Options/NoEditInfo"); theConf->DelValue("Options/NoEditWarn"); @@ -3007,6 +3111,8 @@ void CSandMan::OnResetMsgs() theConf->DelValue("Options/InfoMkLink"); theConf->DelValue("Options/WarnOpenCOM"); + + theConf->DelValue("Options/WarnWizardOnClose"); } theAPI->GetUserSettings()->UpdateTextList("SbieCtrl_HideMessage", QStringList(), true); @@ -3181,9 +3287,14 @@ void CSandMan::OnMonitoring() } } -SB_STATUS CSandMan::AddAsyncOp(const CSbieProgressPtr& pProgress, bool bWait, const QString& InitialMsg) +void CSandMan::OnSymbolStatus(const QString& Message) { - m_pAsyncProgress.insert(pProgress.data(), pProgress); + statusBar()->showMessage(Message, 30*1000); +} + +SB_STATUS CSandMan::AddAsyncOp(const CSbieProgressPtr& pProgress, bool bWait, const QString& InitialMsg, QWidget* pParent) +{ + m_pAsyncProgress.insert(pProgress.data(), qMakePair(pProgress, pParent)); connect(pProgress.data(), SIGNAL(Message(const QString&)), this, SLOT(OnAsyncMessage(const QString&))); connect(pProgress.data(), SIGNAL(Progress(int)), this, SLOT(OnAsyncProgress(int))); connect(pProgress.data(), SIGNAL(Finished()), this, SLOT(OnAsyncFinished())); @@ -3212,14 +3323,15 @@ void CSandMan::OnAsyncFinished() void CSandMan::OnAsyncFinished(CSbieProgress* pSender) { - CSbieProgressPtr pProgress = m_pAsyncProgress.take(pSender); + auto Pair = m_pAsyncProgress.take(pSender); + CSbieProgressPtr pProgress = Pair.first; if (pProgress.isNull()) return; disconnect(pProgress.data() , SIGNAL(Finished()), this, SLOT(OnAsyncFinished())); SB_STATUS Status = pProgress->GetStatus(); if(Status.IsError()) - CSandMan::CheckResults(QList() << Status); + CheckResults(QList() << Status, Pair.second.data()); if (m_pAsyncProgress.isEmpty()) { if(m_pProgressModal) @@ -3241,8 +3353,8 @@ void CSandMan::OnAsyncProgress(int Progress) void CSandMan::OnCancelAsync() { - foreach(const CSbieProgressPtr& pProgress, m_pAsyncProgress) - pProgress->Cancel(); + foreach(auto Pair, m_pAsyncProgress) + Pair.first->Cancel(); } QString CSandMan::FormatError(const SB_STATUS& Error) @@ -3273,9 +3385,11 @@ QString CSandMan::FormatError(const SB_STATUS& Error) case SB_DeleteProtect: Message = tr("Delete protection is enabled for the sandbox"); break; case SB_DeleteNotEmpty: Message = tr("All sandbox processes must be stopped before the box content can be deleted"); break; case SB_DeleteError: Message = tr("Error deleting sandbox folder: %1"); break; + case SB_RemNotStopped: Message = tr("A all processes in a sandbox must be stopped before it can be renamed."); break; //case SB_RemNotEmpty: Message = tr("A sandbox must be emptied before it can be renamed."); break; case SB_DelNotEmpty: Message = tr("A sandbox must be emptied before it can be deleted."); break; case SB_FailedMoveDir: Message = tr("Failed to move directory '%1' to '%2'"); break; + case SB_FailedMoveImage:Message = tr("Failed to move box image '%1' to '%2'"); break; case SB_SnapIsRunning: Message = tr("This Snapshot operation can not be performed while processes are still running in the box."); break; case SB_SnapMkDirFail: Message = tr("Failed to create directory for new snapshot"); break; case SB_SnapCopyDatFail:Message = tr("Failed to copy box data files"); break; @@ -3290,6 +3404,9 @@ QString CSandMan::FormatError(const SB_STATUS& Error) case SB_NameExists: Message = tr("A sandbox with that name already exists"); break; case SB_PasswordBad: Message = tr("The config password must not be longer than 64 characters"); break; case SB_Canceled: Message = tr("The operation was canceled by the user"); break; + case SB_DeleteNoMount: Message = tr("The content of an un mounted sandbox can not be deleted"); break; + + case SB_OtherError: Message = tr("%1"); break; case SBX_7zNotReady: Message = tr("Import/Export not available, 7z.dll could not be loaded"); break; case SBX_7zCreateFailed: Message = tr("Failed to create the box archive"); break; @@ -3306,7 +3423,7 @@ QString CSandMan::FormatError(const SB_STATUS& Error) return Message; } -void CSandMan::CheckResults(QList Results, bool bAsync) +void CSandMan::CheckResults(QList Results, QWidget* pParent, bool bAsync) { QStringList Errors; for (QList::iterator I = Results.begin(); I != Results.end(); ++I) { @@ -3319,13 +3436,18 @@ void CSandMan::CheckResults(QList Results, bool bAsync) theGUI->OnLogMessage(Error, true); } else if (Errors.count() == 1) - QMessageBox::warning(theGUI, tr("Sandboxie-Plus - Error"), Errors.first()); + QMessageBox::warning(pParent ? pParent : this, tr("Sandboxie-Plus - Error"), Errors.first()); else if (Errors.count() > 1) { - CMultiErrorDialog Dialog(tr("Operation failed for %1 item(s).").arg(Errors.size()), Errors, theGUI); + CMultiErrorDialog Dialog(tr("Operation failed for %1 item(s).").arg(Errors.size()), Errors, pParent ? pParent : this); Dialog.exec(); } } +void CSandMan::OnBoxAssistant() +{ + CBoxAssistant::ShowAssistant(); +} + void CSandMan::OpenUrl(const QUrl& url) { QString scheme = url.scheme(); @@ -3333,6 +3455,11 @@ void CSandMan::OpenUrl(const QUrl& url) QString path = url.path(); QString query = url.query(); + if (scheme == "addon") { + m_AddonManager->TryInstallAddon(host, qobject_cast(sender())); + return; + } + if (scheme == "sbie") { if (path == "/check") m_pUpdater->CheckForUpdates(true); @@ -3486,19 +3613,23 @@ void CSandMan::UpdateTitleTheme(const HWND& hwnd) void CSandMan::LoadLanguage() { - QString Lang = theConf->GetString("Options/UiLanguage"); - if(Lang.isEmpty()) - Lang = QLocale::system().name(); + m_Language = theConf->GetString("Options/UiLanguage"); + if(m_Language.isEmpty()) + m_Language = QLocale::system().name(); - if (Lang.compare("native", Qt::CaseInsensitive) == 0) - Lang.clear(); + if (m_Language.compare("native", Qt::CaseInsensitive) == 0) +#ifdef _DEBUG + m_Language = "en"; +#else + m_Language.clear(); +#endif - m_LanguageId = LocaleNameToLCID(Lang.toStdWString().c_str(), 0); + m_LanguageId = LocaleNameToLCID(m_Language.toStdWString().c_str(), 0); if (!m_LanguageId) m_LanguageId = 1033; // default to English - LoadLanguage(Lang, "sandman", 0); - LoadLanguage(Lang, "qt", 1); + LoadLanguage(m_Language, "sandman", 0); + LoadLanguage(m_Language, "qt", 1); QTreeViewEx::m_ResetColumns = tr("Reset Columns"); CPanelView::m_CopyCell = tr("Copy Cell"); @@ -3522,10 +3653,9 @@ void CSandMan::LoadLanguage(const QString& Lang, const QString& Module, int Inde QString LangAux = Lang; // Short version as fallback LangAux.truncate(LangAux.lastIndexOf('_')); - C7zFileEngineHandler LangFS(QApplication::applicationDirPath() + "/translations.7z", "lang", this); - QString LangDir; - if (LangFS.IsOpen()) + C7zFileEngineHandler LangFS("lang", this); + if (LangFS.Open(QApplication::applicationDirPath() + "/translations.7z")) LangDir = LangFS.Prefix() + "/"; else LangDir = QApplication::applicationDirPath() + "/translations/"; diff --git a/SandboxiePlus/SandMan/SandMan.h b/SandboxiePlus/SandMan/SandMan.h index 2da77f78..3a4a2ed1 100644 --- a/SandboxiePlus/SandMan/SandMan.h +++ b/SandboxiePlus/SandMan/SandMan.h @@ -21,6 +21,7 @@ class CFileView; class CBoxBorder; class CSbieTemplates; class CTraceView; +class CAddonManager; struct ToolBarAction { // Identifier of action stored in ini. Empty for separator. @@ -42,32 +43,37 @@ public: virtual ~CSandMan(); CSbieTemplates* GetCompat() { return m_SbieTemplates; } + void CheckCompat(QObject* receiver, const char* member); + CAddonManager* GetAddonManager() { return m_AddonManager; } static QString GetVersion(); bool IsWFPEnabled() const; SB_PROGRESS RecoverFiles(const QString& BoxName, const QList>& FileList, QWidget* pParent, int Action = 0); + static QStringList GetFileCheckers(const CSandBoxPtr& pBox); SB_PROGRESS CheckFiles(const QString& BoxName, const QStringList& Files); enum EDelMode { - eDefault, + eCleanUp, eAuto, eForDelete }; SB_STATUS DeleteBoxContent(const CSandBoxPtr& pBox, EDelMode Mode, bool DeleteSnapshots = true); - SB_STATUS AddAsyncOp(const CSbieProgressPtr& pProgress, bool bWait = false, const QString& InitialMsg = QString()); + void UpdateProcesses(); + + SB_STATUS AddAsyncOp(const CSbieProgressPtr& pProgress, bool bWait = false, const QString& InitialMsg = QString(), QWidget* pParent = NULL); static QString FormatError(const SB_STATUS& Error); - static void CheckResults(QList Results, bool bAsync = false); + void CheckResults(QList Results, QWidget* pParent, bool bAsync = false); static QIcon GetIcon(const QString& Name, int iAction = 1); bool IsFullyPortable(); bool IsShowHidden() { return m_pShowHidden && m_pShowHidden->isChecked(); } - bool KeepTerminated() { return m_pKeepTerminated && m_pKeepTerminated->isChecked(); } + bool KeepTerminated(); bool ShowAllSessions() { return m_pShowAllSessions && m_pShowAllSessions->isChecked(); } bool IsSilentMode(); bool IsDisableRecovery() {return IsSilentMode() || m_pDisableRecovery && m_pDisableRecovery->isChecked();} @@ -78,6 +84,7 @@ public: int SafeExec(QDialog* pDialog); bool RunSandboxed(const QStringList& Commands, QString BoxName = QString(), const QString& WrkDir = QString()); + SB_RESULT(quint32) RunStart(const QString& BoxName, const QString& Command, bool Elevated = false, const QString& WorkingDir = QString(), QProcess* pProcess = NULL); QIcon GetBoxIcon(int boxType, bool inUse = false);// , bool inBusy = false); QRgb GetBoxColor(int boxType) { return m_BoxColors[boxType]; } @@ -93,6 +100,8 @@ public: void UpdateCertState(); + void SaveMessageLog(QIODevice* pFile); + signals: void CertUpdated(); @@ -124,8 +133,9 @@ protected: bool m_bStopPending; CBoxBorder* m_pBoxBorder; CSbieTemplates* m_SbieTemplates; + CAddonManager* m_AddonManager; - QMap m_pAsyncProgress; + QMap>> m_pAsyncProgress; QStringList m_MissingTemplates; @@ -171,6 +181,8 @@ public slots: bool OpenRecovery(const CSandBoxPtr& pBox, bool& DeleteSnapshots, bool bCloseEmpty = false); class CRecoveryWindow* ShowRecovery(const CSandBoxPtr& pBox, bool bFind = true); + void OpenCompat(); + void UpdateSettings(bool bRebuildUI); void RebuildUI(); void OnIniReloaded(); @@ -214,6 +226,7 @@ private slots: void OnSettingsAction(); void OnEmptyAll(); void OnWndFinder(); + void OnBoxAssistant(); void OnDisableForce(); void OnDisableForce2(); void OnDisablePopUp(); @@ -234,6 +247,8 @@ private slots: void OnReloadIni(); void OnMonitoring(); + void OnSymbolStatus(const QString& Message); + void CheckForUpdates(bool bManual = true); void OnExit(); @@ -380,6 +395,9 @@ private: QAction* m_pReloadIni; QAction* m_pEnableMonitoring; + //QMenu* m_pMenuTools; + QAction* m_pBoxAssistant; + QAction* m_pSeparator; QLabel* m_pLabel; @@ -434,6 +452,7 @@ private: public: class COnlineUpdater*m_pUpdater; + QString m_Language; quint32 m_LanguageId; bool m_DarkTheme; bool m_FusionTheme; diff --git a/SandboxiePlus/SandMan/SandMan.pri b/SandboxiePlus/SandMan/SandMan.pri index c3632b66..4813a271 100644 --- a/SandboxiePlus/SandMan/SandMan.pri +++ b/SandboxiePlus/SandMan/SandMan.pri @@ -23,7 +23,6 @@ HEADERS += ./stdafx.h \ ./Helpers/WinHelper.h \ ./Helpers/ReadDirectoryChanges.h \ ./Helpers/ReadDirectoryChangesPrivate.h \ - ./Windows/NewBoxWindow.h \ ./Windows/RecoveryWindow.h \ ./Windows/PopUpWindow.h \ ./Windows/SnapshotsWindow.h \ @@ -34,7 +33,18 @@ HEADERS += ./stdafx.h \ ./OnlineUpdater.h \ ./Wizards/NewBoxWizard.h \ ./Wizards/TemplateWizard.h \ - ./Wizards/SetupWizard.h + ./Wizards/SetupWizard.h \ + ./Wizards/BoxAssistant.h \ + ./Windows/BoxImageWindow.h \ + ./Engine/BoxEngine.h \ + ./Engine/BoxObject.h \ + ./Engine/IniObject.h \ + ./Engine/SbieObject.h \ + ./Engine/SysObject.h \ + ./Engine/V4ScriptDebuggerApi.h \ + ./Engine/JSEngineExt.h \ + ./Engine/WizardObject.h \ + ./AddonManager.h SOURCES += ./main.cpp \ ./stdafx.cpp \ @@ -58,7 +68,6 @@ SOURCES += ./main.cpp \ ./Helpers/ReadDirectoryChanges.cpp \ ./Helpers/ReadDirectoryChangesPrivate.cpp \ ./Helpers/WindowFromPointEx.cpp \ - ./Windows/NewBoxWindow.cpp \ ./Windows/OptionsWindow.cpp \ ./Windows/PopUpWindow.cpp \ ./Windows/RecoveryWindow.cpp \ @@ -69,15 +78,23 @@ SOURCES += ./main.cpp \ ./OnlineUpdater.cpp \ ./Wizards/NewBoxWizard.cpp \ ./Wizards/TemplateWizard.cpp \ - ./Wizards/SetupWizard.cpp + ./Wizards/SetupWizard.cpp \ + ./Wizards/BoxAssistant.cpp \ + ./Windows/BoxImageWindow.cpp \ + ./Engine/BoxEngine.cpp \ + ./Engine/BoxObject.cpp \ + ./Engine/IniObject.cpp \ + ./Engine/SbieObject.cpp \ + ./Engine/JSEngineExt.cpp \ + ./Engine/SysObject.cpp \ + ./AddonManager.cpp -FORMS += ./Forms/NewBoxWindow.ui \ +FORMS += ./Forms/SelectBoxWindow.ui \ ./Forms/OptionsWindow.ui \ ./Forms/PopUpWindow.ui \ ./Forms/RecoveryWindow.ui \ ./Forms/SettingsWindow.ui \ - ./Forms/SnapshotsWindow.ui \ - ./Forms/SelectBoxWindow.ui + ./Forms/SnapshotsWindow.ui TRANSLATIONS += sandman_de.ts \ sandman_en.ts \ diff --git a/SandboxiePlus/SandMan/SandMan.qc.pro b/SandboxiePlus/SandMan/SandMan.qc.pro index 8671ce41..51aaacdb 100644 --- a/SandboxiePlus/SandMan/SandMan.qc.pro +++ b/SandboxiePlus/SandMan/SandMan.qc.pro @@ -3,7 +3,7 @@ TEMPLATE = app TARGET = SandMan PRECOMPILED_HEADER = stdafx.h -QT += core gui network widgets concurrent +QT += core gui network widgets widgets-private concurrent core-private qml qml-private CONFIG += lrelease diff --git a/SandboxiePlus/SandMan/SandMan.vcxproj b/SandboxiePlus/SandMan/SandMan.vcxproj index 90eccef2..edb92356 100644 --- a/SandboxiePlus/SandMan/SandMan.vcxproj +++ b/SandboxiePlus/SandMan/SandMan.vcxproj @@ -115,7 +115,7 @@ msvc2019_64 - core;network;gui;widgets;winextras;concurrent + core;network;gui;widgets;qml;winextras;concurrent;widgets-private;qml-private msvc2019_64 @@ -127,7 +127,7 @@ msvc2019_64 - core;network;gui;widgets;winextras;concurrent + core;gui;network;qml;widgets;concurrent;widgets-private;qml-private msvc2019_64 @@ -160,7 +160,7 @@ Windows $(OutDir)\$(ProjectName).exe true - QSbieAPI.lib;MiscHelpers.lib;ntdll.lib;QtSingleApp.lib;UGlobalHotkey.lib;comctl32.lib;%(AdditionalDependencies) + QSbieAPI.lib;MiscHelpers.lib;ntdll.lib;QtSingleApp.lib;UGlobalHotkey.lib;comctl32.lib;bcrypt.lib;%(AdditionalDependencies) @@ -182,7 +182,7 @@ Windows $(OutDir)\$(ProjectName).exe true - QSbieAPI.lib;MiscHelpers.lib;ntdll.lib;QtSingleApp.lib;UGlobalHotkey.lib;comctl32.lib;%(AdditionalDependencies) + QSbieAPI.lib;MiscHelpers.lib;ntdll.lib;QtSingleApp.lib;UGlobalHotkey.lib;comctl32.lib;bcrypt.lib;%(AdditionalDependencies) @@ -207,7 +207,7 @@ true MachineX86 /SUBSYSTEM:WINDOWS - QSbieAPI.lib;MiscHelpers.lib;ntdll.lib;QtSingleApp.lib;UGlobalHotkey.lib;comctl32.lib;%(AdditionalDependencies) + QSbieAPI.lib;MiscHelpers.lib;ntdll.lib;QtSingleApp.lib;UGlobalHotkey.lib;comctl32.lib;bcrypt.lib;%(AdditionalDependencies) @@ -228,7 +228,7 @@ Windows $(OutDir)\$(ProjectName).exe true - QSbieAPI.lib;MiscHelpers.lib;ntdll.lib;QtSingleApp.lib;UGlobalHotkey.lib;comctl32.lib;%(AdditionalDependencies) + QSbieAPI.lib;MiscHelpers.lib;ntdll.lib;QtSingleApp.lib;UGlobalHotkey.lib;comctl32.lib;bcrypt.lib;%(AdditionalDependencies) @@ -249,7 +249,7 @@ Windows $(OutDir)\$(ProjectName).exe true - QSbieAPI.lib;MiscHelpers.lib;ntdll.lib;QtSingleApp.lib;UGlobalHotkey.lib;comctl32.lib;%(AdditionalDependencies) + QSbieAPI.lib;MiscHelpers.lib;ntdll.lib;QtSingleApp.lib;UGlobalHotkey.lib;comctl32.lib;bcrypt.lib;%(AdditionalDependencies) @@ -273,13 +273,27 @@ true MachineX86 /SUBSYSTEM:WINDOWS - QSbieAPI.lib;MiscHelpers.lib;ntdll.lib;QtSingleApp.lib;UGlobalHotkey.lib;comctl32.lib;%(AdditionalDependencies) + QSbieAPI.lib;MiscHelpers.lib;ntdll.lib;QtSingleApp.lib;UGlobalHotkey.lib;comctl32.lib;bcrypt.lib;%(AdditionalDependencies) + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + @@ -292,6 +306,7 @@ + true @@ -331,7 +346,6 @@ - true true @@ -419,11 +433,13 @@ + + @@ -433,7 +449,6 @@ - @@ -447,6 +462,14 @@ + + + + + + + + @@ -455,6 +478,7 @@ + @@ -469,7 +493,6 @@ - diff --git a/SandboxiePlus/SandMan/SandMan.vcxproj.filters b/SandboxiePlus/SandMan/SandMan.vcxproj.filters index f5010287..29a68a42 100644 --- a/SandboxiePlus/SandMan/SandMan.vcxproj.filters +++ b/SandboxiePlus/SandMan/SandMan.vcxproj.filters @@ -49,6 +49,9 @@ {4bf40c7e-2ce4-4528-813c-3b48b8c56155} + + {7f2e2eea-0d08-44d4-af39-01390e441438} + @@ -90,9 +93,6 @@ Windows - - Windows - Helpers @@ -192,6 +192,33 @@ Views + + Wizards + + + Engine + + + Engine + + + Engine + + + Engine + + + Engine + + + Engine + + + SandMan + + + Source Files + @@ -224,6 +251,9 @@ Helpers + + Engine + @@ -256,9 +286,6 @@ Windows - - Windows - Models @@ -301,6 +328,33 @@ Views + + Wizards + + + Engine + + + Engine + + + Engine + + + Engine + + + Engine + + + Engine + + + Engine + + + SandMan + @@ -334,9 +388,6 @@ Form Files - - Form Files - Form Files diff --git a/SandboxiePlus/SandMan/SandManRecovery.cpp b/SandboxiePlus/SandMan/SandManRecovery.cpp index 30405dbc..4afeaabc 100644 --- a/SandboxiePlus/SandMan/SandManRecovery.cpp +++ b/SandboxiePlus/SandMan/SandManRecovery.cpp @@ -72,17 +72,27 @@ CRecoveryWindow* CSandMan::ShowRecovery(const CSandBoxPtr& pBox, bool bFind) return pBoxEx->m_pRecoveryWnd; } -SB_PROGRESS CSandMan::CheckFiles(const QString& BoxName, const QStringList& Files) +QStringList CSandMan::GetFileCheckers(const CSandBoxPtr& pBox) { - CSbieProgressPtr pProgress = CSbieProgressPtr(new CSbieProgress()); - CSandBoxPtr pBox = theAPI->GetBoxByName(BoxName); QStringList Checkers; + + if (theGUI->GetAddonManager()->HasAddon("FileChecker")) + Checkers.append(pBox->Expand("powershell -exec bypass -nop -File \"%SbieHome%\\bin\\CheckFile.ps1\" -bin")); + if (!pBox.isNull()) { foreach(const QString & Value, pBox->GetTextList("OnFileRecovery", true, false, true)) { Checkers.append(pBox->Expand(Value)); } } - QtConcurrent::run(CSandMan::CheckFilesAsync, pProgress, BoxName, Files, Checkers); + + return Checkers; +} + +SB_PROGRESS CSandMan::CheckFiles(const QString& BoxName, const QStringList& Files) +{ + CSbieProgressPtr pProgress = CSbieProgressPtr(new CSbieProgress()); + CSandBoxPtr pBox = theAPI->GetBoxByName(BoxName); + QtConcurrent::run(CSandMan::CheckFilesAsync, pProgress, BoxName, Files, GetFileCheckers(pBox)); return SB_PROGRESS(OP_ASYNC, pProgress); } @@ -124,13 +134,7 @@ SB_PROGRESS CSandMan::RecoverFiles(const QString& BoxName, const QListGetBoxByName(BoxName); - QStringList Checkers; - if (!pBox.isNull()) { - foreach(const QString & Value, pBox->GetTextList("OnFileRecovery", true, false, true)) { - Checkers.append(pBox->Expand(Value)); - } - } - QtConcurrent::run(CSandMan::RecoverFilesAsync, qMakePair(pProgress, pParent), BoxName, FileList, Checkers, Action); + QtConcurrent::run(CSandMan::RecoverFilesAsync, qMakePair(pProgress, pParent), BoxName, FileList, GetFileCheckers(pBox), Action); return SB_PROGRESS(OP_ASYNC, pProgress); } diff --git a/SandboxiePlus/SandMan/SandManTray.cpp b/SandboxiePlus/SandMan/SandManTray.cpp index dd1b3cf8..d5313bb2 100644 --- a/SandboxiePlus/SandMan/SandManTray.cpp +++ b/SandboxiePlus/SandMan/SandManTray.cpp @@ -336,9 +336,6 @@ void CSandMan::OnBoxMenuHover(QAction* action) } } -double CSelectBoxWindow__GetBoxOrder(const QMap& Groups, const QString& Name, double value = 0.0, int Depth = 0); -QTreeWidgetItem* CSelectBoxWindow__GetBoxParent(const QMap& Groups, QMap& GroupItems, QTreeWidget* treeBoxes, const QString& Name, int Depth = 0); - void CSandMan::OnSysTray(QSystemTrayIcon::ActivationReason Reason) { static bool TriggerSet = false; @@ -365,7 +362,7 @@ void CSandMan::OnSysTray(QSystemTrayIcon::ActivationReason Reason) if (theConf->GetBool("MainWindow/BoxTree_UseOrder", false)) { QMultiMap Boxes2; foreach(const CSandBoxPtr &pBox, Boxes) { - Boxes2.insertMulti(CSelectBoxWindow__GetBoxOrder(Groups, pBox->GetName()), pBox); + Boxes2.insertMulti(CBoxPicker::GetBoxOrder(Groups, pBox->GetName()), pBox); } Boxes = Boxes2.values(); } @@ -387,7 +384,7 @@ void CSandMan::OnSysTray(QSystemTrayIcon::ActivationReason Reason) continue; } - QTreeWidgetItem* pParent = CSelectBoxWindow__GetBoxParent(Groups, GroupItems, m_pTrayBoxes, pBox->GetName()); + QTreeWidgetItem* pParent = CBoxPicker::GetBoxParent(Groups, GroupItems, m_pTrayBoxes, pBox->GetName()); QTreeWidgetItem* pItem = new QTreeWidgetItem(); pItem->setText(0, pBox->GetName().replace("_", " ")); diff --git a/SandboxiePlus/SandMan/SbiePlusAPI.cpp b/SandboxiePlus/SandMan/SbiePlusAPI.cpp index b2cc8fd1..c5a3cfbf 100644 --- a/SandboxiePlus/SandMan/SbiePlusAPI.cpp +++ b/SandboxiePlus/SandMan/SbiePlusAPI.cpp @@ -92,16 +92,16 @@ void CSbiePlusAPI::StopMonitor() m_BoxMonitor->Stop(); } -SB_STATUS CSbiePlusAPI::RunStart(const QString& BoxName, const QString& Command, bool Elevated, const QString& WorkingDir, QProcess* pProcess) +SB_RESULT(quint32) CSbiePlusAPI::RunStart(const QString& BoxName, const QString& Command, bool Elevated, const QString& WorkingDir, QProcess* pProcess) { if (!pProcess) pProcess = new QProcess(this); - SB_STATUS Status = CSbieAPI::RunStart(BoxName, Command, Elevated, WorkingDir, pProcess); + SB_RESULT(quint32) Status = CSbieAPI::RunStart(BoxName, Command, Elevated, WorkingDir, pProcess); if (pProcess->parent() == this) { if (!Status.IsError()) { connect(pProcess, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(OnStartFinished())); m_PendingStarts.insert(pProcess->processId()); - return SB_OK; + return Status; } delete pProcess; } @@ -228,7 +228,7 @@ void CSandBoxPlus::ExportBoxAsync(const CSbieProgressPtr& pProgress, const QStri } SB_STATUS Status = SB_OK; - if (!Archive.Update(&Files)) + if (!Archive.Update(&Files, true, theConf->GetInt("Options/ExportCompression", 5))) // 0, 1 - 9 Status = SB_ERR((ESbieMsgCodes)SBX_7zCreateFailed); //if(!Status.IsError() && !pProgress->IsCanceled()) @@ -549,22 +549,22 @@ void CSandBoxPlus::SetBoxPaths(const QString& FilePath, const QString& RegPath, return; } - m_IsEmpty = IsEmpty(); - - if (bPathChanged && theConf->GetBool("Options/WatchBoxSize", false) && m_TotalSize == -1) - ((CSbiePlusAPI*)theAPI)->m_BoxMonitor->ScanBox(this); + if(bPathChanged) + UpdateSize(false); if (theConf->GetBool("Options/ScanStartMenu", true)) ScanStartMenu(); } -void CSandBoxPlus::UpdateSize() +void CSandBoxPlus::UpdateSize(bool bReset) { - m_TotalSize = -1; - if(theConf->GetBool("Options/WatchBoxSize", false)) - ((CSbiePlusAPI*)theAPI)->m_BoxMonitor->ScanBox(this); + if(bReset) + m_TotalSize = -1; m_IsEmpty = IsEmpty(); + + if(theConf->GetBool("Options/WatchBoxSize", false) && m_TotalSize == -1) + ((CSbiePlusAPI*)theAPI)->m_BoxMonitor->ScanBox(this); } void CSandBoxPlus::SetSize(quint64 Size) @@ -600,6 +600,28 @@ void CSandBoxPlus::CloseBox() ScanStartMenu(); } +SB_STATUS CSandBoxPlus::RenameBox(const QString& NewName) +{ + if (GetBool("IsShadow")) + return RenameSection(NewName); + + BeginModifyingBox(); + + SB_STATUS Status = CSandBox::RenameBox(NewName); + + ConnectEndSlot(Status); + + return Status; +} + +SB_STATUS CSandBoxPlus::RemoveBox() +{ + if (GetBool("IsShadow")) + return RemoveSection(); + + return CSandBox::RemoveBox(); +} + void CSandBoxPlus::ConnectEndSlot(const SB_PROGRESS& Status) { CSbieProgressPtr pProgress = Status.GetValue(); @@ -628,6 +650,13 @@ void CSandBoxPlus::EndModifyingBox() ScanStartMenu(); } +bool CSandBoxPlus::IsEmpty() const +{ + if (!CSandBox::IsEmpty()) + return false; + return true; +} + bool CSandBoxPlus::CheckUnsecureConfig() const { //if (GetBool("UnsafeTemplate", false, true, true)) return true; @@ -975,7 +1004,7 @@ next: if (Status.IsError()) { theAPI->m_JobCount -= m_JobQueue.count(); m_JobQueue.clear(); - theGUI->CheckResults(QList() << Status); + theGUI->CheckResults(QList() << Status, theGUI); return; } if (!m_JobQueue.isEmpty()) @@ -1003,7 +1032,7 @@ void CSandBoxPlus::OnAsyncFinished() if (Status.IsError()) { theAPI->m_JobCount -= m_JobQueue.count(); m_JobQueue.clear(); - theGUI->CheckResults(QList() << Status, true); + theGUI->CheckResults(QList() << Status, theGUI, true); return; } else @@ -1068,4 +1097,4 @@ QString CSandBoxPlus::GetFullCommand(const QString& Command) //else if(FullCmd.left(2) == "\"\\") // FullCmd.insert(1, m_FilePath); return FullCmd.replace("%BoxRoot%", m_FilePath, Qt::CaseInsensitive); -} \ No newline at end of file +} diff --git a/SandboxiePlus/SandMan/SbiePlusAPI.h b/SandboxiePlus/SandMan/SbiePlusAPI.h index 3fb19ec5..b7ffe3d3 100644 --- a/SandboxiePlus/SandMan/SbiePlusAPI.h +++ b/SandboxiePlus/SandMan/SbiePlusAPI.h @@ -30,7 +30,7 @@ public: virtual void StopMonitor(); - virtual SB_STATUS RunStart(const QString& BoxName, const QString& Command, bool Elevated = false, const QString& WorkingDir = QString(), QProcess* pProcess = NULL); + virtual SB_RESULT(quint32) RunStart(const QString& BoxName, const QString& Command, bool Elevated = false, const QString& WorkingDir = QString(), QProcess* pProcess = NULL); virtual bool IsStarting(qint64 pid) const { return m_PendingStarts.contains(pid); } @@ -47,6 +47,8 @@ protected: virtual CSandBox* NewSandBox(const QString& BoxName, class CSbieAPI* pAPI); virtual CBoxedProcess* NewBoxedProcess(quint32 ProcessId, class CSandBox* pBox); + virtual SB_STATUS UpdateBoxPaths(CSandBox* pSandBox) { return CSbieAPI::UpdateBoxPaths(pSandBox); } + virtual CBoxedProcessPtr OnProcessBoxed(quint32 ProcessId, const QString& Path, const QString& Box, quint32 ParentId, const QString& CmdLine); int m_JobCount; @@ -82,11 +84,14 @@ public: virtual void CloseBox(); virtual SB_PROGRESS CleanBox() { BeginModifyingBox(); SB_PROGRESS Status = CSandBox::CleanBox(); ConnectEndSlot(Status); return Status; } - virtual SB_STATUS RenameBox(const QString& NewName) { BeginModifyingBox(); SB_STATUS Status = CSandBox::RenameBox(NewName); ConnectEndSlot(Status); return Status; } + virtual SB_STATUS RenameBox(const QString& NewName); + virtual SB_STATUS RemoveBox(); virtual SB_PROGRESS TakeSnapshot(const QString& Name) { BeginModifyingBox(); SB_PROGRESS Status = CSandBox::TakeSnapshot(Name); ConnectEndSlot(Status); return Status; } virtual SB_PROGRESS RemoveSnapshot(const QString& ID) { BeginModifyingBox(); SB_PROGRESS Status = CSandBox::RemoveSnapshot(ID); ConnectEndSlot(Status); return Status; } virtual SB_PROGRESS SelectSnapshot(const QString& ID) { BeginModifyingBox(); SB_PROGRESS Status = CSandBox::SelectSnapshot(ID); ConnectEndSlot(Status); return Status; } + virtual bool IsEmpty() const; + virtual QString GetStatusStr() const; virtual void SetLogApi(bool bEnable); @@ -115,7 +120,7 @@ public: virtual bool IsEmptyCached() const { return m_IsEmpty; } - virtual void UpdateSize(); + virtual void UpdateSize(bool bReset = true); virtual quint64 GetSize() const { if(m_TotalSize == -1) return 0; return m_TotalSize; } virtual void SetSize(quint64 Size); //{ m_TotalSize = Size; } virtual bool IsSizePending() const; @@ -153,8 +158,7 @@ public: class COptionsWindow* m_pOptionsWnd; class CRecoveryWindow* m_pRecoveryWnd; - bool IsOpen() const { return m_bRootAccessOpen; } - bool IsBusy() const { return IsSizePending() || !m_JobQueue.isEmpty(); } + bool IsBoxBusy() const { return IsSizePending() || !m_JobQueue.isEmpty(); } SB_STATUS DeleteContentAsync(bool DeleteSnapshots = true, bool bOnAutoDelete = false); struct SLink { diff --git a/SandboxiePlus/SandMan/Views/FileView.cpp b/SandboxiePlus/SandMan/Views/FileView.cpp index 7fe31cda..f03d670b 100644 --- a/SandboxiePlus/SandMan/Views/FileView.cpp +++ b/SandboxiePlus/SandMan/Views/FileView.cpp @@ -219,7 +219,7 @@ int openShellContextMenu(const QStringList& Files, void* parentWindow, const CSa std::wstring Str3 = CFileView::tr("Recover to Same Folder").toStdWString(); addItemToShellContextMenu(hMenu, Str3.c_str(), MENU_RECOVER); - if (!pBox->GetTextList("OnFileRecovery", true, false, true).isEmpty()) { + if (!CSandMan::GetFileCheckers(pBox).isEmpty()) { std::wstring Str4 = CFileView::tr("Run Recovery Checks").toStdWString(); addItemToShellContextMenu(hMenu, Str4.c_str(), MENU_CHECK_FILE); } @@ -354,7 +354,8 @@ void CFileView::OnFileMenu(const QPoint&) if (Path.isEmpty()) return; - CSbieUtils::CreateShortcut(theAPI, Path, LinkName, BoxName, LinkPath, LinkPath); + QString StartExe = theAPI->GetSbiePath() + "\\SandMan.exe"; + CSbieUtils::CreateShortcut(StartExe, Path, LinkName, BoxName, LinkPath, LinkPath); break; } diff --git a/SandboxiePlus/SandMan/Views/SbieView.cpp b/SandboxiePlus/SandMan/Views/SbieView.cpp index c67c8f55..73c4a8c8 100644 --- a/SandboxiePlus/SandMan/Views/SbieView.cpp +++ b/SandboxiePlus/SandMan/Views/SbieView.cpp @@ -10,7 +10,6 @@ #include "../Windows/SnapshotsWindow.h" #include "../../MiscHelpers/Common/CheckableMessageBox.h" #include "../Windows/RecoveryWindow.h" -#include "../Windows/NewBoxWindow.h" #include "../Views/FileView.h" #include "../Wizards/NewBoxWizard.h" #include "../Helpers/WinHelper.h" @@ -678,10 +677,6 @@ bool CSbieView::UpdateMenu() iSandBoxeCount = -1; else if (iSandBoxeCount != -1) iSandBoxeCount++; - - auto pBoxEx = pBox.objectCast(); - if(pBoxEx->IsBusy()) - bBoxBusy = true; } else iGroupe++; @@ -992,18 +987,7 @@ bool CSbieView::MoveItem(const QString& Name, const QString& To, int pos) QString CSbieView::AddNewBox(bool bAlowTemp) { - QString BoxName; - - bool bVintage = theConf->GetInt("Options/ViewMode", 1) == 2; - - if (bVintage) { - CNewBoxWindow NewBoxWindow(this); - connect(theGUI, SIGNAL(Closed()), &NewBoxWindow, SLOT(close())); - if (NewBoxWindow.exec() == 1) - BoxName = NewBoxWindow.m_Name; - } - else - BoxName = CNewBoxWizard::CreateNewBox(bAlowTemp, this); + QString BoxName = CNewBoxWizard::CreateNewBox(bAlowTemp, this); if (!BoxName.isEmpty()) { theAPI->ReloadBoxes(); @@ -1049,7 +1033,7 @@ QString CSbieView::ImportSandbox() } } else - CSandMan::CheckResults(QList() << Status); + theGUI->CheckResults(QList() << Status, this); return Name; } @@ -1117,7 +1101,7 @@ void CSbieView::OnSandBoxAction(QAction* Action, const QList& SandB return; if (Action == m_pStopAsync) { - foreach(const CSandBoxPtr & pBox, SandBoxes) + foreach(const CSandBoxPtr& pBox, SandBoxes) { auto pBoxEx = pBox.objectCast(); pBoxEx->OnCancelAsync(); @@ -1129,12 +1113,12 @@ void CSbieView::OnSandBoxAction(QAction* Action, const QList& SandB if(!Command.isEmpty()) SandBoxes.first()->RunCommand(Command);*/ - Results.append(SandBoxes.first()->RunStart("run_dialog")); + Results.append(theGUI->RunStart(SandBoxes.first()->GetName(), "run_dialog")); } else if (Action == m_pMenuRunBrowser) - Results.append(SandBoxes.first()->RunStart("default_browser")); + Results.append(theGUI->RunStart(SandBoxes.first()->GetName(), "default_browser")); else if (Action == m_pMenuRunMailer) - Results.append(SandBoxes.first()->RunStart("mail_agent")); + Results.append(theGUI->RunStart(SandBoxes.first()->GetName(), "mail_agent")); else if (Action == m_pMenuRunExplorer) { if (theConf->GetInt("Options/ViewMode", 1) != 1 && theConf->GetBool("Options/BoxedExplorerInfo", true)) @@ -1148,21 +1132,21 @@ void CSbieView::OnSandBoxAction(QAction* Action, const QList& SandB theConf->SetValue("Options/BoxedExplorerInfo", false); } - Results.append(SandBoxes.first()->RunStart("explorer.exe /e,::{20D04FE0-3AEA-1069-A2D8-08002B30309D}")); + Results.append(theGUI->RunStart(SandBoxes.first()->GetName(), "explorer.exe /e,::{20D04FE0-3AEA-1069-A2D8-08002B30309D}")); } else if (Action == m_pMenuRunRegEdit) - Results.append(SandBoxes.first()->RunStart("regedit.exe")); + Results.append(theGUI->RunStart(SandBoxes.first()->GetName(), "regedit.exe")); else if (Action == m_pMenuRunAppWiz) - Results.append(SandBoxes.first()->RunStart("\"C:\\WINDOWS\\System32\\control.exe\" \"C:\\Windows\\System32\\appwiz.cpl\"")); + Results.append(theGUI->RunStart(SandBoxes.first()->GetName(), "\"C:\\WINDOWS\\System32\\control.exe\" \"C:\\Windows\\System32\\appwiz.cpl\"")); else if (Action == m_pMenuAutoRun) - Results.append(SandBoxes.first()->RunStart("auto_run")); + Results.append(theGUI->RunStart(SandBoxes.first()->GetName(), "auto_run")); else if (Action == m_pMenuRunCmd) - Results.append(SandBoxes.first()->RunStart("cmd.exe")); + Results.append(theGUI->RunStart(SandBoxes.first()->GetName(), "cmd.exe")); else if (Action == m_pMenuRunCmdAdmin) - Results.append(SandBoxes.first()->RunStart("cmd.exe", true)); + Results.append(theGUI->RunStart(SandBoxes.first()->GetName(), "cmd.exe", true)); #ifdef _WIN64 else if (Action == m_pMenuRunCmd32) - Results.append(SandBoxes.first()->RunStart("C:\\WINDOWS\\SysWOW64\\cmd.exe")); + Results.append(theGUI->RunStart(SandBoxes.first()->GetName(), "C:\\WINDOWS\\SysWOW64\\cmd.exe")); #endif else if (Action == m_pMenuPresetsShowUAC) { @@ -1318,8 +1302,7 @@ void CSbieView::OnSandBoxAction(QAction* Action, const QList& SandB } theAPI->CommitIniChanges(); - theAPI->ReloadConfig(); - theAPI->ReloadBoxes(); + theAPI->ReloadBoxes(true); } Results.append(Status); @@ -1368,13 +1351,16 @@ void CSbieView::OnSandBoxAction(QAction* Action, const QList& SandB bool bChanged = false; foreach(const CSandBoxPtr& pBox, SandBoxes) { - SB_STATUS Status = theGUI->DeleteBoxContent(pBox, CSandMan::eForDelete); - if (Status.GetMsgCode() == SB_Canceled) - break; + if (!pBox->GetBool("IsShadow")) { + SB_STATUS Status = theGUI->DeleteBoxContent(pBox, CSandMan::eForDelete); + if (Status.GetMsgCode() == SB_Canceled) + break; + if (Status.IsError()) + continue; + } QString Name = pBox->GetName(); - if (!Status.IsError()) - Status = pBox->RemoveBox(); + SB_STATUS Status = pBox->RemoveBox(); Results.append(Status); if (!Status.IsError()) { @@ -1410,30 +1396,31 @@ void CSbieView::OnSandBoxAction(QAction* Action, const QList& SandB if(!theGUI->OpenRecovery(SandBoxes.first(), DeleteSnapshots)) return; } - else if(CCheckableMessageBox::question(this, "Sandboxie-Plus", tr("Do you want to delete the content of the selected sandbox?") - , tr("Also delete all Snapshots"), &DeleteSnapshots, QDialogButtonBox::Yes | QDialogButtonBox::No, QDialogButtonBox::Yes) != QDialogButtonBox::Yes) - return; + else { + if (SandBoxes.first()->HasSnapshots()) { + if(CCheckableMessageBox::question(this, "Sandboxie-Plus", tr("Do you want to delete the content of the selected sandbox?") + , tr("Also delete all Snapshots"), &DeleteSnapshots, QDialogButtonBox::Yes | QDialogButtonBox::No, QDialogButtonBox::Yes) != QDialogButtonBox::Yes) + return; + } + else { + if(QMessageBox::question(this, "Sandboxie-Plus", tr("Do you want to delete the content of the selected sandbox?") + , QMessageBox::Yes, QMessageBox::No) != QMessageBox::Yes) + return; + } + } + + } else if(CCheckableMessageBox::question(this, "Sandboxie-Plus", tr("Do you really want to delete the content of all selected sandboxes?") , tr("Also delete all Snapshots"), &DeleteSnapshots, QDialogButtonBox::Yes | QDialogButtonBox::No, QDialogButtonBox::Yes) != QDialogButtonBox::Yes) return; - foreach(const CSandBoxPtr &pBox, SandBoxes) + foreach(const CSandBoxPtr& pBox, SandBoxes) { - if (theConf->GetBool("Options/UseAsyncBoxOps", false) || theGUI->IsSilentMode()) - { - auto pBoxEx = pBox.objectCast(); - SB_STATUS Status = pBoxEx->DeleteContentAsync(DeleteSnapshots); - if (Status.IsError()) - Results.append(Status); - } - else - { - SB_STATUS Status = theGUI->DeleteBoxContent(pBox, CSandMan::eDefault, DeleteSnapshots); - if (Status.GetMsgCode() == SB_Canceled) - break; - Results.append(Status); - } + SB_STATUS Status = theGUI->DeleteBoxContent(pBox, CSandMan::eCleanUp, DeleteSnapshots); + if (Status.GetMsgCode() == SB_Canceled) + break; + Results.append(Status); } } else if (Action == m_pMenuEmptyBox) @@ -1477,14 +1464,14 @@ void CSbieView::OnSandBoxAction(QAction* Action, const QList& SandB QString Command = Action->data().toString(); QString WorkingDir = Action->property("WorkingDir").toString(); if (Command.isEmpty()) - Results.append(SandBoxes.first()->RunStart("start_menu", false, WorkingDir)); + Results.append(theGUI->RunStart(SandBoxes.first()->GetName(), "start_menu", false, WorkingDir)); else { auto pBoxEx = SandBoxes.first().objectCast(); - Results.append(SandBoxes.first()->RunStart(pBoxEx->GetFullCommand(Command), false, WorkingDir)); + Results.append(theGUI->RunStart(SandBoxes.first()->GetName(), pBoxEx->GetFullCommand(Command), false, WorkingDir)); } } - CSandMan::CheckResults(Results); + theGUI->CheckResults(Results, this); } bool CSbieView::CreateShortcut(const QString& LinkPath, const QString& BoxName, const QString &IconPath, int IconIndex, const QString &WorkDir) @@ -1511,11 +1498,12 @@ bool CSbieView::CreateShortcut(const QString& LinkPath, const QString& BoxName, Path.append("\\"); Path += "[" + BoxName + "] " + LinkName; - Path = QFileDialog::getSaveFileName(this, tr("Create Shortcut to sandbox %1").arg(BoxName), Path, QString("Shortcut files (*.lnk)")).replace("/", "\\"); + Path = QFileDialog::getSaveFileName(theGUI, tr("Create Shortcut to sandbox %1").arg(BoxName), Path, QString("Shortcut files (*.lnk)")).replace("/", "\\"); if (Path.isEmpty()) return false; - return CSbieUtils::CreateShortcut(theAPI, Path, LinkName, BoxName, LinkPath, IconPath, IconIndex, WorkDir); + QString StartExe = theAPI->GetSbiePath() + "\\SandMan.exe"; + return CSbieUtils::CreateShortcut(StartExe, Path, LinkName, BoxName, LinkPath, IconPath, IconIndex, WorkDir); } void CSbieView::OnProcessAction() @@ -1567,7 +1555,8 @@ void CSbieView::OnProcessAction(QAction* Action, const QList& if (Path.isEmpty()) return; - CSbieUtils::CreateShortcut(theAPI, Path, LinkName, BoxName, LinkPath, LinkPath); + QString StartExe = theAPI->GetSbiePath() + "\\SandMan.exe"; + CSbieUtils::CreateShortcut(StartExe, Path, LinkName, BoxName, LinkPath, LinkPath); } else if (Action == m_pMenuPinToRun) { @@ -1604,7 +1593,7 @@ void CSbieView::OnProcessAction(QAction* Action, const QList& Results.append(pProcess->SetSuspend(false));*/ } - CSandMan::CheckResults(Results); + theGUI->CheckResults(Results, this); } void CSbieView::ShowOptions(const CSandBoxPtr& pBox) diff --git a/SandboxiePlus/SandMan/Views/SbieView.h b/SandboxiePlus/SandMan/Views/SbieView.h index 93866f7d..4d803e37 100644 --- a/SandboxiePlus/SandMan/Views/SbieView.h +++ b/SandboxiePlus/SandMan/Views/SbieView.h @@ -65,6 +65,8 @@ public: QMap GetGroups() { return m_Groups; } + static bool CreateShortcut(const QString& LinkPath, const QString& BoxName, const QString& IconPath = QString(), int IconIndex = 0, const QString& WorkDir = QString()); + signals: void BoxSelected(); @@ -138,8 +140,6 @@ private: QMenu* GetMenuFolder(const QString& Folder, QMenu* pParent, QMap& Folders); - bool CreateShortcut(const QString& LinkPath, const QString& BoxName, const QString& IconPath = QString(), int IconIndex = 0, const QString& WorkDir = QString()); - QVBoxLayout* m_pMainLayout; QTreeViewEx* m_pSbieTree; diff --git a/SandboxiePlus/SandMan/Views/TraceView.cpp b/SandboxiePlus/SandMan/Views/TraceView.cpp index 41fbee90..8e6ae9f9 100644 --- a/SandboxiePlus/SandMan/Views/TraceView.cpp +++ b/SandboxiePlus/SandMan/Views/TraceView.cpp @@ -1,11 +1,13 @@ #include "stdafx.h" #include "TraceView.h" #include "..\SandMan.h" +#include "..\AddonManager.h" #include "../QSbieAPI/SbieAPI.h" #include "..\Models\TraceModel.h" #include "..\..\MiscHelpers\Common\Common.h" #include "..\..\MiscHelpers\Common\CheckList.h" #include "SbieView.h" +#include //class CTraceFilterProxyModel : public CSortFilterProxyModel //{ @@ -370,6 +372,8 @@ void CTraceView::SetEnabled(bool bSet) void CTraceView::OnShowStack() { + if (!theGUI->GetAddonManager()->HasAddon("DbgHelp")) + theGUI->GetAddonManager()->TryInstallAddon("DbgHelp", this, tr("To use the stack traces feature the DbgHelp.dll and SymSrv.dll are required, do you want to download and install them?")); theAPI->GetGlobalSettings()->SetBool("MonitorStackTrace", m_pShowStack->isChecked()); m_pTrace->m_pStackView->setVisible(m_pShowStack->isChecked()); } @@ -709,29 +713,64 @@ void CTraceView::SaveToFile() } else { - const QVector &ResourceLog = theAPI->GetTrace(); - for (int i = 0; i < ResourceLog.count(); i++) - { - const CTraceEntryPtr& pEntry = ResourceLog.at(i); - - QStringList Line; - Line.append(QDateTime::fromMSecsSinceEpoch(pEntry->GetTimeStamp()).toString("hh:mm:ss.zzz")); - QString Name = pEntry->GetProcessName(); - Line.append(Name.isEmpty() ? tr("Unknown") : Name); - Line.append(QString("%1").arg(pEntry->GetProcessId())); - Line.append(QString("%1").arg(pEntry->GetThreadId())); - Line.append(pEntry->GetTypeStr()); - Line.append(pEntry->GetStautsStr()); - Line.append(pEntry->GetName()); - Line.append(pEntry->GetMessage()); - - File.write(Line.join("\t").toLatin1() + "\n"); - } + SaveToFile(&File); } File.close(); } +void CTraceView::SaveToFileAsync(const CSbieProgressPtr& pProgress, QVector ResourceLog, QIODevice* pFile) +{ + pProgress->ShowMessage(tr("Saving TraceLog...")); + + QByteArray Unknown = "Unknown"; + + quint64 LastTimeStamp = 0; + QByteArray LastTimeStampStr; + for (int i = 0; i < ResourceLog.count() && !pProgress->IsCanceled(); i++) + { + if (i % 10000 == 0) + pProgress->SetProgress(100 * i / ResourceLog.count()); + + const CTraceEntryPtr& pEntry = ResourceLog.at(i); + + if (LastTimeStamp != pEntry->GetTimeStamp()) { + LastTimeStamp = pEntry->GetTimeStamp(); + LastTimeStampStr = QDateTime::fromMSecsSinceEpoch(pEntry->GetTimeStamp()).toString("hh:mm:ss.zzz").toUtf8(); + } + + pFile->write(LastTimeStampStr); + pFile->write("\t"); + QString Name = pEntry->GetProcessName(); + pFile->write(Name.isEmpty() ? Unknown : Name.toUtf8()); + pFile->write("\t"); + pFile->write(QByteArray::number(pEntry->GetProcessId())); + pFile->write("\t"); + pFile->write(QByteArray::number(pEntry->GetThreadId())); + pFile->write("\t"); + pFile->write(pEntry->GetTypeStr().toUtf8()); + pFile->write("\t"); + pFile->write(pEntry->GetStautsStr().toUtf8()); + pFile->write("\t"); + pFile->write(pEntry->GetName().toUtf8()); + pFile->write("\t"); + pFile->write(pEntry->GetMessage().toUtf8()); + pFile->write("\n"); + } + + pProgress->Finish(SB_OK); +} + +bool CTraceView::SaveToFile(QIODevice* pFile) +{ + pFile->write("Timestamp\tProcess\tPID\tTID\tType\tStatus\tName\tMessage\n"); // don't translate log + QVector ResourceLog = theAPI->GetTrace(); + CSbieProgressPtr pProgress = CSbieProgressPtr(new CSbieProgress()); + QtConcurrent::run(CTraceView::SaveToFileAsync, pProgress, ResourceLog, pFile); + theGUI->AddAsyncOp(pProgress, true); + return !pProgress->IsCanceled(); +} + //////////////////////////////////////////////////////////////////////////////////////// // CTraceWindow diff --git a/SandboxiePlus/SandMan/Views/TraceView.h b/SandboxiePlus/SandMan/Views/TraceView.h index e338e3ab..4bfd5805 100644 --- a/SandboxiePlus/SandMan/Views/TraceView.h +++ b/SandboxiePlus/SandMan/Views/TraceView.h @@ -71,6 +71,8 @@ public: void SetEnabled(bool bSet); + static bool SaveToFile(QIODevice* pFile); + public slots: void Refresh(); void Clear(); @@ -93,6 +95,8 @@ protected: void timerEvent(QTimerEvent* pEvent); int m_uTimerID; + static void SaveToFileAsync(const CSbieProgressPtr& pProgress, QVector ResourceLog, QIODevice* pFile); + struct SProgInfo { QString Name; diff --git a/SandboxiePlus/SandMan/Windows/NewBoxWindow.cpp b/SandboxiePlus/SandMan/Windows/NewBoxWindow.cpp deleted file mode 100644 index b3913588..00000000 --- a/SandboxiePlus/SandMan/Windows/NewBoxWindow.cpp +++ /dev/null @@ -1,126 +0,0 @@ -#include "stdafx.h" -#include "NewBoxWindow.h" -#include "SandMan.h" -#include "../MiscHelpers/Common/Settings.h" -#include "Views/SbieView.h" - - -CNewBoxWindow::CNewBoxWindow(QWidget *parent) - : QDialog(parent) -{ - Qt::WindowFlags flags = windowFlags(); - flags |= Qt::CustomizeWindowHint; - //flags &= ~Qt::WindowContextHelpButtonHint; - //flags &= ~Qt::WindowSystemMenuHint; - //flags &= ~Qt::WindowMinMaxButtonsHint; - //flags |= Qt::WindowMinimizeButtonHint; - //flags &= ~Qt::WindowCloseButtonHint; - flags &= ~Qt::WindowContextHelpButtonHint; - //flags &= ~Qt::WindowSystemMenuHint; - setWindowFlags(flags); - - ui.setupUi(this); - this->setWindowTitle(tr("Sandboxie-Plus - Create New Box")); - - connect(ui.buttonBox, SIGNAL(accepted()), SLOT(CreateBox())); - connect(ui.buttonBox, SIGNAL(rejected()), SLOT(reject())); - - QMap Boxes = theAPI->GetAllBoxes(); - - for (int i=0;; i++) { - QString NewName = "New Box"; - if (i > 0) NewName.append(" " + QString::number(i)); - if (Boxes.contains(NewName.toLower().replace(" ", "_"))) - continue; - ui.txtName->setText(NewName); - break; - } - - ui.cmbBoxType->addItem(theGUI->GetBoxIcon(CSandBoxPlus::eHardenedPlus), tr("Hardened Sandbox with Data Protection"), (int)CSandBoxPlus::eHardenedPlus); - ui.cmbBoxType->addItem(theGUI->GetBoxIcon(CSandBoxPlus::eHardened), tr("Security Hardened Sandbox"), (int)CSandBoxPlus::eHardened); - ui.cmbBoxType->addItem(theGUI->GetBoxIcon(CSandBoxPlus::eDefaultPlus), tr("Sandbox with Data Protection"), (int)CSandBoxPlus::eDefaultPlus); - ui.cmbBoxType->addItem(theGUI->GetBoxIcon(CSandBoxPlus::eDefault), tr("Standard Isolation Sandbox (Default)"), (int)CSandBoxPlus::eDefault); - //ui.cmbBoxType->addItem(theGUI->GetBoxIcon(CSandBoxPlus::eInsecure), tr("INSECURE Configuration (please change)"), (int)CSandBoxPlus::eInsecure); - ui.cmbBoxType->addItem(theGUI->GetBoxIcon(CSandBoxPlus::eAppBoxPlus), tr("Application Compartment with Data Protection"), (int)CSandBoxPlus::eAppBoxPlus); - ui.cmbBoxType->addItem(theGUI->GetBoxIcon(CSandBoxPlus::eAppBox), tr("Application Compartment (NO Isolation)"), (int)CSandBoxPlus::eAppBox); - - connect(ui.cmbBoxType, SIGNAL(currentIndexChanged(int)), this, SLOT(OnBoxTypChanged())); - ui.cmbBoxType->setCurrentIndex(3); // default - - ui.txtName->setFocus(); - - //restoreGeometry(theConf->GetBlob("NewBoxWindow/Window_Geometry")); -} - -CNewBoxWindow::~CNewBoxWindow() -{ - //theConf->SetBlob("NewBoxWindow/Window_Geometry", saveGeometry()); -} - -void CNewBoxWindow::OnBoxTypChanged() -{ - int BoxType = ui.cmbBoxType->currentData().toInt(); - - ui.lblBoxInfo->setText(theGUI->GetBoxDescription(BoxType)); - - if(BoxType != CSandBoxPlus::eDefault) - theGUI->CheckCertificate(this); -} - -void CNewBoxWindow::CreateBox() -{ - m_Name = ui.txtName->text(); - int BoxType = ui.cmbBoxType->currentData().toInt(); - - if (!theGUI->GetBoxView()->TestNameAndWarn(m_Name)) - return; - - m_Name.replace(" ", "_"); - - SB_STATUS Status = theAPI->CreateBox(m_Name, true); - - if (!Status.IsError()) - { - CSandBoxPtr pBox = theAPI->GetBoxByName(m_Name); - - pBox->SetBool("AutoRecover", true); - - switch (BoxType) - { - case CSandBoxPlus::eHardenedPlus: - case CSandBoxPlus::eHardened: - //pBox->SetBool("NoSecurityIsolation", false); - pBox->SetBool("UseSecurityMode", true); - //pBox->SetBool("DropAdminRights", true); - //pBox->SetBool("MsiInstallerExemptions", false); - pBox->SetBool("UsePrivacyMode", BoxType == CSandBoxPlus::eHardenedPlus); - break; - case CSandBoxPlus::eDefaultPlus: - case CSandBoxPlus::eDefault: - //pBox->SetBool("NoSecurityIsolation", false); - pBox->SetBool("UseSecurityMode", false); - //pBox->SetBool("DropAdminRights", false); - //pBox->SetBool("MsiInstallerExemptions", false); - //pBox->SetBool("RunServicesAsSystem", false); - pBox->SetBool("UsePrivacyMode", BoxType == CSandBoxPlus::eDefaultPlus); - break; - case CSandBoxPlus::eAppBoxPlus: - case CSandBoxPlus::eAppBox: - //pBox->SetBool("UseSecurityMode", false); - pBox->SetBool("NoSecurityIsolation", true); - //pBox->SetBool("RunServicesAsSystem", true); - pBox->SetBool("UsePrivacyMode", BoxType == CSandBoxPlus::eAppBoxPlus); - //pBox->InsertText("Template", "NoUACProxy"); // proxy is always needed for exes in the box - pBox->InsertText("Template", "RpcPortBindingsExt"); - break; - } - - QRgb rgb = theGUI->GetBoxColor(BoxType); - pBox->SetText("BorderColor", QString("#%1%2%3").arg(qBlue(rgb), 2, 16, QChar('0')).arg(qGreen(rgb), 2, 16, QChar('0')).arg(qRed(rgb), 2, 16, QChar('0')) + ",ttl"); - } - - if(Status.IsError()) - CSandMan::CheckResults(QList() << Status); - else - accept(); -} diff --git a/SandboxiePlus/SandMan/Windows/NewBoxWindow.h b/SandboxiePlus/SandMan/Windows/NewBoxWindow.h deleted file mode 100644 index d72351b1..00000000 --- a/SandboxiePlus/SandMan/Windows/NewBoxWindow.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include -#include "ui_NewBoxWindow.h" -#include "SbiePlusAPI.h" - -class CNewBoxWindow : public QDialog -{ - Q_OBJECT - -public: - CNewBoxWindow(QWidget *parent = Q_NULLPTR); - ~CNewBoxWindow(); - - QString m_Name; - -private slots: - void CreateBox(); - - void OnBoxTypChanged(); - -private: - Ui::NewBoxWindow ui; -}; diff --git a/SandboxiePlus/SandMan/Windows/OptionsWindow.cpp b/SandboxiePlus/SandMan/Windows/OptionsWindow.cpp index 81e320d2..ea14acfd 100644 --- a/SandboxiePlus/SandMan/Windows/OptionsWindow.cpp +++ b/SandboxiePlus/SandMan/Windows/OptionsWindow.cpp @@ -919,7 +919,7 @@ void COptionsWindow::SaveConfig() } catch (SB_STATUS Status) { - theGUI->CheckResults(QList() << Status); + theGUI->CheckResults(QList() << Status, this); } m_pBox->SetRefreshOnChange(true); diff --git a/SandboxiePlus/SandMan/Windows/RecoveryWindow.cpp b/SandboxiePlus/SandMan/Windows/RecoveryWindow.cpp index 76706cd9..8dbe39e7 100644 --- a/SandboxiePlus/SandMan/Windows/RecoveryWindow.cpp +++ b/SandboxiePlus/SandMan/Windows/RecoveryWindow.cpp @@ -579,7 +579,7 @@ void CRecoveryWindow::RecoverFiles(bool bBrowse, QString RecoveryFolder) if (Status.GetStatus() == OP_ASYNC) { connect(Status.GetValue().data(), SIGNAL(Finished()), this, SLOT(FindFiles())); - theGUI->AddAsyncOp(Status.GetValue()); + theGUI->AddAsyncOp(Status.GetValue(), false, tr("Recovering File(s)..."), this); } } diff --git a/SandboxiePlus/SandMan/Windows/SelectBoxWindow.cpp b/SandboxiePlus/SandMan/Windows/SelectBoxWindow.cpp index 29dbfc32..6fafdce4 100644 --- a/SandboxiePlus/SandMan/Windows/SelectBoxWindow.cpp +++ b/SandboxiePlus/SandMan/Windows/SelectBoxWindow.cpp @@ -12,7 +12,98 @@ #include #endif -QTreeWidgetItem* CSelectBoxWindow__GetBoxParent(const QMap& Groups, QMap& GroupItems, QTreeWidget* treeBoxes, const QString& Name, int Depth = 0) +////////////////////////////////////////////////////////////////////////////////////// +// CBoxPicker +// + +CBoxPicker::CBoxPicker(QString DefaultBox, QWidget* parent) + : QWidget(parent) +{ + m_pTreeBoxes = new QTreeWidget(); + m_pTreeBoxes->setHeaderLabels(tr("Sandbox").split("|")); + connect(m_pTreeBoxes, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, SIGNAL(BoxDblClick())); + m_pTreeBoxes->setAlternatingRowColors(theConf->GetBool("Options/AltRowColors", false)); + QVBoxLayout* pLayout = new QVBoxLayout(this); + pLayout->setContentsMargins(0, 0, 0, 0); + pLayout->addWidget(new CFinder(this, this, 0)); + pLayout->insertWidget(0, m_pTreeBoxes); + + this->setMaximumWidth(300); + + if(DefaultBox.isEmpty() && theAPI->IsConnected()) + DefaultBox = theAPI->GetGlobalSettings()->GetText("DefaultBox", "DefaultBox"); + + LoadBoxed("", DefaultBox); +} + +void CBoxPicker::SetFilter(const QString& Exp, int iOptions, int Column) +{ + LoadBoxed(Exp); +} + +void CBoxPicker::LoadBoxed(const QString& Filter, const QString& SelectBox) +{ + m_pTreeBoxes->clear(); + + QList Boxes = theAPI->GetAllBoxes().values(); // map is sorted by key (box name) + QMap Groups = theGUI->GetBoxView()->GetGroups(); + + if (theConf->GetBool("MainWindow/BoxTree_UseOrder", false)) { + QMultiMap Boxes2; + foreach(const CSandBoxPtr &pBox, Boxes) { + Boxes2.insertMulti(GetBoxOrder(Groups, pBox->GetName()), pBox); + } + Boxes = Boxes2.values(); + } + + QFileIconProvider IconProvider; + bool ColorIcons = theConf->GetBool("Options/ColorBoxIcons", false); + + QMap GroupItems; + foreach(const CSandBoxPtr &pBox, Boxes) + { + if (!pBox->IsEnabled() || !pBox->GetBool("ShowForRunIn", true)) + continue; + + if (!Filter.isEmpty() && !pBox->GetName().contains(Filter, Qt::CaseInsensitive)) + continue; + + CSandBoxPlus* pBoxEx = qobject_cast(pBox.data()); + + QTreeWidgetItem* pParent = GetBoxParent(Groups, GroupItems, m_pTreeBoxes, pBox->GetName()); + + QTreeWidgetItem* pItem = new QTreeWidgetItem(); + pItem->setText(0, pBox->GetName().replace("_", " ")); + pItem->setData(0, Qt::UserRole, pBox->GetName()); + QIcon Icon; + QString Action = pBox->GetText("DblClickAction"); + if (!Action.isEmpty() && Action.left(1) != "!") + Icon = IconProvider.icon(QFileInfo(pBoxEx->GetCommandFile(Action))); + else if(ColorIcons) + Icon = theGUI->GetColorIcon(pBoxEx->GetColor(), pBox->GetActiveProcessCount()); + else + Icon = theGUI->GetBoxIcon(pBoxEx->GetType(), pBox->GetActiveProcessCount() != 0); + pItem->setData(0, Qt::DecorationRole, Icon); + if (pParent) + pParent->addChild(pItem); + else + m_pTreeBoxes->addTopLevelItem(pItem); + + if (pBox->GetName().compare(SelectBox, Qt::CaseInsensitive) == 0) + m_pTreeBoxes->setCurrentItem(pItem); + } + + m_pTreeBoxes->expandAll(); +} + +QString CBoxPicker::GetBoxName() const +{ + auto pItem = m_pTreeBoxes->currentItem(); + if (!pItem) return QString(); + return pItem->data(0, Qt::UserRole).toString(); +} + +QTreeWidgetItem* CBoxPicker::GetBoxParent(const QMap& Groups, QMap& GroupItems, QTreeWidget* treeBoxes, const QString& Name, int Depth) { if (Depth > 100) return NULL; @@ -27,7 +118,7 @@ QTreeWidgetItem* CSelectBoxWindow__GetBoxParent(const QMap QFont fnt = pParent->font(0); fnt.setBold(true); pParent->setFont(0, fnt); - if (QTreeWidgetItem* pParent2 = CSelectBoxWindow__GetBoxParent(Groups, GroupItems, treeBoxes, I.key(), ++Depth)) + if (QTreeWidgetItem* pParent2 = GetBoxParent(Groups, GroupItems, treeBoxes, I.key(), ++Depth)) pParent2->addChild(pParent); else treeBoxes->addTopLevelItem(pParent); @@ -38,7 +129,7 @@ QTreeWidgetItem* CSelectBoxWindow__GetBoxParent(const QMap return NULL; } -double CSelectBoxWindow__GetBoxOrder(const QMap& Groups, const QString& Name, double value = 0.0, int Depth = 0) +double CBoxPicker::GetBoxOrder(const QMap& Groups, const QString& Name, double value, int Depth) { if (Depth > 100) return 1000000000; @@ -48,12 +139,16 @@ double CSelectBoxWindow__GetBoxOrder(const QMap& Groups, c value = double(Pos) + value / 10.0; if (I.key().isEmpty()) return value; - return CSelectBoxWindow__GetBoxOrder(Groups, I.key(), value, ++Depth); + return GetBoxOrder(Groups, I.key(), value, ++Depth); } } return 1000000000; } +////////////////////////////////////////////////////////////////////////////////////// +// CSelectBoxWindow +// + CSelectBoxWindow::CSelectBoxWindow(const QStringList& Commands, const QString& BoxName, const QString& WrkDir, QWidget *parent) : QDialog(parent) { @@ -88,8 +183,6 @@ CSelectBoxWindow::CSelectBoxWindow(const QStringList& Commands, const QString& B ui.setupUi(this); this->setWindowTitle(tr("Sandboxie-Plus - Run Sandboxed")); - ui.treeBoxes->setAlternatingRowColors(theConf->GetBool("Options/AltRowColors", false)); - connect(ui.radBoxed, SIGNAL(clicked(bool)), this, SLOT(OnBoxType())); connect(ui.radBoxedNew, SIGNAL(clicked(bool)), this, SLOT(OnBoxType())); connect(ui.radUnBoxed, SIGNAL(clicked(bool)), this, SLOT(OnBoxType())); @@ -97,20 +190,12 @@ CSelectBoxWindow::CSelectBoxWindow(const QStringList& Commands, const QString& B connect(ui.buttonBox, SIGNAL(accepted()), SLOT(OnRun())); connect(ui.buttonBox, SIGNAL(rejected()), SLOT(reject())); - connect(ui.treeBoxes, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, SLOT(OnBoxDblClick(QTreeWidgetItem*))); + m_pBoxPicker = new CBoxPicker(BoxName); + connect(m_pBoxPicker, SIGNAL(BoxDblClick()), this, SLOT(OnRun())); + ui.treeBoxes->parentWidget()->layout()->replaceWidget(ui.treeBoxes, m_pBoxPicker); + delete ui.treeBoxes; - QWidget* pWidget = new QWidget(); - QVBoxLayout* pLayout = new QVBoxLayout(pWidget); - pLayout->setContentsMargins(0, 0, 0, 0); - pLayout->addWidget(new CFinder(this, pWidget, 0)); - ui.treeBoxes->parentWidget()->layout()->replaceWidget(ui.treeBoxes, pWidget); - pLayout->insertWidget(0, ui.treeBoxes); - - LoadBoxed("", BoxName); - - ui.treeBoxes->setFocus(); - - //ui.treeBoxes->sortByColumn(0, Qt::AscendingOrder); + m_pBoxPicker->setFocus(); //restoreGeometry(theConf->GetBlob("SelectBoxWindow/Window_Geometry")); } @@ -126,88 +211,21 @@ void CSelectBoxWindow::closeEvent(QCloseEvent *e) this->deleteLater(); } -void CSelectBoxWindow::SetFilter(const QString& Exp, int iOptions, int Column) -{ - LoadBoxed(Exp); -} - -void CSelectBoxWindow::LoadBoxed(const QString& Filter, const QString& SelectBox) -{ - ui.treeBoxes->clear(); - - QList Boxes = theAPI->GetAllBoxes().values(); // map is sorted by key (box name) - QMap Groups = theGUI->GetBoxView()->GetGroups(); - - if (theConf->GetBool("MainWindow/BoxTree_UseOrder", false)) { - QMultiMap Boxes2; - foreach(const CSandBoxPtr &pBox, Boxes) { - Boxes2.insertMulti(CSelectBoxWindow__GetBoxOrder(Groups, pBox->GetName()), pBox); - } - Boxes = Boxes2.values(); - } - - QFileIconProvider IconProvider; - bool ColorIcons = theConf->GetBool("Options/ColorBoxIcons", false); - - QMap GroupItems; - foreach(const CSandBoxPtr &pBox, Boxes) - { - if (!pBox->IsEnabled() || !pBox->GetBool("ShowForRunIn", true)) - continue; - - if (!Filter.isEmpty() && !pBox->GetName().contains(Filter, Qt::CaseInsensitive)) - continue; - - CSandBoxPlus* pBoxEx = qobject_cast(pBox.data()); - - QTreeWidgetItem* pParent = CSelectBoxWindow__GetBoxParent(Groups, GroupItems, ui.treeBoxes, pBox->GetName()); - - QTreeWidgetItem* pItem = new QTreeWidgetItem(); - pItem->setText(0, pBox->GetName().replace("_", " ")); - pItem->setData(0, Qt::UserRole, pBox->GetName()); - QIcon Icon; - QString Action = pBox->GetText("DblClickAction"); - if (!Action.isEmpty() && Action.left(1) != "!") - Icon = IconProvider.icon(QFileInfo(pBoxEx->GetCommandFile(Action))); - else if(ColorIcons) - Icon = theGUI->GetColorIcon(pBoxEx->GetColor(), pBox->GetActiveProcessCount()); - else - Icon = theGUI->GetBoxIcon(pBoxEx->GetType(), pBox->GetActiveProcessCount() != 0); - pItem->setData(0, Qt::DecorationRole, Icon); - if (pParent) - pParent->addChild(pItem); - else - ui.treeBoxes->addTopLevelItem(pItem); - - if (pBox->GetName().compare(SelectBox, Qt::CaseInsensitive) == 0) - ui.treeBoxes->setCurrentItem(pItem); - } - - ui.treeBoxes->expandAll(); -} - void CSelectBoxWindow::OnBoxType() { - ui.treeBoxes->setEnabled(ui.radBoxed->isChecked()); -} - -void CSelectBoxWindow::OnBoxDblClick(QTreeWidgetItem*) -{ - OnRun(); + m_pBoxPicker->setEnabled(ui.radBoxed->isChecked()); } void CSelectBoxWindow::OnRun() { - QTreeWidgetItem* pItem = ui.treeBoxes->currentItem(); - QString BoxName; + if (ui.radUnBoxed->isChecked()) { if (QMessageBox("Sandboxie-Plus", tr("Are you sure you want to run the program outside the sandbox?"), QMessageBox::Question, QMessageBox::Yes, QMessageBox::No | QMessageBox::Default | QMessageBox::Escape, QMessageBox::NoButton, this).exec() != QMessageBox::Yes) return; - pItem = NULL; } - else if (ui.radBoxedNew->isChecked()) + else if (ui.radBoxedNew->isChecked()) { BoxName = theGUI->GetBoxView()->AddNewBox(true); if (BoxName.isEmpty()) { @@ -215,21 +233,18 @@ void CSelectBoxWindow::OnRun() return; } } - else if (pItem == NULL) { - QMessageBox("Sandboxie-Plus", tr("Please select a sandbox."), QMessageBox::Information, QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton, this).exec(); - return; - } - else { - BoxName = pItem->data(0, Qt::UserRole).toString(); + else + { + BoxName = m_pBoxPicker->GetBoxName(); + if (BoxName.isEmpty()) { + QMessageBox("Sandboxie-Plus", tr("Please select a sandbox."), QMessageBox::Information, QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton, this).exec(); + return; + } } - - //QList Results; - foreach(const QString & Command, m_Commands) { - theAPI->RunStart(BoxName, Command, ui.chkAdmin->isChecked(), m_WrkDir); - } - //CSandMan::CheckResults(Results); + foreach(const QString & Command, m_Commands) + theGUI->RunStart(BoxName, Command, ui.chkAdmin->isChecked(), m_WrkDir); setResult(1); close(); -} +} \ No newline at end of file diff --git a/SandboxiePlus/SandMan/Windows/SelectBoxWindow.h b/SandboxiePlus/SandMan/Windows/SelectBoxWindow.h index b374499c..1b07c01d 100644 --- a/SandboxiePlus/SandMan/Windows/SelectBoxWindow.h +++ b/SandboxiePlus/SandMan/Windows/SelectBoxWindow.h @@ -4,6 +4,38 @@ #include "ui_SelectBoxWindow.h" #include "SbiePlusAPI.h" +////////////////////////////////////////////////////////////////////////////////////// +// CBoxPicker +// + +class CBoxPicker : public QWidget +{ + Q_OBJECT + +public: + CBoxPicker(QString DefaultBox = "", QWidget *parent = Q_NULLPTR); + + void LoadBoxed(const QString& Filter = QString(), const QString& SelectBox = QString()); + + QString GetBoxName() const; + + static QTreeWidgetItem* GetBoxParent(const QMap& Groups, QMap& GroupItems, QTreeWidget* treeBoxes, const QString& Name, int Depth = 0); + static double GetBoxOrder(const QMap& Groups, const QString& Name, double value = 0.0, int Depth = 0); + +signals: + void BoxDblClick(); + +private slots: + void SetFilter(const QString& Exp, int iOptions, int Column); + +private: + QTreeWidget *m_pTreeBoxes; +}; + +////////////////////////////////////////////////////////////////////////////////////// +// CSelectBoxWindow +// + class CSelectBoxWindow : public QDialog { Q_OBJECT @@ -13,20 +45,16 @@ public: ~CSelectBoxWindow(); private slots: - void SetFilter(const QString& Exp, int iOptions, int Column); - - void OnBoxDblClick(QTreeWidgetItem*); void OnBoxType(); void OnRun(); protected: void closeEvent(QCloseEvent* e); - void LoadBoxed(const QString& Filter = QString(), const QString& SelectBox = QString()); - QStringList m_Commands; QString m_WrkDir; private: Ui::SelectBoxWindow ui; + CBoxPicker* m_pBoxPicker; }; diff --git a/SandboxiePlus/SandMan/Windows/SettingsWindow.cpp b/SandboxiePlus/SandMan/Windows/SettingsWindow.cpp index 432b310a..ce42f15c 100644 --- a/SandboxiePlus/SandMan/Windows/SettingsWindow.cpp +++ b/SandboxiePlus/SandMan/Windows/SettingsWindow.cpp @@ -12,6 +12,7 @@ #include "../MiscHelpers/Archive/ArchiveFS.h" #include #include "../Wizards/TemplateWizard.h" +#include "../AddonManager.h" #include @@ -111,6 +112,8 @@ quint32 g_FeatureFlags = 0; QByteArray g_Certificate; SCertInfo g_CertInfo = { 0 }; +void COptionsWindow__AddCertIcon(QWidget* pOriginalWidget); + CSettingsWindow::CSettingsWindow(QWidget* parent) : CConfigDialog(parent) { @@ -144,11 +147,12 @@ CSettingsWindow::CSettingsWindow(QWidget* parent) ui.tabs->setTabIcon(0, CSandMan::GetIcon("Config")); ui.tabs->setTabIcon(1, CSandMan::GetIcon("Shell")); ui.tabs->setTabIcon(2, CSandMan::GetIcon("Design")); - ui.tabs->setTabIcon(3, CSandMan::GetIcon("Support")); - ui.tabs->setTabIcon(4, CSandMan::GetIcon("Advanced")); - ui.tabs->setTabIcon(5, CSandMan::GetIcon("Control")); - ui.tabs->setTabIcon(6, CSandMan::GetIcon("Compatibility")); - ui.tabs->setTabIcon(7, CSandMan::GetIcon("Editor")); + ui.tabs->setTabIcon(3, CSandMan::GetIcon("Plugins")); + ui.tabs->setTabIcon(4, CSandMan::GetIcon("Support")); + ui.tabs->setTabIcon(5, CSandMan::GetIcon("Advanced")); + ui.tabs->setTabIcon(6, CSandMan::GetIcon("Control")); + ui.tabs->setTabIcon(7, CSandMan::GetIcon("Compatibility")); + ui.tabs->setTabIcon(8, CSandMan::GetIcon("Editor")); ui.tabsGeneral->setCurrentIndex(0); ui.tabsGeneral->setTabIcon(0, CSandMan::GetIcon("Presets")); @@ -162,6 +166,14 @@ CSettingsWindow::CSettingsWindow(QWidget* parent) ui.tabsGUI->setTabIcon(0, CSandMan::GetIcon("Interface")); ui.tabsGUI->setTabIcon(1, CSandMan::GetIcon("Monitor")); + ui.tabsAddons->setCurrentIndex(0); + ui.tabsAddons->setTabIcon(0, CSandMan::GetIcon("Plugin")); + //ui.tabsAddons->setTabIcon(1, CSandMan::GetIcon("Qube")); + + ui.tabsSupport->setCurrentIndex(0); + ui.tabsSupport->setTabIcon(0, CSandMan::GetIcon("Cert")); + ui.tabsSupport->setTabIcon(1, CSandMan::GetIcon("ReloadIni")); + ui.tabsAdvanced->setCurrentIndex(0); ui.tabsAdvanced->setTabIcon(0, CSandMan::GetIcon("Options")); ui.tabsAdvanced->setTabIcon(1, CSandMan::GetIcon("EditIni")); @@ -216,10 +228,9 @@ CSettingsWindow::CSettingsWindow(QWidget* parent) ui.uiLang->addItem(tr("Auto Detection"), ""); ui.uiLang->addItem(tr("No Translation"), "native"); - C7zFileEngineHandler LangFS(QApplication::applicationDirPath() + "/translations.7z", "lang", this); - QString langDir; - if (LangFS.IsOpen()) + C7zFileEngineHandler LangFS("lang", this); + if (LangFS.Open(QApplication::applicationDirPath() + "/translations.7z")) langDir = LangFS.Prefix() + "/"; else langDir = QApplication::applicationDirPath() + "/translations/"; @@ -352,6 +363,26 @@ CSettingsWindow::CSettingsWindow(QWidget* parent) m_RunChanged = false; // + // Addons + QObject::connect(theGUI->GetAddonManager(), &CAddonManager::DataUpdated, this, [=]() { + ui.lblUpdateAddons->setVisible(false); + OnLoadAddon(); + }); + + connect(ui.btnInstallAddon, SIGNAL(clicked(bool)), this, SLOT(OnInstallAddon())); + connect(ui.btnRemoveAddon, SIGNAL(clicked(bool)), this, SLOT(OnRemoveAddon())); + + if (theConf->GetInt("Options/CheckForAddons", 2) == 1) { + ui.lblUpdateAddons->setVisible(false); + theGUI->GetAddonManager()->UpdateAddons(); + } else { + connect(ui.lblUpdateAddons, &QLabel::linkActivated, this, [=]() { + theGUI->GetAddonManager()->UpdateAddons(); + }); + } + + // + // Advanced Config connect(ui.cmbDefault, SIGNAL(currentIndexChanged(int)), this, SLOT(OnGeneralChanged())); connect(ui.chkAutoRoot, SIGNAL(stateChanged(int)), this, SLOT(OnRootChanged())); // not sbie ini @@ -419,7 +450,7 @@ CSettingsWindow::CSettingsWindow(QWidget* parent) connect(ui.lblSupport, SIGNAL(linkActivated(const QString&)), theGUI, SLOT(OpenUrl(const QString&))); connect(ui.lblSupportCert, SIGNAL(linkActivated(const QString&)), theGUI, SLOT(OpenUrl(const QString&))); connect(ui.lblCertExp, SIGNAL(linkActivated(const QString&)), theGUI, SLOT(OpenUrl(const QString&))); - //connect(ui.lblInsiderInfo, SIGNAL(linkActivated(const QString&)), theGUI, SLOT(OpenUrl(const QString&))); + connect(ui.lblInsiderInfo, SIGNAL(linkActivated(const QString&)), theGUI, SLOT(OpenUrl(const QString&))); m_CertChanged = false; connect(ui.txtCertificate, SIGNAL(textChanged()), this, SLOT(CertChanged())); @@ -433,22 +464,28 @@ CSettingsWindow::CSettingsWindow(QWidget* parent) "SIGNATURE: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==" ); + connect(ui.chkNoCheck, SIGNAL(stateChanged(int)), this, SLOT(OnOptChanged())); + + // + connect(ui.lblCurrent, SIGNAL(linkActivated(const QString&)), this, SLOT(OnUpdate(const QString&))); connect(ui.lblStable, SIGNAL(linkActivated(const QString&)), this, SLOT(OnUpdate(const QString&))); connect(ui.lblPreview, SIGNAL(linkActivated(const QString&)), this, SLOT(OnUpdate(const QString&))); - //connect(ui.lblInsider, SIGNAL(linkActivated(const QString&)), this, SLOT(OnUpdate(const QString&))); + connect(ui.lblInsider, SIGNAL(linkActivated(const QString&)), this, SLOT(OnUpdate(const QString&))); //connect(ui.lblInsiderInfo, SIGNAL(linkActivated(const QString&)), this, SLOT(OnUpdate(const QString&))); connect(ui.chkAutoUpdate, SIGNAL(toggled(bool)), this, SLOT(UpdateUpdater())); connect(ui.radStable, SIGNAL(toggled(bool)), this, SLOT(UpdateUpdater())); connect(ui.radPreview, SIGNAL(toggled(bool)), this, SLOT(UpdateUpdater())); - //connect(ui.radInsider, SIGNAL(toggled(bool)), this, SLOT(UpdateUpdater())); + connect(ui.radInsider, SIGNAL(toggled(bool)), this, SLOT(UpdateUpdater())); connect(ui.cmbUpdate, SIGNAL(currentIndexChanged(int)), this, SLOT(OnOptChanged())); connect(ui.cmbRelease, SIGNAL(currentIndexChanged(int)), this, SLOT(OnOptChanged())); - connect(ui.chkNoCheck, SIGNAL(stateChanged(int)), this, SLOT(OnOptChanged())); + connect(ui.chkUpdateIssues, SIGNAL(toggled(bool)), this, SLOT(OnOptChanged())); + connect(ui.chkUpdateAddons, SIGNAL(toggled(bool)), this, SLOT(OnOptChanged())); + // connect(ui.tabs, SIGNAL(currentChanged(int)), this, SLOT(OnTab())); @@ -464,6 +501,9 @@ CSettingsWindow::CSettingsWindow(QWidget* parent) connect(ui.buttonBox->button(QDialogButtonBox::Apply), SIGNAL(clicked(bool)), this, SLOT(apply())); connect(ui.buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + //COptionsWindow__AddCertIcon(ui.chkUpdateTemplates); + COptionsWindow__AddCertIcon(ui.chkUpdateIssues); + this->installEventFilter(this); // prevent enter from closing the dialog restoreGeometry(theConf->GetBlob("SettingsWindow/Window_Geometry")); @@ -693,7 +733,7 @@ void CSettingsWindow::OnDelCommand() OnRunChanged(); } -Qt::CheckState CSettingsWindow__IsContextMenu() +Qt::CheckState CSettingsWindow::IsContextMenu() { //QSettings Package("HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes\\PackagedCom\\Package", QSettings::NativeFormat); QSettings Package("HKEY_CURRENT_USER\\Software\\Classes\\PackagedCom\\Package", QSettings::NativeFormat); @@ -710,7 +750,7 @@ Qt::CheckState CSettingsWindow__IsContextMenu() return Qt::Unchecked; // not set up } -void CSettingsWindow__AddContextMenu(bool bAlwaysClassic) +void CSettingsWindow::AddContextMenu(bool bAlwaysClassic) { QSettings CurrentVersion("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", QSettings::NativeFormat); if (CurrentVersion.value("CurrentBuild").toInt() >= 22000 && !bAlwaysClassic) // Windows 11 @@ -731,7 +771,7 @@ void CSettingsWindow__AddContextMenu(bool bAlwaysClassic) QApplication::applicationDirPath().replace("/", "\\") + "\\Start.exe"); } -void CSettingsWindow__RemoveContextMenu() +void CSettingsWindow::RemoveContextMenu() { QSettings CurrentVersion("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", QSettings::NativeFormat); if (CurrentVersion.value("CurrentBuild").toInt() >= 22000) // Windows 11 @@ -745,11 +785,13 @@ void CSettingsWindow__RemoveContextMenu() CSbieUtils::RemoveContextMenu(); } -void CSettingsWindow__AddBrowserIcon() +bool CSettingsWindow::AddBrowserIcon() { QString Path = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation).replace("/", "\\"); Path += "\\" + CSettingsWindow::tr("Sandboxed Web Browser") + ".lnk"; - CSbieUtils::CreateShortcut(theAPI, Path, "", "", "default_browser"); + QString StartExe = theAPI->GetSbiePath() + "\\SandMan.exe"; + QString BoxName = theAPI->GetGlobalSettings()->GetText("DefaultBox", "DefaultBox"); + return CSbieUtils::CreateShortcut(StartExe, Path, "", BoxName, "default_browser"); } void CSettingsWindow::LoadSettings() @@ -771,7 +813,7 @@ void CSettingsWindow::LoadSettings() ui.chkSvcStart->setEnabled(false); } - ui.chkShellMenu->setCheckState(CSettingsWindow__IsContextMenu()); + ui.chkShellMenu->setCheckState(IsContextMenu()); ui.chkShellMenu2->setChecked(CSbieUtils::HasContextMenu2()); ui.chkAlwaysDefault->setChecked(theConf->GetBool("Options/RunInDefaultBox", false)); @@ -817,6 +859,7 @@ void CSettingsWindow::LoadSettings() ui.chkCompactTray->setChecked(theConf->GetBool("Options/CompactTray", false)); ui.chkBoxOpsNotify->setChecked(theConf->GetBool("Options/AutoBoxOpsNotify", false)); + OnLoadAddon(); if (theAPI->IsConnected()) { @@ -926,14 +969,17 @@ void CSettingsWindow::LoadSettings() UpdateCert(); + + ui.chkNoCheck->setChecked(theConf->GetBool("Options/NoSupportCheck", false)); + if(ui.chkNoCheck->isCheckable() && !g_CertInfo.expired) + ui.chkNoCheck->setVisible(false); // hide if not relevant + ui.chkAutoUpdate->setCheckState(CSettingsWindow__Int2Chk(theConf->GetInt("Options/CheckForUpdates", 2))); - //ui.chkAutoDownload->setCheckState(CSettingsWindow__Int2Chk(theConf->GetInt("Options/DownloadUpdates", 0))); - //ui.chkAutoInstall->setCheckState(CSettingsWindow__Int2Chk(theConf->GetInt("Options/InstallUpdates", 0))); QString ReleaseChannel = theConf->GetString("Options/ReleaseChannel", "stable"); ui.radStable->setChecked(ReleaseChannel == "stable"); ui.radPreview->setChecked(ReleaseChannel == "preview"); - //ui.radInsider->setChecked(ReleaseChannel == "insider"); + ui.radInsider->setChecked(ReleaseChannel == "insider"); m_HoldChange = true; UpdateUpdater(); @@ -942,10 +988,12 @@ void CSettingsWindow::LoadSettings() ui.cmbUpdate->setCurrentIndex(ui.cmbUpdate->findData(theConf->GetString("Options/OnNewUpdate", "ignore"))); ui.cmbRelease->setCurrentIndex(ui.cmbRelease->findData(theConf->GetString("Options/OnNewRelease", "download"))); + //ui.chkUpdateTemplates->setCheckState(CSettingsWindow__Int2Chk(theConf->GetInt("Options/CheckForTemplates", 2))); + ui.chkUpdateAddons->setCheckState(CSettingsWindow__Int2Chk(theConf->GetInt("Options/CheckForAddons", 2))); + ui.chkUpdateIssues->setCheckState(CSettingsWindow__Int2Chk(theConf->GetInt("Options/CheckForIssues", 2))); - ui.chkNoCheck->setChecked(theConf->GetBool("Options/NoSupportCheck", false)); - if(ui.chkNoCheck->isCheckable() && !g_CertInfo.expired) - ui.chkNoCheck->setVisible(false); // hide if not relevant + //ui.chkUpdateTemplates->setEnabled(g_CertInfo.valid && !g_CertInfo.expired); + ui.chkUpdateIssues->setEnabled(g_CertInfo.valid && !g_CertInfo.expired); } void CSettingsWindow::UpdateCert() @@ -988,7 +1036,7 @@ void CSettingsWindow::UpdateCert() ui.txtCertificate->setPalette(palette); } - //ui.radInsider->setEnabled(g_CertInfo.insider); + ui.radInsider->setEnabled(g_CertInfo.insider); } void CSettingsWindow::UpdateUpdater() @@ -1000,7 +1048,7 @@ void CSettingsWindow::UpdateUpdater() ui.lblRevision->setText(QString()); } else { - if (ui.radStable->isChecked() && (!g_CertInfo.valid)) { + if (ui.radStable->isChecked() && (!g_CertInfo.valid || g_CertInfo.expired)) { ui.cmbUpdate->setEnabled(false); ui.cmbUpdate->setCurrentIndex(ui.cmbUpdate->findData("ignore")); ui.lblRevision->setText(tr("Supporter certificate required")); @@ -1096,14 +1144,14 @@ void CSettingsWindow::SaveSettings() theAPI->GetUserSettings()->SetBool("SbieCtrl_EnableAutoStart", false); } - if (ui.chkShellMenu->checkState() != CSettingsWindow__IsContextMenu()) + if (ui.chkShellMenu->checkState() != IsContextMenu()) { if (ui.chkShellMenu->isChecked()) { CSecretCheckBox* SecretCheckBox = qobject_cast(ui.chkShellMenu); - CSettingsWindow__AddContextMenu(SecretCheckBox && SecretCheckBox->IsSecretSet()); + AddContextMenu(SecretCheckBox && SecretCheckBox->IsSecretSet()); } else - CSettingsWindow__RemoveContextMenu(); + RemoveContextMenu(); } if (ui.chkShellMenu2->isChecked() != CSbieUtils::HasContextMenu2()) { @@ -1285,7 +1333,7 @@ void CSettingsWindow::SaveSettings() } catch (SB_STATUS Status) { - theGUI->CheckResults(QList() << Status); + theGUI->CheckResults(QList() << Status, theGUI); } } @@ -1321,23 +1369,25 @@ void CSettingsWindow::SaveSettings() m_CertChanged = false; } + theConf->SetValue("Options/NoSupportCheck", ui.chkNoCheck->isChecked()); + theConf->SetValue("Options/CheckForUpdates", CSettingsWindow__Chk2Int(ui.chkAutoUpdate->checkState())); - //theConf->SetValue("Options/DownloadUpdates", CSettingsWindow__Chk2Int(ui.chkAutoDownload->checkState())); - //theConf->SetValue("Options/InstallUpdates", CSettingsWindow__Chk2Int(ui.chkAutoInstall->checkState())); QString ReleaseChannel; if (ui.radStable->isChecked()) ReleaseChannel = "stable"; else if (ui.radPreview->isChecked()) ReleaseChannel = "preview"; - //else if (ui.radInsider->isChecked()) - // ReleaseChannel = "insider"; + else if (ui.radInsider->isChecked()) + ReleaseChannel = "insider"; if(!ReleaseChannel.isEmpty()) theConf->SetValue("Options/ReleaseChannel", ReleaseChannel); theConf->SetValue("Options/OnNewUpdate", ui.cmbUpdate->currentData()); theConf->SetValue("Options/OnNewRelease", ui.cmbRelease->currentData()); - theConf->SetValue("Options/NoSupportCheck", ui.chkNoCheck->isChecked()); + //theConf->SetValue("Options/CheckForTemplates", CSettingsWindow__Chk2Int(ui.chkUpdateTemplates->checkState())); + theConf->SetValue("Options/CheckForAddons", CSettingsWindow__Chk2Int(ui.chkUpdateAddons->checkState())); + theConf->SetValue("Options/CheckForIssues", CSettingsWindow__Chk2Int(ui.chkUpdateIssues->checkState())); emit OptionsChanged(m_bRebuildUI); } @@ -1435,6 +1485,49 @@ void CSettingsWindow::OnOptChanged() ui.buttonBox->button(QDialogButtonBox::Apply)->setEnabled(true); } +void CSettingsWindow::OnLoadAddon() +{ + ui.treeAddons->clear(); + foreach(const CAddonPtr pAddon, theGUI->GetAddonManager()->GetAddons()) { + + QTreeWidgetItem* pItem = new QTreeWidgetItem; + pItem->setText(0, pAddon->GetLocalizedEntry("name")); + if(!pAddon->Data["mandatory"].toBool()) + pItem->setData(0, Qt::UserRole, pAddon->Id); + pItem->setIcon(0, pAddon->Data.contains("icon") ? CSandMan::GetIcon(pAddon->Data["icon"].toString()) : CSandMan::GetIcon("Addon")); + pItem->setText(1, pAddon->Installed ? tr("Installed") : ""); + pItem->setText(2, pAddon->GetLocalizedEntry("description")); + + ui.treeAddons->addTopLevelItem(pItem); + } +} + +void CSettingsWindow::OnInstallAddon() +{ + QTreeWidgetItem* pItem = ui.treeAddons->currentItem(); + if (!pItem) + return; + + QString Id = pItem->data(0, Qt::UserRole).toString(); + SB_PROGRESS Status = theGUI->GetAddonManager()->TryInstallAddon(Id, this); + if (Status.GetStatus() == OP_ASYNC) connect(Status.GetValue().data(), SIGNAL(Finished()), this, SLOT(OnLoadAddon())); +} + +void CSettingsWindow::OnRemoveAddon() +{ + QTreeWidgetItem* pItem = ui.treeAddons->currentItem(); + if (!pItem) + return; + + QString Id = pItem->data(0, Qt::UserRole).toString(); + if (Id.isEmpty()) { + QMessageBox::warning(this, "Sandboxie-Plus", tr("This Addon is mandatory and can not be removed.")); + return; + } + SB_PROGRESS Status = theGUI->GetAddonManager()->TryRemoveAddon(Id, this); + if (Status.GetStatus() == OP_ASYNC) connect(Status.GetValue().data(), SIGNAL(Finished()), this, SLOT(OnLoadAddon())); +} + void CSettingsWindow::OnBrowse() { QString Value = QFileDialog::getExistingDirectory(this, tr("Select Directory")).replace("/", "\\"); @@ -1477,52 +1570,55 @@ void CSettingsWindow::OnTab(QWidget* pTab) else if (pTab == ui.tabCompat && m_CompatLoaded != 1 && theAPI->IsConnected()) { if(m_CompatLoaded == 0) - theGUI->GetCompat()->RunCheck(); - - ui.treeCompat->clear(); - - bool bNew = false; - - QMap Templates = theGUI->GetCompat()->GetTemplates(); - for (QMap::iterator I = Templates.begin(); I != Templates.end(); ++I) - { - if (I.value() == CSbieTemplates::eNone) - continue; - - QSharedPointer pTemplate = QSharedPointer(new CSbieIni("Template_" + I.key(), theAPI)); - - QString Title = pTemplate->GetText("Tmpl.Title", "", false, true, true); - if (Title.left(1) == "#") - { - int End = Title.mid(1).indexOf(","); - if (End == -1) End = Title.length() - 1; - int MsgNum = Title.mid(1, End).toInt(); - Title = theAPI->GetSbieMsgStr(MsgNum, theGUI->m_LanguageId).arg(Title.mid(End + 2)).arg(""); - } - //if (Title.isEmpty()) Title = Name; - - QTreeWidgetItem* pItem = new QTreeWidgetItem(); - pItem->setText(0, Title); - pItem->setData(0, Qt::UserRole, "Template_" + I.key()); - if((I.value() & CSbieTemplates::eDisabled) != 0) - pItem->setCheckState(0, Qt::Unchecked); - else if((I.value() & CSbieTemplates::eEnabled) != 0) - pItem->setCheckState(0, Qt::Checked); - else { - pItem->setCheckState(0, Qt::PartiallyChecked); - bNew = true; - } - ui.treeCompat->addTopLevelItem(pItem); - } - - m_CompatLoaded = 1; - if(bNew) - OnCompatChanged(); - - LoadTemplates(); + theGUI->CheckCompat(this, "OnCompat"); } } +void CSettingsWindow::OnCompat() +{ + ui.treeCompat->clear(); + + bool bNew = false; + + QMap Templates = theGUI->GetCompat()->GetTemplates(); + for (QMap::iterator I = Templates.begin(); I != Templates.end(); ++I) + { + if (I.value() == CSbieTemplates::eNone) + continue; + + QSharedPointer pTemplate = QSharedPointer(new CSbieIni("Template_" + I.key(), theAPI)); + + QString Title = pTemplate->GetText("Tmpl.Title", "", false, true, true); + if (Title.left(1) == "#") + { + int End = Title.mid(1).indexOf(","); + if (End == -1) End = Title.length() - 1; + int MsgNum = Title.mid(1, End).toInt(); + Title = theAPI->GetSbieMsgStr(MsgNum, theGUI->m_LanguageId).arg(Title.mid(End + 2)).arg(""); + } + //if (Title.isEmpty()) Title = Name; + + QTreeWidgetItem* pItem = new QTreeWidgetItem(); + pItem->setText(0, Title); + pItem->setData(0, Qt::UserRole, "Template_" + I.key()); + if((I.value() & CSbieTemplates::eDisabled) != 0) + pItem->setCheckState(0, Qt::Unchecked); + else if((I.value() & CSbieTemplates::eEnabled) != 0) + pItem->setCheckState(0, Qt::Checked); + else { + pItem->setCheckState(0, Qt::PartiallyChecked); + bNew = true; + } + ui.treeCompat->addTopLevelItem(pItem); + } + + m_CompatLoaded = 1; + if(bNew) + OnCompatChanged(); + + LoadTemplates(); +} + void CSettingsWindow::OnProtectionChange() { ui.btnSetPassword->setEnabled(ui.chkPassRequired->isChecked()); @@ -1824,8 +1920,8 @@ void CSettingsWindow::OnUpdateData(const QVariantMap& Data, const QVariantMap& P ui.lblCurrent->setText(tr("%1 (Current)").arg(Version)); ui.lblStable->setText(CSettingsWindow__MkVersion("stable", Releases)); ui.lblPreview->setText(CSettingsWindow__MkVersion("preview", Releases)); - //if(ui.radInsider->isEnabled()) - // ui.lblInsider->setText(CSettingsWindow__MkVersion("insider", Releases)); + if(ui.radInsider->isEnabled()) + ui.lblInsider->setText(CSettingsWindow__MkVersion("insider", Releases)); } void CSettingsWindow::OnUpdate(const QString& Channel) diff --git a/SandboxiePlus/SandMan/Windows/SettingsWindow.h b/SandboxiePlus/SandMan/Windows/SettingsWindow.h index 2c19ce0f..2639c8fe 100644 --- a/SandboxiePlus/SandMan/Windows/SettingsWindow.h +++ b/SandboxiePlus/SandMan/Windows/SettingsWindow.h @@ -55,6 +55,11 @@ public: virtual void accept() {} virtual void reject(); + static Qt::CheckState IsContextMenu(); + static void AddContextMenu(bool bAlwaysClassic = false); + static void RemoveContextMenu(); + static bool AddBrowserIcon(); + static bool ApplyCertificate(const QByteArray &Certificate, QWidget* widget); static void LoadCertificate(QString CertPath = QString()); @@ -83,6 +88,7 @@ public slots: private slots: void OnTab(); + void OnCompat(); void OnAddMessage(); void OnDelMessage(); @@ -103,6 +109,10 @@ private slots: void OnFeaturesChanged() { m_FeaturesChanged = true; OnGeneralChanged(); } void OnGeneralChanged() { m_GeneralChanged = true; OnOptChanged(); } + void OnLoadAddon(); + void OnInstallAddon(); + void OnRemoveAddon(); + void OnBrowse(); void OnProtectionChange(); @@ -185,10 +195,6 @@ private: Ui::SettingsWindow ui; }; -void CSettingsWindow__AddContextMenu(bool bAlwaysClassic = false); -void CSettingsWindow__RemoveContextMenu(); -void CSettingsWindow__AddBrowserIcon(); - void WindowsMoveFile(const QString& from, const QString& to); extern quint32 g_FeatureFlags; diff --git a/SandboxiePlus/SandMan/Windows/SnapshotsWindow.cpp b/SandboxiePlus/SandMan/Windows/SnapshotsWindow.cpp index ee23b507..b93a31df 100644 --- a/SandboxiePlus/SandMan/Windows/SnapshotsWindow.cpp +++ b/SandboxiePlus/SandMan/Windows/SnapshotsWindow.cpp @@ -242,9 +242,9 @@ void CSnapshotsWindow::HandleResult(SB_PROGRESS Status) if (Status.GetStatus() == OP_ASYNC) { connect(Status.GetValue().data(), SIGNAL(Finished()), this, SLOT(UpdateSnapshots())); - theGUI->AddAsyncOp(Status.GetValue()); + theGUI->AddAsyncOp(Status.GetValue(), false, tr("Performing Snapshot operation..."), this); } else if (Status.IsError()) - CSandMan::CheckResults(QList() << Status); + theGUI->CheckResults(QList() << Status, this); UpdateSnapshots(); } diff --git a/SandboxiePlus/SandMan/Windows/SupportDialog.cpp b/SandboxiePlus/SandMan/Windows/SupportDialog.cpp index 2b1368c3..9acf500c 100644 --- a/SandboxiePlus/SandMan/Windows/SupportDialog.cpp +++ b/SandboxiePlus/SandMan/Windows/SupportDialog.cpp @@ -4,6 +4,7 @@ #include "../MiscHelpers/Common/Common.h" #include "SettingsWindow.h" #include +#include "OnlineUpdater.h" bool CSupportDialog::m_ReminderShown = false; @@ -32,14 +33,35 @@ bool CSupportDialog::IsBusinessUse() bool CSupportDialog::CheckSupport(bool bOnRun) { + bool NoGo = false; + +#ifdef INSIDER_BUILD + if (g_CertInfo.valid) { + if (!g_CertInfo.insider) { + TArguments args = GetArguments(g_Certificate, L'\n', L':'); + if (args.value("TYPE").contains("PATREON")) { + if (QMessageBox::question(NULL, "Sandboxie-Plus", tr("This Insider build requires a special certificate of type GREAT_PATREON, PERSONAL-HUGE, or CONTRIBUTOR.\r\n" + "If you are a great patreaon supporter already, sandboxie can check online for an update of your certificate."), QMessageBox::Ok, QMessageBox::Cancel) == QMessageBox::Ok) { + theGUI->m_pUpdater->UpdateCert(true); + if (g_CertInfo.insider) + return false; + } + } + else + QMessageBox::warning(NULL, "Sandboxie-Plus", tr("This Insider build requires a special certificate of type GREAT_PATREON, PERSONAL-HUGE, or CONTRIBUTOR.")); + } + else + return false; + } + + NoGo = true; +#else if (g_CertInfo.valid) return false; QDateTime InstallDate = GetSbieInstallationDate(); bool bOnARM64 = (g_FeatureFlags & CSbieAPI::eSbieFeatureARM64) != 0; - bool NoGo = false; - QDateTime CurretnDate = QDateTime::currentDateTimeUtc(); int Days = InstallDate.daysTo(CurretnDate); if (Days < 40) @@ -92,6 +114,7 @@ bool CSupportDialog::CheckSupport(bool bOnRun) return false; } m_ReminderShown = true; +#endif if (!ShowDialog(NoGo)) PostQuitMessage(0); @@ -107,6 +130,13 @@ bool CSupportDialog::ShowDialog(bool NoGo, int Wait) QString Message; +#ifdef INSIDER_BUILD + if (!g_CertInfo.insider) + { + Message += tr("This is a exclusive Insider build of Sandboxie-Plus it is only available to Patreon Supporters on higher tiers as well as to project contributors and owners of a HUGE supporter certificate."); + } + else +#endif if (IsBusinessUse()) { if (g_CertInfo.expired) { @@ -272,7 +302,22 @@ void CSupportDialog::OnButton() CSettingsWindow* pSettingsWindow = new CSettingsWindow(this); pSettingsWindow->showTab(CSettingsWindow::eSupport, true); connect(pSettingsWindow, &CSettingsWindow::Closed, [this]() { - if(g_CertInfo.valid) +#ifdef INSIDER_BUILD + if (g_CertInfo.valid && !g_CertInfo.insider) { + TArguments args = GetArguments(g_Certificate, L'\n', L':'); + if (args.value("TYPE").contains("PATREON")) { + theGUI->m_pUpdater->UpdateCert(true); + if (g_CertInfo.insider) { + accept(); + return; + } + } + + QMessageBox::warning(this, "Sandboxie-Plus", tr("This Insider build requires a special certificate of type GREAT_PATREON, PERSONAL-HUGE, or CONTRIBUTOR.")); + return; + } +#endif + if (g_CertInfo.valid) accept(); }); } diff --git a/SandboxiePlus/SandMan/Wizards/BoxAssistant.cpp b/SandboxiePlus/SandMan/Wizards/BoxAssistant.cpp new file mode 100644 index 00000000..23b4226e --- /dev/null +++ b/SandboxiePlus/SandMan/Wizards/BoxAssistant.cpp @@ -0,0 +1,1238 @@ +#include "stdafx.h" + +#include "BoxAssistant.h" +#include "../MiscHelpers/Common/Common.h" +#include "../MiscHelpers/Common/OtherFunctions.h" +#include "../Windows/SettingsWindow.h" +#include "../Windows/SelectBoxWindow.h" +#include "../SandMan.h" +#include "Helpers/WinAdmin.h" +#include +#include +#include "../QSbieAPI/SbieUtils.h" +#include "../Engine/BoxEngine.h" +#include "../Engine/SysObject.h" +#include "OnlineUpdater.h" +#include "../MiscHelpers/Archive/Archive.h" +#include "../MiscHelpers/Archive/ArchiveFS.h" +#include +#include +#include "../MiscHelpers/Common/CheckableMessageBox.h" +#include +#include "../Views/TraceView.h" +#include "../AddonManager.h" + + +QList ReadCommentHeader(const QString& Header) +{ + QList HeaderFields; + QStringList HeaderLines = Header.split("\n"); + foreach(QString Line, HeaderLines) + { + Line = Line.trimmed(); + if(Line.left(1) == "*") + { + Line.remove(0,1); + Line = Line.trimmed(); + } + + StrPair Field = Split2(Line, ":"); + if(Field.first.isEmpty() || Field.first.contains(" ")) + continue; + + HeaderFields.append(Field); + } + return HeaderFields; +} + +CBoxAssistant::CBoxAssistant(QWidget *parent) + : QWizard(parent) +{ + setWindowTitle(tr("Troubleshooting Wizard")); + + m_pEngine = NULL; + m_bUseDebugger = false; + m_pDebugger = NULL; + + QAction* pDbgAction = new QAction(tr("Toggle Debugger")); + pDbgAction->setShortcut(QKeySequence("Ctrl+Shift+D")); + connect(pDbgAction, SIGNAL(triggered()), this, SLOT(OnToggleDebugger())); + addAction(pDbgAction); + + m_NextCounter = 0; + + setPage(Page_Begin, new CBeginPage); + setPage(Page_Group, new CGroupPage); + setPage(Page_List, new CListPage); + setPage(Page_Run, new CRunPage); + setPage(Page_Submit, new CSubmitPage); + setPage(Page_Complete, new CCompletePage); + + setWizardStyle(ModernStyle); + setPixmap(QWizard::LogoPixmap, QPixmap(":/SandMan.png").scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation)); + + + // + // Load Issues, when the user has an own troubleshooting folder, don't load the 7z or online + // + + C7zFileEngineHandler IssueFS("issue"); + LoadIssues(GetIssueDir(IssueFS, &m_IssueDate)); + if (m_IssueDate.isValid()) { + if (theConf->GetInt("Options/CheckForIssues", 2) == 1) + theGUI->m_pUpdater->GetUpdates(this, SLOT(OnUpdateData(const QVariantMap&, const QVariantMap&))); + } +} + +CBoxAssistant::~CBoxAssistant() +{ +} + +void CBoxAssistant::OnToggleDebugger() +{ + m_bUseDebugger = !m_bUseDebugger; + + if (m_bUseDebugger && !theGUI->GetAddonManager()->HasAddon("V4dbg")) + theGUI->GetAddonManager()->TryInstallAddon("V4dbg", this, tr("To debug troubleshooting scripts you need the V4 Script Debugger addon, do you want to download and install it?")); + + QString title = windowTitle(); + if (m_bUseDebugger) + setWindowTitle(title + " - " + tr("Debugger Enabled")); + else + setWindowTitle(title.mid(0, title.indexOf(" - "))); +} + +QString CBoxAssistant::GetIssueDir(C7zFileEngineHandler& IssueFS, QDateTime* pDate) +{ + QString IssueDir = theConf->GetConfigDir() + "/troubleshooting/"; + if (!QFile::exists(IssueDir)) { + + QFileInfo Installed(QApplication::applicationDirPath() + "/troubleshooting.7z"); + QFileInfo Latest(theConf->GetConfigDir() + "/troubleshooting.7z"); + quint64 latest = Latest.lastModified().toSecsSinceEpoch(); + quint64 installed = Installed.lastModified().toSecsSinceEpoch(); + if (latest >= installed && IssueFS.Open(theConf->GetConfigDir() + "/troubleshooting.7z")) { + IssueDir = IssueFS.Prefix() + "/"; + if(pDate) *pDate = Latest.lastModified(); + } + else if (IssueFS.Open(QApplication::applicationDirPath() + "/troubleshooting.7z")) { + IssueDir = IssueFS.Prefix() + "/"; + if(pDate) *pDate = Installed.lastModified(); + } + } + return IssueDir; +} + +void CBoxAssistant::OnUpdateData(const QVariantMap& Data, const QVariantMap& Params) +{ + if (Data.isEmpty() || Data["error"].toBool()) + return; + + QVariantMap Issues = Data["issues"].toMap(); + + quint64 Date = Issues["date"].toULongLong(); + if (Date >= m_IssueDate.toSecsSinceEpoch()) { + + QString Download = Issues["download"].toString(); + + QVariantMap Params; + Params["path"] = theConf->GetConfigDir() + "/troubleshooting.tmp"; + Params["setDate"] = QDateTime::fromSecsSinceEpoch(Date); + Params["signature"] = Issues["signature"]; + theGUI->m_pUpdater->DownloadFile(Download, this, SLOT(OnDownload(const QString&, const QVariantMap&)), Params); + } +} + +extern "C" long VerifyFileSignatureImpl(const wchar_t* FilePath, void* Signature, unsigned long SignatureSize); + +void CBoxAssistant::OnDownload(const QString& Path, const QVariantMap& Params) +{ + QByteArray Signature = QByteArray::fromBase64(Params["signature"].toByteArray()); + + if (VerifyFileSignatureImpl(QString(Path).replace("/","\\").toStdWString().c_str(), Signature.data(), Signature.size()) < 0) { // !NT_SUCCESS + QFile::remove(Path); + return; + } + QString FinalPath = theConf->GetConfigDir() + "/troubleshooting.7z"; + QFile::remove(FinalPath); + QFile::rename(Path, FinalPath); + + + QString IssueDir; + C7zFileEngineHandler IssueFS("issue"); + if (!IssueFS.Open(FinalPath)) { + QMessageBox::critical(this, "Sandboxie-Plus", tr("Downloaded troubleshooting instructions are currupted!")); + QFile::remove(Path); + return; + } + + LoadIssues(IssueFS.Prefix() + "/"); + + CBeginPage* pBegin = qobject_cast(currentPage()); + if (pBegin) + pBegin->initializePage(); +} + +void CBoxAssistant::LoadIssues(const QString& IssueDir) +{ + QVariantMap Issues = QJsonDocument::fromJson(ReadFileAsString(IssueDir + "layout.json").toUtf8()).toVariant().toMap(); + + QVariantList Entries = Issues.value("entries").toList(); + + if (Entries.isEmpty()) { + QMessageBox::critical(this, "Sandboxie-Plus", tr("Fatal error, failed to load troubleshooting instructions!")); + return; + } + + m_GroupedIssues.clear(); + + quint32 OsBuild = JSysObject::GetOSVersion()["build"].toUInt(); + + //QDir Dir(IssueDir); + //foreach(const QFileInfo & Info, Dir.entryInfoList(QStringList() << "*.js", QDir::Files)) { + foreach(const QString & FileName, ListDir(IssueDir, QStringList() << "*.js")) { + QFileInfo Info(IssueDir + FileName); + QString Script = ReadFileAsString(Info.filePath()); + + int HeaderBegin = Script.indexOf("/*"); + int HeaderEnd = Script.indexOf("*/"); + if(HeaderBegin == -1 || HeaderEnd == -1) + continue; // Header is mandatory + if(HeaderBegin != 0) { + qDebug() << "Bad Header of" << Info.fileName(); + continue; + } + + QVariantMap Issue; + Issue["id"] = Info.fileName().left(Info.fileName().length() - 3); + Issue["type"] = "issue"; + foreach(const StrPair& KeyValue, ReadCommentHeader(Script.mid(HeaderBegin + 2, HeaderEnd - (HeaderBegin + 2)))) + Issue[KeyValue.first] = KeyValue.second; + Issue["script"] = Script; + + bool NotApplicable = false; + if (Issue.contains("versions")) { + NotApplicable = true; + foreach(const QString & V, SplitStr(Issue["versions"].toString(), ",")) { + StrPair VV = Split2(V, "-"); + if ((VV.second.isEmpty() && COnlineUpdater::VersionToInt(VV.first) == COnlineUpdater::CurrentVersion()) || // exact version match + (!VV.second.isEmpty() && (COnlineUpdater::VersionToInt(VV.first) <= COnlineUpdater::CurrentVersion() && COnlineUpdater::VersionToInt(VV.second) >= COnlineUpdater::CurrentVersion()))) { // inside version range + NotApplicable = false; + break; + } + } + } + if (!NotApplicable && Issue.contains("os_builds")) { + NotApplicable = true; + foreach(const QString & V, SplitStr(Issue["os_builds"].toString(), ",")) { + StrPair VV = Split2(V, "-"); + if ((VV.second.isEmpty() && VV.first.toUInt() == OsBuild) || // exact version match + (!VV.second.isEmpty() && (VV.first.toUInt() <= OsBuild && VV.second.toUInt() >= OsBuild))) { // inside version range + NotApplicable = false; + break; + } + } + } + if (NotApplicable) + continue; + + Entries.append(Issue); + } + + foreach(const QVariant & vIssue, Entries) { + QVariantMap Issue = vIssue.toMap(); + QList& Group = m_GroupedIssues[Issue["group"].toString()]; + // Note: This way we can define order in the layout json and have the issue scripts loaded at the right place + QString ID = Issue["id"].toString(); + auto I = std::find_if(Group.begin(), Group.end(), [ID](const QVariantMap& cur)->int { return cur["id"] == ID; }); + if (I == Group.end()) + Group.append(Issue); + else { + if (I->contains("script")) { + QMessageBox::warning(this, "Sandboxie-Plus", tr("Error, troubleshooting instructions duplicated %1 (%2 <-> %3)!") + .arg(ID).arg(I->value("id").toString()).arg(Issue.value("id").toString())); + } + for(auto J = Issue.begin(); J != Issue.end(); ++J) + I->insert(J.key(), J.value()); + } + } + + // + // Load Translations + // + + QString Translation = ReadFileAsString(IssueDir + "lang_" + theGUI->m_Language + ".json"); + if (Translation.isEmpty()) { + QString LangAux = theGUI->m_Language; // Short version as fallback + LangAux.truncate(LangAux.lastIndexOf('_')); + Translation = ReadFileAsString(IssueDir + "lang_" + LangAux + ".json"); + } + + if(!Translation.isEmpty()) + m_Translation = QJsonDocument::fromJson(Translation.toUtf8()).toVariant().toMap(); +} + +QList CBoxAssistant::GetIssues(const QVariantMap& Root) const +{ + if (Root.contains("id")) + return m_GroupedIssues.value(Root["id"].toString()); + + QString Class = Root["class"].toString(); + QList AllIssues; + for (auto I = m_GroupedIssues.begin(); I != m_GroupedIssues.end(); ++I) { + for(auto J = I->begin(); J != I->end(); ++J) { + if (J->value("type") == "issue" + && (Class.isEmpty() || J->value("class").toString().compare(Class, Qt::CaseInsensitive) == 0)) + AllIssues.append(*J); + } + } + return AllIssues; +} + +void CBoxAssistant::ShowAssistant() +{ + CBoxAssistant* pWizard = new CBoxAssistant(theGUI); + pWizard->setAttribute(Qt::WA_DeleteOnClose); + SafeShow(pWizard); +} + +bool CBoxAssistant::StartEngine() +{ + QVariantMap Issue = CurrentIssue(); + + QString Script = Issue["script"].toString(); + QString Name = Issue["id"].toString(); + + if (!Script.isEmpty()) { + m_pEngine = new CWizardEngine(this); + + connect(m_pEngine, SIGNAL(LogMessage(const QString&)), theGUI, SLOT(AddLogMessage(const QString&))); + + connect(m_pEngine, SIGNAL(BoxUsed(const CSandBoxPtr&)), this, SLOT(OnBoxUsed(const CSandBoxPtr&))); + + m_pEngine->AppendLog(QString("Starting troubleshooting script: %1").arg(Issue["id"].toString())); // no tr + + if (m_bUseDebugger) { + QObject* pDebuggerBackend = m_pEngine->GetDebuggerBackend(); + if (pDebuggerBackend != NULL) { + QObject* pDebuggerFrontend = newJSScriptDebuggerFrontendDynamic(); + + QObject::connect(pDebuggerBackend, SIGNAL(sendResponse(QVariant)), pDebuggerFrontend, SLOT(processResponse(QVariant)), Qt::QueuedConnection); + QObject::connect(pDebuggerFrontend, SIGNAL(sendRequest(QVariant)), pDebuggerBackend, SLOT(processRequest(QVariant)), Qt::QueuedConnection); + + m_pDebugger = newJSScriptDebuggerDynamic(pDebuggerFrontend); + //connect(pDebugger, SIGNAL(detach()), this, ...); + m_pDebugger->resize(1024, 640); + m_pDebugger->restoreGeometry(theConf->GetBlob("DebuggerWindow/Window_Geometry")); + m_pDebugger->show(); + } + else { + QMessageBox::critical(this, "Sandboxie-Plus", tr("V4ScriptDebuggerBackend could not be instantiated, probably V4ScriptDebugger.dll and or its dependencies are missing, script debuger could not be opened.")); + } + } + + return m_pEngine->RunScript(Script, Name); + } + return true; +} + +void CBoxAssistant::KillEngine() +{ + m_pEngine->AppendLog(QString("Troubleshooting script terminated")); // no tr + + if (m_pDebugger) { + + QObject* pDebuggerBackend = m_pEngine->GetDebuggerBackend(); + QMetaObject::invokeMethod(pDebuggerBackend, "detach", Qt::DirectConnection); + + m_pDebugger->close(); + theConf->SetBlob("DebuggerWindow/Window_Geometry", m_pDebugger->saveGeometry()); + m_pDebugger->deleteLater(); + m_pDebugger = NULL; + } + + delete m_pEngine; + m_pEngine = NULL; +} + +void CBoxAssistant::OnBoxUsed(const CSandBoxPtr& pBox) +{ + SUsedBox UsedBox; + UsedBox.pBox = pBox; + QDir Dir(pBox->GetFileRoot()); + foreach(const QFileInfo & Info, Dir.entryInfoList(QStringList() << "*.dmp", QDir::Files)) + UsedBox.OldDumps.append(Info.fileName()); + m_UsedBoxes.append(UsedBox); +} + +void CBoxAssistant::accept() +{ + if (m_pEngine && currentId() != Page_Submit) + m_pEngine->ApplyShadowChanges(); + QWizard::accept(); +} + +void CBoxAssistant::reject() +{ + if (m_pEngine && currentId() != Page_Submit) { + if (theConf->GetInt("Options/WarnWizardOnClose", -1) == -1) { + bool State = false; + if (CCheckableMessageBox::question(this, "Sandboxie-Plus", tr("A troubleshooting procedure is in progress, canceling the wizard will abort it, this may leave the sandbox in an incosistent state.") + , tr("Don't ask in future"), &State, QDialogButtonBox::Ok | QDialogButtonBox::Cancel, QDialogButtonBox::Cancel) == QDialogButtonBox::Cancel) + return; + if (State) + theConf->SetValue("Options/WarnWizardOnClose", 1); + } + } + QWizard::reject(); +} + + +////////////////////////////////////////////////////////////////////////////////////////// +// CBeginPage +// + +CBeginPage::CBeginPage(QWidget *parent) + : QWizardPage(parent) +{ + setTitle(tr("Troubleshooting Wizard")); + setPixmap(QWizard::WatermarkPixmap, QPixmap(":/SideLogo.png")); + + int row = 0; + m_pLayout = new QGridLayout; + QLabel* pTopLabel = new QLabel(tr("Welcome to the Troubleshooting Wizard for Sandboxie-Plus. " + "This interactive assistant is designed to help you in resolving sandboxing issues.")); + pTopLabel->setWordWrap(true); + m_pLayout->addWidget(pTopLabel, row++, 0, 1, 3); + + m_pLayout->addItem(new QSpacerItem(40, 10, QSizePolicy::Fixed, QSizePolicy::Fixed), row, 0); + m_pLayout->addItem(new QSpacerItem(40, 10, QSizePolicy::Expanding, QSizePolicy::Fixed), row, 2); + + setLayout(m_pLayout); +} + +void CBeginPage::initializePage() +{ + foreach(QWidget * pWidget, m_pWidgets) + delete pWidget; + m_pWidgets.clear(); + + int row = 2; + + auto AddIssue = [&](QVariantMap Issue) { + QPushButton* pIssue = new QPushButton(((CBoxAssistant*)wizard())->Tr(Issue["name"].toString())); + pIssue->setProperty("issue", Issue); + connect(pIssue, SIGNAL(pressed()), this, SLOT(OnCategory())); + pIssue->setIcon(CSandMan::GetIcon(Issue["icon"].toString())); + pIssue->setIconSize(QSize(32, 32)); + pIssue->setProperty("leftButton", true); + pIssue->setStyle(new MyButtonStyle(pIssue->style())); + m_pLayout->addWidget(pIssue, row++, 1); + m_pWidgets.append(pIssue); + return pIssue; + }; + + QVariantMap Root; + Root["id"] = "root"; + foreach(auto Issue, ((CBoxAssistant*)wizard())->GetIssues(Root)) { + if (((CBoxAssistant*)wizard())->GetIssues(Issue).isEmpty() && Issue["type"] != "issue") + continue; + AddIssue(Issue); + } + + m_pLayout->addItem(new QSpacerItem(10, 10, QSizePolicy::Fixed, QSizePolicy::Expanding), row++, 0); + + if (!g_CertInfo.valid || g_CertInfo.expired) { + QLabel* pBottomLabel = new QLabel(tr("With a valid supporter certificate the wizard would be even more powerfull. " + "It could access the online solution database to retriev the latest troubleshooting instructions.")); + connect(pBottomLabel, SIGNAL(linkActivated(const QString&)), theGUI, SLOT(OpenUrl(const QString&))); + pBottomLabel->setWordWrap(true); + m_pLayout->addWidget(pBottomLabel, row++, 0, 1, 3); + m_pWidgets.append(pBottomLabel); + } +} + +void CBeginPage::OnCategory() +{ + QVariantMap Issue = sender()->property("issue").toMap(); + ((CBoxAssistant*)wizard())->PushIssue(Issue); + wizard()->next(); +} + +int CBeginPage::nextId() const +{ + QVariantMap Issue = ((CBoxAssistant*)wizard())->CurrentIssue(); + QString type = Issue["type"].toString(); + if (type == "issue") + return CBoxAssistant::Page_Run; + if (type == "list") + return CBoxAssistant::Page_List; + return CBoxAssistant::Page_Group; +} + +bool CBeginPage::isComplete() const +{ + //return false; + return true; +} + +bool CBeginPage::validatePage() +{ + if (((CBoxAssistant*)wizard())->CurrentIssue().isEmpty()) { + QVariantMap Issue; + Issue["type"] = "list"; + Issue["name"] = tr("Another issue"); + ((CBoxAssistant*)wizard())->PushIssue(Issue); + } + return true; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// CGroupPage +// + +CGroupPage::CGroupPage(QWidget *parent) + : QWizardPage(parent) +{ + setTitle(tr("Select issue from group")); + setPixmap(QWizard::WatermarkPixmap, QPixmap(":/SideLogo.png")); + + int row = 0; + m_pLayout = new QGridLayout; + m_pLayout->setSpacing(2); + m_pTopLabel = new QLabel(tr("Please specify the exact issue:")); + m_pTopLabel->setWordWrap(true); + m_pLayout->addWidget(m_pTopLabel, row++, 0, 1, 2); + + m_pGroup = new QButtonGroup(); + connect(m_pGroup, SIGNAL(idToggled(int, bool)), this, SIGNAL(completeChanged())); + + setLayout(m_pLayout); +} + +void CGroupPage::initializePage() +{ + int row = 2; + + foreach(QWidget * pWidget, m_pWidgets) + delete pWidget; + m_pWidgets.clear(); + + m_pLayout->addItem(new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Preferred), row++, 1); + + QVariantMap Group = ((CBoxAssistant*)wizard())->CurrentIssue(); + + m_pTopLabel->setText(((CBoxAssistant*)wizard())->Tr(Group["description"].toString())); + + //QLabel* pCommon = new QLabel(tr("Common Issues:")); + //m_pLayout->addWidget(pCommon, row++, 0); + //m_pWidgets.append(pCommon); + + auto AddIssue = [&](QVariantMap Issue) { + QRadioButton* pIssue = new QRadioButton(((CBoxAssistant*)wizard())->Tr(Issue["name"].toString())); + pIssue->setToolTip(((CBoxAssistant*)wizard())->Tr(Issue["description"].toString())); + pIssue->setProperty("issue", Issue); + m_pGroup->addButton(pIssue); + m_pLayout->addWidget(pIssue, row++, 1); + m_pWidgets.append(pIssue); + }; + + foreach(auto Issue, ((CBoxAssistant*)wizard())->GetIssues(Group)) + AddIssue(Issue); + + if (!Group["class"].toString().isEmpty()) { + QWidget* pSpacer = new QWidget(); + pSpacer->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); + m_pLayout->addWidget(pSpacer, row++, 0); + m_pWidgets.append(pSpacer); + + //QLabel* pOther = new QLabel(tr("More Issues:")); + //m_pLayout->addWidget(pOther, row++, 0); + //m_pWidgets.append(pOther); + + QVariantMap Issue; + Issue["type"] = "list"; + Issue["class"] = Group["class"]; + Issue["name"] = tr("Another issue"); + AddIssue(Issue); + + pSpacer = new QWidget(); + pSpacer->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); + m_pLayout->addWidget(pSpacer, row++, 0); + m_pWidgets.append(pSpacer); + } +} + +void CGroupPage::cleanupPage() +{ + ((CBoxAssistant*)wizard())->PopIssue(); + + QPointer w = wizard(); + QTimer::singleShot(10, [w]() { + if (w && ((CBoxAssistant*)w.data())->m_NextCounter > 0) + ((CBoxAssistant*)w.data())->removePage(CBoxAssistant::Page_Next + ((CBoxAssistant*)w.data())->m_NextCounter--); + }); +} + +int CGroupPage::nextId() const +{ + if (QAbstractButton* pButton = m_pGroup->checkedButton()) { + QVariantMap Issue = pButton->property("issue").toMap(); + QString type = Issue["type"].toString(); + if (type == "issue") + return CBoxAssistant::Page_Run; + if (type == "group") + return CBoxAssistant::Page_Next + ((CBoxAssistant*)wizard())->m_NextCounter; + if (type == "list") + return CBoxAssistant::Page_List; + } + return CBoxAssistant::Page_Submit; +} + +bool CGroupPage::isComplete() const +{ + return m_pGroup->checkedId() != -1; +} + +bool CGroupPage::validatePage() +{ + if (QAbstractButton* pButton = m_pGroup->checkedButton()) { + QVariantMap Issue = pButton->property("issue").toMap(); + QString type = Issue["type"].toString(); + if (type == "group" || type == "list") + ((CBoxAssistant*)wizard())->setPage(CBoxAssistant::Page_Next + ++((CBoxAssistant*)wizard())->m_NextCounter, new CGroupPage()); + ((CBoxAssistant*)wizard())->PushIssue(Issue); + return true; + } + return false; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// CListPage +// + +CListPage::CListPage(QWidget *parent) + : QWizardPage(parent) +{ + setTitle(tr("Select issue from full list")); + setPixmap(QWizard::WatermarkPixmap, QPixmap(":/SideLogo.png")); + + int row = 0; + m_pLayout = new QGridLayout; + m_pLayout->setSpacing(2); + //QLabel* pTopLabel = new QLabel(tr("Please select an isue from the list")); + //pTopLabel->setWordWrap(true); + //m_pLayout->addWidget(pTopLabel, row++, 0, 1, 2); + + m_pFilter = new QLineEdit(); + m_pFilter->setPlaceholderText(tr("Search filter")); + m_pLayout->addWidget(m_pFilter, row++, 0, 1, 2); + connect(m_pFilter, SIGNAL(textChanged(const QString &)), this, SLOT(ApplyFilter())); + + m_pList = new QListWidget(); + m_pLayout->addWidget(m_pList, row++, 0, 1, 2); + connect(m_pList, SIGNAL(itemClicked(QListWidgetItem *)), this, SIGNAL(completeChanged())); + + setLayout(m_pLayout); +} + +void CListPage::ApplyFilter() +{ + static bool UpdatePending = false; + if (!UpdatePending) { + UpdatePending = true; + QTimer::singleShot(100, [=]() { + UpdatePending = false; + LoadIssues(); + }); + } +} + +void CListPage::LoadIssues() +{ + m_pList->clear(); + + QVariantMap List = ((CBoxAssistant*)wizard())->CurrentIssue(); + + int iAny = List.contains("id") ? 0 : 1; + + auto AddIssue = [&](QVariantMap Issue) { + QListWidgetItem* pItem = new QListWidgetItem(); + pItem->setText(((CBoxAssistant*)wizard())->Tr(Issue["name"].toString())); + pItem->setToolTip(((CBoxAssistant*)wizard())->Tr(Issue["description"].toString())); + pItem->setData(Qt::UserRole, Issue); + if (iAny != 1 && Issue["bold"].toBool()) { + QFont font = pItem->font(); + font.setBold(true); + pItem->setFont(font); + } + m_pList->addItem(pItem); + }; + + QString Filter = m_pFilter->text(); + + foreach(auto Issue, ((CBoxAssistant*)wizard())->GetIssues(List)) { + if (Filter.isEmpty() + || ((CBoxAssistant*)wizard())->Tr(Issue["name"].toString()).contains(Filter, Qt::CaseInsensitive) + || ((CBoxAssistant*)wizard())->Tr(Issue["description"].toString()).contains(Filter, Qt::CaseInsensitive)) + AddIssue(Issue); + } + + if (iAny) { + QVariantMap Issue; + Issue["type"] = "submit"; + Issue["name"] = tr("None of the above"); + Issue["bold"] = true; + iAny = 2; + AddIssue(Issue); + } + else + setTitle(((CBoxAssistant*)wizard())->Tr(List["name"].toString())); +} + +void CListPage::initializePage() +{ + m_pFilter->clear(); + LoadIssues(); +} + +void CListPage::cleanupPage() +{ + ((CBoxAssistant*)wizard())->PopIssue(); + + QPointer w = wizard(); + QTimer::singleShot(10, [w]() { + if (w && ((CBoxAssistant*)w.data())->m_NextCounter > 0) + ((CBoxAssistant*)w.data())->removePage(CBoxAssistant::Page_Next + ((CBoxAssistant*)w.data())->m_NextCounter--); + }); +} + +int CListPage::nextId() const +{ + if (QListWidgetItem* pItem = m_pList->currentItem()) { + QVariantMap Issue = pItem->data(Qt::UserRole).toMap(); + QString type = Issue["type"].toString(); + if (type == "issue") + return CBoxAssistant::Page_Run; + if (type == "group") + return CBoxAssistant::Page_Next + ((CBoxAssistant*)wizard())->m_NextCounter; + if (type == "list") + return CBoxAssistant::Page_List; + } + return CBoxAssistant::Page_Submit; +} + +bool CListPage::isComplete() const +{ + return !m_pList->selectedItems().isEmpty(); +} + +bool CListPage::validatePage() +{ + if (QListWidgetItem* pItem = m_pList->currentItem()) { + QVariantMap Issue = pItem->data(Qt::UserRole).toMap(); + QString type = Issue["type"].toString(); + if (type == "group" || type == "list") + ((CBoxAssistant*)wizard())->setPage(CBoxAssistant::Page_Next + ++((CBoxAssistant*)wizard())->m_NextCounter, new CGroupPage()); + ((CBoxAssistant*)wizard())->PushIssue(Issue); + return true; + } + return false; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// CRunPage +// + +CRunPage::CRunPage(QWidget *parent) + : QWizardPage(parent) +{ + setTitle(tr("Troubleshooting ...")); + setSubTitle(tr("")); + + m_pLayout = new QGridLayout; + m_pTopLabel = new QLabel(); + m_pTopLabel->setWordWrap(true); + m_pLayout->addWidget(m_pTopLabel, 0, 0, 1, 2); + m_pForm = NULL; + + setLayout(m_pLayout); +} + +void CRunPage::initializePage() +{ + QVariantMap Issue = ((CBoxAssistant*)wizard())->CurrentIssue(); + setTitle(((CBoxAssistant*)wizard())->Tr(Issue["name"].toString())); + setSubTitle(((CBoxAssistant*)wizard())->Tr(Issue["description"].toString())); + + if(((CBoxAssistant*)wizard())->StartEngine()) { + CWizardEngine* pEngine = ((CBoxAssistant*)wizard())->GetEngine(); + connect(pEngine, SIGNAL(StateChanged(int, const QString&)), this, SLOT(OnStateChanged(int, const QString&))); + } else + m_pTopLabel->setText(tr("This troubleshooting procedure could not be initialized. " + "You can click on next to submit an issue report.")); +} + +void CRunPage::cleanupPage() +{ + ((CBoxAssistant*)wizard())->KillEngine(); +} + +void CRunPage::OnStateChanged(int state, const QString& Text) +{ + CWizardEngine* pEngine = ((CBoxAssistant*)wizard())->GetEngine(); + if (!pEngine || pEngine != sender()) + return; + + if (m_pForm) { + delete m_pForm; + m_pForm = NULL; + m_pWidgets.clear(); + } + + bool bEnableNext = true; + + //qDebug() << "OnStateChanged" << state; + switch (state) + { + case CBoxEngine::eRunning: + case CBoxEngine::eRunningAsync: + bEnableNext = false; + case CBoxEngine::eReady: + m_pTopLabel->setText(Text); + break; + case CBoxEngine::eQuery: + { + QVariantMap Query = pEngine->GetQuery(); + m_pTopLabel->setText(Query["text"].toString()); + + if (Query["type"].toString().compare("form", Qt::CaseInsensitive) == 0) { + + m_pForm = new QWidget(); + QFormLayout* pForm = new QFormLayout(m_pForm); + m_pLayout->addWidget(m_pForm, 1, 0, 1, 2); + + QVariantList Form = Query["form"].toList(); + foreach(const QVariant& vEntry, Form) { + QVariantMap Entry = vEntry.toMap(); + QString type = Entry["type"].toString(); + QString name = ((CBoxAssistant*)wizard())->Tr(Entry["name"].toString()); + QVariant value = Entry["value"].toString(); + QWidget* pWidget; + if (type.compare("label", Qt::CaseInsensitive) == 0) { + pWidget = new QLabel(name); + pForm->addRow(pWidget); + } + else if (type.compare("file", Qt::CaseInsensitive) == 0 || type.compare("folder", Qt::CaseInsensitive) == 0) { + CPathEdit* pPath = new CPathEdit(type.compare("folder", Qt::CaseInsensitive) == 0); + pWidget = pPath; + pPath->SetText(value.toString()); + pForm->addRow(name, pPath); + } + else if (type.compare("edit", Qt::CaseInsensitive) == 0) { + QLineEdit* pEdit = new QLineEdit(); + pWidget = pEdit; + pEdit->setText(value.toString()); + pForm->addRow(name, pEdit); + } + else if (type.compare("check", Qt::CaseInsensitive) == 0) { + QCheckBox* pCheck = new QCheckBox(name); + pWidget = pCheck; + pCheck->setChecked(value.toBool()); + pForm->addRow("", pCheck); + } + else if (type.compare("radio", Qt::CaseInsensitive) == 0) { + QRadioButton* pRadio = new QRadioButton(name); + pWidget = pRadio; + pRadio->setChecked(value.toBool()); + pForm->addRow("", pRadio); + + // todo: add mandatory flag for other fields + bEnableNext = false; // user must make a choice + connect(pRadio, SIGNAL(toggled(bool)), this, SLOT(CheckUserInput())); + } + else if (type.compare("box", Qt::CaseInsensitive) == 0) { + QString Name = name; + //if(!Name.isEmpty()) pForm->addRow(new QLabel(Name)); + CBoxPicker* pPicker = new CBoxPicker(value.toString()); + pWidget = pPicker; + pForm->addRow(Name, pPicker); + } + else if (type.compare("combo", Qt::CaseInsensitive) == 0) { + QComboBox* pCombo = new QComboBox(); + pWidget = pCombo; + foreach(const QVariant & vItem, Entry["items"].toList()) { + if (vItem.type() == QVariant::Map) { + QVariantMap Item = vItem.toMap(); + pCombo->addItem(((CBoxAssistant*)wizard())->Tr(Item["name"].toString()), Item["value"]); + } else + pCombo->addItem(vItem.toString()); + } + pForm->addRow(name, pCombo); + } + pWidget->setToolTip(((CBoxAssistant*)wizard())->Tr(Entry["description"].toString())); + if (Entry["disabled"].toBool()) pWidget->setDisabled(true); + QString id = Entry["id"].toString(); + if (!id.isEmpty()) m_pWidgets.insert(id, pWidget); + } + } + break; + } + case CBoxEngine::eError: + m_pTopLabel->setText(tr("Somethign failed internally this troubleshooting procedure can not continue. " + "You can click on next to submit an issue report.") + (pEngine ? tr("\n\nError: ") + Text : "")); + case CBoxEngine::eCanceled: + break; + case CBoxEngine::eCompleted: + case CBoxEngine::eSuccess: + case CBoxEngine::eFailed: + wizard()->next(); + break; + } + + if(bEnableNext) + wizard()->button(QWizard::NextButton)->setEnabled(true); +} + +void CRunPage::CheckUserInput() +{ + wizard()->button(QWizard::NextButton)->setEnabled(true); +} + +bool CRunPage::isComplete() const +{ + return true; +} + +int CRunPage::nextId() const +{ + CWizardEngine* pEngine = ((CBoxAssistant*)wizard())->GetEngine(); + if(!pEngine || pEngine->HasFailed() || pEngine->HasError()) + return CBoxAssistant::Page_Submit; + return CBoxAssistant::Page_Complete; +} + +bool CRunPage::validatePage() +{ + CWizardEngine* pEngine = ((CBoxAssistant*)wizard())->GetEngine(); + + if (!pEngine || !(pEngine->HasQuery() || pEngine->IsReady())) { + // disables back button on next page + setCommitPage(true); + return true; + } + + // dissable back button on the current page + wizard()->button(QWizard::BackButton)->setEnabled(false); + // disable next button, OnStateChanged wi re enable it + wizard()->button(QWizard::NextButton)->setEnabled(false); + + if (pEngine->HasQuery()) { + QVariantMap Reply; + for (auto I = m_pWidgets.begin(); I != m_pWidgets.end(); ++I) { + QVariant Value; + if (CPathEdit* pPath = qobject_cast(I.value())) + Value = pPath->GetText(); + else if (QLineEdit* pEdit = qobject_cast(I.value())) + Value = pEdit->text(); + else if (QCheckBox* pCheck = qobject_cast(I.value())) + Value = pCheck->isChecked(); + else if (QRadioButton* pRadio = qobject_cast(I.value())) + Value = pRadio->isChecked(); + else if (CBoxPicker* pPicker = qobject_cast(I.value())) + Value = pPicker->GetBoxName(); + else if (QComboBox* pCombo = qobject_cast(I.value())) { + Value = pCombo->currentData(); + if (!Value.isValid()) + Value = pCombo->currentIndex(); + } + Reply[I.key()] = Value; + } + pEngine->SetResult(Reply); + } + else if (pEngine->IsReady()) { + pEngine->Continue(); + } + + return false; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// CSubmitPage +// + +CSubmitPage::CSubmitPage(QWidget *parent) + : QWizardPage(parent) +{ + setTitle(tr("Submit Issue Report")); + setPixmap(QWizard::WatermarkPixmap, QPixmap(":/SideLogo.png")); + + int row = 0; + QGridLayout* pLayout = new QGridLayout; + pLayout->setSpacing(2); + m_pTopLabel = new QLabel(); + m_pTopLabel->setWordWrap(true); + pLayout->addWidget(m_pTopLabel, row++, 0, 1, 3); + + m_pReport = new QTextEdit(); + m_pReport->setPlaceholderText(tr("Detailed issue description")); + //m_pReport->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + pLayout->addWidget(m_pReport, row++, 0, 1, 3); + + m_pAttachIni = new QCheckBox(tr("Attach Sandboxie.ini")); + m_pAttachIni->setToolTip(tr("Sandboxing compatybility is relyent on the configuration hence attaching the sandboxie.ini helps a lot with finding the issue.")); + pLayout->addWidget(m_pAttachIni, row, 0); + + m_pAttachLog = new QCheckBox(tr("Attach Logs")); + m_pAttachLog->setTristate(true); + m_pAttachLog->setToolTip(tr("Select partially checked state to sends only message log but no trace log.\nBefore sending you can review the logs in the main window.")); + pLayout->addWidget(m_pAttachLog, row, 1); + + m_pAttachDmp = new QCheckBox(tr("Attach Crash Dumps")); + m_pAttachDmp->setToolTip(tr("An applicatin crashed during the troubleshooting procedure, attaching a crash dump can help with the debugging.")); + pLayout->addWidget(m_pAttachDmp, row, 2); + + m_pMail = new QLineEdit(); + m_pMail->setPlaceholderText(tr("Email address")); + m_pMail->setToolTip(tr("You have the option to provide an email address to receive a notification once a solution for your issue has been identified.")); + pLayout->addWidget(m_pMail, ++row, 0, 1, 3); + + setLayout(pLayout); +} + +void CSubmitPage::initializePage() +{ + QString Info = tr("We apologize for the inconvenience you are currently facing with Sandboxie-Plus. "); + + QString Report; // DO NOT TRANSLATE - Reports must be in English! + + CWizardEngine* pEngine = ((CBoxAssistant*)wizard())->GetEngine(); + if (pEngine) { + if (pEngine->HasFailed() || pEngine->HasError()) { + Info += tr("Unfortunately, the automated troubleshooting procedure failed. "); + + QVariantMap Issue = ((CBoxAssistant*)wizard())->CurrentIssue(); + Report = QString("Troubleshooting procedure '%1' failed").arg(Issue["id"].toString()); + } + } + else { + Info += tr("Regrettably, there is no automated troubleshooting procedure available for the specific issue you have described. "); + + Report = "[PLEASE ENTER YOUR ISSUE DESCRIPTION HERE]"; + } + + Info += tr("If you wish to submit an issue report, please review the report below and click 'Finish'."); + + m_pTopLabel->setText(Info); + + Report += "\n\nFurther information:\n"; + Report += "Sandboxie-Plus Version: " + theGUI->GetVersion() + "\n"; + Report += "Operating System Version: " + QSysInfo::kernelVersion() + "-" + QSysInfo::currentCpuArchitecture() + "\n"; + + bool bNewDumps = false; + foreach(auto & UsedBox, ((CBoxAssistant*)wizard())->m_UsedBoxes) { + QDir Dir(UsedBox.pBox->GetFileRoot()); + foreach(const QFileInfo & Info, Dir.entryInfoList(QStringList() << "*.dmp", QDir::Files)) { + if (!UsedBox.OldDumps.contains(Info.fileName())) { + bNewDumps = true; + break; + } + } + Report += "Used Sandbox: " + UsedBox.pBox->GetName() + "\n"; + } + + if (pEngine) { + QVariantMap Values = pEngine->GetReport(); + for (auto I = Values.begin(); I != Values.end(); ++I) + Report += I.key() + ": " + I->toString() + "\n"; + } + + m_pReport->setText(Report); + + + m_pAttachIni->setChecked(true); + + m_pAttachLog->setChecked(true); + //bool bHasLog = !theAPI->GetTrace().isEmpty(); + //m_pAttachLog->setEnabled(bHasLog); + //m_pAttachLog->setChecked(bHasLog); + + m_pAttachDmp->setEnabled(bNewDumps); + m_pAttachDmp->setChecked(bNewDumps); +} + +bool CSubmitPage::validatePage() +{ + QBuffer* pTraceLog = NULL; + if (m_pAttachLog->checkState() == Qt::Checked) { + pTraceLog = new QBuffer(); + pTraceLog->open(QIODevice::ReadWrite); + if (!CTraceView::SaveToFile(pTraceLog)) { + delete pTraceLog; + return false; + } + } + + m_pUploadProgress = CSbieProgressPtr(new CSbieProgress()); + theGUI->AddAsyncOp(m_pUploadProgress, false, QString(), this); + + CNetworkAccessManager* pRequestManager = new CNetworkAccessManager(30 * 1000, this); + + QHttpMultiPart* pMultiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType); + + QHttpPart Report; + Report.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"report\"")); + Report.setBody(m_pReport->toPlainText().toUtf8()); + pMultiPart->append(Report); + + if (m_pAttachIni->isChecked()) { + + QFile* pSbieIni = new QFile(theAPI->GetIniPath(), pMultiPart); + + if (pSbieIni->open(QIODevice::ReadOnly)) { + + QHttpPart SbieIni; + SbieIni.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/plain")); + SbieIni.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"sbieIni\"; filename=\"Sandboxie.ini\"")); + + SbieIni.setBodyDevice(pSbieIni); + pMultiPart->append(SbieIni); + } + } + + if (m_pAttachLog->isChecked()) { + + QBuffer* pSbieLogs = new QBuffer(pMultiPart); + CArchive Archive("SbieTrace.7z", pSbieLogs); + + QMap Files; + + QBuffer* pMessageLog = new QBuffer(); + pMessageLog->open(QIODevice::ReadWrite); + theGUI->SaveMessageLog(pMessageLog); + int ArcIndex = Archive.AddFile("SbieMsg.log"); + pMessageLog->seek(0); + Files.insert(ArcIndex, pMessageLog); + + if (pTraceLog) { + ArcIndex = Archive.AddFile("SbieTrace.log"); + pTraceLog->seek(0); + Files.insert(ArcIndex, pTraceLog); + } + + m_pUploadProgress->ShowMessage(tr("Compressing Logs")); + Archive.Update(&Files, true, 9); + + if (pSbieLogs->open(QIODevice::ReadOnly)) { + + QHttpPart SbieLogs; + SbieLogs.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/octet-strea")); + SbieLogs.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"sbieLogs\"; filename=\"SbieLogs.7z\"")); + + SbieLogs.setBodyDevice(pSbieLogs); + pMultiPart->append(SbieLogs); + } + } + + if (m_pAttachDmp->isChecked()) { + + QBuffer* pSbieDumps = new QBuffer(pMultiPart); + CArchive Archive("SbieDumps.7z", pSbieDumps); + + QMap Files; + + foreach(auto & UsedBox, ((CBoxAssistant*)wizard())->m_UsedBoxes) { + QDir Dir(UsedBox.pBox->GetFileRoot()); + foreach(const QFileInfo & Info, Dir.entryInfoList(QStringList() << "*.dmp", QDir::Files)) { + if (!UsedBox.OldDumps.contains(Info.fileName())) { + QFile* pCrashDump = new QFile(Info.filePath()); + int ArcIndex = Archive.AddFile(Info.fileName()); + Files.insert(ArcIndex, pCrashDump); + } + } + } + + m_pUploadProgress->ShowMessage(tr("Compressing Dumps")); + Archive.Update(&Files, true, 9); + + if (pSbieDumps->open(QIODevice::ReadOnly)) { + + QHttpPart SbieDumps; + SbieDumps.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/octet-strea")); + SbieDumps.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"sbieDumps\"; filename=\"SbieDumps.7z\"")); + + SbieDumps.setBodyDevice(pSbieDumps); + pMultiPart->append(SbieDumps); + } + } + + if (!m_pMail->text().isEmpty()) { + QHttpPart eMail; + eMail.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"email\"")); + eMail.setBody(m_pMail->text().toUtf8()); + pMultiPart->append(eMail); + } + + QUrl Url("https://sandboxie-plus.com/issues/submit.php"); + QNetworkRequest Request(Url); + //Request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); + Request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy); + //Request.setRawHeader("Accept-Encoding", "gzip"); + QNetworkReply* pReply = pRequestManager->post(Request, pMultiPart); + pMultiPart->setParent(pReply); + + m_pUploadProgress->ShowMessage(tr("Submitting issue report...")); + + connect(pReply, &QNetworkReply::finished, this, [pReply, this]() { + QByteArray Reply = pReply->readAll(); + pReply->deleteLater(); + + m_pUploadProgress->Finish(SB_OK); + m_pUploadProgress.clear(); + + QVariantMap Result = QJsonDocument::fromJson(Reply).toVariant().toMap(); + if (!Result["success"].toBool()) { + QMessageBox::critical(this, "Sandboxie-Plus", tr("Failed to submit issue report, error %1\nTry submitting without the log attached.").arg(Result["error"].toInt())); + return; + } + + QMessageBox::information(this, "Sandboxie-Plus", tr("Your issue report have been successfully submitted, thank you.")); + wizard()->close(); + }); + + connect(pReply, &QNetworkReply::uploadProgress, this, [this](qint64 bytes, qint64 bytesTotal) { + if (bytesTotal != 0 && !m_pUploadProgress.isNull()) + m_pUploadProgress->Progress(100 * bytes / bytesTotal); + }); + + return false; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// CCompletePage +// + +CCompletePage::CCompletePage(QWidget *parent) + : QWizardPage(parent) +{ + setTitle(tr("Troubleshooting Completed")); + setPixmap(QWizard::WatermarkPixmap, QPixmap(":/SideLogo.png")); + + QVBoxLayout *pLayout = new QVBoxLayout; + + m_pLabel = new QLabel; + m_pLabel->setWordWrap(true); + m_pLabel->setText(tr("Thank you for using the Troubleshooting Wizard for Sandboxie-Plus. We apologize for any inconvenience you experienced during the process." + "If you have any additional questions or need further assistance, please don't hesitate to reach out. We're here to help. " + "Thank you for your understanding and cooperation. \n\nYou can click Finish to close this wizard.")); + pLayout->addWidget(m_pLabel); + + // todo: report success optionally + + setLayout(pLayout); +} + +void CCompletePage::initializePage() +{ + //wizard()->button(QWizard::CancelButton)->setEnabled(false); +} diff --git a/SandboxiePlus/SandMan/Wizards/BoxAssistant.h b/SandboxiePlus/SandMan/Wizards/BoxAssistant.h new file mode 100644 index 00000000..d4c6b87b --- /dev/null +++ b/SandboxiePlus/SandMan/Wizards/BoxAssistant.h @@ -0,0 +1,339 @@ +#pragma once + +#include +#include +#include "SbiePlusAPI.h" + +QT_BEGIN_NAMESPACE +class QCheckBox; +class QLabel; +class QLineEdit; +class QRadioButton; +class QButtonGroup; +class QListWidget; +QT_END_NAMESPACE + +class CWizardEngine; + +class MyButtonStyle : public QProxyStyle +{ +public: + MyButtonStyle(QStyle* pStyle) : QProxyStyle(pStyle) {} + + virtual QSize sizeFromContents(ContentsType type, const QStyleOption* option, const QSize& size, const QWidget* widget) const + { + QSize s = QProxyStyle::sizeFromContents(type, option, size, widget); + if (type == CE_PushButton && widget->property("leftButton").toBool()) + { + if (const QStyleOptionButton* button = qstyleoption_cast(option)) + { + if (!button->icon.isNull()) { + s.setWidth(s.width() + 20 + button->iconSize.width()); + } + } + } + return s; + } + + virtual void drawControl(ControlElement element, const QStyleOption* opt, QPainter* p, const QWidget* widget) const + { + if (element == CE_PushButtonLabel && widget->property("leftButton").toBool()) + { + if (const QStyleOptionButton* button = qstyleoption_cast(opt)) + { + QRect textRect = button->rect; + uint tf = Qt::AlignVCenter | Qt::TextShowMnemonic; + if (!proxy()->styleHint(SH_UnderlineShortcut, button, widget)) + tf |= Qt::TextHideMnemonic; + + if (!button->icon.isNull()) { + QRect iconRect; + QIcon::Mode mode = button->state & State_Enabled ? QIcon::Normal : QIcon::Disabled; + if (mode == QIcon::Normal && button->state & State_HasFocus) + mode = QIcon::Active; + QIcon::State state = QIcon::Off; + if (button->state & State_On) + state = QIcon::On; + + QPixmap pixmap = button->icon.pixmap(widget ? widget->window()->windowHandle() : 0, button->iconSize, mode, state); + + int pixmapWidth = pixmap.width() / pixmap.devicePixelRatio(); + int pixmapHeight = pixmap.height() / pixmap.devicePixelRatio(); + int labelWidth = pixmapWidth; + int labelHeight = pixmapHeight; + int iconSpacing = 4;//### 4 is currently hardcoded in QPushButton::sizeHint() + int textWidth = button->fontMetrics.boundingRect(opt->rect, tf, button->text).width(); + if (!button->text.isEmpty()) + labelWidth += (textWidth + iconSpacing); + + textRect.setLeft(textRect.left() + 20 + button->iconSize.width()); + + /*************************************************************/ + // Make the icon rectangle always be 10px in from the left edge + /*************************************************************/ + iconRect = QRect(10, + textRect.y() + (textRect.height() - labelHeight) / 2, + pixmapWidth, pixmapHeight); + + iconRect = visualRect(button->direction, textRect, iconRect); + + /***********************************/ + // Always horizontal align the text + /***********************************/ + tf |= Qt::AlignLeft; + + + if (button->state & (State_On | State_Sunken)) + iconRect.translate(proxy()->pixelMetric(PM_ButtonShiftHorizontal, opt, widget), + proxy()->pixelMetric(PM_ButtonShiftVertical, opt, widget)); + p->drawPixmap(iconRect, pixmap); + } + else { + tf |= Qt::AlignHCenter; + } + if (button->state & (State_On | State_Sunken)) + textRect.translate(proxy()->pixelMetric(PM_ButtonShiftHorizontal, opt, widget), + proxy()->pixelMetric(PM_ButtonShiftVertical, opt, widget)); + + if (button->features & QStyleOptionButton::HasMenu) { + int indicatorSize = proxy()->pixelMetric(PM_MenuButtonIndicator, button, widget); + if (button->direction == Qt::LeftToRight) + textRect = textRect.adjusted(0, 0, -indicatorSize, 0); + else + textRect = textRect.adjusted(indicatorSize, 0, 0, 0); + } + proxy()->drawItemText(p, textRect, tf, button->palette, (button->state & State_Enabled), + button->text, QPalette::ButtonText); + } + return; + } + + + // For all other controls, draw the default + QProxyStyle::drawControl(element, opt, p, widget); + } +}; + + +class CBoxAssistant : public QWizard +{ + Q_OBJECT + +public: + enum { Page_Begin, Page_Group, Page_List, Page_Run, Page_Submit, Page_Complete, Page_Next }; + + CBoxAssistant(QWidget *parent = nullptr); + ~CBoxAssistant(); + + static void ShowAssistant(); + + virtual void accept(); + virtual void reject(); + + QString Tr(const QString& Text) { return m_Translation.value(Text, Text).toString(); } + + static QString GetIssueDir(class C7zFileEngineHandler& IssueFS, QDateTime* pDate = NULL); + +private slots: + + void OnUpdateData(const QVariantMap& Data, const QVariantMap& Params); + void OnDownload(const QString& Path, const QVariantMap& Params); + + void OnToggleDebugger(); + + void OnBoxUsed(const CSandBoxPtr& pBox); + +protected: + friend class CBeginPage; + friend class CGroupPage; + friend class CListPage; + friend class CRunPage; + friend class CSubmitPage; + friend class CCompletePage; + + void LoadIssues(const QString& IssueDir); + + QList GetIssues(const QVariantMap& Root) const; + + void PushIssue(const QVariantMap& Issue) { m_IssueStack.append(Issue); } + void PopIssue() { m_IssueStack.removeLast(); } + QVariantMap CurrentIssue() const { return m_IssueStack.isEmpty() ? QVariantMap() : m_IssueStack.last(); } + + bool StartEngine(); + void KillEngine(); + + CWizardEngine* GetEngine() { return m_pEngine; } + + int m_NextCounter; + + struct SUsedBox + { + CSandBoxPtr pBox; + QStringList OldDumps; + }; + + QList m_UsedBoxes; + +private: + QMap> m_GroupedIssues; + + QList m_IssueStack; + QDateTime m_IssueDate; + + CWizardEngine* m_pEngine; + bool m_bUseDebugger; + QMainWindow* m_pDebugger; + + QVariantMap m_Translation; +}; + +////////////////////////////////////////////////////////////////////////////////////////// +// CBeginPage +// + +class CBeginPage : public QWizardPage +{ + Q_OBJECT + +public: + CBeginPage(QWidget *parent = nullptr); + + void initializePage() override; + int nextId() const override; + bool isComplete() const override; + bool validatePage() override; + +private slots: + void OnCategory(); + +private: + QGridLayout* m_pLayout; + QPushButton* m_pCurrent; + QList m_pWidgets; +}; + +////////////////////////////////////////////////////////////////////////////////////////// +// CGroupPage +// + +class CGroupPage : public QWizardPage +{ + Q_OBJECT + +public: + CGroupPage(QWidget *parent = nullptr); + + void initializePage() override; + void cleanupPage() override; + int nextId() const override; + bool isComplete() const override; + bool validatePage() override; + +private: + QGridLayout* m_pLayout; + QLabel* m_pTopLabel; + QButtonGroup* m_pGroup; + QList m_pWidgets; +}; + +////////////////////////////////////////////////////////////////////////////////////////// +// CListPage +// + +class CListPage : public QWizardPage +{ + Q_OBJECT + +public: + CListPage(QWidget *parent = nullptr); + + void initializePage() override; + void cleanupPage() override; + int nextId() const override; + bool isComplete() const override; + bool validatePage() override; + +private slots: + void ApplyFilter(); + +private: + void LoadIssues(); + + QGridLayout* m_pLayout; + QLineEdit* m_pFilter; + QListWidget* m_pList; + +}; + +////////////////////////////////////////////////////////////////////////////////////////// +// CRunPage +// + +class CRunPage : public QWizardPage +{ + Q_OBJECT + +public: + CRunPage(QWidget *parent = nullptr); + + void initializePage() override; + void cleanupPage() override; + bool isComplete() const override; + int nextId() const override; + bool validatePage() override; + +private slots: + void OnStateChanged(int state, const QString& Text = ""); + void CheckUserInput(); + +private: + QGridLayout* m_pLayout; + QLabel* m_pTopLabel; + QWidget* m_pForm; + QMultiMap m_pWidgets; +}; + +////////////////////////////////////////////////////////////////////////////////////////// +// CSubmitPage +// + +class CSubmitPage : public QWizardPage +{ + Q_OBJECT + +public: + CSubmitPage(QWidget *parent = nullptr); + + void initializePage() override; + int nextId() const override {return -1;} + bool validatePage() override; + +private: + QLabel* m_pTopLabel; + QTextEdit* m_pReport; + QLineEdit* m_pMail; + QCheckBox* m_pAttachIni; + QCheckBox* m_pAttachLog; + QCheckBox* m_pAttachDmp; + + CSbieProgressPtr m_pUploadProgress; +}; + +////////////////////////////////////////////////////////////////////////////////////////// +// CCompletePage +// + +class CCompletePage : public QWizardPage +{ + Q_OBJECT + +public: + CCompletePage(QWidget *parent = nullptr); + + void initializePage() override; + int nextId() const override {return -1;} + +private: + QLabel* m_pLabel; +}; + diff --git a/SandboxiePlus/SandMan/Wizards/NewBoxWizard.cpp b/SandboxiePlus/SandMan/Wizards/NewBoxWizard.cpp index c5cb9135..944993ed 100644 --- a/SandboxiePlus/SandMan/Wizards/NewBoxWizard.cpp +++ b/SandboxiePlus/SandMan/Wizards/NewBoxWizard.cpp @@ -28,6 +28,8 @@ CNewBoxWizard::CNewBoxWizard(bool bAlowTemp, QWidget *parent) connect(this, &QWizard::helpRequested, this, &CNewBoxWizard::showHelp); setWindowTitle(tr("New Box Wizard")); + + setMinimumWidth(600); } void CNewBoxWizard::showHelp() @@ -120,8 +122,10 @@ SB_STATUS CNewBoxWizard::TryToCreateBox() } pBox->SetBool("BlockNetworkFiles", !field("shareAccess").toBool()); - if(field("fakeAdmin").toBool()) + if (field("fakeAdmin").toBool()) { + pBox->SetBool("DropAdminRights", true); pBox->SetBool("FakeAdminRights", true); + } if(field("msiServer").toBool()) pBox->SetBool("MsiInstallerExemptions", true); @@ -617,7 +621,8 @@ bool CSummaryPage::validatePage() SB_STATUS Status = ((CNewBoxWizard*)wizard())->TryToCreateBox(); if (Status.IsError()) { - QMessageBox::critical(this, "Sandboxie-Plus", tr("Failed to create new box: %1").arg(theGUI->FormatError(Status))); + if(Status.GetMsgCode() != SB_Canceled) + QMessageBox::critical(this, "Sandboxie-Plus", tr("Failed to create new box: %1").arg(theGUI->FormatError(Status))); return false; } return true; diff --git a/SandboxiePlus/SandMan/Wizards/SetupWizard.cpp b/SandboxiePlus/SandMan/Wizards/SetupWizard.cpp index f503ee79..f9acd280 100644 --- a/SandboxiePlus/SandMan/Wizards/SetupWizard.cpp +++ b/SandboxiePlus/SandMan/Wizards/SetupWizard.cpp @@ -8,16 +8,19 @@ #include #include "../QSbieAPI/SbieUtils.h" -QString emailRegExp = QStringLiteral(".+@.+"); - -CSetupWizard::CSetupWizard(QWidget *parent) +CSetupWizard::CSetupWizard(int iOldLevel, QWidget *parent) : QWizard(parent) { - setPage(Page_Intro, new CIntroPage); - setPage(Page_Certificate, new CCertificatePage); - setPage(Page_UI, new CUIPage); - setPage(Page_Shell, new CShellPage); - setPage(Page_WFP, new CWFPPage); + if (iOldLevel < SETUP_LVL_1) { + setPage(Page_Intro, new CIntroPage); + setPage(Page_Certificate, new CCertificatePage); + setPage(Page_UI, new CUIPage); + setPage(Page_Shell, new CShellPage); + //setPage(Page_WFP, new CWFPPage); + } + if (iOldLevel < SETUP_LVL_2) { + setPage(Page_Update, new CSBUpdate); + } setPage(Page_Finish, new CFinishPage); setWizardStyle(ModernStyle); @@ -51,46 +54,83 @@ void CSetupWizard::showHelp() lastHelpMessage = message; } -bool CSetupWizard::ShowWizard() +bool CSetupWizard::ShowWizard(int iOldLevel) { - CSetupWizard wizard; + CSetupWizard wizard(iOldLevel, theGUI); if (!theGUI->SafeExec(&wizard)) return false; - //bool useBusiness = wizard.field("useBusiness").toBool(); - //QString Certificate = wizard.field("useCertificate").toString(); - //bool isEvaluate = wizard.field("isEvaluate").toBool(); + if (iOldLevel < SETUP_LVL_1) { + //bool useBusiness = wizard.field("useBusiness").toBool(); + //QString Certificate = wizard.field("useCertificate").toString(); + //bool isEvaluate = wizard.field("isEvaluate").toBool(); - if (wizard.field("useAdvanced").toBool()) - theConf->SetValue("Options/ViewMode", 1); - else if (wizard.field("useSimple").toBool()) - theConf->SetValue("Options/ViewMode", 0); - else if (wizard.field("useClassic").toBool()) - theConf->SetValue("Options/ViewMode", 2); - - if (wizard.field("useBrightMode").toInt()) - theConf->SetValue("Options/UseDarkTheme", 0); - else if (wizard.field("useDarkMode").toInt()) - theConf->SetValue("Options/UseDarkTheme", 1); + if (wizard.field("useAdvanced").toBool()) + theConf->SetValue("Options/ViewMode", 1); + else if (wizard.field("useSimple").toBool()) + theConf->SetValue("Options/ViewMode", 0); + else if (wizard.field("useClassic").toBool()) + theConf->SetValue("Options/ViewMode", 2); - AutorunEnable(wizard.field("isAutoStart").toBool()); - - if (wizard.field("useContecxtMenu").toBool()) - CSettingsWindow__AddContextMenu(); + if (wizard.field("useBrightMode").toInt()) + theConf->SetValue("Options/UseDarkTheme", 0); + else if (wizard.field("useDarkMode").toInt()) + theConf->SetValue("Options/UseDarkTheme", 1); - if (wizard.field("useBrowserIcon").toBool()) - CSettingsWindow__AddBrowserIcon(); + AutorunEnable(wizard.field("isAutoStart").toBool()); - if (wizard.field("useWFP").toBool()) { - theAPI->GetGlobalSettings()->SetBool("NetworkEnableWFP", true); - theAPI->ReloadConfig(true); + if (wizard.field("useContecxtMenu").toBool()) + CSettingsWindow::AddContextMenu(); + + if (wizard.field("useBrowserIcon").toBool()) + CSettingsWindow::AddBrowserIcon(); + + //if (wizard.field("useWFP").toBool()) { + // theAPI->GetGlobalSettings()->SetBool("NetworkEnableWFP", true); + // theAPI->ReloadConfig(true); + //} } - if (wizard.field("isUpdate").toBool()) { - theConf->SetValue("Options/CheckForUpdates", 1); + if (iOldLevel < SETUP_LVL_2) { + + if (wizard.field("updateAll").toBool()) + { + theConf->SetValue("Options/CheckForUpdates", 1); + theConf->SetValue("Options/OnNewUpdate", "install"); + //theConf->SetValue("Options/CheckForTemplates", 1); + theConf->SetValue("Options/CheckForIssues", 1); + theConf->SetValue("Options/CheckForAddons", 1); + } + else + { + if(wizard.field("updateApp").toBool()) + theConf->SetValue("Options/CheckForUpdates", 1); + if(wizard.field("applyHotfixes").toBool()) + theConf->SetValue("Options/OnNewUpdate", "install"); + //if(wizard.field("updateCompat").toBool()) + // theConf->SetValue("Options/CheckForTemplates", 1); + if(wizard.field("updateIssues").toBool()) + theConf->SetValue("Options/CheckForIssues", 1); + if(wizard.field("updateAddons").toBool()) + theConf->SetValue("Options/CheckForAddons", 1); + } + + if (wizard.field("updateAll").toBool() || wizard.field("updateApp").toBool()) { + QString ReleaseChannel; + if (wizard.field("channelStable").toBool()) + ReleaseChannel = "stable"; + else if (wizard.field("channelPreview").toBool()) + ReleaseChannel = "preview"; + else if (wizard.field("channelInsider").toBool()) + ReleaseChannel = "insider"; + if (!ReleaseChannel.isEmpty()) theConf->SetValue("Options/ReleaseChannel", ReleaseChannel); + } } - theConf->SetValue("Options/WizardLevel", 1); + //if (wizard.field("isUpdate").toBool()) + // theConf->SetValue("Options/CheckForUpdates", 1); + + theConf->SetValue("Options/WizardLevel", SETUP_LVL_CURRENT); theGUI->UpdateSettings(true); @@ -101,7 +141,7 @@ void CSetupWizard::ShellUninstall() { AutorunEnable(false); - CSettingsWindow__RemoveContextMenu(); + CSettingsWindow::RemoveContextMenu(); CSbieUtils::RemoveContextMenu2(); // todo: delete desktop browser shortcut and start menu integration @@ -439,7 +479,8 @@ CShellPage::CShellPage(QWidget *parent) int CShellPage::nextId() const { - return CSetupWizard::Page_WFP; + //return CSetupWizard::Page_WFP; + return CSetupWizard::Page_Update; //return CSetupWizard::Page_Finish; } @@ -447,7 +488,7 @@ int CShellPage::nextId() const // CWFPPage // -CWFPPage::CWFPPage(QWidget *parent) +/*CWFPPage::CWFPPage(QWidget *parent) : QWizardPage(parent) { setTitle(tr("Configure Sandboxie-Plus network filtering")); @@ -475,6 +516,147 @@ CWFPPage::CWFPPage(QWidget *parent) } int CWFPPage::nextId() const +{ + return CSetupWizard::Page_Finish; +}*/ + +////////////////////////////////////////////////////////////////////////////////////////// +// CSBUpdate +// + +CSBUpdate::CSBUpdate(QWidget *parent) + : QWizardPage(parent) +{ + setTitle(tr("Configure Sandboxie-Plus updater")); + setSubTitle(tr("Like with any other security product it's important to keep your Sandboxie-Plus up to date.")); + + QGridLayout *layout = new QGridLayout; + layout->setSpacing(3); + + int row = 0; + int rows = 4; + + m_pUpdate = new QCheckBox(tr("Regularly Check for all udpates to Sandboxie-Plus and optional components")); + m_pUpdate->setToolTip(tr("Let sandboxie regularly check for latest updates.")); + layout->addWidget(m_pUpdate, row++, 0, 1, rows); + connect(m_pUpdate, &QCheckBox::toggled, this, &CSBUpdate::UpdateOptions); + registerField("updateAll", m_pUpdate); + + QWidget* pSpacer = new QWidget(); + pSpacer->setMinimumHeight(16); + pSpacer->setMaximumWidth(16); + layout->addWidget(pSpacer, row+5, 0, 1, 1); + + m_pVersion = new QCheckBox(tr("Check for new Sandboxie-Plus versions:")); + m_pVersion->setToolTip(tr("Check for new Sandboxie-Plus builds.")); + layout->addWidget(m_pVersion, row++, 1, 1, rows-2); + //layout->addWidget(new QComboBox(), row-1, 3, 1, 1); + connect(m_pVersion, &QCheckBox::toggled, this, &CSBUpdate::UpdateOptions); + registerField("updateApp", m_pVersion); + + m_pChanelInfo = new QLabel(tr("Sellect in which update channel to look for new Sandboxie-Plus builds:")); + m_pChanelInfo->setMinimumHeight(20); + layout->addWidget(m_pChanelInfo, row++, 1, 1, rows-1); + + pSpacer = new QWidget(); + pSpacer->setMinimumHeight(16); + pSpacer->setMaximumWidth(16); + layout->addWidget(pSpacer, row, 1, 1, 1); + + m_pStable = new QRadioButton(tr("In the Stable Channel")); + m_pStable->setToolTip(tr("The stable channel contains the latest stable GitHub releases.")); + layout->addWidget(m_pStable, row++, 2, 1, rows-2); + registerField("channelStable", m_pStable); + + m_pPreview = new QRadioButton(tr("In the Preview Channel - with newest experimental changes")); + m_pPreview->setToolTip(tr("The preview channel contains the latest GitHub pre-releases.")); + layout->addWidget(m_pPreview, row++, 2, 1, rows-2); + registerField("channelPreview", m_pPreview); + + m_pInsider = new QRadioButton(tr("In the Insider Channel - exclusive features")); + m_pInsider->setToolTip(tr("The Insider channel offers early access to new features and bugfixes that will eventually be released to the public, " + "as well as all relevant improvements from the stable channel. \nUnlike the preview channel, it does not include untested, potentially breaking, " + "or experimental changes that may not be ready for wider use.")); + layout->addWidget(m_pInsider, row, 2, 1, 1); + registerField("channelInsider", m_pInsider); + QLabel* pInsiderInfo = new QLabel(tr("More about the Insider Channel")); + connect(pInsiderInfo, SIGNAL(linkActivated(const QString&)), theGUI, SLOT(OpenUrl(const QString&))); + layout->addWidget(pInsiderInfo, row++, 3, 1, 1); + + //m_pTemplates = new QCheckBox(tr("Keep Compatybility Templates up to date")); + //m_pTemplates->setToolTip(tr("Check for latest compatybility tempaltes.")); + //layout->addWidget(m_pTemplates, row++, 1, 1, rows-1); + //registerField("updateCompat", m_pTemplates); + + m_pHotfixes = new QCheckBox(tr("Keep Compatybility Templates up to date and apply hotfixes")); + m_pHotfixes->setToolTip(tr("Check for latest compatybility tempaltes and hotfixes.")); + layout->addWidget(m_pHotfixes, row++, 1, 1, rows-1); + registerField("applyHotfixes", m_pHotfixes); + + m_pIssues = new QCheckBox(tr("Get the latest Scripts for the Troubleshooting Wizard")); + m_pIssues->setToolTip(tr("Check for latest troubleshooting scripts for the troubleshooting wizars.")); + layout->addWidget(m_pIssues, row++, 1, 1, rows-1); + registerField("updateIssues", m_pIssues); + + m_pAddons = new QCheckBox(tr("Keep the list of optional Addon components up to date")); + m_pAddons->setToolTip(tr("Check for latest avaialble addons.")); + layout->addWidget(m_pAddons, row++, 1, 1, rows-1); + registerField("updateAddons", m_pAddons); + + m_pUpdateInfo = new QLabel(); + m_pUpdateInfo->setWordWrap(true); + //m_pUpdateInfo->setText(tr("Sandboxie-Plus applies many application restrictions which may occasionally lead to compatibility issues, necessitating mitigation efforts. " + // "Compatibility may be broken by new Windows updates and changes within sandboxed applications themselves. " + // "To ensure smooth operation, it is highly recommended to regularly check for Sandboxie-Plus updates, apply the latest compatibility templates, and keep troubleshooting scripts up-to-date.")); + m_pUpdateInfo->setText(tr("Sandboxie-Plus applies strict application restrictions, which can lead to compatibility issues. " + "Stay updated with Sandboxie-Plus, including compatibility templates and troubleshooting, to ensure smooth operation amid Windows updates and application changes.")); + layout->addWidget(m_pUpdateInfo, row++, 0, 1, rows); + + layout->addItem(new QSpacerItem(10, 10, QSizePolicy::Fixed, QSizePolicy::Expanding), row++, 0); + + m_pBottomLabel = new QLabel(tr("Access to the latest compatibility templates and the online troubleshooting database requires a valid supporter certificate.")); + connect(m_pBottomLabel, SIGNAL(linkActivated(const QString&)), theGUI, SLOT(OpenUrl(const QString&))); + m_pBottomLabel->setWordWrap(true); + layout->addWidget(m_pBottomLabel, row++, 0, 1, rows); + + setLayout(layout); +} + +void CSBUpdate::initializePage() +{ + m_pUpdate->setChecked(true); + m_pStable->setChecked(true); + + m_pBottomLabel->setVisible(!g_CertInfo.valid || g_CertInfo.expired); + + UpdateOptions(); +} + +void CSBUpdate::UpdateOptions() +{ + m_pVersion->setVisible(!m_pUpdate->isChecked()); + //m_pTemplates->setVisible(!m_pUpdate->isChecked()); + m_pHotfixes->setVisible(!m_pUpdate->isChecked()); + m_pIssues->setVisible(!m_pUpdate->isChecked()); + m_pAddons->setVisible(!m_pUpdate->isChecked()); + m_pChanelInfo->setVisible(m_pUpdate->isChecked()); + m_pUpdateInfo->setVisible(m_pUpdate->isChecked()); + + if (m_pUpdate->isChecked()) { + m_pVersion->setChecked(true); + //m_pTemplates->setChecked(true); + m_pIssues->setChecked(true); + m_pAddons->setChecked(true); + } + + m_pStable->setEnabled(m_pVersion->isChecked()); + m_pPreview->setEnabled(m_pVersion->isChecked()); + m_pInsider->setEnabled(g_CertInfo.insider && m_pVersion->isChecked()); + + m_pHotfixes->setEnabled(m_pVersion->isChecked()); +} + +int CSBUpdate::nextId() const { return CSetupWizard::Page_Finish; } @@ -496,19 +678,19 @@ CFinishPage::CFinishPage(QWidget *parent) m_pLabel->setText(tr("Almost complete, click Finish to apply all selected options and conclude the wizard.")); layout->addWidget(m_pLabel); - QWidget* pSpacer = new QWidget(); - pSpacer->setMinimumHeight(16); - layout->addWidget(pSpacer); + //QWidget* pSpacer = new QWidget(); + //pSpacer->setMinimumHeight(16); + //layout->addWidget(pSpacer); //QLabel* pLabel = new QLabel; //pLabel->setWordWrap(true); //pLabel->setText(tr("Like with any other security product it's important to keep your Sandboxie-Plus up to date.")); //layout->addWidget(pLabel); - m_pUpdate = new QCheckBox(tr("Keep Sandboxie-Plus up to date.")); - m_pUpdate->setChecked(true); - layout->addWidget(m_pUpdate); - registerField("isUpdate", m_pUpdate); + //m_pUpdate = new QCheckBox(tr("Keep Sandboxie-Plus up to date.")); + //m_pUpdate->setChecked(true); + //layout->addWidget(m_pUpdate); + //registerField("isUpdate", m_pUpdate); setLayout(layout); } diff --git a/SandboxiePlus/SandMan/Wizards/SetupWizard.h b/SandboxiePlus/SandMan/Wizards/SetupWizard.h index 42c74f01..46fb193f 100644 --- a/SandboxiePlus/SandMan/Wizards/SetupWizard.h +++ b/SandboxiePlus/SandMan/Wizards/SetupWizard.h @@ -9,16 +9,20 @@ class QLineEdit; class QRadioButton; QT_END_NAMESPACE +#define SETUP_LVL_1 1 +#define SETUP_LVL_2 2 +#define SETUP_LVL_CURRENT SETUP_LVL_2 + class CSetupWizard : public QWizard { Q_OBJECT public: - enum { Page_Intro, Page_Certificate, Page_UI, Page_Shell, Page_WFP, Page_Finish }; + enum { Page_Intro, Page_Certificate, Page_UI, Page_Shell, Page_Update, Page_Finish }; - CSetupWizard(QWidget *parent = nullptr); + CSetupWizard(int iOldLevel = 0, QWidget *parent = nullptr); - static bool ShowWizard(); + static bool ShowWizard(int iOldLevel = 0); static void ShellUninstall(); @@ -117,7 +121,7 @@ private: // CWFPPage // -class CWFPPage : public QWizardPage +/*class CWFPPage : public QWizardPage { Q_OBJECT @@ -128,6 +132,39 @@ public: private: QCheckBox *m_pUseWFP; +};*/ + +////////////////////////////////////////////////////////////////////////////////////////// +// CSBUpdate +// + +class CSBUpdate : public QWizardPage +{ + Q_OBJECT + +public: + CSBUpdate(QWidget *parent = nullptr); + + void initializePage() override; + + int nextId() const override; + +private slots: + void UpdateOptions(); + +private: + QCheckBox* m_pUpdate; + QCheckBox* m_pVersion; + QLabel* m_pChanelInfo; + QRadioButton* m_pStable; + QRadioButton* m_pPreview; + QRadioButton* m_pInsider; + QCheckBox* m_pHotfixes; + //QCheckBox* m_pTemplates; + QCheckBox* m_pIssues; + QCheckBox* m_pAddons; + QLabel* m_pUpdateInfo; + QLabel* m_pBottomLabel; }; ////////////////////////////////////////////////////////////////////////////////////////// @@ -147,6 +184,6 @@ public: private: QLabel *m_pLabel; - QCheckBox *m_pUpdate; + //QCheckBox *m_pUpdate; }; diff --git a/SandboxiePlus/SandMan/Wizards/TemplateWizard.cpp b/SandboxiePlus/SandMan/Wizards/TemplateWizard.cpp index c632df4d..447a758d 100644 --- a/SandboxiePlus/SandMan/Wizards/TemplateWizard.cpp +++ b/SandboxiePlus/SandMan/Wizards/TemplateWizard.cpp @@ -336,7 +336,7 @@ CBrowserTypePage::CBrowserTypePage(QWidget *parent) layout->addWidget(new QLabel(tr("Enter browser name:")), row++, 0); m_pName = new QLineEdit(); - m_pName->setMaxLength(32); + m_pName->setMaxLength(32); // BOXNAME_COUNT m_pName->setMaximumWidth(150); layout->addWidget(m_pName, row++, 0, 1, 1); connect(m_pName, SIGNAL(textChanged(const QString&)), this, SLOT(OnNameChanged())); diff --git a/SandboxiePlus/SandMan/main.cpp b/SandboxiePlus/SandMan/main.cpp index ab47af70..737c4694 100644 --- a/SandboxiePlus/SandMan/main.cpp +++ b/SandboxiePlus/SandMan/main.cpp @@ -28,8 +28,12 @@ int main(int argc, char *argv[]) g_CertInfo.business = GetArguments(g_Certificate, L'\n', L':').value("TYPE").toUpper().contains("BUSINESS"); } + // use AppFolder/PlusData when present, else fallback to AppFolder + QString ConfDir = AppDir + "\\PlusData"; + if(!QFile::exists(ConfDir)) + ConfDir = AppDir; // use a shared setting location when used in a business environment for easier administration - theConf = new CSettings(AppDir, "Sandboxie-Plus", g_CertInfo.business); + theConf = new CSettings(ConfDir, "Sandboxie-Plus", g_CertInfo.business); #ifndef _DEBUG InitMiniDumpWriter(QString("SandMan-v%1").arg(CSandMan::GetVersion()).toStdWString().c_str() , QString(theConf->GetConfigDir()).replace("/", "\\").toStdWString().c_str()); @@ -101,22 +105,34 @@ int main(int argc, char *argv[]) g_PendingMessage = "Op:" + Op; } - CmdPos = Args.indexOf("/box:__ask__", Qt::CaseInsensitive); + CmdPos = -1; + for (int i = 0; i < Args.size(); i++) { + if (Args[i].left(5).compare("/box:", Qt::CaseInsensitive) == 0) + CmdPos = i; + } if (CmdPos != -1) { // Note: a escaped command ending with \" will fail and unescape " //QString CommandLine; //for (int i = CmdPos + 1; i < Args.count(); i++) // CommandLine += "\"" + Args[i] + "\" "; //g_PendingMessage = "Run:" + CommandLine.trimmed(); - LPWSTR ChildCmdLine = wcsstr(GetCommandLineW(), L"/box:__ask__") + 13; + LPWSTR cmdLine0 = wcsstr(GetCommandLineW(), L"/box:"); + if (!cmdLine0) return -1; + LPWSTR cmdLine = wcschr(cmdLine0 + 5, L' '); + if (!cmdLine) return -2; if (IsBoxed) { - ShellExecute(NULL, L"open", ChildCmdLine, NULL, NULL, SW_SHOWNORMAL); + ShellExecute(NULL, L"open", cmdLine + 1, NULL, NULL, SW_SHOWNORMAL); return 0; } - g_PendingMessage = "Run:" + QString::fromWCharArray(ChildCmdLine); + g_PendingMessage = "Run:" + QString::fromWCharArray(cmdLine + 1); + g_PendingMessage += "\nFrom:" + QDir::currentPath(); + + QString BoxName = QString::fromWCharArray(cmdLine0 + 5, cmdLine - (cmdLine0 + 5)); + if(BoxName != "__ask__") + g_PendingMessage += "\nIn:" + BoxName; } if (IsBoxed) { diff --git a/SandboxiePlus/version.h b/SandboxiePlus/version.h index 21381e70..bddd14a1 100644 --- a/SandboxiePlus/version.h +++ b/SandboxiePlus/version.h @@ -1,8 +1,8 @@ #pragma once #define VERSION_MJR 1 -#define VERSION_MIN 9 -#define VERSION_REV 8 +#define VERSION_MIN 10 +#define VERSION_REV 0 #define VERSION_UPD 0 #ifndef STR diff --git a/SandboxieTools/UpdUtil/Common/WebUtils.cpp b/SandboxieTools/Common/WebUtils.cpp similarity index 95% rename from SandboxieTools/UpdUtil/Common/WebUtils.cpp rename to SandboxieTools/Common/WebUtils.cpp index d1b52863..08abd3ca 100644 --- a/SandboxieTools/UpdUtil/Common/WebUtils.cpp +++ b/SandboxieTools/Common/WebUtils.cpp @@ -1,4 +1,13 @@ -#include "../framework.h" +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +// Windows Header Files +#include +// C RunTime Header Files +#include +#include +#include +#include +#include + #include "helpers.h" #include diff --git a/SandboxieTools/UpdUtil/Common/WebUtils.h b/SandboxieTools/Common/WebUtils.h similarity index 100% rename from SandboxieTools/UpdUtil/Common/WebUtils.h rename to SandboxieTools/Common/WebUtils.h diff --git a/SandboxieTools/UpdUtil/Common/base64.c b/SandboxieTools/Common/base64.c similarity index 100% rename from SandboxieTools/UpdUtil/Common/base64.c rename to SandboxieTools/Common/base64.c diff --git a/SandboxieTools/UpdUtil/Common/dirent.h b/SandboxieTools/Common/dirent.h similarity index 100% rename from SandboxieTools/UpdUtil/Common/dirent.h rename to SandboxieTools/Common/dirent.h diff --git a/SandboxieTools/UpdUtil/Common/helpers.cpp b/SandboxieTools/Common/helpers.cpp similarity index 53% rename from SandboxieTools/UpdUtil/Common/helpers.cpp rename to SandboxieTools/Common/helpers.cpp index bfdca55f..6fdd35ab 100644 --- a/SandboxieTools/UpdUtil/Common/helpers.cpp +++ b/SandboxieTools/Common/helpers.cpp @@ -1,4 +1,31 @@ -#include "../framework.h" +/* + * Copyright (c) 2020-2023, David Xanatos + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +// Windows Header Files +#include +// C RunTime Header Files +#include +#include +#include +#include +#include + +#include "helpers.h" #include "dirent.h" OSVERSIONINFOW g_osvi; @@ -59,4 +86,25 @@ std::wstring hexStr(unsigned char* data, int len) s[2 * i + 1] = hexmap[data[i] & 0x0F]; } return s; +} + +bool FileExists(const wchar_t* path) +{ + if (GetFileAttributes(path) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND) + return false; + return true; +} + +void DbgPrint(const wchar_t* format, ...) +{ + va_list va_args; + va_start(va_args, format); + + wchar_t tmp1[510]; + + _vsnwprintf(tmp1, sizeof(tmp1), format, va_args); + + OutputDebugStringW(tmp1); + + va_end(va_args); } \ No newline at end of file diff --git a/SandboxieTools/UpdUtil/Common/helpers.h b/SandboxieTools/Common/helpers.h similarity index 78% rename from SandboxieTools/UpdUtil/Common/helpers.h rename to SandboxieTools/Common/helpers.h index 4abfc4a2..1dbd5f29 100644 --- a/SandboxieTools/UpdUtil/Common/helpers.h +++ b/SandboxieTools/Common/helpers.h @@ -1,5 +1,34 @@ +/* + * Copyright (c) 2020-2023, David Xanatos + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #pragma once -#include "../framework.h" + +// std includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include void InitOsVersionInfo(); extern OSVERSIONINFOW g_osvi; @@ -123,4 +152,8 @@ const T* wildstrcmp(const T* Wild, const T* Str) while (*Wild == '*') Wild++; return *Wild ? NULL : Str; // rest -} \ No newline at end of file +} + +bool FileExists(const wchar_t* path); + +void DbgPrint(const wchar_t* format, ...); \ No newline at end of file diff --git a/SandboxieTools/UpdUtil/Common/json/JSON.cpp b/SandboxieTools/Common/json/JSON.cpp similarity index 100% rename from SandboxieTools/UpdUtil/Common/json/JSON.cpp rename to SandboxieTools/Common/json/JSON.cpp diff --git a/SandboxieTools/UpdUtil/Common/json/JSON.h b/SandboxieTools/Common/json/JSON.h similarity index 100% rename from SandboxieTools/UpdUtil/Common/json/JSON.h rename to SandboxieTools/Common/json/JSON.h diff --git a/SandboxieTools/UpdUtil/Common/json/JSONValue.cpp b/SandboxieTools/Common/json/JSONValue.cpp similarity index 100% rename from SandboxieTools/UpdUtil/Common/json/JSONValue.cpp rename to SandboxieTools/Common/json/JSONValue.cpp diff --git a/SandboxieTools/UpdUtil/Common/json/JSONValue.h b/SandboxieTools/Common/json/JSONValue.h similarity index 100% rename from SandboxieTools/UpdUtil/Common/json/JSONValue.h rename to SandboxieTools/Common/json/JSONValue.h diff --git a/SandboxieTools/UpdUtil/Common/verify.c b/SandboxieTools/Common/verify.c similarity index 95% rename from SandboxieTools/UpdUtil/Common/verify.c rename to SandboxieTools/Common/verify.c index 1c3196fc..4b1c0f52 100644 --- a/SandboxieTools/UpdUtil/Common/verify.c +++ b/SandboxieTools/Common/verify.c @@ -3,18 +3,8 @@ * * Based on the processhacker's CustomSignTool, Copyright 2016 wj32 * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This program is free software under the MIT license. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . */ #include @@ -381,11 +371,35 @@ CleanupExit: } -NTSTATUS VerifyFileSignature(const wchar_t* FilePath) +NTSTATUS VerifyFileSignatureImpl(const wchar_t* FilePath, PVOID Signature, ULONG SignatureSize) { NTSTATUS status; ULONG hashSize; PVOID hash = NULL; + + // Hash the file. + + if (!NT_SUCCESS(status = MyHashFile(FilePath, &hash, &hashSize))) + goto CleanupExit; + + // Verify the hash. + + if (!NT_SUCCESS(status = VerifyHashSignature((PUCHAR)hash, hashSize, (PUCHAR)Signature, SignatureSize))) + { + goto CleanupExit; + } + +CleanupExit: + if (hash) + free(hash); + + return status; +} + + +NTSTATUS VerifyFileSignature(const wchar_t* FilePath) +{ + NTSTATUS status; ULONG signatureSize; PVOID signature = NULL; WCHAR* signatureFileName = NULL; @@ -405,23 +419,13 @@ NTSTATUS VerifyFileSignature(const wchar_t* FilePath) if (!NT_SUCCESS(status = MyReadFile(signatureFileName, KPH_SIGNATURE_MAX_SIZE, &signature, &signatureSize))) goto CleanupExit; - // Hash the file. + // Verify the signature. - if (!NT_SUCCESS(status = MyHashFile(FilePath, &hash, &hashSize))) - goto CleanupExit; - - // Verify the hash. - - if (!NT_SUCCESS(status = VerifyHashSignature((PUCHAR)hash, hashSize, (PUCHAR)signature, signatureSize))) - { - goto CleanupExit; - } + status = VerifyFileSignatureImpl(FilePath, signature, signatureSize); CleanupExit: if (signature) free(signature); - if (hash) - free(hash); if (signatureFileName) free(signatureFileName); @@ -490,4 +494,4 @@ NTSTATUS CreateKeyPair(_In_ PCWSTR PrivFile, _In_ PCWSTR PubFile) BCryptCloseAlgorithmProvider(signAlgHandle, 0); return status; -} \ No newline at end of file +} diff --git a/SandboxieTools/UpdUtil/UpdUtil.cpp b/SandboxieTools/UpdUtil/UpdUtil.cpp index 043f970b..6864ea06 100644 --- a/SandboxieTools/UpdUtil/UpdUtil.cpp +++ b/SandboxieTools/UpdUtil/UpdUtil.cpp @@ -1,14 +1,28 @@ -// UpdUtil.cpp : Defines the entry point for the application. -// +/* + * Copyright 2022-2023 David Xanatos, xanasoft.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ #include "framework.h" #include #include #include #include -#include "common/helpers.h" -#include "common/WebUtils.h" -#include "common/json/JSON.h" +#include "../Common/helpers.h" +#include "../Common/WebUtils.h" +#include "../Common/json/JSON.h" #include "UpdUtil.h" @@ -588,6 +602,8 @@ void PrintUsage() std::wcout << L"" << std::endl; } + + bool HasFlag(const std::vector& arguments, std::wstring name) { return std::find(arguments.begin(), arguments.end(), L"/" + name) != arguments.end(); @@ -596,7 +612,7 @@ bool HasFlag(const std::vector& arguments, std::wstring name) std::wstring GetArgument(const std::vector& arguments, std::wstring name) { std::wstring prefix = L"/" + name + L":"; - for (int i = 0; i < arguments.size(); i++) { + for (size_t i = 0; i < arguments.size(); i++) { if (_wcsicmp(arguments[i].substr(0, prefix.length()).c_str(), prefix.c_str()) == 0) { return arguments[i].substr(prefix.length()); } @@ -604,13 +620,6 @@ std::wstring GetArgument(const std::vector& arguments, std::wstrin return L""; } -bool FileExists(const wchar_t* path) -{ - if (GetFileAttributes(path) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND) - return false; - return true; -} - int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, diff --git a/SandboxieTools/UpdUtil/UpdUtil.vcxproj b/SandboxieTools/UpdUtil/UpdUtil.vcxproj index d8d84742..7c0050ea 100644 --- a/SandboxieTools/UpdUtil/UpdUtil.vcxproj +++ b/SandboxieTools/UpdUtil/UpdUtil.vcxproj @@ -211,23 +211,23 @@ - - - - - + + + + + - - - - - - + + + + + + diff --git a/SandboxieTools/UpdUtil/UpdUtil.vcxproj.filters b/SandboxieTools/UpdUtil/UpdUtil.vcxproj.filters index 9dd9a2ea..96ea3452 100644 --- a/SandboxieTools/UpdUtil/UpdUtil.vcxproj.filters +++ b/SandboxieTools/UpdUtil/UpdUtil.vcxproj.filters @@ -33,21 +33,21 @@ Header Files - + + Common + + + Common + + + Common + + Common\json - + Common\json - - Common - - - Common - - - Common - @@ -56,24 +56,24 @@ Source Files - + + Common + + + Common + + + Common + + + Common + + Common\json - + Common\json - - Common - - - Common - - - Common - - - Common -