new Welcome Page and firstrunWizard (#235)

Co-authored-by: Chris Rizzitello <crizzitello@ics.com>
main
crizzitello 2023-11-14 18:40:53 -05:00 committed by GitHub
parent 3e1ba34ca5
commit 26fb82edd5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 1845 additions and 7 deletions

View File

@ -64,6 +64,7 @@ find_package(Qt6 6.5.0 REQUIRED COMPONENTS
Network Network
Sql Sql
Core Core
Svg
) )
add_subdirectory(deploy) add_subdirectory(deploy)

View File

@ -104,6 +104,9 @@ QString AppConfig::defaultValue(const QString &key)
if (key == CONFIG::APIURL) if (key == CONFIG::APIURL)
return QStringLiteral("http://localhost:8080"); return QStringLiteral("http://localhost:8080");
if (key == CONFIG::SHOW_WELCOME_SCREEN)
return QStringLiteral("true");
if (key == CONFIG::SHORTCUT_CAPTURECLIPBOARD) { if (key == CONFIG::SHORTCUT_CAPTURECLIPBOARD) {
if(!get()->appSettings->value(key).isValid()) if(!get()->appSettings->value(key).isValid())
return QStringLiteral("Meta+Alt+v"); return QStringLiteral("Meta+Alt+v");

View File

@ -21,6 +21,7 @@ struct CONFIG {
inline static const auto COMMAND_CAPTUREWINDOW = QStringLiteral("captureWindowExec"); inline static const auto COMMAND_CAPTUREWINDOW = QStringLiteral("captureWindowExec");
inline static const auto SHORTCUT_CAPTUREWINDOW = QStringLiteral("captureWindowShortcut"); inline static const auto SHORTCUT_CAPTUREWINDOW = QStringLiteral("captureWindowShortcut");
inline static const auto SHORTCUT_CAPTURECLIPBOARD = QStringLiteral("captureClipboardShortcut"); 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. /// AppConfig is a singleton for accessing the application's configuration.
@ -102,5 +103,6 @@ private:
CONFIG::COMMAND_CAPTUREWINDOW, CONFIG::COMMAND_CAPTUREWINDOW,
CONFIG::SHORTCUT_CAPTUREWINDOW, CONFIG::SHORTCUT_CAPTUREWINDOW,
CONFIG::SHORTCUT_CAPTURECLIPBOARD, CONFIG::SHORTCUT_CAPTURECLIPBOARD,
CONFIG::SHOW_WELCOME_SCREEN,
}; };
}; };

View File

@ -9,6 +9,19 @@ add_library (FORMS STATIC
getinfo/getinfo.cpp getinfo/getinfo.h getinfo/getinfo.cpp getinfo/getinfo.h
porting/porting_dialog.cpp porting/porting_dialog.h porting/porting_dialog.cpp porting/porting_dialog.h
settings/settings.cpp settings/settings.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) add_library(ASHIRT::FORMS ALIAS FORMS)
@ -26,6 +39,7 @@ target_link_libraries ( FORMS
Qt::Gui Qt::Gui
Qt::Widgets Qt::Widgets
Qt::Sql Qt::Sql
Qt::Svg
ASHIRT::HELPERS ASHIRT::HELPERS
ASHIRT::MODELS ASHIRT::MODELS
ASHIRT::COMPONENTS ASHIRT::COMPONENTS

View File

@ -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);
}

View File

@ -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;
};

View File

@ -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);
}

View File

@ -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;
};

View File

@ -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);
}

View File

@ -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;
};

View File

@ -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);
}

View File

@ -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;
};

View File

@ -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);
}

View File

@ -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;
};

View File

@ -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);
}

View File

@ -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;
};

View File

@ -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);
}

View File

@ -0,0 +1,11 @@
//Settings Wizard Chris Rizzitello 2023
#pragma once
#include <QWizard>
class FirstTimeWizard : public QWizard
{
Q_OBJECT
public:
FirstTimeWizard();
};

View File

@ -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);
}

View File

@ -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;
};

View File

@ -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();
}

View File

@ -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;
};

View File

@ -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));
}
}
}

View File

@ -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;
};

View File

@ -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);
}

View File

@ -0,0 +1,11 @@
#pragma once
#include "wizardpage.h"
#include <QObject>
class RequirementsPage : public WizardPage
{
Q_OBJECT
public:
RequirementsPage(QWidget *parent = nullptr);
};

View File

@ -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();
}

View File

@ -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
};

View File

@ -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;
}

View File

@ -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);
};

View File

