AppConfig to QSettings (#186)

Co-authored-by: Chris Rizzitello <crizzitello@ics.com>
main
crizzitello 2022-07-14 23:51:04 -04:00 committed by GitHub
parent e28a6f5190
commit ac5fa6b875
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 283 additions and 344 deletions

View File

@ -10,8 +10,7 @@ add_subdirectory(models)
add_subdirectory(porting)
set(ASHIRT_SOURCES
appconfig.h
appsettings.h
appconfig.cpp appconfig.h
hotkeymanager.cpp hotkeymanager.h
main.cpp
traymanager.cpp traymanager.h

128
src/appconfig.cpp Normal file
View File

@ -0,0 +1,128 @@
// New AppConfig 2022, Chris Rizzitello
// Licensed under the terms of MIT. See LICENSE file in project root for terms.
#include <appconfig.h>
#include <QIODevice>
#include <QJsonParseError>
#include <QJsonObject>
AppConfig::AppConfig(QObject *parent)
: QObject(parent)
, appConfig(new QSettings(_configFile, AppConfig::JSON, this))
, appSettings(new QSettings(this))
{
validateConfig();
}
void AppConfig::validateConfig()
{
//Remove Any invalid Keys and set or fix any keys needed.
for (const auto &key : appConfig->allKeys()) {
if(!_appConfigValidKeys.contains(key))
appConfig->remove(key);
}
if (appConfig->value(CONFIG::EVIDENCEREPO).isNull())
appConfig->setValue(CONFIG::EVIDENCEREPO, QStringLiteral("%1/ashirt/evidence").arg(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation)));
#ifdef Q_OS_MACOS
if (appConfig->value(CONFIG::COMMAND_SCREENSHOT).isNull())
appConfig->setValue(CONFIG::COMMAND_SCREENSHOT, QStringLiteral("screencapture -s %file"));
if (appConfig->value(CONFIG::COMMAND_CAPTUREWINDOW).isNull())
appConfig->setValue(CONFIG::COMMAND_CAPTUREWINDOW, QStringLiteral("screencapture -w %file"));
#endif
}
QString AppConfig::value(const QString &key)
{
return get()->appConfig->value(key, QString()).toString();
}
void AppConfig::setValue(const QString &key, const QString &value)
{
if (!AppConfig::appConfigKeys().contains(key))
return;
if (AppConfig::value(key) == value)
return;
if (value.isEmpty())
get()->appConfig->remove(key);
else
get()->appConfig->setValue(key, value);
get()->appConfig->sync();
}
bool AppConfig::exportConfig(const QString &fileName)
{
if(fileName.isEmpty())
return false;
QSettings newConfig(fileName, JSON);
for (const auto &key : newConfig.allKeys())
newConfig.setValue(key, get()->appConfig->value(key));
newConfig.sync();
return true;
}
void AppConfig::importConfig(const QString &fileName)
{
if(fileName.isEmpty())
return;
QSettings oldConfig(fileName, JSON);
for (const auto &key : oldConfig.allKeys()) {
if (key != CONFIG::ACCESSKEY || key != CONFIG::SECRETKEY || key != CONFIG::APIURL)
AppConfig::setValue(key, QString());
else
AppConfig::setValue(key, oldConfig.value(key).toString());
}
}
QString AppConfig::operationName()
{
return get()->appSettings->value(_opNameSetting).toString();
}
QString AppConfig::operationSlug()
{
return get()->appSettings->value(_opSlugSetting).toString();
}
void AppConfig::setOperationDetails(const QString &operationSlug, const QString &operationName)
{
get()->appSettings->setValue(_opNameSetting, operationName);
get()->appSettings->setValue(_opSlugSetting, operationSlug);
Q_EMIT get()->operationChanged(operationSlug, operationName);
}
void AppConfig::setLastUsedTags(QList<model::Tag> lastTags)
{
QVariantList writeTags;
for (const auto &tag : lastTags)
writeTags << QVariant::fromValue(tag);
get()->appSettings->setValue(_lastUsedTagsSetting, QVariant::fromValue(writeTags));
}
QList<model::Tag> AppConfig::getLastUsedTags()
{
QList<model::Tag> rtn;
const auto tags = get()->appSettings->value(_lastUsedTagsSetting).toList();
for (const auto &tag : tags)
rtn.append(tag.value<model::Tag>());
return rtn;
}
bool AppConfig::readJSONSettings(QIODevice &device, QMap<QString, QVariant> &map)
{
QJsonParseError error;
QJsonObject json = QJsonDocument::fromJson(device.readAll(), &error).object();
if(error.error != QJsonParseError::NoError) {
qWarning() << "Error parsing settings: " << error.errorString();
return false;
}
map = json.toVariantMap();
return true;
}
bool AppConfig::writeJSONSettings(QIODevice &device, const QMap<QString, QVariant> &map)
{
QJsonObject temp = QJsonObject::fromVariantMap(map);
return (device.write(QJsonDocument(temp).toJson()) != -1);
}

View File

@ -1,143 +1,92 @@
// Copyright 2020, Verizon Media
// New AppConfig 2022, Chris Rizzitello
// Licensed under the terms of MIT. See LICENSE file in project root for terms.
#pragma once
#include <QDir>
#include <QFile>
#include <QJsonValue>
#include <QJsonDocument>
#include <QJsonObject>
#include <QObject>
#include <QStandardPaths>
#include <cstdlib>
#include <stdexcept>
#include <QSettings>
#include <QVariant>
#include <QRegularExpression>
#include "exceptions/fileerror.h"
#include "helpers/constants.h"
#include "helpers/file_helpers.h"
#include "helpers/jsonhelpers.h"
#include "models/tag.h"
// AppConfig is a singleton construct for accessing the application's configuration.
// singleton design borrowed from:
// https://stackoverflow.com/questions/1008019/c-singleton-design-pattern
class AppConfig {
public:
static AppConfig &getInstance() {
static AppConfig instance;
return instance;
}
AppConfig(AppConfig const &) = delete;
void operator=(AppConfig const &) = delete;
QString evidenceRepo;
QString accessKey;
QString secretKey;
QString apiURL;
QString screenshotExec;
QString screenshotShortcutCombo;
QString captureWindowExec;
QString captureWindowShortcut;
QString captureClipboardShortcut;
QString errorText;
private:
AppConfig() noexcept {
try {
readConfig();
}
catch (std::exception &e) {
errorText = e.what();
}
}
/// readConfig attempts to read the provided path and parse the configuration file.
/// If successful, the config file is loaded. If the config file is missing, then a
/// default file will be generated. If some other error occurs, a FileError is thrown.
void readConfig(QString location = Constants::configLocation) {
QFile configFile(location);
if (!configFile.open(QIODevice::ReadOnly)) {
if (configFile.exists()) {
throw FileError::mkError("Error reading config file", location.toStdString(),
configFile.error());
}
writeDefaultConfig();
return;
}
QByteArray data = configFile.readAll();
if (configFile.error() != QFile::NoError) {
throw FileError::mkError("Error reading config file", location.toStdString(),
configFile.error());
}
auto result = parseJSONItem<QString>(data, [this](QJsonObject src) {
applyConfig(src);
return "";
});
if (result.isNull()) {
throw std::runtime_error("Unable to parse config file");
}
}
/// writeDefaultConfig attempts to write a basic configuration to disk.
/// This is useful on first runs/when no config data is set.
void writeDefaultConfig() {
evidenceRepo = Constants::defaultEvidenceRepo;
#ifdef Q_OS_MACOS
screenshotExec = QStringLiteral("screencapture -s %file");
captureWindowExec = QStringLiteral("screencapture -w %file");
#endif
writeConfig();
}
public:
/// applyConfig takes a parsed json configuration, and applies it to the current running app instance
void applyConfig(QJsonObject src) {
QList<QPair<QString, QString*>> fields = {
QPair<QString, QString*>(QStringLiteral("evidenceRepo"), &evidenceRepo),
QPair<QString, QString*>(QStringLiteral("accessKey"), &accessKey),
QPair<QString, QString*>(QStringLiteral("secretKey"), &secretKey),
QPair<QString, QString*>(QStringLiteral("apiURL"), &apiURL),
QPair<QString, QString*>(QStringLiteral("screenshotCommand"), &screenshotExec),
QPair<QString, QString*>(QStringLiteral("screenshotShortcut"), &screenshotShortcutCombo),
QPair<QString, QString*>(QStringLiteral("captureWindowExec"), &captureWindowExec),
QPair<QString, QString*>(QStringLiteral("captureWindowShortcut"), &captureWindowShortcut),
QPair<QString, QString*>(QStringLiteral("captureClipboardShortcut"), &captureClipboardShortcut),
};
for (auto fieldPair : fields) {
QJsonValue val = src.value(fieldPair.first);
if (!val.isUndefined() && val.isString()) {
*fieldPair.second = val.toString();
}
}
}
/// serializeConfig creates a Json Object from the currently-used configuration
QJsonObject serializeConfig() {
QJsonObject root;
root["evidenceRepo"] = evidenceRepo;
root["accessKey"] = accessKey;
root["secretKey"] = secretKey;
root["apiURL"] = apiURL;
root["screenshotCommand"] = screenshotExec;
root["screenshotShortcut"] = screenshotShortcutCombo;
root["captureWindowExec"] = captureWindowExec;
root["captureWindowShortcut"] = captureWindowShortcut;
root["captureClipboardShortcut"] = captureClipboardShortcut;
return root;
}
/// writeConfig serializes the running config, and writes the assoicated file to the given path.
/// The path defaults to Constants::configLocation()
/// Returns True if successful
bool writeConfig(const QString &alternateSavePath = QString()) {
QString writeLoc = alternateSavePath.isEmpty() ? Constants::configLocation : alternateSavePath;
auto configContent = QJsonDocument(serializeConfig()).toJson();
return FileHelpers::writeFile(writeLoc, configContent);
}
struct CONFIG {
inline static const auto EVIDENCEREPO = QStringLiteral("evidenceRepo");
inline static const auto ACCESSKEY = QStringLiteral("accessKey");
inline static const auto SECRETKEY = QStringLiteral("secretKey");
inline static const auto APIURL = QStringLiteral("apiURL");
inline static const auto COMMAND_SCREENSHOT = QStringLiteral("screenshotCommand");
inline static const auto SHORTCUT_SCREENSHOT = QStringLiteral("screenshotShortcut");
inline static const auto COMMAND_CAPTUREWINDOW = QStringLiteral("captureWindowExec");
inline static const auto SHORTCUT_CAPTUREWINDOW = QStringLiteral("captureWindowShortcut");
inline static const auto SHORTCUT_CAPTURECLIPBOARD = QStringLiteral("captureClipboardShortcut");
};
/// AppConfig is a singleton for accessing the application's configuration.
class AppConfig : public QObject
{
Q_OBJECT
public:
/// Access the AppConfig for connections
static AppConfig* get() {
static AppConfig instance;
return &instance;
}
/// Request the value of a key; returns a QString version of that value or empty QString
static QString value(const QString &key = QString());
/// Sets a value of a key to any QString Only accepts QStrings
static void setValue(const QString &key = QString(), const QString &value = QString());
/// Returns a List of all the Valid Keys in the config file
static QStringList appConfigKeys() { return _appConfigValidKeys; }
/// Writes a Copy of the config to FileName. Returns true if successful
static bool exportConfig(const QString &fileName = QString());
/// Import configuration from a file.
static void importConfig(const QString &fileName = QString());
/// Helper to get the operation Name
static QString operationName();
/// Helper to get the operation Slug
static QString operationSlug();
/// Helper to write operation Details, emits operationsChanged when called.
static void setOperationDetails(const QString &operationSlug = QString(), const QString &operationName = QString());
/// Get the list of the last used tag(s)
static QList<model::Tag> getLastUsedTags();
/// Set the last used Tags
static void setLastUsedTags(QList<model::Tag> lastTags);
signals:
void operationChanged(QString operationSlug, QString operationName);
private:
AppConfig(QObject *parent = nullptr);
~AppConfig() = default;
AppConfig(AppConfig const &) = delete;
void operator=(AppConfig const &) = delete;
void validateConfig();
// Helpers for JSON Format
static bool readJSONSettings(QIODevice &device, QMap<QString, QVariant> &map);
static bool writeJSONSettings(QIODevice &device, const QMap<QString, QVariant> &map);
inline static const auto JSON = QSettings::registerFormat(QStringLiteral("json"), &readJSONSettings, &writeJSONSettings);
//Vars Used Internally
QSettings *appConfig = nullptr;
QSettings *appSettings = nullptr;
#ifdef Q_OS_MAC
inline static const auto _configFile = QStringLiteral("%1/ashirt/config.json").arg(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation));
#else
inline static const QString _configFile = QStringLiteral("%1/ashirt/config.json").arg(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation));
#endif
inline static const auto _opSlugSetting = QStringLiteral("operation/slug");
inline static const auto _opNameSetting = QStringLiteral("operation/name");
inline static const auto _lastUsedTagsSetting = QStringLiteral("gather/tags");
inline static const QStringList _appConfigValidKeys {
CONFIG::EVIDENCEREPO,
CONFIG::ACCESSKEY,
CONFIG::SECRETKEY,
CONFIG::APIURL,
CONFIG::COMMAND_SCREENSHOT,
CONFIG::SHORTCUT_SCREENSHOT,
CONFIG::COMMAND_CAPTUREWINDOW,
CONFIG::SHORTCUT_CAPTUREWINDOW,
CONFIG::SHORTCUT_CAPTURECLIPBOARD,
};
};

