2022-08-09 17:19:46 +01:00
# include "stdafx.h"
# include "OnlineUpdater.h"
# include "../MiscHelpers/Common/Common.h"
2022-11-20 16:23:15 +00:00
# include "../MiscHelpers/Common/OtherFunctions.h"
2022-08-09 17:19:46 +01:00
# include "SandMan.h"
# include "Windows/SettingsWindow.h"
# include <QUrlQuery>
# include <QJsonDocument>
2022-11-20 16:23:15 +00:00
# include <QJsonObject>
2022-08-09 17:19:46 +01:00
# include "../MiscHelpers/Common/CheckableMessageBox.h"
# include <QMessageBox>
2022-11-20 16:23:15 +00:00
# include "../../SandboxieLive/UpdUtil/UpdUtil.h"
# include <QCryptographicHash>
# include "Helpers/WinAdmin.h"
2022-08-09 17:19:46 +01:00
# include <windows.h>
2022-11-20 16:23:15 +00:00
# ifdef _DEBUG
2022-08-09 17:19:46 +01:00
2022-11-20 16:23:15 +00:00
// mess with a dummy installation when debugging
# undef VERSION_MJR
# define VERSION_MJR 1
# undef VERSION_MIN
# define VERSION_MIN 5
# undef VERSION_REV
# define VERSION_REV 3
# undef VERSION_UPD
# define VERSION_UPD 0
# define DUMMY_PATH "C:\\Projects\\Sandboxie\\SandboxieLive\\x64\\Debug\\Test"
# endif
DWORD GetIdleTime ( ) // in seconds
2022-08-09 17:19:46 +01:00
{
2022-11-20 16:23:15 +00:00
LASTINPUTINFO lastInPut ;
GetLastInputInfo ( & lastInPut ) ;
return ( GetTickCount ( ) - lastInPut . dwTime ) / 1000 ;
2022-08-09 17:19:46 +01:00
}
2022-11-20 16:23:15 +00:00
COnlineUpdater : : COnlineUpdater ( QObject * parent ) : QObject ( parent )
2022-08-09 17:19:46 +01:00
{
2022-11-20 16:23:15 +00:00
m_IgnoredUpdates = theConf - > GetStringList ( " Options/IgnoredUpdates " ) ;
m_RequestManager = NULL ;
m_pUpdaterUtil = NULL ;
m_CheckMode = eInit ;
2022-12-16 14:26:23 +00:00
int iUpdate = 0 ;
QString UpdateStr = ParseVersionStr ( theConf - > GetString ( " Updater/PendingUpdate " ) , & iUpdate ) ;
if ( ! IsVersionNewer ( UpdateStr ) & & ( UpdateStr ! = GetCurrentVersion ( ) | | iUpdate < = GetCurrentUpdate ( ) ) )
2022-12-17 20:06:15 +00:00
theConf - > SetValue ( " Updater/PendingUpdate " , " " ) ; // it seems update has been applied
2022-12-16 14:26:23 +00:00
2022-11-20 16:23:15 +00:00
bool bIsInstallerReady = false ;
QString FilePath = theConf - > GetString ( " Updater/InstallerPath " ) ;
if ( ! FilePath . isEmpty ( ) & & QFile : : exists ( FilePath ) ) {
QString ReleaseStr = ParseVersionStr ( theConf - > GetString ( " Updater/InstallerVersion " ) ) ;
if ( IsVersionNewer ( ReleaseStr ) ) {
bIsInstallerReady = true ;
}
}
QString OnNewRelease = theConf - > GetString ( " Options/OnNewRelease " , " download " ) ;
bool bCanRunInstaller = OnNewRelease = = " install " ;
bool bIsUpdateReady = false ;
2023-02-02 08:03:01 +00:00
QVariantMap Update = QJsonDocument : : fromJson ( ReadFileAsString ( GetUpdateDir ( ) + " / " UPDATE_FILE ) . toUtf8 ( ) ) . toVariant ( ) . toMap ( ) ;
2022-11-20 16:23:15 +00:00
if ( ! Update . isEmpty ( ) ) {
int iUpdate = 0 ;
QString UpdateStr = ParseVersionStr ( theConf - > GetString ( " Updater/UpdateVersion " ) , & iUpdate ) ;
if ( IsVersionNewer ( UpdateStr ) | | ( UpdateStr = = GetCurrentVersion ( ) & & iUpdate > GetCurrentUpdate ( ) ) ) {
if ( ScanUpdateFiles ( Update ) = = eNone ) // check if this update has already been applied
theConf - > SetValue ( " Updater/CurrentUpdate " , MakeVersionStr ( Update ) ) ; // cache result
else
bIsUpdateReady = true ;
}
}
2022-12-03 19:25:04 +00:00
QString OnNewUpdate = theConf - > GetString ( " Options/OnNewUpdate " , " ignore " ) ;
2022-11-20 16:23:15 +00:00
bool bCanApplyUpdate = OnNewUpdate = = " install " ;
if ( bIsInstallerReady & & bCanRunInstaller )
m_CheckMode = ePendingInstall ;
else if ( bIsUpdateReady & & bCanApplyUpdate )
m_CheckMode = ePendingUpdate ;
2022-08-09 17:19:46 +01:00
}
void COnlineUpdater : : Process ( )
{
2022-11-20 16:23:15 +00:00
int iCheckUpdates = theConf - > GetInt ( " Options/CheckForUpdates " , 2 ) ;
if ( iCheckUpdates ! = 0 )
{
time_t NextUpdateCheck = theConf - > GetUInt64 ( " Options/NextCheckForUpdates " , 0 ) ;
if ( NextUpdateCheck = = 0 )
theConf - > SetValue ( " Options/NextCheckForUpdates " , QDateTime : : currentDateTime ( ) . addDays ( 7 ) . toSecsSinceEpoch ( ) ) ;
else if ( QDateTime : : currentDateTime ( ) . toSecsSinceEpoch ( ) > = NextUpdateCheck )
{
if ( iCheckUpdates = = 2 )
{
bool bCheck = false ;
iCheckUpdates = CCheckableMessageBox : : question ( theGUI , " Sandboxie-Plus " , tr ( " Do you want to check if there is a new version of Sandboxie-Plus? " )
, tr ( " Don't show this message again. " ) , & bCheck , QDialogButtonBox : : Yes | QDialogButtonBox : : No , QDialogButtonBox : : Yes , QMessageBox : : Information ) = = QDialogButtonBox : : Ok ? 1 : 0 ;
2022-08-09 17:19:46 +01:00
2022-11-20 16:23:15 +00:00
if ( bCheck )
theConf - > SetValue ( " Options/CheckForUpdates " , iCheckUpdates ) ;
}
if ( iCheckUpdates = = 0 )
theConf - > SetValue ( " Options/NextCheckForUpdates " , QDateTime : : currentDateTime ( ) . addDays ( 7 ) . toSecsSinceEpoch ( ) ) ;
else
{
theConf - > SetValue ( " Options/NextCheckForUpdates " , QDateTime : : currentDateTime ( ) . addDays ( 1 ) . toSecsSinceEpoch ( ) ) ;
CheckForUpdates ( false ) ;
}
}
}
if ( ! m_pUpdateProgress . isNull ( ) & & m_RequestManager ! = NULL ) {
if ( m_pUpdateProgress - > IsCanceled ( ) ) {
m_pUpdateProgress - > Finish ( SB_OK ) ;
m_pUpdateProgress . clear ( ) ;
m_RequestManager - > AbortAll ( ) ;
if ( m_pUpdaterUtil & & m_pUpdaterUtil - > state ( ) = = QProcess : : Running )
m_pUpdaterUtil - > terminate ( ) ;
}
}
if ( m_CheckMode = = ePendingUpdate | | m_CheckMode = = ePendingInstall )
{
// When auto install/apply is active wait for the user to be idle
# ifndef _DEBUG
if ( GetIdleTime ( ) > theConf - > GetInt ( " Options/UpdateIdleTime " , 30 * 60 ) ) // default 30 minutes
# endif
// and wait for no processes running in the boxes
if ( theAPI - > IsConnected ( ) & & theAPI - > GetAllProcesses ( ) . isEmpty ( ) )
{
if ( m_CheckMode = = ePendingUpdate )
ApplyUpdate ( true ) ;
else if ( m_CheckMode = = ePendingInstall )
RunInstaller ( true ) ;
m_CheckMode = eInit ;
2022-08-09 17:19:46 +01:00
}
}
}
2022-08-11 23:09:35 +01:00
void COnlineUpdater : : GetUpdates ( QObject * receiver , const char * member , const QVariantMap & Params )
2022-06-08 16:23:19 +01:00
{
2022-08-11 23:09:35 +01:00
CGetUpdatesJob * pJob = new CGetUpdatesJob ( Params , this ) ;
QObject : : connect ( pJob , SIGNAL ( UpdateData ( const QVariantMap & , const QVariantMap & ) ) , receiver , member , Qt : : QueuedConnection ) ;
2022-06-08 16:23:19 +01:00
if ( m_RequestManager = = NULL )
m_RequestManager = new CNetworkAccessManager ( 30 * 1000 , this ) ;
QUrlQuery Query ;
2022-11-20 16:23:15 +00:00
Query . addQueryItem ( " action " , " update " ) ;
2022-06-08 16:23:19 +01:00
Query . addQueryItem ( " software " , " sandboxie-plus " ) ;
2023-02-03 07:05:10 +00:00
//QString Branch = theConf->GetString("Options/ReleaseBranch");
//if (!Branch.isEmpty())
// Query.addQueryItem("branch", Branch);
2022-11-20 16:23:15 +00:00
//Query.addQueryItem("version", theGUI->GetVersion());
//Query.addQueryItem("version", QString::number(VERSION_MJR) + "." + QString::number(VERSION_MIN) + "." + QString::number(VERSION_REV) + "." + QString::number(VERSION_UPD));
Query . addQueryItem ( " version " , QString : : number ( VERSION_MJR ) + " . " + QString : : number ( VERSION_MIN ) + " . " + QString : : number ( VERSION_REV ) ) ;
2022-06-08 16:23:19 +01:00
Query . addQueryItem ( " system " , " windows- " + QSysInfo : : kernelVersion ( ) + " - " + QSysInfo : : currentCpuArchitecture ( ) ) ;
2022-08-09 17:19:46 +01:00
Query . addQueryItem ( " language " , QString : : number ( theGUI - > m_LanguageId ) ) ;
2022-06-08 16:23:19 +01:00
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 ( ) )
Query . addQueryItem ( " update_key " , UpdateKey ) ;
2022-11-20 16:23:15 +00:00
2022-08-11 23:09:35 +01:00
if ( Params . contains ( " channel " ) )
Query . addQueryItem ( " channel " , Params [ " channel " ] . toString ( ) ) ;
else {
2022-11-20 16:23:15 +00:00
QString ReleaseChannel = theConf - > GetString ( " Options/ReleaseChannel " , " stable " ) ;
Query . addQueryItem ( " channel " , ReleaseChannel ) ;
2022-08-11 23:09:35 +01:00
}
2022-11-20 16:23:15 +00:00
2022-08-11 23:09:35 +01:00
if ( Params . contains ( " manual " ) ) Query . addQueryItem ( " auto " , Params [ " manual " ] . toBool ( ) ? " 0 " : " 1 " ) ;
//QString Test = Query.toString();
2022-06-08 16:23:19 +01:00
QUrl Url ( " https://sandboxie-plus.com/update.php " ) ;
Url . setQuery ( Query ) ;
QNetworkRequest Request = QNetworkRequest ( Url ) ;
2022-08-09 17:19:46 +01:00
//Request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
Request . setAttribute ( QNetworkRequest : : RedirectPolicyAttribute , QNetworkRequest : : NoLessSafeRedirectPolicy ) ;
2022-06-08 16:23:19 +01:00
//Request.setRawHeader("Accept-Encoding", "gzip");
QNetworkReply * pReply = m_RequestManager - > get ( Request ) ;
connect ( pReply , SIGNAL ( finished ( ) ) , this , SLOT ( OnUpdateCheck ( ) ) ) ;
2022-08-11 23:09:35 +01:00
m_JobQueue . insert ( pReply , pJob ) ;
2022-06-08 16:23:19 +01:00
}
2022-11-20 16:23:15 +00:00
void COnlineUpdater : : CheckForUpdates ( bool bManual )
2022-06-08 16:23:19 +01:00
{
2022-08-11 23:09:35 +01:00
if ( ! m_pUpdateProgress . isNull ( ) )
2022-06-08 16:23:19 +01:00
return ;
2022-11-20 16:23:15 +00:00
# ifdef _DEBUG
if ( QApplication : : keyboardModifiers ( ) & Qt : : ControlModifier )
bManual = false ;
# endif
2022-08-11 23:09:35 +01:00
m_pUpdateProgress = CSbieProgressPtr ( new CSbieProgress ( ) ) ;
theGUI - > AddAsyncOp ( m_pUpdateProgress ) ;
m_pUpdateProgress - > ShowMessage ( tr ( " Checking for updates... " ) ) ;
2022-11-20 16:23:15 +00:00
// clean up old check result
m_UpdateData . clear ( ) ;
m_CheckMode = bManual ? eManual : eAuto ;
GetUpdates ( this , SLOT ( OnUpdateData ( const QVariantMap & , const QVariantMap & ) ) ) ;
2022-08-11 23:09:35 +01:00
}
void COnlineUpdater : : OnUpdateCheck ( )
{
2022-06-08 16:23:19 +01:00
QNetworkReply * pReply = qobject_cast < QNetworkReply * > ( sender ( ) ) ;
QByteArray Reply = pReply - > readAll ( ) ;
pReply - > deleteLater ( ) ;
2022-08-11 23:09:35 +01:00
CGetUpdatesJob * pJob = m_JobQueue . take ( pReply ) ;
if ( ! pJob )
return ;
2022-06-08 16:23:19 +01:00
QVariantMap Data = QJsonDocument : : fromJson ( Reply ) . toVariant ( ) . toMap ( ) ;
2022-08-11 23:09:35 +01:00
emit pJob - > UpdateData ( Data , pJob - > m_Params ) ;
pJob - > deleteLater ( ) ;
}
2022-11-20 16:23:15 +00:00
void COnlineUpdater : : OnDownloadProgress ( qint64 bytes , qint64 bytesTotal )
2022-08-11 23:09:35 +01:00
{
2022-11-20 16:23:15 +00:00
if ( bytesTotal ! = 0 & & ! m_pUpdateProgress . isNull ( ) )
m_pUpdateProgress - > Progress ( 100 * bytes / bytesTotal ) ;
}
2022-08-11 23:09:35 +01:00
2022-11-20 16:23:15 +00:00
void COnlineUpdater : : OnUpdateData ( const QVariantMap & Data , const QVariantMap & Params )
{
2022-08-11 23:09:35 +01:00
if ( ! m_pUpdateProgress . isNull ( ) ) {
m_pUpdateProgress - > Finish ( SB_OK ) ;
m_pUpdateProgress . clear ( ) ;
}
2022-11-20 16:23:15 +00:00
if ( Data . isEmpty ( ) | | Data [ " error " ] . toBool ( ) ) {
2022-06-08 16:23:19 +01:00
QString Error = Data . isEmpty ( ) ? tr ( " server not reachable " ) : Data [ " errorMsg " ] . toString ( ) ;
2022-11-20 16:23:15 +00:00
theGUI - > OnLogMessage ( tr ( " Failed to check for updates, error: %1 " ) . arg ( Error ) , m_CheckMode ! = eManual ) ;
if ( m_CheckMode = = eManual )
2022-08-09 17:19:46 +01:00
QMessageBox : : critical ( theGUI , " Sandboxie-Plus " , tr ( " Failed to check for updates, error: %1 " ) . arg ( Error ) ) ;
2022-06-08 16:23:19 +01:00
return ;
}
bool bNothing = true ;
2022-11-20 16:23:15 +00:00
if ( HandleUserMessage ( Data ) )
bNothing = false ;
2022-06-08 16:23:19 +01:00
2022-11-20 16:23:15 +00:00
m_UpdateData = Data ;
bool PendingUpdate = HandleUpdate ( ) ;
theGUI - > UpdateLabel ( ) ;
2022-06-08 16:23:19 +01:00
2022-11-20 16:23:15 +00:00
if ( PendingUpdate ) {
bNothing = false ;
}
2022-06-08 16:23:19 +01:00
2022-11-20 16:23:15 +00:00
if ( bNothing ) {
2022-06-08 16:23:19 +01:00
2022-11-20 16:23:15 +00:00
//theConf->SetValue("Options/NextCheckForUpdates", QDateTime::currentDateTime().addDays(7).toSecsSinceEpoch());
2022-06-08 16:23:19 +01:00
2022-11-20 16:23:15 +00:00
if ( m_CheckMode = = eManual ) {
QMessageBox : : information ( theGUI , " Sandboxie-Plus " , tr ( " No new updates found, your Sandboxie-Plus is up-to-date. \n "
" \n Note: The update check is often behind the latest GitHub release to ensure that only tested updates are offered. " ) ) ;
}
}
}
bool COnlineUpdater : : HandleUpdate ( )
{
2022-12-16 14:26:23 +00:00
QString PendingUpdate ;
2022-11-20 16:23:15 +00:00
bool bNewRelease = false ;
QVariantMap Release = m_UpdateData [ " release " ] . toMap ( ) ;
QString ReleaseStr = Release [ " version " ] . toString ( ) ;
if ( IsVersionNewer ( ReleaseStr ) ) {
if ( m_CheckMode = = eManual | | ! m_IgnoredUpdates . contains ( ReleaseStr ) ) {
2022-12-16 14:26:23 +00:00
PendingUpdate = ReleaseStr ;
2022-11-20 16:23:15 +00:00
bNewRelease = true ;
}
}
2022-12-20 08:18:21 +00:00
QString OnNewUpdate = theConf - > GetString ( " Options/OnNewUpdate " , " ignore " ) ;
2022-11-20 16:23:15 +00:00
bool bNewUpdate = false ;
QVariantMap Update = m_UpdateData [ " update " ] . toMap ( ) ;
QString UpdateStr = Update [ " version " ] . toString ( ) ;
bool bNewer ;
if ( ( bNewer = IsVersionNewer ( UpdateStr ) ) | | UpdateStr = = GetCurrentVersion ( ) ) {
int iUpdate = Update [ " update " ] . toInt ( ) ;
2022-11-20 17:16:13 +00:00
if ( iUpdate ) UpdateStr + = QChar ( ' a ' + ( iUpdate - 1 ) ) ;
2022-11-20 16:23:15 +00:00
if ( bNewer | | iUpdate > GetCurrentUpdate ( ) ) {
if ( ScanUpdateFiles ( Update ) = = eNone ) // check if this update has already been applied
theConf - > SetValue ( " Updater/CurrentUpdate " , MakeVersionStr ( Update ) ) ; // cache result
2022-12-20 08:18:21 +00:00
else if ( OnNewUpdate ! = " ignore " )
2022-06-08 16:23:19 +01:00
{
2022-12-16 14:26:23 +00:00
if ( PendingUpdate . isEmpty ( ) )
PendingUpdate = UpdateStr ;
2022-11-20 16:23:15 +00:00
if ( m_CheckMode = = eManual | | ! m_IgnoredUpdates . contains ( UpdateStr ) ) {
bNewUpdate = true ;
}
2022-06-08 16:23:19 +01:00
}
}
}
2022-12-16 14:26:23 +00:00
theConf - > SetValue ( " Updater/PendingUpdate " , PendingUpdate ) ;
2022-11-20 16:23:15 +00:00
//
2022-12-17 20:06:15 +00:00
// special case: updates allowed be to installed, but releases only allowed to be downloaded
2022-11-20 16:23:15 +00:00
// solution: apply updates silently, then prompt to install new release, else prioritize installing new releases over updating the existing one
//
2022-08-09 17:19:46 +01:00
2022-11-20 16:23:15 +00:00
QString OnNewRelease = theConf - > GetString ( " Options/OnNewRelease " , " download " ) ;
bool bCanRunInstaller = ( m_CheckMode = = eAuto & & OnNewRelease = = " install " ) ;
bool bIsInstallerReady = false ;
if ( bNewRelease )
2022-06-08 16:23:19 +01:00
{
2022-11-20 16:23:15 +00:00
if ( theConf - > GetString ( " Updater/InstallerVersion " ) = = MakeVersionStr ( Release ) )
2022-06-08 16:23:19 +01:00
{
2022-11-20 16:23:15 +00:00
QString FilePath = theConf - > GetString ( " Updater/InstallerPath " ) ;
bIsInstallerReady = ( ! FilePath . isEmpty ( ) & & QFile : : exists ( FilePath ) ) ;
}
2022-06-08 16:23:19 +01:00
2022-11-20 16:23:15 +00:00
if ( ! bIsInstallerReady )
{
// clear when not up to date
theConf - > DelValue ( " Updater/InstallerVersion " ) ;
2022-06-08 16:23:19 +01:00
2022-11-20 16:23:15 +00:00
if ( ( bCanRunInstaller | | ( m_CheckMode = = eAuto & & OnNewRelease = = " download " ) ) | | AskDownload ( Release ) )
2022-08-22 20:06:43 +01:00
{
2022-11-20 16:23:15 +00:00
if ( DownloadInstaller ( Release , m_CheckMode = = eManual ) )
return true ;
2022-08-22 20:06:43 +01:00
}
2022-11-20 16:23:15 +00:00
}
}
2022-06-08 16:23:19 +01:00
2022-11-20 16:23:15 +00:00
bool bCanApplyUpdate = ( m_CheckMode = = eAuto & & OnNewUpdate = = " install " ) ;
2022-12-03 19:25:04 +00:00
if ( bNewUpdate )
2022-11-20 16:23:15 +00:00
{
2022-12-20 08:18:21 +00:00
if ( ( ! bNewRelease | | ( bCanApplyUpdate & & ! bCanRunInstaller ) ) )
2022-11-20 16:23:15 +00:00
{
2022-12-03 19:25:04 +00:00
bool bIsUpdateReady = false ;
if ( theConf - > GetString ( " Updater/UpdateVersion " ) = = MakeVersionStr ( Update ) )
2023-02-02 08:03:01 +00:00
bIsUpdateReady = QFile : : exists ( GetUpdateDir ( ) + " / " UPDATE_FILE ) ;
2022-06-08 16:23:19 +01:00
2022-12-03 19:25:04 +00:00
if ( ! bIsUpdateReady )
2022-11-20 16:23:15 +00:00
{
2022-12-03 19:25:04 +00:00
// clear when not up to date
theConf - > DelValue ( " Updater/UpdateVersion " ) ;
if ( ( bCanApplyUpdate | | ( m_CheckMode = = eAuto & & OnNewUpdate = = " download " ) ) | | AskDownload ( Update ) )
{
if ( DownloadUpdate ( Update , m_CheckMode = = eManual ) )
return true ;
}
}
else if ( m_CheckMode = = eManual ) {
if ( ApplyUpdate ( false ) )
2022-11-20 16:23:15 +00:00
return true ;
2022-06-08 16:23:19 +01:00
}
2022-12-03 19:25:04 +00:00
else if ( bCanApplyUpdate )
m_CheckMode = ePendingUpdate ;
2022-06-08 16:23:19 +01:00
}
2022-11-20 16:23:15 +00:00
}
if ( bIsInstallerReady )
{
if ( m_CheckMode = = eManual ) {
if ( RunInstaller ( false ) )
return true ;
}
else if ( bCanRunInstaller )
m_CheckMode = ePendingInstall ;
}
return bNewRelease | | bNewUpdate ;
}
bool COnlineUpdater : : AskDownload ( const QVariantMap & Data )
{
QString VersionStr = MakeVersionStr ( Data ) ;
QString UpdateMsg = Data [ " infoMsg " ] . toString ( ) ;
QString UpdateUrl = Data [ " infoUrl " ] . toString ( ) ;
QString FullMessage = ! UpdateMsg . isEmpty ( ) ? UpdateMsg :
tr ( " <p>There is a new version of Sandboxie-Plus available.<br /><font color='red'><b>New version:</b></font> <b>%1</b></p> " ) . arg ( VersionStr ) ;
QVariantMap Installer = Data [ " installer " ] . toMap ( ) ;
QString DownloadUrl = Installer [ " downloadUrl " ] . toString ( ) ;
if ( ! DownloadUrl . isEmpty ( ) )
FullMessage + = tr ( " <p>Do you want to download the installer?</p> " ) ;
else if ( Data . contains ( " files " ) )
FullMessage + = tr ( " <p>Do you want to download the updates?</p> " ) ;
else if ( ! UpdateUrl . isEmpty ( ) )
FullMessage + = tr ( " <p>Do you want to go to the <a href= \" %1 \" >update page</a>?</p> " ) . arg ( UpdateUrl ) ;
CCheckableMessageBox mb ( theGUI ) ;
mb . setWindowTitle ( " Sandboxie-Plus " ) ;
QIcon ico ( QLatin1String ( " :/SandMan.png " ) ) ;
mb . setIconPixmap ( ico . pixmap ( 64 , 64 ) ) ;
//mb.setTextFormat(Qt::RichText);
mb . setText ( FullMessage ) ;
mb . setCheckBoxText ( tr ( " Don't show this update anymore. " ) ) ;
mb . setCheckBoxVisible ( m_CheckMode ! = eManual ) ;
if ( ! UpdateUrl . isEmpty ( ) | | ! DownloadUrl . isEmpty ( ) | | Data . contains ( " files " ) ) {
mb . setStandardButtons ( QDialogButtonBox : : Yes | QDialogButtonBox : : No ) ;
mb . setDefaultButton ( QDialogButtonBox : : Yes ) ;
2022-06-08 16:23:19 +01:00
}
2022-11-20 16:23:15 +00:00
else
mb . setStandardButtons ( QDialogButtonBox : : Ok ) ;
2022-06-08 16:23:19 +01:00
2022-11-20 16:23:15 +00:00
mb . exec ( ) ;
if ( mb . clickedStandardButton ( ) = = QDialogButtonBox : : Yes )
2022-06-08 16:23:19 +01:00
{
2022-11-20 16:23:15 +00:00
if ( ! DownloadUrl . isEmpty ( ) | | Data . contains ( " files " ) ) {
m_CheckMode = eManual ;
return true ;
}
else
QDesktopServices : : openUrl ( UpdateUrl ) ;
}
else if ( mb . isChecked ( ) )
theConf - > SetValue ( " Options/IgnoredUpdates " , m_IgnoredUpdates < < VersionStr ) ;
return false ;
}
COnlineUpdater : : EUpdateScope COnlineUpdater : : GetFileScope ( const QString & Path )
{
static const WCHAR CoreFiles [ ] = SCOPE_CORE_FILES ;
static const WCHAR LangFiles [ ] = SCOPE_LANG_FILES ;
static const WCHAR TmplFiles [ ] = SCOPE_TMPL_FILES ;
auto WildMatch = [ Path ] ( const WCHAR * pFiles ) {
for ( const WCHAR * pFile = pFiles ; * pFile ; pFile + = wcslen ( pFile ) + 1 ) {
QString WC = QRegularExpression : : wildcardToRegularExpression ( QString : : fromWCharArray ( pFile ) ) ;
QRegularExpression RegExp ( WC , QRegularExpression : : CaseInsensitiveOption ) ;
if ( RegExp . match ( Path ) . hasMatch ( ) )
return true ;
}
return false ;
} ;
if ( WildMatch ( CoreFiles ) )
return eCore ;
if ( WildMatch ( TmplFiles ) | | WildMatch ( LangFiles ) )
return eMeta ;
2022-11-21 18:22:33 +00:00
// unknown files are handled the same as known Plus files
2022-11-20 16:23:15 +00:00
return eFull ;
}
COnlineUpdater : : EUpdateScope COnlineUpdater : : ScanUpdateFiles ( const QVariantMap & Update )
{
QString AppDir = QApplication : : applicationDirPath ( ) ;
# ifdef DUMMY_PATH
AppDir = DUMMY_PATH ;
# endif
EUpdateScope Scope = eNone ;
foreach ( const QVariant vFile , Update [ " files " ] . toList ( ) ) {
QVariantMap File = vFile . toMap ( ) ;
QCryptographicHash qHash ( QCryptographicHash : : Sha256 ) ;
QFile qFile ( AppDir + " \\ " + File [ " path " ] . toString ( ) ) ;
if ( qFile . open ( QFile : : ReadOnly ) ) {
qHash . addData ( & qFile ) ;
qFile . close ( ) ;
}
if ( qHash . result ( ) = = QByteArray : : fromHex ( File [ " hash " ] . toByteArray ( ) ) )
continue ; // file did not change
EUpdateScope CurScope = GetFileScope ( File [ " path " ] . toString ( ) ) ;
if ( Scope < CurScope )
Scope = CurScope ;
}
return Scope ;
}
bool COnlineUpdater : : DownloadUpdate ( const QVariantMap & Update , bool bAndApply )
{
QJsonDocument doc ( QJsonValue : : fromVariant ( Update ) . toObject ( ) ) ;
WriteStringToFile ( GetUpdateDir ( true ) + " / " UPDATE_FILE , doc . toJson ( ) ) ;
theConf - > DelValue ( " Updater/UpdateVersion " ) ;
QStringList Params ;
Params . append ( " update " ) ;
Params . append ( " sandboxie-plus " ) ;
Params . append ( " /step:prepare " ) ;
Params . append ( " /embedded " ) ;
Params . append ( " /temp: " + GetUpdateDir ( ) . replace ( " / " , " \\ " ) ) ;
# ifdef DUMMY_PATH
Params . append ( " /path: " DUMMY_PATH ) ;
# endif
m_pUpdaterUtil = new QProcess ( this ) ;
m_pUpdaterUtil - > setProperty ( " apply " , bAndApply ) ;
m_pUpdaterUtil - > setProperty ( " version " , MakeVersionStr ( Update ) ) ;
m_pUpdaterUtil - > setProgram ( QApplication : : applicationDirPath ( ) + " /UpdUtil.exe " ) ;
m_pUpdaterUtil - > setArguments ( Params ) ;
connect ( m_pUpdaterUtil , SIGNAL ( finished ( int , QProcess : : ExitStatus ) ) , this , SLOT ( OnPrepareFinished ( int , QProcess : : ExitStatus ) ) ) ;
connect ( m_pUpdaterUtil , SIGNAL ( readyReadStandardOutput ( ) ) , this , SLOT ( OnPrepareOutput ( ) ) ) ;
connect ( m_pUpdaterUtil , SIGNAL ( readyReadStandardError ( ) ) , this , SLOT ( OnPrepareError ( ) ) ) ;
m_pUpdaterUtil - > start ( ) ;
if ( m_pUpdaterUtil - > state ( ) ! = QProcess : : Running )
return false ;
m_pUpdateProgress = CSbieProgressPtr ( new CSbieProgress ( ) ) ;
theGUI - > AddAsyncOp ( m_pUpdateProgress ) ;
m_pUpdateProgress - > ShowMessage ( tr ( " Downloading updates... " ) ) ;
return true ;
}
void COnlineUpdater : : OnPrepareOutput ( )
{
QProcess * pProcess = ( QProcess * ) sender ( ) ;
QByteArray Text = pProcess - > readAllStandardOutput ( ) ;
qDebug ( ) < < " UPD-OUT: \t " < < Text ;
if ( ! m_pUpdateProgress . isNull ( ) )
m_pUpdateProgress - > ShowMessage ( Text . trimmed ( ) ) ;
}
void COnlineUpdater : : OnPrepareError ( )
{
QProcess * pProcess = ( QProcess * ) sender ( ) ;
QByteArray Text = pProcess - > readAllStandardOutput ( ) ;
qDebug ( ) < < " UPD-ERR: \t " < < Text ;
}
QString GetUpdErrorStr ( int exitCode )
{
switch ( exitCode )
{
case ERROR_INVALID : return COnlineUpdater : : tr ( " invalid parameter " ) ;
2022-11-21 18:22:33 +00:00
case ERROR_GET : return COnlineUpdater : : tr ( " failed to download updated information " ) ;
case ERROR_LOAD : return COnlineUpdater : : tr ( " failed to load updated json file " ) ;
2022-11-20 16:23:15 +00:00
case ERROR_DOWNLOAD : return COnlineUpdater : : tr ( " failed to download a particular file " ) ;
case ERROR_SCAN : return COnlineUpdater : : tr ( " failed to scan existing installation " ) ;
2022-11-21 18:22:33 +00:00
case ERROR_SIGN : return COnlineUpdater : : tr ( " updated signature is invalid !!! " ) ;
2022-11-20 16:23:15 +00:00
case ERROR_HASH : return COnlineUpdater : : tr ( " downloaded file is corrupted " ) ;
case ERROR_INTERNAL : return COnlineUpdater : : tr ( " internal error " ) ;
default : return COnlineUpdater : : tr ( " unknown error " ) ;
}
}
void COnlineUpdater : : OnPrepareFinished ( int exitCode , QProcess : : ExitStatus exitStatus )
{
QProcess * pProcess = ( QProcess * ) sender ( ) ;
if ( pProcess ! = m_pUpdaterUtil ) {
pProcess - > deleteLater ( ) ;
return ;
}
bool bAndApply = pProcess - > property ( " apply " ) . toBool ( ) ;
QString VersionStr = pProcess - > property ( " version " ) . toString ( ) ;
m_pUpdaterUtil - > deleteLater ( ) ;
m_pUpdaterUtil = NULL ;
if ( m_pUpdateProgress . isNull ( ) )
return ; // canceled
m_pUpdateProgress - > Finish ( SB_OK ) ;
m_pUpdateProgress . clear ( ) ;
if ( exitCode < 0 ) {
QMessageBox : : critical ( theGUI , " Sandboxie-Plus " , tr ( " Failed to download updates from server, error %1 " ) . arg ( GetUpdErrorStr ( exitCode ) ) ) ;
return ; // failed
}
theConf - > SetValue ( " Updater/UpdateVersion " , VersionStr ) ;
if ( bAndApply )
ApplyUpdate ( false ) ;
else
{
HandleUpdate ( ) ;
2022-08-22 20:06:43 +01:00
theGUI - > UpdateLabel ( ) ;
2022-11-20 16:23:15 +00:00
}
}
2022-06-08 16:23:19 +01:00
2022-11-20 16:23:15 +00:00
bool COnlineUpdater : : ApplyUpdate ( bool bSilent )
{
if ( ! bSilent )
{
QString Message = tr ( " <p>Updates for Sandboxie-Plus have been downloaded.</p><p>Do you want to apply these updates? If any programs are running sandboxed, they will be terminated.</p> " ) ;
int Ret = QMessageBox ( " Sandboxie-Plus " , Message , QMessageBox : : Information , QMessageBox : : Yes | QMessageBox : : Default , QMessageBox : : No | QMessageBox : : Escape , QMessageBox : : Cancel , theGUI ) . exec ( ) ;
if ( Ret = = QMessageBox : : Cancel ) {
theConf - > DelValue ( " Updater/UpdateVersion " ) ;
theGUI - > UpdateLabel ( ) ;
2022-06-08 16:23:19 +01:00
}
2022-11-20 16:23:15 +00:00
if ( Ret ! = QMessageBox : : Yes )
return false ;
}
2023-02-02 08:03:01 +00:00
QVariantMap Update = QJsonDocument : : fromJson ( ReadFileAsString ( GetUpdateDir ( ) + " / " UPDATE_FILE ) . toUtf8 ( ) ) . toVariant ( ) . toMap ( ) ;
2022-11-20 16:23:15 +00:00
EUpdateScope Scope = ScanUpdateFiles ( Update ) ;
if ( Scope = = eNone )
2022-12-07 10:58:37 +00:00
return true ; // nothing to do
2022-11-20 16:23:15 +00:00
if ( Scope ! = eMeta )
theAPI - > TerminateAll ( ) ;
QStringList Params ;
Params . append ( " update " ) ;
Params . append ( " sandboxie-plus " ) ;
Params . append ( " /step:apply " ) ;
if ( Scope = = eMeta )
Params . append ( " /scope:meta " ) ;
else
Params . append ( " /restart " ) ;
# ifndef _DEBUG
Params . append ( " /embedded " ) ;
# else
Params . append ( " /pause " ) ;
# endif
Params . append ( " /temp: " + GetUpdateDir ( ) . replace ( " / " , " \\ " ) ) ;
# ifdef DUMMY_PATH
Params . append ( " /path: " DUMMY_PATH ) ;
# endif
if ( Scope = = eFull )
Params . append ( " /open:sandman.exe " ) ;
if ( RunUpdater ( Params , bSilent , Scope ! = eFull ) ) {
if ( bSilent )
theConf - > DelValue ( " Updater/UpdateVersion " ) ;
if ( Scope = = eMeta )
theAPI - > ReloadConfig ( ) ;
else if ( Scope = = eFull )
QApplication : : quit ( ) ;
else
theGUI - > ConnectSbie ( ) ;
return true ;
}
return false ;
}
bool COnlineUpdater : : RunUpdater ( const QStringList & Params , bool bSilent , bool Wait )
{
if ( bSilent ) {
SB_RESULT ( int ) Result = theAPI - > RunUpdateUtility ( Params , 2 , Wait ) ;
if ( ! Result . IsError ( ) )
return true ;
// else fallback to ShellExecuteEx
if ( theConf - > GetBool ( " Options/UpdateNoFallback " , false ) )
return false ;
2022-06-08 16:23:19 +01:00
}
2022-11-20 16:23:15 +00:00
std : : wstring wFile = QString ( QApplication : : applicationDirPath ( ) + " /UpdUtil.exe " ) . replace ( " / " , " \\ " ) . toStdWString ( ) ;
std : : wstring wParams ;
foreach ( const QString & Param , Params ) {
if ( ! wParams . empty ( ) ) wParams . push_back ( L ' ' ) ;
wParams + = L " \" " + Param . toStdWString ( ) + L " \" " ;
}
return RunElevated ( wFile , wParams , Wait ? INFINITE : 0 ) = = 0 ;
2022-06-08 16:23:19 +01:00
}
2022-11-20 16:23:15 +00:00
bool COnlineUpdater : : DownloadInstaller ( const QVariantMap & Release , bool bAndRun )
2022-06-08 16:23:19 +01:00
{
2022-11-20 16:23:15 +00:00
if ( m_RequestManager = = NULL )
m_RequestManager = new CNetworkAccessManager ( 30 * 1000 , this ) ;
QVariantMap Installer = Release [ " installer " ] . toMap ( ) ;
QString DownloadUrl = Installer [ " downloadUrl " ] . toString ( ) ;
if ( DownloadUrl . isEmpty ( ) )
return false ;
// clean up old installer if present
QString FilePath = theConf - > GetString ( " Updater/InstallerPath " ) ;
if ( ! FilePath . isEmpty ( ) ) {
QFile : : remove ( FilePath ) ;
QFile : : remove ( FilePath + " .sig " ) ;
theConf - > DelValue ( " Updater/InstallerPath " ) ;
}
2022-06-08 16:23:19 +01:00
QNetworkRequest Request = QNetworkRequest ( DownloadUrl ) ;
2022-08-09 17:19:46 +01:00
//Request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
Request . setAttribute ( QNetworkRequest : : RedirectPolicyAttribute , QNetworkRequest : : NoLessSafeRedirectPolicy ) ;
2022-06-08 16:23:19 +01:00
//Request.setRawHeader("Accept-Encoding", "gzip");
QNetworkReply * pReply = m_RequestManager - > get ( Request ) ;
2022-11-20 16:23:15 +00:00
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 ) ) ) ;
2022-06-08 16:23:19 +01:00
m_pUpdateProgress = CSbieProgressPtr ( new CSbieProgress ( ) ) ;
2022-08-09 17:19:46 +01:00
theGUI - > AddAsyncOp ( m_pUpdateProgress ) ;
2022-11-20 16:23:15 +00:00
m_pUpdateProgress - > ShowMessage ( tr ( " Downloading installer... " ) ) ;
2022-06-08 16:23:19 +01:00
2022-11-20 16:23:15 +00:00
return true ;
2022-06-08 16:23:19 +01:00
}
2022-11-20 16:23:15 +00:00
void COnlineUpdater : : OnInstallerDownload ( )
2022-06-08 16:23:19 +01:00
{
if ( m_pUpdateProgress . isNull ( ) )
return ;
m_pUpdateProgress - > Progress ( - 1 ) ;
QNetworkReply * pReply = qobject_cast < QNetworkReply * > ( sender ( ) ) ;
2022-11-20 16:23:15 +00:00
bool bAndRun = pReply - > property ( " run " ) . toBool ( ) ;
QString VersionStr = pReply - > property ( " version " ) . toString ( ) ;
QByteArray Signature = pReply - > property ( " signature " ) . toByteArray ( ) ;
2022-06-08 16:23:19 +01:00
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 " ;
2023-02-02 08:03:01 +00:00
QString FilePath = GetUpdateDir ( true ) + " / " + Name ;
2022-06-08 16:23:19 +01:00
QFile File ( FilePath ) ;
if ( File . open ( QFile : : WriteOnly ) ) {
while ( pReply - > bytesAvailable ( ) > 0 )
File . write ( pReply - > read ( 4096 ) ) ;
File . close ( ) ;
}
2022-11-20 16:23:15 +00:00
QFile SigFile ( FilePath + " .sig " ) ;
if ( SigFile . open ( QFile : : WriteOnly ) ) {
SigFile . write ( QByteArray : : fromBase64 ( Signature ) ) ;
SigFile . close ( ) ;
}
2022-06-08 16:23:19 +01:00
pReply - > deleteLater ( ) ;
m_pUpdateProgress - > Finish ( SB_OK ) ;
m_pUpdateProgress . clear ( ) ;
if ( File . size ( ) ! = Size ) {
2022-11-20 16:23:15 +00:00
QMessageBox : : critical ( theGUI , " Sandboxie-Plus " , tr ( " Failed to download installer from: %1 " ) . arg ( pReply - > request ( ) . url ( ) . toString ( ) ) ) ;
2022-06-08 16:23:19 +01:00
return ;
}
2022-11-20 16:23:15 +00:00
theConf - > SetValue ( " Updater/InstallerVersion " , VersionStr ) ;
theConf - > SetValue ( " Updater/InstallerPath " , FilePath ) ;
2022-06-08 16:23:19 +01:00
2022-11-20 16:23:15 +00:00
if ( bAndRun )
RunInstaller ( false ) ;
else
{
HandleUpdate ( ) ;
theGUI - > UpdateLabel ( ) ;
}
2022-06-08 16:23:19 +01:00
}
2022-11-20 16:23:15 +00:00
bool COnlineUpdater : : RunInstaller ( bool bSilent )
2022-08-22 20:06:43 +01:00
{
2022-11-20 16:23:15 +00:00
QString FilePath = theConf - > GetString ( " Updater/InstallerPath " ) ;
if ( FilePath . isEmpty ( ) | | ! QFile : : exists ( FilePath ) ) {
theConf - > DelValue ( " Updater/InstallerPath " ) ;
theConf - > DelValue ( " Updater/InstallerVersion " ) ;
return false ;
}
if ( ! bSilent ) {
QString Message = tr ( " <p>A new Sandboxie-Plus installer has been downloaded to the following location:</p><p><a href= \" %2 \" >%1</a></p><p>Do you want to begin the installation? If any programs are running sandboxed, they will be terminated.</p> " )
. arg ( FilePath ) . arg ( " File:/// " + Split2 ( FilePath , " / " , true ) . first ) ;
int Ret = QMessageBox ( " Sandboxie-Plus " , Message , QMessageBox : : Information , QMessageBox : : Yes | QMessageBox : : Default , QMessageBox : : No | QMessageBox : : Escape , QMessageBox : : Cancel , theGUI ) . exec ( ) ;
if ( Ret = = QMessageBox : : Cancel ) {
QFile : : remove ( FilePath ) ;
QFile : : remove ( FilePath + " .sig " ) ;
theConf - > DelValue ( " Updater/InstallerPath " ) ;
theGUI - > UpdateLabel ( ) ;
}
if ( Ret ! = QMessageBox : : Yes )
return false ;
}
theAPI - > TerminateAll ( ) ;
if ( RunInstaller2 ( FilePath , bSilent ) ) {
if ( bSilent )
theConf - > DelValue ( " Updater/InstallerVersion " ) ;
QApplication : : quit ( ) ;
2022-08-22 20:06:43 +01:00
return true ;
2022-11-20 16:23:15 +00:00
}
return false ;
}
bool COnlineUpdater : : RunInstaller2 ( const QString & FilePath , bool bSilent )
{
if ( bSilent )
{
QStringList Params ;
Params . append ( " run_setup " ) ;
Params . append ( QString ( FilePath ) . replace ( " / " , " \\ " ) ) ;
# ifndef _DEBUG
Params . append ( " /embedded " ) ;
# else
Params . append ( " /pause " ) ;
2022-08-22 20:06:43 +01:00
# endif
2022-11-20 16:23:15 +00:00
SB_RESULT ( int ) Result = theAPI - > RunUpdateUtility ( Params , 1 ) ;
if ( ! Result . IsError ( ) )
return true ;
// else fallback to ShellExecuteEx
if ( theConf - > GetBool ( " Options/UpdateNoFallback " , false ) )
return false ;
}
2022-08-22 20:06:43 +01:00
2022-11-20 16:23:15 +00:00
std : : wstring wFile = QString ( FilePath ) . replace ( " / " , " \\ " ) . toStdWString ( ) ;
std : : wstring wParams ;
# ifndef _DEBUG
wParams = L " /SILENT " ;
# endif
2022-08-22 20:06:43 +01:00
2022-11-20 16:23:15 +00:00
return RunElevated ( wFile , wParams ) = = 0 ;
2022-08-22 20:06:43 +01:00
}
2022-11-20 16:23:15 +00:00
bool COnlineUpdater : : HandleUserMessage ( const QVariantMap & Data )
2022-08-22 20:06:43 +01:00
{
2022-11-20 16:23:15 +00:00
QString UserMsg = Data [ " userMsg " ] . toString ( ) ;
if ( ! UserMsg . isEmpty ( ) )
{
QString MsgHash = QCryptographicHash : : hash ( Data [ " userMsg " ] . toByteArray ( ) , QCryptographicHash : : Md5 ) . toHex ( ) . left ( 8 ) ;
if ( ! m_IgnoredUpdates . contains ( MsgHash ) )
{
QString FullMessage = UserMsg ;
QString InfoUrl = Data [ " infoUrl " ] . toString ( ) ;
if ( ! InfoUrl . isEmpty ( ) )
FullMessage + = tr ( " <p>Do you want to go to the <a href= \" %1 \" >info page</a>?</p> " ) . arg ( InfoUrl ) ;
CCheckableMessageBox mb ( theGUI ) ;
mb . setWindowTitle ( " Sandboxie-Plus " ) ;
QIcon ico ( QLatin1String ( " :/SandMan.png " ) ) ;
mb . setIconPixmap ( ico . pixmap ( 64 , 64 ) ) ;
//mb.setTextFormat(Qt::RichText);
mb . setText ( UserMsg ) ;
mb . setCheckBoxText ( tr ( " Don't show this announcement in the future. " ) ) ;
if ( ! InfoUrl . isEmpty ( ) ) {
mb . setStandardButtons ( QDialogButtonBox : : Yes | QDialogButtonBox : : No ) ;
mb . setDefaultButton ( QDialogButtonBox : : Yes ) ;
}
else
mb . setStandardButtons ( QDialogButtonBox : : Ok ) ;
mb . exec ( ) ;
if ( mb . isChecked ( ) )
theConf - > SetValue ( " Options/IgnoredUpdates " , m_IgnoredUpdates < < MsgHash ) ;
if ( mb . clickedStandardButton ( ) = = QDialogButtonBox : : Yes )
{
QDesktopServices : : openUrl ( InfoUrl ) ;
}
return true ;
}
}
return false ;
2022-08-22 20:06:43 +01:00
}
2022-11-20 16:23:15 +00:00
QString COnlineUpdater : : GetUpdateDir ( bool bCreate )
2022-08-22 20:06:43 +01:00
{
2022-11-20 16:23:15 +00:00
QString TempDir = QStandardPaths : : writableLocation ( QStandardPaths : : TempLocation ) ;
if ( TempDir . right ( 1 ) ! = " / " )
TempDir + = " / " ;
TempDir + = " sandboxie-updater " ;
// Note: must not end with a /
if ( bCreate )
QDir ( ) . mkpath ( TempDir ) ;
return TempDir ;
2022-08-22 20:06:43 +01:00
}
2022-11-20 16:23:15 +00:00
QString COnlineUpdater : : MakeVersionStr ( const QVariantMap & Data )
2022-06-08 16:23:19 +01:00
{
2022-11-20 16:23:15 +00:00
QString Str = Data [ " version " ] . toString ( ) ;
int iUpdate = Data [ " update " ] . toInt ( ) ;
2022-11-20 17:16:13 +00:00
if ( iUpdate ) Str + = QChar ( ' a ' + ( iUpdate - 1 ) ) ;
2022-11-20 16:23:15 +00:00
return Str ;
}
2022-06-08 16:23:19 +01:00
2022-11-20 16:23:15 +00:00
QString COnlineUpdater : : ParseVersionStr ( const QString & Str , int * pUpdate )
{
int pos = Str . indexOf ( QRegularExpression ( " [a-zA-Z] " ) ) ;
if ( pos = = - 1 )
return Str ;
QString Ver = Str . left ( pos ) ;
if ( pUpdate ) {
QString Tmp = Str . mid ( pos ) ;
* pUpdate = Tmp [ 0 ] . toLatin1 ( ) - ' a ' + 1 ;
2022-06-08 16:23:19 +01:00
}
2022-11-20 16:23:15 +00:00
return Ver ;
}
2022-06-08 16:23:19 +01:00
2022-11-20 16:23:15 +00:00
QString COnlineUpdater : : GetCurrentVersion ( )
{
return QString : : number ( VERSION_MJR ) + " . " + QString : : number ( VERSION_MIN ) + " . " + QString : : number ( VERSION_REV ) ;
2022-06-08 16:23:19 +01:00
}
2022-11-20 16:23:15 +00:00
int COnlineUpdater : : GetCurrentUpdate ( )
{
int iUpdate = 0 ;
QString Version = ParseVersionStr ( theConf - > GetString ( " Updater/CurrentUpdate " , 0 ) , & iUpdate ) ;
if ( Version ! = GetCurrentVersion ( ) | | iUpdate < VERSION_UPD )
iUpdate = VERSION_UPD ;
return iUpdate ;
}
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 ;
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 ) ;
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// cert stuf
2023-01-25 11:54:41 +00:00
void COnlineUpdater : : UpdateCert ( bool bWait )
2022-06-08 16:23:19 +01:00
{
QString UpdateKey ; // for now only patreons can update the cert automatically
2022-08-09 17:19:46 +01:00
TArguments args = GetArguments ( g_Certificate , L ' \n ' , L ' : ' ) ;
2023-01-25 11:54:41 +00:00
if ( args . value ( " TYPE " ) . contains ( " PATREON " ) )
2022-08-09 17:19:46 +01:00
UpdateKey = args . value ( " UPDATEKEY " ) ;
2022-06-08 16:23:19 +01:00
if ( UpdateKey . isEmpty ( ) ) {
2022-08-09 17:19:46 +01:00
theGUI - > OpenUrl ( " https://sandboxie-plus.com/go.php?to=sbie-get-cert " ) ;
2022-06-08 16:23:19 +01:00
return ;
}
if ( ! m_pUpdateProgress . isNull ( ) )
return ;
m_pUpdateProgress = CSbieProgressPtr ( new CSbieProgress ( ) ) ;
2022-08-09 17:19:46 +01:00
theGUI - > AddAsyncOp ( m_pUpdateProgress ) ;
2022-06-08 16:23:19 +01:00
m_pUpdateProgress - > ShowMessage ( tr ( " Checking for certificate... " ) ) ;
if ( m_RequestManager = = NULL )
m_RequestManager = new CNetworkAccessManager ( 30 * 1000 , this ) ;
QUrlQuery Query ;
Query . addQueryItem ( " UpdateKey " , UpdateKey ) ;
QUrl Url ( " https://sandboxie-plus.com/get_cert.php " ) ;
Url . setQuery ( Query ) ;
QNetworkRequest Request = QNetworkRequest ( Url ) ;
2022-08-09 17:19:46 +01:00
//Request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
Request . setAttribute ( QNetworkRequest : : RedirectPolicyAttribute , QNetworkRequest : : NoLessSafeRedirectPolicy ) ;
2022-06-08 16:23:19 +01:00
//Request.setRawHeader("Accept-Encoding", "gzip");
QNetworkReply * pReply = m_RequestManager - > get ( Request ) ;
connect ( pReply , SIGNAL ( finished ( ) ) , this , SLOT ( OnCertCheck ( ) ) ) ;
2023-01-25 11:54:41 +00:00
if ( bWait ) {
while ( ! pReply - > isFinished ( ) ) {
QCoreApplication : : processEvents ( ) ; // keep UI responsive
}
}
2022-06-08 16:23:19 +01:00
}
2022-08-09 17:19:46 +01:00
void COnlineUpdater : : OnCertCheck ( )
2022-06-08 16:23:19 +01:00
{
if ( m_pUpdateProgress . isNull ( ) )
return ;
QNetworkReply * pReply = qobject_cast < QNetworkReply * > ( sender ( ) ) ;
QByteArray Reply = pReply - > readAll ( ) ;
int Code = pReply - > attribute ( QNetworkRequest : : HttpStatusCodeAttribute ) . toInt ( ) ;
pReply - > deleteLater ( ) ;
m_pUpdateProgress - > Finish ( SB_OK ) ;
m_pUpdateProgress . clear ( ) ;
if ( Code > 299 | | Code < 200 ) {
2022-08-09 17:19:46 +01:00
QMessageBox : : critical ( theGUI , " Sandboxie-Plus " , tr ( " No certificate found on server! " ) ) ;
2022-06-08 16:23:19 +01:00
return ;
}
if ( Reply . replace ( " \r \n " , " \n " ) . compare ( g_Certificate . replace ( " \r \n " , " \n " ) , Qt : : CaseInsensitive ) = = 0 ) {
2022-08-09 17:19:46 +01:00
QMessageBox : : information ( theGUI , " Sandboxie-Plus " , tr ( " There is no updated certificate available. " ) ) ;
2022-06-08 16:23:19 +01:00
return ;
}
QString CertPath = theAPI - > GetSbiePath ( ) + " \\ Certificate.dat " ;
QString TempPath = QDir : : tempPath ( ) + " /Sbie+Certificate.dat " ;
QFile CertFile ( TempPath ) ;
if ( CertFile . open ( QFile : : WriteOnly ) ) {
CertFile . write ( Reply ) ;
CertFile . close ( ) ;
}
WindowsMoveFile ( TempPath . replace ( " / " , " \\ " ) , CertPath . replace ( " / " , " \\ " ) ) ;
if ( ! theAPI - > ReloadCert ( ) . IsError ( ) ) {
CSettingsWindow : : LoadCertificate ( ) ;
2022-08-09 17:19:46 +01:00
theGUI - > UpdateCertState ( ) ;
2022-06-08 16:23:19 +01:00
}
else { // this should not happen
g_Certificate . clear ( ) ;
g_CertInfo . State = 0 ;
}
2022-11-20 16:23:15 +00:00
}