Skip to content

Commit

Permalink
ContextLinks part google#1:
Browse files Browse the repository at this point in the history
+ Configuration schema & file
+ API endpoint resource and routes
+ Some minor adjustments to make them work
  • Loading branch information
jkppr committed Dec 1, 2022
1 parent 88e8ab7 commit 553c679
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 0 deletions.
46 changes: 46 additions & 0 deletions data/scenarios/context_links.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# ------------------------------------------------------------------------
# -- CONTEXT LINKS --
# ------------------------------------------------------------------------
#
# This is a config file to define context links for event attributes.
#
# Each context link consists of the following fields:
#
# context_link_name:
#
# short_name: Type: str | The name for the context link.
# Will be displayed in the context link submenu.
#
# match_fields: Type: list[str] | List of field keys where
# this context link should be available. Will
# be checked as case insensitive!
#
# validation_regex: Type: str | OPTIONAL
# A regex pattern that needs to be
# matched by the field value to to make the
# context link available. This can be used to
# validate the format of a value (e.g. a hash).
#
# context_link: Type: str | The link that will be opened in a
# new tab when the context link is clicked.
# IMPORTANT: Add the placeholder "<ATTR_VALUE>"
# where the attribute value should be inserted
# into the link.
#
# redirect_warning: [TRUE]: If the context link is clicked it will
# open a pop-up dialog first that asks the
# user if they would like to proceed to
# the linked page. (Recommended for
# external pages.)
# [FALSE]: The linked page will be opened without
# any pop-up. (Recommended for internal
# pages.)
#
# ------------------------------------------------------------------------
## Virustotal Example:
# virustotal_hash_lookup:
# short_name: 'VirusTotal'
# match_fields: ['hash', 'sha256_hash', 'sha256', 'sha1_hash', 'sha1',]
# validation_regex: '/^[0-9a-f]{64}$|^[0-9a-f]{40}$|^[0-9a-f]{32}$/i'
# context_link: 'https://www.virustotal.com/gui/search/<ATTR_VALUE>'
# redirect_warning: TRUE
3 changes: 3 additions & 0 deletions data/timesketch.conf
Original file line number Diff line number Diff line change
Expand Up @@ -320,3 +320,6 @@ QUESTIONS_PATH = '/etc/timesketch/scenarios/questions.yaml'

# Intelligence tag metadata configuration
INTELLIGENCE_TAG_METADATA = '/etc/timesketch/intelligence_tag_metadata.yaml'

# Context links configuration
CONTEXT_LINKS_CONFIG_PATH = '/etc/timesketch/context_links.yaml'
2 changes: 2 additions & 0 deletions docker/dev/build/docker-entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ if [ "$1" = 'timesketch' ]; then
ln -s /usr/local/src/timesketch/data/sigma_config.yaml /etc/timesketch/sigma_config.yaml
ln -s /usr/local/src/timesketch/data/sigma_rule_status.csv /etc/timesketch/sigma_rule_status.csv
ln -s /usr/local/src/timesketch/data/sigma /etc/timesketch/
ln -s /usr/local/src/timesketch/data/scenarios /etc/timesketch/
ln -s /usr/local/src/timesketch/data/context_links.yaml /etc/timesketch/context_links.yaml


# Set SECRET_KEY in /etc/timesketch/timesketch.conf if it isn't already set
Expand Down
105 changes: 105 additions & 0 deletions timesketch/api/v1/resources/contextlinks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# Copyright 2022 Google Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Context link API for version 1 of the Timesketch API."""
import logging
import re
import copy

from flask import jsonify
from flask_restful import Resource
from flask_login import login_required

from timesketch.api.v1 import resources
from timesketch.api.v1.utils import load_yaml_config

# Set up logging
logger = logging.getLogger("timesketch.contextlinks_api")


class ContextLinkConfigResource(resources.ResourceMixin, Resource):
"""Resource to get context link information."""

@login_required
def get(self):
"""Handles GET request to the resource.
Returns:
JSON object including version info
"""
context_link_config = load_yaml_config("CONTEXT_LINKS_CONFIG_PATH")

response = {}

if not context_link_config:
logger.warning('The config file "data/context_links.yaml" is empty!')
return jsonify(response)

# Check mandatory fields are correctly defined.
for item in context_link_config:
item_dict = context_link_config[item]

check_ok = True

# Verify that short_name is defined and type string
if not isinstance(item_dict.get('short_name'), str):
check_ok = False

# Verify that match_fields is defined, has entries and is type list
if isinstance(item_dict.get('match_fields'), list):
if not len(item_dict.get('match_fields')) > 0:
check_ok = False
else:
check_ok = False

# Verify that validation_regex is a valid regeular expression
if isinstance(item_dict.get('validation_regex'), str):
try:
re.compile(item_dict.get('validation_regex'))
except re.error:
logger.warning(
'Context link "{0:s}": "validation_regex" is not a '
'legitimate regex! Please check again.'.format(item))
check_ok = False
else:
if not 'validation_regex' in item_dict.keys():
item_dict['validation_regex'] = ''
else:
check_ok = False

# Verify that context_link is defined and a type string
# Verify that context_link contains the replacment keyword for the value
if isinstance(item_dict.get('context_link'), str):
if not '<ATTR_VALUE>' in item_dict.get('context_link'):
check_ok = False
else:
check_ok = False

# Verify that redirect_warning is defined and type bool
if not isinstance(item_dict.get('redirect_warning'), bool):
check_ok = False

if not check_ok:
logger.warning(
'Failed to load context link: "{0:s}"! Please check the '
'mandatory fields and required format!'.format(item))
continue

# All checks clear. Restructure the output and append to the response.
context_link_conf = copy.deepcopy(item_dict)
del context_link_conf['match_fields']
for field in item_dict.get('match_fields'):
response.setdefault(field.lower(), []).append(
context_link_conf)

return jsonify(response)

2 changes: 2 additions & 0 deletions timesketch/api/v1/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
from .resources.graph import GraphPluginListResource
from .resources.graph import GraphCacheResource
from .resources.intelligence import TagMetadataResource
from .resources.contextlinks import ContextLinkConfigResource

from .resources.scenarios import ScenarioTemplateListResource
from .resources.scenarios import ScenarioListResource
Expand Down Expand Up @@ -163,4 +164,5 @@
(ScenarioTemplateListResource, "/scenarios/"),
(ScenarioListResource, "/sketches/<int:sketch_id>/scenarios/"),
(TagMetadataResource, "/intelligence/tagmetadata/"),
(ContextLinkConfigResource, "/contextlinks/"),
]

0 comments on commit 553c679

Please sign in to comment.