Skip to content

Commit

Permalink
Adding QR Card
Browse files Browse the repository at this point in the history
  • Loading branch information
phutelmyer committed Feb 2, 2024
1 parent 1469bc6 commit 4c51ddd
Show file tree
Hide file tree
Showing 6 changed files with 263 additions and 113 deletions.
47 changes: 36 additions & 11 deletions ui/src/components/FileComponents/OcrOverviewCard.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
import React, { useState } from "react";
import { Checkbox, Input, Row, Col, Modal } from "antd";
import { Checkbox, Input, Row, Col, Modal, Button, Tooltip } from "antd";
import "../../styles/OcrOverviewCard.css";

const OcrOverviewCard = ({ data }) => {
const [isModalVisible, setIsModalVisible] = useState(false);
const [wrapText, setWrapText] = useState(false);
const [trimText, setTrimText] = useState(true);
const [filter, setFilter] = useState("");
const [isBlurred, setIsBlurred] = useState(data.scan.qr ? true : false); // State to manage blur for QR codes

const showModal = () => setIsModalVisible(true);
const showModal = () => {
// Only show modal if the image is not blurred
if (!isBlurred) {
setIsModalVisible(true);
}
};
const handleCancel = () => setIsModalVisible(false);
const toggleBlur = () => setIsBlurred(!isBlurred);

let texts = Array.isArray(data.scan.ocr?.text)
? data.scan.ocr.text
Expand All @@ -27,6 +34,16 @@ const OcrOverviewCard = ({ data }) => {
return <div className="thumbnail-placeholder" />;
};

// Conditional styling for blurred image (QR codes)
const imageStyle = isBlurred
? {
filter: "blur(4px)",
cursor: "pointer",
}
: {
cursor: "pointer",
};

// Function to create line numbers and corresponding text
const renderTextLines = (texts) => {
let lineNumber = 1; // Initialize line number
Expand Down Expand Up @@ -83,19 +100,27 @@ const OcrOverviewCard = ({ data }) => {
</table>
</Col>
<Col span={5} className="thumbnail-container">
{base64Thumbnail ? (
<>
{base64Thumbnail ? (
<div className="thumbnail-wrapper">
<img
src={`data:image/jpeg;base64,${base64Thumbnail}`}
alt="Email Preview"
style={{
width: "auto",
maxHeight: "200px",
overflowY: "auto",
cursor: "pointer",
}}
style={imageStyle}
onClick={showModal}
/>
{isBlurred && (
<div>
<Tooltip title="QR codes can pose a security risk, use with caution">
<Button
onClick={toggleBlur}
danger
className="centered-button"
>
Remove Blur
</Button>
</Tooltip>
</div>
)}
<Modal
open={isModalVisible}
footer={null}
Expand All @@ -107,7 +132,7 @@ const OcrOverviewCard = ({ data }) => {
style={{ width: "100%" }}
/>
</Modal>
</>
</div>
) : (
<ThumbnailPlaceholder />
)}
Expand Down
56 changes: 56 additions & 0 deletions ui/src/components/FileComponents/QrOverviewCard.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import React, { useState } from "react";
import { Input, Table, Typography } from "antd";
import "../../styles/IocOverviewCard.css";

const { Text } = Typography;

const QrOverviewCard = ({ data }) => {
const [filter, setFilter] = useState("");

const columns = [
{
title: "Data",
dataIndex: "data",
key: "data",
render: (text) => (
<Text code copyable>
{text}
</Text>
),
},
];

const processQrData = () => {
// Assuming data.scan.qr.data is an array of strings (URLs)
return data.scan.qr.data
.filter((url) => {
const searchTerm = filter.toLowerCase();
return !filter || url.toLowerCase().includes(searchTerm);
})
.map((data, index) => ({
key: index,
data: data,
}));
};

const filteredQrData = processQrData();

return (
<div>
<Input
placeholder="Filter QR Codes"
onChange={(e) => setFilter(e.target.value)}
style={{ width: "100%", marginBottom: 16 }}
/>
<Table
columns={columns}
dataSource={filteredQrData}
pagination={{ pageSize: 10 }}
scroll={{ y: 200 }}
className="qr-table"
/>
</div>
);
};

export default QrOverviewCard;
37 changes: 30 additions & 7 deletions ui/src/components/FileFlow/NodeTypes/EventNode.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { memo } from "react";
import styled, { createGlobalStyle } from "styled-components";
import { CameraOutlined } from "@ant-design/icons";
import { CameraOutlined, QrcodeOutlined } from "@ant-design/icons";
import { Tag, Tooltip } from "antd";
import { Handle, Position } from "reactflow";
import { getIconConfig } from "../../../utils/iconMappingTable";
Expand Down Expand Up @@ -55,6 +55,21 @@ function getVirusTotalStatus(virusTotalResponse) {
}

// Styled Components
const QrCodePreviewWrapper = styled.div`
position: absolute;
bottom: 10px;
right: ${({ hasImage }) => (hasImage ? "40px" : "10px")};
width: 24px;
height: 24px;
border-radius: 20%;
background-color: #ff7a45;
display: flex;
justify-content: center;
align-items: center;
box-shadow: 0px 4px 6px -1px rgba(0, 0, 0, 0.1);
cursor: pointer;
`;

const PulsatingAnimation = createGlobalStyle`
@keyframes pulsate {
0% {
Expand Down Expand Up @@ -97,15 +112,15 @@ const ImageTooltip = styled(Tooltip)`
`;

const PreviewImage = styled.img`
max-width: 100%;
max-height: 100%;
width: auto;
height: auto;
max-width: 100%;
max-height: 100%;
width: auto;
height: auto;
`;

const TagWrapper = styled.div`
display: inline-block;
margin-right: 10px;
display: inline-block;
margin-right: 10px;
position: absolute;
top: -15px;
z-index: 10;
Expand Down Expand Up @@ -235,6 +250,7 @@ const EventNode = memo(({ data, selected }) => {
const mappingEntry = getIconConfig("strelka", data.nodeMain.toLowerCase());
const IconComponent = mappingEntry?.icon;
const color = mappingEntry?.color || data.color;
const hasImage = Boolean(data.nodeImage);
const virusTotalResponse = data.nodeVirustotal;
data.nodeAlert =
typeof virusTotalResponse === "number" && virusTotalResponse > 5;
Expand Down Expand Up @@ -302,6 +318,13 @@ const EventNode = memo(({ data, selected }) => {
<b>{getVirusTotalStatus(data.nodeVirustotal)}</b>
</Tag>
</VirustotalWrapper>
{data.nodeQrData && (
<Tooltip title="QR Code found">
<QrCodePreviewWrapper hasImage={hasImage}>
<QrcodeOutlined style={{ color: "white" }} />
</QrCodePreviewWrapper>
</Tooltip>
)}
{data.nodeImage && (
<ImageTooltip
color="white"
Expand Down
38 changes: 36 additions & 2 deletions ui/src/pages/SubmissionView.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import FileHighlightsOverviewCard from "../components/FileComponents/FileHighlig
import VbOverviewCard from "../components/FileComponents/VbOverviewCard";
import JavascriptOverviewCard from "../components/FileComponents/JavascriptOverviewCard";
import EmailOverviewCard from "../components/FileComponents/EmailOverviewCard";
import QrOverviewCard from "../components/FileComponents/QrOverviewCard";

import { getIconConfig } from "../utils/iconMappingTable";

Expand Down Expand Up @@ -513,6 +514,39 @@ const SubmissionsPage = (props) => {
</Collapse.Panel>
</Collapse>
)}
{selectedNodeData && selectedNodeData.scan?.qr?.data && (
<Collapse
defaultActiveKey={[]}
style={{ width: "100%", marginBottom: "10px" }}
>
<Collapse.Panel
header={
<div
style={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
}}
>
<div style={{ display: "flex", alignItems: "center" }}>
<div style={{ marginLeft: "8px" }}>
{" "}
<Text strong>QR Code Data</Text>
<div style={{ fontSize: "smaller", color: "#888" }}>
{selectedNodeData.scan.qr.data.length > 0
? "QR Data Count: " + selectedNodeData.scan.qr.data.length
: "No QR Data"}
</div>
</div>
</div>
</div>
}
key="1"
>
<QrOverviewCard data={selectedNodeData} />
</Collapse.Panel>
</Collapse>
)}
{selectedNodeData && selectedNodeData.scan.email && (
<Collapse
defaultActiveKey={[]}
Expand Down Expand Up @@ -698,8 +732,8 @@ const SubmissionsPage = (props) => {
<div>
<Text strong>Indicators of Compromise (IOCs)</Text>
<div style={{ fontSize: "smaller", color: "#888" }}>
{selectedNodeData.iocs[0].ioc} and{" "}
{selectedNodeData.iocs.length - 1} more
{selectedNodeData.iocs[0].ioc} {" "}
{selectedNodeData.iocs.length > 1 && ` and ${selectedNodeData.iocs.length - 1} more`}
</div>
</div>
<div style={{ fontSize: "smaller", color: "#888" }}>
Expand Down
Loading

0 comments on commit 4c51ddd

Please sign in to comment.