diff --git a/AdaptixClient/Headers/Agent/Commander.h b/AdaptixClient/Headers/Agent/Commander.h index d04a6fb7..757c2162 100644 --- a/AdaptixClient/Headers/Agent/Commander.h +++ b/AdaptixClient/Headers/Agent/Commander.h @@ -38,6 +38,7 @@ struct Command struct CommandsGroup { QString groupName; + QString filepath; QList commands; QJSEngine* engine; }; @@ -51,8 +52,10 @@ struct CommanderResult bool hooked; }; -class Commander +class Commander : public QObject { +Q_OBJECT + QString agentType; QString listenerType; QString error; @@ -60,24 +63,24 @@ class Commander CommandsGroup regCommandsGroup; QVector axCommandsGroup; - void ProcessPreHook(QJSEngine *engine, const QString &agentId, const Command &command, const QString &cmdline, QStringList args); + QString ProcessPreHook(QJSEngine *engine, const Command &command, const QString &agentId, const QString &cmdline, const QJsonObject &jsonObj, QStringList args); CommanderResult ProcessCommand(Command command, QStringList args, QJsonObject jsonObj); CommanderResult ProcessHelp(QStringList commandParts); public: explicit Commander(); - ~Commander(); + ~Commander() override; void AddRegCommands(const CommandsGroup &group); - void AddAxCommands(const QString &groupName, const QList &axCommands, QJSEngine *engine); + void AddAxCommands(const CommandsGroup &group); + void RemoveAxCommands(const QString &filepath); QString GetError(); QStringList GetCommands(); CommanderResult ProcessInput(QString agentId, QString cmdline); - - - void RemoveAxCommands(const QString &filepath); +signals: + void commandsUpdated(); }; -#endif //ADAPTIXCLIENT_COMMANDER_H +#endif diff --git a/AdaptixClient/Headers/Client/AxScript/AxCommandWrappers.h b/AdaptixClient/Headers/Client/AxScript/AxCommandWrappers.h index f68c49de..abdc25c5 100644 --- a/AdaptixClient/Headers/Client/AxScript/AxCommandWrappers.h +++ b/AdaptixClient/Headers/Client/AxScript/AxCommandWrappers.h @@ -36,7 +36,7 @@ public: Q_INVOKABLE void setPreHook(const QJSValue& handler); signals: - void consoleError(const QString &msg); + void scriptError(const QString &msg); }; @@ -51,8 +51,9 @@ Q_OBJECT QJSEngine* engine; public: - explicit AxCommandGroupWrapper(const QString &name, const QJSValue& array, QJSEngine* engine, QObject* parent = nullptr); + explicit AxCommandGroupWrapper(QJSEngine* engine, QObject* parent = nullptr); + void SetParams(const QString &name, const QJSValue& array); QString getName() const; QList getCommands() const; QJSEngine* getEngine() const; @@ -60,7 +61,7 @@ public: Q_INVOKABLE void add(const QJSValue& array); signals: - void consoleError(const QString &msg); + void scriptError(const QString &msg); }; #endif diff --git a/AdaptixClient/Headers/Client/AxScript/AxScriptEngine.h b/AdaptixClient/Headers/Client/AxScript/AxScriptEngine.h index 24940c47..fd1a2804 100644 --- a/AdaptixClient/Headers/Client/AxScript/AxScriptEngine.h +++ b/AdaptixClient/Headers/Client/AxScript/AxScriptEngine.h @@ -64,6 +64,9 @@ public: bool execute(const QString &code); QList getMenuItems(const QString &type); + +public slots: + void engineError(const QString &message); }; -#endif //AXSCRIPTENGINE_H +#endif diff --git a/AdaptixClient/Headers/Client/AxScript/AxScriptManager.h b/AdaptixClient/Headers/Client/AxScript/AxScriptManager.h index dd1bb499..bbd47604 100644 --- a/AdaptixClient/Headers/Client/AxScript/AxScriptManager.h +++ b/AdaptixClient/Headers/Client/AxScript/AxScriptManager.h @@ -4,8 +4,10 @@ #include #include #include +#include class AxScriptEngine; +class ExtensionFile; class AdaptixWidget; class Agent; @@ -31,19 +33,21 @@ public: QStringList ListenerScriptList(); void ListenerScriptAdd(const QString &name, const QString &ax_script); QJSEngine* ListenerScriptEngine(const QString &name); + QStringList AgentScriptList(); void AgentScriptAdd(const QString &name, const QString &ax_script); QJSEngine* AgentScriptEngine(const QString &name); + QJSValue AgentScriptExecute(const QString &name, const QString &code); - //// + QStringList ScriptList(); + bool ScriptAdd(ExtensionFile* ext); + void ScriptRemove(const ExtensionFile &ext); - void ScriptAdd(const QString &name, AxScriptEngine* script); - void ScriptRemove(const QString &name); - // void ExScriptRemove(const QString &name); + void GlobalScriptLoad(const QString &path); + void GlobalScriptUnload(const QString &path); - QJSValue AgentScriptExecute(const QString &name, const QString &code); - - int AddMenuSession(QMenu* menu, const QString &menuType, QStringList agentIds) const; + void RegisterCommandsGroup(const CommandsGroup &group, const QStringList &listeners, const QStringList &agents, const QList &os); + int AddMenuSession(QMenu* menu, const QString &menuType, QStringList agentIds) const; void emitAllEventTestClick(); @@ -52,4 +56,4 @@ public slots: void consolePrintError(const QString &message); }; -#endif //AXSCRIPTMANAGER_H +#endif diff --git a/AdaptixClient/Headers/Client/AxScript/BridgeApp.h b/AdaptixClient/Headers/Client/AxScript/BridgeApp.h index 97eca632..b555ea46 100644 --- a/AdaptixClient/Headers/Client/AxScript/BridgeApp.h +++ b/AdaptixClient/Headers/Client/AxScript/BridgeApp.h @@ -20,13 +20,16 @@ public: public slots: QJSValue agents() const; - QString bof_pack(const QString &types, const QJSValue &args) const; + QString arch(const QString &id) const; + QString bof_pack(const QString &types, const QJSValue &args); void console_message(const QString &id, const QString &message, const QString &type = "", const QString &text = ""); void credentials_add(const QString &username, const QString &password, const QString &realm = "", const QString &type = "password", const QString &tag = "", const QString &storage = "manual", const QString &host = ""); QObject* create_command(const QString &name, const QString &description, const QString &example = "", const QString &message = ""); QObject* create_commands_group(const QString &name, const QJSValue& array); - void execute_alias(const QString &id, const QString &cmdline, const QString &command) const; + void execute_alias(const QString &id, const QString &cmdline, const QString &command, const QString &message = "") const; void execute_command(const QString &id, const QString &command) const; + QString file_basename(const QString &path) const; + QString file_read(QString path) const; bool is64(const QString &id) const; void log(const QString &text); void log_error(const QString &text); @@ -34,11 +37,15 @@ public slots: void open_browser_files(const QString &id); void open_browser_process(const QString &id); void open_browser_terminal(const QString &id); - void register_commands_group(QObject* obj, const QJSValue& os, const QJSValue& agents, const QJSValue& listeners) const; + void register_commands_group(QObject* obj, const QJSValue& agents, const QJSValue& os, const QJSValue& listeners); + void script_load(const QString &path); + void script_unload(const QString &path); + QString script_dir(); signals: void consoleMessage(const QString &msg); void consoleError(const QString &msg); + void engineError(const QString &msg); }; -#endif //BRIDGEAPP_H +#endif diff --git a/AdaptixClient/Headers/Client/AxScript/BridgeEvent.h b/AdaptixClient/Headers/Client/AxScript/BridgeEvent.h index cca4b17f..0d491103 100644 --- a/AdaptixClient/Headers/Client/AxScript/BridgeEvent.h +++ b/AdaptixClient/Headers/Client/AxScript/BridgeEvent.h @@ -23,7 +23,7 @@ public slots: void emitEventTestClick(); signals: - void consoleError(const QString &msg); + void scriptError(const QString &msg); }; #endif diff --git a/AdaptixClient/Headers/Client/AxScript/BridgeForm.h b/AdaptixClient/Headers/Client/AxScript/BridgeForm.h index c76cc48b..82c75270 100644 --- a/AdaptixClient/Headers/Client/AxScript/BridgeForm.h +++ b/AdaptixClient/Headers/Client/AxScript/BridgeForm.h @@ -47,7 +47,7 @@ public slots: QObject* create_dialog(const QString &title) const; signals: - void consoleError(const QString &msg); + void scriptError(const QString &msg); }; diff --git a/AdaptixClient/Headers/Client/Extender.h b/AdaptixClient/Headers/Client/Extender.h index 56a62de3..1d4a13ce 100644 --- a/AdaptixClient/Headers/Client/Extender.h +++ b/AdaptixClient/Headers/Client/Extender.h @@ -6,23 +6,29 @@ class DialogExtender; class MainAdaptix; -class Extender +class Extender : public QObject { +Q_OBJECT MainAdaptix* mainAdaptix = nullptr; public: explicit Extender(MainAdaptix* m); - ~Extender(); + ~Extender() override; DialogExtender* dialogExtender = nullptr; QMap extenderFiles; void LoadFromDB(); - void LoadFromFile(QString path, bool enabled); - void SetExtension(const ExtensionFile &extFile ); + void LoadFromFile(const QString &path, bool enabled); + void SetExtension(ExtensionFile extFile ); void EnableExtension(const QString &path); void DisableExtension(const QString &path); void RemoveExtension(const QString &path); + +public slots: + void syncedOnReload(QString project); + void loadGlobalScript(const QString &path); + void unloadGlobalScript(const QString &path); }; -#endif //ADAPTIXCLIENT_EXTENDER_H +#endif diff --git a/AdaptixClient/Headers/UI/Dialogs/DialogSettings.h b/AdaptixClient/Headers/UI/Dialogs/DialogSettings.h index c9dfff9b..46333174 100644 --- a/AdaptixClient/Headers/UI/Dialogs/DialogSettings.h +++ b/AdaptixClient/Headers/UI/Dialogs/DialogSettings.h @@ -72,5 +72,4 @@ public slots: void onClose(); }; - #endif \ No newline at end of file diff --git a/AdaptixClient/Headers/UI/MainUI.h b/AdaptixClient/Headers/UI/MainUI.h index 66a6d244..9216152b 100644 --- a/AdaptixClient/Headers/UI/MainUI.h +++ b/AdaptixClient/Headers/UI/MainUI.h @@ -11,7 +11,7 @@ class MainUI : public QMainWindow { QTabWidget* mainuiTabWidget = nullptr; - QMap AdaptixProjects; + QVector AdaptixProjects; public: explicit MainUI(); @@ -26,7 +26,7 @@ public: void AddNewProject(AuthProfile* profile, QThread* channelThread, WebSocketWorker* channelWsWorker); - void AddNewExtension(const ExtensionFile &extFile); + bool AddNewExtension(ExtensionFile *extFile); void RemoveExtension(const ExtensionFile &extFile); void UpdateSessionsTableColumns(); diff --git a/AdaptixClient/Headers/UI/Widgets/AdaptixWidget.h b/AdaptixClient/Headers/UI/Widgets/AdaptixWidget.h index 62e94df8..aa3a19f8 100644 --- a/AdaptixClient/Headers/UI/Widgets/AdaptixWidget.h +++ b/AdaptixClient/Headers/UI/Widgets/AdaptixWidget.h @@ -100,7 +100,6 @@ public: QMap TasksMap; QVector AgentsVector; QMap AgentsMap; - QMap Extensions; QMap ClientTunnels; explicit AdaptixWidget(AuthProfile* authProfile, QThread* channelThread, WebSocketWorker* channelWsWorker); @@ -110,15 +109,17 @@ public: void AddTab(QWidget* tab, const QString &title, const QString &icon = "" ) const; void RemoveTab(int index) const; - void AddExtension(ExtensionFile ext); + bool AddExtension(ExtensionFile* ext); void RemoveExtension(const ExtensionFile &ext); void Close(); void ClearAdaptix(); void RegisterListenerConfig(const QString &fn, const QString &ax_script); - void RegisterAgentConfig(const QString &agentName, const QString &watermark, const QString &ax_script, const QStringList &listeners); + void RegisterAgentConfig(const QString &agentName, const QString &ax_script, const QStringList &listeners); QList GetAgentNames(const QString &listenerType) const; RegAgentConfig GetRegAgent(const QString &agentName, const QString &listenerName, int os); + QList GetCommanders(const QStringList &listeners, const QStringList &agents, const QList &os) const; + QList GetCommandersAll() const; void LoadConsoleUI(const QString &AgentId); void LoadTasksOutput() const; @@ -129,6 +130,9 @@ public: signals: void SyncedSignal(); + void SyncedOnReloadSignal(QString project); + void LoadGlobalScriptSignal(QString path); + void UnloadGlobalScriptSignal(QString path); public slots: void ChannelClose() const; diff --git a/AdaptixClient/Headers/UI/Widgets/AxConsoleWidget.h b/AdaptixClient/Headers/UI/Widgets/AxConsoleWidget.h index f9738caf..d271e385 100644 --- a/AdaptixClient/Headers/UI/Widgets/AxConsoleWidget.h +++ b/AdaptixClient/Headers/UI/Widgets/AxConsoleWidget.h @@ -14,10 +14,11 @@ class AxConsoleWidget : public QWidget AdaptixWidget* adaptixWidget = nullptr; AxScriptManager* scriptManager = nullptr; - QGridLayout* MainGridLayout = nullptr; - QLabel* CmdLabel = nullptr; - QLineEdit* InputLineEdit = nullptr; - TextEditConsole* OutputTextEdit = nullptr; + QGridLayout* MainGridLayout = nullptr; + QLabel* CmdLabel = nullptr; + QLineEdit* InputLineEdit = nullptr; + TextEditConsole* OutputTextEdit = nullptr; + QPushButton* ResetButton = nullptr; QWidget* searchWidget = nullptr; QHBoxLayout* searchLayout = nullptr; @@ -44,7 +45,6 @@ public: void InputFocus() const; void AddToHistory(const QString& command); -// void Clear(); void PrintMessage(const QString& message); void PrintError(const QString& message); @@ -54,6 +54,7 @@ public slots: void handleSearch(); void handleSearchBackward(); void handleShowHistory(); + void onResetScript(); }; #endif diff --git a/AdaptixClient/Headers/main.h b/AdaptixClient/Headers/main.h index 60a915a9..988f7a74 100644 --- a/AdaptixClient/Headers/main.h +++ b/AdaptixClient/Headers/main.h @@ -322,8 +322,12 @@ typedef struct ExtensionFile { QString Name; QString FilePath; + QString Code; QString Description; + QString Message; bool Enabled; + bool NoSave; + bool Valid; QMap > ExCommands; } ExtensionFile; diff --git a/AdaptixClient/Source/Agent/Commander.cpp b/AdaptixClient/Source/Agent/Commander.cpp index f33dcba9..339ea0c0 100644 --- a/AdaptixClient/Source/Agent/Commander.cpp +++ b/AdaptixClient/Source/Agent/Commander.cpp @@ -83,15 +83,20 @@ Commander::~Commander() = default; void Commander::AddRegCommands(const CommandsGroup &group) { regCommandsGroup = group; } -void Commander::AddAxCommands(const QString &groupName, const QList &axCommands, QJSEngine *engine) -{ - CommandsGroup newGroup = {groupName, axCommands}; - axCommandsGroup.append(newGroup); +void Commander::AddAxCommands(const CommandsGroup &group) { + axCommandsGroup.append(group); + emit commandsUpdated(); } void Commander::RemoveAxCommands(const QString &filepath) { - // extModules.remove(filepath); + for (int i = 0; i < axCommandsGroup.size(); ++i) { + if (axCommandsGroup[i].filepath == filepath) { + axCommandsGroup.removeAt(i); + i--; + } + } + emit commandsUpdated(); } CommanderResult Commander::ProcessInput(QString agentId, QString cmdline) @@ -113,7 +118,20 @@ CommanderResult Commander::ProcessInput(QString agentId, QString cmdline) jsonObj["command"] = command.name; if ( command.subcommands.isEmpty() ) { - return ProcessCommand(command, parts, jsonObj); + + auto cmdResult = ProcessCommand(command, parts, jsonObj); + if ( !cmdResult.output && command.is_pre_hook) { + QString hook_result = ProcessPreHook(script_group.engine, command, agentId, cmdline, cmdResult.data, parts); + if (hook_result.isEmpty()) { + return CommanderResult{false, false, "", {}, true }; + } else { + cmdResult.output = true; + cmdResult.error = true; + cmdResult.message = hook_result; + } + } + return cmdResult; + } else { if ( parts.isEmpty() ) @@ -126,10 +144,20 @@ CommanderResult Commander::ProcessInput(QString agentId, QString cmdline) if (subCommandName == subcommand.name) { jsonObj["subcommand"] = subcommand.name; - return ProcessCommand(subcommand, parts, jsonObj); + auto cmdResult = ProcessCommand(subcommand, parts, jsonObj); + if ( !cmdResult.output && subcommand.is_pre_hook) { + QString hook_result = ProcessPreHook(script_group.engine, subcommand, agentId, cmdline, cmdResult.data, parts); + if (hook_result.isEmpty()) { + return CommanderResult{false, false, "", {}, true }; + } else { + cmdResult.output = true; + cmdResult.error = true; + cmdResult.message = hook_result; + } + } + return cmdResult; } } - return CommanderResult{true, true, "Subcommand not found"}; } } @@ -142,12 +170,20 @@ CommanderResult Commander::ProcessInput(QString agentId, QString cmdline) jsonObj["command"] = command.name; if ( command.subcommands.isEmpty() ) { - if (command.is_pre_hook) { - ProcessPreHook(regCommandsGroup.engine, agentId, command, cmdline, parts); - return CommanderResult{false, false, "", {}, true }; - } else { - return ProcessCommand(command, parts, jsonObj); + + auto cmdResult = ProcessCommand(command, parts, jsonObj); + if ( !cmdResult.output && command.is_pre_hook) { + QString hook_result = ProcessPreHook(regCommandsGroup.engine, command, agentId, cmdline, cmdResult.data, parts); + if (hook_result.isEmpty()) { + return CommanderResult{false, false, "", {}, true }; + } else { + cmdResult.output = true; + cmdResult.error = true; + cmdResult.message = hook_result; + } } + return cmdResult; + } else { if ( parts.isEmpty() ) return CommanderResult{true, true, "Subcommand must be set" }; @@ -159,15 +195,21 @@ CommanderResult Commander::ProcessInput(QString agentId, QString cmdline) if (subCommandName == subcommand.name) { jsonObj["subcommand"] = subcommand.name; - if (subcommand.is_pre_hook) { - ProcessPreHook(regCommandsGroup.engine, agentId, subcommand, cmdline, parts); - return CommanderResult{false, false, "", {}, true }; - } else { - return ProcessCommand(subcommand, parts, jsonObj); + auto cmdResult = ProcessCommand(subcommand, parts, jsonObj); + if ( !cmdResult.output && subcommand.is_pre_hook) { + QString hook_result = ProcessPreHook(regCommandsGroup.engine, subcommand, agentId, cmdline, cmdResult.data, parts); + if (hook_result.isEmpty()) { + return CommanderResult{false, false, "", {}, true }; + } else { + cmdResult.output = true; + cmdResult.error = true; + cmdResult.message = hook_result; + } + } + return cmdResult; } } - return CommanderResult{true, true, "Subcommand not found" }; } } @@ -176,23 +218,24 @@ CommanderResult Commander::ProcessInput(QString agentId, QString cmdline) return CommanderResult{true, true, "Command not found"}; } -void Commander::ProcessPreHook(QJSEngine *engine, const QString &agentId, const Command &command, const QString &cmdline, QStringList args) +QString Commander::ProcessPreHook(QJSEngine *engine, const Command &command, const QString &agentId, const QString &cmdline, const QJsonObject &jsonObj, QStringList args) { if (!engine) - return; + return "Ax Engine is not available"; QList jsArgs; jsArgs << engine->toScriptValue(agentId); jsArgs << engine->toScriptValue(cmdline); + jsArgs << engine->toScriptValue(jsonObj.toVariantMap()); for (const QString& arg : args) { jsArgs << engine->toScriptValue(arg); } QJSValue result = command.pre_hook.call(jsArgs); if (result.isError()) { - qWarning() << "JS error:" << result.property("message").toString(); - qWarning() << "Stack trace:" << result.property("stack").toString(); + return "Error: " + result.property("message").toString(); } + return ""; } CommanderResult Commander::ProcessCommand(Command command, QStringList args, QJsonObject jsonObj) diff --git a/AdaptixClient/Source/Client/AxScript/AxCommandWrappers.cpp b/AdaptixClient/Source/Client/AxScript/AxCommandWrappers.cpp index bc324d11..33297ae3 100644 --- a/AdaptixClient/Source/Client/AxScript/AxCommandWrappers.cpp +++ b/AdaptixClient/Source/Client/AxScript/AxCommandWrappers.cpp @@ -27,7 +27,7 @@ void AxCommandWrappers::addSubCommands(const QJSValue& value) command.subcommands.append(commandWrapper->getCommand()); } else { - emit consoleError("Item at index " + QString::number(i) + " is not an Command"); + emit scriptError("Item at index " + QString::number(i) + " is not an Command"); } } } @@ -37,7 +37,7 @@ void AxCommandWrappers::addSubCommands(const QJSValue& value) command.subcommands.append(commandWrapper->getCommand()); } else { - emit consoleError("Item is not an Command"); + emit scriptError("Item is not an Command"); } } @@ -135,20 +135,20 @@ void AxCommandWrappers::addArgFlagString(const QString &flag, const QString &nam void AxCommandWrappers::addArgFile(const QString &name, bool required, const QString &description) { - Argument arg = { "STRING", name, required, false, "", description, false, QVariant() }; + Argument arg = { "FILE", name, required, false, "", description, false, QVariant() }; command.args.append(arg); } void AxCommandWrappers::addArgFlagFile(const QString &flag, const QString &name, bool required, const QString &description) { - Argument arg = { "STRING", name, required, true, flag, description, false, QVariant() }; + Argument arg = { "FILE", name, required, true, flag, description, false, QVariant() }; command.args.append(arg); } void AxCommandWrappers::setPreHook(const QJSValue &handler) { if (!handler.isCallable()) { - emit consoleError("handler is not function"); + emit scriptError("handler is not function"); return; } @@ -157,12 +157,14 @@ void AxCommandWrappers::setPreHook(const QJSValue &handler) } -AxCommandGroupWrapper::AxCommandGroupWrapper(const QString &name, const QJSValue& array, QJSEngine* engine, QObject* parent) : QObject(parent), name(name) +AxCommandGroupWrapper::AxCommandGroupWrapper(QJSEngine* engine, QObject* parent) : QObject(parent), parent(parent), engine(engine) {} + +void AxCommandGroupWrapper::SetParams(const QString &name, const QJSValue &array) { - this->parent = parent; + this->name = name; if (array.isUndefined() || array.isNull() || !array.isArray()) { - emit consoleError("array is not the Command[]"); + emit scriptError("array is not the Command[]"); return; } @@ -174,11 +176,9 @@ AxCommandGroupWrapper::AxCommandGroupWrapper(const QString &name, const QJSValue if (auto* commandWrapper = qobject_cast(obj)) { this->commands.append(commandWrapper->getCommand()); } else { - emit consoleError("Item at index " + QString::number(i) + " is not an Command"); + emit scriptError("Item at index " + QString::number(i) + " is not an Command"); } } - - this->engine = engine; } QString AxCommandGroupWrapper::getName() const { return name; } @@ -200,7 +200,7 @@ void AxCommandGroupWrapper::add(const QJSValue &value) { if (auto* commandWrapper = qobject_cast(obj)) { this->commands.append(commandWrapper->getCommand()); } else { - emit consoleError("Item at index " + QString::number(i) + " is not an Command"); + emit scriptError("Item at index " + QString::number(i) + " is not an Command"); } } } @@ -209,7 +209,7 @@ void AxCommandGroupWrapper::add(const QJSValue &value) { if (auto* commandWrapper = qobject_cast(obj)) { this->commands.append(commandWrapper->getCommand()); } else { - emit consoleError("Item is not an Command"); + emit scriptError("Item is not an Command"); } } } diff --git a/AdaptixClient/Source/Client/AxScript/AxScriptEngine.cpp b/AdaptixClient/Source/Client/AxScript/AxScriptEngine.cpp index f000eec4..2c67f0f1 100644 --- a/AdaptixClient/Source/Client/AxScript/AxScriptEngine.cpp +++ b/AdaptixClient/Source/Client/AxScript/AxScriptEngine.cpp @@ -20,10 +20,11 @@ AxScriptEngine::AxScriptEngine(AxScriptManager* script_manager, const QString &n jsEngine->globalObject().setProperty("event", jsEngine->newQObject(bridgeEvent.get())); jsEngine->globalObject().setProperty("menu", jsEngine->newQObject(bridgeMenu.get())); - connect(bridgeEvent.get(), &BridgeEvent::consoleError, script_manager, &AxScriptManager::consolePrintError); - connect(bridgeForm.get(), &BridgeForm::consoleError, script_manager, &AxScriptManager::consolePrintError); connect(bridgeApp.get(), &BridgeApp::consoleError, script_manager, &AxScriptManager::consolePrintError); - connect(bridgeApp.get(), &BridgeApp::consoleError, script_manager, &AxScriptManager::consolePrintMessage); + connect(bridgeApp.get(), &BridgeApp::consoleMessage, script_manager, &AxScriptManager::consolePrintMessage); + connect(bridgeApp.get(), &BridgeApp::engineError, this, &AxScriptEngine::engineError); + connect(bridgeForm.get(), &BridgeForm::scriptError, this, &AxScriptEngine::engineError); + connect(bridgeEvent.get(), &BridgeEvent::scriptError, this, &AxScriptEngine::engineError); context.name = name; } @@ -91,20 +92,16 @@ QList AxScriptEngine::getMenuItems(const QString &type) return QList(); } +void AxScriptEngine::engineError(const QString &message) { engine()->throwError(QJSValue::TypeError, message); } + bool AxScriptEngine::execute(const QString &code) { QJSValue result = jsEngine->evaluate(code, context.name); + context.scriptObject = result; if (result.isError()) { - QString error = QStringLiteral("%1\n at line %2 in %3\n stack: %4") - .arg(result.toString()) - .arg(result.property("lineNumber").toInt()) - .arg(result.property("fileName").toString()) - .arg(result.property("stack").toString()); - + QString error = QStringLiteral("%1\n at line %2 in %3\n stack: %4\n").arg(result.toString()).arg(result.property("lineNumber").toInt()).arg(context.name).arg(result.property("stack").toString()); scriptManager->consolePrintError(error); - return false; } - context.scriptObject = result; return true; } diff --git a/AdaptixClient/Source/Client/AxScript/AxScriptManager.cpp b/AdaptixClient/Source/Client/AxScript/AxScriptManager.cpp index 7b6bb497..0fd103e2 100644 --- a/AdaptixClient/Source/Client/AxScript/AxScriptManager.cpp +++ b/AdaptixClient/Source/Client/AxScript/AxScriptManager.cpp @@ -6,8 +6,7 @@ #include #include -AxScriptManager::AxScriptManager(AdaptixWidget* main_widget, QObject *parent): QObject(parent), mainWidget(main_widget) -{ +AxScriptManager::AxScriptManager(AdaptixWidget* main_widget, QObject *parent): QObject(parent), mainWidget(main_widget) { mainScript = new AxScriptEngine(this, "main", this); } @@ -29,6 +28,10 @@ void AxScriptManager::Clear() void AxScriptManager::ResetMain() { + auto commanderList = mainWidget->GetCommandersAll(); + for (auto commander : commanderList) + commander->RemoveAxCommands(mainScript->context.name); + if (mainScript) delete mainScript; @@ -39,8 +42,6 @@ AdaptixWidget* AxScriptManager::GetAdaptix() const { return this->mainWidget; } QMap AxScriptManager::GetAgents() const { return mainWidget->AgentsMap; } - - /// MAIN QStringList AxScriptManager::ListenerScriptList() { return listeners_scripts.keys(); } @@ -62,6 +63,8 @@ QJSEngine* AxScriptManager::ListenerScriptEngine(const QString &name) return listeners_scripts[name]->engine(); } + + QStringList AxScriptManager::AgentScriptList() { return agents_scripts.keys(); } void AxScriptManager::AgentScriptAdd(const QString &name, const QString &ax_script) @@ -80,29 +83,6 @@ QJSEngine* AxScriptManager::AgentScriptEngine(const QString &name) return agents_scripts[name]->engine(); } -void AxScriptManager::ScriptAdd(const QString &name, AxScriptEngine* script) -{ - if (scripts.contains(name)) return; - scripts[name] = script; -} - -void AxScriptManager::ScriptRemove(const QString &name) -{ - if (!scripts.contains(name)) return; - auto scriptEngine = scripts.take(name); - delete scriptEngine; -} - -// void AxScriptManager::ExScriptRemove(const QString &name) -// { -// if (!ex_scripts.contains(name)) -// return; -// -// auto scriptEngine = ex_scripts.take(name); -// -// delete scriptEngine; -// } - QJSValue AxScriptManager::AgentScriptExecute(const QString &name, const QString &code) { QJSValue result; @@ -117,6 +97,55 @@ QJSValue AxScriptManager::AgentScriptExecute(const QString &name, const QString return result; } + + +QStringList AxScriptManager::ScriptList() { return scripts.keys(); } + +bool AxScriptManager::ScriptAdd(ExtensionFile* ext) +{ + AxScriptEngine* script = new AxScriptEngine(this, ext->FilePath, this); + scripts[ext->FilePath] = script; + bool result = script->execute(ext->Code); + if (result) { + QJSValue metadata = script->engine()->globalObject().property("metadata"); + if (metadata.isObject()) { + ext->Name = metadata.property("name").toString(); + ext->Description = metadata.property("description").toString(); + ext->NoSave = metadata.property("nosave").toBool(); + } + } + else { + ext->Enabled = false; + ext->Message = QString("%1\n at line %2 in %3").arg(script->context.scriptObject.toString()).arg(script->context.scriptObject.property("lineNumber").toInt()).arg(ext->FilePath); + } + return result; +} + +void AxScriptManager::ScriptRemove(const ExtensionFile &ext) +{ + auto scriptEngine = scripts.take(ext.FilePath); + + auto commanderList = mainWidget->GetCommandersAll(); + for (auto commander : commanderList) + commander->RemoveAxCommands(ext.FilePath); + + delete scriptEngine; +} + + + +void AxScriptManager::GlobalScriptLoad(const QString &path) { emit mainWidget->LoadGlobalScriptSignal(path); } + +void AxScriptManager::GlobalScriptUnload(const QString &path) { emit mainWidget->UnloadGlobalScriptSignal(path); } + +void AxScriptManager::RegisterCommandsGroup(const CommandsGroup &group, const QStringList &listeners, const QStringList &agents, const QList &os) +{ + auto commanderList = mainWidget->GetCommanders(listeners, agents, os); + for (auto commander : commanderList) + commander->AddAxCommands(group); +} + + /// MENU int AxScriptManager::AddMenuSession(QMenu *menu, const QString &menuType, QStringList agentIds) const @@ -184,6 +213,8 @@ void AxScriptManager::emitAllEventTestClick() } } +/// SLOTS + void AxScriptManager::consolePrintMessage(const QString &message) { this->mainWidget->AxConsoleTab->PrintMessage(message); } void AxScriptManager::consolePrintError(const QString &message) { this->mainWidget->AxConsoleTab->PrintError(message); } diff --git a/AdaptixClient/Source/Client/AxScript/BridgeApp.cpp b/AdaptixClient/Source/Client/AxScript/BridgeApp.cpp index 5907065c..6b463c53 100644 --- a/AdaptixClient/Source/Client/AxScript/BridgeApp.cpp +++ b/AdaptixClient/Source/Client/AxScript/BridgeApp.cpp @@ -8,6 +8,8 @@ #include #include +#include "MainAdaptix.h" + BridgeApp::BridgeApp(AxScriptEngine* scriptEngine, QObject* parent) : QObject(parent), scriptEngine(scriptEngine), widget(new QWidget()){} BridgeApp::~BridgeApp() { delete widget; } @@ -53,10 +55,18 @@ QJSValue BridgeApp::agents() const return this->scriptEngine->engine()->toScriptValue(list); } -QString BridgeApp::bof_pack(const QString &types, const QJSValue &args) const +QString BridgeApp::arch(const QString &id) const { + auto mapAgents = scriptEngine->manager()->GetAgents(); + if (!mapAgents.contains(id)) + return "x86"; + + return mapAgents[id]->data.Arch; +} + +QString BridgeApp::bof_pack(const QString &types, const QJSValue &args) { if (!args.isArray()) { - scriptEngine->engine()->throwError(QJSValue::TypeError, "bof_pack expected array of arguments!"); + emit engineError("bof_pack expected array of arguments!"); return ""; } @@ -64,7 +74,7 @@ QString BridgeApp::bof_pack(const QString &types, const QJSValue &args) const int length = args.property("length").toInt(); if (items.size() != length) { - scriptEngine->engine()->throwError(QJSValue::TypeError, "bof_pack expects the same number of types and arguments!"); + emit engineError("bof_pack expects the same number of types and arguments!"); return ""; } @@ -75,7 +85,7 @@ QString BridgeApp::bof_pack(const QString &types, const QJSValue &args) const if (items[i] == "cstr") { if (!value.canConvert()) { - scriptEngine->engine()->throwError(QJSValue::TypeError, QString("bof_pack cannot convert argument at index %1 to string").arg(i)); + emit engineError(QString("bof_pack cannot convert argument at index %1 to string").arg(i)); return ""; } @@ -94,7 +104,7 @@ QString BridgeApp::bof_pack(const QString &types, const QJSValue &args) const } else if (items[i] == "wstr") { if (!value.canConvert()) { - scriptEngine->engine()->throwError(QJSValue::TypeError, QString("bof_pack cannot convert argument at index %1 to string").arg(i)); + emit engineError(QString("bof_pack cannot convert argument at index %1 to string").arg(i)); return ""; } @@ -123,24 +133,22 @@ QString BridgeApp::bof_pack(const QString &types, const QJSValue &args) const } } else if (items[i] == "bytes") { - if (!value.canConvert()) { - scriptEngine->engine()->throwError(QJSValue::TypeError, QString("bof_pack cannot convert argument at index %1 to bytes").arg(i)); + if (!value.canConvert()) { + emit engineError(QString("bof_pack cannot convert argument at index %1 to string").arg(i)); return ""; } - QByteArray bytes = value.toByteArray(); + QByteArray valueData = QByteArray::fromBase64(value.toString().toUtf8()); + int strLength = valueData.size(); - QByteArray bytesLengthData; - int bytesLength = bytes.size(); - bytesLengthData.append(reinterpret_cast(&bytesLength), 4); - - data.append(bytesLengthData); - if (bytesLength > 0) - data.append(bytes); + QByteArray valueLengthData; + valueLengthData.append(reinterpret_cast(&strLength), 4); + data.append(valueLengthData); + data.append(valueData); } else if (items[i] == "int") { if (!value.canConvert()) { - scriptEngine->engine()->throwError(QJSValue::TypeError, QString("bof_pack cannot convert argument at index %1 to int").arg(i)); + emit engineError(QString("bof_pack cannot convert argument at index %1 to int").arg(i)); return ""; } @@ -151,7 +159,7 @@ QString BridgeApp::bof_pack(const QString &types, const QJSValue &args) const } else if (items[i] == "short") { if (!value.canConvert()) { - scriptEngine->engine()->throwError(QJSValue::TypeError, QString("bof_pack cannot convert argument at index %1 to short").arg(i)); + emit engineError(QString("bof_pack cannot convert argument at index %1 to short").arg(i)); return ""; } @@ -161,7 +169,7 @@ QString BridgeApp::bof_pack(const QString &types, const QJSValue &args) const data.append(numData); } else { - scriptEngine->engine()->throwError(QJSValue::TypeError, QString("bof_pack does not expect type '%1' (index %2)").arg(items[i]).arg(i)); + emit engineError(QString("bof_pack does not expect type '%1' (index %2)").arg(items[i]).arg(i)); return ""; } } @@ -195,27 +203,26 @@ void BridgeApp::console_message(const QString &id, const QString &message, const agent->Console->ConsoleOutputMessage(QDateTime::currentSecsSinceEpoch(), "", msgType, message, text, false); } -void BridgeApp::credentials_add(const QString &username, const QString &password, const QString &realm, const QString &type, const QString &tag, const QString &storage, const QString &host) { - scriptEngine->manager()->GetAdaptix()->CredentialsTab->CredentialsAdd(username, password, realm, type, tag, storage, host); -} +void BridgeApp::credentials_add(const QString &username, const QString &password, const QString &realm, const QString &type, const QString &tag, const QString &storage, const QString &host) { scriptEngine->manager()->GetAdaptix()->CredentialsTab->CredentialsAdd(username, password, realm, type, tag, storage, host); } QObject* BridgeApp::create_command(const QString &name, const QString &description, const QString &example, const QString &message) { auto* wrapper = new AxCommandWrappers(name, description, example, message, this); - connect(wrapper, &AxCommandWrappers::consoleError, this, &BridgeApp::consoleError); + connect(wrapper, &AxCommandWrappers::scriptError, this, &BridgeApp::engineError); scriptEngine->registerObject(wrapper); return wrapper; } QObject* BridgeApp::create_commands_group(const QString &name, const QJSValue &array) { - auto* wrapper = new AxCommandGroupWrapper(name, array, scriptEngine->engine(), this); - connect(wrapper, &AxCommandGroupWrapper::consoleError, this, &BridgeApp::consoleError); + auto* wrapper = new AxCommandGroupWrapper(scriptEngine->engine(), this); + connect(wrapper, &AxCommandGroupWrapper::scriptError, this, &BridgeApp::engineError); + wrapper->SetParams(name, array); scriptEngine->registerObject(wrapper); return wrapper; } -void BridgeApp::execute_alias(const QString &id, const QString &cmdline, const QString &command) const +void BridgeApp::execute_alias(const QString &id, const QString &cmdline, const QString &command, const QString &message) const { auto mapAgents = scriptEngine->manager()->GetAgents(); if (!mapAgents.contains(id)) @@ -226,8 +233,12 @@ void BridgeApp::execute_alias(const QString &id, const QString &cmdline, const Q return; auto cmdResult = agent->commander->ProcessInput(id, command); - if (!cmdResult.hooked) + if (!cmdResult.hooked) { + if (!message.isEmpty()) { + cmdResult.data["message"] = message; + } agent->Console->ProcessCmdResult(cmdline, cmdResult); + } } void BridgeApp::execute_command(const QString &id, const QString &command) const @@ -246,6 +257,27 @@ void BridgeApp::execute_command(const QString &id, const QString &command) const } +QString BridgeApp::file_basename(const QString &path) const +{ + int slash = qMax(path.lastIndexOf('/'), path.lastIndexOf('\\')); + return path.mid(slash + 1); +} + +QString BridgeApp::file_read(QString path) const +{ + if (path.startsWith("~/")) + path = QDir::home().filePath(path.mid(2)); + + QFile file(path); + if (file.open(QIODevice::ReadOnly)) { + QByteArray fileData = file.readAll(); + file.close(); + return QString::fromLatin1(fileData.toBase64()); + } else { + return ""; + } +} + bool BridgeApp::is64(const QString &id) const { auto mapAgents = scriptEngine->manager()->GetAgents(); @@ -267,30 +299,32 @@ void BridgeApp::open_browser_process(const QString &id) { scriptEngine->manager( void BridgeApp::open_browser_terminal(const QString &id) { scriptEngine->manager()->GetAdaptix()->LoadTerminalUI(id); } -void BridgeApp::register_commands_group(QObject *obj, const QJSValue &os, const QJSValue &agents, const QJSValue &listeners) const +void BridgeApp::register_commands_group(QObject *obj, const QJSValue &agents, const QJSValue &os, const QJSValue &listeners) { - QStringList list_os; + QList list_os; QStringList list_agents; QStringList list_listeners; - if (os.isUndefined() || os.isNull() || !os.isArray()) { - scriptEngine->engine()->throwError(QJSValue::TypeError, "register_commands_group expected array of strings in os parameter!");; - return; - } - if (agents.isUndefined() || agents.isNull() || !agents.isArray()) { - scriptEngine->engine()->throwError(QJSValue::TypeError, "register_commands_group expected array of strings in agents parameter!");; + emit engineError("register_commands_group expected array of strings in agents parameter!"); return; } - if (listeners.isUndefined() || listeners.isNull() || !listeners.isArray()) { - scriptEngine->engine()->throwError(QJSValue::TypeError, "register_commands_group expected array of strings in listeners parameter!");; + if (os.isUndefined() && (os.isNull() || !os.isArray()) ) { + emit engineError("register_commands_group expected array of strings in os parameter!"); + return; + } + + if (listeners.isUndefined() && (listeners.isNull() || !listeners.isArray())) { + emit engineError("register_commands_group expected array of strings in listeners parameter!"); return; } for (int i = 0; i < os.property("length").toInt(); ++i) { QJSValue val = os.property(i); - list_os << val.toString(); + if (val.toString() == "windows") list_os.append(1); + else if (val.toString() == "linux") list_os.append(2); + else if (val.toString() == "macos") list_os.append(3); } for (int i = 0; i < agents.property("length").toInt(); ++i) { @@ -304,16 +338,29 @@ void BridgeApp::register_commands_group(QObject *obj, const QJSValue &os, const } auto wrapper = qobject_cast(obj); - if (wrapper) { - CommandsGroup commandsGroup; - commandsGroup.groupName = wrapper->getName(); - commandsGroup.commands = wrapper->getCommands(); - commandsGroup.engine = wrapper->getEngine(); - - /// TODO: register_commands_group - - // main->commander->AddAxCommands(commandsGroup); - } else { - scriptEngine->engine()->throwError(QJSValue::TypeError, "register_commands_group no support object type!");; + if (!wrapper) { + emit engineError("register_commands_group no support object type!"); + return; } + + CommandsGroup commandsGroup = {}; + commandsGroup.groupName = wrapper->getName(); + commandsGroup.commands = wrapper->getCommands(); + commandsGroup.engine = wrapper->getEngine(); + commandsGroup.filepath = scriptEngine->context.name; + + scriptEngine->manager()->RegisterCommandsGroup(commandsGroup, list_listeners, list_agents, list_os); +} + +void BridgeApp::script_load(const QString &path) { scriptEngine->manager()->GlobalScriptLoad(path); } + +void BridgeApp::script_unload(const QString &path) { scriptEngine->manager()->GlobalScriptUnload(path); } + +QString BridgeApp::script_dir() +{ +#ifdef Q_OS_WIN + return GetParentPathWindows(scriptEngine->context.name) + "\\"; +#else + return GetParentPathUnix(scriptEngine->context.name) + "/"; +#endif } diff --git a/AdaptixClient/Source/Client/AxScript/BridgeEvent.cpp b/AdaptixClient/Source/Client/AxScript/BridgeEvent.cpp index 1b449bff..742fc569 100644 --- a/AdaptixClient/Source/Client/AxScript/BridgeEvent.cpp +++ b/AdaptixClient/Source/Client/AxScript/BridgeEvent.cpp @@ -9,7 +9,7 @@ void BridgeEvent::on_event(const QJSValue &handler) if (handler.isCallable()) eventHandlers.append(handler); else - emit consoleError("on_event -> handler in not Callable"); + emit scriptError("on_event -> handler in not Callable"); } void BridgeEvent::emitEventTestClick() @@ -18,6 +18,6 @@ void BridgeEvent::emitEventTestClick() if (handler.isCallable()) eventHandlers.append(handler); else - emit consoleError("EventTestClick -> handler in not Callable"); + emit scriptError("EventTestClick -> handler in not Callable"); } } diff --git a/AdaptixClient/Source/Client/AxScript/BridgeForm.cpp b/AdaptixClient/Source/Client/AxScript/BridgeForm.cpp index dc4aa80d..f9779362 100644 --- a/AdaptixClient/Source/Client/AxScript/BridgeForm.cpp +++ b/AdaptixClient/Source/Client/AxScript/BridgeForm.cpp @@ -12,7 +12,7 @@ BridgeForm::~BridgeForm() { delete widget; } void BridgeForm::connect(QObject* sender, const QString& signalName, const QJSValue& handler) { if (!sender || !handler.isCallable()) { - emit consoleError("connect -> Invalid sender or handler"); + emit scriptError("connect -> Invalid sender or handler"); return; } @@ -44,17 +44,17 @@ void BridgeForm::connect(QObject* sender, const QString& signalName, const QJSVa connected = QObject::connect(sender, method, proxy, proxy->metaObject()->method(proxy->metaObject()->indexOfSlot("callWithArg(bool)"))); } else { - emit consoleError("connect -> Signal " + signalName + " has too many parameters (not supported)"); + emit scriptError("connect -> Signal " + signalName + " has too many parameters (not supported)"); return; } if (!connected) - emit consoleError("connect -> Failed to connect signal " + method.methodSignature()); + emit scriptError("connect -> Failed to connect signal " + method.methodSignature()); return; } - emit consoleError("connect -> Signal " + signalName + " not found"); + emit scriptError("connect -> Signal " + signalName + " not found"); } void BridgeForm::show_message(const QString &title, const QString &text) diff --git a/AdaptixClient/Source/Client/Extender.cpp b/AdaptixClient/Source/Client/Extender.cpp index c6dae6aa..5dab5eed 100644 --- a/AdaptixClient/Source/Client/Extender.cpp +++ b/AdaptixClient/Source/Client/Extender.cpp @@ -8,8 +8,6 @@ Extender::Extender(MainAdaptix* m) { mainAdaptix = m; dialogExtender = new DialogExtender(this); - - this->LoadFromDB(); } Extender::~Extender() = default; @@ -21,126 +19,57 @@ void Extender::LoadFromDB() this->LoadFromFile( list[i].FilePath, list[i].Enabled ); } -void Extender::LoadFromFile(QString path, bool enabled) +void Extender::LoadFromFile(const QString &path, const bool enabled) { - QString fileContent; - QJsonObject rootObj; - QJsonDocument jsonDocument; - QJsonArray extensionsArray; - QJsonArray agentsArray; - QVector exConstants; - QMap > exCommands; + if (extenderFiles.contains(path)) + return; - ExtensionFile extensionFile = {0}; + ExtensionFile extensionFile = {}; extensionFile.FilePath = path; + extensionFile.Enabled = enabled; QFile file(path); if (!file.open(QIODevice::ReadOnly)) { extensionFile.Enabled = false; - extensionFile.Valid = false; + extensionFile.Message = "Cannot open file."; goto END; } - fileContent = QString(file.readAll()); + extensionFile.Code = QTextStream(&file).readAll(); file.close(); - jsonDocument = QJsonDocument::fromJson(fileContent.toUtf8()); - if ( jsonDocument.isNull() || !jsonDocument.isObject()) { - extensionFile.Enabled = false; - goto END; - } - - rootObj = jsonDocument.object(); - if( !rootObj.contains("name") && rootObj["name"].isString() ) { - extensionFile.Enabled = false; - goto END; - } - - if( !rootObj.contains("extensions") && rootObj["extensions"].isArray() ) { - extensionFile.Enabled = false; - goto END; - } - - extensionFile.Name = rootObj.value("name").toString(); - extensionFile.Description = rootObj.value("description").toString(); - - extensionsArray = rootObj.value("extensions").toArray(); - for (QJsonValue extensionValue : extensionsArray) { - QJsonObject extJsonObject = extensionValue.toObject(); - - if( !extJsonObject.contains("type") && extJsonObject["type"].isString() ) { - extensionFile.Enabled = false; - goto END; - } - - QString type = extJsonObject.value("type").toString(); - if(type == "command") { - QStringList agentsList; - - if( !extJsonObject.contains("agents") && extJsonObject["agents"].isArray() ) { - extensionFile.Enabled = false; - goto END; - } - - agentsArray = extJsonObject.value("agents").toArray(); - for (QJsonValue agentStr : agentsArray) { - agentsList.push_back(agentStr.toString()); - } - - bool result = true; - QString msg = ValidExtCommand(extJsonObject, &result); - if (!result) { - extensionFile.Enabled = false; - goto END; - } - - for(QString key : agentsList) { - exCommands[key].push_back(extJsonObject); - } - - } else if(type == "constant") { - bool result = true; - QString msg = ValidExtConstant(extJsonObject, &result); - if (!result) { - extensionFile.Enabled = false; - goto END; - } - - exConstants.push_back(extJsonObject); - - } else { - extensionFile.Enabled = false; - goto END; - } - } - - extensionFile.Comment = fileContent; - extensionFile.ExConstants = exConstants; - extensionFile.ExCommands = exCommands; - extensionFile.Enabled = enabled; - extensionFile.Valid = true; - END: this->SetExtension(extensionFile); } -void Extender::SetExtension(const ExtensionFile &extFile) +void Extender::SetExtension(ExtensionFile extFile) { + bool result = false; + if(extenderFiles.contains(extFile.FilePath)) { - if( extFile.Valid && extFile.Enabled ) { + if(extFile.Enabled) { mainAdaptix->mainUI->RemoveExtension(extFile); - mainAdaptix->mainUI->AddNewExtension(extFile); + bool success = mainAdaptix->mainUI->AddNewExtension(&extFile); + if (!success) { + mainAdaptix->mainUI->RemoveExtension(extFile); + } } dialogExtender->UpdateExtenderItem(extFile); mainAdaptix->storage->UpdateExtension(extFile); } else { - extenderFiles[extFile.FilePath] = extFile; - if( extFile.Valid && extFile.Enabled ) - mainAdaptix->mainUI->AddNewExtension(extFile); + if( extFile.Enabled ) { + bool success = mainAdaptix->mainUI->AddNewExtension(&extFile); + if (!success) { + mainAdaptix->mainUI->RemoveExtension(extFile); + } + } - dialogExtender->AddExtenderItem(extFile); - if( !mainAdaptix->storage->ExistsExtension(extFile.FilePath)) - mainAdaptix->storage->AddExtension(extFile); + if (!extFile.NoSave) { + extenderFiles[extFile.FilePath] = extFile; + dialogExtender->AddExtenderItem(extFile); + if( !mainAdaptix->storage->ExistsExtension(extFile.FilePath)) + mainAdaptix->storage->AddExtension(extFile); + } } } @@ -149,9 +78,13 @@ void Extender::EnableExtension(const QString &path) if( !extenderFiles.contains(path) ) return; - if( extenderFiles[path].Valid && !extenderFiles[path].Enabled ) { + if( !extenderFiles[path].Enabled && extenderFiles[path].Message.isEmpty()) { extenderFiles[path].Enabled = true; - mainAdaptix->mainUI->AddNewExtension(extenderFiles[path]); + bool success = mainAdaptix->mainUI->AddNewExtension(&(extenderFiles[path])); + if (!success) { + mainAdaptix->mainUI->RemoveExtension(extenderFiles[path]); + } + dialogExtender->UpdateExtenderItem(extenderFiles[path]); mainAdaptix->storage->UpdateExtension(extenderFiles[path]); } @@ -162,7 +95,7 @@ void Extender::DisableExtension(const QString &path) if( !extenderFiles.contains(path) ) return; - if( extenderFiles[path].Valid && extenderFiles[path].Enabled ) { + if( extenderFiles[path].Enabled ) { extenderFiles[path].Enabled = false; mainAdaptix->mainUI->RemoveExtension(extenderFiles[path]); dialogExtender->UpdateExtenderItem(extenderFiles[path]); @@ -180,4 +113,10 @@ void Extender::RemoveExtension(const QString &path) mainAdaptix->storage->RemoveExtension(path); extenderFiles.remove(path); -} \ No newline at end of file +} + +void Extender::syncedOnReload(QString project) { this->LoadFromDB(); } + +void Extender::loadGlobalScript(const QString &path) { this->LoadFromFile(path, true); } + +void Extender::unloadGlobalScript(const QString &path) { this->RemoveExtension(path); } diff --git a/AdaptixClient/Source/UI/MainUI.cpp b/AdaptixClient/Source/UI/MainUI.cpp index 1114457f..f5643d74 100644 --- a/AdaptixClient/Source/UI/MainUI.cpp +++ b/AdaptixClient/Source/UI/MainUI.cpp @@ -29,7 +29,7 @@ MainUI::MainUI() auto scriptManagerAction = new QAction("Script manager", this); connect(scriptManagerAction, &QAction::triggered, this, &MainUI::onScriptManager); - auto menuExtender = new QMenu("Extender", this); + auto menuExtender = new QMenu("Ax Script", this); menuExtender->addAction(axConsoleAction); menuExtender->addAction(scriptManagerAction); @@ -55,10 +55,8 @@ MainUI::MainUI() MainUI::~MainUI() { - for (auto project : AdaptixProjects.keys()) { - delete AdaptixProjects[project]; - AdaptixProjects.remove(project); - } + qDeleteAll(AdaptixProjects); + AdaptixProjects.clear(); } void MainUI::closeEvent(QCloseEvent* event) @@ -70,25 +68,28 @@ void MainUI::closeEvent(QCloseEvent* event) void MainUI::AddNewProject(AuthProfile* profile, QThread* channelThread, WebSocketWorker* channelWsWorker) { auto adaptixWidget = new AdaptixWidget(profile, channelThread, channelWsWorker); - - for (auto extFile : GlobalClient->extender->extenderFiles){ - if(extFile.Enabled) - adaptixWidget->AddExtension(extFile); - } + connect(adaptixWidget, &AdaptixWidget::SyncedOnReloadSignal, GlobalClient->extender, &Extender::syncedOnReload); + connect(adaptixWidget, &AdaptixWidget::LoadGlobalScriptSignal, GlobalClient->extender, &Extender::loadGlobalScript); + connect(adaptixWidget, &AdaptixWidget::UnloadGlobalScriptSignal, GlobalClient->extender, &Extender::unloadGlobalScript); QString tabName = " " + profile->GetProject() + " " ; int id = mainuiTabWidget->addTab( adaptixWidget, tabName); mainuiTabWidget->setCurrentIndex( id ); - AdaptixProjects[profile->GetProject()] = adaptixWidget; + AdaptixProjects.append(adaptixWidget); } -void MainUI::AddNewExtension(const ExtensionFile &extFile) +bool MainUI::AddNewExtension(ExtensionFile *extFile) { + bool result = true; for (auto adaptixWidget : AdaptixProjects) { - if (adaptixWidget) - adaptixWidget->AddExtension(extFile); + if (adaptixWidget) { + result = adaptixWidget->AddExtension(extFile); + if (!result) + break; + } } + return result; } void MainUI::RemoveExtension(const ExtensionFile &extFile) @@ -99,7 +100,8 @@ void MainUI::RemoveExtension(const ExtensionFile &extFile) } } -void MainUI::UpdateSessionsTableColumns() { +void MainUI::UpdateSessionsTableColumns() +{ for (auto adaptixWidget : AdaptixProjects) { if (adaptixWidget) adaptixWidget->SessionsTablePage->UpdateColumnsVisible(); @@ -117,7 +119,8 @@ void MainUI::UpdateGraphIcons() { } } -void MainUI::UpdateTasksTableColumns() { +void MainUI::UpdateTasksTableColumns() +{ for (auto adaptixWidget : AdaptixProjects) { if (adaptixWidget) adaptixWidget->TasksTab->UpdateColumnsVisible(); @@ -135,7 +138,13 @@ void MainUI::onCloseProject() if (!adaptixWidget) return; - AdaptixProjects.remove(adaptixWidget->GetProfile()->GetProject()); + for (int i = 0; i < AdaptixProjects.size(); ++i) { + if (AdaptixProjects[i] == adaptixWidget) { + AdaptixProjects.remove(i); + break; + } + } + adaptixWidget->Close(); delete adaptixWidget; diff --git a/AdaptixClient/Source/UI/Widgets/AdaptixWidget.cpp b/AdaptixClient/Source/UI/Widgets/AdaptixWidget.cpp index b806ab1a..b207fd5b 100644 --- a/AdaptixClient/Source/UI/Widgets/AdaptixWidget.cpp +++ b/AdaptixClient/Source/UI/Widgets/AdaptixWidget.cpp @@ -254,54 +254,29 @@ void AdaptixWidget::RemoveTab(int index) const mainTabWidget->setMovable(false); } -void AdaptixWidget::AddExtension(ExtensionFile ext) +bool AdaptixWidget::AddExtension(ExtensionFile* ext) { - if( Extensions.contains(ext.FilePath) ) - return; + if (ScriptManager->ScriptList().contains(ext->FilePath)) { + ext->Enabled = false; + ext->Message = "Script already loaded"; + return false; + } - Extensions[ext.FilePath] = ext; + if( !synchronized ) { + ext->Enabled = false; + ext->Message = "C2 not synchronized"; + return false; + } - if( !synchronized ) - return; - - // ToDo: AddExtension - - // for (QString agentName : ext.ExCommands.keys()) { - // if (Commanders.contains(agentName)) { - // for (auto commander : Commanders[agentName] ) { - // if (commander) { - // bool result = commander->AddExtModule(ext.FilePath, ext.Name, ext.ExCommands[agentName], ext.ExConstants); - // if (result) { - // for( auto agent : AgentsMap ){ - // if( agent && agent->Console ) - // agent->Console->UpgradeCompleter(); - // } - // } - // } - // } - // } - // } + return ScriptManager->ScriptAdd(ext); } void AdaptixWidget::RemoveExtension(const ExtensionFile &ext) { - Extensions.remove(ext.FilePath); + if (!ScriptManager->ScriptList().contains(ext.FilePath)) + return; - // ToDo: RemoveExtension - - // for (QString agentName : ext.ExCommands.keys()) { - // if (Commanders.contains(agentName)) { - // for (auto commander : Commanders[agentName] ) { - // if (commander) { - // commander->RemoveExtModule(ext.FilePath); - // for( auto agent : AgentsMap ){ - // if( agent && agent->Console ) - // agent->Console->UpgradeCompleter(); - // } - // } - // } - // } - // } + return ScriptManager->ScriptRemove(ext); } void AdaptixWidget::Close() @@ -331,8 +306,6 @@ void AdaptixWidget::ClearAdaptix() TunnelsTab->Clear(); CredentialsTab->Clear(); - ScriptManager->Clear(); - for (auto tunnelId : ClientTunnels.keys()) { auto tunnel = ClientTunnels[tunnelId]; ClientTunnels.remove(tunnelId); @@ -341,35 +314,19 @@ void AdaptixWidget::ClearAdaptix() } ClientTunnels.clear(); - // ToDO: ClearAdaptix + ScriptManager->Clear(); - // for (int i = 0; i < RegisterAgents.size(); i++) { - // WidgetBuilder* builder = RegisterAgents[i].builder; - // RegisterAgents.remove(i); - // i--; - // delete builder; - // } + for (auto regAgent : RegisterAgents) + delete regAgent.commander; - // ToDo: Clear Commanders - - // for (auto commanderMap : Commanders ) { - // for (auto k : commanderMap.keys()) { - // Commander* commander = commanderMap[k]; - // commanderMap.remove(k); - // delete commander; - // } - // } - // Commanders.clear(); + RegisterAgents.clear(); } /// REGISTER -void AdaptixWidget::RegisterListenerConfig(const QString &fn, const QString &ax_script) -{ - ScriptManager->ListenerScriptAdd(fn, ax_script); -} +void AdaptixWidget::RegisterListenerConfig(const QString &fn, const QString &ax_script) { ScriptManager->ListenerScriptAdd(fn, ax_script); } -void AdaptixWidget::RegisterAgentConfig(const QString &agentName, const QString &watermark, const QString &ax_script, const QStringList &listeners) +void AdaptixWidget::RegisterAgentConfig(const QString &agentName, const QString &ax_script, const QStringList &listeners) { ScriptManager->AgentScriptAdd(agentName, ax_script); @@ -403,15 +360,16 @@ void AdaptixWidget::RegisterAgentConfig(const QString &agentName, const QString QObject* objPanel = commands_windows.toQObject(); auto* wrapper = dynamic_cast(objPanel); if (wrapper) { - CommandsGroup commandsGroup; + CommandsGroup commandsGroup = {}; commandsGroup.groupName = wrapper->getName(); commandsGroup.commands = wrapper->getCommands(); commandsGroup.engine = wrapper->getEngine(); + commandsGroup.filepath = ""; Commander* commander = new Commander(); commander->AddRegCommands(commandsGroup); - RegAgentConfig config = {agentName, watermark, listener, OS_WINDOWS, commander, {}, true}; + RegAgentConfig config = {agentName, listener, OS_WINDOWS, commander, {}, true}; RegisterAgents.push_back(config); } else { @@ -424,15 +382,16 @@ void AdaptixWidget::RegisterAgentConfig(const QString &agentName, const QString QObject* objPanel = commands_linux.toQObject(); auto* wrapper = dynamic_cast(objPanel); if (wrapper) { - CommandsGroup commandsGroup; + CommandsGroup commandsGroup = {}; commandsGroup.groupName = wrapper->getName(); commandsGroup.commands = wrapper->getCommands(); commandsGroup.engine = wrapper->getEngine(); + commandsGroup.filepath = ""; Commander* commander = new Commander(); commander->AddRegCommands(commandsGroup); - RegAgentConfig config = {agentName, watermark, listener, OS_LINUX, commander, {}, true}; + RegAgentConfig config = {agentName, listener, OS_LINUX, commander, {}, true}; RegisterAgents.push_back(config); } else { @@ -445,15 +404,16 @@ void AdaptixWidget::RegisterAgentConfig(const QString &agentName, const QString QObject* objPanel = commands_macos.toQObject(); auto* wrapper = dynamic_cast(objPanel); if (wrapper) { - CommandsGroup commandsGroup; + CommandsGroup commandsGroup = {}; commandsGroup.groupName = wrapper->getName(); commandsGroup.commands = wrapper->getCommands(); commandsGroup.engine = wrapper->getEngine(); + commandsGroup.filepath = ""; Commander* commander = new Commander(); commander->AddRegCommands(commandsGroup); - RegAgentConfig config = {agentName, watermark, listener, OS_MAC, commander, {}, true}; + RegAgentConfig config = {agentName, listener, OS_MAC, commander, {}, true}; RegisterAgents.push_back(config); } else { @@ -493,6 +453,29 @@ RegAgentConfig AdaptixWidget::GetRegAgent(const QString &agentName, const QStrin return {}; } +QList AdaptixWidget::GetCommanders(const QStringList &listeners, const QStringList &agents, const QList &os) const +{ + QList commanders; + for (auto regAgent : this->RegisterAgents) { + if ( !agents.contains(regAgent.name) ) continue; + + if ( !listeners.empty() && !listeners.contains(regAgent.listenerType)) continue; + + if ( !os.empty() && !os.contains(regAgent.os) ) continue; + + commanders.append(regAgent.commander); + } + return commanders; +} + +QList AdaptixWidget::GetCommandersAll() const +{ + QList commanders; + for (auto regAgent : this->RegisterAgents) + commanders.append(regAgent.commander); + return commanders; +} + /// SHOW PANELS void AdaptixWidget::LoadConsoleUI(const QString &AgentId) @@ -509,10 +492,7 @@ void AdaptixWidget::LoadConsoleUI(const QString &AgentId) } -void AdaptixWidget::LoadTasksOutput() const -{ - this->AddTab(TasksTab->taskOutputConsole, "Task Output", ":/icons/job"); -} +void AdaptixWidget::LoadTasksOutput() const { this->AddTab(TasksTab->taskOutputConsole, "Task Output", ":/icons/job"); } void AdaptixWidget::LoadFileBrowserUI(const QString &AgentId) { @@ -650,28 +630,7 @@ void AdaptixWidget::OnSynced() this->SessionsGraphPage->TreeDraw(); - // ToDo: OnSynced - - // for (auto ext : Extensions) { - // - // for (QString agentName : ext.ExCommands.keys()) { - // - // if (Commanders.contains(agentName)) { - // for (auto commander : Commanders[agentName] ) { - // - // if (commander) { - // bool result = commander->AddExtModule(ext.FilePath, ext.Name, ext.ExCommands[agentName], ext.ExConstants); - // if (result) { - // for( auto agent : AgentsMap ){ - // if( agent && agent->Console ) - // agent->Console->UpgradeCompleter(); - // } - // } - // } - // } - // } - // } - // } + emit SyncedOnReloadSignal(profile->GetProject()); } void AdaptixWidget::SetSessionsTableUI() const diff --git a/AdaptixClient/Source/UI/Widgets/AxConsoleWidget.cpp b/AdaptixClient/Source/UI/Widgets/AxConsoleWidget.cpp index 5754ed09..c519c85e 100644 --- a/AdaptixClient/Source/UI/Widgets/AxConsoleWidget.cpp +++ b/AdaptixClient/Source/UI/Widgets/AxConsoleWidget.cpp @@ -17,6 +17,7 @@ AxConsoleWidget::AxConsoleWidget(AxScriptManager* m, AdaptixWidget* w): adaptixW connect(hideButton, &ClickableLabel::clicked, this, &AxConsoleWidget::toggleSearchPanel); connect(OutputTextEdit, &TextEditConsole::ctx_find, this, &AxConsoleWidget::toggleSearchPanel); connect(OutputTextEdit, &TextEditConsole::ctx_history, this, &AxConsoleWidget::handleShowHistory); + connect(ResetButton, &QPushButton::clicked, this, &AxConsoleWidget::onResetScript); shortcutSearch = new QShortcut(QKeySequence("Ctrl+F"), OutputTextEdit); shortcutSearch->setContext(Qt::WidgetShortcut); @@ -70,6 +71,11 @@ void AxConsoleWidget::createUI() searchLayout->addWidget(hideButton); searchLayout->addSpacerItem(spacer); + OutputTextEdit = new TextEditConsole(this, 30000, true, true); + OutputTextEdit->setReadOnly(true); + OutputTextEdit->setProperty( "TextEditStyle", "console" ); + OutputTextEdit->setFont( QFont( "Hack" )); + CmdLabel = new QLabel( "ax >", this ); CmdLabel->setProperty( "LabelStyle", "console" ); @@ -77,18 +83,16 @@ void AxConsoleWidget::createUI() InputLineEdit->setProperty( "LineEditStyle", "console" ); InputLineEdit->setFont( QFont( "Hack" )); - OutputTextEdit = new TextEditConsole(this, 30000, true, true); - OutputTextEdit->setReadOnly(true); - OutputTextEdit->setProperty( "TextEditStyle", "console" ); - OutputTextEdit->setFont( QFont( "Hack" )); + ResetButton = new QPushButton("Reset AxScript"); MainGridLayout = new QGridLayout(this ); MainGridLayout->setVerticalSpacing(4 ); MainGridLayout->setContentsMargins(0, 1, 0, 4 ); - MainGridLayout->addWidget( searchWidget, 0, 0, 1, 2 ); - MainGridLayout->addWidget( OutputTextEdit, 1, 0, 1, 2 ); + MainGridLayout->addWidget( searchWidget, 0, 0, 1, 3 ); + MainGridLayout->addWidget( OutputTextEdit, 1, 0, 1, 3 ); MainGridLayout->addWidget( CmdLabel, 2, 0, 1, 1 ); MainGridLayout->addWidget( InputLineEdit, 2, 1, 1, 1 ); + MainGridLayout->addWidget( ResetButton, 2, 2, 1, 1 ); searchWidget->setVisible(false); } @@ -150,8 +154,6 @@ void AxConsoleWidget::PrintMessage(const QString &message) { OutputTextEdit->app void AxConsoleWidget::PrintError(const QString &message) { OutputTextEdit->appendColor(message + "\n", QColor(COLOR_ChiliPepper)); } -// void AxConsoleWidget::Clear() { OutputTextEdit->clear(); } - void AxConsoleWidget::processInput() { QString code = TrimmedEnds(InputLineEdit->text()); @@ -290,4 +292,10 @@ void AxConsoleWidget::handleShowHistory() historyDialog->setModal(true); historyDialog->show(); -} \ No newline at end of file +} + +void AxConsoleWidget::onResetScript() +{ + scriptManager->ResetMain(); + OutputTextEdit->clear(); +}