Skip to content
51 changes: 46 additions & 5 deletions importer_client/python/tools/timesketch_importer.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
from timesketch_api_client import cli_input
from timesketch_api_client import credentials as ts_credentials
from timesketch_api_client import crypto
from timesketch_api_client import config
from timesketch_api_client import config, client
from timesketch_api_client import sketch
from timesketch_api_client import version as api_version
from timesketch_import_client import helper
Expand Down Expand Up @@ -59,6 +59,35 @@ def configure_logger_default():
handler.setFormatter(logger_formatter)


def get_sketch_by_name(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Architectural comment

So looking up a sketch by name is a generic operation that would be useful for other integrations as well, not just the importer. (like the existing get_sketch)

Instead of keeping this logic isolated in timesketch_importer.py, could you move this method into the core TimesketchApi class in api_client/python/timesketch_api_client/client.py here?

This would ensure the method can be used in other tools as well and keeps the "business logic" of how we handle sketches in one place. It also let's the importer focus on what it can do best: Import Data.

You can add it right next to the existing get_sketch(self, sketch_id) method. It should handle all the duplicate name issues etc. that we discussed in this PR there as well.

Then, in timesketch_importer.py, you can simply call my_sketch = ts_client.get_sketch_by_name(sketch_name).

ts_client: client.TimesketchApi, sketch_name: str
) -> sketch.Sketch:
"""Gets a sketch by its name.

Args:
ts_client: An instance of timesketch_api_client.TimesketchApi (or similar).
sketch_name: The name of the sketch to find.

Raises:
KeyError: If a sketch with the given name is not found.

Returns:
A sketch object.
"""
sketches = ts_client.list_sketches() # may return Sketch objects or dicts
for s in sketches:
# Sketch object
if hasattr(s, "name") and s.name.lower() == sketch_name.lower():
return s
# dict representation
if isinstance(s, dict) and s.get("name", "").lower() == sketch_name.lower():
sketch_id = s.get("id")
if sketch_id and hasattr(ts_client, "get_sketch"):
return ts_client.get_sketch(sketch_id)
return s
raise KeyError(f"Sketch named {sketch_name!s} not found")


def upload_file(
my_sketch: sketch.Sketch, config_dict: Dict[str, any], file_path: str
) -> str:
Expand Down Expand Up @@ -601,10 +630,22 @@ def main(args=None):
my_sketch = ts_client.get_sketch(sketch_id)
else:
sketch_name = options.sketch_name or "New Sketch From Importer CLI"
my_sketch = ts_client.create_sketch(sketch_name)
logger.info(
"New sketch created: [{0:d}] {1:s}".format(my_sketch.id, my_sketch.name)
)
try:
# check if the sketch name already exists
my_sketch = get_sketch_by_name(ts_client, sketch_name)
logger.info(
"Using existing sketch: [%d] %s",
my_sketch.id,
my_sketch.name,
)
except KeyError:
# no existing sketch found, create a new one
my_sketch = ts_client.create_sketch(sketch_name)
logger.info(
"New sketch created: [%d] %s",
my_sketch.id,
my_sketch.name,
)

if not my_sketch:
logger.error("Unable to get sketch ID: {0:d}".format(sketch_id))
Expand Down