Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions frontend/src/components/GuideWrapper.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import Joyride from "react-joyride";
import { Outlet, useNavigate } from "react-router-dom";
import { useMount } from "react-use";
import { useGuideContext } from "../contexts/GuideContext";
import { INTELOWL_DOCS_URL } from "../constants/environment";

export default function GuideWrapper() {
const { guideState, setGuideState } = useGuideContext();
Expand All @@ -17,8 +18,7 @@ export default function GuideWrapper() {
<p>
Welcome to IntelOwls Guide for First Time Visitors! For further
questions you could either check out our{" "}
<a href="https://intelowlproject.github.io/docs/">docs</a> or reach
us out on{" "}
<a href={INTELOWL_DOCS_URL}>docs</a> or reach us out on{" "}
<a href="https://gsoc-slack.honeynet.org/">
the official IntelOwl slack channel
</a>
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/components/common/form/TLPSelectInput.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { TLPDescriptions } from "../../../constants/miscConst";
import { TlpChoices } from "../../../constants/advancedSettingsConst";
import { TLPTag } from "../TLPTag";
import { TLPColors } from "../../../constants/colorConst";
import { INTELOWL_DOCS_URL } from "../../../constants/environment";

export function TLPSelectInputLabel(props) {
const { size } = props;
Expand All @@ -36,7 +37,7 @@ export function TLPSelectInputLabel(props) {
<br />
For more info check the{" "}
<Link
to="https://intelowlproject.github.io/docs/IntelOwl/usage/#tlp-support"
to={`${INTELOWL_DOCS_URL}IntelOwl/usage/#tlp-support`}
target="_blank"
>
official doc.
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/components/plugins/PluginConfigModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { AnalyzerConfigForm } from "./forms/AnalyzerConfigForm";
import { PivotConfigForm } from "./forms/PivotConfigForm";
import { PlaybookConfigForm } from "./forms/PlaybookConfigForm";
import { PluginConfigContainer } from "./PluginConfigContainer";
import { INTELOWL_DOCS_URL } from "../../constants/environment";

export function PluginConfigModal({
pluginConfig,
Expand Down Expand Up @@ -45,7 +46,7 @@ export function PluginConfigModal({
<br />
For more info check the{" "}
<Link
to="https://intelowlproject.github.io/docs/IntelOwl/usage/#parameters"
to={`${INTELOWL_DOCS_URL}IntelOwl/usage/#parameters`}
target="_blank"
>
official doc.
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/components/plugins/tables/PluginWrapper.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
import { useOrganizationStore } from "../../../stores/useOrganizationStore";
import { usePluginConfigurationStore } from "../../../stores/usePluginConfigurationStore";
import { PluginsTypes } from "../../../constants/pluginConst";
import { INTELOWL_DOCS_URL } from "../../../constants/environment";

// table config
const tableConfig = {};
Expand Down Expand Up @@ -67,7 +68,7 @@ export default function PluginWrapper({
<span className="text-muted">
{description} For more info check the{" "}
<Link
to="https://intelowlproject.github.io/docs/IntelOwl/usage/#plugins-framework"
to={`${INTELOWL_DOCS_URL}IntelOwl/usage/#plugins-framework`}
target="_blank"
>
official doc.
Expand Down
120 changes: 117 additions & 3 deletions frontend/src/components/plugins/tables/pluginActionsButtons.jsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,26 @@
import React from "react";
import PropTypes from "prop-types";
import { Button, Modal, ModalHeader, ModalBody } from "reactstrap";
import {
Button,
Modal,
ModalHeader,
ModalBody,
UncontrolledTooltip,
} from "reactstrap";
import { RiHeartPulseLine } from "react-icons/ri";
import { MdDelete, MdFileDownload, MdEdit } from "react-icons/md";
import {
MdDelete,
MdFileDownload,
MdEdit,
MdInfoOutline,
} from "react-icons/md";
import { BsPeopleFill } from "react-icons/bs";
import { AiFillSetting } from "react-icons/ai";
import { FaDiagramProject } from "react-icons/fa6";
import { VscJson } from "react-icons/vsc";
import { Link } from "react-router-dom";

import { IconButton } from "@certego/certego-ui";
import { IconButton, CustomJsonInput } from "@certego/certego-ui";

import { useAuthStore } from "../../../stores/useAuthStore";
import { useOrganizationStore } from "../../../stores/useOrganizationStore";
Expand All @@ -17,6 +30,10 @@ import { deleteConfiguration } from "../pluginsApi";
import { PluginsTypes } from "../../../constants/pluginConst";
import { PluginConfigModal } from "../PluginConfigModal";
import { PlaybookFlows } from "../flows/PlaybookFlows";
import {
INTELOWL_DOCS_URL,
INTELOWL_REPO_URL,
} from "../../../constants/environment";

export function PluginHealthCheckButton({ pluginName, pluginType_ }) {
const { checkPluginHealth } = usePluginConfigurationStore(
Expand Down Expand Up @@ -459,3 +476,100 @@ export function PlaybookFlowsButton({ playbook }) {
PlaybookFlowsButton.propTypes = {
playbook: PropTypes.object.isRequired,
};

export function MappingDataModel({ data, type, pythonModule }) {
// state
const [showModal, setShowModal] = React.useState(false);
const pythonModuleName = pythonModule.split(".")[0];

return (
<div className="d-flex flex-column align-items-center p-1">
<IconButton
id={`mapping-data-model__${pythonModuleName}`}
color="info"
size="sm"
Icon={VscJson}
title="View data model mapping"
onClick={() => setShowModal(!showModal)}
titlePlacement="top"
disabled={Object.keys(data).length === 0}
/>
{showModal && (
<Modal
id="mapping-data-model-modal"
autoFocus
centered
zIndex="1050"
size="lg"
keyboard={false}
backdrop="static"
labelledBy="Data model modal"
isOpen={showModal}
style={{ minWidth: "50%" }}
>
<ModalHeader className="mx-2" toggle={() => setShowModal(false)}>
<small className="text-info">
Data model mapping
<MdInfoOutline
id="dataModelMapping_infoicon"
fontSize="16"
className="ms-2"
/>
<UncontrolledTooltip
trigger="hover"
target="dataModelMapping_infoicon"
placement="right"
fade={false}
autohide={false}
innerClassName="p-2 text-start text-nowrap md-fit-content"
>
The main functionality of a `DataModel` is to model an
`Analyzer` result to a set of prearranged keys, allowing users
to easily search, evaluate and use the analyzer result.
<br />
For more info check the{" "}
<Link
to={`${INTELOWL_DOCS_URL}IntelOwl/usage/#datamodels`}
target="_blank"
>
official doc.
</Link>
</UncontrolledTooltip>
</small>
</ModalHeader>
<ModalBody className="d-flex flex-column mx-2">
<small>
The <strong className="text-info">keys </strong>
represent the path used to retrieve the value in the analyzer
report and the <strong className="text-info">value</strong> the
path of the data model.
</small>
<small>
For more info check the{" "}
<Link
to={`${INTELOWL_REPO_URL}tree/master/api_app/analyzers_manager/${type}_analyzers/${pythonModuleName}.py`}
target="_blank"
>
analyzer&apos;s source code.
</Link>
</small>
<div className="my-2 d-flex justify-content-center">
<CustomJsonInput
id="data_model_mapping_json"
placeholder={data}
viewOnly
confirmGood={false}
/>
</div>
</ModalBody>
</Modal>
)}
</div>
);
}

MappingDataModel.propTypes = {
type: PropTypes.string.isRequired,
data: PropTypes.object.isRequired,
pythonModule: PropTypes.string.isRequired,
};
16 changes: 16 additions & 0 deletions frontend/src/components/plugins/tables/pluginTableColumns.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
PluginDeletionButton,
PluginConfigButton,
PlaybookFlowsButton,
MappingDataModel,
} from "./pluginActionsButtons";
import { JobTypes } from "../../../constants/jobConst";
import TableCell from "../../common/TableCell";
Expand Down Expand Up @@ -158,8 +159,23 @@ export const analyzersTableColumns = [
Cell: ({ value }) => <TLPTag value={value} />,
Filter: SelectOptionsFilter,
selectOptions: TlpChoices,
disableSortBy: true,
maxWidth: 80,
},
{
Header: "Data model",
id: "data_model",
accessor: (analyzerConfig) => analyzerConfig,
Cell: ({ value }) => (
<MappingDataModel
data={value.mapping_data_model}
type={value.type}
pythonModule={value.python_module}
/>
),
maxWidth: 70,
disableSortBy: true,
},
{
Header: "Actions",
id: "actions",
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/components/search/Search.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { format } from "date-fns";
import { PluginsTypes, PluginFinalStatuses } from "../../constants/pluginConst";
import { searchTableColumns } from "./searchTableColumns";
import { pluginReportQueries } from "./searchApi";
import { INTELOWL_DOCS_URL } from "../../constants/environment";

// table config
const tableConfig = { enableExpanded: true, enableFlexLayout: true };
Expand Down Expand Up @@ -145,7 +146,7 @@ export default function Search() {
This section only works if Elasticsearch has been configured
correctly. For more info check the{" "}
<Link
to="https://intelowlproject.github.io/docs/IntelOwl/advanced_configuration/#elasticsearch"
to={`${INTELOWL_DOCS_URL}IntelOwl/advanced_configuration/#elasticsearch`}
target="_blank"
>
official doc.
Expand Down
1 change: 1 addition & 0 deletions frontend/src/constants/environment.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export const INTELOWL_DOCS_URL = "https://intelowlproject.github.io/docs/";
export const PYINTELOWL_GH_URL =
"https://github.com/intelowlproject/pyintelowl";
export const INTELOWL_TWITTER_ACCOUNT = "intel_owl";
export const INTELOWL_REPO_URL = "https://github.com/intelowlproject/IntelOwl/";

// env variables
export const VERSION = process.env.REACT_APP_INTELOWL_VERSION;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
PlaybooksEditButton,
PluginConfigButton,
PlaybookFlowsButton,
MappingDataModel,
} from "../../../../src/components/plugins/tables/pluginActionsButtons";
import {
mockedUseOrganizationStoreOwner,
Expand Down Expand Up @@ -485,3 +486,59 @@ describe("PlaybookFlowsButton test", () => {
});
});
});

describe("DataModel mapping test", () => {
test("DataModel mapping button", async () => {
const userAction = userEvent.setup();
const data = {
mapping_data_model: {
permalink: "external_references",
"data.hostnames": "resolutions",
},
type: "observable",
python_module: "pythonmodule.pythonclass",
};
const { container } = render(
<BrowserRouter>
<MappingDataModel
data={data.mapping_data_model}
type={data.type}
pythonModule={data.python_module}
/>
</BrowserRouter>,
);

const dataModelMappingIcon = container.querySelector(
"#mapping-data-model__pythonmodule",
);
expect(dataModelMappingIcon).toBeInTheDocument();

userAction.click(dataModelMappingIcon);
await waitFor(() => {
expect(screen.getByText("Data model mapping")).toBeInTheDocument();
});
});

test("DataModel mapping button - disabled", async () => {
const data = {
mapping_data_model: {},
type: "observable",
python_module: "pythonmodule.pythonclass",
};
const { container } = render(
<BrowserRouter>
<MappingDataModel
data={data.mapping_data_model}
type={data.type}
pythonModule={data.python_module}
/>
</BrowserRouter>,
);

const dataModelMappingIcon = container.querySelector(
"#mapping-data-model__pythonmodule",
);
expect(dataModelMappingIcon).toBeInTheDocument();
expect(dataModelMappingIcon.className).toContain("disabled");
});
});
1 change: 1 addition & 0 deletions frontend/tests/mock.js
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,7 @@ export const mockedPlugins = {
run_hash: false,
run_hash_type: "",
not_supported_filetypes: [],
mapping_data_model: {},
params: {
query_type: {
type: "str",
Expand Down
Loading