#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# -------------------------------------------------------------------------------
# This file is part of Mentat system (https://mentat.cesnet.cz/).
#
# Copyright (C) since 2011 CESNET, z.s.p.o (http://www.ces.net/)
# Use of this source is governed by the MIT license, see LICENSE file.
# -------------------------------------------------------------------------------
"""
This pluggable module provides access to `NERD <https://nerd.cesnet.cz/>`__
service operated by `CESNET, a.l.e. <https://www.cesnet.cz/>`__. It is implemented
upon custom :py:mod:`mentat.services.nerd` module.
Provided endpoints
------------------
``/nerd/search``
Endpoint providing search form for querying NERD service and formatting result
as HTML page.
* *Authentication:* login required
* *Methods:* ``GET``
``/api/nerd/search``
Endpoint providing API search form for querying NERD service and formatting
result as JSON document.
* *Authentication:* login required
* *Authorization:* any role
* *Methods:* ``GET``, ``POST``
``/snippet/nerd/search``
Endpoint providing API search form for querying NERD service and formatting
result as JSON document containing HTML snippets.
* *Authentication:* login required
* *Authorization:* any role
* *Methods:* ``GET``, ``POST``
"""
__author__ = "Jan Mach <jan.mach@cesnet.cz>"
__credits__ = "Pavel Kácha <pavel.kacha@cesnet.cz>, Andrea Kropáčová <andrea.kropacova@cesnet.cz>"
import flask
from flask_babel import lazy_gettext
import mentat.services.nerd
from mentat.const import tr_
import hawat.db
import hawat.const
import hawat.acl
from hawat.base import HawatBlueprint
from hawat.view import RenderableView
from hawat.view.mixin import HTMLMixin, AJAXMixin, SnippetMixin
from hawat.utils import URLParamsBuilder
from hawat.blueprints.nerd.forms import NerdSearchForm
BLUEPRINT_NAME = 'nerd'
"""Name of the blueprint as module global constant."""
[docs]class AbstractSearchView(RenderableView): # pylint: disable=locally-disabled,abstract-method
"""
Application view providing base search capabilities for NERD service.
The querying is implemented using :py:mod:`mentat.services.nerd` module.
"""
authentication = True
[docs] @classmethod
def get_view_title(cls, **kwargs):
return lazy_gettext('Search NERD')
[docs] def dispatch_request(self):
"""
Mandatory interface required by the :py:func:`flask.views.View.dispatch_request`.
Will be called by the *Flask* framework to service the request.
"""
form = NerdSearchForm(flask.request.args, meta={'csrf': False})
if hawat.const.FORM_ACTION_SUBMIT in flask.request.args:
if form.validate():
form_data = form.data
nerd_service = mentat.services.nerd.service()
self.response_context.update(
search_item=form.search.data,
search_url=nerd_service.get_url_lookup_ip(form.search.data),
form_data=form_data
)
try:
self.response_context.update(
search_result=nerd_service.lookup_ip(form.search.data)
)
except Exception as exc:
self.flash(str(exc), level='error')
self.response_context.update(
search_form=form,
request_args=flask.request.args
)
return self.generate_response()
[docs]class SearchView(HTMLMixin, AbstractSearchView): # pylint: disable=locally-disabled,too-many-ancestors
"""
View responsible for querying external NERD service and presenting the results
in the form of HTML page.
"""
methods = ['GET']
[docs] @classmethod
def get_view_name(cls):
return 'search'
[docs]class APISearchView(AJAXMixin, AbstractSearchView): # pylint: disable=locally-disabled,too-many-ancestors
"""
View responsible for querying external NERD service and presenting the results
in the form of JSON document.
"""
methods = ['GET', 'POST']
[docs] @classmethod
def get_view_name(cls):
return 'apisearch'
[docs]class SnippetSearchView(SnippetMixin, AbstractSearchView): # pylint: disable=locally-disabled,too-many-ancestors
"""
View responsible for querying DNS service and presenting the results in the
form of JSON document containing ready to use HTML page snippets.
"""
methods = ['GET', 'POST']
renders = ['label', 'full']
snippets = [
{
'name': 'reputation',
'condition': lambda x: x.get('search_result', False)
}
]
[docs] @classmethod
def get_view_name(cls):
"""*Implementation* of :py:func:`hawat.view.BaseView.get_view_name`."""
return 'sptsearch'
# -------------------------------------------------------------------------------
[docs]class NerdBlueprint(HawatBlueprint):
"""Pluggable module - NERD service (*nerd*)."""
[docs] @classmethod
def get_module_title(cls):
return lazy_gettext('NERD service')
[docs] def register_app(self, app):
mentat.services.nerd.init(app.mconfig)
app.menu_main.add_entry(
'view',
'more.{}'.format(BLUEPRINT_NAME),
position=30,
view=SearchView
)
# Register context actions provided by this module.
app.set_csag(
hawat.const.CSAG_ADDRESS,
tr_('Search for address <strong>%(name)s</strong> locally in NERD service'),
SearchView,
URLParamsBuilder({'submit': tr_('Search')}).add_rule('search')
)
app.set_csag_url(
hawat.const.CSAG_ADDRESS,
tr_('Search for address <strong>%(name)s</strong> externally in NERD service'),
SearchView.get_view_icon(),
mentat.services.nerd.service().get_url_lookup_ip
)
# Register object additional data services provided by this module.
app.set_oads(
hawat.const.AODS_IP4,
SnippetSearchView,
URLParamsBuilder({'submit': tr_('Search')}).add_rule('search').add_kwrule('render', False, True)
)
# -------------------------------------------------------------------------------
[docs]def get_blueprint():
"""
Mandatory interface for :py:mod:`hawat.Hawat` and factory function. This function
must return a valid instance of :py:class:`hawat.app.HawatBlueprint` or
:py:class:`flask.Blueprint`.
"""
hbp = NerdBlueprint(
BLUEPRINT_NAME,
__name__,
template_folder='templates'
)
hbp.register_view_class(SearchView, '/{}/search'.format(BLUEPRINT_NAME))
hbp.register_view_class(APISearchView, '/api/{}/search'.format(BLUEPRINT_NAME))
hbp.register_view_class(SnippetSearchView, '/snippet/{}/search'.format(BLUEPRINT_NAME))
return hbp