From c2e60cd3de185dd044ae5bf95b30919859dd0838 Mon Sep 17 00:00:00 2001 From: Ralf Date: Mon, 8 Sep 2025 10:55:29 +0300 Subject: [PATCH] Terminal tasks saver --- .../Headers/Client/AxScript/AxScriptEngine.h | 2 +- AdaptixClient/Headers/Client/Requestor.h | 2 + .../Headers/UI/Dialogs/DialogSaveTask.h | 43 +++++++ .../Headers/UI/Widgets/TerminalWidget.h | 33 +++--- .../Source/Client/AxScript/AxScriptEngine.cpp | 16 +-- .../Source/Client/AxScript/BridgeEvent.cpp | 2 +- AdaptixClient/Source/Client/Requestor.cpp | 20 ++++ .../Source/UI/Dialogs/DialogSaveTask.cpp | 105 ++++++++++++++++++ .../Source/UI/Widgets/TerminalWidget.cpp | 56 +++++++--- 9 files changed, 238 insertions(+), 41 deletions(-) create mode 100644 AdaptixClient/Headers/UI/Dialogs/DialogSaveTask.h create mode 100644 AdaptixClient/Source/UI/Dialogs/DialogSaveTask.cpp diff --git a/AdaptixClient/Headers/Client/AxScript/AxScriptEngine.h b/AdaptixClient/Headers/Client/AxScript/AxScriptEngine.h index 01574762..27459170 100644 --- a/AdaptixClient/Headers/Client/AxScript/AxScriptEngine.h +++ b/AdaptixClient/Headers/Client/AxScript/AxScriptEngine.h @@ -40,7 +40,7 @@ struct ScriptContext { QList eventFileBroserDisks; QList eventFileBroserList; - QList eventFileBroserUpload; + QList eventFileBrowserUpload; QList eventProcessBrowserList; QList eventNewAgent; QList eventReady; diff --git a/AdaptixClient/Headers/Client/Requestor.h b/AdaptixClient/Headers/Client/Requestor.h index 19263f62..d70d6703 100644 --- a/AdaptixClient/Headers/Client/Requestor.h +++ b/AdaptixClient/Headers/Client/Requestor.h @@ -53,6 +53,8 @@ bool HttpReqTasksDelete(const QString &agentId, QStringList tasksId, AuthProfile bool HttpReqTasksHook(const QByteArray &jsonData, AuthProfile profile, QString* message, bool* ok); +bool HttpReqTasksSave(const QString &agentId, const QString &CommandLine, int MessageType, const QString &Message, const QString &ClearText, AuthProfile profile, QString* message, bool* ok ); + ///CHAT bool HttpReqChatSendMessage(const QString &text, AuthProfile profile, QString* message, bool* ok ); diff --git a/AdaptixClient/Headers/UI/Dialogs/DialogSaveTask.h b/AdaptixClient/Headers/UI/Dialogs/DialogSaveTask.h new file mode 100644 index 00000000..17c912fd --- /dev/null +++ b/AdaptixClient/Headers/UI/Dialogs/DialogSaveTask.h @@ -0,0 +1,43 @@ +#ifndef ADAPTIXCLIENT_DIALOGSAVETASK_H +#define ADAPTIXCLIENT_DIALOGSAVETASK_H + +#include + +class DialogSaveTask : public QDialog +{ + QGridLayout* mainGridLayout = nullptr; + QLabel* commandLineLabel = nullptr; + QLineEdit* commandLineInput = nullptr; + QLabel* messageLabel = nullptr; + QComboBox* messageCombo = nullptr; + QLineEdit* messageInput = nullptr; + QLabel* textLabel = nullptr; + QTextEdit* textEdit = nullptr; + QHBoxLayout* hLayoutBottom = nullptr; + QSpacerItem* spacer_1 = nullptr; + QSpacerItem* spacer_2 = nullptr; + QPushButton* createButton = nullptr; + QPushButton* cancelButton = nullptr; + + bool valid = false; + QString message = ""; + QString credsId = ""; + TaskData data = {}; + + void createUI(); + +public: + explicit DialogSaveTask(); + ~DialogSaveTask() override; + + void StartDialog(const QString &text); + bool IsValid() const; + QString GetMessage() const; + TaskData GetData() const; + +protected slots: + void onButtonSave(); + void onButtonCancel(); +}; + +#endif //ADAPTIXCLIENT_DIALOGSAVETASK_H \ No newline at end of file diff --git a/AdaptixClient/Headers/UI/Widgets/TerminalWidget.h b/AdaptixClient/Headers/UI/Widgets/TerminalWidget.h index 482d6aee..6afbbfd8 100644 --- a/AdaptixClient/Headers/UI/Widgets/TerminalWidget.h +++ b/AdaptixClient/Headers/UI/Widgets/TerminalWidget.h @@ -7,24 +7,25 @@ class Agent; class Konsole; class QTermWidget; class TerminalWorker; +class AdaptixWidget; class TerminalWidget : public QWidget { - QWidget* mainWidget = nullptr; - QGridLayout* mainGridLayout = nullptr; - QHBoxLayout* topHBoxLayout = nullptr; - QLabel* statusDescLabel = nullptr; - QLabel* statusLabel = nullptr; - QFrame* line_1 = nullptr; - QFrame* line_2 = nullptr; - QFrame* line_3 = nullptr; - QPushButton* startButton = nullptr; - QPushButton* stopButton = nullptr; - QComboBox* programComboBox = nullptr; - QLabel* keytabLabel = nullptr; - QComboBox* keytabComboBox = nullptr; - QLineEdit* programInput = nullptr; - QSpacerItem* spacer = nullptr; + AdaptixWidget* adaptixWidget = nullptr; + QGridLayout* mainGridLayout = nullptr; + QHBoxLayout* topHBoxLayout = nullptr; + QLabel* statusDescLabel = nullptr; + QLabel* statusLabel = nullptr; + QFrame* line_1 = nullptr; + QFrame* line_2 = nullptr; + QFrame* line_3 = nullptr; + QPushButton* startButton = nullptr; + QPushButton* stopButton = nullptr; + QComboBox* programComboBox = nullptr; + QLabel* keytabLabel = nullptr; + QComboBox* keytabComboBox = nullptr; + QLineEdit* programInput = nullptr; + QSpacerItem* spacer = nullptr; QTermWidget* termWidget = nullptr; @@ -40,7 +41,7 @@ class TerminalWidget : public QWidget void SetKeys(); public: - explicit TerminalWidget(Agent* a, QWidget* w); + explicit TerminalWidget(Agent* a, AdaptixWidget* w); ~TerminalWidget() override; void setStatus(const QString& text); diff --git a/AdaptixClient/Source/Client/AxScript/AxScriptEngine.cpp b/AdaptixClient/Source/Client/AxScript/AxScriptEngine.cpp index b8874963..47718233 100644 --- a/AdaptixClient/Source/Client/AxScript/AxScriptEngine.cpp +++ b/AdaptixClient/Source/Client/AxScript/AxScriptEngine.cpp @@ -80,7 +80,7 @@ void AxScriptEngine::registerEvent(const QString &type, const QJSValue &handler, if ( type == "FileBroserDisks") context.eventFileBroserDisks.append(event); else if (type == "FileBroserList") context.eventFileBroserList.append(event); - else if (type == "FileBroserUpload") context.eventFileBroserUpload.append(event); + else if (type == "FileBrowserUpload") context.eventFileBrowserUpload.append(event); else if (type == "ProcessBrowserList") context.eventProcessBrowserList.append(event); else if (type == "new_agent") context.eventNewAgent.append(event); else if (type == "ready") context.eventReady.append(event); @@ -92,7 +92,7 @@ QList AxScriptEngine::getEvents(const QString &type) { if ( type == "FileBroserDisks") return context.eventFileBroserDisks; else if (type == "FileBroserList") return context.eventFileBroserList; - else if (type == "FileBroserUpload") return context.eventFileBroserUpload; + else if (type == "FileBrowserUpload") return context.eventFileBrowserUpload; else if (type == "ProcessBrowserList") return context.eventProcessBrowserList; else if (type == "new_agent") return context.eventNewAgent; else if (type == "ready") return context.eventReady; @@ -118,9 +118,9 @@ void AxScriptEngine::removeEvent(const QString &id) i--; } } - for (int i=0; i< context.eventFileBroserUpload.size(); i++) { - if (id == context.eventFileBroserUpload[i].event_id) { - context.eventFileBroserUpload.removeAt(i); + for (int i=0; i< context.eventFileBrowserUpload.size(); i++) { + if (id == context.eventFileBrowserUpload[i].event_id) { + context.eventFileBrowserUpload.removeAt(i); i--; } } @@ -169,9 +169,9 @@ QStringList AxScriptEngine::listEvent() if (context.eventFileBroserList[i].event_id != "") list.append(context.eventFileBroserList[i].event_id); } - for (int i=0; i< context.eventFileBroserUpload.size(); i++) { - if (context.eventFileBroserUpload[i].event_id != "") - list.append(context.eventFileBroserUpload[i].event_id); + for (int i=0; i< context.eventFileBrowserUpload.size(); i++) { + if (context.eventFileBrowserUpload[i].event_id != "") + list.append(context.eventFileBrowserUpload[i].event_id); } for (int i=0; i< context.eventProcessBrowserList.size(); i++) { if (context.eventProcessBrowserList[i].event_id != "") diff --git a/AdaptixClient/Source/Client/AxScript/BridgeEvent.cpp b/AdaptixClient/Source/Client/AxScript/BridgeEvent.cpp index e1ae2ae2..49e6a487 100644 --- a/AdaptixClient/Source/Client/AxScript/BridgeEvent.cpp +++ b/AdaptixClient/Source/Client/AxScript/BridgeEvent.cpp @@ -55,7 +55,7 @@ void BridgeEvent::on_filebrowser_list(const QJSValue &handler, const QJSValue &a } void BridgeEvent::on_filebrowser_upload(const QJSValue &handler, const QJSValue &agents, const QJSValue &os, const QJSValue &listeners, const QString &event_id) { - this->reg("FileBroserUpload", "on_filebrowser_upload", handler, agents, os, listeners, event_id); + this->reg("FileBrowserUpload", "on_filebrowser_upload", handler, agents, os, listeners, event_id); } void BridgeEvent::on_processbrowser_list(const QJSValue &handler, const QJSValue &agents, const QJSValue &os, const QJSValue &listeners, const QString &event_id) { diff --git a/AdaptixClient/Source/Client/Requestor.cpp b/AdaptixClient/Source/Client/Requestor.cpp index c775e5ef..db44e612 100644 --- a/AdaptixClient/Source/Client/Requestor.cpp +++ b/AdaptixClient/Source/Client/Requestor.cpp @@ -397,6 +397,26 @@ bool HttpReqTasksDelete(const QString &agentId, QStringList tasksId, AuthProfile return false; } +bool HttpReqTasksSave(const QString &agentId, const QString &CommandLine, const int MessageType, const QString &Message, const QString &ClearText, AuthProfile profile, QString* message, bool* ok ) +{ + QJsonObject dataJson; + dataJson["agent_id"] = agentId; + dataJson["command_line"] = CommandLine; + dataJson["message_type"] = MessageType; + dataJson["message"] = Message; + dataJson["clear_text"] = ClearText; + QByteArray jsonData = QJsonDocument(dataJson).toJson(); + + QString sUrl = profile.GetURL() + "/agent/task/save"; + QJsonObject jsonObject = HttpReq(sUrl, jsonData, profile.GetAccessToken()); + if ( jsonObject.contains("message") && jsonObject.contains("ok") ) { + *message = jsonObject["message"].toString(); + *ok = jsonObject["ok"].toBool(); + return true; + } + return false; +} + bool HttpReqTasksHook(const QByteArray &jsonData, AuthProfile profile, QString* message, bool* ok) { QString sUrl = profile.GetURL() + "/agent/task/hook"; diff --git a/AdaptixClient/Source/UI/Dialogs/DialogSaveTask.cpp b/AdaptixClient/Source/UI/Dialogs/DialogSaveTask.cpp new file mode 100644 index 00000000..fe3f68ea --- /dev/null +++ b/AdaptixClient/Source/UI/Dialogs/DialogSaveTask.cpp @@ -0,0 +1,105 @@ +#include + +DialogSaveTask::DialogSaveTask() +{ + this->createUI(); + + connect(createButton, &QPushButton::clicked, this, &DialogSaveTask::onButtonSave); + connect(cancelButton, &QPushButton::clicked, this, &DialogSaveTask::onButtonCancel); +} + +DialogSaveTask::~DialogSaveTask() = default; + +void DialogSaveTask::createUI() +{ + this->resize(900, 500); + this->setWindowTitle( "Save Task" ); + + commandLineLabel = new QLabel("CommandLine:", this); + commandLineInput = new QLineEdit(this); + + messageLabel = new QLabel("Message:", this); + messageCombo = new QComboBox(this); + messageCombo->addItems(QStringList() << "Success" << "Error" ); + messageInput = new QLineEdit(this); + + textLabel = new QLabel("Output:", this); + textEdit = new QTextEdit(this); + + spacer_1 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Maximum); + spacer_2 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Maximum); + + createButton = new QPushButton("Save", this); + createButton->setProperty("ButtonStyle", "dialog"); + cancelButton = new QPushButton("Cancel", this); + cancelButton->setProperty("ButtonStyle", "dialog"); + + hLayoutBottom = new QHBoxLayout(); + hLayoutBottom->addItem(spacer_1); + hLayoutBottom->addWidget(createButton); + hLayoutBottom->addWidget(cancelButton); + hLayoutBottom->addItem(spacer_2); + + mainGridLayout = new QGridLayout(this); + mainGridLayout->setContentsMargins(4, 4, 4, 4 ); + mainGridLayout->addWidget(commandLineLabel, 0, 0, 1, 1); + mainGridLayout->addWidget(commandLineInput, 0, 1, 1, 2); + mainGridLayout->addWidget(messageLabel, 1, 0, 1, 1); + mainGridLayout->addWidget(messageCombo, 1, 1, 1, 1); + mainGridLayout->addWidget(messageInput, 1, 2, 1, 1); + mainGridLayout->addWidget(textLabel, 2, 0, 1, 1); + mainGridLayout->addWidget(textEdit, 2, 1, 1, 2); + mainGridLayout->addLayout(hLayoutBottom, 3, 0, 1, 3); + + int buttonWidth = createButton->width(); + createButton->setFixedWidth(buttonWidth); + cancelButton->setFixedWidth(buttonWidth); + + int buttonHeight = createButton->height(); + createButton->setFixedHeight(buttonHeight); + cancelButton->setFixedHeight(buttonHeight); +} + +void DialogSaveTask::StartDialog(const QString &text) +{ + QString firstLine = text.section('\n', 0, 0); + QString restLines = text.section('\n', 1); + + commandLineInput->setText(firstLine); + messageInput->setText("Remote Terminal output"); + textEdit->setText(restLines); + + this->valid = false; + this->message = ""; + this->exec(); +} + +bool DialogSaveTask::IsValid() const { return this->valid; } + +QString DialogSaveTask::GetMessage() const { return this->message; } + +TaskData DialogSaveTask::GetData() const { return this->data; } + +void DialogSaveTask::onButtonSave() +{ + QString commandLine = commandLineInput->text(); + if (commandLine.isEmpty()) { + this->valid = false; + return; + } + + int type = 7; + if (messageCombo->currentText() == "Error") + type = 6; + + data = {}; + data.CommandLine = commandLine; + data.MessageType = type; + data.Message = messageInput->text(); + data.Output = textEdit->toPlainText(); + + this->valid = true; + this->close(); +} + +void DialogSaveTask::onButtonCancel() { this->close(); } \ No newline at end of file diff --git a/AdaptixClient/Source/UI/Widgets/TerminalWidget.cpp b/AdaptixClient/Source/UI/Widgets/TerminalWidget.cpp index aa3f2928..77853a19 100644 --- a/AdaptixClient/Source/UI/Widgets/TerminalWidget.cpp +++ b/AdaptixClient/Source/UI/Widgets/TerminalWidget.cpp @@ -1,16 +1,18 @@ #include #include #include +#include #include #include #include #include +#include #include -TerminalWidget::TerminalWidget(Agent* a, QWidget* w) +TerminalWidget::TerminalWidget(Agent* a, AdaptixWidget* w) { this->agent = a; - this->mainWidget = w; + this->adaptixWidget = w; this->termWidget = new QTermWidget(this, this); this->createUI(); @@ -212,6 +214,38 @@ void TerminalWidget::handleTerminalMenu(const QPoint &pos) termWidget->setHistorySize(newSize); }); + QAction *saveToTasksAction = menu.addAction("Save to Tasks Manager"); + connect(saveToTasksAction, &QAction::triggered, this, [this]() { + QString text = termWidget->selectedText(); + + DialogSaveTask* dialogTask = new DialogSaveTask(); + while (true) { + dialogTask->StartDialog(text); + if (dialogTask->IsValid()) + break; + + QString msg = dialogTask->GetMessage(); + if (msg.isEmpty()) { + delete dialogTask; + return; + } + + MessageError(msg); + } + + TaskData taskData = dialogTask->GetData(); + delete dialogTask; + + QString message = ""; + bool ok = false; + bool result = HttpReqTasksSave(agent->data.Id, taskData.CommandLine, taskData.MessageType, taskData.Message, taskData.Output, *(adaptixWidget->GetProfile()), &message, &ok); + if( !result ) { + MessageError("Server is not responding"); + return; + } + if (!ok) MessageError(message); + }); + menu.exec(this->termWidget->mapToGlobal(pos)); } @@ -233,16 +267,15 @@ void TerminalWidget::SetKeys() void TerminalWidget::onStart() { + if ( !adaptixWidget ) + return; + programInput->setEnabled(false); programComboBox->setEnabled(false); startButton->setEnabled(false); stopButton->setEnabled(true); this->setStatus("Waiting..."); - auto adaptixWidget = qobject_cast( mainWidget ); - if ( !adaptixWidget ) - return; - auto profile = adaptixWidget->GetProfile(); QString urlTemplate = "wss://%1:%2%3/channel"; @@ -284,7 +317,6 @@ void TerminalWidget::onRestart() void TerminalWidget::onStop() { - if (!terminalWorker || !terminalThread) return; @@ -336,12 +368,6 @@ void TerminalWidget::onProgramChanged() } } -void TerminalWidget::onKeytabChanged() -{ - termWidget->setKeyBindings(keytabComboBox->currentText()); -} +void TerminalWidget::onKeytabChanged() { termWidget->setKeyBindings(keytabComboBox->currentText()); } -void TerminalWidget::recvDataFromSocket(const QByteArray &msg) -{ - this->termWidget->recvData(msg.constData(), msg.size()); -} +void TerminalWidget::recvDataFromSocket(const QByteArray &msg) { this->termWidget->recvData(msg.constData(), msg.size()); }