Skip to content
This repository was archived by the owner on Dec 5, 2025. It is now read-only.

Commit 1d913fa

Browse files
author
Samuel Hassine
authored
[client] Introduce notes & opinions (#73)
* [client] Add notes & opinions, prepare STIX 2.1 * [client] Fix some bugs with new entities opinions/notes
1 parent dd2fec0 commit 1d913fa

18 files changed

+1568
-71
lines changed

examples/import_stix2_file.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
from pycti import OpenCTIApiClient
44

55
# Variables
6-
api_url = "https://demo.opencti.io"
7-
api_token = "2b4f29e3-5ea8-4890-8cf5-a76f61f1e2b2"
6+
api_url = "http://localhost:4000"
7+
api_token = "0b23f787-d013-41a8-8078-97bee84cc99d"
88

99
# OpenCTI initialization
1010
opencti_api_client = OpenCTIApiClient(api_url, api_token)

pycti/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
from .entities.opencti_attack_pattern import AttackPattern
3131
from .entities.opencti_course_of_action import CourseOfAction
3232
from .entities.opencti_report import Report
33+
from .entities.opencti_note import Note
34+
from .entities.opencti_opinion import Opinion
3335
from .entities.opencti_indicator import Indicator
3436

3537
from .utils.opencti_stix2 import OpenCTIStix2
@@ -64,6 +66,8 @@
6466
"AttackPattern",
6567
"CourseOfAction",
6668
"Report",
69+
"Note",
70+
"Opinion",
6771
"Indicator",
6872
"OpenCTIStix2",
6973
"ObservableTypes",

pycti/api/opencti_api_client.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
from pycti.entities.opencti_attack_pattern import AttackPattern
3333
from pycti.entities.opencti_course_of_action import CourseOfAction
3434
from pycti.entities.opencti_report import Report
35+
from pycti.entities.opencti_note import Note
36+
from pycti.entities.opencti_opinion import Opinion
3537
from pycti.entities.opencti_indicator import Indicator
3638

3739
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
@@ -98,6 +100,8 @@ def __init__(self, url, token, log_level="info", ssl_verify=False):
98100
self.attack_pattern = AttackPattern(self)
99101
self.course_of_action = CourseOfAction(self)
100102
self.report = Report(self)
103+
self.note = Note(self)
104+
self.opinion = Opinion(self)
101105
self.indicator = Indicator(self)
102106

103107
# Check if openCTI is available
@@ -483,6 +487,7 @@ def resolve_role(self, relation_type, from_type, to_type):
483487
"country": {"from_role": "source", "to_role": "target"},
484488
"city": {"from_role": "source", "to_role": "target"},
485489
"organization": {"from_role": "source", "to_role": "target"},
490+
"user": {"from_role": "source", "to_role": "target"},
486491
"vulnerability": {"from_role": "source", "to_role": "target"},
487492
},
488493
"intrusion-set": {
@@ -492,6 +497,7 @@ def resolve_role(self, relation_type, from_type, to_type):
492497
"country": {"from_role": "source", "to_role": "target"},
493498
"city": {"from_role": "source", "to_role": "target"},
494499
"organization": {"from_role": "source", "to_role": "target"},
500+
"user": {"from_role": "source", "to_role": "target"},
495501
"vulnerability": {"from_role": "source", "to_role": "target"},
496502
},
497503
"campaign": {
@@ -501,6 +507,7 @@ def resolve_role(self, relation_type, from_type, to_type):
501507
"country": {"from_role": "source", "to_role": "target"},
502508
"city": {"from_role": "source", "to_role": "target"},
503509
"organization": {"from_role": "source", "to_role": "target"},
510+
"user": {"from_role": "source", "to_role": "target"},
504511
"vulnerability": {"from_role": "source", "to_role": "target"},
505512
},
506513
"incident": {
@@ -510,6 +517,7 @@ def resolve_role(self, relation_type, from_type, to_type):
510517
"country": {"from_role": "source", "to_role": "target"},
511518
"city": {"from_role": "source", "to_role": "target"},
512519
"organization": {"from_role": "source", "to_role": "target"},
520+
"user": {"from_role": "source", "to_role": "target"},
513521
"vulnerability": {"from_role": "source", "to_role": "target"},
514522
},
515523
"malware": {
@@ -519,6 +527,7 @@ def resolve_role(self, relation_type, from_type, to_type):
519527
"country": {"from_role": "source", "to_role": "target"},
520528
"city": {"from_role": "source", "to_role": "target"},
521529
"organization": {"from_role": "source", "to_role": "target"},
530+
"user": {"from_role": "source", "to_role": "target"},
522531
"vulnerability": {"from_role": "source", "to_role": "target"},
523532
},
524533
"attack-pattern": {
@@ -529,6 +538,7 @@ def resolve_role(self, relation_type, from_type, to_type):
529538
"threat-actor": {
530539
"identity": {"from_role": "attribution", "to_role": "origin"},
531540
"organization": {"from_role": "attribution", "to_role": "origin"},
541+
"user": {"from_role": "attribution", "to_role": "origin"},
532542
},
533543
"intrusion-set": {
534544
"identity": {"from_role": "attribution", "to_role": "origin"},

pycti/entities/opencti_attack_pattern.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import json
44
from pycti.utils.constants import CustomProperties
5+
from pycti.utils.opencti_stix2 import SPEC_VERSION
56

67

78
class AttackPattern:
@@ -498,6 +499,7 @@ def to_stix2(self, **kwargs):
498499
attack_pattern = dict()
499500
attack_pattern["id"] = entity["stix_id_key"]
500501
attack_pattern["type"] = "attack-pattern"
502+
attack_pattern["spec_version"] = SPEC_VERSION
501503
if self.opencti.not_empty(entity["external_id"]):
502504
attack_pattern[CustomProperties.EXTERNAL_ID] = entity["external_id"]
503505
attack_pattern["name"] = entity["name"]

pycti/entities/opencti_campaign.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import json
44
from pycti.utils.constants import CustomProperties
5+
from pycti.utils.opencti_stix2 import SPEC_VERSION
56

67

78
class Campaign:
@@ -376,6 +377,7 @@ def to_stix2(self, **kwargs):
376377
campaign = dict()
377378
campaign["id"] = entity["stix_id_key"]
378379
campaign["type"] = "campaign"
380+
campaign["spec_version"] = SPEC_VERSION
379381
campaign["name"] = entity["name"]
380382
if self.opencti.not_empty(entity["stix_label"]):
381383
campaign["labels"] = entity["stix_label"]

pycti/entities/opencti_course_of_action.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import json
44
from pycti.utils.constants import CustomProperties
5+
from pycti.utils.opencti_stix2 import SPEC_VERSION
56

67

78
class CourseOfAction:
@@ -344,6 +345,7 @@ def to_stix2(self, **kwargs):
344345
course_of_action = dict()
345346
course_of_action["id"] = entity["stix_id_key"]
346347
course_of_action["type"] = "course-of-action"
348+
course_of_action["spec_version"] = SPEC_VERSION
347349
course_of_action["name"] = entity["name"]
348350
if self.opencti.not_empty(entity["stix_label"]):
349351
course_of_action["labels"] = entity["stix_label"]

pycti/entities/opencti_identity.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import json
44
from pycti.utils.constants import CustomProperties
5+
from pycti.utils.opencti_stix2 import SPEC_VERSION
56

67

78
class Identity:
@@ -351,6 +352,7 @@ def to_stix2(self, **kwargs):
351352
identity = dict()
352353
identity["id"] = entity["stix_id_key"]
353354
identity["type"] = "identity"
355+
identity["spec_version"] = SPEC_VERSION
354356
identity["name"] = entity["name"]
355357
identity["identity_class"] = identity_class
356358
if self.opencti.not_empty(entity["stix_label"]):
@@ -366,6 +368,7 @@ def to_stix2(self, **kwargs):
366368
if (
367369
entity["entity_type"] == "organization"
368370
and "organization_class" in entity
371+
and self.opencti.not_empty(entity["organization_class"])
369372
):
370373
identity[CustomProperties.ORG_CLASS] = entity["organization_class"]
371374
identity[CustomProperties.IDENTITY_TYPE] = entity["entity_type"]

pycti/entities/opencti_incident.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import json
44
from pycti.utils.constants import CustomProperties
5+
from pycti.utils.opencti_stix2 import SPEC_VERSION
56

67

78
class Incident:
@@ -445,6 +446,7 @@ def to_stix2(self, **kwargs):
445446
incident = dict()
446447
incident["id"] = entity["stix_id_key"]
447448
incident["type"] = "x-opencti-incident"
449+
incident["spec_version"] = SPEC_VERSION
448450
incident["name"] = entity["name"]
449451
if self.opencti.not_empty(entity["stix_label"]):
450452
incident["labels"] = entity["stix_label"]

pycti/entities/opencti_indicator.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import json
44
from pycti.utils.constants import CustomProperties
5+
from pycti.utils.opencti_stix2 import SPEC_VERSION
56

67

78
class Indicator:
@@ -494,6 +495,7 @@ def to_stix2(self, **kwargs):
494495
indicator = dict()
495496
indicator["id"] = entity["stix_id_key"]
496497
indicator["type"] = "indicator"
498+
indicator["spec_version"] = SPEC_VERSION
497499
indicator["name"] = entity["name"]
498500
if self.opencti.not_empty(entity["stix_label"]):
499501
indicator["labels"] = entity["stix_label"]

pycti/entities/opencti_intrusion_set.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import json
44

55
from pycti.utils.constants import CustomProperties
6+
from pycti.utils.opencti_stix2 import SPEC_VERSION
67

78

89
class IntrusionSet:
@@ -448,6 +449,7 @@ def to_stix2(self, **kwargs):
448449
intrusion_set = dict()
449450
intrusion_set["id"] = entity["stix_id_key"]
450451
intrusion_set["type"] = "intrusion-set"
452+
intrusion_set["spec_version"] = SPEC_VERSION
451453
intrusion_set["name"] = entity["name"]
452454
if self.opencti.not_empty(entity["stix_label"]):
453455
intrusion_set["labels"] = entity["stix_label"]

0 commit comments

Comments
 (0)