From b123299376b0a8ec5b6c849d65afe9b6ea9e4b8e Mon Sep 17 00:00:00 2001 From: Maham Riaz Keyani Date: Thu, 17 Oct 2024 13:24:41 +0500 Subject: [PATCH 01/80] docker and flask setup --- docker-compose.base.yml | 3 +++ docker-compose.dev.yml | 2 ++ source/app/alembic.ini | 3 +-- source/app/iris_engine/utils/tracker.py | 9 +++++---- source/app/post_init.py | 3 ++- source/requirements.txt | 1 + 6 files changed, 14 insertions(+), 7 deletions(-) diff --git a/docker-compose.base.yml b/docker-compose.base.yml index 2f29ecc54..0305533ec 100644 --- a/docker-compose.base.yml +++ b/docker-compose.base.yml @@ -34,6 +34,8 @@ services: - POSTGRES_DB networks: - iris_backend + ports: + - "0.0.0.0:5432:5432" volumes: - db_data:/var/lib/postgresql/data @@ -47,6 +49,7 @@ services: - iris-downloads:/home/iris/downloads - user_templates:/home/iris/user_templates - server_data:/home/iris/server_data + - ./source/app:/iriswebapp/app restart: always depends_on: - "rabbitmq" diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 8be1806c0..c79258788 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -31,6 +31,7 @@ services: image: iriswebapp_db:v2.4.7 ports: - "127.0.0.1:5432:5432" + - "0.0.0.0:5432:5432" app: extends: @@ -42,6 +43,7 @@ services: image: iriswebapp_app:v2.4.7 ports: - "127.0.0.1:8000:8000" + - "0.0.0.0:5678:5678" worker: extends: diff --git a/source/app/alembic.ini b/source/app/alembic.ini index bae233cac..9d9e00091 100644 --- a/source/app/alembic.ini +++ b/source/app/alembic.ini @@ -1,7 +1,6 @@ [alembic] # path to migration scripts -script_location = app/alembic - +script_location = source/app/alembic # template used to generate migration files # file_template = %%(rev)s_%%(slug)s diff --git a/source/app/iris_engine/utils/tracker.py b/source/app/iris_engine/utils/tracker.py index 59e086caf..8ec9b2b7a 100644 --- a/source/app/iris_engine/utils/tracker.py +++ b/source/app/iris_engine/utils/tracker.py @@ -52,10 +52,11 @@ def track_activity(message, caseid=None, ctx_less=False, user_input=False, displ ua.activity_date = datetime.utcnow() ua.activity_desc = message.capitalize() - if current_user.is_authenticated: - log.info(f"{current_user.user} [#{current_user.id}] :: Case {caseid} :: {ua.activity_desc}") - else: - log.info(f"Anonymous :: Case {caseid} :: {ua.activity_desc}") + # if current_user.is_authenticated: + # pass + # log.info(f"{current_user.user} [#{current_user.id}] :: Case {caseid} :: {ua.activity_desc}") + # else: + # log.info(f"Anonymous :: Case {caseid} :: {ua.activity_desc}") ua.user_input = user_input ua.display_in_ui = display_in_ui diff --git a/source/app/post_init.py b/source/app/post_init.py index c64d06ab5..9383b5cc5 100644 --- a/source/app/post_init.py +++ b/source/app/post_init.py @@ -153,7 +153,8 @@ def run_post_init(development=False): log.info("Running DB migration") - alembic_cfg = Config(file_='app/alembic.ini') + # alembic_cfg = Config(file_='app/alembic.ini') + alembic_cfg = Config(file_='source/app/alembic.ini') alembic_cfg.set_main_option('sqlalchemy.url', app.config['SQLALCHEMY_DATABASE_URI']) command.upgrade(alembic_cfg, 'head') diff --git a/source/requirements.txt b/source/requirements.txt index a29374dfc..69c5a234e 100644 --- a/source/requirements.txt +++ b/source/requirements.txt @@ -37,6 +37,7 @@ graphene==3.3 qrcode[pil]==7.4.2 dictdiffer==0.2.0 oic==1.7.0 +Debugpy # unfortunately we are relying on a beta version here. I hope a definitive version gets released soon graphql-server[flask]==3.0.0b7 graphene-sqlalchemy==3.0.0rc1 From 1d6a741ef8af091ad1d5e6a905260f230eb1c1d7 Mon Sep 17 00:00:00 2001 From: Muhammad Hanzila Date: Fri, 18 Oct 2024 21:14:36 +0500 Subject: [PATCH 02/80] local setup changes --- docker-compose.base.yml | 2 ++ docker-compose.dev.yml | 5 ++--- source/app/alembic.ini | 2 +- source/app/iris_engine/utils/tracker.py | 8 ++++---- source/app/post_init.py | 2 +- source/requirements.txt | 1 + 6 files changed, 11 insertions(+), 9 deletions(-) diff --git a/docker-compose.base.yml b/docker-compose.base.yml index 2f29ecc54..85371485c 100644 --- a/docker-compose.base.yml +++ b/docker-compose.base.yml @@ -36,6 +36,8 @@ services: - iris_backend volumes: - db_data:/var/lib/postgresql/data + ports: + - "0.0.0.0:5432:5432" app: container_name: iriswebapp_app diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 8be1806c0..1f6f9d5af 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -16,7 +16,6 @@ # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. services: - rabbitmq: extends: file: docker-compose.base.yml @@ -31,6 +30,7 @@ services: image: iriswebapp_db:v2.4.7 ports: - "127.0.0.1:5432:5432" + - "0.0.0.0:5432:5432" app: extends: @@ -63,7 +63,6 @@ services: NGINX_CONF_FILE: nginx.conf image: iriswebapp_nginx:v2.4.7 - volumes: iris-downloads: user_templates: @@ -74,4 +73,4 @@ networks: iris_backend: name: iris_backend iris_frontend: - name: iris_frontend \ No newline at end of file + name: iris_frontend diff --git a/source/app/alembic.ini b/source/app/alembic.ini index bae233cac..0c1d8af90 100644 --- a/source/app/alembic.ini +++ b/source/app/alembic.ini @@ -1,6 +1,6 @@ [alembic] # path to migration scripts -script_location = app/alembic +script_location = source/app/alembic # template used to generate migration files # file_template = %%(rev)s_%%(slug)s diff --git a/source/app/iris_engine/utils/tracker.py b/source/app/iris_engine/utils/tracker.py index 59e086caf..eb0078af6 100644 --- a/source/app/iris_engine/utils/tracker.py +++ b/source/app/iris_engine/utils/tracker.py @@ -52,10 +52,10 @@ def track_activity(message, caseid=None, ctx_less=False, user_input=False, displ ua.activity_date = datetime.utcnow() ua.activity_desc = message.capitalize() - if current_user.is_authenticated: - log.info(f"{current_user.user} [#{current_user.id}] :: Case {caseid} :: {ua.activity_desc}") - else: - log.info(f"Anonymous :: Case {caseid} :: {ua.activity_desc}") + # if current_user.is_authenticated: + # log.info(f"{current_user.user} [#{current_user.id}] :: Case {caseid} :: {ua.activity_desc}") + # else: + # log.info(f"Anonymous :: Case {caseid} :: {ua.activity_desc}") ua.user_input = user_input ua.display_in_ui = display_in_ui diff --git a/source/app/post_init.py b/source/app/post_init.py index c64d06ab5..ff21d9f39 100644 --- a/source/app/post_init.py +++ b/source/app/post_init.py @@ -153,7 +153,7 @@ def run_post_init(development=False): log.info("Running DB migration") - alembic_cfg = Config(file_='app/alembic.ini') + alembic_cfg = Config(file_='source/app/alembic.ini') alembic_cfg.set_main_option('sqlalchemy.url', app.config['SQLALCHEMY_DATABASE_URI']) command.upgrade(alembic_cfg, 'head') diff --git a/source/requirements.txt b/source/requirements.txt index a29374dfc..77c10ebc9 100644 --- a/source/requirements.txt +++ b/source/requirements.txt @@ -40,6 +40,7 @@ oic==1.7.0 # unfortunately we are relying on a beta version here. I hope a definitive version gets released soon graphql-server[flask]==3.0.0b7 graphene-sqlalchemy==3.0.0rc1 +Debugpy dependencies/docx_generator-0.8.0-py3-none-any.whl dependencies/iris_interface-1.2.0-py3-none-any.whl From 46aa119df26f04e8bf62b9625a5c4b9506101ccc Mon Sep 17 00:00:00 2001 From: Maham Riaz Keyani Date: Wed, 23 Oct 2024 14:40:28 +0500 Subject: [PATCH 03/80] webhooks-route added to advance --- .../manage/manage_webhooks_routes.py | 18 ++++++++ .../manage/templates/modal_case_template.html | 46 +++++++++++++------ source/app/templates/includes/sidenav.html | 6 +++ source/app/views.py | 2 + 4 files changed, 59 insertions(+), 13 deletions(-) create mode 100644 source/app/blueprints/manage/manage_webhooks_routes.py diff --git a/source/app/blueprints/manage/manage_webhooks_routes.py b/source/app/blueprints/manage/manage_webhooks_routes.py new file mode 100644 index 000000000..b38d01618 --- /dev/null +++ b/source/app/blueprints/manage/manage_webhooks_routes.py @@ -0,0 +1,18 @@ +import json +from flask import Blueprint, redirect, render_template, request, url_for +from app import db +from app.models.authorization import Permissions +from app.util import ac_api_requires, ac_requires, response_error, response_success + +manage_webhooks_blueprint = Blueprint('manage_webhooks', __name__, template_folder='templates') + +# CONTENT ------------------------------------------------ +@manage_webhooks_blueprint.route('/manage/webhooks') +@ac_requires(Permissions.server_administrator, no_cid_required=True) +def manage_webhooks(caseid, url_redir): + if url_redir: + return redirect(url_for('manage_webhooks.manage_webhooks', cid=caseid)) + + return render_template('manage_webhooks.html') + + diff --git a/source/app/blueprints/manage/templates/modal_case_template.html b/source/app/blueprints/manage/templates/modal_case_template.html index 65321530c..6b865914b 100644 --- a/source/app/blueprints/manage/templates/modal_case_template.html +++ b/source/app/blueprints/manage/templates/modal_case_template.html @@ -51,6 +51,9 @@

