#include "stdafx.h" #include "TemplateWizard.h" #include "../MiscHelpers/Common/Common.h" #include "../Windows/SettingsWindow.h" #include "../SandMan.h" #include "Helpers/WinAdmin.h" #include #include "../QSbieAPI/SbieUtils.h" #include "../Views/SbieView.h" #include "../MiscHelpers/Common/CheckableMessageBox.h" CTemplateWizard::CTemplateWizard(ETemplateType Type, QWidget *parent) : QWizard(parent) { setPage(Page_TemplateType, new CTemplateTypePage); setPage(Page_BrowserType, new CBrowserTypePage); setPage(Page_BrowserPaths, new CBrowserPathsPage); setPage(Page_BrowserOptions, new CBrowserOptionsPage); setPage(Page_FinishTemplate, new CFinishTemplatePage); m_Type = Type; m_Hold = false; switch (Type) { case TmplWebBrowser: setStartId(Page_BrowserType); break; } setWizardStyle(ModernStyle); //setOption(HaveHelpButton, true); setPixmap(QWizard::LogoPixmap, QPixmap(":/SandMan.png").scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation)); connect(this, &QWizard::helpRequested, this, &CTemplateWizard::showHelp); setWindowTitle(tr("Compatibility Template Wizard")); } void CTemplateWizard::showHelp() { } QString CTemplateWizard::GetTemplateLabel(ETemplateType Type) { switch (Type) { case TmplCustom: return tr("Custom"); case TmplWebBrowser: return tr("Web Browser"); default: return QString(); } } bool CTemplateWizard::CreateNewTemplate(CSandBox* pBox, ETemplateType Type, QWidget* pParent) { CTemplateWizard wizard(Type, pParent); if (!theGUI->SafeExec(&wizard)) return false; if (Type == TmplCustom) Type = (ETemplateType)wizard.field("tmplType").toInt(); QString Name = wizard.field("templateName").toString(); QString Section = QString(Name).replace(" ", "_"); switch (Type) { case TmplCustom: // todo: break; case TmplWebBrowser: { CBrowserTypePage* pPage = (CBrowserTypePage*)wizard.page(CTemplateWizard::Page_BrowserType); QString BrowserPath = wizard.field("browserPath").toString(); QString BrowserBinary = Split2(BrowserPath, "\\", true).second; QString ProfilePath = wizard.field("profilePath").toString(); if (wizard.field("noProfile").toBool()) ProfilePath.clear(); { QSharedPointer pTemplate = QSharedPointer(new CSbieIni("Template_Local_" + Section + "_Force", theAPI)); pTemplate->SetText("Tmpl.Title", tr("Force %1 to run in this sandbox").arg(Name)); pTemplate->SetText("Tmpl.Class", "Local"); pTemplate->AppendText("ForceProcess", BrowserBinary); if (wizard.field("forceBrowser").toBool() && pBox) pBox->AppendText("Template", pTemplate->GetName().mid(9)); } if (!ProfilePath.isEmpty()) { QString AppData_Roaming = QProcessEnvironment::systemEnvironment().value("AppData"); QString AppData_Local = QProcessEnvironment::systemEnvironment().value("LocalAppData"); ProfilePath.replace(AppData_Roaming, "%AppData%"); ProfilePath.replace(AppData_Local, "%Local AppData%"); { QSharedPointer pTemplate = QSharedPointer(new CSbieIni("Template_Local_" + Section + "_Profile_DirectAccess", theAPI)); pTemplate->SetText("Tmpl.Title", tr("Allow direct access to the entire %1 profile folder").arg(Name)); pTemplate->SetText("Tmpl.Class", "Local"); pTemplate->AppendText("OpenFilePath", BrowserBinary + "," + ProfilePath); if (wizard.field("fullProfile").toBool() && pBox) pBox->AppendText("Template", pTemplate->GetName().mid(9)); } switch (pPage->m_BrowserType) { case CBrowserTypePage::Browser_Gecko: { QSharedPointer pTemplate = QSharedPointer(new CSbieIni("Template_Local_" + Section + "_Phishing_DirectAccess", theAPI)); pTemplate->SetText("Tmpl.Title", tr("Allow direct access to %1 phishing database").arg(Name)); pTemplate->SetText("Tmpl.Class", "Local"); pTemplate->AppendText("OpenFilePath", BrowserBinary + "," + ProfilePath + "*\\cert9.db"); QString ProfilePath2 = ProfilePath; ProfilePath2.replace("%AppData%", "%Local AppData%"); pTemplate->AppendText("OpenFilePath", BrowserBinary + "," + ProfilePath2 + "*\\safebrowsing*"); if (wizard.field("phishingDb").toBool() && pBox) pBox->AppendText("Template", pTemplate->GetName().mid(9)); } { QSharedPointer pTemplate = QSharedPointer(new CSbieIni("Template_Local_" + Section + "_Session_DirectAccess", theAPI)); pTemplate->SetText("Tmpl.Title", tr("Allow direct access to %1 session management").arg(Name)); pTemplate->SetText("Tmpl.Class", "Local"); pTemplate->AppendText("OpenFilePath", BrowserBinary + "," + ProfilePath + "*\\sessionstore.js*"); if (wizard.field("sessions").toBool() && pBox) pBox->AppendText("Template", pTemplate->GetName().mid(9)); } { QSharedPointer pTemplate = QSharedPointer(new CSbieIni("Template_Local_" + Section + "_Passwords_DirectAccess", theAPI)); pTemplate->SetText("Tmpl.Title", tr("Allow direct access to %1 passwords").arg(Name)); pTemplate->SetText("Tmpl.Class", "Local"); pTemplate->AppendText("OpenFilePath", BrowserBinary + "," + ProfilePath + "*\\logins.json"); pTemplate->AppendText("OpenFilePath", BrowserBinary + "," + ProfilePath + "*\\key*.db"); if (wizard.field("passwords").toBool() && pBox) pBox->AppendText("Template", pTemplate->GetName().mid(9)); } { QSharedPointer pTemplate = QSharedPointer(new CSbieIni("Template_Local_" + Section + "_Cookies_DirectAccess", theAPI)); pTemplate->SetText("Tmpl.Title", tr("Allow direct access to %1 cookies").arg(Name)); pTemplate->SetText("Tmpl.Class", "Local"); pTemplate->AppendText("OpenFilePath", BrowserBinary + "," + ProfilePath + "*\\cookies*"); if (wizard.field("cookies").toBool() && pBox) pBox->AppendText("Template", pTemplate->GetName().mid(9)); } { QSharedPointer pTemplate = QSharedPointer(new CSbieIni("Template_Local_" + Section + "_Bookmarks_DirectAccess", theAPI)); pTemplate->SetText("Tmpl.Title", tr("Allow direct access to %1 bookmark and history database").arg(Name)); pTemplate->SetText("Tmpl.Class", "Local"); pTemplate->AppendText("OpenFilePath", BrowserBinary + "," + ProfilePath + "*\\bookmark*"); pTemplate->AppendText("OpenFilePath", BrowserBinary + "," + ProfilePath + "*\\places*"); pTemplate->AppendText("OpenFilePath", BrowserBinary + "," + ProfilePath + "*\\favicons.sqlite"); if (wizard.field("history").toBool() && pBox) pBox->AppendText("Template", pTemplate->GetName().mid(9)); } break; case CBrowserTypePage::Browser_Chromium: { QSharedPointer pTemplate = QSharedPointer(new CSbieIni("Template_Local_" + Section + "_Phishing_DirectAccess", theAPI)); pTemplate->SetText("Tmpl.Title", tr("Allow direct access to %1 phishing database").arg(Name)); pTemplate->SetText("Tmpl.Class", "Local"); pTemplate->AppendText("OpenFilePath", BrowserBinary + "," + ProfilePath + "\\Safe Browsing*"); pTemplate->AppendText("OpenFilePath", BrowserBinary + "," + ProfilePath + "\\CertificateRevocation"); pTemplate->AppendText("OpenFilePath", BrowserBinary + "," + ProfilePath + "\\SmartScreen"); // Microsoft Edge pTemplate->AppendText("OpenFilePath", BrowserBinary + "," + ProfilePath + "\\Ad Blocking"); // Microsoft Edge if (wizard.field("phishingDb").toBool() && pBox) pBox->AppendText("Template", pTemplate->GetName().mid(9)); } { QSharedPointer pTemplate = QSharedPointer(new CSbieIni("Template_Local_" + Section + "_Sync_DirectAccess", theAPI)); pTemplate->SetText("Tmpl.Title", tr("Allow direct access to %1 sync data").arg(Name)); pTemplate->SetText("Tmpl.Class", "Local"); pTemplate->AppendText("OpenFilePath", BrowserBinary + "," + ProfilePath + "*\\Sync Data\\*"); pTemplate->AppendText("OpenFilePath", BrowserBinary + "," + ProfilePath + "*\\Sync Extension Settings\\*"); if (wizard.field("syncData").toBool() && pBox) pBox->AppendText("Template", pTemplate->GetName().mid(9)); } { QSharedPointer pTemplate = QSharedPointer(new CSbieIni("Template_Local_" + Section + "_Preferences_DirectAccess", theAPI)); pTemplate->SetText("Tmpl.Title", tr("Allow direct access to %1 preferences").arg(Name)); pTemplate->SetText("Tmpl.Class", "Local"); pTemplate->AppendText("OpenFilePath", BrowserBinary + "," + ProfilePath + "*\\Preferences*"); if (wizard.field("preferences").toBool() && pBox) pBox->AppendText("Template", pTemplate->GetName().mid(9)); } { QSharedPointer pTemplate = QSharedPointer(new CSbieIni("Template_Local_" + Section + "_Passwords_DirectAccess", theAPI)); pTemplate->SetText("Tmpl.Title", tr("Allow direct access to %1 passwords").arg(Name)); pTemplate->SetText("Tmpl.Class", "Local"); pTemplate->AppendText("OpenFilePath", BrowserBinary + "," + ProfilePath + "*\\Login Data*"); if (wizard.field("passwords").toBool() && pBox) pBox->AppendText("Template", pTemplate->GetName().mid(9)); } { QSharedPointer pTemplate = QSharedPointer(new CSbieIni("Template_Local_" + Section + "_Cookies_DirectAccess", theAPI)); pTemplate->SetText("Tmpl.Title", tr("Allow direct access to %1 cookies").arg(Name)); pTemplate->SetText("Tmpl.Class", "Local"); pTemplate->AppendText("OpenFilePath", BrowserBinary + "," + ProfilePath + "*\\Cookies*"); if (wizard.field("cookies").toBool() && pBox) pBox->AppendText("Template", pTemplate->GetName().mid(9)); } { QSharedPointer pTemplate = QSharedPointer(new CSbieIni("Template_Local_" + Section + "_Bookmarks_DirectAccess", theAPI)); pTemplate->SetText("Tmpl.Title", tr("Allow direct access to %1 bookmarks").arg(Name)); pTemplate->SetText("Tmpl.Class", "Local"); pTemplate->AppendText("OpenFilePath", BrowserBinary + "," + ProfilePath + "*\\Bookmarks*"); pTemplate->AppendText("OpenFilePath", BrowserBinary + "," + ProfilePath + "*\\Favicons*"); if (wizard.field("bookmarks").toBool() && pBox) pBox->AppendText("Template", pTemplate->GetName().mid(9)); } { QSharedPointer pTemplate = QSharedPointer(new CSbieIni("Template_Local_" + Section + "_History_DirectAccess", theAPI)); pTemplate->SetText("Tmpl.Title", tr("Allow direct access to %1 bookmark and history database").arg(Name)); pTemplate->SetText("Tmpl.Class", "Local"); pTemplate->AppendText("OpenFilePath", BrowserBinary + "," + ProfilePath + "*\\Bookmarks*"); pTemplate->AppendText("OpenFilePath", BrowserBinary + "," + ProfilePath + "*\\Favicons*"); pTemplate->AppendText("OpenFilePath", BrowserBinary + "," + ProfilePath + "*\\*History*"); pTemplate->AppendText("OpenFilePath", BrowserBinary + "," + ProfilePath + "*\\Current *"); pTemplate->AppendText("OpenFilePath", BrowserBinary + "," + ProfilePath + "*\\Last *"); pTemplate->AppendText("OpenFilePath", BrowserBinary + "," + ProfilePath + "*\\Visited Links*"); if (wizard.field("history").toBool() && pBox) pBox->AppendText("Template", pTemplate->GetName().mid(9)); } break; } } break; } } return true; } ////////////////////////////////////////////////////////////////////////////////////////// // CTemplateTypePage // CTemplateTypePage::CTemplateTypePage(QWidget *parent) : QWizardPage(parent) { setTitle(tr("Create new Template")); setPixmap(QWizard::WatermarkPixmap, QPixmap(":/SideLogo.png")); int row = 0; QGridLayout *layout = new QGridLayout; //QLabel* pTopLabel = new QLabel(tr("")); //pTopLabel->setWordWrap(true); //layout->addWidget(pTopLabel, row++ , 0, 1, 3); layout->addWidget(new QLabel(tr("Select template type:")), row++, 0); m_pTemplateType = new QComboBox(); for (int i = 0; i < CTemplateWizard::TmplMax; i++) m_pTemplateType->addItem(tr("%1 template").arg(CTemplateWizard::GetTemplateLabel((CTemplateWizard::ETemplateType)i))); connect(m_pTemplateType, SIGNAL(currentIndexChanged(int)), this, SLOT(OnTypChanged())); layout->addWidget(m_pTemplateType, row++, 1, 1, 2); registerField("tmplType", m_pTemplateType); QLabel* pInfoLabel = new QLabel(); pInfoLabel->setWordWrap(true); layout->addWidget(pInfoLabel, row++, 0, 1, 3); setLayout(layout); } void CTemplateTypePage::OnTypChanged() { CTemplateWizard::ETemplateType Type = (CTemplateWizard::ETemplateType)field("tmplType").toInt(); if (!((CTemplateWizard*)wizard())->m_Hold && ((CTemplateWizard*)wizard())->m_Type != Type) { ((CTemplateWizard*)wizard())->m_Type = Type; ((CTemplateWizard*)wizard())->m_Hold = true; wizard()->restart(); ((CTemplateWizard*)wizard())->m_Hold = false; } } void CTemplateTypePage::initializePage() { m_pTemplateType->setCurrentIndex(((CTemplateWizard*)wizard())->m_Type); } int CTemplateTypePage::nextId() const { switch (field("tmplType").toInt()) { case CTemplateWizard::TmplWebBrowser: return CTemplateWizard::Page_BrowserPaths; default: return -1; } } bool CTemplateTypePage::isComplete() const { return true; } bool CTemplateTypePage::validatePage() { return true; } ////////////////////////////////////////////////////////////////////////////////////////// // CBrowserTypePage // CBrowserTypePage::CBrowserTypePage(QWidget *parent) : QWizardPage(parent) { setTitle(tr("Create Web Browser Template")); setSubTitle(tr("Select your Web Browsers main executable, this will allow Sandboxie to identify the browser.")); m_BrowserType = Browser_Other; int row = 0; QGridLayout *layout = new QGridLayout; //QLabel* pTopLabel = new QLabel(tr("")); //pTopLabel->setWordWrap(true); //layout->addWidget(pTopLabel, row++, 0, 1, 3); layout->addWidget(new QLabel(tr("Enter browser name:")), row++, 0); m_pName = new QLineEdit(); 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())); registerField("templateName", m_pName); m_NameState = 0; layout->addWidget(new QLabel(tr("Main executable (eg. firefox.exe, chrome.exe, msedge.exe, etc...):")), row++, 0); CPathEdit* pImagePath = new CPathEdit(false, true); pImagePath->SetWindowsPaths(); pImagePath->SetFilter(tr("Browser executable (*.exe)")); //pImagePath->SetDefault(); //pImagePath->SetText(); QStringList KnownPaths; // Firefox based KnownPaths.append("C:\\Program Files\\Mozilla Firefox\\firefox.exe"); KnownPaths.append("C:\\Program Files\\Firefox Developer Edition\\firefox.exe"); KnownPaths.append("C:\\Program Files\\Waterfox\\waterfox.exe"); KnownPaths.append("C:\\Program Files\\LibreWolf\\librewolf.exe"); KnownPaths.append("C:\\Program Files\\Pale Moon\\palemoon.exe"); KnownPaths.append("C:\\Program Files\\SeaMonkey\\seamonkey.exe"); // CHromium based QString AppData_Local = QProcessEnvironment::systemEnvironment().value("LocalAppData"); KnownPaths.append("C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe"); KnownPaths.append("C:\\Program Files\\Google\\Chrome Dev\\Application\\chrome.exe"); KnownPaths.append("C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe"); KnownPaths.append("C:\\Program Files (x86)\\Microsoft\\Edge Dev\\Application\\msedge.exe"); KnownPaths.append("C:\\Program Files\\BraveSoftware\\Brave-Browser\\Application\\brave.exe"); KnownPaths.append("C:\\Program Files\\SRWare Iron (64-Bit)\\iron.exe"); KnownPaths.append("C:\\Program Files\\Comodo\\Dragon\\dragon.exe"); KnownPaths.append(AppData_Local + "\\Chromium\\Application\\chrome.exe"); KnownPaths.append(AppData_Local + "\\Programs\\Opera\\launcher.exe"); KnownPaths.append(AppData_Local + "\\Vivaldi\\Application\\vivaldi.exe"); KnownPaths.append(AppData_Local + "\\Opera Software\\Opera Neon\\Application\\neon.exe"); KnownPaths.append(AppData_Local + "\\Maxthon\\Application\\Maxthon.exe"); foreach(const QString& KnownPath, KnownPaths) { if(QFile::exists(KnownPath)) pImagePath->GetCombo()->addItem(KnownPath); } pImagePath->GetCombo()->setCurrentText(""); connect(pImagePath, SIGNAL(textChanged(const QString&)), this, SLOT(OnPathChanged())); layout->addWidget(pImagePath, row++, 0, 1, 3); m_pBrowserPath = pImagePath->GetEdit(); registerField("browserPath", m_pBrowserPath); m_pInfoLabel = new QLabel(); m_pInfoLabel->setWordWrap(true); layout->addWidget(m_pInfoLabel, row++, 0, 1, 3); setLayout(layout); } int CBrowserTypePage::TestFiles(const QString& ImageDir, const QList& Files) { int TotalConfidence = 0; foreach(const STestFile & File, Files) { if (QFile::exists(ImageDir + "\\" + File.Name)) { TotalConfidence += File.Confidence; } } return TotalConfidence; } CBrowserTypePage::EBrowserType CBrowserTypePage::DetectBrowserType(const QString& ImagePath, int* pConfidence) { int Confidence = 0; StrPair PathName = Split2(ImagePath, "\\", true); StrPair NameExt = Split2(PathName.second, ".", true); // check for Gecko based QList GeckoFiles = QList() << STestFile{ "xul.dll", 50 } << STestFile{ "mozglue.dll", 50 }; Confidence = TestFiles(PathName.first, GeckoFiles); if (Confidence > 0) { if (pConfidence) *pConfidence = Confidence; return Browser_Gecko; } // check for Chromium based QList ChromiumFiles = QList() << STestFile{ "chrome.dll", 40 } << STestFile{ NameExt.first + ".dll", 40 } // some releases rename this dll << STestFile{ "chrome_elf.dll", 40 } << STestFile{ NameExt.first + "_elf.dll", 40 } // some releases rename and that dll << STestFile{ "v8_context_snapshot.bin", 20 }; QDir Dir(PathName.first); auto Dirs = Dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); for (int i = -1; i < Dirs.size(); i++) { Confidence = TestFiles(PathName.first + (i == -1 ? "" : ("\\" + Dirs[i].fileName())), ChromiumFiles); if (Confidence > 0) { if (pConfidence) *pConfidence = Confidence; return Browser_Chromium; } } return Browser_Other; } void CBrowserTypePage::OnPathChanged() { QString Path = m_pBrowserPath->text(); m_BrowserType = DetectBrowserType(Path); switch (m_BrowserType) { case Browser_Gecko: m_pInfoLabel->setText(tr("The browser appears to be Gecko based, like Mozilla Firefox and its derivatives.")); break; case Browser_Chromium: m_pInfoLabel->setText(tr("The browser appears to be Chromium based, like Microsoft Edge or Google Chrome and its derivatives.")); break; default: m_pInfoLabel->setText(tr("Browser could not be recognized, template cannot be created.")); } if (m_pName->text().isEmpty() || m_NameState == 0) { StrPair PathName = Split2(Path, "\\", true); StrPair NameExt = Split2(PathName.second, ".", true); StrPair PathParent = Split2(PathName.first, "\\", true); if (PathParent.second == "Application") PathParent = Split2(PathParent.first, "\\", true); m_NameState = 2; m_pName->setText(PathParent.second); m_NameState = 0; } emit completeChanged(); } void CBrowserTypePage::OnNameChanged() { if (m_NameState == 2) return; m_NameState = 1; emit completeChanged(); } void CBrowserTypePage::initializePage() { //QTimer::singleShot(10, m_pBrowserPath, SLOT(setFocus())); } int CBrowserTypePage::nextId() const { return CTemplateWizard::Page_BrowserPaths; } bool CBrowserTypePage::isComplete() const { return m_BrowserType != Browser_Other && !field("templateName").toString().isEmpty(); } bool CBrowserTypePage::validatePage() { QString Section = field("templateName").toString().replace(" ", "_"); QSharedPointer pTemplate = QSharedPointer(new CSbieIni("Template_Local_" + Section + "_Force", theAPI)); if (!pTemplate->GetText("ForceProcess").isEmpty()) { QMessageBox::critical(this, "Sandboxie-Plus", tr("This browser name is already in use, please choose an other one.")); return false; } return true; } ////////////////////////////////////////////////////////////////////////////////////////// // CBrowserPathsPage // CBrowserPathsPage::CBrowserPathsPage(QWidget *parent) : QWizardPage(parent) { setTitle(tr("Create Web Browser Template")); setSubTitle(tr("Configure your Web Browser's profile directories.")); int row = 0; QGridLayout *layout = new QGridLayout; //QLabel* pTopLabel = new QLabel(tr("")); //pTopLabel->setWordWrap(true); //layout->addWidget(pTopLabel, row++, 0, 1, 3); layout->addWidget(new QLabel(tr("User profile(s) directory:")), row, 0); m_pProfileFilter = new QCheckBox(tr("Show also imperfect matches")); layout->addWidget(m_pProfileFilter, row++, 2); connect(m_pProfileFilter, SIGNAL(toggled(bool)), this, SLOT(OnProfilesChange())); CPathEdit* pImagePath = new CPathEdit(true, true); pImagePath->SetWindowsPaths(); pImagePath->SetFilter(tr("Browser Executable (*.exe)")); //pImagePath->SetDefault(); //pImagePath->SetText(); connect(pImagePath, SIGNAL(textChanged(const QString&)), this, SLOT(OnProfileChange())); layout->addWidget(pImagePath, row++, 0, 1, 3); m_pProfilePath = pImagePath->GetCombo(); registerField("profilePath", m_pProfilePath->lineEdit()); m_pInfoLabel = new QLabel(); m_pInfoLabel->setWordWrap(true); layout->addWidget(m_pInfoLabel, row++, 0, 1, 3); QWidget* pSpacer = new QWidget(); pSpacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); layout->addWidget(pSpacer, row++, 1); m_pNoProfile = new QCheckBox(tr("Continue without browser profile")); layout->addWidget(m_pNoProfile, row++, 2); connect(m_pNoProfile, SIGNAL(toggled(bool)), this, SLOT(OnNoProfile())); registerField("noProfile", m_pNoProfile); setLayout(layout); } void CBrowserPathsPage::OnNoProfile() { m_pProfilePath->setEnabled(!m_pNoProfile->isChecked()); m_pInfoLabel->setEnabled(!m_pNoProfile->isChecked()); emit completeChanged(); } bool CBrowserPathsPage::IsFirefoxProfile(const QString& Path) { int FoundCount = 0; QStringList KnownFiles = QStringList() << "prefs.js" << "extensions.json" << "cookies.sqlite" << "storage.sqlite" << "protections.sqlite" << "xulstore.json" << "places.sqlite" << "favicons.sqlite" << "permissions.sqlite" << "formhistory.sqlite" << "credentialstate.sqlite" << "extension-preferences.json"; foreach(const QString & KnownFile, KnownFiles) { if (QFile::exists(Path + "\\" + KnownFile)) FoundCount++; } return FoundCount >= KnownFiles.size() / 2; } QString CBrowserPathsPage::GetFirefoxProfiles(const QString& Path) { if (QFile::exists(Path + "\\Profiles")) return Path + "\\Profiles"; return QString(); } bool CBrowserPathsPage::IsChromiumProfile(const QString& Path) { int FoundCount = 0; QStringList KnownFiles = QStringList() << "Bookmarks" << "Favicons" << "History" << "Preferences" << "Shortcuts" << "Web Data" << "Code Cache" << "Extension Scripts" << "Extension State" << "Local Storage" << "Network" << "Session Storage"; foreach(const QString & KnownFile, KnownFiles) { if (QFile::exists(Path + "\\" + KnownFile)) FoundCount++; } return FoundCount >= KnownFiles.size() / 2; } QString CBrowserPathsPage::GetChromiumProfiles(const QString& Path) { if (IsChromiumProfile(Path)) return Path; if (QFile::exists(Path + "\\User Data")) return Path + "\\User Data"; return QString(); } int CBrowserPathsPage::SmartMatch(const QString& DirName, const QString& Name) { if (DirName.compare(Name, Qt::CaseInsensitive) == 0) return 100; if(DirName.simplified().remove(" ").compare(Name, Qt::CaseInsensitive) == 0) return 90; QStringList DirNameParts = DirName.split(QRegularExpression("[^A-Za-z0-9]"), Qt::SkipEmptyParts); foreach(const QString & DirNamePart, DirNameParts) { if (Name.contains(DirNamePart, Qt::CaseInsensitive)) return 50; } QStringList NameParts = Name.split(QRegularExpression("[^A-Za-z0-9]"), Qt::SkipEmptyParts); foreach(const QString & NamePart, NameParts) { if (DirName.contains(NamePart, Qt::CaseInsensitive)) return 50; } return 0; } QList CBrowserPathsPage::FindFolders(const QString& Root, const QString& Name, QString(*GetProfilePath)(const QString&), int Depth) { QList Folders; QDir Dir(Root); foreach(const QFileInfo& Info, Dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot)) { QString DirName = Info.fileName(); if (DirName.compare("Temp", Qt::CaseInsensitive) == 0) continue; if (int Match = SmartMatch(DirName, Name)) { QString ProfilePath = GetProfilePath(Root + "\\" + DirName); if (!ProfilePath.isEmpty()) Folders.append(SFoundFolder{ ProfilePath, Match }); } if (Depth > 0) Folders.append(FindFolders(Root + "\\" + DirName, Name, GetProfilePath, Depth - 1)); } return Folders; } QList CBrowserPathsPage::FindFirefoxFolders(const QString& ImagePath) { StrPair PathName = Split2(ImagePath, "\\", true); StrPair NameExt = Split2(PathName.second, ".", true); QString AppData_Roaming = QProcessEnvironment::systemEnvironment().value("AppData"); return FindFolders(AppData_Roaming, NameExt.first, GetFirefoxProfiles); } QList CBrowserPathsPage::FindChromiumFolders(const QString& ImagePath) { QList Folders; StrPair PathName = Split2(ImagePath, "\\", true); StrPair NameExt = Split2(PathName.second, ".", true); StrPair PathParent = Split2(PathName.first, "\\", true); QString AppData_Local = QProcessEnvironment::systemEnvironment().value("LocalAppData"); // same directory, best match QString GetProfilePath = GetChromiumProfiles(PathParent.first); if (!GetProfilePath.isEmpty()) // "User Data" in the same parent as "Application" Folders.append(SFoundFolder{ PathParent.first + "\\User Data", 100 }); GetProfilePath = GetChromiumProfiles(PathName.first); if (!GetProfilePath.isEmpty()) // "User Data" under "Application" like Maxthon Folders.append(SFoundFolder{ PathName.first + "\\User Data", 100 }); if (Folders.isEmpty()) { // find directories by image parent name, higher priority if (PathParent.second == "Application") { PathParent = Split2(PathParent.first, "\\", true); Folders.append(FindFolders(AppData_Local, PathParent.second, GetChromiumProfiles)); } // find directories by image name else { //if (NameExt.first.compare("Chrome.exe", Qt::CaseInsensitive) == 0 && !PathParent.first.contains("\\Google\\")) { //} Folders.append(FindFolders(AppData_Local, NameExt.first, GetChromiumProfiles)); if (Folders.isEmpty()) // like opera { QString AppData_Roaming = QProcessEnvironment::systemEnvironment().value("AppData"); Folders.append(FindFolders(AppData_Roaming, PathParent.second, GetChromiumProfiles)); } } } return Folders; } void CBrowserPathsPage::initializePage() { CBrowserTypePage* pPage = (CBrowserTypePage*)wizard()->page(CTemplateWizard::Page_BrowserType); switch (pPage->m_BrowserType) { case CBrowserTypePage::Browser_Gecko: setSubTitle(tr("Configure your Gecko based Browsers profile directories.")); m_FoundFolders = FindFirefoxFolders(field("browserPath").toString()); break; case CBrowserTypePage::Browser_Chromium: setSubTitle(tr("Configure your Chromium based Browsers profile directories.")); m_FoundFolders = FindChromiumFolders(field("browserPath").toString()); break; } OnProfilesChange(); } void CBrowserPathsPage::OnProfilesChange() { QList Folders = m_FoundFolders; int MaxConfidence = 0; int MinConfidence = 0; if (!Folders.isEmpty()) { auto min_max = std::minmax_element(Folders.begin(), Folders.end(), [](const SFoundFolder& s1, const SFoundFolder& s2) { return s1.Confidence < s2.Confidence; }); MinConfidence = min_max.first->Confidence; MaxConfidence = min_max.second->Confidence; if (!m_pProfileFilter->isChecked()) { // filter the results with the highest confidence level only QList BestFolders; std::copy_if(Folders.begin(), Folders.end(), std::inserter(BestFolders, BestFolders.end()), [MaxConfidence](const SFoundFolder& s) {return s.Confidence == MaxConfidence; }); Folders = BestFolders; } else { // sort the items with the highest confidence first std::sort(Folders.begin(), Folders.end(), [](const SFoundFolder& s1, const SFoundFolder& s2) { return s1.Confidence > s2.Confidence; }); } } m_pProfileFilter->setVisible(MinConfidence < 100 && MaxConfidence > 0); if (MaxConfidence != 100) m_pProfileFilter->setChecked(true); m_pProfileFilter->setEnabled(MaxConfidence >= 100); m_pProfilePath->clear(); foreach(const SFoundFolder & Folder, Folders) m_pProfilePath->addItem(Folder.Path); if (m_pProfilePath->count() > 1) // require the user to make a choice m_pProfilePath->setCurrentText(""); OnProfileChange(); } bool CBrowserPathsPage::IsBrowserProfile(const QString& Path) const { CBrowserTypePage* pPage = (CBrowserTypePage*)wizard()->page(CTemplateWizard::Page_BrowserType); switch (pPage->m_BrowserType) { case CBrowserTypePage::Browser_Gecko: return IsFirefoxProfile(Path); case CBrowserTypePage::Browser_Chromium: return IsChromiumProfile(Path); default: return false; } } bool CBrowserPathsPage::TestProfilePath(const QString& Path) const { if (IsBrowserProfile(Path)) return true; QDir Dir(Path); foreach(const QFileInfo& Info, Dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot)) { if (IsBrowserProfile(Path + "\\" + Info.fileName())) return true; } return false; } void CBrowserPathsPage::OnProfileChange() { QString CurPath = m_pProfilePath->currentText(); if (CurPath.isEmpty()) { if(m_FoundFolders.isEmpty()) m_pInfoLabel->setText(tr( "No suitable folders have been found.\n" "Note: you need to run the browser unsandboxed for them to get created.\n" "Please browse to the correct user profile directory.")); else m_pInfoLabel->setText(tr( "Please choose the correct user profile directory, if it is not listed you may need to browse to it.")); } else if (TestProfilePath(CurPath)) { if (m_pProfileFilter->isVisible() && m_pProfileFilter->isCheckable()) m_pInfoLabel->setText(tr( "Please ensure the selected directory is correct, the wizard is not confident in all the presented options.")); else m_pInfoLabel->setText(tr( "Please ensure the selected directory is correct.")); } else { m_pInfoLabel->setText(tr( "This path does not look like a valid profile directory.")); } emit completeChanged(); } int CBrowserPathsPage::nextId() const { return CTemplateWizard::Page_BrowserOptions; } bool CBrowserPathsPage::isComplete() const { return TestProfilePath(m_pProfilePath->currentText()) || field("noProfile").toBool(); } bool CBrowserPathsPage::validatePage() { return true; } ////////////////////////////////////////////////////////////////////////////////////////// // CBrowserOptionsPage // CBrowserOptionsPage::CBrowserOptionsPage(QWidget *parent) : QWizardPage(parent) { setTitle(tr("Create Web Browser Template")); setSubTitle(tr("Configure web browser template options.")); int row = 0; QGridLayout *layout = new QGridLayout; //QLabel* pTopLabel = new QLabel(tr("")); //pTopLabel->setWordWrap(true); //layout->addWidget(pTopLabel, row++, 0, 1, 3); layout->setSpacing(3); m_pForce = new QCheckBox(tr("Force the Web Browser to run in this sandbox")); layout->addWidget(m_pForce, row++, 0, 1, 3); registerField("forceBrowser", m_pForce); m_pProfile = new QCheckBox(tr("Allow direct access to the entire Web Browser profile folder")); layout->addWidget(m_pProfile, row++, 0, 1, 3); registerField("fullProfile", m_pProfile); m_pPhishingDb = new QCheckBox(tr("Allow direct access to Web Browser's phishing database")); layout->addWidget(m_pPhishingDb, row++, 0, 1, 3); registerField("phishingDb", m_pPhishingDb); m_pSessions = new QCheckBox(tr("Allow direct access to Web Browser's session management")); layout->addWidget(m_pSessions, row++, 0, 1, 3); registerField("sessions", m_pSessions); m_pSyncData = new QCheckBox(tr("Allow direct access to Web Browser's sync data")); layout->addWidget(m_pSyncData, row++, 0, 1, 3); registerField("syncData", m_pSyncData); m_pPreferences = new QCheckBox(tr("Allow direct access to Web Browser's preferences")); layout->addWidget(m_pPreferences, row++, 0, 1, 3); registerField("preferences", m_pPreferences); m_pPasswords = new QCheckBox(tr("Allow direct access to Web Browser's passwords")); layout->addWidget(m_pPasswords, row++, 0, 1, 3); registerField("passwords", m_pPasswords); m_pCookies = new QCheckBox(tr("Allow direct access to Web Browser's cookies")); layout->addWidget(m_pCookies, row++, 0, 1, 3); registerField("cookies", m_pCookies); m_pBookmarks = new QCheckBox(tr("Allow direct access to Web Browser's bookmarks")); layout->addWidget(m_pBookmarks, row++, 0, 1, 3); registerField("bookmarks", m_pBookmarks); m_pHistory = new QCheckBox(tr("Allow direct access to Web Browser's bookmark and history database")); layout->addWidget(m_pHistory, row++, 0, 1, 3); registerField("history", m_pHistory); setLayout(layout); } int CBrowserOptionsPage::nextId() const { return CTemplateWizard::Page_FinishTemplate; } void CBrowserOptionsPage::initializePage() { CBrowserTypePage* pPage = (CBrowserTypePage*)wizard()->page(CTemplateWizard::Page_BrowserType); m_pSessions->setVisible(pPage->m_BrowserType == CBrowserTypePage::Browser_Gecko); m_pSyncData->setVisible(pPage->m_BrowserType == CBrowserTypePage::Browser_Chromium); m_pPreferences->setVisible(pPage->m_BrowserType == CBrowserTypePage::Browser_Chromium); m_pBookmarks->setVisible(pPage->m_BrowserType == CBrowserTypePage::Browser_Chromium); m_pProfile->setEnabled(!field("noProfile").toBool()); m_pPhishingDb->setEnabled(!field("noProfile").toBool()); m_pSessions->setEnabled(!field("noProfile").toBool()); m_pSyncData->setEnabled(!field("noProfile").toBool()); m_pPreferences->setEnabled(!field("noProfile").toBool()); m_pPasswords->setEnabled(!field("noProfile").toBool()); m_pCookies->setEnabled(!field("noProfile").toBool()); m_pBookmarks->setEnabled(!field("noProfile").toBool()); m_pHistory->setEnabled(!field("noProfile").toBool()); } bool CBrowserOptionsPage::validatePage() { return true; } ////////////////////////////////////////////////////////////////////////////////////////// // CFinishTemplatePage // CFinishTemplatePage::CFinishTemplatePage(QWidget *parent) : QWizardPage(parent) { setTitle(tr("Create Web Browser Template")); setPixmap(QWizard::WatermarkPixmap, QPixmap(":/SideLogo.png")); int row = 0; QGridLayout *layout = new QGridLayout; QLabel* pLabel = new QLabel; pLabel->setWordWrap(true); pLabel->setText(tr("Almost complete, click Finish to create a new Web Browser Template and conclude the wizard.")); layout->addWidget(pLabel, row++ , 0, 1, 3); m_pSummary = new QTextEdit(); m_pSummary->setReadOnly(true); m_pSummary->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); layout->addWidget(m_pSummary, row++ , 0, 1, 3); setLayout(layout); } int CFinishTemplatePage::nextId() const { return -1; } void CFinishTemplatePage::initializePage() { QString Info = tr("Browser name: %1\n").arg(field("templateName").toString()); CBrowserTypePage* pPage = (CBrowserTypePage*)wizard()->page(CTemplateWizard::Page_BrowserType); switch (pPage->m_BrowserType) { case CBrowserTypePage::Browser_Gecko: Info += tr("Browser Type: Gecko (Mozilla Firefox)\n"); break; case CBrowserTypePage::Browser_Chromium: Info += tr("Browser Type: Chromium (Google Chrome)\n"); break; } Info += tr("\n"); Info += tr("Browser executable path: %1\n").arg(field("browserPath").toString()); QString ProfilePath = field("profilePath").toString(); QString AppData_Roaming = QProcessEnvironment::systemEnvironment().value("AppData"); QString AppData_Local = QProcessEnvironment::systemEnvironment().value("LocalAppData"); ProfilePath.replace(AppData_Roaming, "%AppData%"); ProfilePath.replace(AppData_Local, "%Local AppData%"); Info += tr("Browser profile path: %1\n").arg(ProfilePath); m_pSummary->setText(Info); } bool CFinishTemplatePage::validatePage() { return true; }