new Welcome Page and firstrunWizard (#235)
Co-authored-by: Chris Rizzitello <crizzitello@ics.com>main
parent
3e1ba34ca5
commit
26fb82edd5
|
@ -64,6 +64,7 @@ find_package(Qt6 6.5.0 REQUIRED COMPONENTS
|
|||
Network
|
||||
Sql
|
||||
Core
|
||||
Svg
|
||||
)
|
||||
|
||||
add_subdirectory(deploy)
|
||||
|
|
|
@ -104,6 +104,9 @@ QString AppConfig::defaultValue(const QString &key)
|
|||
if (key == CONFIG::APIURL)
|
||||
return QStringLiteral("http://localhost:8080");
|
||||
|
||||
if (key == CONFIG::SHOW_WELCOME_SCREEN)
|
||||
return QStringLiteral("true");
|
||||
|
||||
if (key == CONFIG::SHORTCUT_CAPTURECLIPBOARD) {
|
||||
if(!get()->appSettings->value(key).isValid())
|
||||
return QStringLiteral("Meta+Alt+v");
|
||||
|
|
|
@ -21,6 +21,7 @@ struct CONFIG {
|
|||
inline static const auto COMMAND_CAPTUREWINDOW = QStringLiteral("captureWindowExec");
|
||||
inline static const auto SHORTCUT_CAPTUREWINDOW = QStringLiteral("captureWindowShortcut");
|
||||
inline static const auto SHORTCUT_CAPTURECLIPBOARD = QStringLiteral("captureClipboardShortcut");
|
||||
inline static const auto SHOW_WELCOME_SCREEN = QStringLiteral("showWelcomeScreen");
|
||||
};
|
||||
|
||||
/// AppConfig is a singleton for accessing the application's configuration.
|
||||
|
@ -102,5 +103,6 @@ private:
|
|||
CONFIG::COMMAND_CAPTUREWINDOW,
|
||||
CONFIG::SHORTCUT_CAPTUREWINDOW,
|
||||
CONFIG::SHORTCUT_CAPTURECLIPBOARD,
|
||||
CONFIG::SHOW_WELCOME_SCREEN,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -9,6 +9,19 @@ add_library (FORMS STATIC
|
|||
getinfo/getinfo.cpp getinfo/getinfo.h
|
||||
porting/porting_dialog.cpp porting/porting_dialog.h
|
||||
settings/settings.cpp settings/settings.h
|
||||
firstRunWizard/firstTimeWizard.h firstRunWizard/firstTimeWizard.cpp
|
||||
firstRunWizard/welcomepage.h firstRunWizard/welcomepage.cpp
|
||||
firstRunWizard/wizardpage.h firstRunWizard/wizardpage.cpp
|
||||
firstRunWizard/requirementspage.h firstRunWizard/requirementspage.cpp
|
||||
firstRunWizard/evidencepage.h firstRunWizard/evidencepage.cpp
|
||||
firstRunWizard/apikeyspage.h firstRunWizard/apikeyspage.cpp
|
||||
firstRunWizard/hostpathpage.h firstRunWizard/hostpathpage.cpp
|
||||
firstRunWizard/hosttestpage.h firstRunWizard/hosttestpage.cpp
|
||||
firstRunWizard/captureareapage.h firstRunWizard/captureareapage.cpp
|
||||
firstRunWizard/capturewindowpage.h firstRunWizard/capturewindowpage.cpp
|
||||
firstRunWizard/captureclipboardpage.h firstRunWizard/captureclipboardpage.cpp
|
||||
firstRunWizard/opspage.h firstRunWizard/opspage.cpp
|
||||
firstRunWizard/finishedpage.h firstRunWizard/finishedpage.cpp
|
||||
)
|
||||
|
||||
add_library(ASHIRT::FORMS ALIAS FORMS)
|
||||
|
@ -26,6 +39,7 @@ target_link_libraries ( FORMS
|
|||
Qt::Gui
|
||||
Qt::Widgets
|
||||
Qt::Sql
|
||||
Qt::Svg
|
||||
ASHIRT::HELPERS
|
||||
ASHIRT::MODELS
|
||||
ASHIRT::COMPONENTS
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
#include "apikeyspage.h"
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
#include <appconfig.h>
|
||||
|
||||
bool ApiKeysPage::validatePage()
|
||||
{
|
||||
if (!field("host.accessKey").isValid())
|
||||
return false;
|
||||
|
||||
if (!field("host.secretKey").isValid())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ApiKeysPage::initializePage()
|
||||
{
|
||||
QString accessKey = AppConfig::value(CONFIG::ACCESSKEY);
|
||||
setField("host.accessKey", accessKey);
|
||||
accessKeyLine->setText(accessKey);
|
||||
|
||||
QString secretKey = AppConfig::value(CONFIG::SECRETKEY);
|
||||
setField("host.secretKey", secretKey);
|
||||
secretKeyLine->setText(secretKey);
|
||||
}
|
||||
|
||||
ApiKeysPage::ApiKeysPage(QWidget *parent)
|
||||
: WizardPage{Page_Api, parent}
|
||||
{
|
||||
|
||||
auto f = font();
|
||||
auto _lblTitleLabel = new QLabel(this);
|
||||
f.setPointSize(titleFont.first);
|
||||
f.setWeight(titleFont.second);
|
||||
_lblTitleLabel->setFont(f);
|
||||
_lblTitleLabel->setText(tr("API Keys"));
|
||||
|
||||
auto _lblSubtitle = new QLabel(this);
|
||||
f.setPointSize(subTitleFont.first);
|
||||
f.setWeight(subTitleFont.second);
|
||||
_lblSubtitle->setFont(f);
|
||||
_lblSubtitle->setWordWrap(true);
|
||||
_lblSubtitle->setText(tr("Input Api keys for the server"));
|
||||
|
||||
auto _lblBody = new QLabel(this);
|
||||
f.setPointSize(bodyFont.first);
|
||||
f.setWeight(bodyFont.second);
|
||||
_lblBody->setFont(f);
|
||||
_lblBody->setWordWrap(true);
|
||||
_lblBody->setText(tr("• Login to the Ashirt server click the profile icon in the top right then select <i>Account Settings</i><br>"));
|
||||
|
||||
auto _lblBody2 = new QLabel(this);
|
||||
_lblBody2->setFont(f);
|
||||
_lblBody2->setWordWrap(true);
|
||||
_lblBody2->setText(tr("• Select <i>API Keys</i> on the left, select click <i>Generate New API Key</i><br>"));
|
||||
|
||||
auto _lblBody3 = new QLabel(this);
|
||||
_lblBody3->setFont(f);
|
||||
_lblBody3->setWordWrap(true);
|
||||
_lblBody3->setText(tr("• Enter your keys below"));
|
||||
|
||||
auto _lblAKey = new QLabel(this);
|
||||
f.setPointSize(smallFont.first);
|
||||
f.setWeight(smallFont.second);
|
||||
_lblAKey->setFont(f);
|
||||
_lblAKey->setText(tr("Access Key"));
|
||||
|
||||
accessKeyLine = new QLineEdit(this);
|
||||
accessKeyLine->setMaxLength(24);
|
||||
accessKeyLine->setTextMargins(3,0,3,0);
|
||||
accessKeyLine->setMaximumWidth(fontMetrics().averageCharWidth() * 27);
|
||||
registerField("host.accessKey*", accessKeyLine);
|
||||
|
||||
auto t1 = new QVBoxLayout();
|
||||
t1->setSpacing(1);
|
||||
t1->addWidget(_lblAKey);
|
||||
t1->addWidget(accessKeyLine);
|
||||
|
||||
auto _lblBKey = new QLabel(this);
|
||||
f.setPointSize(smallFont.first);
|
||||
f.setWeight(smallFont.second);
|
||||
_lblBKey->setFont(f);
|
||||
_lblBKey->setText(tr("Secret Key"));
|
||||
|
||||
secretKeyLine = new QLineEdit(this);
|
||||
secretKeyLine->setTextMargins(3,0,3,0);
|
||||
registerField("host.secretKey*", secretKeyLine);
|
||||
|
||||
auto t2 = new QVBoxLayout();
|
||||
t2->setSpacing(1);
|
||||
t2->addWidget(_lblBKey);
|
||||
t2->addWidget(secretKeyLine);
|
||||
|
||||
auto tLayout = new QHBoxLayout();
|
||||
tLayout->addLayout(t1);
|
||||
tLayout->addLayout(t2);
|
||||
|
||||
auto layout = new QVBoxLayout();
|
||||
layout->addWidget(_lblTitleLabel);
|
||||
layout->addWidget(_lblSubtitle);
|
||||
layout->addSpacerItem(new QSpacerItem(0,30,QSizePolicy::Minimum, QSizePolicy::Fixed));
|
||||
layout->addWidget(_lblBody);
|
||||
layout->addWidget(_lblBody2);
|
||||
layout->addWidget(_lblBody3);
|
||||
layout->addSpacerItem(new QSpacerItem(0,30,QSizePolicy::Minimum, QSizePolicy::Fixed));
|
||||
layout->addLayout(tLayout);
|
||||
layout->addSpacerItem(new QSpacerItem(0,0,QSizePolicy::Minimum, QSizePolicy::Expanding));
|
||||
setLayout(layout);
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
#pragma once
|
||||
|
||||
#include "wizardpage.h"
|
||||
#include <QObject>
|
||||
|
||||
class QLineEdit;
|
||||
class ApiKeysPage : public WizardPage
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
bool validatePage() override;
|
||||
void initializePage() override;
|
||||
ApiKeysPage(QWidget *parent = nullptr);
|
||||
private:
|
||||
QLineEdit * accessKeyLine = nullptr;
|
||||
QLineEdit * secretKeyLine = nullptr;
|
||||
};
|
|
@ -0,0 +1,115 @@
|
|||
#include "captureareapage.h"
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
#include <appconfig.h>
|
||||
|
||||
#include "hotkeymanager.h"
|
||||
#include "components/custom_keyseq_edit/singlestrokekeysequenceedit.h"
|
||||
|
||||
bool CaptureAreaPage::validatePage()
|
||||
{
|
||||
if(!field("command.area").isValid())
|
||||
return false;
|
||||
AppConfig::setValue(CONFIG::COMMAND_SCREENSHOT, field("command.area").toString());
|
||||
|
||||
if(!field("keySequence.area").isValid())
|
||||
return false;
|
||||
auto keyCombo = QKeySequence::fromString(field("keySequence.area").toString(), QKeySequence::NativeText);
|
||||
AppConfig::setValue(CONFIG::SHORTCUT_SCREENSHOT, keyCombo.toString(QKeySequence::PortableText));
|
||||
HotkeyManager::updateHotkeys();
|
||||
return true;
|
||||
}
|
||||
|
||||
void CaptureAreaPage::initializePage()
|
||||
{
|
||||
HotkeyManager::unregisterKey(HotkeyManager::ACTION_CAPTURE_AREA);
|
||||
QString captureAreaCommand = AppConfig::value(CONFIG::COMMAND_SCREENSHOT);
|
||||
if(!captureAreaCommand.isEmpty()) {
|
||||
setField("command.area", captureAreaCommand);
|
||||
captureAreaLine->setText(captureAreaCommand);
|
||||
}
|
||||
|
||||
QString sequence = AppConfig::value(CONFIG::SHORTCUT_SCREENSHOT);
|
||||
if(!sequence.isEmpty()) {
|
||||
setField("keySequence.area", sequence);
|
||||
captureAreaKeySequenceEdit->setKeySequence(QKeySequence::fromString(sequence));
|
||||
}
|
||||
}
|
||||
|
||||
void CaptureAreaPage::cleanupPage()
|
||||
{
|
||||
HotkeyManager::updateHotkeys();
|
||||
}
|
||||
|
||||
CaptureAreaPage::CaptureAreaPage(QWidget *parent)
|
||||
: WizardPage{Page_CaptureArea, parent}
|
||||
{
|
||||
auto f = font();
|
||||
auto _lblTitleLabel = new QLabel(this);
|
||||
f.setPointSize(titleFont.first);
|
||||
f.setWeight(titleFont.second);
|
||||
_lblTitleLabel->setFont(f);
|
||||
_lblTitleLabel->setText(tr("Capture Area"));
|
||||
|
||||
auto _lblSubtitle = new QLabel(this);
|
||||
f.setPointSize(subTitleFont.first);
|
||||
f.setWeight(subTitleFont.second);
|
||||
_lblSubtitle->setFont(f);
|
||||
_lblSubtitle->setWordWrap(true);
|
||||
_lblSubtitle->setText(tr("Set the capture area command and shortcut."));
|
||||
|
||||
auto _lblB1 = new QLabel(this);
|
||||
f.setPointSize(bodyFont.first);
|
||||
f.setWeight(bodyFont.second);
|
||||
_lblB1->setFont(f);
|
||||
_lblB1->setText(tr("<html><br><br>• Enter the command ashirt will use to capture area screenshots<br><br>• Enter a key combination that will trigger the capture area command<html>"));
|
||||
|
||||
auto hLayout = new QHBoxLayout();
|
||||
hLayout->addWidget(_lblB1, 0, Qt::AlignHCenter);
|
||||
|
||||
auto _lblAKey = new QLabel(this);
|
||||
f.setPointSize(smallFont.first);
|
||||
f.setWeight(smallFont.second);
|
||||
_lblAKey->setFont(f);
|
||||
_lblAKey->setText(tr("Capture Area Command"));
|
||||
|
||||
captureAreaLine = new QLineEdit(this);
|
||||
captureAreaLine->setTextMargins(3,0,3,0);
|
||||
registerField("command.area*", captureAreaLine);
|
||||
|
||||
auto t1 = new QVBoxLayout();
|
||||
t1->setSpacing(1);
|
||||
t1->addWidget(_lblAKey);
|
||||
t1->addWidget(captureAreaLine);
|
||||
|
||||
auto _lblBKey = new QLabel(this);
|
||||
f.setPointSize(smallFont.first);
|
||||
f.setWeight(smallFont.second);
|
||||
_lblBKey->setFont(f);
|
||||
_lblBKey->setText(tr("Shortcut"));
|
||||
|
||||
captureAreaKeySequenceEdit = new SingleStrokeKeySequenceEdit(this);
|
||||
registerField("keySequence.area*", captureAreaKeySequenceEdit, "keySequence", SIGNAL(keySequenceChanged(const QKeySequence &)));
|
||||
|
||||
auto t2 = new QVBoxLayout();
|
||||
t2->setSpacing(1);
|
||||
t2->addWidget(_lblBKey);
|
||||
t2->addWidget(captureAreaKeySequenceEdit);
|
||||
|
||||
auto tLayout = new QHBoxLayout();
|
||||
tLayout->addLayout(t1, 8);
|
||||
tLayout->addLayout(t2, 2);
|
||||
|
||||
auto layout = new QVBoxLayout();
|
||||
layout->addWidget(_lblTitleLabel);
|
||||
layout->addWidget(_lblSubtitle);
|
||||
layout->addLayout(hLayout);
|
||||
layout->addSpacerItem(new QSpacerItem(0,60,QSizePolicy::Minimum, QSizePolicy::Fixed));
|
||||
layout->addLayout(tLayout);
|
||||
layout->addSpacerItem(new QSpacerItem(0,0,QSizePolicy::Minimum, QSizePolicy::Expanding));
|
||||
setLayout(layout);
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include "wizardpage.h"
|
||||
#include <QObject>
|
||||
|
||||
class QLineEdit;
|
||||
class SingleStrokeKeySequenceEdit;
|
||||
class CaptureAreaPage : public WizardPage
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
bool validatePage() override;
|
||||
void initializePage() override;
|
||||
void cleanupPage() override;
|
||||
CaptureAreaPage(QWidget *parent = nullptr);
|
||||
private:
|
||||
QLineEdit *captureAreaLine = nullptr;
|
||||
SingleStrokeKeySequenceEdit *captureAreaKeySequenceEdit = nullptr;
|
||||
};
|
|
@ -0,0 +1,84 @@
|
|||
#include "captureclipboardpage.h"
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
#include <appconfig.h>
|
||||
|
||||
#include "hotkeymanager.h"
|
||||
#include "components/custom_keyseq_edit/singlestrokekeysequenceedit.h"
|
||||
|
||||
bool CaptureClipboardPage::validatePage()
|
||||
{
|
||||
if(!field("keySequence.clipboard").isValid())
|
||||
return false;
|
||||
|
||||
auto keyCombo = QKeySequence::fromString(field("keySequence.clipboard").toString(), QKeySequence::NativeText);
|
||||
AppConfig::setValue(CONFIG::SHORTCUT_CAPTURECLIPBOARD, keyCombo.toString(QKeySequence::PortableText));
|
||||
HotkeyManager::updateHotkeys();
|
||||
return true;
|
||||
}
|
||||
|
||||
void CaptureClipboardPage::initializePage()
|
||||
{
|
||||
HotkeyManager::unregisterKey(HotkeyManager::ACTION_CAPTURE_CLIPBOARD);
|
||||
QString sequence = AppConfig::value(CONFIG::SHORTCUT_CAPTURECLIPBOARD);
|
||||
setField("keySequence.clipboard", sequence);
|
||||
captureClipboardKeySequence->setKeySequence(QKeySequence::fromString(sequence));
|
||||
}
|
||||
|
||||
void CaptureClipboardPage::cleanupPage()
|
||||
{
|
||||
HotkeyManager::updateHotkeys();
|
||||
HotkeyManager::unregisterKey(HotkeyManager::ACTION_CAPTURE_WINDOW);
|
||||
}
|
||||
|
||||
CaptureClipboardPage::CaptureClipboardPage(QWidget *parent)
|
||||
: WizardPage{WizardPage::Page_CaptureClipboard, parent}
|
||||
{
|
||||
auto f = font();
|
||||
auto _lblTitleLabel = new QLabel(this);
|
||||
f.setPointSize(titleFont.first);
|
||||
f.setWeight(titleFont.second);
|
||||
_lblTitleLabel->setFont(f);
|
||||
_lblTitleLabel->setText(tr("Capture Cliboard"));
|
||||
|
||||
auto _lblSubtitle = new QLabel(this);
|
||||
f.setPointSize(subTitleFont.first);
|
||||
f.setWeight(subTitleFont.second);
|
||||
_lblSubtitle->setFont(f);
|
||||
_lblSubtitle->setWordWrap(true);
|
||||
_lblSubtitle->setText(tr("Uploads clipboard images or text to ashirt.\nText is uploaded as a code block"));
|
||||
|
||||
auto _lblB1 = new QLabel(this);
|
||||
f.setPointSize(bodyFont.first);
|
||||
f.setWeight(bodyFont.second);
|
||||
_lblB1->setFont(f);
|
||||
_lblB1->setText(tr("\n\n• Enter the shortcut code below"));
|
||||
|
||||
auto _lblBKey = new QLabel(this);
|
||||
f.setPointSize(smallFont.first);
|
||||
f.setWeight(smallFont.second);
|
||||
_lblBKey->setFont(f);
|
||||
_lblBKey->setText(tr("Capture Clipboard Shortcut"));
|
||||
|
||||
captureClipboardKeySequence = new SingleStrokeKeySequenceEdit(this);
|
||||
captureClipboardKeySequence->setFixedWidth(120);
|
||||
registerField("keySequence.clipboard*", captureClipboardKeySequence, "keySequence", SIGNAL(keySequenceChanged(const QKeySequence &)));
|
||||
|
||||
auto t2 = new QVBoxLayout();
|
||||
t2->setSpacing(1);
|
||||
t2->addWidget(_lblBKey);
|
||||
t2->addWidget(captureClipboardKeySequence);
|
||||
|
||||
auto layout = new QVBoxLayout();
|
||||
layout->addWidget(_lblTitleLabel);
|
||||
layout->addWidget(_lblSubtitle);
|
||||
layout->addWidget(_lblB1);
|
||||
layout->addSpacerItem(new QSpacerItem(0,60,QSizePolicy::Minimum, QSizePolicy::Fixed));
|
||||
layout->addLayout(t2);
|
||||
layout->addSpacerItem(new QSpacerItem(0,0,QSizePolicy::Minimum, QSizePolicy::Expanding));
|
||||
setLayout(layout);
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
#pragma once
|
||||
|
||||
#include "wizardpage.h"
|
||||
#include <QObject>
|
||||
|
||||
class SingleStrokeKeySequenceEdit;
|
||||
class CaptureClipboardPage : public WizardPage
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
bool validatePage() override;
|
||||
void initializePage() override;
|
||||
void cleanupPage() override;
|
||||
CaptureClipboardPage(QWidget *parent = nullptr);
|
||||
private:
|
||||
SingleStrokeKeySequenceEdit *captureClipboardKeySequence = nullptr;
|
||||
};
|
|
@ -0,0 +1,113 @@
|
|||
#include "capturewindowpage.h"
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QKeySequenceEdit>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
#include <appconfig.h>
|
||||
|
||||
#include "hotkeymanager.h"
|
||||
#include "components/custom_keyseq_edit/singlestrokekeysequenceedit.h"
|
||||
|
||||
bool CaptureWindowPage::validatePage()
|
||||
{
|
||||
if(!field("command.window").isValid())
|
||||
return false;
|
||||
AppConfig::setValue(CONFIG::COMMAND_CAPTUREWINDOW, field("command.window").toString());
|
||||
|
||||
if(!field("keySequence.window").isValid())
|
||||
return false;
|
||||
auto keyCombo = QKeySequence::fromString(field("keySequence.window").toString(), QKeySequence::NativeText);
|
||||
AppConfig::setValue(CONFIG::SHORTCUT_CAPTUREWINDOW, keyCombo.toString(QKeySequence::PortableText));
|
||||
HotkeyManager::updateHotkeys();
|
||||
return true;
|
||||
}
|
||||
|
||||
void CaptureWindowPage::initializePage()
|
||||
{
|
||||
HotkeyManager::unregisterKey(HotkeyManager::ACTION_CAPTURE_WINDOW);
|
||||
QString captureWindowCommand = AppConfig::value(CONFIG::COMMAND_CAPTUREWINDOW);
|
||||
setField("command.window", captureWindowCommand);
|
||||
captureWindowLine->setText(captureWindowCommand);
|
||||
|
||||
QString sequence = AppConfig::value(CONFIG::SHORTCUT_CAPTUREWINDOW);
|
||||
setField("keySequence.window", sequence);
|
||||
captureWindowKeySequence->setKeySequence(QKeySequence::fromString(sequence));
|
||||
}
|
||||
|
||||
void CaptureWindowPage::cleanupPage()
|
||||
{
|
||||
HotkeyManager::updateHotkeys();
|
||||
HotkeyManager::unregisterKey(HotkeyManager::ACTION_CAPTURE_AREA);
|
||||
}
|
||||
|
||||
CaptureWindowPage::CaptureWindowPage(QWidget *parent)
|
||||
: WizardPage{Page_CaptureWindow, parent}
|
||||
{
|
||||
auto f = font();
|
||||
auto _lblTitleLabel = new QLabel(this);
|
||||
f.setPointSize(titleFont.first);
|
||||
f.setWeight(titleFont.second);
|
||||
_lblTitleLabel->setFont(f);
|
||||
_lblTitleLabel->setText(tr("Capture Window"));
|
||||
|
||||
auto _lblSubtitle = new QLabel(this);
|
||||
f.setPointSize(subTitleFont.first);
|
||||
f.setWeight(subTitleFont.second);
|
||||
_lblSubtitle->setFont(f);
|
||||
_lblSubtitle->setWordWrap(true);
|
||||
_lblSubtitle->setText(tr("Set the capture window command and shortcut."));
|
||||
|
||||
auto _lblB1 = new QLabel(this);
|
||||
f.setPointSize(bodyFont.first);
|
||||
f.setWeight(bodyFont.second);
|
||||
_lblB1->setFont(f);
|
||||
_lblB1->setText(tr("<html><br><br>• Enter the command ashirt will use to capture window screenshots<br><br>• Enter a key combination that will trigger the capture window command<html>"));
|
||||
|
||||
auto hLayout = new QHBoxLayout();
|
||||
hLayout->addWidget(_lblB1, 0, Qt::AlignHCenter);
|
||||
|
||||
auto _lblAKey = new QLabel(this);
|
||||
f.setPointSize(smallFont.first);
|
||||
f.setWeight(smallFont.second);
|
||||
_lblAKey->setFont(f);
|
||||
_lblAKey->setText(tr("Capture Window Command"));
|
||||
|
||||
captureWindowLine = new QLineEdit(this);
|
||||
captureWindowLine->setTextMargins(3,0,3,0);
|
||||
registerField("command.window*", captureWindowLine);
|
||||
|
||||
auto t1 = new QVBoxLayout();
|
||||
t1->setSpacing(1);
|
||||
t1->addWidget(_lblAKey);
|
||||
t1->addWidget(captureWindowLine);
|
||||
|
||||
auto _lblBKey = new QLabel(this);
|
||||
f.setPointSize(smallFont.first);
|
||||
f.setWeight(smallFont.second);
|
||||
_lblBKey->setFont(f);
|
||||
_lblBKey->setText(tr("Shortcut"));
|
||||
|
||||
captureWindowKeySequence = new SingleStrokeKeySequenceEdit(this);
|
||||
registerField("keySequence.window*", captureWindowKeySequence, "keySequence", SIGNAL(keySequenceChanged(const QKeySequence &)));
|
||||
|
||||
auto t2 = new QVBoxLayout();
|
||||
t2->setSpacing(1);
|
||||
t2->addWidget(_lblBKey);
|
||||
t2->addWidget(captureWindowKeySequence);
|
||||
|
||||
auto tLayout = new QHBoxLayout();
|
||||
tLayout->addLayout(t1, 8);
|
||||
tLayout->addLayout(t2, 2);
|
||||
|
||||
auto layout = new QVBoxLayout();
|
||||
layout->addWidget(_lblTitleLabel);
|
||||
layout->addWidget(_lblSubtitle);
|
||||
layout->addLayout(hLayout);
|
||||
layout->addSpacerItem(new QSpacerItem(0,60,QSizePolicy::Minimum, QSizePolicy::Fixed));
|
||||
layout->addLayout(tLayout);
|
||||
layout->addSpacerItem(new QSpacerItem(0,0,QSizePolicy::Minimum, QSizePolicy::Expanding));
|
||||
setLayout(layout);
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include "wizardpage.h"
|
||||
#include <QObject>
|
||||
|
||||
class QLineEdit;
|
||||
class SingleStrokeKeySequenceEdit;
|
||||
class CaptureWindowPage : public WizardPage
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
bool validatePage() override;
|
||||
void initializePage() override;
|
||||
void cleanupPage() override;
|
||||
CaptureWindowPage(QWidget *parent = nullptr);
|
||||
private:
|
||||
QLineEdit *captureWindowLine = nullptr;
|
||||
SingleStrokeKeySequenceEdit *captureWindowKeySequence = nullptr;
|
||||
};
|
|
@ -0,0 +1,121 @@
|
|||
#include "evidencepage.h"
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
#include <appconfig.h>
|
||||
|
||||
bool EvidencePage::validatePage()
|
||||
{
|
||||
QDir path = field("eRepo").toString();
|
||||
|
||||
if (!path.exists())
|
||||
path.mkpath(path.absolutePath());
|
||||
|
||||
if(!path.exists()) {
|
||||
errorLabel->setText(tr("can not use selected path"));
|
||||
return false;
|
||||
}
|
||||
AppConfig::setValue(CONFIG::EVIDENCEREPO, path.absolutePath());
|
||||
errorLabel->setText(QString());
|
||||
return true;
|
||||
}
|
||||
|
||||
void EvidencePage::initializePage()
|
||||
{
|
||||
QString repoPath = AppConfig::value(CONFIG::EVIDENCEREPO);
|
||||
setField("eRepo", repoPath);
|
||||
evidenceLine->setText(repoPath);
|
||||
|
||||
if(repoPath.isEmpty())
|
||||
errorLabel->setText(tr("Enter a Path"));
|
||||
QDir repo(repoPath);
|
||||
|
||||
if (!repo.exists()) {
|
||||
repo.mkpath(repo.absolutePath());
|
||||
}
|
||||
|
||||
if(!repo.exists() || !repo.isReadable())
|
||||
errorLabel->setText(tr("Invalid Path"));
|
||||
}
|
||||
|
||||
EvidencePage::EvidencePage(QWidget *parent)
|
||||
: WizardPage{Page_Evidence, parent}
|
||||
{
|
||||
auto f = font();
|
||||
|
||||
auto _lblTitleLabel = new QLabel(this);
|
||||
f.setPointSize(titleFont.first);
|
||||
f.setWeight(titleFont.second);
|
||||
_lblTitleLabel->setFont(f);
|
||||
_lblTitleLabel->setText(tr("Evidence Repository"));
|
||||
|
||||
auto _lblSubtitle = new QLabel(this);
|
||||
f.setPointSize(subTitleFont.first);
|
||||
f.setWeight(subTitleFont.second);
|
||||
_lblSubtitle->setFont(f);
|
||||
_lblSubtitle->setWordWrap(true);
|
||||
_lblSubtitle->setText(tr("This is where evidence is stored and your jumping off point.\n Files will be stored in a subdirectory using the operation name."));
|
||||
|
||||
auto _lblEvidence = new QLabel(this);
|
||||
f.setPointSize(smallFont.first);
|
||||
f.setWeight(smallFont.second);
|
||||
_lblEvidence->setFont(f);
|
||||
_lblEvidence->setText(tr("Evidence Repository:"));
|
||||
|
||||
evidenceLine = new QLineEdit(this);
|
||||
evidenceLine->setTextMargins(3,0,3,0);
|
||||
registerField("eRepo*", evidenceLine);
|
||||
|
||||
auto _btnRepoBrowse = new QPushButton(this);
|
||||
_btnRepoBrowse->setText(tr("Browse"));
|
||||
connect(_btnRepoBrowse, &QPushButton::clicked, this, [this] {
|
||||
QString txt = QFileDialog::getExistingDirectory(this, tr("Select Path to Store Evidence"), evidenceLine->text());
|
||||
if(txt.isEmpty())
|
||||
return;
|
||||
evidenceLine->setText(txt);
|
||||
setField("eRepo", txt);
|
||||
});
|
||||
|
||||
auto _btnReset = new QPushButton(this);
|
||||
_btnReset->setText(tr("Restore Default"));
|
||||
connect(_btnReset, &QPushButton::clicked, this, [this] {
|
||||
evidenceLine->setText(AppConfig::defaultValue(CONFIG::EVIDENCEREPO));
|
||||
setField("eRepo", evidenceLine->text());
|
||||
});
|
||||
|
||||
errorLabel = new QLabel(this);
|
||||
f.setPointSize(smallFont.first);
|
||||
f.setWeight(smallFont.second);
|
||||
errorLabel->setFont(f);
|
||||
|
||||
auto btnLayout = new QHBoxLayout();
|
||||
btnLayout->addWidget(evidenceLine);
|
||||
btnLayout->addWidget(_btnRepoBrowse);
|
||||
btnLayout->addWidget(_btnReset);
|
||||
|
||||
auto t1 = new QVBoxLayout();
|
||||
t1->setSpacing(1);
|
||||
t1->addWidget(_lblEvidence);
|
||||
t1->addLayout(btnLayout);
|
||||
t1->addWidget(errorLabel);
|
||||
|
||||
auto _lblBody = new QLabel(this);
|
||||
f.setPointSize(bodyFont.first);
|
||||
f.setWeight(bodyFont.second);
|
||||
_lblBody->setFont(f);
|
||||
_lblBody->setText(tr("• Browse and input operation filename"));
|
||||
|
||||
auto layout = new QVBoxLayout();
|
||||
layout->addWidget(_lblTitleLabel);
|
||||
layout->addWidget(_lblSubtitle);
|
||||
layout->addSpacerItem(new QSpacerItem(0,30,QSizePolicy::Minimum, QSizePolicy::Fixed));
|
||||
layout->addWidget(_lblBody);
|
||||
layout->addSpacerItem(new QSpacerItem(0,40,QSizePolicy::Minimum, QSizePolicy::Fixed));
|
||||
layout->addLayout(t1);
|
||||
layout->addSpacerItem(new QSpacerItem(0,0,QSizePolicy::Minimum, QSizePolicy::Expanding));
|
||||
setLayout(layout);
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
#pragma once
|
||||
|
||||
#include "wizardpage.h"
|
||||
#include <QObject>
|
||||
|
||||
class QLineEdit;
|
||||
class QLabel;
|
||||
class EvidencePage : public WizardPage
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
bool validatePage() override;
|
||||
void initializePage() override;
|
||||
EvidencePage(QWidget *parent = nullptr);
|
||||
private:
|
||||
QLineEdit * evidenceLine = nullptr;
|
||||
QLabel *errorLabel = nullptr;
|
||||
};
|
|
@ -0,0 +1,70 @@
|
|||
#include "finishedpage.h"
|
||||
|
||||
#include <QDesktopServices>
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
#include <appconfig.h>
|
||||
|
||||
void FinishedPage::initializePage()
|
||||
{
|
||||
auto shortCut = QKeySequence(AppConfig::value(CONFIG::SHORTCUT_CAPTUREWINDOW)).toString(QKeySequence::NativeText);
|
||||
m_lblBody->setText(tr("\n\nYou can now submit evidence Try it now,\n Use %1 to capture the window").arg(shortCut));
|
||||
}
|
||||
|
||||
bool FinishedPage::validatePage()
|
||||
{
|
||||
AppConfig::setValue(CONFIG::SHOW_WELCOME_SCREEN, QStringLiteral("false"));
|
||||
return true;
|
||||
}
|
||||
|
||||
FinishedPage::FinishedPage(QWidget *parent)
|
||||
: WizardPage{Page_Finished, parent}
|
||||
, m_lblBody{new QLabel(this)}
|
||||
{
|
||||
auto f = font();
|
||||
auto _lblTitleLabel = new QLabel(this);
|
||||
f.setPointSize(titleFont.first);
|
||||
f.setWeight(titleFont.second);
|
||||
_lblTitleLabel->setFont(f);
|
||||
_lblTitleLabel->setText(tr("Congratulations!"));
|
||||
|
||||
auto _lblSubtitle = new QLabel(this);
|
||||
f.setPointSize(subTitleFont.first);
|
||||
f.setWeight(subTitleFont.second);
|
||||
_lblSubtitle->setFont(f);
|
||||
_lblSubtitle->setWordWrap(true);
|
||||
_lblSubtitle->setText(tr("You have successfully completed the configuration setup and can continue working within the ashirt application as needed."));
|
||||
|
||||
f.setPointSize(bodyFont.first);
|
||||
f.setWeight(bodyFont.second);
|
||||
f.setItalic(true);
|
||||
m_lblBody->setFont(f);
|
||||
|
||||
auto _lblBody2 = new QLabel(this);
|
||||
f.setPointSize(bodyFont.first);
|
||||
f.setWeight(bodyFont.second);
|
||||
f.setItalic(true);
|
||||
_lblBody2->setFont(f);
|
||||
_lblBody2->setText(tr("\n\nFor more information or support"));
|
||||
|
||||
QString buttonStyle = QStringLiteral("QPushButton:enabled{background-color: rgba(93, 172, 232, 255);font:;color:\"black\";}");
|
||||
auto _faqButton = new QPushButton(this);
|
||||
_faqButton->setText(tr("Click here"));
|
||||
_faqButton->setStyleSheet(buttonStyle);
|
||||
connect(_faqButton, &QPushButton::clicked, this, [this]{
|
||||
QDesktopServices::openUrl(QUrl(QStringLiteral("https://ashirt.io"), QUrl::TolerantMode));
|
||||
});
|
||||
|
||||
auto hLayout = new QHBoxLayout();
|
||||
hLayout->addWidget(_lblBody2, 8, Qt::AlignLeft | Qt::AlignBottom);
|
||||
hLayout->addWidget(_faqButton, 2, Qt::AlignLeft | Qt::AlignBottom);
|
||||
|
||||
auto layout = new QVBoxLayout();
|
||||
layout->addWidget(_lblTitleLabel);
|
||||
layout->addWidget(_lblSubtitle);
|
||||
layout->addWidget(m_lblBody);
|
||||
layout->addLayout(hLayout);
|
||||
layout->addSpacerItem(new QSpacerItem(0,0,QSizePolicy::Minimum, QSizePolicy::Expanding));
|
||||
setLayout(layout);
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
#pragma once
|
||||
|
||||
#include "wizardpage.h"
|
||||
#include <QObject>
|
||||
|
||||
class QLabel;
|
||||
class FinishedPage : public WizardPage
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
void initializePage() override;
|
||||
bool validatePage() override;
|
||||
FinishedPage(QWidget *parent = nullptr);
|
||||
private:
|
||||
QLabel * m_lblBody = nullptr;
|
||||
};
|
|
@ -0,0 +1,44 @@
|
|||
#include "firstTimeWizard.h"
|
||||
|
||||
#include <QDesktopServices>
|
||||
#include <QGridLayout>
|
||||
#include <QKeySequenceEdit>
|
||||
#include <QLabel>
|
||||
#include <QLine>
|
||||
#include <QPainter>
|
||||
#include <QPushButton>
|
||||
#include <releaseinfo.h>
|
||||
#include <appconfig.h>
|
||||
#include <QFileDialog>
|
||||
|
||||
#include "requirementspage.h"
|
||||
#include "evidencepage.h"
|
||||
#include "apikeyspage.h"
|
||||
#include "hostpathpage.h"
|
||||
#include "hosttestpage.h"
|
||||
#include "captureareapage.h"
|
||||
|
||||
#include "capturewindowpage.h"
|
||||
#include "captureclipboardpage.h"
|
||||
#include "opspage.h"
|
||||
#include "finishedpage.h"
|
||||
|
||||
FirstTimeWizard::FirstTimeWizard()
|
||||
{
|
||||
setFixedSize(780, 480);
|
||||
setWizardStyle(ModernStyle);
|
||||
|
||||
setOption(QWizard::NoCancelButton, true);
|
||||
setOption(QWizard::NoDefaultButton, true);
|
||||
setPage(WizardPage::Page_Requiments, new RequirementsPage(this));
|
||||
setPage(WizardPage::Page_Evidence, new EvidencePage(this));
|
||||
setPage(WizardPage::Page_HostPath, new HostPathPage(this));
|
||||
setPage(WizardPage::Page_Api, new ApiKeysPage(this));
|
||||
setPage(WizardPage::Page_HostTest, new HostTestPage(this));
|
||||
setPage(WizardPage::Page_CaptureArea, new CaptureAreaPage(this));
|
||||
setPage(WizardPage::Page_CaptureWindow, new CaptureWindowPage(this));
|
||||
setPage(WizardPage::Page_CaptureClipboard, new CaptureClipboardPage(this));
|
||||
setPage(WizardPage::Page_Ops, new OpsPage(this));
|
||||
setPage(WizardPage::Page_Finished, new FinishedPage(this));
|
||||
setStartId(WizardPage::Page_Requiments);
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
//Settings Wizard Chris Rizzitello 2023
|
||||
#pragma once
|
||||
#include <QWizard>
|
||||
|
||||
class FirstTimeWizard : public QWizard
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
FirstTimeWizard();
|
||||
};
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
#include "hostpathpage.h"
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
#include <appconfig.h>
|
||||
|
||||
bool HostPathPage::validatePage()
|
||||
{
|
||||
return field("host.url").isValid();
|
||||
}
|
||||
|
||||
void HostPathPage::initializePage()
|
||||
{
|
||||
QString hostPath = AppConfig::value(CONFIG::APIURL);
|
||||
setField("host.url", hostPath);
|
||||
hostPathLine->setText(hostPath);
|
||||
}
|
||||
|
||||
HostPathPage::HostPathPage(QWidget *parent)
|
||||
: WizardPage{Page_HostPath, parent}
|
||||
{
|
||||
auto f = font();
|
||||
auto _lblTitleLabel = new QLabel(this);
|
||||
f.setPointSize(titleFont.first);
|
||||
f.setWeight(titleFont.second);
|
||||
_lblTitleLabel->setFont(f);
|
||||
_lblTitleLabel->setText(tr("Server URL"));
|
||||
|
||||
auto _lblSubtitle = new QLabel(this);
|
||||
f.setPointSize(subTitleFont.first);
|
||||
f.setWeight(subTitleFont.second);
|
||||
_lblSubtitle->setFont(f);
|
||||
_lblSubtitle->setWordWrap(true);
|
||||
_lblSubtitle->setText(tr("The URL of the ashirt server. Example below:"));
|
||||
|
||||
auto _lblSubtitle2 = new QLabel(this);
|
||||
f.setPointSize(subTitleFont.first);
|
||||
f.setWeight(subTitleFont.second);
|
||||
f.setItalic(true);
|
||||
_lblSubtitle2->setFont(f);
|
||||
_lblSubtitle2->setWordWrap(true);
|
||||
_lblSubtitle2->setText(tr("http://localhost:8080"));
|
||||
|
||||
auto _lblBody = new QLabel(this);
|
||||
f.setPointSize(bodyFont.first);
|
||||
f.setWeight(bodyFont.second);
|
||||
f.setItalic(false);
|
||||
_lblBody->setFont(f);
|
||||
_lblBody->setWordWrap(true);
|
||||
_lblBody->setText(tr("• Enter the URL that was provided by admin"));
|
||||
|
||||
auto _lblPath = new QLabel(this);
|
||||
f.setPointSize(smallFont.first);
|
||||
f.setWeight(smallFont.second);
|
||||
_lblPath->setFont(f);
|
||||
_lblPath->setText(tr("Server URL:"));
|
||||
|
||||
hostPathLine = new QLineEdit(this);
|
||||
hostPathLine->setTextMargins(3,0,3,0);
|
||||
registerField("host.url*", hostPathLine);
|
||||
|
||||
auto t1 = new QVBoxLayout();
|
||||
t1->setSpacing(1);
|
||||
t1->addWidget(_lblPath);
|
||||
t1->addWidget(hostPathLine);
|
||||
|
||||
auto layout = new QVBoxLayout();
|
||||
layout->addWidget(_lblTitleLabel);
|
||||
layout->addWidget(_lblSubtitle);
|
||||
layout->addWidget(_lblSubtitle2);
|
||||
layout->addSpacerItem(new QSpacerItem(0,30,QSizePolicy::Minimum, QSizePolicy::Fixed));
|
||||
layout->addWidget(_lblBody);
|
||||
layout->addSpacerItem(new QSpacerItem(0,60,QSizePolicy::Minimum, QSizePolicy::Fixed));
|
||||
layout->addLayout(t1);
|
||||
layout->addSpacerItem(new QSpacerItem(0,0,QSizePolicy::Minimum, QSizePolicy::Expanding));
|
||||
|
||||
setLayout(layout);
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
#pragma once
|
||||
|
||||
#include "wizardpage.h"
|
||||
#include <QObject>
|
||||
|
||||
class QLineEdit;
|
||||
class HostPathPage : public WizardPage
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
bool validatePage() override;
|
||||
void initializePage() override;
|
||||
HostPathPage(QWidget *parent = nullptr);
|
||||
private:
|
||||
QLineEdit * hostPathLine = nullptr;
|
||||
};
|
|
@ -0,0 +1,156 @@
|
|||
#include "hosttestpage.h"
|
||||
|
||||
#include <QLabel>
|
||||
#include <QMovie>
|
||||
#include <QPaintEvent>
|
||||
#include <QPainter>
|
||||
#include <QVBoxLayout>
|
||||
#include <QTimer>
|
||||
#include <QNetworkReply>
|
||||
#include <QCheckBox>
|
||||
|
||||
#include "helpers/netman.h"
|
||||
|
||||
HostTestPage::HostTestPage(QWidget *parent)
|
||||
: WizardPage{Page_HostTest, parent}
|
||||
, timer{new QTimer(this)}
|
||||
{
|
||||
setCommitPage(true);
|
||||
timer->setSingleShot(false);
|
||||
|
||||
connect(NetMan::get(), &NetMan::testStatusChanged, this, &HostTestPage::testResultsChanged);
|
||||
|
||||
connect(timer, &QTimer::timeout, this, [this] {
|
||||
f = (f > 359) ? 0 : f+=1;
|
||||
update();
|
||||
});
|
||||
auto f = font();
|
||||
auto _lblTitleLabel = new QLabel(this);
|
||||
f.setPointSize(titleFont.first);
|
||||
f.setWeight(titleFont.second);
|
||||
_lblTitleLabel->setFont(f);
|
||||
_lblTitleLabel->setText(tr("Testing Server Connection"));
|
||||
|
||||
//Hidden Check box to allow us to have a manditory key for going foward
|
||||
auto isReady = new QCheckBox(this);
|
||||
isReady->setVisible(false);
|
||||
registerField("host.accessable*", isReady);
|
||||
|
||||
auto layout = new QVBoxLayout();
|
||||
layout->addWidget(_lblTitleLabel);
|
||||
layout->addSpacerItem(new QSpacerItem(0,300,QSizePolicy::Minimum, QSizePolicy::Expanding));
|
||||
setLayout(layout);
|
||||
}
|
||||
|
||||
bool HostTestPage::validatePage()
|
||||
{
|
||||
if(!field("host.accessable").toBool())
|
||||
return false;
|
||||
|
||||
AppConfig::setValue(CONFIG::ACCESSKEY, field("host.accessKey").toString());
|
||||
AppConfig::setValue(CONFIG::SECRETKEY, field("host.secretKey").toString());
|
||||
AppConfig::setValue(CONFIG::APIURL, field("host.url").toString());
|
||||
return true;
|
||||
}
|
||||
|
||||
void HostTestPage::initializePage()
|
||||
{
|
||||
f=0;
|
||||
setField("host.accessable", false);
|
||||
connect(wizard(), &QWizard::currentIdChanged, this, &HostTestPage::timerCheck, Qt::UniqueConnection);
|
||||
NetMan::testConnection(field("host.url").toString(), field("host.accessKey").toString(), field("host.secretKey").toString());
|
||||
}
|
||||
|
||||
void HostTestPage::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
WizardPage::paintEvent(event);
|
||||
QPixmap tmp(250,250);
|
||||
QPainter p(&tmp);
|
||||
|
||||
p.fillRect(tmp.rect(), palette().base());
|
||||
p.setRenderHint(QPainter::Antialiasing, true);
|
||||
p.setRenderHint(QPainter::TextAntialiasing, true);
|
||||
p.setPen(QPen(palette().text().color(), 8));
|
||||
p.drawEllipse(25, 25, 200, 200);
|
||||
|
||||
if ( currentState == NetMan::INPROGRESS) {
|
||||
p.translate(125, 125);
|
||||
p.rotate(f);
|
||||
p.translate(-125, -125);
|
||||
p.setBrush(QBrush( isDarkMode() ? QColor(0x6B,0x7F,0x8B) : QColor(0x5B,0x6C,0x76)));
|
||||
p.drawEllipse(113, 13, 24,24);
|
||||
}
|
||||
p.end();
|
||||
|
||||
QRect drawArea (154,88,250,250);
|
||||
QRect errorArea (0, 351, 555, 48);
|
||||
|
||||
static QFont errorFont = QFont("Helvetica Neue", 16, QFont::Normal);
|
||||
errorFont.setStyleStrategy(QFont::StyleStrategy(QFont::PreferQuality | QFont::PreferAntialias));
|
||||
|
||||
static QFont statusFont = QFont("Helvetica Neue", 24, QFont::Normal);
|
||||
statusFont.setStyleStrategy(QFont::StyleStrategy(QFont::PreferQuality | QFont::PreferAntialias));
|
||||
|
||||
static QFont checkFont = QFont("Helvetica Neue", 42, QFont::ExtraBold);
|
||||
checkFont.setStyleStrategy(QFont::StyleStrategy(QFont::PreferQuality | QFont::NoSubpixelAntialias));
|
||||
|
||||
QPainter t (this);
|
||||
t.setRenderHint(QPainter::TextAntialiasing, true);
|
||||
t.setRenderHint(QPainter::Antialiasing, true);
|
||||
|
||||
t.drawPixmap(drawArea, tmp);
|
||||
|
||||
QTextOption textOptions;
|
||||
textOptions.setAlignment(Qt::AlignCenter);
|
||||
|
||||
t.setFont(errorFont);
|
||||
t.drawText(errorArea, NetMan::lastTestError(), textOptions);
|
||||
|
||||
t.translate(154, 88);
|
||||
QRect iconArea (91, 50, 72, 72);
|
||||
QRect labelArea (55,130,140,48);
|
||||
QRect testLabelArea(55,100,140,48);
|
||||
|
||||
t.setPen(palette().text().color());
|
||||
switch (currentState) {
|
||||
case NetMan::INPROGRESS:
|
||||
t.setFont(statusFont);
|
||||
t.drawText(testLabelArea, "Testing", textOptions);
|
||||
break;
|
||||
case NetMan::SUCCESS:
|
||||
t.setFont(checkFont);
|
||||
t.drawText(iconArea, QStringLiteral("✓"), textOptions);
|
||||
t.setFont(statusFont);
|
||||
t.drawText(labelArea, "Success!", textOptions) ;
|
||||
break;
|
||||
default:
|
||||
t.setFont(checkFont);
|
||||
t.drawText(iconArea, QStringLiteral("X"), textOptions);
|
||||
t.setFont(statusFont);
|
||||
t.drawText(labelArea, "Failed", textOptions);
|
||||
break;
|
||||
};
|
||||
t.end();
|
||||
|
||||
}
|
||||
|
||||
void HostTestPage::testResultsChanged(int result)
|
||||
{
|
||||
currentState = result;
|
||||
timerCheck();
|
||||
setField("host.accessable", (currentState == NetMan::SUCCESS));
|
||||
update();
|
||||
}
|
||||
|
||||
void HostTestPage::timerCheck()
|
||||
{
|
||||
if(wizard()->currentId() == id()) {
|
||||
f=0;
|
||||
if (currentState == NetMan::INPROGRESS)
|
||||
timer->start(33);
|
||||
else
|
||||
timer->stop();
|
||||
}
|
||||
else
|
||||
timer->stop();
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
|
||||
#include "wizardpage.h"
|
||||
#include <QObject>
|
||||
|
||||
class QLabel;
|
||||
class QNetworkReply;
|
||||
class HostTestPage : public WizardPage
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
HostTestPage(QWidget *parent = nullptr);
|
||||
protected:
|
||||
bool validatePage() override;
|
||||
void initializePage() override;
|
||||
void paintEvent(QPaintEvent*) override;
|
||||
private:
|
||||
void testResultsChanged(int result);
|
||||
void timerCheck();
|
||||
int f=0;
|
||||
QTimer *timer = nullptr;
|
||||
QNetworkReply *currentTestReply = nullptr;
|
||||
int currentState;
|
||||
};
|
|
@ -0,0 +1,148 @@
|
|||
#include "opspage.h"
|
||||
|
||||
#include <QNetworkReply>
|
||||
#include <QComboBox>
|
||||
#include <QFileDialog>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
#include <appconfig.h>
|
||||
|
||||
#include "helpers/netman.h"
|
||||
|
||||
#include <dtos/ashirt_error.h>
|
||||
|
||||
bool OpsPage::validatePage()
|
||||
{
|
||||
if (!field("ops").isValid())
|
||||
return false;
|
||||
|
||||
QString slug = opsCombo->currentData().toString();
|
||||
QString name = opsCombo->currentText();
|
||||
|
||||
if(!_OpsList.contains(name)) {
|
||||
slug = name.toLower().replace(invalidCharsRegex, QStringLiteral("-")).replace(startOrEndDash, QString());
|
||||
createOpReply = NetMan::createOperation(name, slug);
|
||||
connect(createOpReply, &QNetworkReply::finished, this, &OpsPage::createOpComplete);
|
||||
return successful;
|
||||
}
|
||||
AppConfig::setOperationDetails(slug, name);
|
||||
return true;
|
||||
}
|
||||
|
||||
void OpsPage::initializePage()
|
||||
{
|
||||
NetMan::refreshOperationsList();
|
||||
int v = opsCombo->findText(AppConfig::operationName());
|
||||
setField("ops", v);
|
||||
opsCombo->setCurrentIndex(v);
|
||||
}
|
||||
|
||||
OpsPage::OpsPage(QWidget *parent)
|
||||
: WizardPage{Page_Ops, parent}
|
||||
{
|
||||
connect(NetMan::get(), &NetMan::operationListUpdated, this, &OpsPage::operationsUpdated);
|
||||
auto f = font();
|
||||
|
||||
auto _lblTitleLabel = new QLabel(this);
|
||||
f.setPointSize(titleFont.first);
|
||||
f.setWeight(titleFont.second);
|
||||
_lblTitleLabel->setFont(f);
|
||||
_lblTitleLabel->setText(tr("Select or Create Operation"));
|
||||
|
||||
auto _lblSubtitle = new QLabel(this);
|
||||
f.setPointSize(subTitleFont.first);
|
||||
f.setWeight(subTitleFont.second);
|
||||
_lblSubtitle->setFont(f);
|
||||
_lblSubtitle->setWordWrap(true);
|
||||
_lblSubtitle->setText(tr("Select the desired operation below. If none exist you can create a new one."));
|
||||
|
||||
auto _lblBody = new QLabel(this);
|
||||
f.setPointSize(bodyFont.first);
|
||||
f.setWeight(bodyFont.second);
|
||||
_lblBody->setFont(f);
|
||||
_lblBody->setWordWrap(true);
|
||||
_lblBody->setText(tr("• Select the desired operation below. If none exist you can create a new one."));
|
||||
|
||||
auto _lblBody2 = new QLabel(this);
|
||||
f.setPointSize(bodyFont.first);
|
||||
f.setWeight(bodyFont.second);
|
||||
_lblBody2->setFont(f);
|
||||
_lblBody2->setWordWrap(true);
|
||||
_lblBody2->setText(tr("• The user that creates an operation automatically becomes the admin, and can assign access to additional users in the ashirt server."));
|
||||
|
||||
auto _lblEvidence = new QLabel(this);
|
||||
f.setPointSize(smallFont.first);
|
||||
f.setWeight(smallFont.second);
|
||||
_lblEvidence->setFont(f);
|
||||
_lblEvidence->setText(tr("Operation Name:"));
|
||||
|
||||
opsCombo = new QComboBox(this);
|
||||
registerField("ops", opsCombo);
|
||||
|
||||
responseLabel = new QLabel(this);
|
||||
f.setPointSize(smallFont.first);
|
||||
f.setWeight(smallFont.second);
|
||||
responseLabel->setFont(f);
|
||||
|
||||
auto t1 = new QVBoxLayout();
|
||||
t1->setSpacing(1);
|
||||
t1->addWidget(_lblEvidence);
|
||||
t1->addWidget(opsCombo);
|
||||
t1->addWidget(responseLabel);
|
||||
|
||||
auto topLayout = new QVBoxLayout();
|
||||
topLayout->addWidget(_lblTitleLabel);
|
||||
topLayout->addWidget(_lblSubtitle);
|
||||
topLayout->addSpacerItem(new QSpacerItem(0,20,QSizePolicy::Minimum, QSizePolicy::Fixed));
|
||||
topLayout->addWidget(_lblBody);
|
||||
topLayout->addSpacerItem(new QSpacerItem(0,10,QSizePolicy::Minimum, QSizePolicy::Fixed));
|
||||
topLayout->addWidget(_lblBody2);
|
||||
topLayout->addSpacerItem(new QSpacerItem(0,50,QSizePolicy::Minimum, QSizePolicy::Fixed));
|
||||
topLayout->addLayout(t1);
|
||||
topLayout->addSpacerItem(new QSpacerItem(0,0,QSizePolicy::Minimum, QSizePolicy::Expanding));
|
||||
setLayout(topLayout);
|
||||
}
|
||||
|
||||
void OpsPage::operationsUpdated(bool success, const QList<dto::Operation> & operations)
|
||||
{
|
||||
if (!success)
|
||||
return;
|
||||
|
||||
opsCombo->clear();
|
||||
opsCombo->setEditable(true);
|
||||
_OpsList.clear();
|
||||
for (const auto& op : operations) {
|
||||
_OpsList.insert(op.name, op.slug);
|
||||
opsCombo->addItem(op.name, op.slug);
|
||||
}
|
||||
int v = opsCombo->findText(AppConfig::operationName());
|
||||
setField("ops", v);
|
||||
opsCombo->setCurrentIndex(v);
|
||||
}
|
||||
|
||||
void OpsPage::createOpComplete()
|
||||
{
|
||||
bool isValid;
|
||||
auto data = NetMan::extractResponse(createOpReply, isValid);
|
||||
if (isValid) {
|
||||
dto::Operation op = dto::Operation::parseData(data);
|
||||
AppConfig::setOperationDetails(op.slug, op.name);
|
||||
NetMan::refreshOperationsList();
|
||||
cleanUpReply(&createOpReply);
|
||||
successful = true;
|
||||
wizard()->next();
|
||||
} else {
|
||||
setField("ops", -1);
|
||||
successful = false;
|
||||
cleanUpReply(&createOpReply);
|
||||
dto::AShirtError err = dto::AShirtError::parseData(data);
|
||||
if (err.error.contains(QStringLiteral("slug already exists"))) {
|
||||
responseLabel->setText(tr("A similar operation name already exists. Please try a new name."));
|
||||
}
|
||||
else {
|
||||
responseLabel->setText(tr("Got an unexpected error: %1").arg(err.error));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
#pragma once
|
||||
|
||||
#include "wizardpage.h"
|
||||
#include <QObject>
|
||||
|
||||
#include "dtos/operation.h"
|
||||
|
||||
class QNetworkReply;
|
||||
class QLabel;
|
||||
class QComboBox;
|
||||
class OpsPage : public WizardPage
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
bool validatePage() override;
|
||||
void initializePage() override;
|
||||
OpsPage(QWidget *parent = nullptr);
|
||||
private:
|
||||
void operationsUpdated(bool success, const QList<dto::Operation> & operations);
|
||||
void createOpComplete();
|
||||
QLabel *responseLabel = nullptr;
|
||||
QComboBox *opsCombo = nullptr;
|
||||
QNetworkReply* createOpReply = nullptr;
|
||||
QMap<QString, QString> _OpsList;
|
||||
inline static const QRegularExpression invalidCharsRegex = QRegularExpression(QStringLiteral("[^A-Za-z0-9]+"));
|
||||
inline static const QRegularExpression startOrEndDash = QRegularExpression(QStringLiteral("^-|-$"));
|
||||
bool successful= false;
|
||||
};
|
|
@ -0,0 +1,36 @@
|
|||
#include "requirementspage.h"
|
||||
|
||||
#include <QLabel>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
RequirementsPage::RequirementsPage(QWidget *parent)
|
||||
: WizardPage{Page_Requiments, parent}
|
||||
{
|
||||
auto f = font();
|
||||
|
||||
auto _lblTitleLabel = new QLabel(this);
|
||||
f.setPointSize(titleFont.first);
|
||||
f.setWeight(titleFont.second);
|
||||
_lblTitleLabel->setFont(f);
|
||||
_lblTitleLabel->setText(tr("Requirements"));
|
||||
|
||||
auto _lblSubtitle = new QLabel(this);
|
||||
f.setPointSize(subTitleFont.first);
|
||||
f.setWeight(subTitleFont.second);
|
||||
_lblSubtitle->setFont(f);
|
||||
_lblSubtitle->setWordWrap(true);
|
||||
_lblSubtitle->setText(tr("To get started, make sure you have acquired the following information from your admin:"));
|
||||
|
||||
auto _lblBody = new QLabel(this);
|
||||
f.setPointSize(bodyFont.first);
|
||||
f.setWeight(bodyFont.second);
|
||||
_lblBody->setFont(f);
|
||||
_lblBody->setText(tr("\n\n\n\t• URL for the ashirt server\n\n\t• Login method"));
|
||||
|
||||
auto topLayout = new QVBoxLayout();
|
||||
topLayout->addWidget(_lblTitleLabel);
|
||||
topLayout->addWidget(_lblSubtitle);
|
||||
topLayout->addWidget(_lblBody);
|
||||
topLayout->addSpacerItem(new QSpacerItem(0,0,QSizePolicy::Minimum, QSizePolicy::Expanding));
|
||||
setLayout(topLayout);
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
#pragma once
|
||||
|
||||
#include "wizardpage.h"
|
||||
#include <QObject>
|
||||
|
||||
class RequirementsPage : public WizardPage
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
RequirementsPage(QWidget *parent = nullptr);
|
||||
};
|
|
@ -0,0 +1,163 @@
|
|||
#include "welcomepage.h"
|
||||
#include <QCheckBox>
|
||||
#include <QDesktopServices>
|
||||
#include <QGridLayout>
|
||||
#include <QLabel>
|
||||
#include <QLine>
|
||||
#include <QPainter>
|
||||
#include <QPushButton>
|
||||
#include <releaseinfo.h>
|
||||
#include <appconfig.h>
|
||||
|
||||
WelcomePage::WelcomePage(QWidget *parent)
|
||||
: AShirtDialog{parent}
|
||||
, m_sideGrad{QLinearGradient(0,0, m_side_w, m_side_h)}
|
||||
|
||||
{
|
||||
m_sideGrad.setColorAt(0, QColor(0x2E, 0x33, 0x37));
|
||||
m_sideGrad.setColorAt(1, QColor(0x1D, 0x20, 0x24));
|
||||
setFixedSize(780, 468);
|
||||
QString buttonStyle = QStringLiteral("QPushButton:enabled{\
|
||||
background-color: rgba(93, 172, 232, 255);\
|
||||
font:;color:\"black\";}");
|
||||
|
||||
auto f = font();
|
||||
|
||||
auto _lblTitleLabel = new QLabel(this);
|
||||
f.setPointSize(m_titleFontSize);
|
||||
f.setBold(true);
|
||||
_lblTitleLabel->setFont(f);
|
||||
_lblTitleLabel->setText(tr("Welcome!"));
|
||||
|
||||
auto _lblSubtitle = new QLabel(this);
|
||||
f.setPointSize(m_subTitleFontSize);
|
||||
f.setBold(false);
|
||||
_lblSubtitle->setFont(f);
|
||||
_lblSubtitle->setText(tr("Click on the Ashirt tray icon to begin"));
|
||||
|
||||
auto topLayout = new QVBoxLayout();
|
||||
topLayout->addWidget(_lblTitleLabel);
|
||||
topLayout->addWidget(_lblSubtitle);
|
||||
auto tGrid = new QGridLayout();
|
||||
tGrid->setContentsMargins(215, 20, 20, 20);
|
||||
tGrid->addLayout(topLayout, 0, 0, 6, 5);
|
||||
tGrid->setVerticalSpacing(15);
|
||||
|
||||
auto startSetup = new QPushButton(this);
|
||||
startSetup->setStyleSheet(buttonStyle);
|
||||
startSetup->setText(tr("Start Setup"));
|
||||
connect(startSetup, &QPushButton::clicked, this, [this]{
|
||||
close();
|
||||
Q_EMIT requestSetupWizard();
|
||||
});
|
||||
|
||||
auto _lblTopLabel = new QLabel(this);
|
||||
f.setPointSize(m_h3FontSize);
|
||||
f.setBold(true);
|
||||
_lblTopLabel->setFont(f);
|
||||
_lblTopLabel->setText(tr("New Users"));
|
||||
|
||||
auto _lblTopBody = new QLabel(this);
|
||||
f.setPointSize(m_bodyFontSize);
|
||||
f.setBold(false);
|
||||
_lblTopBody->setFont(f);
|
||||
_lblTopBody->setText(tr("On your first launch, you must setup an appropriate\nconfiguration with our setup wizard."));
|
||||
auto line = new QFrame(this);
|
||||
line->setFrameStyle(QFrame::HLine);
|
||||
|
||||
tGrid->addWidget(_lblTopLabel, 7, 0, 2, 5, Qt::AlignLeft | Qt::AlignTop);
|
||||
tGrid->addWidget(_lblTopBody, 8, 0, 4, 4, Qt::AlignLeft | Qt::AlignBottom);
|
||||
tGrid->addWidget(startSetup, 8, 5, 6, 1, Qt::AlignVCenter);
|
||||
tGrid->addWidget(line ,12 , 0, 1, 6, Qt::AlignVCenter);
|
||||
|
||||
auto _lblMidLabel = new QLabel(this);
|
||||
f.setPointSize(m_h3FontSize);
|
||||
f.setBold(true);
|
||||
_lblMidLabel->setFont(f);
|
||||
_lblMidLabel->setText(tr("Explore the Server"));
|
||||
|
||||
auto _lblMidBody = new QLabel(this);
|
||||
f.setPointSize(m_bodyFontSize);
|
||||
f.setBold(false);
|
||||
_lblMidBody->setFont(f);
|
||||
_lblMidBody->setText(tr("This is our frontend web toolkit that allows ease of use with\ntesting operations and viewing evience."));
|
||||
auto viewServer = new QPushButton(this);
|
||||
viewServer->setStyleSheet(buttonStyle);
|
||||
connect(viewServer, &QPushButton::clicked, this, [this] {
|
||||
QDesktopServices::openUrl(QUrl(QStringLiteral("https://github.com/ashirt-ops/ashirt-server"), QUrl::TolerantMode));
|
||||
});
|
||||
viewServer->setText(tr("Download"));
|
||||
|
||||
auto line2 = new QFrame(this);
|
||||
line2->setFrameStyle(QFrame::HLine);
|
||||
|
||||
tGrid->addWidget(_lblMidLabel, 13, 0, 2, 5, Qt::AlignLeft | Qt::AlignTop);
|
||||
tGrid->addWidget(_lblMidBody, 14, 0, 4, 4, Qt::AlignLeft | Qt::AlignBottom);
|
||||
tGrid->addWidget(viewServer, 14, 5, 6, 1, Qt::AlignVCenter);
|
||||
tGrid->addWidget(line2 ,18 , 0, 1, 6, Qt::AlignVCenter);
|
||||
|
||||
auto _lblBottomLabel = new QLabel(this);
|
||||
f.setPointSize(m_h3FontSize);
|
||||
f.setBold(true);
|
||||
_lblBottomLabel->setFont(f);
|
||||
_lblBottomLabel->setText(tr("Quick Docs"));
|
||||
|
||||
auto _lblBottomBody = new QLabel(this);
|
||||
f.setPointSize(m_bodyFontSize);
|
||||
f.setBold(false);
|
||||
_lblBottomBody->setFont(f);
|
||||
_lblBottomBody->setText(tr("For more information about ashirt, support and access to\ndocumentation or common user questions."));
|
||||
auto learnMore = new QPushButton(this);
|
||||
learnMore->setStyleSheet(buttonStyle);
|
||||
connect(learnMore, &QPushButton::clicked, this, [this] {
|
||||
QDesktopServices::openUrl(QUrl(QStringLiteral("https://ashirt.io"), QUrl::TolerantMode));
|
||||
});
|
||||
learnMore->setText(tr("Learn More"));
|
||||
|
||||
tGrid->addWidget(_lblBottomLabel, 19, 0, 2, 5, Qt::AlignLeft | Qt::AlignTop);
|
||||
tGrid->addWidget(_lblBottomBody, 20, 0, 4, 4, Qt::AlignLeft | Qt::AlignBottom);
|
||||
tGrid->addWidget(learnMore, 20, 5, 6, 1, Qt::AlignVCenter);
|
||||
|
||||
auto hide = new QCheckBox("Do Not show when starting", this);
|
||||
hide->setChecked(AppConfig::value(CONFIG::SHOW_WELCOME_SCREEN) != "true");
|
||||
connect(hide,&QCheckBox::stateChanged, this, [hide, this] (int newState) {
|
||||
if(newState != Qt::Checked)
|
||||
AppConfig::setValue(CONFIG::SHOW_WELCOME_SCREEN, "true");
|
||||
else
|
||||
AppConfig::setValue(CONFIG::SHOW_WELCOME_SCREEN, "false");
|
||||
});
|
||||
tGrid->addWidget(hide, 25, 0, 2, 6);
|
||||
|
||||
setLayout(tGrid);
|
||||
}
|
||||
|
||||
void WelcomePage::paintEvent(QPaintEvent *)
|
||||
{
|
||||
static QFont titleFont = QFont("Helvetica Neue", m_sideLargeFont, QFont::ExtraBold, false);
|
||||
titleFont.setStyleHint(QFont::Helvetica, QFont::StyleStrategy(QFont::PreferQuality | QFont::PreferAntialias));
|
||||
|
||||
static QFont subFont = QFont("Helvetica Neue", m_sideSmallFont, QFont::Light, true);
|
||||
subFont.setStyleHint(QFont::Helvetica, QFont::StyleStrategy(QFont::PreferQuality | QFont::PreferAntialias));
|
||||
|
||||
static QFont versionFont = QFont("Helvetica Neue", m_sideSmallFont, QFont::ExtraLight, false);
|
||||
versionFont.setStyleHint(QFont::Helvetica, QFont::StyleStrategy(QFont::PreferQuality | QFont::PreferAntialias));
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
subFont.setWeight(QFont::Normal);
|
||||
versionFont.setWeight(QFont::Light);
|
||||
#endif
|
||||
|
||||
QPainter painter(this);
|
||||
painter.setRenderHint(QPainter::Antialiasing, true);
|
||||
painter.setRenderHint(QPainter::TextAntialiasing, true);
|
||||
painter.fillRect(0,0, 200, height(), m_sideGrad);
|
||||
painter.drawPixmap(QRect(50, 135, 100, 100), QStringLiteral(":/icons/shirt-light.svg"));
|
||||
painter.setPen(QColor(0xF5,0xFB,0xFF));
|
||||
painter.setFont(titleFont);
|
||||
painter.drawText(QRect(0, 227, 200, 251), QStringLiteral("ASHIRT"), QTextOption(Qt::AlignHCenter));
|
||||
painter.setFont(subFont);
|
||||
painter.drawText(QRect(25, 275, 175, 350), QStringLiteral("Adversary Simulators High-Fedelity Intelligence and Reporting Toolkit"));
|
||||
painter.setFont(versionFont);
|
||||
painter.drawText(QRect(0, 445, 200, 455), QStringLiteral("Version %1").arg(ReleaseInfo::version), QTextOption(Qt::AlignHCenter));
|
||||
painter.end();
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
#pragma once
|
||||
#include <QWidget>
|
||||
#include "ashirtdialog/ashirtdialog.h"
|
||||
|
||||
class WelcomePage : public AShirtDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit WelcomePage(QWidget *parent = nullptr);
|
||||
|
||||
signals:
|
||||
void requestSetupWizard();
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *);
|
||||
private:
|
||||
const int m_side_w = 200;
|
||||
const int m_side_h = 468;
|
||||
QLinearGradient m_sideGrad;
|
||||
#ifdef Q_OS_MAC
|
||||
const int m_titleFontSize = 28;
|
||||
const int m_subTitleFontSize = 20;
|
||||
const int m_h3FontSize = 18;
|
||||
const int m_bodyFontSize = 14;
|
||||
const int m_sideLargeFont = 28;
|
||||
const int m_sideSmallFont = 12;
|
||||
|
||||
#else
|
||||
const int m_titleFontSize = 22;
|
||||
const int m_subTitleFontSize = 16;
|
||||
const int m_h3FontSize = 14;
|
||||
const int m_bodyFontSize = 10;
|
||||
const int m_sideLargeFont = 26;
|
||||
const int m_sideSmallFont = 10;
|
||||
#endif
|
||||
};
|
|
@ -0,0 +1,253 @@
|
|||
#include "wizardpage.h"
|
||||
#include <QPen>
|
||||
#include <QPainter>
|
||||
#include <QEvent>
|
||||
#include "system_helpers.h"
|
||||
|
||||
WizardPage::WizardPage(int pageId, QWidget *parent)
|
||||
: QWizardPage{parent}
|
||||
, m_id(pageId)
|
||||
, m_sideGrad{QLinearGradient(0,0, m_side_w, m_side_h)}
|
||||
{
|
||||
m_sideGrad.setColorAt(0, QColor(0x2E, 0x33, 0x37));
|
||||
m_sideGrad.setColorAt(1, QColor(0x1D, 0x20, 0x24));
|
||||
|
||||
setPixmap(QWizard::WatermarkPixmap, paintSideImage(m_id));
|
||||
setStyleSheet(isDarkMode() ? _darkStyle : _lightStyle);
|
||||
}
|
||||
|
||||
void WizardPage::changeEvent(QEvent *event)
|
||||
{
|
||||
if (event->type() == QEvent::PaletteChange) {
|
||||
setStyleSheet(isDarkMode() ? _darkStyle : _lightStyle);
|
||||
setPixmap(QWizard::WatermarkPixmap, paintSideImage(m_id));
|
||||
event->accept();
|
||||
return;
|
||||
}
|
||||
event->ignore();
|
||||
}
|
||||
|
||||
bool WizardPage::isDarkMode()
|
||||
{
|
||||
return !SystemHelpers::isLightTheme();
|
||||
}
|
||||
|
||||
QPixmap WizardPage::paintSideImage(int pageId)
|
||||
{
|
||||
QPen inactiveBubbleOutline = QPen(QColor(0x2D, 0x31, 0x35), 1);
|
||||
QColor highlightedStep = QColor(0x79, 0xC5, 0xFF);
|
||||
QString checkMark = QStringLiteral("✓");
|
||||
|
||||
QPixmap sideImage(m_side_w + 20, m_side_h);
|
||||
QPainter painter;
|
||||
|
||||
painter.begin(&sideImage);
|
||||
|
||||
painter.setRenderHint(QPainter::Antialiasing, true);
|
||||
painter.setRenderHint(QPainter::TextAntialiasing, true);
|
||||
painter.setRenderHint(QPainter::SmoothPixmapTransform, true);
|
||||
|
||||
QString fontFamily = "Helvetica Neue";
|
||||
#ifdef Q_OS_LINUX
|
||||
int sideFontSize = 14;
|
||||
#elif defined Q_OS_WIN
|
||||
int sideFontSize = 16;
|
||||
#elif defined Q_OS_MAC
|
||||
int sideFontSize = 22;
|
||||
#endif
|
||||
|
||||
static QFont currentItemFont = QFont(fontFamily, sideFontSize, QFont::ExtraBold);
|
||||
currentItemFont.setStyleHint(QFont::Helvetica, QFont::StyleStrategy(QFont::PreferQuality | QFont::PreferAntialias));
|
||||
|
||||
static QFont nonCurrentItemFont = QFont(fontFamily, sideFontSize, QFont::Light);
|
||||
nonCurrentItemFont.setStyleHint(QFont::Helvetica, QFont::StyleStrategy(QFont::PreferQuality | QFont::PreferAntialias));
|
||||
|
||||
static QFont bubbleTextFont = QFont(fontFamily, sideFontSize, QFont::Normal);
|
||||
bubbleTextFont.setStyleHint(QFont::Helvetica, QFont::StyleStrategy(QFont::PreferQuality | QFont::PreferAntialias));
|
||||
|
||||
static QFont bubbleCheckFont = QFont(fontFamily, sideFontSize, QFont::Normal);
|
||||
bubbleCheckFont.setStyleHint(QFont::Helvetica, QFont::StyleStrategy(QFont::PreferQuality | QFont::NoSubpixelAntialias));
|
||||
|
||||
static QFont stepsFont = QFont(fontFamily, smallFont.first, smallFont.second);
|
||||
stepsFont.setStyleHint(QFont::Helvetica, QFont::StyleStrategy(QFont::PreferQuality | QFont::PreferAntialias));
|
||||
|
||||
QColor inactiveBubbleColor = QColor(0x2D, 0x32, 0x36);
|
||||
QString _textTemp;
|
||||
//Background
|
||||
painter.fillRect(0,0, sideImage.width() - 20, sideImage.height(), m_sideGrad);
|
||||
painter.fillRect(m_side_w, 0 , 20, m_side_h, QBrush(palette().base().color()));
|
||||
|
||||
if(pageId == Page_Requiments) {
|
||||
painter.setFont(currentItemFont);
|
||||
painter.setPen(highlightedStep);
|
||||
painter.setBrush(highlightedStep);
|
||||
} else {
|
||||
painter.setFont(nonCurrentItemFont);
|
||||
painter.setPen(QPen(Qt::white));
|
||||
painter.setBrush(inactiveBubbleColor);
|
||||
}
|
||||
|
||||
painter.drawText(QRect(6, 30, 165, 32), Qt::AlignRight | Qt::AlignVCenter, QStringLiteral("Requirements"));
|
||||
|
||||
painter.setPen(inactiveBubbleOutline);
|
||||
painter.drawEllipse(184, 30,32,32);
|
||||
|
||||
painter.setPen(Qt::white);
|
||||
if(pageId == Page_Requiments) {
|
||||
painter.setFont(bubbleTextFont);
|
||||
_textTemp = QStringLiteral("1");
|
||||
} else {
|
||||
painter.setFont(bubbleCheckFont);
|
||||
_textTemp = checkMark;
|
||||
}
|
||||
painter.drawText(QRect(184, 30,32,32), Qt::AlignCenter, _textTemp);
|
||||
|
||||
if(pageId == Page_Evidence) {
|
||||
painter.setFont(currentItemFont);
|
||||
painter.setPen(highlightedStep);
|
||||
painter.setBrush(highlightedStep);
|
||||
} else {
|
||||
painter.setFont(nonCurrentItemFont);
|
||||
painter.setPen(Qt::white);
|
||||
painter.setBrush(inactiveBubbleColor);
|
||||
}
|
||||
|
||||
painter.drawText(QRect(6,117,165,32), Qt::AlignRight | Qt::AlignVCenter, QStringLiteral("Evidence Path"));
|
||||
painter.setPen(inactiveBubbleOutline);
|
||||
painter.drawEllipse(184,117,32,32);
|
||||
|
||||
painter.setPen(Qt::white);
|
||||
if(pageId < Page_HostPath) {
|
||||
painter.setFont(bubbleTextFont);
|
||||
_textTemp = QStringLiteral("2");
|
||||
} else {
|
||||
painter.setFont(bubbleCheckFont);
|
||||
_textTemp = checkMark;
|
||||
}
|
||||
painter.drawText(QRect(184, 117, 32,32), Qt::AlignCenter, _textTemp);
|
||||
|
||||
if(pageId >= Page_HostPath && pageId < Page_CaptureArea) {
|
||||
painter.setFont(currentItemFont);
|
||||
painter.setPen(highlightedStep);
|
||||
painter.setBrush(highlightedStep);
|
||||
} else {
|
||||
painter.setFont(nonCurrentItemFont);
|
||||
painter.setPen(Qt::white);
|
||||
painter.setBrush(inactiveBubbleColor);
|
||||
}
|
||||
|
||||
painter.drawText(QRect(6, 204, 165, 32), Qt::AlignRight | Qt::AlignVCenter, QStringLiteral("Server Settings"));
|
||||
painter.setPen(inactiveBubbleOutline);
|
||||
|
||||
if(pageId == Page_HostPath) {
|
||||
painter.setBrush(highlightedStep);
|
||||
painter.drawPie(184,204,32,32, 90*16, -120*16);
|
||||
painter.setBrush(inactiveBubbleColor);
|
||||
painter.drawPie(184,204, 32,32, 90*16, 240*16);
|
||||
painter.setPen(Qt::white);
|
||||
painter.setFont(stepsFont);
|
||||
painter.drawText(QRect(0,229,200,16), Qt::AlignHCenter | Qt::AlignVCenter, QStringLiteral("Step 1 of 3"));
|
||||
} else if(pageId == Page_Api) {
|
||||
painter.setBrush(highlightedStep);
|
||||
painter.drawPie(184,204,32,32, 90*16, -240*16);
|
||||
painter.setBrush(inactiveBubbleColor);
|
||||
painter.drawPie(184,204,32,32, 90*16, 120*16);
|
||||
painter.setPen(Qt::white);
|
||||
painter.setFont(stepsFont);
|
||||
painter.drawText(QRect(0,229,200,16), Qt::AlignHCenter | Qt::AlignVCenter, QStringLiteral("Step 2 of 3"));
|
||||
} else if(pageId == Page_HostTest) {
|
||||
painter.drawEllipse(184,204,32,32);
|
||||
painter.setPen(Qt::white);
|
||||
painter.setFont(stepsFont);
|
||||
painter.drawText(QRect(0,229,200,16), Qt::AlignHCenter | Qt::AlignVCenter, QStringLiteral("Step 3 of 3"));
|
||||
} else {
|
||||
painter.drawEllipse(184,204,32,32);
|
||||
}
|
||||
|
||||
painter.setPen(Qt::white);
|
||||
if(pageId < Page_CaptureArea) {
|
||||
painter.setFont(bubbleTextFont);
|
||||
_textTemp = QStringLiteral("3");
|
||||
} else {
|
||||
painter.setFont(bubbleCheckFont);
|
||||
_textTemp = checkMark;
|
||||
}
|
||||
painter.drawText(QRect(184,204,32,32), Qt::AlignCenter, _textTemp);
|
||||
|
||||
if(pageId >= Page_CaptureArea && pageId < Page_Ops) {
|
||||
painter.setFont(currentItemFont);
|
||||
painter.setPen(highlightedStep);
|
||||
painter.setBrush(highlightedStep);
|
||||
} else {
|
||||
painter.setFont(nonCurrentItemFont);
|
||||
painter.setPen(Qt::white);
|
||||
painter.setBrush(inactiveBubbleColor);
|
||||
}
|
||||
|
||||
painter.drawText(QRect(6, 291, 165, 32), Qt::AlignRight | Qt::AlignVCenter, QStringLiteral("Input Settings"));
|
||||
painter.setPen(inactiveBubbleOutline);
|
||||
painter.drawEllipse(184,291,32,32);
|
||||
|
||||
if(pageId == Page_CaptureArea) {
|
||||
painter.setBrush(highlightedStep);
|
||||
painter.drawPie(184,291,32,32, 90*16, -120*16);
|
||||
painter.setBrush(inactiveBubbleColor);
|
||||
painter.drawPie(184,291, 32,32, 90*16, 240*16);
|
||||
painter.setPen(Qt::white);
|
||||
painter.setFont(stepsFont);
|
||||
painter.drawText(QRect(0,316,200,16), Qt::AlignHCenter | Qt::AlignVCenter, QStringLiteral("Step 1 of 3"));
|
||||
} else if(pageId == Page_CaptureWindow) {
|
||||
painter.setBrush(highlightedStep);
|
||||
painter.drawPie(184,291,32,32, 90*16, -240*16);
|
||||
painter.setBrush(inactiveBubbleColor);
|
||||
painter.drawPie(184,291,32,32, 90*16, 120*16);
|
||||
painter.setPen(Qt::white);
|
||||
painter.setFont(stepsFont);
|
||||
painter.drawText(QRect(0,316,200,16), Qt::AlignHCenter | Qt::AlignVCenter, QStringLiteral("Step 2 of 3"));
|
||||
} else if(pageId == Page_CaptureClipboard) {
|
||||
painter.drawEllipse(184,291,32,32);
|
||||
painter.setPen(Qt::white);
|
||||
painter.setFont(stepsFont);
|
||||
painter.drawText(QRect(0,316,200,16), Qt::AlignHCenter | Qt::AlignVCenter, QStringLiteral("Step 3 of 3"));
|
||||
} else {
|
||||
painter.drawEllipse(184,291,32,32);
|
||||
}
|
||||
|
||||
|
||||
painter.setPen(Qt::white);
|
||||
if(pageId < Page_Ops) {
|
||||
painter.setFont(bubbleTextFont);
|
||||
_textTemp = QStringLiteral("4");
|
||||
} else {
|
||||
painter.setFont(bubbleCheckFont);
|
||||
_textTemp = checkMark;
|
||||
}
|
||||
painter.drawText(QRect(184,291,32,32), Qt::AlignCenter, _textTemp);
|
||||
|
||||
if(pageId >= Page_Ops && pageId < Page_Finished) {
|
||||
painter.setFont(currentItemFont);
|
||||
painter.setPen(highlightedStep);
|
||||
painter.setBrush(highlightedStep);
|
||||
} else {
|
||||
painter.setFont(nonCurrentItemFont);
|
||||
painter.setPen(Qt::white);
|
||||
painter.setBrush(inactiveBubbleColor);
|
||||
}
|
||||
|
||||
painter.drawText(QRect(6, 378, 165, 32),Qt::AlignRight | Qt::AlignVCenter, QStringLiteral("Operation Name"));
|
||||
painter.setPen(inactiveBubbleOutline);
|
||||
painter.drawEllipse(184,378,32,32);
|
||||
|
||||
painter.setPen(Qt::white);
|
||||
if(pageId != Page_Finished) {
|
||||
painter.setFont(bubbleTextFont);
|
||||
_textTemp = QStringLiteral("5");
|
||||
} else {
|
||||
painter.setFont(bubbleCheckFont);
|
||||
_textTemp = checkMark;
|
||||
}
|
||||
painter.drawText(QRect(184,378,32,32),Qt::AlignCenter, _textTemp);
|
||||
painter.end();
|
||||
|
||||
return sideImage;
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
#pragma once
|
||||
|
||||
#include <QWizardPage>
|
||||
#include <QObject>
|
||||
|
||||
class WizardPage : public QWizardPage
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum PAGE {
|
||||
Page_Requiments = 0,
|
||||
Page_Evidence,
|
||||
Page_HostPath,
|
||||
Page_Api,
|
||||
Page_HostTest,
|
||||
Page_CaptureArea,
|
||||
Page_CaptureWindow,
|
||||
Page_CaptureClipboard,
|
||||
Page_Ops,
|
||||
Page_Finished
|
||||
};
|
||||
WizardPage(int pageId = Page_Requiments, QWidget *parent = nullptr);
|
||||
int id() {return m_id;}
|
||||
protected:
|
||||
void changeEvent(QEvent *event);
|
||||
bool isDarkMode();
|
||||
#ifdef Q_OS_MAC
|
||||
const QPair<int, QFont::Weight> titleFont = QPair<int, QFont::Weight>(28, QFont::Bold);
|
||||
const QPair<int, QFont::Weight> subTitleFont = QPair<int, QFont::Weight>(20, QFont::Normal);
|
||||
const QPair<int, QFont::Weight> bodyFont = QPair<int, QFont::Weight>(18, QFont::Normal);
|
||||
const QPair<int, QFont::Weight> smallFont = QPair<int, QFont::Weight>(12, QFont::Light);
|
||||
#else
|
||||
const QPair<int, QFont::Weight> titleFont = QPair<int, QFont::Weight>(22, QFont::Bold);
|
||||
const QPair<int, QFont::Weight> subTitleFont = QPair<int, QFont::Weight>(14, QFont::Normal);
|
||||
const QPair<int, QFont::Weight> bodyFont = QPair<int, QFont::Weight>(12, QFont::Normal);
|
||||
const QPair<int, QFont::Weight> smallFont = QPair<int, QFont::Weight>(9, QFont::Normal);
|
||||
#endif
|
||||
private:
|
||||
const int m_side_w = 200;
|
||||
const int m_side_h = 468;
|
||||
const int m_id;
|
||||
QLinearGradient m_sideGrad;
|
||||
QString _styleTemplate = QStringLiteral("QComboBox:editable,QLineEdit{background:rgba(%1,%2,%3,255);}");
|
||||
QString _lightStyle = _styleTemplate.arg(QStringLiteral("235"), QStringLiteral("235"), QStringLiteral("235"));
|
||||
QString _darkStyle = _styleTemplate.arg(QStringLiteral("21"), QStringLiteral("23"), QStringLiteral("26"));
|
||||
|
||||
QPixmap paintSideImage(int pageId);
|
||||
};
|
|
@ -36,6 +36,7 @@ Settings::Settings(QWidget *parent)
|
|||
, captureClipboardShortcutTextBox(new SingleStrokeKeySequenceEdit(this))
|
||||
, testConnectionButton(new LoadingButton(tr("Test Connection"), this))
|
||||
, couldNotSaveSettingsMsg(new QErrorMessage(this))
|
||||
, showWelcomeScreen(new QCheckBox(tr("Show Welcome Screen"), this))
|
||||
{
|
||||
buildUi();
|
||||
wireUi();
|
||||
|
@ -65,11 +66,13 @@ void Settings::buildUi() {
|
|||
+---------------+-------------+------------+-------------+
|
||||
6 | CodeblkSh Lbl | [CodeblkSh TB] |
|
||||
+---------------+-------------+------------+-------------+
|
||||
7 | Test Conn Btn | StatusLabel |
|
||||
7 | [] Show Welcome Screen |
|
||||
+---------------+-------------+------------+-------------+
|
||||
8 | Vertical spacer |
|
||||
8 | Test Conn Btn | StatusLabel |
|
||||
+---------------+-------------+------------+-------------+
|
||||
9 | Dialog button Box{save, cancel} |
|
||||
9 | Vertical spacer |
|
||||
+---------------+-------------+------------+-------------+
|
||||
10 | Dialog button Box{save, cancel} |
|
||||
+---------------+-------------+------------+-------------+
|
||||
*/
|
||||
auto gridLayout = new QGridLayout(this);
|
||||
|
@ -107,14 +110,17 @@ void Settings::buildUi() {
|
|||
gridLayout->addWidget(captureClipboardShortcutTextBox, 6, 1);
|
||||
|
||||
// row 7
|
||||
gridLayout->addWidget(testConnectionButton, 7, 0);
|
||||
gridLayout->addWidget(connStatusLabel, 7, 1, 1, 4);
|
||||
gridLayout->addWidget(showWelcomeScreen, 7, 1, 1, 5);
|
||||
|
||||
// row 8
|
||||
gridLayout->addItem(new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Expanding), 8, 0, 1, gridLayout->columnCount());
|
||||
gridLayout->addWidget(testConnectionButton, 8, 0);
|
||||
gridLayout->addWidget(connStatusLabel, 8, 1, 1, 4);
|
||||
|
||||
// row 9
|
||||
gridLayout->addWidget(buttonBox, 9, 0, 1, gridLayout->columnCount());
|
||||
gridLayout->addItem(new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Expanding), 9, 0, 1, gridLayout->columnCount());
|
||||
|
||||
// row 10
|
||||
gridLayout->addWidget(buttonBox, 10, 0, 1, gridLayout->columnCount());
|
||||
|
||||
setLayout(gridLayout);
|
||||
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
|
||||
|
@ -175,6 +181,7 @@ void Settings::showEvent(QShowEvent *evt) {
|
|||
captureWindowCmdTextBox->setText(AppConfig::value(CONFIG::COMMAND_CAPTUREWINDOW));
|
||||
captureWindowShortcutTextBox->setKeySequence(QKeySequence::fromString(AppConfig::value(CONFIG::SHORTCUT_CAPTUREWINDOW)));
|
||||
captureClipboardShortcutTextBox->setKeySequence(QKeySequence::fromString(AppConfig::value(CONFIG::SHORTCUT_CAPTURECLIPBOARD)));
|
||||
showWelcomeScreen->setChecked(AppConfig::value(CONFIG::SHOW_WELCOME_SCREEN) == "true");
|
||||
|
||||
// re-enable form
|
||||
connStatusLabel->clear();
|
||||
|
@ -209,6 +216,8 @@ void Settings::onSaveClicked() {
|
|||
AppConfig::setValue(CONFIG::COMMAND_CAPTUREWINDOW, captureWindowCmdTextBox->text());
|
||||
AppConfig::setValue(CONFIG::SHORTCUT_CAPTUREWINDOW, captureWindowShortcutTextBox->keySequence().toString());
|
||||
AppConfig::setValue(CONFIG::SHORTCUT_CAPTURECLIPBOARD, captureClipboardShortcutTextBox->keySequence().toString());
|
||||
QString showWelcome = showWelcomeScreen->isChecked() ? "true" : "false";
|
||||
AppConfig::setValue(CONFIG::SHOW_WELCOME_SCREEN, showWelcome);
|
||||
|
||||
HotkeyManager::updateHotkeys();
|
||||
close();
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "ashirtdialog/ashirtdialog.h"
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QCloseEvent>
|
||||
|
||||
class HotkeyManager;
|
||||
|
@ -75,4 +76,5 @@ class Settings : public AShirtDialog {
|
|||
LoadingButton* testConnectionButton = nullptr;
|
||||
QPushButton* eviRepoBrowseButton = nullptr;
|
||||
QErrorMessage* couldNotSaveSettingsMsg = nullptr;
|
||||
QCheckBox *showWelcomeScreen = nullptr;
|
||||
};
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
#include "helpers/system_helpers.h"
|
||||
#include "hotkeymanager.h"
|
||||
#include "models/codeblock.h"
|
||||
#include "firstRunWizard/firstTimeWizard.h"
|
||||
#include "firstRunWizard/welcomepage.h"
|
||||
|
||||
TrayManager::TrayManager(QWidget * parent, DatabaseConnection* db)
|
||||
: QDialog(parent)
|
||||
|
@ -51,6 +53,9 @@ TrayManager::TrayManager(QWidget * parent, DatabaseConnection* db)
|
|||
// delayed so that windows can listen for get all ops signal
|
||||
NetMan::refreshOperationsList();
|
||||
QTimer::singleShot(5000, this, &TrayManager::checkForUpdate);
|
||||
|
||||
if(AppConfig::value(CONFIG::SHOW_WELCOME_SCREEN) != "false")
|
||||
showWelcomeScreen();
|
||||
}
|
||||
|
||||
TrayManager::~TrayManager() {
|
||||
|
@ -156,6 +161,19 @@ void TrayManager::changeEvent(QEvent *event)
|
|||
event->ignore();
|
||||
}
|
||||
|
||||
void TrayManager::showWizard()
|
||||
{
|
||||
auto gandalf = new FirstTimeWizard();
|
||||
gandalf->show();
|
||||
}
|
||||
|
||||
void TrayManager::showWelcomeScreen()
|
||||
{
|
||||
auto welcomePage = new WelcomePage(this);
|
||||
connect(welcomePage, &WelcomePage::requestSetupWizard, this, &TrayManager::showWizard);
|
||||
welcomePage->show();
|
||||
}
|
||||
|
||||
void TrayManager::spawnGetInfoWindow(qint64 evidenceID) {
|
||||
auto getInfoWindow = new GetInfo(db, evidenceID, this);
|
||||
connect(getInfoWindow, &GetInfo::evidenceSubmitted, [](const model::Evidence& evi) {
|
||||
|
@ -252,6 +270,12 @@ void TrayManager::showNoOperationSetTrayMessage() {
|
|||
void TrayManager::setActiveOperationLabel() {
|
||||
const auto& opName = AppConfig::operationName();
|
||||
chooseOpSubmenu->setTitle(tr("Operation: %1").arg(opName.isEmpty() ? tr("<None>") : opName));
|
||||
for(const auto &a : allOperationActions.actions()) {
|
||||
if(a->text() == opName) {
|
||||
a->setChecked(true);
|
||||
selectedAction = a;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TrayManager::onOperationListUpdated(bool success,
|
||||
|
|
|
@ -94,6 +94,12 @@ class TrayManager : public QDialog {
|
|||
QTimer *updateCheckTimer = nullptr;
|
||||
MessageType currentTrayMessage = NO_ACTION;
|
||||
|
||||
///Show the Settings Wizard
|
||||
void showWizard();
|
||||
|
||||
///Show the Welcome Screen
|
||||
void showWelcomeScreen();
|
||||
|
||||
/// openServicesPath is a variable to store where, on click, to open a path the next time a tray message is displayed
|
||||
QString openServicesPath;
|
||||
|
||||
|
|
Loading…
Reference in New Issue