diff --git a/lib/hawat/app.py b/lib/hawat/app.py index daa78fc695ca6868e148075e402337d3de4ae3c5..48554616bc9a3ce422c05932e3639b17a2752de0 100644 --- a/lib/hawat/app.py +++ b/lib/hawat/app.py @@ -243,6 +243,16 @@ def _setup_app_core(app): hawat.const.FA_ICONS[app.view_classes.get(endpoint).get_menu_icon()] ) + def get_csag(group): + """ + Return list of all registered context search actions under given group. + + :param str group: Name of the group. + :return: List of all registered context search actions. + :rtype: list + """ + return app.get_csag(group) + def get_country_flag(country): """ Get URL to static country flag file. @@ -356,6 +366,7 @@ def _setup_app_core(app): get_icon = get_icon, get_module_icon = get_module_icon, get_endpoint_icon = get_endpoint_icon, + get_csag = get_csag, get_country_flag = get_country_flag, get_timedelta = get_timedelta, diff --git a/lib/hawat/base.py b/lib/hawat/base.py index a955dd96cb74c8b8d2d7e6484af64a6ea703c5df..ada0ec1863b16e8f6bdb8135851d672595085378 100644 --- a/lib/hawat/base.py +++ b/lib/hawat/base.py @@ -54,6 +54,7 @@ __credits__ = "Pavel Kácha <pavel.kacha@cesnet.cz>, Andrea Kropáčová <andrea import re import sys +import copy import collections import datetime import weakref @@ -89,6 +90,47 @@ class HawatAppException(Exception): pass +class URLParamsBuilder: + """ + Small utility class for building URL parameter dictionaries for various view + endpoints. + + .. note:: + + This class is still proof of concept and work in progress. + """ + def __init__(self, skeleton = None): + self.rules = {} + self.skeleton = skeleton or {} + + @staticmethod + def _add_scalar(dst, key, val): + dst[key] = val + + @staticmethod + def _add_vector(dst, key, val): + dst[key] = [val] + + def add_rule(self, key, as_list = False): + """ + Add new rule to URL parameter builder. + """ + if as_list: + self.rules[key] = self._add_vector + else: + self.rules[key] = self._add_scalar + return self + + def get_params(self, value): + """ + Get URL parameters as dictionary with filled-in value. + """ + tmp = copy.deepcopy(self.skeleton) + for key, rule in self.rules.items(): + rule(tmp, key, value) + return tmp + + class HawatApp(flask.Flask): """ Custom implementation of :py:class:`flask.Flask` class. This class extends the @@ -119,6 +161,7 @@ class HawatApp(flask.Flask): self.view_classes = {} self.resources = {} + self.csag = {} @property def mconfig(self): @@ -252,6 +295,33 @@ class HawatApp(flask.Flask): """ self.resources[name] = weakref.ref(resource) + def get_csag(self, group): + """ + Return list of all registered context search actions under given group + (CSAG: Context Search Action Group). + + :param str group: Name of the group. + :return: List of all registered context search actions. + :rtype: list + """ + return self.csag.get(group, []) + + def set_csag(self, group, title, view_class, params_builder): + """ + Store new context search action for given group (CSAG: Context Search + Action Group). + + :param str group: Name of the group. + :param str title: Title for the search action. + :param class view_class: Associated view class. + :param URLParamsBuilder params_builder: URL parameter builder for this action. + """ + self.csag.setdefault(group, []).append({ + 'title': title, + 'view': view_class, + 'params': params_builder + }) + class HawatBlueprint(flask.Blueprint): """ diff --git a/lib/hawat/blueprints/design/templates/_macros_site.html b/lib/hawat/blueprints/design/templates/_macros_site.html index b9b2fc9c81ee82292012f7fe9ed9bdab53c28f95..7d2196ca3aa2b559b95894cd1d7f1be1034ffa51 100644 --- a/lib/hawat/blueprints/design/templates/_macros_site.html +++ b/lib/hawat/blueprints/design/templates/_macros_site.html @@ -373,44 +373,211 @@ {%- endif %} {%- endmacro %} -{%- macro render_event_search_widget_category(itemlist, marklist = None, align_right = False, separate_dropdown = False) %} - {%- if itemlist %} - {%- for subitem in itemlist %} - {%- if separate_dropdown %} - {% if marklist and subitem in marklist %}<mark>{{ subitem }}</mark>{%- else %}{{ subitem }}{%- endif %} - {%- endif %} + +{#- + Complex internal macro for rendering context search action dropdown menu for + given group. Main use cases are rendering context action menus for values on + event search result and event detail views. + + string csag_group: Name of the context search action group for which to render + the widget. + list item_list: List of items for which to generate the widgets. This macro can + generate multiple witgets at once, which is very handy for example on + event search result view. + list mark_list: List of items, that should be highlighted. This is usefull for + for example for highlighting search results within the result set. + bool align_right: Align dropdown to the right instead of the default left. + bool separate_dropdown: Generate dropdown separatelly from the label (use + only caret for the button label). + bool without_label: Generate widget without the label. + bool as_code: Generate separate label inside HTML CODE tags. + int item_limit: Limit number of items for which to generate the widgets. This + feature is usefull for limiting number of displayed items in the result, + for example for keeping the table columns in the result from bloating up. + string empty_title: Title to be displayed in case the item_list is empty. + string empty_icon: Icon to be displayed in case the item_list is empty. +-#} +{%- macro _render_widget_csag(csag_group, item_list, mark_list = None, align_right = False, separate_dropdown = False, without_label = False, as_code = False, item_limit = 0, empty_title = _('-- unassigned --'), empty_icon = 'unassigned') %} + {%- if item_list %} + {%- set tmp_csag_list = get_csag(csag_group) %} + {%- for subitem in item_list %} + {#- Limit number of items from item_list for which to generate CSAG widget. -#} + {%- if item_limit and loop.index > item_limit %} + {%- if loop.index0 == item_limit %} + <span class="underlined-tooltip" data-toggle="tooltip" title="{{ _('Please download raw message to view full list.') }}">({{ gettext('%(count)s more', count = loop.length - loop.index0) }})</span> + {%- endif %} + {%- else %} + {%- if separate_dropdown and not without_label %} + {%- if as_code %}<code>{%- endif %}{% if mark_list and subitem.__str__() in mark_list %}<mark>{{ subitem }}</mark>{%- else %}{{ subitem }}{%- endif %}{%- if as_code %}</code>{%- endif %} + {%- endif %} <div class="btn-group"> <button class="btn btn-default btn-xs dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> - {%- if separate_dropdown %} + {%- if separate_dropdown and not without_label %} <span class="caret"></span> - {%- else %} - {% if marklist and subitem in marklist %}<mark>{{ subitem }}</mark>{%- else %}{{ subitem }}{%- endif %} <span class="caret"></span> - {%- endif %} + {%- elif not without_label %} + {% if mark_list and subitem.__str__() in mark_list %}<mark>{{ subitem }}</mark>{%- else %}{{ subitem }}{%- endif %} <span class="caret"></span> + {%- else %} + <span class="caret"></span> + {%- endif %} </button> <ul class="dropdown-menu{% if align_right %} dropdown-menu-right{% endif %}"> <li class="dropdown-header"> - {{ gettext('Event category "%(name)s"', name = subitem) | safe }} + {{ _('Context search actions:') }} </li> - {%- if check_endpoint_exists('events.search') %} + {%- for csag_item in tmp_csag_list %} + {%- if check_endpoint_exists(csag_item.view.get_view_endpoint()) %} + {%- set tmp_endpoint_name = csag_item.view.get_view_endpoint() %} <li> - <a href="{{ url_for('events.search', categories = [subitem], submit = gettext('Search')) }}"> - {{ get_endpoint_icon('events.search') }} {{ gettext('Search for category <strong>%(name)s</strong> in event database', name = subitem) | safe }} + <a href="{{ url_for(tmp_endpoint_name, **csag_item.params.get_params(subitem)) }}"> + {{ get_endpoint_icon(tmp_endpoint_name) }} {{ _(csag_item.title, name = subitem) | safe }} </a> </li> - {%- endif %} + {%- endif %} + {%- endfor %} </ul> </div> + {%- endif %} {%- endfor %} {%- else %} - {{ gettext('-- undisclosed --')}} + <span data-toggle="tooltip" title="{{ empty_title }}">{{ get_icon(empty_icon) }}</span> {%- endif %} {%- endmacro %} -{%- macro render_event_search_widget_severity(itemlist, marklist = None, align_right = False, separate_dropdown = False, without_label = False) %} - {%- if itemlist %} - {%- for subitem in itemlist %} +{%- macro render_widget_csag_abuse(item_list, mark_list = None, align_right = False, separate_dropdown = False, without_label = False) %} +{{ + _render_widget_csag( + 'abuse', + item_list, + mark_list, + align_right, + separate_dropdown, + without_label + ) +}} +{%- endmacro %} + +{%- macro render_widget_csag_address(item_list, mark_list = None, align_right = False, separate_dropdown = False, without_label = False, item_limit = 0) %} +{{ + _render_widget_csag( + 'address', + item_list, + mark_list, + align_right, + separate_dropdown, + without_label, + True, + item_limit, + _('-- undisclosed --'), + 'undisclosed' + ) +}} +{%- endmacro %} + +{%- macro render_widget_csag_category(item_list, mark_list = None, align_right = False, separate_dropdown = False, without_label = False) %} +{{ + _render_widget_csag( + 'category', + item_list, + mark_list, + align_right, + separate_dropdown, + without_label + ) +}} +{%- endmacro %} + +{%- macro render_widget_csag_class(item_list, mark_list = None, align_right = False, separate_dropdown = False, without_label = False) %} +{{ + _render_widget_csag( + 'class', + item_list, + mark_list, + align_right, + separate_dropdown, + without_label + ) +}} +{%- endmacro %} + +{%- macro render_widget_csag_detector(item_list, mark_list = None, align_right = False, separate_dropdown = False, without_label = False) %} +{{ + _render_widget_csag( + 'detector', + item_list, + mark_list, + align_right, + separate_dropdown, + without_label + ) +}} +{%- endmacro %} + +{%- macro render_widget_csag_detectortype(item_list, mark_list = None, align_right = False, separate_dropdown = False, without_label = False) %} +{{ + _render_widget_csag( + 'detector_type', + item_list, + mark_list, + align_right, + separate_dropdown, + without_label + ) +}} +{%- endmacro %} + +{%- macro render_widget_csag_hosttype(item_list, mark_list = None, align_right = False, separate_dropdown = False, without_label = False) %} +{{ + _render_widget_csag( + 'host_type', + item_list, + mark_list, + align_right, + separate_dropdown, + without_label + ) +}} +{%- endmacro %} + +{%- macro render_widget_csag_port(item_list, mark_list = None, align_right = False, separate_dropdown = False, without_label = False, item_limit = 0) %} +{{ + _render_widget_csag( + 'port', + item_list, + mark_list, + align_right, + separate_dropdown, + without_label, + True, + item_limit, + _('-- undisclosed --'), + 'undisclosed' + ) +}} +{%- endmacro %} + +{%- macro render_widget_csag_protocol(item_list, mark_list = None, align_right = False, separate_dropdown = False, without_label = False, item_limit = 0) %} +{{ + _render_widget_csag( + 'protocol', + item_list, + mark_list, + align_right, + separate_dropdown, + without_label, + True, + item_limit, + _('-- undisclosed --'), + 'undisclosed' + ) +}} +{%- endmacro %} + + +{%- macro render_widget_csag_severity(item_list, mark_list = None, align_right = False, separate_dropdown = False, without_label = False) %} + {%- if item_list %} + {%- for subitem in item_list %} {%- if separate_dropdown and not without_label %} - {% if marklist and subitem in marklist %}<mark>{{ subitem }}</mark>{%- else %}{{ subitem }}{%- endif %} + {% if mark_list and subitem in mark_list %}<mark>{{ subitem }}</mark>{%- else %}{{ subitem }}{%- endif %} {%- endif %} <div class="btn-group"> {%- if subitem == 'low' %} @@ -433,376 +600,29 @@ {%- if separate_dropdown and not without_label %} <span class="caret"></span> {%- elif not without_label %} - {{ get_icon(tmpicon) }} {% if marklist and subitem in marklist %}<mark>{{ gettext(subitem) | upper }}</mark>{%- else %}{{ gettext(subitem) | upper }}{%- endif %} <span class="caret"></span> - {%- else %} - <span class="caret"></span> - {%- endif %} - </button> - <ul class="dropdown-menu{% if align_right %} dropdown-menu-right{% endif %}"> - <li class="dropdown-header"> - {{ gettext('Event severity "%(name)s"', name = gettext(subitem)) | safe }} - </li> - {%- if check_endpoint_exists('events.search') %} - <li> - <a href="{{ url_for('events.search', severities = [subitem], submit = gettext('Search')) }}"> - {{ get_endpoint_icon('events.search') }} {{ gettext('Search for severity <strong>%(name)s</strong> in event database', name = subitem) | safe }} - </a> - </li> - {%- endif %} - </ul> - </div> - {%- endfor %} - {%- else %} - {{ gettext('-- unassigned --')}} - {%- endif %} -{%- endmacro %} - -{%- macro render_event_search_widget_class(itemlist, marklist = None, align_right = False, separate_dropdown = False, without_label = False) %} - {%- if itemlist %} - {%- for subitem in itemlist %} - {%- if separate_dropdown and not without_label %} - {% if marklist and subitem in marklist %}<mark>{{ subitem }}</mark>{%- else %}{{ subitem }}{%- endif %} - {%- endif %} - <div class="btn-group"> - <button class="btn btn-default btn-xs dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> - {%- if separate_dropdown and not without_label %} - <span class="caret"></span> - {%- elif not without_label %} - {% if marklist and subitem in marklist %}<mark>{{ subitem }}</mark>{%- else %}{{ subitem }}{%- endif %} <span class="caret"></span> - {%- else %} - <span class="caret"></span> - {%- endif %} - </button> - <ul class="dropdown-menu{% if align_right %} dropdown-menu-right{% endif %}"> - <li class="dropdown-header"> - {{ gettext('Event class "%(name)s"', name = subitem) | safe }} - </li> - {%- if check_endpoint_exists('events.search') %} - <li> - <a href="{{ url_for('events.search', classes = [subitem], submit = gettext('Search')) }}"> - {{ get_endpoint_icon('events.search') }} {{ gettext('Search for class <strong>%(name)s</strong> in event database', name = subitem) | safe }} - </a> - </li> - {%- endif %} - </ul> - </div> - {%- endfor %} - {%- else %} - {{ gettext('-- unassigned --')}} - {%- endif %} -{%- endmacro %} - -{%- macro render_event_search_widget_group(itemlist, marklist = None, align_right = False, separate_dropdown = False) %} - {%- if itemlist %} - {%- for subitem in itemlist %} - {%- if separate_dropdown %} - <a href="{{ url_for('groups.show_by_name', item_id = subitem) }}">{% if marklist and subitem in marklist %}<mark>{{ subitem }}</mark>{%- else %}{{ subitem }}{%- endif %}</a> - {%- endif %} - <div class="btn-group"> - <button class="btn btn-default btn-xs dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> - {%- if separate_dropdown %} - <span class="caret"></span> - {%- else %} - {% if marklist and subitem in marklist %}<mark>{{ subitem }}</mark>{%- else %}{{ subitem }}{%- endif %} <span class="caret"></span> - {%- endif %} - </button> - <ul class="dropdown-menu{% if align_right %} dropdown-menu-right{% endif %}"> - <li class="dropdown-header"> - {{ gettext('Abuse group "%(name)s"', name = subitem) | safe }} - </li> - {%- if check_endpoint_exists('events.search') %} - <li> - <a href="{{ url_for('events.search', groups = [subitem], submit = gettext('Search')) }}"> - {{ get_endpoint_icon('events.search') }} {{ gettext('Search for abuse group <strong>%(name)s</strong> in event database', name = subitem) | safe }} - </a> - </li> - {%- endif %} - {%- if check_endpoint_exists('reports.search') %} - <li> - <a href="{{ url_for('reports.search', groups = [subitem], submit = gettext('Search')) }}"> - {{ get_endpoint_icon('reports.search') }} {{ gettext('Search for abuse group <strong>%(name)s</strong> in report database', name = subitem) | safe }} - </a> - </li> - {%- endif %} - {%- if check_endpoint_exists('reports.dashboard') %} - <li> - <a href="{{ url_for('reports.dashboard', groups = [subitem], submit = gettext('Search')) }}"> - {{ get_endpoint_icon('reports.dashboard') }} {{ gettext('Search for abuse group <strong>%(name)s</strong> in reporting dashboards', name = subitem) | safe }} - </a> - </li> - {%- endif %} - {%- if check_endpoint_exists('groups.show_by_name') %} - <li> - <a href="{{ url_for('groups.show_by_name', item_id = subitem) }}"> - {{ get_endpoint_icon('groups.show_by_name') }} {{ gettext('View details of abuse group <strong>%(name)s</strong>', name = subitem) | safe }} - </a> - </li> - {%- endif %} - </ul> - </div> - {%- endfor %} - {%- else %} - {{ gettext('-- unassigned --')}} - {%- endif %} -{%- endmacro %} - -{%- macro render_event_search_widget_hostaddr(itemlist, marklist = None, align_right = False, separate_dropdown = False, item_limit = 0) %} - {%- if itemlist %} - {%- for subitem in itemlist %} - {%- if item_limit and loop.index > item_limit %} - {%- if loop.index0 == item_limit %} - <span class="underlined-tooltip" data-toggle="tooltip" title="{{ gettext('Please download raw message to view full list.') }}">({{ gettext('%(count)s more', count = loop.length - loop.index0) }})</span> - {%- endif %} - {%- else %} - {%- if separate_dropdown %} - <code>{% if marklist and subitem in marklist %}<mark>{{ subitem }}</mark>{%- else %}{{ subitem }}{%- endif %}</code> - {%- endif %} - <div class="btn-group"> - <button class="btn btn-default btn-xs dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> - {%- if separate_dropdown %} - <span class="caret"></span> - {%- else %} - {%- if marklist and subitem.__str__() in marklist %}<mark>{{ subitem }}</mark>{%- else %}{{ subitem }}{%- endif %} <span class="caret"></span> - {%- endif %} - </button> - <ul class="dropdown-menu{% if align_right %} dropdown-menu-right{% endif %}"> - <li class="dropdown-header"> - {{ gettext('Host "%(name)s"', name = subitem) | safe }} - </li> - {%- if check_endpoint_exists('events.search') %} - <li> - <a href="{{ url_for('events.search', source_addrs = subitem, submit = gettext('Search')) }}"> - {{ get_endpoint_icon('events.search') }} {{ gettext('Search for source <strong>%(name)s</strong> in IDEA event database', name = subitem) | safe }} - </a> - </li> - <li> - <a href="{{ url_for('events.search', target_addrs = subitem, submit = gettext('Search')) }}"> - {{ get_endpoint_icon('events.search') }} {{ gettext('Search for target <strong>%(name)s</strong> in IDEA event database', name = subitem) | safe }} - </a> - </li> - <li> - <a href="{{ url_for('events.search', host_addrs = subitem, submit = gettext('Search')) }}"> - {{ get_endpoint_icon('events.search') }} {{ gettext('Search for host <strong>%(name)s</strong> in IDEA event database', name = subitem) | safe }} - </a> - </li> - {%- endif %} - {%- if check_endpoint_exists('geoip.search') %} - <li> - <a href="{{ url_for('geoip.search', search = subitem, submit = gettext('Search')) }}"> - {{ get_endpoint_icon('geoip.search') }} {{ gettext('Search for address <strong>%(name)s</strong> in internal IP geolocation database', name = subitem) | safe }} - </a> - </li> - {%- endif %} - {%- if check_endpoint_exists('whois.search') %} - <li> - <a href="{{ url_for('whois.search', search = subitem, submit = gettext('Search')) }}"> - {{ get_endpoint_icon('whois.search') }} {{ gettext('Search for address <strong>%(name)s</strong> in internal whois database', name = subitem) | safe }} - </a> - </li> - {%- endif %} - </ul> - </div> - {%- endif %} - {%- endfor %} - {%- else %} - {{ gettext('-- undisclosed --')}} - {%- endif %} -{%- endmacro %} - -{%- macro render_event_search_widget_hostport(itemlist, marklist = None, align_right = False, separate_dropdown = False, item_limit = 0) %} - {%- if itemlist %} - {%- for subitem in itemlist %} - {%- if item_limit and loop.index > item_limit %} - {%- if loop.index0 == item_limit %} - <span class="underlined-tooltip" data-toggle="tooltip" title="{{ gettext('Please download raw message to view full list.') }}">({{ gettext('%(count)s more', count = loop.length - loop.index0) }})</span> - {%- endif %} + {{ get_icon(tmpicon) }} {% if mark_list and subitem in mark_list %}<mark>{{ gettext(subitem) | upper }}</mark>{%- else %}{{ gettext(subitem) | upper }}{%- endif %} <span class="caret"></span> {%- else %} - {%- if separate_dropdown %} - <code>{% if marklist and subitem in marklist %}<mark>{{ subitem }}</mark>{%- else %}{{ subitem }}{%- endif %}</code> - {%- endif %} - <div class="btn-group"> - <button class="btn btn-default btn-xs dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> - {%- if separate_dropdown %} <span class="caret"></span> - {%- else %} - {% if marklist and subitem in marklist %}<mark>{{ subitem }}</mark>{%- else %}{{ subitem }}{%- endif %} <span class="caret"></span> - {%- endif %} - </button> - <ul class="dropdown-menu{% if align_right %} dropdown-menu-right{% endif %}"> - <li class="dropdown-header"> - {{ gettext('Host port "%(name)s"', name = subitem) | safe }} - </li> - {%- if check_endpoint_exists('events.search') %} - <li> - <a href="{{ url_for('events.search', source_ports = [subitem], submit = gettext('Search')) }}"> - {{ get_endpoint_icon('events.search') }} {{ gettext('Search for source port <strong>%(name)s</strong> in event database', name = subitem) | safe }} - </a> - </li> - <li> - <a href="{{ url_for('events.search', target_ports = [subitem], submit = gettext('Search')) }}"> - {{ get_endpoint_icon('events.search') }} {{ gettext('Search for target port <strong>%(name)s</strong> in event database', name = subitem) | safe }} - </a> - </li> - <li> - <a href="{{ url_for('events.search', host_ports = [subitem], submit = gettext('Search')) }}"> - {{ get_endpoint_icon('events.search') }} {{ gettext('Search for host port <strong>%(name)s</strong> in event database', name = subitem) | safe }} - </a> - </li> - {%- endif %} - </ul> - </div> - {%- endif %} - {%- endfor %} - {%- else %} - {{ gettext('-- undisclosed --')}} - {%- endif %} -{%- endmacro %} - -{%- macro render_event_search_widget_hosttype(itemlist, marklist = None, align_right = False, separate_dropdown = False) %} - {%- if itemlist %} - {%- for subitem in itemlist %} - {%- if separate_dropdown %} - <code>{% if marklist and subitem in marklist %}<mark>{{ subitem }}</mark>{%- else %}{{ subitem }}{%- endif %}</code> - {%- endif %} - <div class="btn-group"> - <button class="btn btn-default btn-xs dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> - {%- if separate_dropdown %} - <span class="caret"></span> - {%- else %} - {% if marklist and subitem in marklist %}<mark>{{ subitem }}</mark>{%- else %}{{ subitem }}{%- endif %} <span class="caret"></span> {%- endif %} </button> <ul class="dropdown-menu{% if align_right %} dropdown-menu-right{% endif %}"> <li class="dropdown-header"> - {{ gettext('Host type "%(name)s"', name = subitem) | safe }} - </li> - {%- if check_endpoint_exists('events.search') %} - <li> - <a href="{{ url_for('events.search', source_types = [subitem], submit = gettext('Search')) }}"> - {{ get_endpoint_icon('events.search') }} {{ gettext('Search for source type <strong>%(name)s</strong> in event database', name = subitem) | safe }} - </a> - </li> - <li> - <a href="{{ url_for('events.search', target_types = [subitem], submit = gettext('Search')) }}"> - {{ get_endpoint_icon('events.search') }} {{ gettext('Search for target type <strong>%(name)s</strong> in event database', name = subitem) | safe }} - </a> + {{ _('Context search actions:') }} </li> + {%- for csag_item in get_csag('severity') %} + {%- if check_endpoint_exists(csag_item.view.get_view_endpoint()) %} <li> - <a href="{{ url_for('events.search', host_types = [subitem], submit = gettext('Search')) }}"> - {{ get_endpoint_icon('events.search') }} {{ gettext('Search for host type <strong>%(name)s</strong> in event database', name = subitem) | safe }} - </a> - </li> - {%- endif %} - </ul> - </div> - {%- endfor %} - {%- else %} - {{ gettext('-- undisclosed --')}} - {%- endif %} -{%- endmacro %} - -{%- macro render_event_search_widget_protocol(itemlist, marklist = None, align_right = False, separate_dropdown = False, item_limit = 0) %} - {%- if itemlist %} - {%- for subitem in itemlist %} - {%- if item_limit and loop.index > item_limit %} - {%- if loop.index0 == item_limit %} - <span class="underlined-tooltip" data-toggle="tooltip" title="{{ gettext('Please download raw message to view full list.') }}">({{ gettext('%(count)s more', count = loop.length - loop.index0) }})</span> - {%- endif %} - {%- else %} - {%- if separate_dropdown %} - <code>{% if marklist and subitem in marklist %}<mark>{{ subitem }}</mark>{%- else %}{{ subitem }}{%- endif %}</code> - {%- endif %} - <div class="btn-group"> - <button class="btn btn-default btn-xs dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> - {%- if separate_dropdown %} - <span class="caret"></span> - {%- else %} - {% if marklist and subitem in marklist %}<mark>{{ subitem }}</mark>{%- else %}{{ subitem }}{%- endif %} <span class="caret"></span> - {%- endif %} - </button> - <ul class="dropdown-menu{% if align_right %} dropdown-menu-right{% endif %}"> - <li class="dropdown-header"> - {{ gettext('Protocol "%(name)s"', name = subitem) | safe }} - </li> - {%- if check_endpoint_exists('events.search') %} - <li> - <a href="{{ url_for('events.search', protocols = [subitem], submit = gettext('Search')) }}"> - {{ get_endpoint_icon('events.search') }} {{ gettext('Search for protocol <strong>%(name)s</strong> in event database', name = subitem) | safe }} + <a href="{{ url_for(csag_item.view.get_view_endpoint(), **csag_item.params.get_params(subitem)) }}"> + {{ get_endpoint_icon(csag_item.view.get_view_endpoint()) }} {{ _(csag_item.title, name = subitem) | safe }} </a> </li> {%- endif %} - </ul> - </div> - {%- endif %} - {%- endfor %} - {%- else %} - {{ gettext('-- undisclosed --')}} - {%- endif %} -{%- endmacro %} - -{%- macro render_event_search_widget_detector(itemlist, marklist = None, align_right = False, separate_dropdown = False) %} - {%- if itemlist %} - {%- for subitem in itemlist %} - {%- if separate_dropdown %} - {% if marklist and subitem in marklist %}<mark>{{ subitem }}</mark>{%- else %}{{ subitem }}{%- endif %} - {%- endif %} - <div class="btn-group"> - <button class="btn btn-default btn-xs dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> - {%- if separate_dropdown %} - <span class="caret"></span> - {%- else %} - {% if marklist and subitem in marklist %}<mark>{{ subitem }}</mark>{%- else %}{{ subitem }}{%- endif %} <span class="caret"></span> - {%- endif %} - </button> - <ul class="dropdown-menu{% if align_right %} dropdown-menu-right{% endif %}"> - <li class="dropdown-header"> - {{ gettext('Detector "%(name)s"', name = subitem) | safe }} - </li> - {%- if check_endpoint_exists('events.search') %} - <li> - <a href="{{ url_for('events.search', detectors = [subitem], submit = gettext('Search')) }}"> - {{ get_endpoint_icon('events.search') }} {{ gettext('Search for detector <strong>%(name)s</strong> in event database', name = subitem) | safe }} - </a> - </li> - {%- endif %} - </ul> - </div> - {%- endfor %} - {%- else %} - {{ gettext('-- undisclosed --')}} - {%- endif %} -{%- endmacro %} - -{%- macro render_event_search_widget_detectortype(itemlist, marklist = None, align_right = False, separate_dropdown = False) %} - {%- if itemlist %} - {%- for subitem in itemlist %} - {%- if separate_dropdown %} - <code>{% if marklist and subitem in marklist %}<mark>{{ subitem }}</mark>{%- else %}{{ subitem }}{%- endif %}</code> - {%- endif %} - <div class="btn-group"> - <button class="btn btn-default btn-xs dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> - {%- if separate_dropdown %} - <span class="caret"></span> - {%- else %} - {% if marklist and subitem in marklist %}<mark>{{ subitem }}</mark>{%- else %}{{ subitem }}{%- endif %} <span class="caret"></span> - {%- endif %} - </button> - <ul class="dropdown-menu{% if align_right %} dropdown-menu-right{% endif %}"> - <li class="dropdown-header"> - {{ gettext('Detector type "%(name)s"', name = subitem) | safe }} - </li> - {%- if check_endpoint_exists('events.search') %} - <li> - <a href="{{ url_for('events.search', detector_types = [subitem], submit = gettext('Search')) }}"> - {{ get_endpoint_icon('events.search') }} {{ gettext('Search for detector type <strong>%(name)s</strong> in event database', name = subitem) | safe }} - </a> - </li> - {%- endif %} + {%- endfor %} </ul> </div> {%- endfor %} {%- else %} - {{ gettext('-- undisclosed --')}} + <span data-toggle="tooltip" title="{{ _('-- unassigned --') }}">{{ get_icon('unassigned') }}</span> {%- endif %} {%- endmacro %} diff --git a/lib/hawat/blueprints/events/__init__.py b/lib/hawat/blueprints/events/__init__.py index 720c88cb018135440c51574c460f1414daefbd7e..739a8f635e2967bdc262c49851a73e0239a6e553 100644 --- a/lib/hawat/blueprints/events/__init__.py +++ b/lib/hawat/blueprints/events/__init__.py @@ -532,12 +532,14 @@ from flask_babel import gettext, lazy_gettext import mentat.stats.idea import mentat.services.eventstorage from mentat.datatype.sqldb import EventStatisticsModel +from mentat.const import tr_ import hawat.const import hawat.events import hawat.acl from hawat.base import HTMLViewMixin, PsycopgViewMixin, AJAXViewMixin, SQLAlchemyViewMixin,\ - HawatBaseView, HawatSearchView, HawatItemShowView, HawatSimpleView, HawatBlueprint + HawatBaseView, HawatSearchView, HawatItemShowView, HawatSimpleView, HawatBlueprint,\ + URLParamsBuilder from hawat.blueprints.events.forms import SimpleEventSearchForm, EventDashboardForm @@ -987,6 +989,113 @@ class EventsBlueprint(HawatBlueprint): resptitle = True ) + # Register context search actions provided by this module. + app.set_csag( + hawat.const.HAWAT_CSAG_ABUSE, + tr_('Search for abuse group <strong>%(name)s</strong> in event database'), + SearchView, + URLParamsBuilder({'submit': tr_('Search')}).add_rule('groups', True) + ) + + app.set_csag( + hawat.const.HAWAT_CSAG_ADDRESS, + tr_('Search for source <strong>%(name)s</strong> in event database'), + SearchView, + URLParamsBuilder({'submit': tr_('Search')}).add_rule('source_addrs', True) + ) + app.set_csag( + hawat.const.HAWAT_CSAG_ADDRESS, + tr_('Search for target <strong>%(name)s</strong> in event database'), + SearchView, + URLParamsBuilder({'submit': tr_('Search')}).add_rule('target_addrs', True) + ) + app.set_csag( + hawat.const.HAWAT_CSAG_ADDRESS, + tr_('Search for host <strong>%(name)s</strong> in event database'), + SearchView, + URLParamsBuilder({'submit': tr_('Search')}).add_rule('host_addrs', True) + ) + + app.set_csag( + hawat.const.HAWAT_CSAG_CATEGORY, + tr_('Search for category <strong>%(name)s</strong> in event database'), + SearchView, + URLParamsBuilder({'submit': tr_('Search')}).add_rule('categories', True) + ) + + app.set_csag( + hawat.const.HAWAT_CSAG_CLASS, + tr_('Search for class <strong>%(name)s</strong> in event database'), + SearchView, + URLParamsBuilder({'submit': tr_('Search')}).add_rule('classes', True) + ) + + app.set_csag( + hawat.const.HAWAT_CSAG_DETECTOR, + tr_('Search for detector <strong>%(name)s</strong> in event database'), + SearchView, + URLParamsBuilder({'submit': tr_('Search')}).add_rule('detectors', True) + ) + + app.set_csag( + hawat.const.HAWAT_CSAG_DETTYPE, + tr_('Search for detector type <strong>%(name)s</strong> in event database'), + SearchView, + URLParamsBuilder({'submit': tr_('Search')}).add_rule('detector_types', True) + ) + + app.set_csag( + hawat.const.HAWAT_CSAG_HOSTTYPE, + tr_('Search for source type <strong>%(name)s</strong> in event database'), + SearchView, + URLParamsBuilder({'submit': tr_('Search')}).add_rule('source_types', True) + ) + app.set_csag( + hawat.const.HAWAT_CSAG_HOSTTYPE, + tr_('Search for target type <strong>%(name)s</strong> in event database'), + SearchView, + URLParamsBuilder({'submit': tr_('Search')}).add_rule('target_types', True) + ) + app.set_csag( + hawat.const.HAWAT_CSAG_HOSTTYPE, + tr_('Search for host type <strong>%(name)s</strong> in event database'), + SearchView, + URLParamsBuilder({'submit': tr_('Search')}).add_rule('host_types', True) + ) + + app.set_csag( + hawat.const.HAWAT_CSAG_PORT, + tr_('Search for source port <strong>%(name)s</strong> in event database'), + SearchView, + URLParamsBuilder({'submit': tr_('Search')}).add_rule('source_ports', True) + ) + app.set_csag( + hawat.const.HAWAT_CSAG_PORT, + tr_('Search for target port <strong>%(name)s</strong> in event database'), + SearchView, + URLParamsBuilder({'submit': tr_('Search')}).add_rule('target_ports', True) + ) + app.set_csag( + hawat.const.HAWAT_CSAG_PORT, + tr_('Search for host port <strong>%(name)s</strong> in event database'), + SearchView, + URLParamsBuilder({'submit': tr_('Search')}).add_rule('host_ports', True) + ) + + app.set_csag( + hawat.const.HAWAT_CSAG_PROTOCOL, + tr_('Search for protocol <strong>%(name)s</strong> in event database'), + SearchView, + URLParamsBuilder({'submit': tr_('Search')}).add_rule('protocols', True) + ) + + app.set_csag( + hawat.const.HAWAT_CSAG_SEVERITY, + tr_('Search for severity <strong>%(name)s</strong> in event database'), + SearchView, + URLParamsBuilder({'submit': tr_('Search')}).add_rule('severities', True) + ) + #------------------------------------------------------------------------------- diff --git a/lib/hawat/blueprints/events/templates/events/search.html b/lib/hawat/blueprints/events/templates/events/search.html index a6305589e81eb4d9963624ead35726f86ba6734d..129656c0d58afd5875ee4594dad2cd1e930984e1 100644 --- a/lib/hawat/blueprints/events/templates/events/search.html +++ b/lib/hawat/blueprints/events/templates/events/search.html @@ -4,7 +4,6 @@ <div class="row"> <div class="col-lg-12"> - {{ macros_page.render_breadcrumbs() }} <!-- Search form - BEGIN ----------------------------------> @@ -83,6 +82,7 @@ {%- set frmctrldsb = in_query_params(request.args, ['dt_from', 'dt_to'], False, True, False) %} {%- set frmctrlhdn = in_query_params(request.args, ['dt_from', 'dt_to'], '', ' hidden', '') %} + <div class="form-group{{ frmctrlhdn }}" id="form-group-detecttime"> <div class="col-sm-6"> <label>{{ g.search_form.dt_from.label }}</label> @@ -363,7 +363,6 @@ {%- endif %} {%- if items_count %} - {{ macros_site.render_pager(request.endpoint, query_params, pager_index_low, pager_index_high, pager_index_limit) }} <table class="table table-striped table-bordered table-hover table-condensed table-responsive"> @@ -383,7 +382,7 @@ {{ gettext('Detected at') }} </th> {%- endif %} - <th data-toggle="tooltip" title="{{ gettext('Problem sources') }}"> + <th data-toggle="tooltip" title="{{ gettext('Problem sources') }}" class="hidden-xs hidden-sm"> {{ gettext('Sources') }} </th> <th data-toggle="tooltip" title="{{ gettext('Targets or victims') }}" class="hidden-xs hidden-sm hidden-md"> @@ -424,42 +423,77 @@ {{ babel_format_datetime(item.get_detect_time()) | replace(' ', ' ' | safe )}} </td> {%- endif %} - <td> - {%- if item.get_addresses('Source') %} - {{ macros_site.render_event_search_widget_hostaddr(item.get_addresses('Source'), [] + form_data['source_addrs'] + form_data['target_addrs'] + form_data['host_addrs'], separate_dropdown = False, item_limit = search_widget_item_limit) }} - {%- else %} - <span data-toggle="tooltip" title="{{ gettext('-- undisclosed --') }}">{{ get_icon('undisclosed') }}</span> - {%- endif %} + <td class="hidden-xs hidden-sm"> + {{ + macros_site.render_widget_csag_address( + item.get_addresses('Source'), + [] + form_data['source_addrs'] + form_data['target_addrs'] + form_data['host_addrs'], separate_dropdown = False, + item_limit = search_widget_item_limit + ) + }} </td> <td class="hidden-xs hidden-sm hidden-md"> - {%- if item.get_addresses('Target') %} - {{ macros_site.render_event_search_widget_hostaddr(item.get_addresses('Target'), [] + form_data['source_addrs'] + form_data['target_addrs'] + form_data['host_addrs'], separate_dropdown = False, item_limit = search_widget_item_limit) }} - {%- else %} - <span data-toggle="tooltip" title="{{ gettext('-- undisclosed --') }}">{{ get_icon('undisclosed') }}</span> - {%- endif %} + {{ + macros_site.render_widget_csag_address( + item.get_addresses('Target'), + [] + form_data['source_addrs'] + form_data['target_addrs'] + form_data['host_addrs'], separate_dropdown = False, + item_limit = search_widget_item_limit + ) + }} </td> <td> - {%- if item.get_severity() %} - {{ macros_site.render_event_search_widget_severity([item.get_severity()], align_right = True, separate_dropdown = False) }} + {%- set tmpval = item.get_severity() %} + {%- if tmpval %} + {{ + macros_site.render_widget_csag_severity( + [tmpval], + align_right = True, + separate_dropdown = False + ) + }} {%- else %} - <span data-toggle="tooltip" title="{{ gettext('-- unassigned --') }}">{{ get_icon('unassigned') }}</span> + <span data-toggle="tooltip" title="{{ gettext('-- unassigned --') }}"> + {{ get_icon('unassigned') }} + </span> {%- endif %} </td> <td> - {{ macros_site.render_event_search_widget_category(item.get_categories(), form_data['categories'], align_right = True, separate_dropdown = False) }} - </td> - <td> - {%- set tmpdts = item.get_detectors() %} - {{ macros_site.render_event_search_widget_detector([tmpdts[-1]], form_data['detectors'], align_right = True, separate_dropdown = False) }} + {{ + macros_site.render_widget_csag_category( + item.get_categories(), + form_data['categories'], + align_right = True, + separate_dropdown = False + ) + }} </td> <td> - {%- if item.get_abuses() %} - {{ macros_site.render_event_search_widget_group(item.get_abuses(), form_data['groups'], align_right = True, separate_dropdown = False) }} + {%- set tmpval = item.get_detectors() %} + {%- if tmpval %} + {{ + macros_site.render_widget_csag_detector( + [tmpval[-1]], + form_data['detectors'], + align_right = True, + separate_dropdown = False + ) + }} {%- else %} - <span data-toggle="tooltip" title="{{ gettext('-- unassigned --') }}">{{ get_icon('unassigned') }}</span> + <span data-toggle="tooltip" title="{{ gettext('-- unassigned --') }}"> + {{ get_icon('unassigned') }} + </span> {%- endif %} </td> - + <td> + {{ + macros_site.render_widget_csag_abuse( + item.get_abuses(), + form_data['groups'], + align_right = True, + separate_dropdown = False + ) + }} + </td> <td> {{ macros_page.render_menu_context_actions(item) }} </td> diff --git a/lib/hawat/blueprints/events/templates/events/show.html b/lib/hawat/blueprints/events/templates/events/show.html index 1a6054973be84df19525748772df31317f14100f..1d294357c4583b92fe146947282de7f2cd25e300 100644 --- a/lib/hawat/blueprints/events/templates/events/show.html +++ b/lib/hawat/blueprints/events/templates/events/show.html @@ -115,7 +115,7 @@ {{ gettext('Categories') }}: </th> <td> - {{ macros_site.render_event_search_widget_category(item.get_categories(), align_right = True, separate_dropdown = True) }} + {{ macros_site.render_widget_csag_category(item.get_categories(), align_right = True, separate_dropdown = True) }} </td> </tr> <tr> @@ -124,7 +124,7 @@ </th> <td> {%- if item.get_severity() %} - {{ macros_site.render_event_search_widget_severity([item.get_severity()], align_right = True) }} + {{ macros_site.render_widget_csag_severity([item.get_severity()], align_right = True) }} {%- else %} {{ gettext('-- unassigned --') }} {%- endif %} @@ -138,7 +138,7 @@ <td> {%- if item.get_class() %} {{ item.get_class() }} - {{ macros_site.render_event_search_widget_class([item.get_class()], align_right = True, separate_dropdown = True, without_label = True) }} + {{ macros_site.render_widget_csag_class([item.get_class()], align_right = True, separate_dropdown = True, without_label = True) }} {%- else %} {{ gettext('-- unclassified --') }} {%- endif %} @@ -150,7 +150,7 @@ {{ gettext('Abuse groups') }}: </th> <td> - {{ macros_site.render_event_search_widget_group(item.get_abuses(), align_right = True, separate_dropdown = True) }} + {{ macros_site.render_widget_csag_abuse(item.get_abuses(), align_right = True, separate_dropdown = True) }} </td> </tr> {%- if item.get_countries_src() %} @@ -188,27 +188,27 @@ <li class="list-group-item"> {%- if 'IP4' in subitem %} <div> - <span class="label label-default"><strong>{{ gettext('IP4') }}:</strong></span> {{ macros_site.render_event_search_widget_hostaddr(subitem['IP4'], separate_dropdown = True, item_limit = search_widget_item_limit) }} + <span class="label label-default"><strong>{{ gettext('IP4') }}:</strong></span> {{ macros_site.render_widget_csag_address(subitem['IP4'], separate_dropdown = True, item_limit = search_widget_item_limit) }} </div> {%- endif %} {%- if 'IP6' in subitem %} <div> - <span class="label label-default"><strong>{{ gettext('IP6') }}:</strong></span> {{ macros_site.render_event_search_widget_hostaddr(subitem['IP6'], separate_dropdown = True, item_limit = search_widget_item_limit) }} + <span class="label label-default"><strong>{{ gettext('IP6') }}:</strong></span> {{ macros_site.render_widget_csag_address(subitem['IP6'], separate_dropdown = True, item_limit = search_widget_item_limit) }} </div> {%- endif %} {%- if 'Port' in subitem %} <div> - <span class="label label-default"><strong>{{ gettext('Port') }}:</strong></span> {{ macros_site.render_event_search_widget_hostport(subitem['Port'], separate_dropdown = True, item_limit = search_widget_item_limit) }} + <span class="label label-default"><strong>{{ gettext('Port') }}:</strong></span> {{ macros_site.render_widget_csag_port(subitem['Port'], separate_dropdown = True, item_limit = search_widget_item_limit) }} </div> {%- endif %} {%- if 'Proto' in subitem %} <div> - <span class="label label-default"><strong>{{ gettext('Proto') }}:</strong></span> {{ macros_site.render_event_search_widget_protocol(subitem['Proto'], separate_dropdown = True, item_limit = search_widget_item_limit) }} + <span class="label label-default"><strong>{{ gettext('Proto') }}:</strong></span> {{ macros_site.render_widget_csag_protocol(subitem['Proto'], separate_dropdown = True, item_limit = search_widget_item_limit) }} </div> {%- endif %} {%- if 'Type' in subitem %} <div> - <span class="label label-default"><strong>{{ gettext('Type') }}:</strong></span> {{ macros_site.render_event_search_widget_hosttype(subitem['Type'], separate_dropdown = True) }} + <span class="label label-default"><strong>{{ gettext('Type') }}:</strong></span> {{ macros_site.render_widget_csag_hosttype(subitem['Type'], separate_dropdown = True) }} </div> {%- endif %} </li> @@ -225,13 +225,13 @@ <li class="list-group-item{% if loop.first %} list-group-item-info{% endif %}"> {%- if not loop.first %}<small>{%- endif %} {%- if 'Name' in subitem %} - <span class="label label-default"><strong>{{ gettext('Name') }}:</strong></span> {% if loop.first %}{{ macros_site.render_event_search_widget_detector([subitem['Name']], separate_dropdown = True) }}{% else %}{{ subitem['Name'] }}{%- endif %} + <span class="label label-default"><strong>{{ gettext('Name') }}:</strong></span> {% if loop.first %}{{ macros_site.render_widget_csag_detector([subitem['Name']], separate_dropdown = True) }}{% else %}{{ subitem['Name'] }}{%- endif %} {%- endif %} {%- if 'SW' in subitem %} <span class="label label-default"><strong>{{ gettext('SW') }}:</strong></span> {{ subitem['SW'] | join(', ') }} {%- endif %} {%- if 'Type' in subitem %} - <span class="label label-default"><strong>{{ gettext('Type') }}:</strong></span> {{ macros_site.render_event_search_widget_detectortype(subitem['Type'], separate_dropdown = True) }} + <span class="label label-default"><strong>{{ gettext('Type') }}:</strong></span> {{ macros_site.render_widget_csag_detectortype(subitem['Type'], separate_dropdown = True) }} {%- endif %} {%- if not loop.first %}</small>{%- endif %} </li> diff --git a/lib/hawat/blueprints/geoip/__init__.py b/lib/hawat/blueprints/geoip/__init__.py index 5776fd68e59915518be306b135e77864d4eb4453..3a12d3677c8db10f58ab1599bb0b742d55f11e62 100644 --- a/lib/hawat/blueprints/geoip/__init__.py +++ b/lib/hawat/blueprints/geoip/__init__.py @@ -42,10 +42,12 @@ from flask_babel import lazy_gettext # Custom modules. # import mentat.services.geoip +from mentat.const import tr_ + import hawat.const import hawat.db import hawat.acl -from hawat.base import HTMLViewMixin, HawatRenderableView, HawatBlueprint +from hawat.base import HTMLViewMixin, HawatRenderableView, HawatBlueprint, URLParamsBuilder from hawat.blueprints.geoip.forms import GeoipSearchForm @@ -146,6 +148,14 @@ class GeoipBlueprint(HawatBlueprint): view = SearchView ) + # Register context actions provided by this module. + app.set_csag( + hawat.const.HAWAT_CSAG_ADDRESS, + tr_('Search for address <strong>%(name)s</strong> in internal IP geolocation database'), + SearchView, + URLParamsBuilder({'submit': tr_('Search')}).add_rule('search') + ) + #------------------------------------------------------------------------------- diff --git a/lib/hawat/blueprints/groups/__init__.py b/lib/hawat/blueprints/groups/__init__.py index 0984d63d2d0ef1eeaf21e0d623277d73746d3844..910b7c5b990dee70264394d2b6d836279e580776 100644 --- a/lib/hawat/blueprints/groups/__init__.py +++ b/lib/hawat/blueprints/groups/__init__.py @@ -44,13 +44,14 @@ from sqlalchemy import and_, or_ # from mentat.datatype.sqldb import GroupModel, SettingsReportingModel,\ FilterModel, NetworkModel, ItemChangeLogModel +from mentat.const import tr_ import hawat.acl import hawat.db import hawat.menu from hawat.base import HTMLViewMixin, SQLAlchemyViewMixin, HawatItemListView,\ HawatItemShowView, HawatItemCreateView, HawatItemUpdateView, HawatItemEnableView,\ - HawatItemDisableView, HawatItemDeleteView, HawatBlueprint + HawatItemDisableView, HawatItemDeleteView, HawatBlueprint, URLParamsBuilder from hawat.blueprints.groups.forms import CreateGroupForm, UpdateGroupForm,\ AdminUpdateGroupForm @@ -698,6 +699,14 @@ class GroupsBlueprint(HawatBlueprint): entry_builder = lambda x, y: hawat.menu.HawatEndpointMenuEntry(x, endpoint = 'groups.show', item = y, title = x, icon = 'module-groups') ) + # Register context actions provided by this module. + app.set_csag( + hawat.const.HAWAT_CSAG_ABUSE, + tr_('View details of abuse group <strong>%(name)s</strong>'), + ShowByNameView, + URLParamsBuilder().add_rule('item_id') + ) + #------------------------------------------------------------------------------- diff --git a/lib/hawat/blueprints/reports/__init__.py b/lib/hawat/blueprints/reports/__init__.py index 2edc15ee8e82c0ea3b5d887c4ec4b4127caf32e2..9a561d5551bd82cefabb1a4b7c5800a4baf89e69 100644 --- a/lib/hawat/blueprints/reports/__init__.py +++ b/lib/hawat/blueprints/reports/__init__.py @@ -38,11 +38,13 @@ from flask_babel import gettext, lazy_gettext import mentat.const import mentat.stats.idea from mentat.datatype.sqldb import EventReportModel, GroupModel, UserModel +from mentat.const import tr_ import hawat.menu import hawat.acl from hawat.base import HTMLViewMixin, SQLAlchemyViewMixin, HawatSearchView,\ - HawatItemShowView, HawatItemDeleteView, HawatFileIdView, HawatBlueprint + HawatItemShowView, HawatItemDeleteView, HawatFileIdView, HawatBlueprint,\ + URLParamsBuilder from hawat.blueprints.reports.forms import EventReportSearchForm, ReportingDashboardForm @@ -595,6 +597,21 @@ class ReportsBlueprint(HawatBlueprint): resptitle = True ) + # Register context actions provided by this module. + app.set_csag( + hawat.const.HAWAT_CSAG_ABUSE, + tr_('Search for abuse group <strong>%(name)s</strong> in report database'), + SearchView, + URLParamsBuilder({'submit': 'Search'}).add_rule('groups', True) + ) + + app.set_csag( + hawat.const.HAWAT_CSAG_ABUSE, + tr_('Search for abuse group <strong>%(name)s</strong> in reporting dashboards'), + DashboardView, + URLParamsBuilder({'submit': tr_('Search')}).add_rule('groups', True) + ) + #------------------------------------------------------------------------------- diff --git a/lib/hawat/blueprints/timeline/__init__.py b/lib/hawat/blueprints/timeline/__init__.py index 3b1724b3fdc83c69c76d9331784555e15a797927..9c0f1e6d4c0213a3743b3ee0fa37ada587f32965 100644 --- a/lib/hawat/blueprints/timeline/__init__.py +++ b/lib/hawat/blueprints/timeline/__init__.py @@ -176,12 +176,13 @@ from flask_babel import gettext, lazy_gettext # import mentat.stats.idea import mentat.services.eventstorage +from mentat.const import tr_ import hawat.const import hawat.events import hawat.acl from hawat.base import HTMLViewMixin, PsycopgViewMixin, AJAXViewMixin,\ - HawatSearchView, HawatBlueprint + HawatSearchView, HawatBlueprint, URLParamsBuilder from hawat.blueprints.timeline.forms import SimpleTimelineSearchForm @@ -339,6 +340,13 @@ class TimelineBlueprint(HawatBlueprint): resptitle = True ) + # Register context actions provided by this module. + app.set_csag( + hawat.const.HAWAT_CSAG_ADDRESS, + tr_('Search for source <strong>%(name)s</strong> on IDEA event timeline'), + SearchView, + URLParamsBuilder({'submit': tr_('Search')}).add_rule('source_addrs', True) + ) #------------------------------------------------------------------------------- diff --git a/lib/hawat/blueprints/whois/__init__.py b/lib/hawat/blueprints/whois/__init__.py index 2b42f4e2a3182d8881cbe1c1faffa382b8350549..b2de0c714e272a474ef2caebba381e0f00a5ce72 100644 --- a/lib/hawat/blueprints/whois/__init__.py +++ b/lib/hawat/blueprints/whois/__init__.py @@ -49,9 +49,11 @@ from flask_babel import lazy_gettext # Custom modules. # import mentat.services.whois +from mentat.const import tr_ + import hawat.db import hawat.acl -from hawat.base import HTMLViewMixin, HawatRenderableView, HawatBlueprint +from hawat.base import HTMLViewMixin, HawatRenderableView, HawatBlueprint, URLParamsBuilder from hawat.blueprints.whois.forms import WhoisSearchForm @@ -152,6 +154,14 @@ class WhoisBlueprint(HawatBlueprint): view = SearchView ) + # Register context actions provided by this module. + app.set_csag( + hawat.const.HAWAT_CSAG_ADDRESS, + tr_('Search for address <strong>%(name)s</strong> in internal whois database'), + SearchView, + URLParamsBuilder({'submit': tr_('Search')}).add_rule('search') + ) + #------------------------------------------------------------------------------- diff --git a/lib/hawat/const.py b/lib/hawat/const.py index f0776189f87b185264c7b2a9697e296946fbec02..a9c14c708fab4425299b81fbd04fc044b252b173 100644 --- a/lib/hawat/const.py +++ b/lib/hawat/const.py @@ -104,6 +104,20 @@ RESOURCE_PRINCIPAL = 'principal' RESOURCE_BABEL = 'babel' """Name for the ``flask_babel.Babel`` object within the application resources.""" +# +# List of all existing Hawat context action search groups. +# +HAWAT_CSAG_ABUSE = 'abuse' +HAWAT_CSAG_ADDRESS = 'address' +HAWAT_CSAG_CATEGORY = 'category' +HAWAT_CSAG_CLASS = 'class' +HAWAT_CSAG_DETECTOR = 'detector' +HAWAT_CSAG_DETTYPE = 'detector_type' +HAWAT_CSAG_HOSTTYPE = 'host_type' +HAWAT_CSAG_PORT = 'port' +HAWAT_CSAG_PROTOCOL = 'protocol' +HAWAT_CSAG_SEVERITY = 'severity' + FA_ICONS = { #