Source code for cybsi.api.observable.relationships
import uuid
from datetime import datetime
from typing import Dict, List, Optional, cast
from ..internal import BaseAPI, JsonObjectView, rfc3339_timestamp
from .aggregate_section import ValuableFactView
from .entity import EntityView
from .enums import RelationshipKinds
def _convert_relationship_kind_kebab(kind: RelationshipKinds) -> str:
"""Convert relationship kind value to kebab-case.
Args:
kind: relationship kind, such of 'ResolvesTo'.
Return:
Relationship kind on kebab-case, such of `resolves-to`.
"""
return _rel_kind_kebab_converters[kind]
_rel_kind_kebab_converters: Dict[RelationshipKinds, str] = {
RelationshipKinds.Has: "has",
RelationshipKinds.Contains: "contains",
RelationshipKinds.BelongsTo: "belongs-to",
RelationshipKinds.ConnectsTo: "connects-to",
RelationshipKinds.Drops: "drops",
RelationshipKinds.Uses: "uses",
RelationshipKinds.Owns: "owns",
RelationshipKinds.Supports: "supports",
RelationshipKinds.ResolvesTo: "resolves-to",
RelationshipKinds.VariantOf: "variant-of",
RelationshipKinds.Hosts: "hosts",
RelationshipKinds.Serves: "serves",
RelationshipKinds.Locates: "locates",
}
[docs]
class RelationshipsAPI(BaseAPI):
"""Relationships API."""
_path = "/observable/relationships"
[docs]
def forecast(
self,
*,
source_entity_uuid: uuid.UUID,
target_entity_uuid: uuid.UUID,
kind: RelationshipKinds,
forecast_at: Optional[datetime] = None,
valuable_facts: Optional[bool] = None,
) -> "RelationshipsForecastView":
"""Get forecast of relationship between two entities.
See Also:
See :ref:`relationships`
for complete information about available relationships.
Note:
Calls `GET /observable/relationships/{sourceEntityUUID}/{relationKind}/{targetEntityUUID}`. # noqa: E501
Args:
source_entity_uuid: Source entity UUID.
kind: Kind of relationship. Converts to kebab-case on URL-path.
target_entity_uuid: Target entity UUID.
forecast_at: Date of forecast.
If not specified, forecast is built on current time.
valuable_facts: Attach list of valuable facts to forecast.
Returns:
Relationship forecast view.
Usage:
>>> from uuid import UUID
>>> from cybsi.api import CybsiClient
>>> from cybsi.api.observable import RelationshipKinds
>>> client: CybsiClient
>>> forecasts = client.observable.relationships.forecast(
>>> source_entity_uuid = UUID("3a53cc35-f632-434c-bd4b-1ed8c014003a"),
>>> target_entity_uuid = UUID("3a53cc35-f632-434c-bd4b-1ed8c014003a"),
>>> kind = RelationshipKinds.ResolvesTo,
>>> )
>>> # Do something with the forecast
>>> print(forecasts)
"""
kebab_kind = _convert_relationship_kind_kebab(kind)
path = f"{self._path}/{source_entity_uuid}/{kebab_kind}/{target_entity_uuid}"
params = {}
if forecast_at is not None:
params["forecastAt"] = rfc3339_timestamp(forecast_at)
if valuable_facts is not None:
params["valuableFacts"] = valuable_facts # type: ignore
r = self._connector.do_get(path=path, params=params)
return RelationshipsForecastView(r.json())
[docs]
class RelationshipsForecastView(JsonObjectView):
"""Relationship forecast view."""
@property
def relationship(self) -> "RelationshipView":
"""Relationship view."""
return RelationshipView(self._get("relationship"))
@property
def confidence(self) -> float:
"""Relationship forecast confidence.
0 if there's no valuable facts about the relationship."""
return self._get("confidence")
@property
def valuable_facts(self) -> Optional[List[ValuableFactView]]:
"""List of forecast valuable facts in descending order of confidence."""
return self._map_list_optional("valuableFacts", ValuableFactView)
[docs]
class RelationshipView(JsonObjectView):
"""Relationship fact view."""
@property
def source(self) -> EntityView:
"""Relationship's source entity.
Warning:
Ref uuid may be zero uuid,
if source entity keys were invalid during registration.
"""
return EntityView(self._get("source"))
@property
def kind(self) -> RelationshipKinds:
"""Kind of the relationship."""
return RelationshipKinds(self._get("kind"))
@property
def target(self) -> EntityView:
"""Target entity.
Warning:
Ref uuid may be zero uuid,
if source entity keys were invalid during registration.
"""
return EntityView(self._get("target"))
@property
def confidence(self) -> float:
"""Relationship fact confidence."""
return float(cast(float, self._get("confidence")))