Skip to content

Commit cd5e02b

Browse files
author
Samuel Hassine
authored
[client] Add a custom STIX field for file upload from bundle (OpenCTI-Platform#51)
1 parent 1a05ab6 commit cd5e02b

File tree

5 files changed

+63
-20
lines changed

5 files changed

+63
-20
lines changed

examples/upload_file_to_intrusion_set.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
print(intrusion_set)
2424

2525
# Upload the file
26-
file = opencti_api_client.stix_domain_entity.upload_file(
26+
file = opencti_api_client.stix_domain_entity.add_file(
2727
id=intrusion_set["id"], file_name="./2005_002_001_14428.pdf",
2828
)
2929
print(file)

pycti/api/opencti_api_client.py

+3
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,9 @@ def process_multiple_fields(self, data):
333333
if "indicators" in data:
334334
data["indicators"] = self.process_multiple(data["indicators"])
335335
data["indicatorsIds"] = self.process_multiple_ids(data["indicators"])
336+
if "importFiles" in data:
337+
data["importFiles"] = self.process_multiple(data["importFiles"])
338+
data["importFilesIds"] = self.process_multiple_ids(data["importFiles"])
336339
return data
337340

338341
def upload_file(self, **kwargs):

pycti/entities/opencti_stix_domain_entity.py

+40-18
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,15 @@ def __init__(self, opencti, file):
8989
}
9090
}
9191
}
92+
importFiles {
93+
edges {
94+
node {
95+
id
96+
name
97+
size
98+
}
99+
}
100+
}
92101
... on AttackPattern {
93102
platform
94103
required_permission
@@ -486,32 +495,45 @@ def delete(self, **kwargs):
486495
:return void
487496
"""
488497

489-
def upload_file(self, **kwargs):
498+
def add_file(self, **kwargs):
490499
id = kwargs.get("id", None)
491500
file_name = kwargs.get("file_name", None)
492501
data = kwargs.get("data", None)
493502
mime_type = kwargs.get("mime_type", "text/plain")
494503
if id is not None and file_name is not None:
495-
self.opencti.log(
496-
"info", "Uploading a file in Stix-Domain-Entity {" + id + "}."
497-
)
498-
query = """
499-
mutation StixDomainEntityEdit($id: ID!, $file: Upload!) {
500-
stixDomainEntityEdit(id: $id) {
501-
importPush(file: $file) {
502-
id
503-
name
504+
stix_domain_entity = self.read(id=id)
505+
if stix_domain_entity is None:
506+
self.opencti.log(
507+
"error", "Cannot add File, entity not found"
508+
)
509+
return False
510+
final_file_name = os.path.basename(file_name)
511+
current_files = {}
512+
for file in stix_domain_entity['importFiles']:
513+
current_files[file['name']] = file
514+
if final_file_name in current_files:
515+
return current_files[final_file_name]
516+
else:
517+
self.opencti.log(
518+
"info", "Uploading a file in Stix-Domain-Entity {" + id + "}."
519+
)
520+
query = """
521+
mutation StixDomainEntityEdit($id: ID!, $file: Upload!) {
522+
stixDomainEntityEdit(id: $id) {
523+
importPush(file: $file) {
524+
id
525+
name
526+
}
504527
}
505528
}
506-
}
507-
"""
508-
if data is None:
509-
data = open(file_name, "rb")
510-
mime_type = magic.from_file(file_name, mime=True)
529+
"""
530+
if data is None:
531+
data = open(file_name, "rb")
532+
mime_type = magic.from_file(file_name, mime=True)
511533

512-
return self.opencti.query(
513-
query, {"id": id, "file": (self.file(file_name, data, mime_type))}
514-
)
534+
return self.opencti.query(
535+
query, {"id": id, "file": (self.file(final_file_name, data, mime_type))}
536+
)
515537
else:
516538
self.opencti.log(
517539
"error",

pycti/utils/constants.py

+3
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ class CustomProperties:
6262
# internal id used by OpenCTI - this will be auto generated
6363
ID = "x_opencti_id"
6464

65+
# List of files
66+
FILES = "x_opencti_files"
67+
6568
# This should be set on all reports to one of the following values:
6669
# "external"
6770
# "internal"

pycti/utils/opencti_stix2.py

+16-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import os
55
import json
66
import uuid
7+
import base64
78
import datetime
89
from typing import List
910

@@ -175,6 +176,12 @@ def extract_embedded_relationships(self, stix_object, types=None):
175176
tag_result = self.opencti.tag.read(id=tag["id"])
176177
if tag_result is not None:
177178
self.mapping_cache[tag["id"]] = {"id": tag_result["id"]}
179+
else:
180+
tag_result = self.opencti.tag.create(
181+
tag_type=tag["tag_type"],
182+
value=tag["value"],
183+
color=tag["color"]
184+
)
178185
if tag_result is not None:
179186
tags_ids.append(tag_result["id"])
180187

@@ -463,7 +470,7 @@ def import_object(self, stix_object, update=False, types=None):
463470
# Add tags
464471
for tag_id in tags_ids:
465472
self.opencti.stix_entity.add_tag(
466-
id=stix_object_result["id"], marking_definition_id=tag_id,
473+
id=stix_object_result["id"], tag_id=tag_id,
467474
)
468475
# Add external references
469476
for external_reference_id in external_references_ids:
@@ -501,6 +508,14 @@ def import_object(self, stix_object, update=False, types=None):
501508
id=stix_object_result["id"],
502509
stix_observable_id=observable_ref["id"],
503510
)
511+
# Add files
512+
if CustomProperties.FILES in stix_object:
513+
for file in stix_object[CustomProperties.FILES]:
514+
self.opencti.stix_domain_entity.add_file(
515+
file_name=file['name'],
516+
data=base64.b64decode(file['data']),
517+
mime_type=file['mime_type']
518+
)
504519

505520
return stix_object_results
506521

0 commit comments

Comments
 (0)