General clean (#174)
* more tagWidgetCleanup * Try not, Do * remove qStringtoByteArray * rm stdStringtoQByteArray use QByteArray::fromStdString() * Clean up Credits More * Hotkeys use QList * Simplify Constants * misc * Use value() calls Co-authored-by: Chris Rizzitello <crizzitello@ics.com>main
parent
16afdb7d3b
commit
3b0823547a
|
@ -55,19 +55,14 @@ class AppConfig {
|
|||
/// 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()) {
|
||||
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());
|
||||
}
|
||||
try {
|
||||
writeDefaultConfig();
|
||||
}
|
||||
catch (...) {
|
||||
// ignoring -- just trying to generate an empty config
|
||||
}
|
||||
writeDefaultConfig();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -89,19 +84,14 @@ class AppConfig {
|
|||
/// 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();
|
||||
evidenceRepo = Constants::defaultEvidenceRepo;
|
||||
|
||||
#ifdef Q_OS_MACOS
|
||||
screenshotExec = "screencapture -s %file";
|
||||
captureWindowExec = "screencapture -w %file";
|
||||
screenshotExec = QStringLiteral("screencapture -s %file");
|
||||
captureWindowExec = QStringLiteral("screencapture -w %file");
|
||||
#endif
|
||||
|
||||
try {
|
||||
writeConfig();
|
||||
}
|
||||
catch (...) {
|
||||
// ignoring error -- best effort approach
|
||||
}
|
||||
writeConfig();
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -118,7 +108,7 @@ class AppConfig {
|
|||
QPair<QString, QString*>(QStringLiteral("captureWindowExec"), &captureWindowExec),
|
||||
QPair<QString, QString*>(QStringLiteral("captureWindowShortcut"), &captureWindowShortcut),
|
||||
QPair<QString, QString*>(QStringLiteral("captureCodeblockShortcut"), &captureCodeblockShortcut),
|
||||
};
|
||||
};
|
||||
|
||||
for (auto fieldPair : fields) {
|
||||
QJsonValue val = src.value(fieldPair.first);
|
||||
|
@ -145,8 +135,8 @@ class AppConfig {
|
|||
|
||||
/// writeConfig serializes the running config, and writes the assoicated file to the given path.
|
||||
/// The path defaults to Constants::configLocation()
|
||||
void writeConfig(QString alternateSavePath="") {
|
||||
QString writeLoc = alternateSavePath == "" ? Constants::configLocation() : alternateSavePath;
|
||||
void writeConfig(QString alternateSavePath = QString()) {
|
||||
QString writeLoc = alternateSavePath.isEmpty() ? Constants::configLocation : alternateSavePath;
|
||||
|
||||
auto configContent = QJsonDocument(serializeConfig()).toJson();
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ CodeEditor::CodeEditor(QWidget *parent)
|
|||
// customize for text/code editing
|
||||
setLineWrapMode(LineWrapMode::NoWrap);
|
||||
setTabChangesFocus(false);
|
||||
QFont font(Constants::codeFont());
|
||||
QFont font(Constants::codeFont);
|
||||
font.setStyleHint(QFont::TypeWriter);
|
||||
setFont(font);
|
||||
|
||||
|
@ -83,7 +83,7 @@ void CodeEditor::keyReleaseEvent(QKeyEvent *e) { QPlainTextEdit::keyReleaseEvent
|
|||
|
||||
int CodeEditor::lineNumberAreaWidth() {
|
||||
int digits = 1;
|
||||
int max = qMax(1, blockCount());
|
||||
int max = std::max(1, blockCount());
|
||||
while (max >= 10) {
|
||||
max /= 10;
|
||||
++digits;
|
||||
|
|
|
@ -48,7 +48,7 @@ void TagView::removeWidget(TagWidget* tagWidget) {
|
|||
|
||||
// remove from includedTags
|
||||
auto itr = std::find(includedTags.begin(), includedTags.end(), tagWidget);
|
||||
if(itr != includedTags.cend()) {
|
||||
if(itr != includedTags.end()) {
|
||||
auto last = includedTags.end()-1;
|
||||
std::iter_swap(itr, last);
|
||||
includedTags.pop_back();
|
||||
|
|
|
@ -46,26 +46,19 @@ void TagWidget::buildTag() {
|
|||
|
||||
int labelWidth = labelSize.width();
|
||||
int innerTagHeight = std::max(labelSize.height(), removeSize.height()); //tag height without the buffer
|
||||
int labelTopOffset = ((innerTagHeight - labelSize.height())/2) + smBuffer;
|
||||
int removeLeftOffset = lgBuffer + labelWidth;
|
||||
int removeTopOffset = ((innerTagHeight - removeSize.height())/2) + smBuffer;
|
||||
|
||||
int tagHeightBuffer = 12; // space around the top/bottom (real size is half as much)
|
||||
int tagWidthBuffer = 12; // space around the outer left/right edges (real size is half as much)
|
||||
int innerBuffer = 6; // space between each segment
|
||||
|
||||
int labelLeftOffset = tagWidthBuffer/2;
|
||||
int labelTopOffset = ((innerTagHeight - labelSize.height())/2) + (tagHeightBuffer/2);
|
||||
|
||||
int removeLeftOffset = labelLeftOffset + labelWidth + innerBuffer;
|
||||
int removeTopOffset = ((innerTagHeight - removeSize.height())/2) + (tagHeightBuffer/2);
|
||||
|
||||
int fullTagWidth = labelWidth + tagWidthBuffer;
|
||||
int fullTagHeight = innerTagHeight + tagHeightBuffer;
|
||||
int fullTagWidth = labelWidth + lgBuffer;
|
||||
int fullTagHeight = innerTagHeight + lgBuffer;
|
||||
|
||||
// set bounds for mouse release event
|
||||
labelArea = QRectF(0, 0, removeLeftOffset, fullTagHeight);
|
||||
removeArea = QRectF(-1, -1, 0, 0); // set to dummy value in case we don't have a remove area
|
||||
|
||||
if (!readonly) {
|
||||
fullTagWidth += removeSize.width() + innerBuffer;
|
||||
fullTagWidth += removeSize.width() + smBuffer;
|
||||
removeArea = QRectF(removeLeftOffset, 0, fullTagWidth - removeLeftOffset, fullTagHeight);
|
||||
}
|
||||
|
||||
|
@ -92,7 +85,7 @@ void TagWidget::buildTag() {
|
|||
painter.setPen(fontColor);
|
||||
|
||||
// draw label
|
||||
painter.drawText(QRectF(QPointF(labelLeftOffset, labelTopOffset), labelSize), Qt::AlignCenter, tag.name);
|
||||
painter.drawText(QRectF(QPointF(smBuffer, labelTopOffset), labelSize), Qt::AlignCenter, tag.name);
|
||||
|
||||
// draw remove (if needed)
|
||||
if(!readonly) {
|
||||
|
|
|
@ -76,4 +76,6 @@ class TagWidget : public QLabel {
|
|||
{QStringLiteral("lightViolet"), QColor(0xC274C2)},
|
||||
};
|
||||
inline static QStringList allColorNames = colorMap.keys();
|
||||
inline static int smBuffer = 6;
|
||||
inline static int lgBuffer = 12;
|
||||
};
|
||||
|
|
|
@ -44,7 +44,7 @@ class DatabaseConnection {
|
|||
* interaction is localized and infrequent.
|
||||
* @param dbPath The path to the database file
|
||||
* @param dbName The name of the database connection (can be anything, but should be unique.
|
||||
* Specifically, it should NOT be the value from Constants::databaseName())
|
||||
* Specifically, it should NOT be the value from Constants::databaseName)
|
||||
* @param actions A function that will execute after a connection is established. This is where
|
||||
* all db interactions should occur.
|
||||
*/
|
||||
|
|
|
@ -19,7 +19,7 @@ class CheckConnection {
|
|||
|
||||
cc.parsedCorrectly = false;
|
||||
if (err.error == QJsonParseError::NoError) {
|
||||
QJsonValue val = doc["ok"];
|
||||
QJsonValue val = doc.object().value(QStringLiteral("ok"));
|
||||
if (!val.isUndefined()) {
|
||||
cc.parsedCorrectly = true;
|
||||
cc.ok = val.toBool();
|
||||
|
|
|
@ -104,22 +104,21 @@ class GithubRelease {
|
|||
private:
|
||||
static GithubRelease fromJson(QJsonObject obj) {
|
||||
GithubRelease release;
|
||||
release.url = obj["url"].toString();
|
||||
release.htmlURL = obj["html_url"].toString();
|
||||
release.assetsURL = obj["assets_url"].toString();
|
||||
release.uploadURL = obj["upload_url"].toString();
|
||||
release.tarballURL = obj["tarball_url"].toString();
|
||||
release.zipballURL = obj["zipball_url"].toString();
|
||||
release.tagName = obj["tag_name"].toString();
|
||||
release.body = obj["body"].toString();
|
||||
release.releaseName = obj["name"].toString();
|
||||
release.publishedAt = obj["published_at"].toString();
|
||||
release.draft = obj["draft"].toBool();
|
||||
release.prerelease = obj["prerelease"].toBool();
|
||||
release.url = obj.value(QStringLiteral("url")).toString();
|
||||
release.htmlURL = obj.value(QStringLiteral("html_url")).toString();
|
||||
release.assetsURL = obj.value(QStringLiteral("assets_url")).toString();
|
||||
release.uploadURL = obj.value(QStringLiteral("upload_url")).toString();
|
||||
release.tarballURL = obj.value(QStringLiteral("tarball_url")).toString();
|
||||
release.zipballURL = obj.value(QStringLiteral("zipball_url")).toString();
|
||||
release.tagName = obj.value(QStringLiteral("tag_name")).toString();
|
||||
release.body = obj.value(QStringLiteral("body")).toString();
|
||||
release.releaseName = obj.value(QStringLiteral("name")).toString();
|
||||
release.publishedAt = obj.value(QStringLiteral("published_at")).toString();
|
||||
release.draft = obj.value(QStringLiteral("draft")).toBool();
|
||||
release.prerelease = obj.value(QStringLiteral("prerelease")).toBool();
|
||||
|
||||
// missing a number of fields here that maybe aren't relevant
|
||||
|
||||
release.id = obj["id"].toVariant().toLongLong();
|
||||
release.id = obj.value(QStringLiteral("id")).toVariant().toLongLong();
|
||||
|
||||
return release;
|
||||
}
|
||||
|
|
|
@ -51,11 +51,10 @@ class Operation {
|
|||
// provides a Operation from a given QJsonObject
|
||||
static Operation fromJson(QJsonObject obj) {
|
||||
Operation o;
|
||||
o.slug = obj["slug"].toString();
|
||||
o.name = obj["name"].toString();
|
||||
o.numUsers = obj["numUsers"].toInt();
|
||||
o.status = static_cast<OperationStatus>(obj["status"].toInt());
|
||||
|
||||
o.slug = obj.value(QStringLiteral("slug")).toString();
|
||||
o.name = obj.value(QStringLiteral("name")).toString();
|
||||
o.numUsers = obj.value(QStringLiteral("numUsers")).toInt();
|
||||
o.status = static_cast<OperationStatus>(obj.value(QStringLiteral("status")).toInt());
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -16,10 +16,9 @@ class Tag {
|
|||
~Tag() = default;
|
||||
Tag(const Tag &) = default;
|
||||
|
||||
Tag(QString name, QString colorName) {
|
||||
this->name = name;
|
||||
this->colorName = colorName;
|
||||
}
|
||||
Tag(QString name, QString colorName)
|
||||
: name(name)
|
||||
, colorName(colorName) { }
|
||||
|
||||
public:
|
||||
static Tag parseData(QByteArray data) { return parseJSONItem<Tag>(data, Tag::fromJson); }
|
||||
|
@ -46,10 +45,9 @@ class Tag {
|
|||
// provides a Tag from a given QJsonObject
|
||||
static Tag fromJson(QJsonObject obj) {
|
||||
Tag t;
|
||||
t.id = obj["id"].toVariant().toLongLong();
|
||||
t.colorName = obj["colorName"].toString();
|
||||
t.name = obj["name"].toString();
|
||||
|
||||
t.id = obj.value(QStringLiteral("id")).toVariant().toLongLong();
|
||||
t.colorName = obj.value(QStringLiteral("colorName")).toString();
|
||||
t.name = obj.value(QStringLiteral("name")).toString();
|
||||
return t;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,127 +5,21 @@
|
|||
|
||||
#include <QDateTime>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QGridLayout>
|
||||
#include <QVBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QTextBrowser>
|
||||
|
||||
#include "helpers/constants.h"
|
||||
#include "helpers/netman.h"
|
||||
|
||||
struct Attribution {
|
||||
std::string library;
|
||||
std::string libraryUrl;
|
||||
std::string authors;
|
||||
std::string license;
|
||||
std::string licenseUrl;
|
||||
|
||||
Attribution() = default;
|
||||
Attribution(std::string library, std::string libraryUrl, std::string authors, std::string license,
|
||||
std::string licenseUrl) {
|
||||
this->library = library;
|
||||
this->libraryUrl = libraryUrl;
|
||||
this->authors = authors;
|
||||
this->license = license;
|
||||
this->licenseUrl = licenseUrl;
|
||||
}
|
||||
};
|
||||
|
||||
static std::string hyperlinkMd(std::string label, std::string url) {
|
||||
return "[" + label + "](" + url + ")";
|
||||
}
|
||||
|
||||
static std::string attributionMarkdown() {
|
||||
QList<Attribution> attribs = {
|
||||
Attribution("Qt", "http://qt.io", "The Qt Company", "LGPLv3",
|
||||
"https://www.gnu.org/licenses/lgpl-3.0.html"),
|
||||
Attribution("QProgressIndicator", "https://github.com/mojocorp/QProgressIndicator",
|
||||
"Mojocorp, et al", "MIT License",
|
||||
"https://github.com/mojocorp/QProgressIndicator/blob/master/LICENSE"),
|
||||
Attribution("MultipartEncoder", "https://github.com/AndsonYe/MultipartEncoder", "Ye Yangang",
|
||||
"MIT License",
|
||||
"https://github.com/AndsonYe/MultipartEncoder/blob/master/LICENSE"),
|
||||
Attribution("UGlobalHotkey", "https://github.com/joelatdeluxe/UGlobalHotkey",
|
||||
"Anton Konstantinov, et al", "Public Domain", ""),
|
||||
Attribution("AspectRatioPixmapLabel", "https://stackoverflow.com/a/22618496/4262552",
|
||||
"phyatt, et al", "CC BY-SA 3.0",
|
||||
"https://creativecommons.org/licenses/by-sa/3.0/"),
|
||||
};
|
||||
|
||||
std::string msg =
|
||||
"This application uses the following open source software:\n\n"
|
||||
"| Project/Library | Authors | License |\n"
|
||||
"| --------------- | ------- | ------- |\n";
|
||||
|
||||
for (const auto& attrib : attribs) {
|
||||
std::string license;
|
||||
std::string suffix;
|
||||
if (!attrib.licenseUrl.empty()) {
|
||||
license += "[";
|
||||
suffix = "](" + attrib.licenseUrl + ")";
|
||||
}
|
||||
license += attrib.license + suffix;
|
||||
|
||||
// clang-format off
|
||||
msg += "| " + hyperlinkMd(attrib.library, attrib.libraryUrl) +
|
||||
" | " + attrib.authors +
|
||||
" | " + license +
|
||||
" |\n";
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
static std::string copyrightDate() {
|
||||
int initialYear = 2020;
|
||||
int currentYear = QDateTime::currentDateTime().date().year();
|
||||
auto rtn = std::to_string(initialYear);
|
||||
if (currentYear != initialYear) {
|
||||
rtn += "-" + std::to_string(currentYear);
|
||||
}
|
||||
return rtn;
|
||||
}
|
||||
|
||||
static std::string preambleMarkdown() {
|
||||
const std::string lf = "\n\n"; // double linefeed to add in linebreaks in markdown
|
||||
// clang-format off
|
||||
return "Version: " + Constants::releaseTag().toStdString() +
|
||||
lf + "Commit Hash: " + Constants::commitHash().toStdString() +
|
||||
lf + "Copyright " + copyrightDate() + ", Verizon Media" +
|
||||
lf + "Licensed under the terms of [MIT](https://github.com/theparanoids/ashirt/blob/master/LICENSE)" +
|
||||
lf + "A short user guide can be found " + hyperlinkMd("here", Constants::userGuideUrl().toStdString()) +
|
||||
lf + "Report issues " + hyperlinkMd("here", Constants::reportAnIssueUrl().toStdString()) +
|
||||
lf;
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
static std::string normalBodyMarkdown() {
|
||||
// clang-format off
|
||||
return "# ASHIRT\n\n"
|
||||
+ preambleMarkdown()
|
||||
+ "## Credits\n"
|
||||
+ attributionMarkdown();
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
Credits::Credits(QWidget* parent)
|
||||
: AShirtDialog(parent, AShirtDialog::commonWindowFlags)
|
||||
, updateLabel(new QLabel(this))
|
||||
: AShirtDialog(parent, AShirtDialog::commonWindowFlags)
|
||||
, updateLabel(new QLabel(this))
|
||||
{
|
||||
buildUi();
|
||||
wireUi();
|
||||
}
|
||||
setWindowTitle("About");
|
||||
connect(&NetMan::getInstance(), &NetMan::releasesChecked, this, &Credits::onReleasesUpdate);
|
||||
|
||||
void Credits::updateRelease() {
|
||||
if (updateDigest.hasUpgrade()) {
|
||||
updateLabel->setText(baseUpdateText.arg(Constants::releasePageUrl()));
|
||||
}
|
||||
else {
|
||||
updateLabel->clear();
|
||||
}
|
||||
}
|
||||
|
||||
void Credits::buildUi() {
|
||||
updateLabel->setVisible(false);
|
||||
updateLabel->setOpenExternalLinks(true);
|
||||
updateLabel->setTextFormat(Qt::RichText);
|
||||
updateLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
|
||||
|
@ -136,39 +30,30 @@ void Credits::buildUi() {
|
|||
auto creditsArea = new QTextBrowser(this);
|
||||
creditsArea->setOpenExternalLinks(true);
|
||||
creditsArea->setReadOnly(true);
|
||||
creditsArea->setMarkdown(normalBodyMarkdown().c_str());
|
||||
creditsArea->setMarkdown(normalBodyMarkdown);
|
||||
|
||||
// Layout
|
||||
/* 0
|
||||
+------------------------------------+
|
||||
0 | update label |
|
||||
+------------------------------------+
|
||||
| |
|
||||
1 | Credits Area |
|
||||
| |
|
||||
+------------------------------------+
|
||||
2 | Dialog button Box{close} |
|
||||
+------------------------------------+
|
||||
*/
|
||||
|
||||
auto gridLayout = new QGridLayout(this);
|
||||
gridLayout->addWidget(updateLabel, 0, 0);
|
||||
gridLayout->addWidget(creditsArea, 1, 0);
|
||||
gridLayout->addWidget(buttonBox, 2, 0);
|
||||
auto gridLayout = new QVBoxLayout(this);
|
||||
gridLayout->addWidget(updateLabel);
|
||||
gridLayout->addWidget(creditsArea);
|
||||
gridLayout->addWidget(buttonBox);
|
||||
setLayout(gridLayout);
|
||||
|
||||
resize(450, 500);
|
||||
setWindowTitle("About");
|
||||
setMinimumSize(425, 500);
|
||||
}
|
||||
|
||||
void Credits::wireUi() {
|
||||
connect(&NetMan::getInstance(), &NetMan::releasesChecked, this, &Credits::onReleasesUpdate);
|
||||
void Credits::updateRelease() {
|
||||
if (updateDigest.hasUpgrade()) {
|
||||
updateLabel->setVisible(true);
|
||||
updateLabel->setText(baseUpdateText.arg(Constants::releasePageUrl));
|
||||
}
|
||||
else {
|
||||
updateLabel->setVisible(false);
|
||||
updateLabel->clear();
|
||||
}
|
||||
}
|
||||
|
||||
void Credits::onReleasesUpdate(bool success, QList<dto::GithubRelease> releases) {
|
||||
if (!success) {
|
||||
return; //doesn't matter if this fails
|
||||
}
|
||||
if (!success)
|
||||
return;
|
||||
|
||||
auto digest = dto::ReleaseDigest::fromReleases(Constants::releaseTag(), releases);
|
||||
updateDigest = digest;
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "ashirtdialog/ashirtdialog.h"
|
||||
#include "dtos/github_release.h"
|
||||
#include "helpers/constants.h"
|
||||
|
||||
class QLabel;
|
||||
|
||||
|
@ -19,10 +20,6 @@ class Credits : public AShirtDialog {
|
|||
void onReleasesUpdate(bool success, QList<dto::GithubRelease> releases);
|
||||
|
||||
private:
|
||||
/// buildUi creates the window structure.
|
||||
void buildUi();
|
||||
/// wireUi connects the components to each other.
|
||||
void wireUi();
|
||||
/// updateRelease waits for an update on a new version, if any. If called, and a new version does exist
|
||||
/// this will update the updateLabel to have a link to the new release
|
||||
void updateRelease();
|
||||
|
@ -30,5 +27,46 @@ class Credits : public AShirtDialog {
|
|||
private:
|
||||
QLabel* updateLabel = nullptr;
|
||||
dto::ReleaseDigest updateDigest;
|
||||
inline static const auto attribBLOB_splitChar = QStringLiteral(">");
|
||||
inline static const auto attrib_splitChar = QStringLiteral("~");
|
||||
inline static const auto hyperlinkMd = QStringLiteral("[%1](%2)");
|
||||
inline static const auto creditLine = QStringLiteral("| %1 | %2 | %3 |\n");
|
||||
inline static const QString baseUpdateText = QStringLiteral("A new update is available! Click <a href=\"%1\">here</a> for more details.");
|
||||
inline static const auto attribBLOB
|
||||
= QStringLiteral(
|
||||
"Qt~http://qt.io~The Qt Company~LGPLv3~https://www.gnu.org/licenses/lgpl-3.0.html"
|
||||
">QProgressIndicator~https://github.com/mojocorp/QProgressIndicator~Mojocorp, et al~MIT License~https://github.com/mojocorp/QProgressIndicator/blob/master/LICENSE"
|
||||
">MultipartEncoder~https://github.com/AndsonYe/MultipartEncoder~Ye Yangang~MIT License~https://github.com/AndsonYe/MultipartEncoder/blob/master/LICENSE"
|
||||
">UGlobalHotkey~https://github.com/joelatdeluxe/UGlobalHotkey~Anton Konstantinov, et al~Public Domain~https://fairuse.stanford.edu/overview/public-domain/welcome"
|
||||
">AspectRatioPixmapLabel~https://stackoverflow.com/a/22618496/4262552~phyatt, et al~CC BY-SA 3.0~https://creativecommons.org/licenses/by-sa/3.0/"
|
||||
);
|
||||
inline static const auto preambleMarkdown
|
||||
= QStringLiteral("Version: %1 \n\n"
|
||||
"Commit Hash: %2\n\n"
|
||||
"Copyright %3, Verizon Media\n\n"
|
||||
"Licensed under the terms of %4\n\n"
|
||||
"A short user guide can be found %5\n\n"
|
||||
"Report issues %6\n\n")
|
||||
.arg(Constants::releaseTag()
|
||||
, Constants::commitHash
|
||||
, QStringLiteral("2020 - %1").arg(QDateTime::currentDateTime().date().year())
|
||||
, hyperlinkMd.arg(QStringLiteral("MIT"), QStringLiteral("https://github.com/theparanoids/ashirt/blob/master/LICENSE"))
|
||||
, hyperlinkMd.arg(QStringLiteral("here"), Constants::userGuideUrl)
|
||||
, hyperlinkMd.arg(QStringLiteral("here"), Constants::reportAnIssueUrl));
|
||||
|
||||
static QString attributionMarkdown() {
|
||||
const QStringList attribs = attribBLOB.split(attribBLOB_splitChar);
|
||||
auto msg =
|
||||
QStringLiteral("This application uses the following open source software:\n\n"
|
||||
"| Project/Library | Authors | License |\n"
|
||||
"| --------------- | ------- | ------- |\n");
|
||||
for (const auto& attrib: attribs) {
|
||||
const QStringList credit = attrib.split(attrib_splitChar);
|
||||
auto library = hyperlinkMd.arg(credit.at(0), credit.at(1));
|
||||
auto copyright = hyperlinkMd.arg(credit.at(3), credit.at(4));
|
||||
msg.append(creditLine.arg(library, credit.at(2), copyright));
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
inline static const auto normalBodyMarkdown = QStringLiteral("# ASHIRT\n\n %1 ## Credits\n %2").arg(preambleMarkdown, attributionMarkdown());
|
||||
};
|
||||
|
|
|
@ -163,7 +163,7 @@ void PortingDialog::doExport(porting::SystemManifest* manifest, const QString& e
|
|||
// Qt db access is limited to single-thread access. A new connection needs to be made, hence
|
||||
// the withconnection here that connects to the same database. Note: we shouldn't write to the db
|
||||
// in this thread, if possible.
|
||||
QString threadedDbName = Constants::defaultDbName() + "_mt_forExport";
|
||||
QString threadedDbName = QStringLiteral("%1_mt_forExport").arg(Constants::defaultDbName);
|
||||
DatabaseConnection::withConnection(
|
||||
db->getDatabasePath(), threadedDbName, [this, &manifest, exportPath, options](DatabaseConnection conn){
|
||||
try {
|
||||
|
@ -198,7 +198,7 @@ void PortingDialog::doImport(porting::SystemManifest* manifest) {
|
|||
options.importDb = portEvidenceCheckBox->isChecked() ? options.Merge : options.None;
|
||||
options.importConfig = portConfigCheckBox->isChecked();
|
||||
|
||||
QString threadedDbName = QStringLiteral("%1_mt_forImport").arg(Constants::defaultDbName());
|
||||
QString threadedDbName = QStringLiteral("%1_mt_forImport").arg(Constants::defaultDbName);
|
||||
DatabaseConnection::withConnection(
|
||||
db->getDatabasePath(), threadedDbName, [this, &manifest, options](DatabaseConnection conn){
|
||||
try {
|
||||
|
|
|
@ -162,8 +162,7 @@ void Settings::checkForDuplicateShortcuts(const QKeySequence& keySequence, QKeyS
|
|||
|
||||
bool alreadyUsed = usesKeySequence(captureWindowShortcutTextBox)
|
||||
|| usesKeySequence(recordCodeblockShortcutTextBox)
|
||||
|| usesKeySequence(captureAreaShortcutTextBox)
|
||||
;
|
||||
|| usesKeySequence(captureAreaShortcutTextBox);
|
||||
|
||||
if(alreadyUsed) {
|
||||
parentComponent->clear();
|
||||
|
@ -231,12 +230,9 @@ void Settings::onSaveClicked() {
|
|||
inst.captureWindowShortcut = captureWindowShortcutTextBox->keySequence().toString();
|
||||
inst.captureCodeblockShortcut = recordCodeblockShortcutTextBox->keySequence().toString();
|
||||
|
||||
try {
|
||||
inst.writeConfig();
|
||||
}
|
||||
catch (std::exception &e) {
|
||||
couldNotSaveSettingsMsg->showMessage(tr("Unable to save settings. Error: %1").arg(e.what()));
|
||||
}
|
||||
inst.writeConfig();
|
||||
if(!inst.errorText.isEmpty())
|
||||
couldNotSaveSettingsMsg->showMessage(tr("Unable to save settings. Error: %1").arg(inst.errorText));
|
||||
|
||||
hotkeyManager->updateHotkeys();
|
||||
close();
|
||||
|
|
|
@ -1,35 +1,28 @@
|
|||
#pragma once
|
||||
|
||||
#include <QRegularExpression>
|
||||
#include <QStandardPaths>
|
||||
#include <QString>
|
||||
|
||||
#include <iostream>
|
||||
#include <QRegularExpression>
|
||||
|
||||
class Constants {
|
||||
public:
|
||||
static QString unknownRepoValue() {
|
||||
return QStringLiteral("???");
|
||||
}
|
||||
static QString unknownOwnerValue() {
|
||||
return QStringLiteral("???");
|
||||
}
|
||||
|
||||
static QString configLocation() {
|
||||
inline static const auto unknownValue = QStringLiteral("???");
|
||||
inline static const auto dbLocation = QStringLiteral("%1/evidence.sqlite").arg(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation));
|
||||
inline static const auto defaultEvidenceRepo = QStringLiteral("%1/evidence").arg(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation));
|
||||
inline static const auto commitHash = QStringLiteral("%1").arg(COMMIT_HASH);
|
||||
inline static const auto userGuideUrl = QStringLiteral("https://www.github.com/theparanoids/ashirt/blob/master/README.md");
|
||||
inline static const auto reportAnIssueUrl = QStringLiteral("https://www.github.com/theparanoids/ashirt/issues");
|
||||
inline static const auto releasePageUrl = QStringLiteral("https://github.com/theparanoids/ashirt/releases");
|
||||
/// defaultDbName returns a string storing the "name" of the database for Qt identification
|
||||
/// purposes. This _value_ should not be reused for other db connections.
|
||||
inline static const auto defaultDbName = QStringLiteral("evidence");
|
||||
#ifdef Q_OS_MACOS
|
||||
return QStringLiteral("%1/config.json").arg(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation));
|
||||
inline static const auto configLocation = QStringLiteral("%1/config.json").arg(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation));
|
||||
inline static const auto codeFont = QStringLiteral("monaco");
|
||||
#else
|
||||
return QStringLiteral("%1/ashirt/config.json").arg(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation));
|
||||
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
|
||||
}
|
||||
|
||||
static QString dbLocation() {
|
||||
return QStringLiteral("%1/evidence.sqlite").arg(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation));
|
||||
}
|
||||
|
||||
static QString defaultEvidenceRepo() {
|
||||
return QStringLiteral("%1/evidence").arg(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation));
|
||||
}
|
||||
|
||||
static QString releaseOwner() {
|
||||
return parseRepo(RepoField::owner);
|
||||
|
@ -39,49 +32,17 @@ class Constants {
|
|||
return parseRepo(RepoField::repo);
|
||||
}
|
||||
|
||||
static QString commitHash() {
|
||||
return QStringLiteral("%1").arg(COMMIT_HASH);
|
||||
}
|
||||
|
||||
static QString releaseTag() {
|
||||
static QString parsedReleaseTag;
|
||||
|
||||
if (parsedReleaseTag.isEmpty()) {
|
||||
QRegularExpression compiledTagRegex(QStringLiteral("(?:tags/)?v(.*)"));
|
||||
auto rawVersion = QStringLiteral("%1").arg(VERSION_TAG);
|
||||
QRegularExpressionMatch match = compiledTagRegex.match(rawVersion);
|
||||
parsedReleaseTag = match.hasMatch() ? QStringLiteral("v") + match.captured(1) : QStringLiteral("v0.0.0-unversioned");
|
||||
}
|
||||
|
||||
return parsedReleaseTag;
|
||||
}
|
||||
|
||||
static QString userGuideUrl() {
|
||||
return QStringLiteral("https://www.github.com/theparanoids/ashirt/blob/master/README.md");
|
||||
}
|
||||
|
||||
static QString reportAnIssueUrl() {
|
||||
return QStringLiteral("https://www.github.com/theparanoids/ashirt/issues");
|
||||
}
|
||||
|
||||
static QString releasePageUrl() {
|
||||
return QStringLiteral("https://github.com/theparanoids/ashirt/releases");
|
||||
}
|
||||
|
||||
static QString codeFont() {
|
||||
#ifdef Q_OS_MACX
|
||||
return QStringLiteral("monaco");
|
||||
#endif
|
||||
|
||||
return QStringLiteral("source code pro");
|
||||
}
|
||||
|
||||
/// defaultDbName returns a string storing the "name" of the database for Qt identification
|
||||
/// purposes. This _value_ should not be reused for other db connections.
|
||||
static QString defaultDbName() {
|
||||
return QStringLiteral("evidence");
|
||||
}
|
||||
|
||||
private:
|
||||
enum RepoField {
|
||||
owner = 0,
|
||||
|
@ -91,15 +52,14 @@ class Constants {
|
|||
static QString parseRepo(RepoField field) {
|
||||
static QString parsedRepo;
|
||||
static QString parsedOwner;
|
||||
|
||||
if (parsedRepo.isEmpty()) {
|
||||
auto rawRepo = QStringLiteral("%1").arg(SOURCE_CONTROL_REPO);
|
||||
QRegularExpression ownerRegex(QStringLiteral("^([^/]+)/(.*)"));
|
||||
QRegularExpressionMatch match = ownerRegex.match(rawRepo);
|
||||
// Note that the specific values for the error cases below don't matter
|
||||
// They are set to avoid rerunning the parsing (since these values won't change mid-run)
|
||||
parsedOwner = match.hasMatch() ? match.captured(1) : unknownOwnerValue();
|
||||
parsedRepo = match.hasMatch() ? match.captured(2) : unknownRepoValue();
|
||||
parsedOwner = match.hasMatch() ? match.captured(1) : unknownValue;
|
||||
parsedRepo = match.hasMatch() ? match.captured(2) : unknownValue;
|
||||
}
|
||||
return field == RepoField::owner ? parsedOwner : parsedRepo;
|
||||
}
|
||||
|
|
|
@ -55,23 +55,10 @@ class FileHelpers {
|
|||
return templateStr.replace(templateIndex, replaceToken.length(), replacement);
|
||||
}
|
||||
|
||||
/// converts a c++ std string into QByteArray, ensuring proper encoding
|
||||
static QByteArray stdStringToByteArray(std::string str) {
|
||||
return QByteArray(str.c_str(), str.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief qstringToByteArray converts a QString into a QByteArray, ensuring proper encoding. Only
|
||||
* safe for ascii content.
|
||||
* @param q The string to convert
|
||||
* @return the QString as a QByteArray
|
||||
*/
|
||||
static QByteArray qstringToByteArray(QString q) { return stdStringToByteArray(q.toStdString()); }
|
||||
|
||||
/// writeFile write the provided content to the provided path.
|
||||
/// @throws a FileError if there are issues opening or writing to the file.
|
||||
static void writeFile(QString path, QString content) {
|
||||
writeFile(path, qstringToByteArray(content));
|
||||
writeFile(path, content.toUtf8());
|
||||
}
|
||||
|
||||
/// writeFile write the provided content to the provided path.
|
||||
|
|
|
@ -123,9 +123,8 @@ inline size_t QtKeyToWin(Qt::Key key)
|
|||
return key;
|
||||
}
|
||||
#elif defined(Q_OS_LINUX)
|
||||
|
||||
#include "ukeysequence.h"
|
||||
#include <unordered_map>
|
||||
#include <QMap>
|
||||
#include "xcb/xcb.h"
|
||||
#include "xcb/xcb_keysyms.h"
|
||||
#include "X11/keysym.h"
|
||||
|
@ -135,7 +134,7 @@ struct UKeyData {
|
|||
int mods;
|
||||
};
|
||||
|
||||
static std::unordered_map<uint32_t, uint32_t> KEY_MAP = {
|
||||
inline const static QMap<uint32_t, uint32_t> KEY_MAP = {
|
||||
{Qt::Key_Escape, XK_Escape},
|
||||
{Qt::Key_Tab, XK_Tab},
|
||||
{Qt::Key_Backspace, XK_BackSpace},
|
||||
|
@ -163,15 +162,15 @@ inline UKeyData QtKeyToLinux(const UKeySequence &keySeq)
|
|||
|
||||
auto key = keySeq.getSimpleKeys();
|
||||
if (key.size() > 0) {
|
||||
data.key = key[0];
|
||||
data.key = key.first();
|
||||
} else {
|
||||
qWarning() << "Invalid hotkey";
|
||||
return data;
|
||||
}
|
||||
// Key conversion
|
||||
// Misc Keys
|
||||
if (KEY_MAP.find(key[0]) != KEY_MAP.end()) {
|
||||
data.key = KEY_MAP[key[0]];
|
||||
if (KEY_MAP.find(key.first()) != KEY_MAP.end()) {
|
||||
data.key = KEY_MAP.value(key.first());
|
||||
} else if (data.key >= Qt::Key_F1 && data.key <= Qt::Key_F35) { // Qt's F keys need conversion
|
||||
const size_t DIFF = Qt::Key_F1 - XK_F1;
|
||||
data.key -= DIFF;
|
||||
|
@ -198,18 +197,19 @@ inline UKeyData QtKeyToLinux(const UKeySequence &keySeq)
|
|||
|
||||
return data;
|
||||
}
|
||||
xcb_connection_t *X11Connection;
|
||||
xcb_window_t X11Wid;
|
||||
xcb_key_symbols_t *X11KeySymbs;
|
||||
#elif defined(Q_OS_MAC)
|
||||
|
||||
#include "ukeysequence.h"
|
||||
#include <Carbon/Carbon.h>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <QMap>
|
||||
struct UKeyData {
|
||||
uint32_t key;
|
||||
uint32_t mods;
|
||||
};
|
||||
|
||||
static std::unordered_map<uint32_t, uint32_t> KEY_MAP = {
|
||||
static QMap<uint32_t, uint32_t> KEY_MAP = {
|
||||
{Qt::Key_A, kVK_ANSI_A},
|
||||
{Qt::Key_B, kVK_ANSI_B},
|
||||
{Qt::Key_C, kVK_ANSI_C},
|
||||
|
@ -263,7 +263,7 @@ static std::unordered_map<uint32_t, uint32_t> KEY_MAP = {
|
|||
{Qt::Key_Print, kVK_F14},
|
||||
};
|
||||
|
||||
static std::unordered_map<uint32_t, uint32_t> MOD_MAP = {
|
||||
static QMap<uint32_t, uint32_t> MOD_MAP = {
|
||||
{Qt::Key_Shift, shiftKey},
|
||||
{Qt::Key_Alt, optionKey},
|
||||
{Qt::Key_Control, controlKey},
|
||||
|
@ -277,8 +277,8 @@ inline UKeyData QtKeyToMac(const UKeySequence &keySeq)
|
|||
auto key = keySeq.getSimpleKeys();
|
||||
auto mods = keySeq.getModifiers();
|
||||
|
||||
if (key.size() == 1 && KEY_MAP.find(key[0]) != KEY_MAP.end()) {
|
||||
data.key = KEY_MAP[key[0]];
|
||||
if (key.size() == 1 && KEY_MAP.find(key.first()) != KEY_MAP.end()) {
|
||||
data.key = KEY_MAP.value(key.first());
|
||||
} else {
|
||||
qWarning() << "Invalid hotkey";
|
||||
return data;
|
||||
|
@ -288,9 +288,9 @@ inline UKeyData QtKeyToMac(const UKeySequence &keySeq)
|
|||
if (MOD_MAP.find(mod) == MOD_MAP.end())
|
||||
return data;
|
||||
|
||||
data.mods += MOD_MAP[mod];
|
||||
data.mods += MOD_MAP.value(mod);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
QHash<size_t, EventHotKeyRef> HotkeyRefs;
|
||||
#endif
|
||||
|
|
|
@ -22,8 +22,8 @@ void UKeySequence::fromString(const QString &str)
|
|||
|
||||
QString UKeySequence::toString()
|
||||
{
|
||||
const QVector<Qt::Key> simpleKeys = getSimpleKeys();
|
||||
const QVector<Qt::Key> modifiers = getModifiers();
|
||||
const QList<Qt::Key> simpleKeys = getSimpleKeys();
|
||||
const QList<Qt::Key> modifiers = getModifiers();
|
||||
QStringList result;
|
||||
for (auto mod : modifiers)
|
||||
result.append(keyToStr(mod));
|
||||
|
@ -34,9 +34,9 @@ QString UKeySequence::toString()
|
|||
return result.join('+');
|
||||
}
|
||||
|
||||
QVector<Qt::Key> UKeySequence::getSimpleKeys() const
|
||||
QList<Qt::Key> UKeySequence::getSimpleKeys() const
|
||||
{
|
||||
QVector<Qt::Key> result;
|
||||
QList<Qt::Key> result;
|
||||
for (auto key : qAsConst(mKeys)) {
|
||||
if (!isModifier(key)) {
|
||||
result.append(key);
|
||||
|
@ -45,9 +45,9 @@ QVector<Qt::Key> UKeySequence::getSimpleKeys() const
|
|||
return result;
|
||||
}
|
||||
|
||||
QVector<Qt::Key> UKeySequence::getModifiers() const
|
||||
QList<Qt::Key> UKeySequence::getModifiers() const
|
||||
{
|
||||
QVector<Qt::Key> result;
|
||||
QList<Qt::Key> result;
|
||||
for (auto key : qAsConst(mKeys)) {
|
||||
if (isModifier(key)) {
|
||||
result.append(key);
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QVector>
|
||||
#include <QList>
|
||||
#include <QStringList>
|
||||
#include <QKeyEvent>
|
||||
|
||||
|
@ -34,11 +34,11 @@ public:
|
|||
return mKeys[n];
|
||||
}
|
||||
|
||||
QVector<Qt::Key> getSimpleKeys() const;
|
||||
QVector<Qt::Key> getModifiers() const;
|
||||
QList<Qt::Key> getSimpleKeys() const;
|
||||
QList<Qt::Key> getModifiers() const;
|
||||
|
||||
private:
|
||||
QVector<Qt::Key> mKeys;
|
||||
QList<Qt::Key> mKeys;
|
||||
|
||||
inline static bool isModifier(Qt::Key key)
|
||||
{
|
||||
|
|
|
@ -115,10 +115,10 @@ class NetMan : public QObject {
|
|||
}
|
||||
|
||||
QMessageAuthenticationCode code(QCryptographicHash::Sha256);
|
||||
QByteArray key = QByteArray::fromBase64(FileHelpers::qstringToByteArray(secretKeyCopy));
|
||||
QByteArray key = QByteArray::fromBase64(secretKeyCopy.toUtf8());
|
||||
|
||||
code.setKey(key);
|
||||
code.addData(FileHelpers::stdStringToByteArray(msg));
|
||||
code.addData(QByteArray::fromStdString(msg));
|
||||
return code.result().toBase64();
|
||||
}
|
||||
|
||||
|
@ -178,7 +178,7 @@ class NetMan : public QObject {
|
|||
|
||||
parser.AddFile("file", evidence.path.toStdString());
|
||||
|
||||
auto body = FileHelpers::stdStringToByteArray(parser.GenBodyContent());
|
||||
auto body = QByteArray::fromStdString(parser.GenBodyContent());
|
||||
|
||||
auto builder = ashirtFormPost(QStringLiteral("/api/operations/%1/evidence").arg(evidence.operationSlug), body, parser.boundary().c_str());
|
||||
addASHIRTAuth(builder);
|
||||
|
@ -256,7 +256,7 @@ class NetMan : public QObject {
|
|||
/// checkForNewRelease retrieves the recent releases from github for the provided owner/repo project.
|
||||
/// Callers should retrieve the result by listening for the releasesChecked signal
|
||||
void checkForNewRelease(QString owner, QString repo) {
|
||||
if (owner == Constants::unknownOwnerValue() || repo == Constants::unknownRepoValue()) {
|
||||
if (owner == Constants::unknownValue || repo == Constants::unknownValue) {
|
||||
std::cerr << "Skipping release check: no owner or repo set." << std::endl;
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -149,7 +149,7 @@ class RequestBuilder {
|
|||
QNetworkRequest req;
|
||||
|
||||
for(const auto& header : rawHeaders) {
|
||||
req.setRawHeader(FileHelpers::qstringToByteArray(header.first), FileHelpers::qstringToByteArray(header.second));
|
||||
req.setRawHeader(header.first.toUtf8(), header.second.toUtf8());
|
||||
}
|
||||
|
||||
for(const auto& header : knownHeaders) {
|
||||
|
|
|
@ -34,7 +34,7 @@ int main(int argc, char* argv[]) {
|
|||
|
||||
DatabaseConnection* conn;
|
||||
try {
|
||||
conn = new DatabaseConnection(Constants::dbLocation(), Constants::defaultDbName());
|
||||
conn = new DatabaseConnection(Constants::dbLocation, Constants::defaultDbName);
|
||||
conn->connect();
|
||||
}
|
||||
catch (FileError& err) {
|
||||
|
|
|
@ -10,11 +10,11 @@
|
|||
|
||||
static Codeblock fromJson(QJsonObject obj) {
|
||||
Codeblock rtn;
|
||||
rtn.content = obj["content"].toVariant().toString();
|
||||
rtn.subtype = obj["contentSubtype"].toString();
|
||||
QJsonObject meta = obj["metadata"].toObject();
|
||||
rtn.content = obj.value(QStringLiteral("content")).toVariant().toString();
|
||||
rtn.subtype = obj.value(QStringLiteral("contentSubtype")).toString();
|
||||
QJsonObject meta = obj.value(QStringLiteral("metadata")).toObject();
|
||||
if (!meta.empty()) {
|
||||
rtn.source = meta["source"].toString();
|
||||
rtn.source = obj.value(QStringLiteral("source")).toString();
|
||||
}
|
||||
|
||||
return rtn;
|
||||
|
|
|
@ -30,7 +30,7 @@ void SystemManifest::migrateConfig() {
|
|||
}
|
||||
}
|
||||
AppConfig::getInstance().applyConfig(src);
|
||||
return "";
|
||||
return QString();
|
||||
});
|
||||
AppConfig::getInstance().writeConfig(); // save updated config
|
||||
}
|
||||
|
|
|
@ -317,7 +317,7 @@ QIcon TrayManager::getTrayIcon()
|
|||
void TrayManager::onTrayMessageClicked() {
|
||||
switch(currentTrayMessage) {
|
||||
case UPGRADE:
|
||||
QDesktopServices::openUrl(Constants::releasePageUrl());
|
||||
QDesktopServices::openUrl(Constants::releasePageUrl);
|
||||
break;
|
||||
case OPEN_PATH:
|
||||
QDesktopServices::openUrl(openServicesPath);
|
||||
|
|
Loading…
Reference in New Issue