2023-07-08 10:46:29 +01:00
# include "stdafx.h"
# include "ScriptManager.h"
# include "../MiscHelpers/Common/Common.h"
# include "../MiscHelpers/Common/OtherFunctions.h"
# include "../SandMan.h"
# include "../OnlineUpdater.h"
# include <QJsonDocument>
# include <QJsonObject>
# include "SysObject.h"
# include "../MiscHelpers/Common/OtherFunctions.h"
# include "../MiscHelpers/Archive/Archive.h"
# include "../MiscHelpers/Archive/ArchiveFS.h"
# include "../Wizards/BoxAssistant.h"
QList < StrPair > ReadCommentHeader ( const QString & Header )
{
QList < StrPair > 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 ;
}
CScriptManager : : CScriptManager ( QObject * parent )
: QObject ( parent )
{
}
QString CScriptManager : : GetScript ( const QString & Name )
{
C7zFileEngineHandler IssueFS ( " issue " ) ;
QString Root = GetIssueDir ( IssueFS ) ;
foreach ( const QString & Path , ListDir ( Root , QStringList ( ) < < " *.js " ) ) {
if ( Path . right ( Name . length ( ) + 3 ) = = Name + " .js " ) {
return ReadFileAsString ( Root + " / " + Path ) ;
}
}
return QString ( ) ;
}
void CScriptManager : : LoadIssues ( )
{
//
// 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 ) {
QVariantMap Data = theGUI - > m_pUpdater - > GetUpdateData ( ) ;
if ( ! Data . isEmpty ( ) & & Data . contains ( " issues " ) & & theGUI - > m_pUpdater - > GetLastUpdateTime ( ) > QDateTime : : currentDateTime ( ) . addDays ( - 1 ) )
OnUpdateData ( Data , QVariantMap ( ) ) ;
else
theGUI - > m_pUpdater - > GetUpdates ( this , SLOT ( OnUpdateData ( const QVariantMap & , const QVariantMap & ) ) ) ;
}
}
}
void CScriptManager : : 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 ( theGUI , " 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)) {
2024-04-13 17:11:50 +01:00
auto List = ListDir ( IssueDir , QStringList ( ) < < " *.js " ) ;
foreach ( const QString & FileName , List ) {
2023-07-08 10:46:29 +01:00
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 ;
if ( Issue [ " group " ] = = " system " | | Issue [ " group " ] = = " library " )
continue ;
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 < QVariantMap > & 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 ( theGUI , " 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 " ) ;
}
2023-11-27 18:14:16 +00:00
if ( ! Translation . isEmpty ( ) ) {
QJsonParseError error ;
m_Translation = QJsonDocument : : fromJson ( Translation . toUtf8 ( ) , & error ) . toVariant ( ) . toMap ( ) ;
if ( m_Translation . isEmpty ( ) )
qDebug ( ) < < error . errorString ( ) < < Translation . mid ( error . offset , 100 ) ;
}
2023-07-08 10:46:29 +01:00
}
QString CScriptManager : : 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 CScriptManager : : 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 CScriptManager : : 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 ) ) {
2023-07-08 13:29:56 +01:00
QMessageBox : : critical ( theGUI , " Sandboxie-Plus " , tr ( " Downloaded troubleshooting instructions are corrupted! " ) ) ;
2023-07-08 10:46:29 +01:00
QFile : : remove ( Path ) ;
return ;
}
LoadIssues ( IssueFS . Prefix ( ) + " / " ) ;
emit IssuesUpdated ( ) ;
2024-04-13 17:11:50 +01:00
}