Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
phutelmyer committed Jan 29, 2024
1 parent f633535 commit a294e24
Show file tree
Hide file tree
Showing 22 changed files with 669 additions and 141 deletions.
12 changes: 1 addition & 11 deletions app/blueprints/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,17 +105,7 @@ def login():

except Exception as err:
# current_app.logger.error("Failed connection to database: %s", err)
try:
return (
jsonify(
{
"error": "Failed to connect to database. Make sure you are set up to connect to a Strelka UI Database."
}
),
400,
)
except Exception as e:
print(e)
return jsonify({"error": "Failed to connect to database"}), 400

return (
jsonify(
Expand Down
3 changes: 3 additions & 0 deletions app/blueprints/strelka.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ def submit_file(user: User) -> Tuple[Response, int]:
if "file" in request.files:
file = request.files["file"]
submitted_description = request.form["description"]
submitted_type = "api"

# Check if the submitted filename is empty.
if file.filename == "":
Expand All @@ -110,6 +111,7 @@ def submit_file(user: User) -> Tuple[Response, int]:
submission = json.loads(request.data)
submitted_description = submission["description"]
submitted_hash = submission["hash"]
submitted_type = "virustotal"

if os.environ.get("VIRUSTOTAL_API_KEY"):
file = create_vt_zip_and_download(
Expand Down Expand Up @@ -220,6 +222,7 @@ def submit_file(user: User) -> Tuple[Response, int]:
get_hashes(submitted_file),
list(insights),
list(iocs),
submitted_type,
request.remote_addr,
request.headers.get("User-Agent"),
user.id,
Expand Down
4 changes: 4 additions & 0 deletions app/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class FileSubmission(db.Model):
files_seen (int): A count of files seen during analysis.
scanners_run (list): A list of scanners that were run on the file.
hashes (list): A list of hashes associated with the file.
submitted_type (str): The type of submission that occurred (e.g., UI, VirusTotal)
submitted_from_ip (str): The IP address of the client that submitted the file.
submitted_from_client (str): The name of the client that submitted the file.
submitted_description (str): A description of the file provided by the user.
Expand Down Expand Up @@ -54,6 +55,7 @@ class FileSubmission(db.Model):
iocs: list = db.Column(db.ARRAY(db.String(), dimensions=1))

# Submission Metadata
submitted_type: str = db.Column(db.String())
submitted_from_ip: str = db.Column(db.String())
submitted_from_client: str = db.Column(db.String())
submitted_description: str = db.Column(db.String())
Expand All @@ -79,6 +81,7 @@ def __init__(
hashes: list,
insights: list,
iocs: list,
submitted_type: str,
submitted_from_ip: str,
submitted_from_client: str,
submitted_by_user_id: int,
Expand All @@ -97,6 +100,7 @@ def __init__(
self.hashes = hashes
self.insights = insights
self.iocs = iocs
self.submitted_type = submitted_type
self.submitted_from_ip = submitted_from_ip
self.submitted_from_client = submitted_from_client
self.submitted_by_user_id = submitted_by_user_id
Expand Down
Binary file added ui/public/strelka.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added ui/public/virustotal.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
176 changes: 176 additions & 0 deletions ui/src/components/FileComponents/EmailOverviewCard.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
import React, { useState } from "react";
import { Row, Col, Modal, Typography, List, Tag } from "antd";
import "../../styles/OcrOverviewCard.css";

const EmailOverviewCard = ({ data }) => {

const [isModalVisible, setIsModalVisible] = useState(false);

const { Text } = Typography;
const base64Thumbnail = data.scan.email?.base64_thumbnail;

const showModal = () => setIsModalVisible(true);
const handleCancel = () => setIsModalVisible(false);

// Placeholder for Thumbnail in case it's disabled or not functioning
const ThumbnailPlaceholder = () => {
return <div className="thumbnail-placeholder" />;
};

const {
attachments: { filenames = [] } = {},
from,
to,
date_utc,
message_id,
subject,
received_domain = [],
body,
} = data.scan.email || {};

// Check if the subject contains [External] (case insensitive)
const isExternalSender =
subject && subject.toLowerCase().includes("[external]");

// Create the list data conditionally
const listData = [
// Conditionally add "External Sender" row if it's an external sender
isExternalSender
? {
title: "External Sender",
tag: "Insight",
}
: null,
{
title: "Subject",
description: subject || "No Subject",
tag: "Informational",
},
{ title: "Sender", description: from || "No Sender", tag: "Informational" },
{
title: "Recipients",
description: to.map((name) => ({ name })) || [],
tag: "Informational",
},
{
title: "Received",
description: date_utc || "No Date",
tag: "Informational",
},
{
title: "Message ID",
description: message_id || "No Message ID",
tag: "Informational",
},
// Conditionally add "Attachment Names" row only if filenames is not empty
...(filenames.length > 0
? [
{
title: "Attachment Names",
description: filenames.map((name) => ({ name })) || [],
tag: "Informational",
},
]
: []),
{
title: "Domains in Header",
description: received_domain.map((domain) => ({ domain })) || [],
tag: "Informational",
},
{ title: "Body", description: body || "No Body", tag: "Informational" },
].filter((item) => item !== null);

return (
<div className="ocr-overview" style={{ maxHeight: "600px" }}>
<Row gutter={[16, 16]}>
<Col span={14}>
<div style={{ maxHeight: "500px", overflowY: "auto" }}>
<List
itemLayout="horizontal"
dataSource={listData}
bordered
renderItem={(item) => (
<List.Item>
<List.Item.Meta
title={
<div>
<Text strong style={{ fontSize: 12 }}>
{item.title}
</Text>
{item.tag && (
<Tag
color={
item.tag === "Informational"
? "default"
: "warning"
}
style={{
marginLeft: 8,
fontSize: 10,
}}
>
{item.tag}
</Tag>
)}
</div>
}
description={
item.description &&
(Array.isArray(item.description) ? (
<ul style={{ paddingLeft: 16 }}>
{item.description.map((subItem, index) => (
<li key={index}>
<Text style={{ fontSize: 12 }} copyable>
{subItem.name || subItem.domain}
</Text>
</li>
))}
</ul>
) : (
<Text style={{ fontSize: 12 }} copyable>
{item.description}
</Text>
))
}
/>
</List.Item>
)}
/>
</div>
</Col>
<Col span={9} className="thumbnail-container">
{base64Thumbnail ? (
<>
<img
src={`data:image/jpeg;base64,${base64Thumbnail}`}
alt="Email Preview"
style={{
width: "auto",
maxHeight: "500px",
overflowY: "auto",
cursor: "pointer",
}}
onClick={showModal}
/>
<Modal
open={isModalVisible}
footer={null}
onCancel={handleCancel}
>
<img
src={`data:image/jpeg;base64,${base64Thumbnail}`}
alt="Email Preview (Expanded)"
style={{ width: "100%" }}
/>
</Modal>
</>
) : (
<ThumbnailPlaceholder />
)}
</Col>
</Row>
</div>
);
};

export default EmailOverviewCard;
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const FileHighlightsOverviewCard = ({ data, onFileNameSelect }) => {
const sortedNodeIds = Object.keys(filenameByNode)
.map((nodeId) => ({
nodeId,
filename: filenameByNode[nodeId],
filename: filenameByNode[nodeId] || 'No Filename',
iocCount: iocsByNode[nodeId]?.length || 0,
insightCount: insightsByNode[nodeId]?.length || 0,
}))
Expand Down Expand Up @@ -93,7 +93,7 @@ const FileHighlightsOverviewCard = ({ data, onFileNameSelect }) => {

const nodeList = sortedNodeIds.map((nodeId) => {
const isExpanded = expandedNodes.has(nodeId);
const filename = filenameByNode[nodeId];
const filename = filenameByNode[nodeId] || "No Filename";
const insights = insightsByNode[nodeId] || [];
const iocs = iocsByNode[nodeId] || [];
const mimeType = mimeTypeByNode[nodeId];
Expand Down
2 changes: 1 addition & 1 deletion ui/src/components/FileComponents/FileOverviewCard.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const FileOverviewCard = ({ data }) => {
</Col>
<Col span={18}>
<Text code={isCode} copyable={copyable} style={{ fontSize: "12px" }}>
{content || "Not Available"}
{content || "No Filename"}
</Text>
</Col>
</Row>
Expand Down
2 changes: 1 addition & 1 deletion ui/src/components/FileComponents/FileTypeOverviewCard.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,4 +123,4 @@ const FileTypeOverviewCard = ({ data, onFileTypeSelect }) => {
);
};

export default FileTypeOverviewCard;
export default FileTypeOverviewCard;
38 changes: 31 additions & 7 deletions ui/src/components/FileComponents/OcrOverviewCard.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import React, { useState } from "react";
import { Checkbox, Input, Row, Col } from "antd";
import { Checkbox, Input, Row, Col, Modal } 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 showModal = () => setIsModalVisible(true);
const handleCancel = () => setIsModalVisible(false);

let texts = Array.isArray(data.scan.ocr?.text)
? data.scan.ocr.text
: [data.scan.ocr?.text || ""];
Expand Down Expand Up @@ -78,12 +83,31 @@ const OcrOverviewCard = ({ data }) => {
</table>
</Col>
<Col span={5} className="thumbnail-container">
{base64Thumbnail ? (
<img
src={`data:image/jpeg;base64,${base64Thumbnail}`}
alt="OCR Thumbnail"
style={{ width: "auto", maxHeight: "200px" }}
/>
{base64Thumbnail ? (
<>
<img
src={`data:image/jpeg;base64,${base64Thumbnail}`}
alt="Email Preview"
style={{
width: "auto",
maxHeight: "200px",
overflowY: "auto",
cursor: "pointer",
}}
onClick={showModal}
/>
<Modal
open={isModalVisible}
footer={null}
onCancel={handleCancel}
>
<img
src={`data:image/jpeg;base64,${base64Thumbnail}`}
alt="Email Preview (Expanded)"
style={{ width: "100%" }}
/>
</Modal>
</>
) : (
<ThumbnailPlaceholder />
)}
Expand Down
17 changes: 9 additions & 8 deletions ui/src/components/FileComponents/VirusTotalUploader.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ const VirusTotalUploader = ({ onUploadSuccess }) => {
return response.json();
})
.then((data) => {
message.success("Hash submitted successfully");
onUploadSuccess(); // Trigger table refresh
setVtHash(""); // Reset hash input
message.success(`${vtHash} analyzed successfully via VirusTotal!`);
setLoading(false); // Stop loading
})
.catch((error) => {
Expand All @@ -48,29 +48,30 @@ const VirusTotalUploader = ({ onUploadSuccess }) => {

return (
<div>
<div style={{paddingBottom: 12}}>
<Input
onChange={handleDescriptionChange}
placeholder="Description to be saved with submission..."
prefix={<MessageOutlined />}
/>
<br />
<br />
<div style={{ display: "flex" }}>
</div>
<div style={{paddingBottom: 12}}>
<Input
onChange={handleVtHashChange}
placeholder="SHA256 Hash..."
placeholder="MD5, SHA1, SHA256 Hash..."
value={vtHash}
style={{ marginRight: "15px" }}
disabled={loading} // Disable input during loading
/>
<Button
</div>
<div style={{float: "right"}}>
<Button
type="primary"
onClick={handleSubmitVtHash}
loading={loading} // Use loading prop for loading indicator
>
<Text strong style={{ fontSize: "12px", color: "white" }}>Submit Hash</Text>
</Button>
</div>
</div>
</div>
);
};
Expand Down
2 changes: 1 addition & 1 deletion ui/src/components/FileComponents/YaraOverviewCard.js
Original file line number Diff line number Diff line change
Expand Up @@ -147,4 +147,4 @@ const YaraOverviewCard = ({ data }) => {
);
};

export default YaraOverviewCard;
export default YaraOverviewCard;
Loading

0 comments on commit a294e24

Please sign in to comment.