@ -36,6 +36,7 @@ Settings::Settings(QWidget *parent)
, captureClipboardShortcutTextBox(new SingleStrokeKeySequenceEdit(this)) , captureClipboardShortcutTextBox(new SingleStrokeKeySequenceEdit(this))
, testConnectionButton(new LoadingButton(tr("Test Connection"), this)) , testConnectionButton(new LoadingButton(tr("Test Connection"), this))
, couldNotSaveSettingsMsg(new QErrorMessage(this)) , couldNotSaveSettingsMsg(new QErrorMessage(this))
, showWelcomeScreen(new QCheckBox(tr("Show Welcome Screen"), this))
{ {
buildUi(); buildUi();
wireUi(); wireUi();
@ -65,11 +66,13 @@ void Settings::buildUi() {
+---------------+-------------+------------+-------------+ +---------------+-------------+------------+-------------+
6 | CodeblkSh Lbl | [CodeblkSh TB] | 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); auto gridLayout = new QGridLayout(this);
@ -107,14 +110,17 @@ void Settings::buildUi() {
gridLayout->addWidget(captureClipboardShortcutTextBox, 6, 1); gridLayout->addWidget(captureClipboardShortcutTextBox, 6, 1);
// row 7 // row 7
gridLayout->addWidget(testConnectionButton, 7, 0); gridLayout->addWidget(showWelcomeScreen, 7, 1, 1, 5);
gridLayout->addWidget(connStatusLabel, 7, 1, 1, 4);
// row 8 // 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 // 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); setLayout(gridLayout);
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding); setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
@ -175,6 +181,7 @@ void Settings::showEvent(QShowEvent *evt) {
captureWindowCmdTextBox->setText(AppConfig::value(CONFIG::COMMAND_CAPTUREWINDOW)); captureWindowCmdTextBox->setText(AppConfig::value(CONFIG::COMMAND_CAPTUREWINDOW));
captureWindowShortcutTextBox->setKeySequence(QKeySequence::fromString(AppConfig::value(CONFIG::SHORTCUT_CAPTUREWINDOW))); captureWindowShortcutTextBox->setKeySequence(QKeySequence::fromString(AppConfig::value(CONFIG::SHORTCUT_CAPTUREWINDOW)));
captureClipboardShortcutTextBox->setKeySequence(QKeySequence::fromString(AppConfig::value(CONFIG::SHORTCUT_CAPTURECLIPBOARD))); captureClipboardShortcutTextBox->setKeySequence(QKeySequence::fromString(AppConfig::value(CONFIG::SHORTCUT_CAPTURECLIPBOARD)));
showWelcomeScreen->setChecked(AppConfig::value(CONFIG::SHOW_WELCOME_SCREEN) == "true");
// re-enable form // re-enable form
connStatusLabel->clear(); connStatusLabel->clear();
@ -209,6 +216,8 @@ void Settings::onSaveClicked() {
AppConfig::setValue(CONFIG::COMMAND_CAPTUREWINDOW, captureWindowCmdTextBox->text()); AppConfig::setValue(CONFIG::COMMAND_CAPTUREWINDOW, captureWindowCmdTextBox->text());
AppConfig::setValue(CONFIG::SHORTCUT_CAPTUREWINDOW, captureWindowShortcutTextBox->keySequence().toString()); AppConfig::setValue(CONFIG::SHORTCUT_CAPTUREWINDOW, captureWindowShortcutTextBox->keySequence().toString());
AppConfig::setValue(CONFIG::SHORTCUT_CAPTURECLIPBOARD, captureClipboardShortcutTextBox->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(); HotkeyManager::updateHotkeys();
close(); close();

View File

@ -5,6 +5,7 @@
#include "ashirtdialog/ashirtdialog.h" #include "ashirtdialog/ashirtdialog.h"
#include <QCheckBox>
#include <QCloseEvent> #include <QCloseEvent>
class HotkeyManager; class HotkeyManager;
@ -75,4 +76,5 @@ class Settings : public AShirtDialog {
LoadingButton* testConnectionButton = nullptr; LoadingButton* testConnectionButton = nullptr;
QPushButton* eviRepoBrowseButton = nullptr; QPushButton* eviRepoBrowseButton = nullptr;
QErrorMessage* couldNotSaveSettingsMsg = nullptr; QErrorMessage* couldNotSaveSettingsMsg = nullptr;
QCheckBox *showWelcomeScreen = nullptr;
}; };

View File

@ -25,6 +25,8 @@
#include "helpers/system_helpers.h" #include "helpers/system_helpers.h"
#include "hotkeymanager.h" #include "hotkeymanager.h"
#include "models/codeblock.h" #include "models/codeblock.h"
#include "firstRunWizard/firstTimeWizard.h"
#include "firstRunWizard/welcomepage.h"
TrayManager::TrayManager(QWidget * parent, DatabaseConnection* db) TrayManager::TrayManager(QWidget * parent, DatabaseConnection* db)
: QDialog(parent) : QDialog(parent)
@ -51,6 +53,9 @@ TrayManager::TrayManager(QWidget * parent, DatabaseConnection* db)
// delayed so that windows can listen for get all ops signal // delayed so that windows can listen for get all ops signal
NetMan::refreshOperationsList(); NetMan::refreshOperationsList();
QTimer::singleShot(5000, this, &TrayManager::checkForUpdate); QTimer::singleShot(5000, this, &TrayManager::checkForUpdate);
if(AppConfig::value(CONFIG::SHOW_WELCOME_SCREEN) != "false")
showWelcomeScreen();
} }
TrayManager::~TrayManager() { TrayManager::~TrayManager() {
@ -156,6 +161,19 @@ void TrayManager::changeEvent(QEvent *event)
event->ignore(); 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) { void TrayManager::spawnGetInfoWindow(qint64 evidenceID) {
auto getInfoWindow = new GetInfo(db, evidenceID, this); auto getInfoWindow = new GetInfo(db, evidenceID, this);
connect(getInfoWindow, &GetInfo::evidenceSubmitted, [](const model::Evidence& evi) { connect(getInfoWindow, &GetInfo::evidenceSubmitted, [](const model::Evidence& evi) {
@ -252,6 +270,12 @@ void TrayManager::showNoOperationSetTrayMessage() {
void TrayManager::setActiveOperationLabel() { void TrayManager::setActiveOperationLabel() {
const auto& opName = AppConfig::operationName(); const auto& opName = AppConfig::operationName();
chooseOpSubmenu->setTitle(tr("Operation: %1").arg(opName.isEmpty() ? tr("<None>") : opName)); 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, void TrayManager::onOperationListUpdated(bool success,

View File

@ -94,6 +94,12 @@ class TrayManager : public QDialog {
QTimer *updateCheckTimer = nullptr; QTimer *updateCheckTimer = nullptr;
MessageType currentTrayMessage = NO_ACTION; 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 /// openServicesPath is a variable to store where, on click, to open a path the next time a tray message is displayed
QString openServicesPath; QString openServicesPath;