From ca76f8aa6b191da6f03c1b240ae18c6c2bdba617 Mon Sep 17 00:00:00 2001 From: KhulnaSoft bot <43526132+khulnasoft-bot@users.noreply.github.com> Date: Sun, 6 Oct 2024 02:12:31 +0600 Subject: [PATCH 01/14] Update job.py Signed-off-by: KhulnaSoft bot <43526132+khulnasoft-bot@users.noreply.github.com> --- api_app/serializers/job.py | 1 + 1 file changed, 1 insertion(+) diff --git a/api_app/serializers/job.py b/api_app/serializers/job.py index 28f8e2dc..d214bddf 100644 --- a/api_app/serializers/job.py +++ b/api_app/serializers/job.py @@ -478,6 +478,7 @@ class Meta: "playbook", "status", "received_request_time", + "is_sample", ] playbook = rfs.SlugRelatedField( From 1e5f593425ccb608a27f35aedaf258977576c38d Mon Sep 17 00:00:00 2001 From: KhulnaSoft bot <43526132+khulnasoft-bot@users.noreply.github.com> Date: Sun, 6 Oct 2024 02:15:42 +0600 Subject: [PATCH 02/14] Update views.py Signed-off-by: KhulnaSoft bot <43526132+khulnasoft-bot@users.noreply.github.com> --- api_app/views.py | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/api_app/views.py b/api_app/views.py index f0a8afbb..3dfd892f 100644 --- a/api_app/views.py +++ b/api_app/views.py @@ -20,6 +20,7 @@ from rest_framework.response import Response from rest_framework.viewsets import ModelViewSet +from api_app.choices import ScanMode from api_app.websocket import JobConsumer from certego_saas.apps.organization.permissions import ( IsObjectOwnerOrSameOrgPermission as IsObjectUserOrSameOrgPermission, @@ -452,7 +453,7 @@ def get_permissions(self): - List of applicable permissions. """ permissions = super().get_permissions() - if self.action in ["destroy", "kill"]: + if self.action in ["destroy", "kill", "rescan"]: permissions.append(IsObjectUserOrSameOrgPermission()) return permissions @@ -541,6 +542,36 @@ def retry(self, request, pk=None): job.retry() return Response(status=status.HTTP_204_NO_CONTENT) + @action(detail=True, methods=["post"]) + def rescan(self, request, pk=None): + logger.info(f"rescan request for job: {pk}") + existing_job: Job = self.get_object() + # create a new job + data = { + "tlp": existing_job.tlp, + "runtime_configuration": existing_job.runtime_configuration, + "scan_mode": ScanMode.FORCE_NEW_ANALYSIS, + } + if existing_job.playbook_requested: + data["playbook_requested"] = existing_job.playbook_requested + else: + data["analyzers_requested"] = existing_job.analyzers_requested.all() + data["connectors_requested"] = existing_job.connectors_requested.all() + if existing_job.is_sample: + data["file"] = existing_job.file + data["file_name"] = existing_job.file_name + job_serializer = FileJobSerializer(data=data, context={"request": request}) + else: + data["observable_classification"] = existing_job.observable_classification + data["observable_name"] = existing_job.observable_name + job_serializer = ObservableAnalysisSerializer( + data=data, context={"request": request} + ) + job_serializer.is_valid(raise_exception=True) + new_job = job_serializer.save(send_task=True) + logger.info(f"rescan request for job: {pk} generated job: {new_job.pk}") + return Response(data={"id": new_job.pk}, status=status.HTTP_202_ACCEPTED) + @add_docs( description="Kill running job by closing celery tasks and marking as killed", request=None, From 6fa86e965f29bdd6c162e3639ef88cfea7425cc9 Mon Sep 17 00:00:00 2001 From: KhulnaSoft bot <43526132+khulnasoft-bot@users.noreply.github.com> Date: Sun, 6 Oct 2024 02:16:30 +0600 Subject: [PATCH 03/14] Create .prettierignore Signed-off-by: KhulnaSoft bot <43526132+khulnasoft-bot@users.noreply.github.com> --- frontend/.prettierignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 frontend/.prettierignore diff --git a/frontend/.prettierignore b/frontend/.prettierignore new file mode 100644 index 00000000..84f38442 --- /dev/null +++ b/frontend/.prettierignore @@ -0,0 +1,2 @@ +# Ignore artifacts: +.coverage From adb796ae5a4ea9a1c53999a9ec3fbbae14d79435 Mon Sep 17 00:00:00 2001 From: KhulnaSoft bot <43526132+khulnasoft-bot@users.noreply.github.com> Date: Sun, 6 Oct 2024 02:17:54 +0600 Subject: [PATCH 04/14] Update CustomJobNode.jsx Signed-off-by: KhulnaSoft bot <43526132+khulnasoft-bot@users.noreply.github.com> --- .../src/components/investigations/flow/CustomJobNode.jsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/investigations/flow/CustomJobNode.jsx b/frontend/src/components/investigations/flow/CustomJobNode.jsx index 098d72e8..eba6ab80 100644 --- a/frontend/src/components/investigations/flow/CustomJobNode.jsx +++ b/frontend/src/components/investigations/flow/CustomJobNode.jsx @@ -56,7 +56,9 @@ function CustomJobNode({ data }) { id="investigation-pivotbtn" className="mx-1 p-2" size="sm" - href={`/scan?parent=${data.id}&observable=${data.name}`} + href={`/scan?parent=${data.id}&${ + data.is_sample ? "isSample=true" : `observable=${data.name}` + }`} target="_blank" rel="noreferrer" > @@ -67,7 +69,8 @@ function CustomJobNode({ data }) { placement="top" fade={false} > - Analyze the same observable again + Analyze the same observable again. CAUTION! Samples require to + select again the file. {data.isFirstLevel && } From e0e7fc7006c60c56f1a74f4394cd274b5c2b4197 Mon Sep 17 00:00:00 2001 From: KhulnaSoft bot <43526132+khulnasoft-bot@users.noreply.github.com> Date: Sun, 6 Oct 2024 02:18:30 +0600 Subject: [PATCH 05/14] Update utils.js Signed-off-by: KhulnaSoft bot <43526132+khulnasoft-bot@users.noreply.github.com> --- frontend/src/components/investigations/flow/utils.js | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/src/components/investigations/flow/utils.js b/frontend/src/components/investigations/flow/utils.js index 13c537b9..40939ff2 100644 --- a/frontend/src/components/investigations/flow/utils.js +++ b/frontend/src/components/investigations/flow/utils.js @@ -20,6 +20,7 @@ function addJobNode( investigation: investigationId, children: job.children || [], status: job.status, + is_sample: job.is_sample, refetchTree, refetchInvestigation, isFirstLevel: isFirstLevel || false, From 181f755b94f704005bbc981118185162ac87ca19 Mon Sep 17 00:00:00 2001 From: KhulnaSoft bot <43526132+khulnasoft-bot@users.noreply.github.com> Date: Sun, 6 Oct 2024 02:20:38 +0600 Subject: [PATCH 06/14] Update JobActionBar.jsx Signed-off-by: KhulnaSoft bot <43526132+khulnasoft-bot@users.noreply.github.com> --- .../jobs/result/bar/JobActionBar.jsx | 34 +++---------------- 1 file changed, 5 insertions(+), 29 deletions(-) diff --git a/frontend/src/components/jobs/result/bar/JobActionBar.jsx b/frontend/src/components/jobs/result/bar/JobActionBar.jsx index dd3bc3ce..767c8b11 100644 --- a/frontend/src/components/jobs/result/bar/JobActionBar.jsx +++ b/frontend/src/components/jobs/result/bar/JobActionBar.jsx @@ -8,9 +8,7 @@ import { ContentSection, IconButton, addToast } from "@certego/certego-ui"; import { SaveAsPlaybookButton } from "./SaveAsPlaybooksForm"; -import { downloadJobSample, deleteJob } from "../jobApi"; -import { createJob } from "../../../scan/scanApi"; -import { ScanModesNumeric } from "../../../../constants/advancedSettingsConst"; +import { downloadJobSample, deleteJob, rescanJob } from "../jobApi"; import { JobResultSections } from "../../../../constants/miscConst"; import { DeleteIcon, @@ -53,33 +51,11 @@ export function JobActionsBar({ job }) { }; const handleRetry = async () => { - if (job.is_sample) { - addToast( - "Rescan File!", - "It's not possible to repeat a sample analysis", - "warning", - false, - 2000, - ); - } else { - addToast("Retrying the same job...", null, "spinner", false, 2000); - const response = await createJob( - [job.observable_name], - job.observable_classification, - job.playbook_requested, - job.analyzers_requested, - job.connectors_requested, - job.runtime_configuration, - job.tags.map((optTag) => optTag.label), - job.tlp, - ScanModesNumeric.FORCE_NEW_ANALYSIS, - 0, - ); + addToast("Retrying the same job...", null, "spinner", false, 2000); + const newJobId = await rescanJob(job.id); + if (newJobId) { setTimeout( - () => - navigate( - `/jobs/${response.jobIds[0]}/${JobResultSections.VISUALIZER}/`, - ), + () => navigate(`/jobs/${newJobId}/${JobResultSections.VISUALIZER}/`), 1000, ); } From 1d3fb9f1f7d5cea636932150303b7495b4ab4c63 Mon Sep 17 00:00:00 2001 From: KhulnaSoft bot <43526132+khulnasoft-bot@users.noreply.github.com> Date: Sun, 6 Oct 2024 02:22:11 +0600 Subject: [PATCH 07/14] Update jobApi.jsx Signed-off-by: KhulnaSoft bot <43526132+khulnasoft-bot@users.noreply.github.com> --- .../src/components/jobs/result/jobApi.jsx | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/frontend/src/components/jobs/result/jobApi.jsx b/frontend/src/components/jobs/result/jobApi.jsx index f6d36666..50f5a537 100644 --- a/frontend/src/components/jobs/result/jobApi.jsx +++ b/frontend/src/components/jobs/result/jobApi.jsx @@ -61,6 +61,33 @@ export async function deleteJob(jobId) { return success; } +export async function rescanJob(jobId) { + try { + const response = await axios.post(`${JOB_BASE_URI}/${jobId}/rescan`); + const newJobId = response.data.id; + if (response.status === 202) { + addToast( + + Sent rescan request for job #{jobId}. Created job #{newJobId}. + , + null, + "success", + 2000, + ); + } + return newJobId; + } catch (error) { + addToast( + + Failed. Operation: rescan job #{jobId} + , + error.parsedMsg, + "warning", + ); + return null; + } +} + export async function killPlugin(jobId, plugin) { const sure = await areYouSureConfirmDialog( `kill ${plugin.type} '${plugin.name}'`, From e8a0edbd4503d1470f35d51a5daf484ea6ae7b1c Mon Sep 17 00:00:00 2001 From: KhulnaSoft bot <43526132+khulnasoft-bot@users.noreply.github.com> Date: Sun, 6 Oct 2024 02:25:43 +0600 Subject: [PATCH 08/14] Update ScanForm.jsx Signed-off-by: KhulnaSoft bot <43526132+khulnasoft-bot@users.noreply.github.com> --- frontend/src/components/scan/ScanForm.jsx | 49 +++++++++++------------ 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/frontend/src/components/scan/ScanForm.jsx b/frontend/src/components/scan/ScanForm.jsx index f27c8e40..faba1188 100644 --- a/frontend/src/components/scan/ScanForm.jsx +++ b/frontend/src/components/scan/ScanForm.jsx @@ -81,6 +81,7 @@ function DangerErrorMessage(fieldName) { export default function ScanForm() { const [searchParams, _] = useSearchParams(); const observableParam = searchParams.get(JobTypes.OBSERVABLE); + const isSampleParam = searchParams.get("isSample") === "true"; const investigationIdParam = searchParams.get("investigation") || null; const parentIdParam = searchParams.get("parent"); const { guideState, setGuideState } = useGuideContext(); @@ -416,6 +417,23 @@ export default function ScanForm() { })) .filter((item) => !item.isDisabled && item.starting); + const selectObservableType = (value) => { + formik.setFieldValue("observableType", value, false); + formik.setFieldValue( + "classification", + value === JobTypes.OBSERVABLE + ? ObservableClassifications.GENERIC + : JobTypes.FILE, + ); + formik.setFieldValue("observable_names", [""], false); + formik.setFieldValue("files", [""], false); + formik.setFieldValue("analysisOptionValues", ScanTypes.playbooks, false); + setScanType(ScanTypes.playbooks); + formik.setFieldValue("playbook", "", false); // reset + formik.setFieldValue("analyzers", [], false); // reset + formik.setFieldValue("connectors", [], false); // reset + }; + const updateAdvancedConfig = ( tags, tlp, @@ -535,9 +553,11 @@ export default function ScanForm() { if (observableParam) { updateSelectedObservable(observableParam, 0); if (formik.playbook) updateSelectedPlaybook(formik.playbook); + } else if (isSampleParam) { + selectObservableType(JobTypes.FILE); } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [observableParam, playbooksLoading]); + }, [observableParam, playbooksLoading, isSampleParam]); /* With the setFieldValue the validation and rerender don't work properly: the last update seems to not trigger the validation and leaves the UI with values not valid, for this reason the scan button is disabled, but if the user set focus on the UI the last @@ -614,30 +634,9 @@ export default function ScanForm() { type="radio" name="observableType" value={jobType} - onClick={(event) => { - formik.setFieldValue( - "observableType", - event.target.value, - false, - ); - formik.setFieldValue( - "classification", - event.target.value === JobTypes.OBSERVABLE - ? ObservableClassifications.GENERIC - : JobTypes.FILE, - ); - formik.setFieldValue("observable_names", [""], false); - formik.setFieldValue("files", [""], false); - formik.setFieldValue( - "analysisOptionValues", - ScanTypes.playbooks, - false, - ); - setScanType(ScanTypes.playbooks); - formik.setFieldValue("playbook", "", false); // reset - formik.setFieldValue("analyzers", [], false); // reset - formik.setFieldValue("connectors", [], false); // reset - }} + onClick={(event) => + selectObservableType(event.target.value) + } />