View File

@ -1,82 +0,0 @@
// Copyright 2020, Verizon Media
// Licensed under the terms of MIT. See LICENSE file in project root for terms.
#pragma once
#include <QObject>
#include <QSequentialIterable>
#include <QSettings>
#include "models/tag.h"
// AppSettings is a singleton construct for accessing the application's settings. This is different
// from configuration, as it represents the application's state, rather than how the application
// communicates.
//
// singleton design borrowed from:
// https://stackoverflow.com/questions/1008019/c-singleton-design-pattern
class AppSettings : public QObject {
Q_OBJECT
public:
static AppSettings &getInstance() {
static AppSettings instance;
return instance;
}
AppSettings(AppSettings const &) = delete;
void operator=(AppSettings const &) = delete;
private:
QSettings settings;
const char *opSlugSetting = "operation/slug";
const char *opNameSetting = "operation/name";
const char *lastUsedTagsSetting = "gather/tags";
AppSettings() : QObject(nullptr) {}
public:
signals:
void onOperationUpdated(QString operationSlug, QString operationName);
void onSettingsSynced();
public:
void sync() {
settings.sync(); // ignoring the error
Q_EMIT this->onSettingsSynced();
}
void setOperationDetails(QString operationSlug, QString operationName) {
settings.setValue(opSlugSetting, operationSlug);
settings.setValue(opNameSetting, operationName);
Q_EMIT onOperationUpdated(operationSlug, operationName);
}
QString operationSlug() { return settings.value(opSlugSetting).toString(); }
QString operationName() { return settings.value(opNameSetting).toString(); }
void setLastUsedTags(QList<model::Tag> lastTags) {
QVariantList writeTags;
for (const auto &tag : lastTags) {
writeTags << QVariant::fromValue(tag);
}
settings.setValue(lastUsedTagsSetting, QVariant::fromValue(writeTags));
}
QList<model::Tag> getLastUsedTags() {
QList<model::Tag> rtn;
auto val = settings.value(lastUsedTagsSetting);
if (val.canConvert<QVariantList>()) {
QSequentialIterable iter = val.value<QSequentialIterable>();
for (const QVariant& item : iter) {
rtn.append(qvariant_cast<model::Tag>(item));
}
}
return rtn;
}
};