Field types

  • tags: A list of case tags.
  • tasks: A list of dictionaries defining tasks. Tasks are defined by title (required), description, and list of tags.
  • note_directories: A list of dictionaries defining note directories. Note directories are defined by title (required), and list of notes. Notes have title (required) and content
  • +
  • actions: A list of dictionaries defining actions that can be triggered from case pages. Each action is defined by a name (required), url, header and a payload.
  • +
  • triggers: A list of dictionaries defining triggers that are executed on case creation. Each trigger is defined by a name (required), order, url, header, and a payload.
  • + @@ -94,28 +97,45 @@

    Field types

    "title": "Containment" } ], + "actions":[ + { + "name":"Name of the action", + "url":"URL of the target webhook", + "header":[{"key1":"value1"}, {"key2":"value2"}, {"keyn":"valuen"}], + "payload":{"key1":"fixed value", "key2":"<>" } + } + ], "note_directories": [ { "title": "Identify", "notes": [ - { - "title": "Identify the compromised accounts", - "content": "# Observations\n\n" - } - ] + { + "title": "Identify the compromised accounts", + "content": "# Observations\n\n" + } + ] }, { "title": "Collect", "notes": [ - { - "title": "Velociraptor deployment" - }, - { - "title": "Assets collected", - "content": "# Assets collected\n\n# Assets not collected" - } - ] + { + "title": "Velociraptor deployment" + }, + { + "title": "Assets collected", + "content": "# Assets collected\n\n# Assets not collected" + } + ] } + ], + "triggers":[ + { + "order":10, + "name":"Name of the action", + "url":"URL of the target webhook", + "header":[{"key1":"value1"}, {"key2":"value2"}, {"keyn":"valuen"}], + "payload":{"key1":"fixed value", "key2":"<>" } + } ] } diff --git a/source/app/templates/includes/sidenav.html b/source/app/templates/includes/sidenav.html index e39592652..dfd76ccf5 100644 --- a/source/app/templates/includes/sidenav.html +++ b/source/app/templates/includes/sidenav.html @@ -163,6 +163,12 @@

    Manage

    Case Templates + {% endif %} {% if user_has_perm(std_permissions.server_administrator) %} + diff --git a/source/app/blueprints/case/templates/case.html b/source/app/blueprints/case/templates/case.html index 1d3cb49e7..fd18458b1 100644 --- a/source/app/blueprints/case/templates/case.html +++ b/source/app/blueprints/case/templates/case.html @@ -11,6 +11,7 @@ {% include 'includes/navigation_ext.html' %} {% include 'includes/sidenav.html' %} +
    @@ -233,264 +234,212 @@

    Case summary {{ "(Syncing with DB )" if case.i

    - -
    - {% include 'case-nav_actions.html' %} -
    -
    -
    -
    -
    -
    - -

    Actions and Triggers

    -
    -
    - -
    -
    + + +
    diff --git a/source/app/blueprints/case/templates/modal_add_case_task.html b/source/app/blueprints/case/templates/modal_add_case_task.html index 78e03aa62..770bd33db 100644 --- a/source/app/blueprints/case/templates/modal_add_case_task.html +++ b/source/app/blueprints/case/templates/modal_add_case_task.html @@ -8,25 +8,34 @@
    @@ -35,86 +44,129 @@ - - + {% endblock javascripts %} \ No newline at end of file From f855d45ac52db0d357fa94bbe905eba02d0b1140 Mon Sep 17 00:00:00 2001 From: Muhammad Hanzila Date: Tue, 26 Nov 2024 13:00:52 +0500 Subject: [PATCH 36/80] endpoint fixed --- .../app/blueprints/case/case_triggers_routes.py | 16 ++++++++++------ .../datamgmt/manage/manage_case_response_db.py | 6 ++---- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/source/app/blueprints/case/case_triggers_routes.py b/source/app/blueprints/case/case_triggers_routes.py index 7d6c7db8b..5c968674e 100644 --- a/source/app/blueprints/case/case_triggers_routes.py +++ b/source/app/blueprints/case/case_triggers_routes.py @@ -17,7 +17,7 @@ # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # IMPORTS ------------------------------------------------ -from flask import Blueprint +from flask import Blueprint, request from flask import redirect from flask import render_template from flask import url_for @@ -27,21 +27,25 @@ from app.models.authorization import CaseAccessLevel from app.util import ac_api_case_requires from app.util import ac_case_requires -from source.app.datamgmt.manage.manage_case_response_db import get_case_responses_list +from app.datamgmt.manage.manage_case_response_db import get_case_responses_list + case_triggers_blueprint = Blueprint('case_triggers', __name__, template_folder='templates') -# CONTENT ------------------------------------------------ @case_triggers_blueprint.route('/case/triggers', methods=['GET']) -#@ac_case_requires(CaseAccessLevel.read_only, CaseAccessLevel.full_access) -def case_triggers(caseid, url_redir): +def case_triggers(): + # Retrieve query parameters from the URL + caseid = request.args.get('caseid') + url_redir = request.args.get('url_redir', type=bool) + if url_redir: return redirect(url_for('case_triggers.case_triggers', cid=caseid, redirect=True)) form = FlaskForm() case = get_case(caseid) - triggers = get_case_responses_list() # Fetch the triggers + triggers = get_case_responses_list() return render_template("case_triggers.html", case=case, form=form, triggers=triggers) + diff --git a/source/app/datamgmt/manage/manage_case_response_db.py b/source/app/datamgmt/manage/manage_case_response_db.py index 4ddf82d96..ce8be88d0 100644 --- a/source/app/datamgmt/manage/manage_case_response_db.py +++ b/source/app/datamgmt/manage/manage_case_response_db.py @@ -30,7 +30,7 @@ def get_case_responses_list() -> List[dict]: Returns: List[dict]: List of case responses. """ - case_responses = CaseResponse.query.with_entities( + case_response = CaseResponse.query.with_entities( CaseResponse.id, CaseResponse.created_at, CaseResponse.updated_at, @@ -38,11 +38,9 @@ def get_case_responses_list() -> List[dict]: CaseResponse.trigger, CaseResponse.body, User.name.label('created_by') - ).join( - CaseResponse.created_by_user ).all() - return [row._asdict() for row in case_responses] + return [row._asdict() for row in case_response] def get_case_response_by_id(response_id: int) -> CaseResponse: From 88d62863d8036f63c5a0cfe92745dceb48b41e6e Mon Sep 17 00:00:00 2001 From: Maham Riaz Keyani Date: Thu, 28 Nov 2024 15:29:11 +0500 Subject: [PATCH 37/80] case triggers implemented --- .../blueprints/case/case_triggers_routes.py | 47 ++---- .../case/templates/case_triggers.html | 137 +++++++++--------- .../manage/manage_case_response_db.py | 2 +- .../static/assets/js/iris/case.triggers.js | 130 ++++------------- 4 files changed, 118 insertions(+), 198 deletions(-) diff --git a/source/app/blueprints/case/case_triggers_routes.py b/source/app/blueprints/case/case_triggers_routes.py index 5c968674e..957c70deb 100644 --- a/source/app/blueprints/case/case_triggers_routes.py +++ b/source/app/blueprints/case/case_triggers_routes.py @@ -1,35 +1,10 @@ -# IRIS Source Code -# Copyright (C) 2021 - Airbus CyberSecurity (SAS) - DFIR-IRIS Team -# ir@cyberactionlab.net - contact@dfir-iris.org -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 3 of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with this program; if not, write to the Free Software Foundation, -# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - # IMPORTS ------------------------------------------------ -from flask import Blueprint, request -from flask import redirect -from flask import render_template -from flask import url_for +from flask import Blueprint, request, redirect, render_template, url_for +import json from flask_wtf import FlaskForm from app.datamgmt.case.case_db import get_case -from app.datamgmt.states import update_tasks_state -from app.models.authorization import CaseAccessLevel -from app.util import ac_api_case_requires -from app.util import ac_case_requires from app.datamgmt.manage.manage_case_response_db import get_case_responses_list - case_triggers_blueprint = Blueprint('case_triggers', __name__, template_folder='templates') @@ -45,7 +20,17 @@ def case_triggers(): form = FlaskForm() case = get_case(caseid) - triggers = get_case_responses_list() - - return render_template("case_triggers.html", case=case, form=form, triggers=triggers) - + triggers = get_case_responses_list() + + # Serialize datetime objects for rendering + for trigger in triggers: + trigger['created_at'] = trigger['created_at'].strftime("%Y-%m-%d %H:%M:%S") + if trigger['updated_at']: + trigger['updated_at'] = trigger['updated_at'].strftime("%Y-%m-%d %H:%M:%S") + if trigger['body']: + try: + trigger['body'] = json.dumps(trigger['body']) + except (TypeError, ValueError) as e: + trigger['body'] = str(trigger['body']) # Fallback to string representation + + return render_template("case_triggers.html", case=case, form=form, triggers=triggers) \ No newline at end of file diff --git a/source/app/blueprints/case/templates/case_triggers.html b/source/app/blueprints/case/templates/case_triggers.html index c6e2680c4..4a4f43f09 100644 --- a/source/app/blueprints/case/templates/case_triggers.html +++ b/source/app/blueprints/case/templates/case_triggers.html @@ -1,58 +1,68 @@ -{% extends "layouts/default_ext.html" %} - -{% block title %} Case Triggers {% endblock title %} - -{% block stylesheets %} -{% include 'includes/header_case.html' %} - - - -{% endblock stylesheets %} - -{% block content %} - -{% include 'includes/navigation_ext.html' %} - - -{% include 'includes/sidenav.html' %} +{% extends "layouts/default_ext.html" %} {% block title %} Case Triggers {% +endblock title %} {% block stylesheets %} {% include 'includes/header_case.html' +%} + + + +{% endblock stylesheets %} {% block content %} {% include +'includes/navigation_ext.html' %} {% include 'includes/sidenav.html' %}
    - -
    - - {% if current_user.is_authenticated %} - {{ form.hidden_tag() }} - -
    -
    -
    -
    Loading...
    -
    - - -
    +
    +
    - - - {% endif %} - - {% include 'includes/footer.html' %} - + {% endif %} + -{% endblock content %} + {% include 'includes/footer.html' %} + -{% block javascripts %} -{% include 'includes/footer_case.html' %} +{% endblock content %} {% block javascripts %} {% include +'includes/footer_case.html' %} - {% endblock javascripts %} \ No newline at end of file diff --git a/source/app/datamgmt/manage/manage_case_response_db.py b/source/app/datamgmt/manage/manage_case_response_db.py index ce8be88d0..91acf1789 100644 --- a/source/app/datamgmt/manage/manage_case_response_db.py +++ b/source/app/datamgmt/manage/manage_case_response_db.py @@ -52,7 +52,7 @@ def get_case_response_by_id(response_id: int) -> CaseResponse: Returns: CaseResponse: Task response object. """ - case_response = CaseResponse.query.filter_by(id=response_id).first() + case_response = CaseResponse.query.filter_by(id=response_id) return case_response diff --git a/source/app/static/assets/js/iris/case.triggers.js b/source/app/static/assets/js/iris/case.triggers.js index 902eb4f84..8f80d1313 100644 --- a/source/app/static/assets/js/iris/case.triggers.js +++ b/source/app/static/assets/js/iris/case.triggers.js @@ -1,106 +1,38 @@ - -const dummyTriggers = [ - { - "id": 1, - "case": 101, - "trigger": 202, - "body": { - "status": "success", - "message": "Action executed successfully", - "details": { - "step_1": "Initiated", - "step_2": "Completed" - } - }, - "execution_time": "2024-11-13T14:30:00Z" - }, - { - "id": 2, - "case": 103, - "trigger": 202, - "body": { - "status": "success", - "message": "Action executed successfully", - "details": { - "step_1": "Initiated", - "step_2": "Completed" +document.addEventListener("DOMContentLoaded", () => { + const table = document.getElementById("trigger_table"); + + table.addEventListener("click", (event) => { + if (event.target && event.target.classList.contains("view-response")) { + const button = event.target; + + const responseData = button.getAttribute("data-response"); + const parsedData = JSON.parse(responseData); + const jsonCrackEmbed = document.getElementById("jsoncrackEmbed"); + + const modal = new bootstrap.Modal(document.getElementById("responseModal")); + modal.show(); + //Check iframe is loaded and contentWindow is available + if (jsonCrackEmbed && jsonCrackEmbed.contentWindow) { + // Define options for jsonCrack + const options = { + theme: "light", + direction: "DOWN", + }; + + // Post message to jsonCrackEmbed iframe + jsonCrackEmbed.contentWindow.postMessage({ json: JSON.stringify(parsedData), options }, "*"); + } else { + console.error("jsonCrackEmbed iframe is not available or not loaded."); } - }, - "execution_time": "2024-11-13T14:50:00Z" - } -]; - - -function get_triggers() { - $('#trigger_table_wrapper'); - show_loader(); - - Table.clear(); - Table.rows.add(dummyTriggers); - Table.draw(); - - hide_loader(); -} - - -$(document).ready(function () { - Table = $("#trigger_table").DataTable({ - dom: '<"container-fluid"<"row"<"col"l><"col"f>>>rt<"container-fluid"<"row"<"col"i><"col"p>>>', - data: [], - columns: [ - { data: "id", title: "ID" }, - { data: "case", title: "Case" }, - { data: "trigger", title: "Trigger" }, - { - data: "body", - title: "Response", - render: function (data, type, row) { - if (type === 'display') { - return ''; - } - return data; - } - }, - { data: "execution_time", title: "Execution Time" } - ], - processing: true, - ordering: true, - pageLength: 10, - responsive: true, - order: [[0, 'asc']], - }); - - - get_triggers(); - - - $('#trigger_table').on('click', '.view-response', function () { - const responseData = $(this).data('body'); - const jsonCrackEmbed = document.getElementById("jsoncrackEmbed"); - - $('#responseModal').modal('show'); - - - const options = { - theme: "light", - direction: "DOWN", - }; - jsonCrackEmbed.contentWindow.postMessage({ json: JSON.stringify(responseData), options }, "*"); + } + }); }); -function closeModal() { - $('#responseModal').modal('hide'); -} - -function show_loader() { - $('#loading_msg').show(); - $('#card_main_load').hide(); -} -function hide_loader() { - $('#loading_msg').hide(); - $('#card_main_load').show(); -} +function closeModal() { + const modal = bootstrap.Modal.getInstance(document.getElementById("responseModal")); + modal.hide(); +} \ No newline at end of file From 1e8045d67533735765c26c995f7c2073aaf03faf Mon Sep 17 00:00:00 2001 From: Maham Riaz Keyani Date: Fri, 29 Nov 2024 20:42:24 +0500 Subject: [PATCH 38/80] implemented json editor in expand view --- .../app/blueprints/case/case_tasks_routes.py | 14 ++- .../blueprints/case/templates/case_tasks.html | 3 +- .../case/templates/modal_add_case_task.html | 27 ++--- .../manage/manage_case_templates_db.py | 41 +++++++ .../app/static/assets/js/iris/case.tasks.js | 110 ++++++++++-------- 5 files changed, 123 insertions(+), 72 deletions(-) diff --git a/source/app/blueprints/case/case_tasks_routes.py b/source/app/blueprints/case/case_tasks_routes.py index 999500ce3..1cfd0c3db 100644 --- a/source/app/blueprints/case/case_tasks_routes.py +++ b/source/app/blueprints/case/case_tasks_routes.py @@ -20,7 +20,7 @@ from datetime import datetime import marshmallow -from flask import Blueprint +from flask import Blueprint, jsonify from flask import redirect from flask import render_template from flask import request @@ -77,6 +77,18 @@ def case_tasks(caseid, url_redir): return render_template("case_tasks.html", case=case, form=form) +@case_tasks_blueprint.route('/case/testjsoneeditorRoute', methods=['POST']) +def save_data(): + # Get the JSON data from the request + data = request.get_json() + + # Debugging output + print('Received data:', data) + + # Process the data (e.g., save to a database, etc.) + + # Return a response + return jsonify({"status": "success", "message": "Data saved successfully!"}) @case_tasks_blueprint.route('/case/tasks/list', methods=['GET']) @ac_api_case_requires(CaseAccessLevel.read_only, CaseAccessLevel.full_access) diff --git a/source/app/blueprints/case/templates/case_tasks.html b/source/app/blueprints/case/templates/case_tasks.html index 1108bdb87..5741dcddf 100644 --- a/source/app/blueprints/case/templates/case_tasks.html +++ b/source/app/blueprints/case/templates/case_tasks.html @@ -83,7 +83,7 @@ - {% include 'includes/footer.html' %} diff --git a/source/app/blueprints/case/templates/modal_add_case_task.html b/source/app/blueprints/case/templates/modal_add_case_task.html index 5b3bda995..6f51474a7 100644 --- a/source/app/blueprints/case/templates/modal_add_case_task.html +++ b/source/app/blueprints/case/templates/modal_add_case_task.html @@ -120,6 +120,13 @@ - {% endblock javascripts %} \ No newline at end of file diff --git a/source/app/datamgmt/manage/manage_case_templates_db.py b/source/app/datamgmt/manage/manage_case_templates_db.py index 3e95270a1..df56f8f14 100644 --- a/source/app/datamgmt/manage/manage_case_templates_db.py +++ b/source/app/datamgmt/manage/manage_case_templates_db.py @@ -439,5 +439,46 @@ def save_results(data, case_template_id, webhook_id): print(f"Error saving CaseResponse: {str(e)}") +# Methods for actions +def execute_and_save_action(action, case_template_id, payload): + try: + # Extract webhook_id from the action + webhook_id = action.get("webhook_id") + print(f"Webhook ID: {webhook_id}") # Debugging: Ensure webhook_id is being accessed + if not webhook_id: + raise ValueError("Trigger execution failed: webhook_id is missing in action.") + + # Fetch the webhook object from the database + webhook = get_webhook_by_id(webhook_id) + print(f"Webhook Object: {webhook}") # Debugging: Log the webhook object + if not webhook: + raise ValueError(f"Trigger execution failed: No webhook found for webhook_id {webhook_id}.") + # Fetch the URL from the webhook object + url = webhook.url # Adjust this based on your webhook model's attributes + print(f"Webhook URL: {url}") # Debugging: Ensure URL is being accessed + if not url: + raise ValueError(f"Trigger execution failed: URL is missing in webhook with id {webhook_id}.") + + # Execute the webhook request + print(f"Executing webhook request to URL: {url} with data: {action}") + response = requests.post(url, json=action) + print(f"Webhook Response Status Code: {response.status_code}") # Log response status + print(f"Webhook Response Content: {response.text}") # Log response content + + # Check response status + if response.status_code == 200: + results = response.json() + print(f"Webhook Execution Results: {results}") # Log the result of the execution + save_results(results, case_template_id, webhook_id) # Assuming save_results is implemented to handle the output + return f"Trigger executed successfully and saved for webhook_id {webhook_id}." + else: + raise ValueError( + f"Trigger execution failed: Webhook request returned status {response.status_code}, " + f"response: {response.text}" + ) + + except Exception as e: + print(f"Error in execute_and_save_action: {str(e)}") # Log the error + return str(e) diff --git a/source/app/static/assets/js/iris/case.tasks.js b/source/app/static/assets/js/iris/case.tasks.js index 52232d1c1..fb992f092 100644 --- a/source/app/static/assets/js/iris/case.tasks.js +++ b/source/app/static/assets/js/iris/case.tasks.js @@ -93,7 +93,7 @@ function edit_task(id) { text: action.name, click: function (e) { e.preventDefault(); // Prevent default link behavior - OpenJsonEditorModal(action.payload_schema); + expandActionDiv(action.payload_schema); }, }) ); @@ -115,65 +115,77 @@ function edit_task(id) { }); } -function OpenJsonEditorModal(payloadSchema) { - $('#responseModal').modal('show'); +function expandActionDiv(actionDetails) { + // Reference to the collapsible content div + const collapsibleContent = $('#collapsibleContent'); + const jsonEditorContainer = $('#jsoneditor'); - // Ensure the editor is initialized only once - if (!window.jsonEditor) { - window.jsonEditor = new JSONEditor(document.getElementById('jsoneditor'), { - schema: payloadSchema, - theme:'bootstrap4' - }); - } else { + // Show the collapsible content + collapsibleContent.slideDown(); + + // Reinitialize JSONEditor + if (window.jsonEditor) { + // Destroy the existing editor instance window.jsonEditor.destroy(); - window.jsonEditor = new JSONEditor(document.getElementById('jsoneditor'), { - schema: payloadSchema - }); + window.jsonEditor = null; // Clear reference to avoid accidental reuse } - // Set the default value if provided in the schema - if (payloadSchema.default) { - window.jsonEditor.set(payloadSchema); - } + // Create a new JSONEditor instance with the given schema + window.jsonEditor = new JSONEditor(jsonEditorContainer[0], { + schema: actionDetails, // Use the provided schema + theme: 'bootstrap4', + }); - // Save button event listener - $('#saveBtn').off('click').on('click', function () { - var updatedData = window.jsonEditor.get(); - console.log('Updated data:', updatedData); + // Use the `onReady` callback to ensure the editor is ready + window.jsonEditor.on('ready', function () { + console.log('JSONEditor is ready.'); + + // Set default data or use schema defaults if available + if (actionDetails.default) { + window.jsonEditor.setValue(actionDetails.default); + } else { + window.jsonEditor.setValue({}); // Initialize with an empty object if no default provided + } }); -} -// Function to handle displaying the response of the selected action using dummy data -function displayActionResponse(taskId, actionId) { - // Dummy response data for each action - var dummyResponses = { - 1: [ - { id: 1, task: 'Task 1', action: 'Review Task', response: 'Reviewed successfully', executionTime: '5s' }, - { id: 2, task: 'Task 2', action: 'Review Task', response: 'Minor changes needed', executionTime: '7s' } - ], - 2: [ - { id: 3, task: 'Task 3', action: 'Approve Task', response: 'Approved successfully', executionTime: '3s' } - ], - 3: [ - { id: 4, task: 'Task 4', action: 'Reject Task', response: 'Rejected due to issues', executionTime: '6s' } - ] - }; - - var response = dummyResponses[actionId] || []; - var table = $('#taskResponse_table').DataTable({ - destroy: true, // Reinitialize the table each time - data: response, - columns: [ - { data: 'id', title: 'ID' }, - { data: 'task', title: 'Tasks' }, - { data: 'action', title: 'Action' }, - { data: 'response', title: 'Response' }, - { data: 'executionTime', title: 'Execution Time' } - ] + // Update the Save button logic to handle the current action + $('#saveBtn').off('click').on('click', function (e) { + e.preventDefault(); + + // Retrieve the updated data from JSONEditor + const updatedData = window.jsonEditor.getValue(); + + console.log('Updated data:', updatedData); + + // Example: Simulated save logic (replace with your actual save endpoint) + fetch('/case/testjsoneeditorRoute', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(updatedData), + }) + .then((response) => { + if (!response.ok) { + throw new Error(`HTTP error! Status: ${response.status}`); + } + return response.json(); + }) + .then((data) => { + console.log('Save successful:', data); + alert('Data saved successfully!'); + }) + .catch((error) => { + console.error('Error saving data:', error); + alert('Error saving data. Please try again.'); + }); }); } + + + function save_task() { $('#submit_new_task').click(); } From 160b8ca1d025088f8300de5dd4a2c1d0a1b60180 Mon Sep 17 00:00:00 2001 From: Maham Riaz Keyani Date: Mon, 2 Dec 2024 18:27:29 +0500 Subject: [PATCH 39/80] added case_id and action_id to execute button --- .../blueprints/case/templates/modal_add_case_task.html | 2 +- source/app/static/assets/js/iris/case.tasks.js | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/source/app/blueprints/case/templates/modal_add_case_task.html b/source/app/blueprints/case/templates/modal_add_case_task.html index 6f51474a7..856355101 100644 --- a/source/app/blueprints/case/templates/modal_add_case_task.html +++ b/source/app/blueprints/case/templates/modal_add_case_task.html @@ -125,7 +125,7 @@