From 699e8a0c6fad4bd5961f78988bb78f19fb3227e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Srokosz?= Date: Wed, 18 Feb 2026 14:08:20 +0100 Subject: [PATCH] Offline HTML analysis reports (#1158) --- .../postprocessing/plugins/__init__.py | 6 + .../plugins/generate_html_report.py | 50 +++ drakrun/web/api.py | 12 + drakrun/web/frontend/embedded/index.html | 15 + .../frontend/embedded_report.vite.config.js | 45 ++ drakrun/web/frontend/package-lock.json | 397 ++++++++++++++---- drakrun/web/frontend/package.json | 6 +- drakrun/web/frontend/src/AnalysisReport.jsx | 140 +++--- .../frontend/src/AnalysisReportContext.jsx | 91 ++++ .../frontend/src/AnalysisScreenshotViewer.jsx | 11 +- drakrun/web/frontend/src/AnalysisView.jsx | 7 +- drakrun/web/frontend/src/App.jsx | 4 +- drakrun/web/frontend/src/ProcessTreeView.jsx | 3 +- drakrun/web/frontend/src/html_report_main.jsx | 53 +++ drakrun/web/storage.py | 6 +- 15 files changed, 686 insertions(+), 160 deletions(-) create mode 100644 drakrun/analyzer/postprocessing/plugins/generate_html_report.py create mode 100644 drakrun/web/frontend/embedded/index.html create mode 100644 drakrun/web/frontend/embedded_report.vite.config.js create mode 100644 drakrun/web/frontend/src/AnalysisReportContext.jsx create mode 100644 drakrun/web/frontend/src/html_report_main.jsx diff --git a/drakrun/analyzer/postprocessing/plugins/__init__.py b/drakrun/analyzer/postprocessing/plugins/__init__.py index b5f199c6..2758570e 100644 --- a/drakrun/analyzer/postprocessing/plugins/__init__.py +++ b/drakrun/analyzer/postprocessing/plugins/__init__.py @@ -3,6 +3,7 @@ from drakrun.lib.paths import DUMPS_DIR, DUMPS_ZIP, IPT_DIR, IPT_ZIP from .build_process_tree import build_process_tree from .capa_plugin.capa_processor import capa_analysis from .compress_ipt import compress_ipt +from .generate_html_report import generate_html_report from .generate_report import generate_report from .generate_wireshark_key_file import generate_wireshark_key_file from .get_http_info import get_http_info @@ -85,6 +86,11 @@ POSTPROCESS_PLUGINS = [ requires=[], generates=[], ), + PostprocessPlugin( + function=generate_html_report, + requires=["report.json"], + generates=["report.html"], + ), PostprocessPlugin( function=index_logs, requires=["process_tree.json"], generates=["log_index"] ), diff --git a/drakrun/analyzer/postprocessing/plugins/generate_html_report.py b/drakrun/analyzer/postprocessing/plugins/generate_html_report.py new file mode 100644 index 00000000..948537ac --- /dev/null +++ b/drakrun/analyzer/postprocessing/plugins/generate_html_report.py @@ -0,0 +1,50 @@ +import base64 +import json +import logging + +from drakrun.lib.paths import PACKAGE_DIR + +from .plugin_base import PostprocessContext + +logger = logging.getLogger(__name__) + +HTML_TEMPLATE = PACKAGE_DIR / "web/frontend/dist/embedded/index.html" +OFFLINE_FILES_PLACEHOLDER = "window.OFFLINE_FILES = {};" + + +def png_bytes_to_data_uri(png_bytes: bytes): + encoded = base64.b64encode(png_bytes).decode("ascii") + return f"data:image/png;base64,{encoded}" + + +def generate_html_report(context: PostprocessContext) -> None: + offline_files = { + "metadata.json": { + **context.metadata.store_to_dict(), + **context.extra_metadata, + } + } + + report_file = context.analysis_dir / "report.json" + with report_file.open("r") as f: + offline_files["report.json"] = json.load(f) + + process_tree_file = context.analysis_dir / "process_tree.json" + if process_tree_file.exists(): + with process_tree_file.open("r") as f: + offline_files["process_tree.json"] = json.load(f) + + offline_files["screenshots"] = [] + screenshots_count = offline_files["metadata.json"].get("screenshots", 0) + for which in range(screenshots_count): + with (context.analysis_dir / f"screenshots/screenshot_{which+1}.png").open( + "rb" + ) as f: + screenshot_data_uri = png_bytes_to_data_uri(f.read()) + offline_files["screenshots"].append(screenshot_data_uri) + + html_report = HTML_TEMPLATE.read_text().replace( + OFFLINE_FILES_PLACEHOLDER, f"window.OFFLINE_FILES={json.dumps(offline_files)};" + ) + (context.analysis_dir / "report.html").write_text(html_report) + context.update_metadata({"html_report": True}) diff --git a/drakrun/web/api.py b/drakrun/web/api.py index b694b0d5..d9ffc3b6 100644 --- a/drakrun/web/api.py +++ b/drakrun/web/api.py @@ -389,3 +389,15 @@ def screenshot(path: ScreenshotRequestPath): mimetype="image/png", s3_config=config.s3, ) + + +@api.get("/html/") +def get_html_report(path: AnalysisRequestPath): + task_uid = path.task_uid + return send_analysis_file( + task_uid, + "report.html", + mimetype="text/html", + s3_config=config.s3, + download_name=f"report-{task_uid}.html", + ) diff --git a/drakrun/web/frontend/embedded/index.html b/drakrun/web/frontend/embedded/index.html new file mode 100644 index 00000000..b0ca72be --- /dev/null +++ b/drakrun/web/frontend/embedded/index.html @@ -0,0 +1,15 @@ + + + + + + DRAKVUF Sandbox + + +
+ + + + diff --git a/drakrun/web/frontend/embedded_report.vite.config.js b/drakrun/web/frontend/embedded_report.vite.config.js new file mode 100644 index 00000000..91a963ea --- /dev/null +++ b/drakrun/web/frontend/embedded_report.vite.config.js @@ -0,0 +1,45 @@ +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react"; +import { viteSingleFile } from "vite-plugin-singlefile"; +import cssInjectedByJsPlugin from "vite-plugin-css-injected-by-js"; +import { gzipSync } from "node:zlib"; + +function viteGzipBundle() { + return { + name: "vite:gzip-bundle-plugin", + apply: "build", + enforce: "post", + generateBundle(_, bundle) { + for (const [fileName, chunk] of Object.entries(bundle)) { + if (chunk.type === "chunk" && fileName.endsWith(".js")) { + console.log("[gzip] ", fileName); + const originalCode = chunk.code; + const gzipped = gzipSync( + Buffer.from(originalCode, "utf-8"), + ); + const base64 = gzipped.toString("base64"); + const loader = `await import(URL.createObjectURL(new Blob([await new Response((await fetch('data:;base64,${base64}')).body.pipeThrough(new DecompressionStream('gzip'))).text()],{type:'application/javascript'})))`; + chunk.code = loader; + } + } + }, + }; +} + +// https://vite.dev/config/ +export default defineConfig({ + root: "./embedded", + plugins: [ + react(), + cssInjectedByJsPlugin(), + viteGzipBundle(), + viteSingleFile(), + ], + define: { + __APP_VERSION__: JSON.stringify(process.env.npm_package_version), + }, + build: { + outDir: "../dist/embedded", + emptyOutDir: true, + }, +}); diff --git a/drakrun/web/frontend/package-lock.json b/drakrun/web/frontend/package-lock.json index d7f520a3..6615c32f 100644 --- a/drakrun/web/frontend/package-lock.json +++ b/drakrun/web/frontend/package-lock.json @@ -36,7 +36,9 @@ "eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-react-refresh": "^0.4.19", "globals": "^16.0.0", - "vite": "^6.4.1" + "vite": "^6.4.1", + "vite-plugin-css-injected-by-js": "^3.5.2", + "vite-plugin-singlefile": "^2.3.0" } }, "node_modules/@ampproject/remapping": { @@ -79,6 +81,7 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.10.tgz", "integrity": "sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==", "dev": true, + "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.26.2", @@ -1010,6 +1013,7 @@ "version": "6.7.2", "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.7.2.tgz", "integrity": "sha512-yxtOBWDrdi5DD5o1pmVdq3WMCvnobT0LU6R8RyyVXPvFRd2o79/0NCuQoCjNTeZz9EzA9xS3JxNWfv54RIHFEA==", + "peer": true, "dependencies": { "@fortawesome/fontawesome-common-types": "6.7.2" }, @@ -1195,260 +1199,350 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.40.0.tgz", - "integrity": "sha512-+Fbls/diZ0RDerhE8kyC6hjADCXA1K4yVNlH0EYfd2XjyH0UGgzaQ8MlT0pCXAThfxv3QUAczHaL+qSv1E4/Cg==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.1.tgz", + "integrity": "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.40.0.tgz", - "integrity": "sha512-PPA6aEEsTPRz+/4xxAmaoWDqh67N7wFbgFUJGMnanCFs0TV99M0M8QhhaSCks+n6EbQoFvLQgYOGXxlMGQe/6w==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.57.1.tgz", + "integrity": "sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.40.0.tgz", - "integrity": "sha512-GwYOcOakYHdfnjjKwqpTGgn5a6cUX7+Ra2HeNj/GdXvO2VJOOXCiYYlRFU4CubFM67EhbmzLOmACKEfvp3J1kQ==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.57.1.tgz", + "integrity": "sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.40.0.tgz", - "integrity": "sha512-CoLEGJ+2eheqD9KBSxmma6ld01czS52Iw0e2qMZNpPDlf7Z9mj8xmMemxEucinev4LgHalDPczMyxzbq+Q+EtA==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.57.1.tgz", + "integrity": "sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.40.0.tgz", - "integrity": "sha512-r7yGiS4HN/kibvESzmrOB/PxKMhPTlz+FcGvoUIKYoTyGd5toHp48g1uZy1o1xQvybwwpqpe010JrcGG2s5nkg==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.57.1.tgz", + "integrity": "sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.40.0.tgz", - "integrity": "sha512-mVDxzlf0oLzV3oZOr0SMJ0lSDd3xC4CmnWJ8Val8isp9jRGl5Dq//LLDSPFrasS7pSm6m5xAcKaw3sHXhBjoRw==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.57.1.tgz", + "integrity": "sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.40.0.tgz", - "integrity": "sha512-y/qUMOpJxBMy8xCXD++jeu8t7kzjlOCkoxxajL58G62PJGBZVl/Gwpm7JK9+YvlB701rcQTzjUZ1JgUoPTnoQA==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.57.1.tgz", + "integrity": "sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.40.0.tgz", - "integrity": "sha512-GoCsPibtVdJFPv/BOIvBKO/XmwZLwaNWdyD8TKlXuqp0veo2sHE+A/vpMQ5iSArRUz/uaoj4h5S6Pn0+PdhRjg==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.57.1.tgz", + "integrity": "sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.40.0.tgz", - "integrity": "sha512-L5ZLphTjjAD9leJzSLI7rr8fNqJMlGDKlazW2tX4IUF9P7R5TMQPElpH82Q7eNIDQnQlAyiNVfRPfP2vM5Avvg==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.57.1.tgz", + "integrity": "sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.40.0.tgz", - "integrity": "sha512-ATZvCRGCDtv1Y4gpDIXsS+wfFeFuLwVxyUBSLawjgXK2tRE6fnsQEkE4csQQYWlBlsFztRzCnBvWVfcae/1qxQ==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.57.1.tgz", + "integrity": "sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, - "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.40.0.tgz", - "integrity": "sha512-wG9e2XtIhd++QugU5MD9i7OnpaVb08ji3P1y/hNbxrQ3sYEelKJOq1UJ5dXczeo6Hj2rfDEL5GdtkMSVLa/AOg==", + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.57.1.tgz", + "integrity": "sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==", "cpu": [ "loong64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, - "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.40.0.tgz", - "integrity": "sha512-vgXfWmj0f3jAUvC7TZSU/m/cOE558ILWDzS7jBhiCAFpY2WEBn5jqgbqvmzlMjtp8KlLcBlXVD2mkTSEQE6Ixw==", + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.57.1.tgz", + "integrity": "sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.57.1.tgz", + "integrity": "sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==", "cpu": [ "ppc64" ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.57.1.tgz", + "integrity": "sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.40.0.tgz", - "integrity": "sha512-uJkYTugqtPZBS3Z136arevt/FsKTF/J9dEMTX/cwR7lsAW4bShzI2R0pJVw+hcBTWF4dxVckYh72Hk3/hWNKvA==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.57.1.tgz", + "integrity": "sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==", "cpu": [ "riscv64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.40.0.tgz", - "integrity": "sha512-rKmSj6EXQRnhSkE22+WvrqOqRtk733x3p5sWpZilhmjnkHkpeCgWsFFo0dGnUGeA+OZjRl3+VYq+HyCOEuwcxQ==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.57.1.tgz", + "integrity": "sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==", "cpu": [ "riscv64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.40.0.tgz", - "integrity": "sha512-SpnYlAfKPOoVsQqmTFJ0usx0z84bzGOS9anAC0AZ3rdSo3snecihbhFTlJZ8XMwzqAcodjFU4+/SM311dqE5Sw==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.57.1.tgz", + "integrity": "sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==", "cpu": [ "s390x" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.40.0.tgz", - "integrity": "sha512-RcDGMtqF9EFN8i2RYN2W+64CdHruJ5rPqrlYw+cgM3uOVPSsnAQps7cpjXe9be/yDp8UC7VLoCoKC8J3Kn2FkQ==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.57.1.tgz", + "integrity": "sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.40.0.tgz", - "integrity": "sha512-HZvjpiUmSNx5zFgwtQAV1GaGazT2RWvqeDi0hV+AtC8unqqDSsaFjPxfsO6qPtKRRg25SisACWnJ37Yio8ttaw==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.57.1.tgz", + "integrity": "sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.40.0.tgz", - "integrity": "sha512-UtZQQI5k/b8d7d3i9AZmA/t+Q4tk3hOC0tMOMSq2GlMYOfxbesxG4mJSeDp0EHs30N9bsfwUvs3zF4v/RzOeTQ==", + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.57.1.tgz", + "integrity": "sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.57.1.tgz", + "integrity": "sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.57.1.tgz", + "integrity": "sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.40.0.tgz", - "integrity": "sha512-+m03kvI2f5syIqHXCZLPVYplP8pQch9JHyXKZ3AGMKlg8dCyr2PKHjwRLiW53LTrN/Nc3EqHOKxUxzoSPdKddA==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.57.1.tgz", + "integrity": "sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==", "cpu": [ "ia32" ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.57.1.tgz", + "integrity": "sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.40.0.tgz", - "integrity": "sha512-lpPE1cLfP5oPzVjKMx10pgBmKELQnFJXHgvtHCtuJWOv8MxqdEIMNtgHgBFf7Ea2/7EuVwa9fodWUfXAlXZLZQ==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.57.1.tgz", + "integrity": "sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -1496,10 +1590,11 @@ } }, "node_modules/@types/estree": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", - "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", - "dev": true + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" }, "node_modules/@types/json-schema": { "version": "7.0.15", @@ -1516,6 +1611,7 @@ "version": "19.1.2", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.2.tgz", "integrity": "sha512-oxLPMytKchWGbnQM9O7D67uPa9paTNxO7jVoNMXgkkErULBPhPARCfkKL9ytcIJJRGjbsVwW4ugJzyFFvm/Tiw==", + "peer": true, "dependencies": { "csstype": "^3.0.2" } @@ -1561,6 +1657,7 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", "dev": true, + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -1679,6 +1776,19 @@ "concat-map": "0.0.1" } }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/browserslist": { "version": "4.24.4", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz", @@ -1698,6 +1808,7 @@ "url": "https://github.com/sponsors/ai" } ], + "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001688", "electron-to-chromium": "^1.5.73", @@ -2035,6 +2146,7 @@ "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.24.0.tgz", "integrity": "sha512-eh/jxIEJyZrvbWRe4XuVclLPDYSYYYgLy5zXGGxD6j8zjSAxFEzI2fL/8xNq6O2yKqVt+eF2YhV+hxjV6UKXwQ==", "dev": true, + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", @@ -2248,6 +2360,19 @@ "node": ">=16.0.0" } }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/find-root": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", @@ -2574,6 +2699,16 @@ "node": ">=0.10.0" } }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -2755,6 +2890,33 @@ "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==" }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -2958,6 +3120,7 @@ "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -3049,6 +3212,7 @@ "version": "19.1.0", "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -3057,6 +3221,7 @@ "version": "19.1.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz", "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==", + "peer": true, "dependencies": { "scheduler": "^0.26.0" }, @@ -3235,12 +3400,14 @@ } }, "node_modules/rollup": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.40.0.tgz", - "integrity": "sha512-Noe455xmA96nnqH5piFtLobsGbCij7Tu+tb3c1vYjNbTkfzGqXqQXG3wJaYXkRZuQ0vEYN4bhwg7QnIrqB5B+w==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.1.tgz", + "integrity": "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==", "dev": true, + "license": "MIT", + "peer": true, "dependencies": { - "@types/estree": "1.0.7" + "@types/estree": "1.0.8" }, "bin": { "rollup": "dist/bin/rollup" @@ -3250,26 +3417,31 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.40.0", - "@rollup/rollup-android-arm64": "4.40.0", - "@rollup/rollup-darwin-arm64": "4.40.0", - "@rollup/rollup-darwin-x64": "4.40.0", - "@rollup/rollup-freebsd-arm64": "4.40.0", - "@rollup/rollup-freebsd-x64": "4.40.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.40.0", - "@rollup/rollup-linux-arm-musleabihf": "4.40.0", - "@rollup/rollup-linux-arm64-gnu": "4.40.0", - "@rollup/rollup-linux-arm64-musl": "4.40.0", - "@rollup/rollup-linux-loongarch64-gnu": "4.40.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.40.0", - "@rollup/rollup-linux-riscv64-gnu": "4.40.0", - "@rollup/rollup-linux-riscv64-musl": "4.40.0", - "@rollup/rollup-linux-s390x-gnu": "4.40.0", - "@rollup/rollup-linux-x64-gnu": "4.40.0", - "@rollup/rollup-linux-x64-musl": "4.40.0", - "@rollup/rollup-win32-arm64-msvc": "4.40.0", - "@rollup/rollup-win32-ia32-msvc": "4.40.0", - "@rollup/rollup-win32-x64-msvc": "4.40.0", + "@rollup/rollup-android-arm-eabi": "4.57.1", + "@rollup/rollup-android-arm64": "4.57.1", + "@rollup/rollup-darwin-arm64": "4.57.1", + "@rollup/rollup-darwin-x64": "4.57.1", + "@rollup/rollup-freebsd-arm64": "4.57.1", + "@rollup/rollup-freebsd-x64": "4.57.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.57.1", + "@rollup/rollup-linux-arm-musleabihf": "4.57.1", + "@rollup/rollup-linux-arm64-gnu": "4.57.1", + "@rollup/rollup-linux-arm64-musl": "4.57.1", + "@rollup/rollup-linux-loong64-gnu": "4.57.1", + "@rollup/rollup-linux-loong64-musl": "4.57.1", + "@rollup/rollup-linux-ppc64-gnu": "4.57.1", + "@rollup/rollup-linux-ppc64-musl": "4.57.1", + "@rollup/rollup-linux-riscv64-gnu": "4.57.1", + "@rollup/rollup-linux-riscv64-musl": "4.57.1", + "@rollup/rollup-linux-s390x-gnu": "4.57.1", + "@rollup/rollup-linux-x64-gnu": "4.57.1", + "@rollup/rollup-linux-x64-musl": "4.57.1", + "@rollup/rollup-openbsd-x64": "4.57.1", + "@rollup/rollup-openharmony-arm64": "4.57.1", + "@rollup/rollup-win32-arm64-msvc": "4.57.1", + "@rollup/rollup-win32-ia32-msvc": "4.57.1", + "@rollup/rollup-win32-x64-gnu": "4.57.1", + "@rollup/rollup-win32-x64-msvc": "4.57.1", "fsevents": "~2.3.2" } }, @@ -3426,6 +3598,19 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -3530,6 +3715,7 @@ "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", @@ -3599,6 +3785,33 @@ } } }, + "node_modules/vite-plugin-css-injected-by-js": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/vite-plugin-css-injected-by-js/-/vite-plugin-css-injected-by-js-3.5.2.tgz", + "integrity": "sha512-2MpU/Y+SCZyWUB6ua3HbJCrgnF0KACAsmzOQt1UvRVJCGF6S8xdA3ZUhWcWdM9ivG4I5az8PnQmwwrkC2CAQrQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "vite": ">2.0.0-0" + } + }, + "node_modules/vite-plugin-singlefile": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/vite-plugin-singlefile/-/vite-plugin-singlefile-2.3.0.tgz", + "integrity": "sha512-DAcHzYypM0CasNLSz/WG0VdKOCxGHErfrjOoyIPiNxTPTGmO6rRD/te93n1YL/s+miXq66ipF1brMBikf99c6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">18.0.0" + }, + "peerDependencies": { + "rollup": "^4.44.1", + "vite": "^5.4.11 || ^6.0.0 || ^7.0.0" + } + }, "node_modules/warning": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", diff --git a/drakrun/web/frontend/package.json b/drakrun/web/frontend/package.json index 351db903..2357837e 100644 --- a/drakrun/web/frontend/package.json +++ b/drakrun/web/frontend/package.json @@ -5,7 +5,7 @@ "type": "module", "scripts": { "dev": "vite", - "build": "vite build", + "build": "vite build && vite build --config embedded_report.vite.config.js", "lint": "eslint .", "preview": "vite preview" }, @@ -38,7 +38,9 @@ "eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-react-refresh": "^0.4.19", "globals": "^16.0.0", - "vite": "^6.4.1" + "vite": "^6.4.1", + "vite-plugin-css-injected-by-js": "^3.5.2", + "vite-plugin-singlefile": "^2.3.0" }, "prettier": { "tabWidth": 4 diff --git a/drakrun/web/frontend/src/AnalysisReport.jsx b/drakrun/web/frontend/src/AnalysisReport.jsx index 3c76586d..91f352a9 100644 --- a/drakrun/web/frontend/src/AnalysisReport.jsx +++ b/drakrun/web/frontend/src/AnalysisReport.jsx @@ -1,11 +1,5 @@ import { useCallback, useEffect, useState } from "react"; -import { - getAnalysisSummary, - getLog, - getLogList, - getProcessInfo, - getProcessLog, -} from "./api.js"; +import { getLog, getLogList, getProcessLog } from "./api.js"; import { TabSwitcher, Tab, useTabContext } from "./TabSwitcher.jsx"; import { getLogLoader, LogViewer } from "./LogViewer.jsx"; import { AnalysisMetadataTable } from "./AnalysisMetadataTable.jsx"; @@ -19,6 +13,7 @@ import axios, { CanceledError } from "axios"; import { AnalysisSummary } from "./AnalysisSummary.jsx"; import { ProcessBadge } from "./ProcessBadge.jsx"; import { AnalysisFilesViewer } from "./AnalysisFiles.jsx"; +import { useAnalysisReport } from "./AnalysisReportContext.jsx"; export function AnalysisLogViewerTab({ analysisId }) { const logType = useTabContext()?.activeTab; @@ -136,6 +131,7 @@ function ProcessLogViewer({ analysisId, selectedProcess }) { const [activeTab, setActiveTab] = useState(); const [processInfo, setProcessInfo] = useState(); const [error, setError] = useState(); + const { getProcessInfo, isOffline } = useAnalysisReport(); const loadProcessInfo = useCallback( async (processSeqId) => { try { @@ -194,11 +190,15 @@ function ProcessLogViewer({ analysisId, selectedProcess }) { selectedProcess={selectedProcess} processInfo={processInfo} /> - + {!isOffline ? ( + + ) : ( + [] + )} @@ -220,6 +220,7 @@ function AnalysisReportTabs({ setSelectedProcess, activeReportTab, setActiveReportTab, + isOffline, }) { const getHeader = useCallback( (tab) => { @@ -256,9 +257,13 @@ function AnalysisReportTabs({ setSelectedProcess={setSelectedProcess} /> - - - + {!isOffline ? ( + + + + ) : ( + [] + )} ) : null} - - - + {!isOffline ? ( + + + + ) : ( + [] + )} ); } -export function AnalysisReport({ analysis }) { +export function AnalysisReport() { const [selectedProcess, setSelectedProcess] = useState(); const [activeReportTab, setActiveReportTab] = useState(); const [analysisSummary, setAnalysisSummary] = useState(); + const { + analysisInfo: analysis, + getAnalysisSummary, + isOffline, + } = useAnalysisReport(); const plugins = analysis.options?.plugins; const baseUrl = axios.defaults.baseURL; const analysisId = analysis.id; @@ -298,7 +312,7 @@ export function AnalysisReport({ analysis }) { console.error(error); } }); - }, [analysisId]); + }, [analysisId, getAnalysisSummary]); useEffect(() => { fetchSummary(); @@ -324,47 +338,66 @@ export function AnalysisReport({ analysis }) {
-
-
- - - - {Array.isArray(plugins) && - plugins.includes("tlsmon") ? ( - + {!isOffline ? ( +
+
+ - ) : ( - [] - )} - {Array.isArray(plugins) && - plugins.includes("memdump") ? ( - - - - ) : ( - [] - )} + {Array.isArray(plugins) && + plugins.includes("tlsmon") ? ( + + + + ) : ( + [] + )} + {Array.isArray(plugins) && + plugins.includes("memdump") ? ( + + + + ) : ( + [] + )} + {analysis["html_report"] ? ( + + + + ) : ( + [] + )} +
-
+ ) : ( + [] + )}
@@ -376,6 +409,7 @@ export function AnalysisReport({ analysis }) { setSelectedProcess={onSelectProcess} activeReportTab={activeReportTab} setActiveReportTab={setActiveReportTab} + isOffline={isOffline} />
diff --git a/drakrun/web/frontend/src/AnalysisReportContext.jsx b/drakrun/web/frontend/src/AnalysisReportContext.jsx new file mode 100644 index 00000000..51843d6d --- /dev/null +++ b/drakrun/web/frontend/src/AnalysisReportContext.jsx @@ -0,0 +1,91 @@ +import React, { useContext, useMemo } from "react"; +import { + getAnalysisSummary, + getProcessInfo, + getAnalysisProcessTree, +} from "./api.js"; + +const AnalysisReportContext = React.createContext({}); + +let BASE_URL = ""; +if (import.meta.env.VITE_API_SERVER) { + BASE_URL = import.meta.env.VITE_API_SERVER; +} else { + BASE_URL = "/api"; +} + +export function useAnalysisReport() { + return useContext(AnalysisReportContext); +} + +export function OnlineAnalysisReportProvider({ analysisInfo, children }) { + const contextValue = useMemo( + () => ({ + analysisInfo, + getAnalysisSummary, + getProcessInfo, + getAnalysisProcessTree, + getScreenshotURL: (analysis_id, screenshot_idx) => + `${BASE_URL}/screenshot/${analysis_id}/${screenshot_idx}`, + isOffline: false, + }), + [analysisInfo], + ); + return ( + + {children} + + ); +} + +export function OfflineAnalysisReportProvider({ reportData, children }) { + const contextValue = useMemo( + () => ({ + analysisInfo: reportData["metadata.json"], + getAnalysisSummary: () => + new Promise((resolve) => { + resolve(reportData["report.json"]); + }), + getProcessInfo: ({ processSeqId }) => + new Promise((resolve) => { + // Conversion between schemas if /api/report and /api/process_info + const processes = reportData["report.json"].processes; + const processInfo = processes[processSeqId]; + const ppid = + processInfo["parent_seqid"] !== null + ? processes[processInfo["parent_seqid"]].pid + : null; + resolve({ + logs: {}, + process: { + ...processInfo, + // evtid: We don't have it in report.json and don't need it + // as we don't have offline logs for now. If needed, change + // this code to fetch information from process_tree.json + // instead of report.json (process_tree needs tree traversal) + evtid_from: 0, + evtid_to: 0, + ppid: ppid, + procname: processInfo["name"], + ts_from: processInfo["started_at"], + ts_to: processInfo["exited_at"], + }, + }); + }), + getAnalysisProcessTree: () => + new Promise((resolve) => { + resolve(reportData["process_tree.json"]); + }), + getScreenshotURL: (analysis_id, screenshot_idx) => + reportData["screenshots"] && + reportData["screenshots"][screenshot_idx - 1], + isOffline: true, + }), + [reportData], + ); + return ( + + {children} + + ); +} diff --git a/drakrun/web/frontend/src/AnalysisScreenshotViewer.jsx b/drakrun/web/frontend/src/AnalysisScreenshotViewer.jsx index 104a79bd..51092e93 100644 --- a/drakrun/web/frontend/src/AnalysisScreenshotViewer.jsx +++ b/drakrun/web/frontend/src/AnalysisScreenshotViewer.jsx @@ -1,14 +1,9 @@ import Zoom from "react-medium-image-zoom"; import "react-medium-image-zoom/dist/styles.css"; - -let BASE_URL = ""; -if (import.meta.env.VITE_API_SERVER) { - BASE_URL = import.meta.env.VITE_API_SERVER; -} else { - BASE_URL = "/api"; -} +import { useAnalysisReport } from "./AnalysisReportContext.jsx"; export function AnalysisScreenshotViewer({ analysis }) { + const { getScreenshotURL } = useAnalysisReport(); return (
@@ -18,7 +13,7 @@ export function AnalysisScreenshotViewer({ analysis }) { {`screenshot-${idx diff --git a/drakrun/web/frontend/src/AnalysisView.jsx b/drakrun/web/frontend/src/AnalysisView.jsx index 54465afa..03eb3b7f 100644 --- a/drakrun/web/frontend/src/AnalysisView.jsx +++ b/drakrun/web/frontend/src/AnalysisView.jsx @@ -8,6 +8,7 @@ import { AnalysisPendingStatusBox, } from "./AnalysisPendingView.jsx"; import { AnalysisReport } from "./AnalysisReport.jsx"; +import { OnlineAnalysisReportProvider } from "./AnalysisReportContext.jsx"; function AnalysisViewComponent({ analysisId }) { const checkInterval = useRef(null); @@ -76,7 +77,11 @@ function AnalysisViewComponent({ analysisId }) { if (isStatusPending(analysisInfo?.status)) { return ; } - return ; + return ( + + + + ); } export default function AnalysisView() { diff --git a/drakrun/web/frontend/src/App.jsx b/drakrun/web/frontend/src/App.jsx index ea3f5748..51004720 100644 --- a/drakrun/web/frontend/src/App.jsx +++ b/drakrun/web/frontend/src/App.jsx @@ -10,7 +10,7 @@ import AnalysisView from "./AnalysisView.jsx"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faFolder, faUpload, faGear } from "@fortawesome/free-solid-svg-icons"; -function AppHeader() { +export function AppHeader() { return (