View File

@ -175,9 +175,12 @@ QList<model::Tag> DatabaseConnection::getFullTagsForEvidenceIDs(
return tags;
}
void DatabaseConnection::setEvidenceTags(const QList<model::Tag> &newTags,
qint64 evidenceID) {
void DatabaseConnection::setEvidenceTags(const QList<model::Tag> &newTags, qint64 evidenceID)
{
// todo: this this actually work?
if(newTags.isEmpty())
return;
auto db = getDB();
QVariantList newTagIds;
for (const auto &tag : newTags) {

View File

@ -6,7 +6,7 @@
#include <QNetworkReply>
#include <QRegularExpression>
#include "appsettings.h"
#include "appconfig.h"
#include "dtos/ashirt_error.h"
#include "components/loading_button/loadingbutton.h"
#include "helpers/netman.h"
@ -79,7 +79,7 @@ void CreateOperation::onRequestComplete() {
auto data = NetMan::extractResponse(createOpReply, isValid);
if (isValid) {
dto::Operation op = dto::Operation::parseData(data);
AppSettings::getInstance().setOperationDetails(op.slug, op.name);
AppConfig::setOperationDetails(op.slug, op.name);
operationNameTextBox->clear();
NetMan::refreshOperationsList();
close();

View File

@ -11,11 +11,11 @@
#include <QMessageBox>
#include <QPushButton>
#include <QRandomGenerator>
#include <QStandardPaths>
#include <QTableWidgetItem>
#include "appsettings.h"
#include "appconfig.h"
#include "dtos/tag.h"
#include "exceptions/fileerror.h"
#include "forms/evidence_filter/evidencefilter.h"
#include "forms/evidence_filter/evidencefilterform.h"
#include "helpers/netman.h"
@ -274,8 +274,9 @@ void EvidenceManager::deleteSet(QList<qint64> ids) {
if (undeletedFiles.length() > 0) {
bool logWritten = true;
auto today = QDateTime::currentDateTime();
auto errLogPath = AppConfig::getInstance().evidenceRepo + "/" +QString("%1.log").arg(today.toMSecsSinceEpoch());
auto errLogPath = QStringLiteral("%1/%2.log")
.arg(AppConfig::value(CONFIG::EVIDENCEREPO)
, QDateTime::currentDateTime().toMSecsSinceEpoch());
try {
QByteArray dataToWrite = tr("Paths to files that could not be deleted: \n\n %1")
.arg(undeletedFiles.join(QStringLiteral("\n"))).toUtf8();
@ -321,7 +322,7 @@ void EvidenceManager::openTableContextMenu(QPoint pos) {
void EvidenceManager::resetFilterButtonClicked() {
EvidenceFilters filter;
filter.operationSlug = AppSettings::getInstance().operationSlug();
filter.operationSlug = AppConfig::operationSlug();
filterTextBox->setText(filter.toString());
loadEvidence();
}

View File

@ -10,7 +10,7 @@
#include <QGridLayout>
#include <QLabel>
#include "appsettings.h"
#include "appconfig.h"
#include "helpers/netman.h"
#include "helpers/ui_helpers.h"
@ -191,6 +191,6 @@ void EvidenceFilterForm::onOperationListUpdated(bool success,
for (const auto &op : operations) {
operationComboBox->addItem(op.name, op.slug);
}
UIHelpers::setComboBoxValue(operationComboBox, AppSettings::getInstance().operationSlug());
UIHelpers::setComboBoxValue(operationComboBox, AppConfig::operationSlug());
operationComboBox->setEnabled(true);
}

View File

@ -6,7 +6,6 @@
#include <QGridLayout>
#include <QMessageBox>
#include "appsettings.h"
#include "components/evidence_editor/evidenceeditor.h"
#include "components/loading_button/loadingbutton.h"
#include "db/databaseconnection.h"

View File

@ -12,6 +12,7 @@
#include <QtConcurrent/QtConcurrent>
#include "db/databaseconnection.h"
#include "exceptions/fileerror.h"
PortingDialog::PortingDialog(PortType dialogType, DatabaseConnection* db, QWidget *parent)
: AShirtDialog(parent)

View File

@ -17,7 +17,6 @@
#include <QString>
#include "appconfig.h"
#include "appsettings.h"
#include "dtos/checkConnection.h"
#include "helpers/http_status.h"
#include "helpers/netman.h"
@ -175,20 +174,18 @@ void Settings::checkForDuplicateShortcuts(const QKeySequence& keySequence, QKeyS
void Settings::showEvent(QShowEvent *evt) {
QDialog::showEvent(evt);
hotkeyManager->disableHotkeys();
AppConfig &inst = AppConfig::getInstance();
eviRepoTextBox->setFocus(); //setting focus to prevent retaining focus for macs
// reset the form in case a user left junk in the text boxes and pressed "cancel"
eviRepoTextBox->setText(QDir::toNativeSeparators(inst.evidenceRepo));
accessKeyTextBox->setText(inst.accessKey);
secretKeyTextBox->setText(inst.secretKey);
hostPathTextBox->setText(inst.apiURL);
captureAreaCmdTextBox->setText(inst.screenshotExec);
captureAreaShortcutTextBox->setKeySequence(QKeySequence::fromString(inst.screenshotShortcutCombo));
captureWindowCmdTextBox->setText(inst.captureWindowExec);
captureWindowShortcutTextBox->setKeySequence(QKeySequence::fromString(inst.captureWindowShortcut));
captureClipboardShortcutTextBox->setKeySequence(QKeySequence::fromString(inst.captureClipboardShortcut));
eviRepoTextBox->setText(QDir::toNativeSeparators(AppConfig::value(CONFIG::EVIDENCEREPO)));
secretKeyTextBox->setText(AppConfig::value(CONFIG::SECRETKEY));
accessKeyTextBox->setText(AppConfig::value(CONFIG::ACCESSKEY));
hostPathTextBox->setText(AppConfig::value(CONFIG::APIURL));
captureAreaCmdTextBox->setText(AppConfig::value(CONFIG::COMMAND_SCREENSHOT));
captureAreaShortcutTextBox->setKeySequence(QKeySequence::fromString(AppConfig::value(CONFIG::SHORTCUT_SCREENSHOT)));
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)));
// re-enable form
connStatusLabel->clear();
@ -211,26 +208,20 @@ void Settings::onSaveClicked() {
stopReply(&currentTestReply);
connStatusLabel->clear();
AppConfig &inst = AppConfig::getInstance();
AppConfig::setValue(CONFIG::EVIDENCEREPO, QDir::fromNativeSeparators(eviRepoTextBox->text()));
AppConfig::setValue(CONFIG::ACCESSKEY, accessKeyTextBox->text());
AppConfig::setValue(CONFIG::SECRETKEY, secretKeyTextBox->text());
inst.evidenceRepo = QDir::fromNativeSeparators(eviRepoTextBox->text());
inst.accessKey = accessKeyTextBox->text();
inst.secretKey = secretKeyTextBox->text();
QString originalApiUrl = inst.apiURL;
inst.apiURL = hostPathTextBox->text();
if (originalApiUrl != hostPathTextBox->text()) {
QString originalApiUrl = AppConfig::value(CONFIG::APIURL);
AppConfig::setValue(CONFIG::APIURL, hostPathTextBox->text());
if (originalApiUrl != hostPathTextBox->text())
NetMan::refreshOperationsList();
}
inst.screenshotExec = captureAreaCmdTextBox->text();
inst.screenshotShortcutCombo = captureAreaShortcutTextBox->keySequence().toString();
inst.captureWindowExec = captureWindowCmdTextBox->text();
inst.captureWindowShortcut = captureWindowShortcutTextBox->keySequence().toString();
inst.captureClipboardShortcut = captureClipboardShortcutTextBox->keySequence().toString();
if(!inst.writeConfig())
couldNotSaveSettingsMsg->showMessage(tr("Unable to save settings. Error: %1").arg(inst.errorText));
AppConfig::setValue(CONFIG::COMMAND_SCREENSHOT, captureAreaCmdTextBox->text());
AppConfig::setValue(CONFIG::SHORTCUT_SCREENSHOT, captureAreaShortcutTextBox->keySequence().toString());
AppConfig::setValue(CONFIG::COMMAND_CAPTUREWINDOW, captureWindowCmdTextBox->text());
AppConfig::setValue(CONFIG::SHORTCUT_CAPTUREWINDOW, captureWindowShortcutTextBox->keySequence().toString());
AppConfig::setValue(CONFIG::SHORTCUT_CAPTURECLIPBOARD, captureClipboardShortcutTextBox->keySequence().toString());
hotkeyManager->updateHotkeys();
close();

View File

@ -10,10 +10,8 @@ class Constants {
/// purposes. This _value_ should not be reused for other db connections.
inline static const auto defaultDbName = QStringLiteral("evidence");
#ifdef Q_OS_MACOS
inline static const auto configLocation = QStringLiteral("%1/config.json").arg(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation));
inline static const auto codeFont = QStringLiteral("monaco");
#else
inline static const auto configLocation = QStringLiteral("%1/ashirt/config.json").arg(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation));
inline static const auto codeFont = QStringLiteral("source code pro");
#endif
};

View File

@ -13,7 +13,7 @@
#include "dtos/operation.h"
#include "dtos/tag.h"
#include "dtos/github_release.h"
#include <helpers/multipartparser.h>
#include "helpers/multipartparser.h"
#include "helpers/stopreply.h"
#include "models/evidence.h"
@ -144,7 +144,7 @@ private:
/// Allows for an optional altHost parameter, in order to check for ashirt servers.
/// Normal usage should provide no value for this parameter.
static RequestBuilder* ashirtGet(QString endpoint, const QString & altHost= QString()) {
QString base = (altHost.isEmpty()) ? AppConfig::getInstance().apiURL : altHost;
QString base = (altHost.isEmpty()) ? AppConfig::value(CONFIG::APIURL) : altHost;
return RequestBuilder::newGet()
->setHost(base)
->setEndpoint(endpoint);
@ -154,8 +154,8 @@ private:
/// authentication is provided (use addASHIRTAuth to do this)
static RequestBuilder* ashirtJSONPost(QString endpoint, QByteArray body) {
return RequestBuilder::newJSONPost()
->setHost(AppConfig::getInstance().apiURL)
->setEndpoint(endpoint)
->setHost(AppConfig::value(CONFIG::APIURL))
->setEndpoint(endpoint)
->setBody(body);
}
@ -163,7 +163,7 @@ private:
/// No authentication is provided (use addASHIRTAuth to do this)
static RequestBuilder* ashirtFormPost(QString endpoint, QByteArray body, QString boundry) {
return RequestBuilder::newFormPost(boundry)
->setHost(AppConfig::getInstance().apiURL)
->setHost(AppConfig::value(CONFIG::APIURL))
->setEndpoint(endpoint)
->setBody(body);
}
@ -177,7 +177,7 @@ private:
reqBuilder->addRawHeader(QStringLiteral("Date"), now);
// load default key if not present
QString apiKeyCopy = altApiKey.isEmpty() ? AppConfig::getInstance().accessKey : QString(altApiKey);
QString apiKeyCopy = altApiKey.isEmpty() ? AppConfig::value(CONFIG::ACCESSKEY) : QString(altApiKey);
auto code = generateHash(RequestMethodToString(reqBuilder->getMethod()),
reqBuilder->getEndpoint(), now, reqBuilder->getBody(), altSecretKey);
@ -192,7 +192,7 @@ private:
const QString &secretKey = QString()) {
QString msg = QStringLiteral("%1\n%2\n%3\n").arg(method, path, date);
QString secretKeyCopy = secretKey.isEmpty() ? AppConfig::getInstance().secretKey : QString(secretKey);
QString secretKeyCopy = secretKey.isEmpty() ? AppConfig::value(CONFIG::SECRETKEY) : QString(secretKey);
QMessageAuthenticationCode code(QCryptographicHash::Sha256);
code.setKey(QByteArray::fromBase64(secretKeyCopy.toUtf8()));

View File

@ -14,9 +14,9 @@
Screenshot::Screenshot(QObject *parent) : QObject(parent) {}
void Screenshot::captureArea() { basicScreenshot(AppConfig::getInstance().screenshotExec); }
void Screenshot::captureArea() { basicScreenshot(AppConfig::value(CONFIG::COMMAND_SCREENSHOT)); }
void Screenshot::captureWindow() { basicScreenshot(AppConfig::getInstance().captureWindowExec); }
void Screenshot::captureWindow() { basicScreenshot(AppConfig::value(CONFIG::COMMAND_CAPTUREWINDOW)); }
QString Screenshot::mkName()
{

View File

@ -4,7 +4,6 @@
#include <QDir>
#include "appconfig.h"
#include "appsettings.h"
class SystemHelpers {
@ -13,8 +12,8 @@ class SystemHelpers {
/// Returns (and creates, if necessary) the path to where evidence should be stored (includes
/// ending path separator)
static QString pathToEvidence() {
auto op = AppSettings::getInstance().operationSlug();
auto root = QStringLiteral("%1/").arg(AppConfig::getInstance().evidenceRepo);
auto op = AppConfig::operationSlug();
auto root = QStringLiteral("%1/").arg(AppConfig::value(CONFIG::EVIDENCEREPO));
if (!op.isEmpty()) {
root.append(QStringLiteral("%1/").arg(op));
}

View File

@ -2,9 +2,7 @@
// Licensed under the terms of MIT. See LICENSE file in project root for terms.
#include "hotkeymanager.h"
#include "appconfig.h"
#include "appsettings.h"
HotkeyManager::HotkeyManager(QObject *parent)
: QObject (parent)
@ -50,7 +48,7 @@ void HotkeyManager::updateHotkeys() {
registerKey(combo, evt);
}
};
regKey(AppConfig::getInstance().screenshotShortcutCombo, ACTION_CAPTURE_AREA);
regKey(AppConfig::getInstance().captureWindowShortcut, ACTION_CAPTURE_WINDOW);
regKey(AppConfig::getInstance().captureClipboardShortcut, ACTION_CAPTURE_CLIPBOARD);
regKey(AppConfig::value(CONFIG::SHORTCUT_SCREENSHOT), ACTION_CAPTURE_AREA);
regKey(AppConfig::value(CONFIG::SHORTCUT_CAPTUREWINDOW), ACTION_CAPTURE_WINDOW);
regKey(AppConfig::value(CONFIG::SHORTCUT_CAPTURECLIPBOARD), ACTION_CAPTURE_CLIPBOARD);
}

View File

@ -13,8 +13,6 @@ void handleCLI(std::vector<std::string> args);
#include <QMessageBox>
#include <QMetaType>
#include "appconfig.h"
#include "appsettings.h"
#include "db/databaseconnection.h"
#include "exceptions/fileerror.h"
#include "traymanager.h"
@ -37,12 +35,6 @@ int main(int argc, char* argv[]) {
return -1;
}
auto configError = AppConfig::getInstance().errorText;
if (!configError.isEmpty()) { // quick check & preload config data
QMessageBox::critical(nullptr, QStringLiteral("ASHIRT Error"), QStringLiteral("Unable to connect to load settings"));
return -1;
}
int rtn;
try {
QApplication app(argc, argv);
@ -62,7 +54,6 @@ int main(int argc, char* argv[]) {
auto window = new TrayManager(nullptr, conn);
rtn = app.exec();
AppSettings::getInstance().sync();
window->deleteLater();
}
catch (std::exception const& ex) {

View File

@ -16,10 +16,7 @@ class Tag {
Tag(qint64 id, qint64 evidenceID, qint64 tagId, QString name) : Tag(id, tagId, name) { this->evidenceId = evidenceID; }
Tag(qint64 id, qint64 tagId, QString name) : Tag(tagId, name) { this->id = id; }
Tag(qint64 tagId, QString name) {
this->serverTagId = tagId;
this->tagName = name;
}
Tag(qint64 tagId, QString name) : serverTagId(tagId), tagName(name) { }
public:
friend QDataStream& operator<<(QDataStream& out, const model::Tag& v) {
@ -41,6 +38,4 @@ class Tag {
qint64 evidenceId;
};
} // namespace model
Q_DECLARE_METATYPE(model::Tag)
Q_DECLARE_METATYPE(QList<model::Tag>)

View File

@ -11,7 +11,7 @@ void SystemManifest::applyManifest(SystemManifestImportOptions options, Database
if (shouldMigrateConfig) {
Q_EMIT onStatusUpdate(tr("Importing Settings"));
migrateConfig();
AppConfig::importConfig(configPath);
}
if (shouldMigrateDb) {
@ -20,21 +20,6 @@ void SystemManifest::applyManifest(SystemManifestImportOptions options, Database
Q_EMIT onComplete();
}
void SystemManifest::migrateConfig()
{
parseJSONItem<QString>(FileHelpers::readFile(pathToFile(configPath)), [](QJsonObject src) {
for(const QString& key : src.keys()) {
// only migrate connections settings, other are not portable
src.remove(QStringLiteral("evidenceRepo")); // we never want to replace what the user has set there.
if (key != QStringLiteral("accessKey") && key != QStringLiteral("secretKey") && key != QStringLiteral("apiURL"))
src.remove(key);
}
AppConfig::getInstance().applyConfig(src);
return QString();
});
AppConfig::getInstance().writeConfig(); // save updated config
}
void SystemManifest::migrateDb(DatabaseConnection* systemDb)
{
Q_EMIT onStatusUpdate(tr("Reading Exported Evidence"));
@ -50,7 +35,7 @@ void SystemManifest::migrateDb(DatabaseConnection* systemDb)
if (importRecord.id == 0)
continue; // in the odd situation that evidence doesn't match up, just skip it
QString newEvidencePath = QStringLiteral("%1/%2/%3")
.arg(AppConfig::getInstance().evidenceRepo
.arg(AppConfig::value(CONFIG::EVIDENCEREPO)
, importRecord.operationSlug
, contentSensitiveFilename(importRecord.contentType));
@ -121,19 +106,7 @@ void SystemManifest::exportManifest(DatabaseConnection* db, const QString& outpu
if (options.exportConfig) {
Q_EMIT onStatusUpdate(tr("Exporting settings"));
configPath = QStringLiteral("config.json");
AppConfig::getInstance().writeConfig(m_fileTemplate.arg(basePath, configPath));
}
if (options.exportDb) {
Q_EMIT onStatusUpdate(tr("Exporting Evidence"));
dbPath = QStringLiteral("db.sqlite");
evidenceManifestPath = QStringLiteral("evidence.json");
auto allEvidence = DatabaseConnection::createEvidenceExportView(m_fileTemplate.arg(basePath, dbPath), EvidenceFilters(), db);
Q_EMIT onReady(allEvidence.size());
porting::EvidenceManifest evidenceManifest = copyEvidence(basePath, allEvidence);
// write evidence manifest
FileHelpers::writeFile(m_fileTemplate.arg(basePath, evidenceManifestPath),
QJsonDocument(EvidenceManifest::serialize(evidenceManifest)).toJson());
AppConfig::exportConfig(m_fileTemplate.arg(basePath, configPath));
}
m_pathToManifest = QStringLiteral("%1/system.json").arg(basePath);

View File

@ -7,7 +7,6 @@
#include "helpers/jsonhelpers.h"
#include "helpers/screenshot.h"
#include "appconfig.h"
#include "appsettings.h"
#include "db/databaseconnection.h"
#include "evidence_manifest.h"
#include "models/codeblock.h"

View File

@ -17,8 +17,8 @@
#include <QDesktopServices>
#include <iostream>
#include "appconfig.h"
#include "appsettings.h"
#include "db/databaseconnection.h"
#include "exceptions/fileerror.h"
#include "forms/getinfo/getinfo.h"
#include "helpers/netman.h"
#include "helpers/screenshot.h"
@ -122,8 +122,8 @@ void TrayManager::wireUi() {
// connect to network signals
connect(NetMan::get(), &NetMan::operationListUpdated, this, &TrayManager::onOperationListUpdated);
connect(NetMan::get(), &NetMan::releasesChecked, this, &TrayManager::onReleaseCheck);
connect(&AppSettings::getInstance(), &AppSettings::onOperationUpdated, this, &TrayManager::setActiveOperationLabel);
connect(AppConfig::get(), &AppConfig::operationChanged, this, &TrayManager::setActiveOperationLabel);
connect(trayIcon, &QSystemTrayIcon::messageClicked, this, &TrayManager::onTrayMessageClicked);
connect(trayIcon, &QSystemTrayIcon::activated, this, [this] {
newOperationAction->setEnabled(false);
@ -166,24 +166,21 @@ void TrayManager::changeEvent(QEvent *event)
void TrayManager::spawnGetInfoWindow(qint64 evidenceID) {
auto getInfoWindow = new GetInfo(db, evidenceID, this);
connect(getInfoWindow, &GetInfo::evidenceSubmitted, [](const model::Evidence& evi){
AppSettings::getInstance().setLastUsedTags(evi.tags);
connect(getInfoWindow, &GetInfo::evidenceSubmitted, [](const model::Evidence& evi) {
AppConfig::setLastUsedTags(evi.tags);
});
getInfoWindow->show();
}
qint64 TrayManager::createNewEvidence(const QString& filepath, const QString& evidenceType) {
AppSettings& inst = AppSettings::getInstance();
auto evidenceID = db->createEvidence(filepath, inst.operationSlug(), evidenceType);
auto tags = inst.getLastUsedTags();
if (!tags.empty()) {
db->setEvidenceTags(tags, evidenceID);
}
auto evidenceID = db->createEvidence(filepath, AppConfig::operationSlug(), evidenceType);
auto tags = AppConfig::getLastUsedTags();
db->setEvidenceTags(tags, evidenceID);
return evidenceID;
}
void TrayManager::captureWindowActionTriggered() {
if(AppSettings::getInstance().operationSlug().isEmpty()) {
if(AppConfig::operationSlug().isEmpty()) {
showNoOperationSetTrayMessage();
return;
}
@ -191,7 +188,7 @@ void TrayManager::captureWindowActionTriggered() {
}
void TrayManager::captureAreaActionTriggered() {
if(AppSettings::getInstance().operationSlug().isEmpty()) {
if(AppConfig::operationSlug().isEmpty()) {
showNoOperationSetTrayMessage();
return;
}
@ -199,7 +196,7 @@ void TrayManager::captureAreaActionTriggered() {
}
void TrayManager::captureClipboardActionTriggered() {
if(AppSettings::getInstance().operationSlug().isEmpty()) {
if(AppConfig::operationSlug().isEmpty()) {
showNoOperationSetTrayMessage();
return;
}
@ -263,7 +260,7 @@ void TrayManager::showNoOperationSetTrayMessage() {
}
void TrayManager::setActiveOperationLabel() {
const auto& opName = AppSettings::getInstance().operationName();
const auto& opName = AppConfig::operationName();
chooseOpSubmenu->setTitle(tr("Operation: %1").arg(opName.isEmpty() ? tr("<None>") : opName));
}
@ -273,7 +270,7 @@ void TrayManager::onOperationListUpdated(bool success,
if (!success)
return;
auto currentOp = AppSettings::getInstance().operationSlug();
auto currentOp = AppConfig::operationSlug();
newOperationAction->setEnabled(true);
newOperationAction->setText(tr("New Operation"));
cleanChooseOpSubmenu();
@ -287,15 +284,15 @@ void TrayManager::onOperationListUpdated(bool success,
}
allOperationActions.addAction(newAction.get());
connect(newAction.get(), &QAction::triggered, this, [this, newAction, op] {
AppSettings::getInstance().setLastUsedTags(QList<model::Tag>{}); // clear last used tags
AppSettings::getInstance().setOperationDetails(op.slug, op.name);
AppConfig::setLastUsedTags(QList<model::Tag>{}); // clear last used tags
AppConfig::setOperationDetails(op.slug, op.name);
selectedAction = newAction.get();
});
chooseOpSubmenu->addAction(newAction.get());
}
if (!selectedAction) {
AppSettings::getInstance().setOperationDetails(QString(), QString());
AppConfig::setOperationDetails(QString(), QString());
}
}