mirror of https://github.com/CIRCL/lookyloo
new: Allow user accessible MISP servers
Related #1021dependabot/pip/publicsuffixlist-1.0.2.20241224
parent
e189d6f679
commit
416eba5beb
|
@ -45,7 +45,7 @@ class BackgroundBuildCaptures(AbstractManager):
|
||||||
# could be an empty file.
|
# could be an empty file.
|
||||||
settings = json.loads(ar)
|
settings = json.loads(ar)
|
||||||
try:
|
try:
|
||||||
self.lookyloo.send_mail(capture_uuid, email=settings.get('email', ''),
|
self.lookyloo.send_mail(capture_uuid, as_admin=True, email=settings.get('email', ''),
|
||||||
comment=settings.get('comment'))
|
comment=settings.get('comment'))
|
||||||
(path / 'auto_report').unlink()
|
(path / 'auto_report').unlink()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
|
@ -882,7 +882,7 @@ class Lookyloo():
|
||||||
|
|
||||||
return f"Malicious capture according to {len(modules)} module(s): {', '.join(modules)}"
|
return f"Malicious capture according to {len(modules)} module(s): {', '.join(modules)}"
|
||||||
|
|
||||||
def send_mail(self, capture_uuid: str, /, email: str | None=None, comment: str | None=None) -> bool | dict[str, Any]:
|
def send_mail(self, capture_uuid: str, /, as_admin: bool, email: str | None=None, comment: str | None=None) -> bool | dict[str, Any]:
|
||||||
'''Send an email notification regarding a specific capture'''
|
'''Send an email notification regarding a specific capture'''
|
||||||
if not get_config('generic', 'enable_mail_notification'):
|
if not get_config('generic', 'enable_mail_notification'):
|
||||||
return {"error": "Unable to send mail: mail notification disabled"}
|
return {"error": "Unable to send mail: mail notification disabled"}
|
||||||
|
@ -916,7 +916,9 @@ class Lookyloo():
|
||||||
self.logger.info('There are no MISP instances available for a lookup.')
|
self.logger.info('There are no MISP instances available for a lookup.')
|
||||||
else:
|
else:
|
||||||
for instance_name in self.misps.keys():
|
for instance_name in self.misps.keys():
|
||||||
if occurrences := self.get_misp_occurrences(capture_uuid, instance_name=instance_name):
|
if occurrences := self.get_misp_occurrences(capture_uuid,
|
||||||
|
as_admin=as_admin,
|
||||||
|
instance_name=instance_name):
|
||||||
elements, misp_url = occurrences
|
elements, misp_url = occurrences
|
||||||
for event_id, attributes in elements.items():
|
for event_id, attributes in elements.items():
|
||||||
for value, ts in attributes:
|
for value, ts in attributes:
|
||||||
|
@ -1225,7 +1227,8 @@ class Lookyloo():
|
||||||
|
|
||||||
return [event]
|
return [event]
|
||||||
|
|
||||||
def get_misp_occurrences(self, capture_uuid: str, /, *, instance_name: str | None=None) -> tuple[dict[int, set[tuple[str, datetime]]], str] | None:
|
def get_misp_occurrences(self, capture_uuid: str, /, as_admin: bool,
|
||||||
|
*, instance_name: str | None=None) -> tuple[dict[int, set[tuple[str, datetime]]], str] | None:
|
||||||
if instance_name is None:
|
if instance_name is None:
|
||||||
misp = self.misps.default_misp
|
misp = self.misps.default_misp
|
||||||
elif self.misps.get(instance_name) is not None:
|
elif self.misps.get(instance_name) is not None:
|
||||||
|
@ -1244,7 +1247,7 @@ class Lookyloo():
|
||||||
nodes_to_lookup = ct.root_hartree.rendered_node.get_ancestors() + [ct.root_hartree.rendered_node]
|
nodes_to_lookup = ct.root_hartree.rendered_node.get_ancestors() + [ct.root_hartree.rendered_node]
|
||||||
to_return: dict[int, set[tuple[str, datetime]]] = defaultdict(set)
|
to_return: dict[int, set[tuple[str, datetime]]] = defaultdict(set)
|
||||||
for node in nodes_to_lookup:
|
for node in nodes_to_lookup:
|
||||||
hits = misp.lookup(node, ct.root_hartree.get_host_node_by_uuid(node.hostnode_uuid))
|
hits = misp.lookup(node, ct.root_hartree.get_host_node_by_uuid(node.hostnode_uuid), as_admin=as_admin)
|
||||||
for event_id, values in hits.items():
|
for event_id, values in hits.items():
|
||||||
if not isinstance(event_id, int) or not isinstance(values, set):
|
if not isinstance(event_id, int) or not isinstance(values, set):
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -57,6 +57,20 @@ class MISPs(Mapping, AbstractModule): # type: ignore[type-arg]
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@property
|
||||||
|
def has_public_misp(self) -> bool:
|
||||||
|
return not all(misp.admin_only for misp in self.__misps.values())
|
||||||
|
|
||||||
|
def has_lookup(self, as_admin: bool) -> bool:
|
||||||
|
if as_admin:
|
||||||
|
return any(misp.enable_lookup for misp in self.__misps.values())
|
||||||
|
return any(misp.enable_lookup and not misp.admin_only for misp in self.__misps.values())
|
||||||
|
|
||||||
|
def has_push(self, as_admin: bool) -> bool:
|
||||||
|
if as_admin:
|
||||||
|
return any(misp.enable_push for misp in self.__misps.values())
|
||||||
|
return any(misp.enable_push and not misp.admin_only for misp in self.__misps.values())
|
||||||
|
|
||||||
def __getitem__(self, name: str) -> MISP:
|
def __getitem__(self, name: str) -> MISP:
|
||||||
return self.__misps[name]
|
return self.__misps[name]
|
||||||
|
|
||||||
|
@ -200,7 +214,7 @@ class MISP(AbstractModule):
|
||||||
existing_uuid_to_extend = None
|
existing_uuid_to_extend = None
|
||||||
for event in events:
|
for event in events:
|
||||||
if not allow_duplicates:
|
if not allow_duplicates:
|
||||||
existing_event = self.get_existing_event(event.attributes[0].value)
|
existing_event = self.__get_existing_event(event.attributes[0].value)
|
||||||
if existing_event:
|
if existing_event:
|
||||||
existing_uuid_to_extend = existing_event.uuid
|
existing_uuid_to_extend = existing_event.uuid
|
||||||
continue
|
continue
|
||||||
|
@ -215,10 +229,18 @@ class MISP(AbstractModule):
|
||||||
events_to_push.append(event)
|
events_to_push.append(event)
|
||||||
return events_to_push
|
return events_to_push
|
||||||
|
|
||||||
def push(self, to_push: list[MISPEvent] | MISPEvent, allow_duplicates: bool=False, auto_publish: bool | None=None) -> list[MISPEvent] | dict[Any, Any]:
|
def push(self, to_push: list[MISPEvent] | MISPEvent, as_admin: bool, *, allow_duplicates: bool=False,
|
||||||
|
auto_publish: bool | None=None) -> list[MISPEvent] | dict[Any, Any]:
|
||||||
|
if not self.available:
|
||||||
|
return {'error': 'Module not available.'}
|
||||||
|
if not self.enable_push:
|
||||||
|
return {'error': 'Push not enabled.'}
|
||||||
|
if self.admin_only and not as_admin:
|
||||||
|
return {'error': 'Admin only module, cannot push.'}
|
||||||
|
|
||||||
if auto_publish is None:
|
if auto_publish is None:
|
||||||
auto_publish = self.auto_publish
|
auto_publish = self.auto_publish
|
||||||
if self.available and self.enable_push:
|
|
||||||
events = self._prepare_push(to_push, allow_duplicates, auto_publish)
|
events = self._prepare_push(to_push, allow_duplicates, auto_publish)
|
||||||
if not events:
|
if not events:
|
||||||
return {'error': 'All the events are already on the MISP instance.'}
|
return {'error': 'All the events are already on the MISP instance.'}
|
||||||
|
@ -245,8 +267,6 @@ class MISP(AbstractModule):
|
||||||
else:
|
else:
|
||||||
return {'error': new_event}
|
return {'error': new_event}
|
||||||
return to_return
|
return to_return
|
||||||
else:
|
|
||||||
return {'error': 'Module not available or push not enabled.'}
|
|
||||||
|
|
||||||
def get_existing_event_url(self, permaurl: str) -> str | None:
|
def get_existing_event_url(self, permaurl: str) -> str | None:
|
||||||
attributes = self.client.search('attributes', value=permaurl, limit=1, page=1, pythonify=True)
|
attributes = self.client.search('attributes', value=permaurl, limit=1, page=1, pythonify=True)
|
||||||
|
@ -255,7 +275,7 @@ class MISP(AbstractModule):
|
||||||
url = f'{self.client.root_url}/events/{attributes[0].event_id}'
|
url = f'{self.client.root_url}/events/{attributes[0].event_id}'
|
||||||
return url
|
return url
|
||||||
|
|
||||||
def get_existing_event(self, permaurl: str) -> MISPEvent | None:
|
def __get_existing_event(self, permaurl: str) -> MISPEvent | None:
|
||||||
attributes = self.client.search('attributes', value=permaurl, limit=1, page=1, pythonify=True)
|
attributes = self.client.search('attributes', value=permaurl, limit=1, page=1, pythonify=True)
|
||||||
if not attributes or not isinstance(attributes, list) or not isinstance(attributes[0], MISPAttribute):
|
if not attributes or not isinstance(attributes, list) or not isinstance(attributes[0], MISPAttribute):
|
||||||
return None
|
return None
|
||||||
|
@ -264,8 +284,14 @@ class MISP(AbstractModule):
|
||||||
return event
|
return event
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def lookup(self, node: URLNode, hostnode: HostNode) -> dict[int | str, str | set[tuple[str, datetime]]]:
|
def lookup(self, node: URLNode, hostnode: HostNode, as_admin: bool) -> dict[int | str, str | set[tuple[str, datetime]]]:
|
||||||
if self.available and self.enable_lookup:
|
if not self.available:
|
||||||
|
return {'error': 'Module not available.'}
|
||||||
|
if not self.enable_lookup:
|
||||||
|
return {'error': 'Lookup not enabled.'}
|
||||||
|
if self.admin_only and not as_admin:
|
||||||
|
return {'error': 'Admin only module, cannot lookup.'}
|
||||||
|
|
||||||
tld = self.psl.publicsuffix(hostnode.name)
|
tld = self.psl.publicsuffix(hostnode.name)
|
||||||
domain = re.sub(f'.{tld}$', '', hostnode.name).split('.')[-1]
|
domain = re.sub(f'.{tld}$', '', hostnode.name).split('.')[-1]
|
||||||
to_lookup = [node.name, hostnode.name, f'{domain}.{tld}']
|
to_lookup = [node.name, hostnode.name, f'{domain}.{tld}']
|
||||||
|
@ -295,5 +321,3 @@ class MISP(AbstractModule):
|
||||||
# The request returned an error
|
# The request returned an error
|
||||||
return attributes # type: ignore[return-value]
|
return attributes # type: ignore[return-value]
|
||||||
return {'info': 'No hits.'}
|
return {'info': 'No hits.'}
|
||||||
else:
|
|
||||||
return {'error': 'Module not available or lookup not enabled.'}
|
|
||||||
|
|
|
@ -725,27 +725,47 @@ def stats(tree_uuid: str) -> str:
|
||||||
|
|
||||||
|
|
||||||
@app.route('/tree/<string:tree_uuid>/misp_lookup', methods=['GET'])
|
@app.route('/tree/<string:tree_uuid>/misp_lookup', methods=['GET'])
|
||||||
@flask_login.login_required # type: ignore[misc]
|
|
||||||
def web_misp_lookup_view(tree_uuid: str) -> str | WerkzeugResponse | Response:
|
def web_misp_lookup_view(tree_uuid: str) -> str | WerkzeugResponse | Response:
|
||||||
if not lookyloo.misps.available:
|
if not lookyloo.misps.available:
|
||||||
flash('There are no MISP instances available.', 'error')
|
flash('There are no MISP instances available.', 'error')
|
||||||
return redirect(url_for('tree', tree_uuid=tree_uuid))
|
return redirect(url_for('tree', tree_uuid=tree_uuid))
|
||||||
|
as_admin = flask_login.current_user.is_authenticated
|
||||||
|
if not as_admin and not lookyloo.misps.has_public_misp:
|
||||||
|
flash('You need to be authenticated to search on MISP.', 'error')
|
||||||
|
return redirect(url_for('tree', tree_uuid=tree_uuid))
|
||||||
|
|
||||||
|
if not as_admin and lookyloo.misps.default_misp.admin_only:
|
||||||
|
current_misp = None
|
||||||
|
else:
|
||||||
|
current_misp = lookyloo.misps.default_instance
|
||||||
|
|
||||||
misps_occurrences = {}
|
misps_occurrences = {}
|
||||||
for instance_name in lookyloo.misps.keys():
|
for instance_name, instance in lookyloo.misps.items():
|
||||||
if occurrences := lookyloo.get_misp_occurrences(tree_uuid, instance_name=instance_name):
|
if instance.admin_only and not as_admin:
|
||||||
|
continue
|
||||||
|
if not current_misp:
|
||||||
|
# Pick the first one we can
|
||||||
|
current_misp = instance_name
|
||||||
|
if occurrences := lookyloo.get_misp_occurrences(tree_uuid,
|
||||||
|
as_admin=as_admin,
|
||||||
|
instance_name=instance_name):
|
||||||
misps_occurrences[instance_name] = occurrences
|
misps_occurrences[instance_name] = occurrences
|
||||||
return render_template('misp_lookup.html', uuid=tree_uuid,
|
return render_template('misp_lookup.html', uuid=tree_uuid,
|
||||||
current_misp=lookyloo.misps.default_instance,
|
current_misp=current_misp,
|
||||||
misps_occurrences=misps_occurrences)
|
misps_occurrences=misps_occurrences)
|
||||||
|
|
||||||
|
|
||||||
@app.route('/tree/<string:tree_uuid>/misp_push', methods=['GET', 'POST'])
|
@app.route('/tree/<string:tree_uuid>/misp_push', methods=['GET', 'POST'])
|
||||||
@flask_login.login_required # type: ignore[misc]
|
def web_misp_push_view(tree_uuid: str) -> str | WerkzeugResponse | Response:
|
||||||
def web_misp_push_view(tree_uuid: str) -> str | WerkzeugResponse | Response | None:
|
|
||||||
if not lookyloo.misps.available:
|
if not lookyloo.misps.available:
|
||||||
flash('There are no MISP instances available.', 'error')
|
flash('There are no MISP instances available.', 'error')
|
||||||
return redirect(url_for('tree', tree_uuid=tree_uuid))
|
return redirect(url_for('tree', tree_uuid=tree_uuid))
|
||||||
|
|
||||||
|
as_admin = flask_login.current_user.is_authenticated
|
||||||
|
if not as_admin and not lookyloo.misps.has_public_misp:
|
||||||
|
flash('You need to be authenticated to push to MISP.', 'error')
|
||||||
|
return redirect(url_for('tree', tree_uuid=tree_uuid))
|
||||||
|
|
||||||
event = lookyloo.misp_export(tree_uuid)
|
event = lookyloo.misp_export(tree_uuid)
|
||||||
if isinstance(event, dict):
|
if isinstance(event, dict):
|
||||||
flash(f'Unable to generate the MISP export: {event}', 'error')
|
flash(f'Unable to generate the MISP export: {event}', 'error')
|
||||||
|
@ -754,7 +774,18 @@ def web_misp_push_view(tree_uuid: str) -> str | WerkzeugResponse | Response | No
|
||||||
if request.method == 'GET':
|
if request.method == 'GET':
|
||||||
# Initialize settings that will be displayed on the template
|
# Initialize settings that will be displayed on the template
|
||||||
misp_instances_settings = {}
|
misp_instances_settings = {}
|
||||||
|
if not as_admin and lookyloo.misps.default_misp.admin_only:
|
||||||
|
current_misp = None
|
||||||
|
else:
|
||||||
|
current_misp = lookyloo.misps.default_instance
|
||||||
for name, instance in lookyloo.misps.items():
|
for name, instance in lookyloo.misps.items():
|
||||||
|
if instance.admin_only and not as_admin:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not current_misp:
|
||||||
|
# Pick the first one we can
|
||||||
|
current_misp = name
|
||||||
|
|
||||||
# the 1st attribute in the event is the link to lookyloo
|
# the 1st attribute in the event is the link to lookyloo
|
||||||
misp_instances_settings[name] = {
|
misp_instances_settings[name] = {
|
||||||
'default_tags': instance.default_tags,
|
'default_tags': instance.default_tags,
|
||||||
|
@ -766,13 +797,13 @@ def web_misp_push_view(tree_uuid: str) -> str | WerkzeugResponse | Response | No
|
||||||
|
|
||||||
cache = lookyloo.capture_cache(tree_uuid)
|
cache = lookyloo.capture_cache(tree_uuid)
|
||||||
return render_template('misp_push_view.html',
|
return render_template('misp_push_view.html',
|
||||||
current_misp=lookyloo.misps.default_instance,
|
current_misp=current_misp,
|
||||||
tree_uuid=tree_uuid,
|
tree_uuid=tree_uuid,
|
||||||
event=event[0],
|
event=event[0],
|
||||||
misp_instances_settings=misp_instances_settings,
|
misp_instances_settings=misp_instances_settings,
|
||||||
has_parent=True if cache and cache.parent else False)
|
has_parent=True if cache and cache.parent else False)
|
||||||
|
|
||||||
elif request.method == 'POST':
|
else:
|
||||||
# event is a MISPEvent at this point
|
# event is a MISPEvent at this point
|
||||||
misp_instance_name = request.form.get('misp_instance_name')
|
misp_instance_name = request.form.get('misp_instance_name')
|
||||||
if not misp_instance_name or misp_instance_name not in lookyloo.misps:
|
if not misp_instance_name or misp_instance_name not in lookyloo.misps:
|
||||||
|
@ -808,8 +839,10 @@ def web_misp_push_view(tree_uuid: str) -> str | WerkzeugResponse | Response | No
|
||||||
events[-1].info = request.form.get('event_info')
|
events[-1].info = request.form.get('event_info')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
new_events = misp.push(events, True if request.form.get('force_push') else False,
|
new_events = misp.push(events, as_admin=as_admin,
|
||||||
True if request.form.get('auto_publish') else False)
|
allow_duplicates=True if request.form.get('force_push') else False,
|
||||||
|
auto_publish=True if request.form.get('auto_publish') else False,
|
||||||
|
)
|
||||||
except MISPServerError:
|
except MISPServerError:
|
||||||
flash(f'MISP returned an error, the event(s) might still have been created on {misp.client.root_url}', 'error')
|
flash(f'MISP returned an error, the event(s) might still have been created on {misp.client.root_url}', 'error')
|
||||||
else:
|
else:
|
||||||
|
@ -819,7 +852,6 @@ def web_misp_push_view(tree_uuid: str) -> str | WerkzeugResponse | Response | No
|
||||||
for e in new_events:
|
for e in new_events:
|
||||||
flash(f'MISP event {e.id} created on {misp.client.root_url}', 'success')
|
flash(f'MISP event {e.id} created on {misp.client.root_url}', 'success')
|
||||||
return redirect(url_for('tree', tree_uuid=tree_uuid))
|
return redirect(url_for('tree', tree_uuid=tree_uuid))
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/tree/<string:tree_uuid>/modules', methods=['GET'])
|
@app.route('/tree/<string:tree_uuid>/modules', methods=['GET'])
|
||||||
|
@ -1130,7 +1162,7 @@ def send_mail(tree_uuid: str) -> WerkzeugResponse:
|
||||||
# skip clearly incorrect emails
|
# skip clearly incorrect emails
|
||||||
email = ''
|
email = ''
|
||||||
comment: str = request.form['comment'] if request.form.get('comment') else ''
|
comment: str = request.form['comment'] if request.form.get('comment') else ''
|
||||||
lookyloo.send_mail(tree_uuid, email, comment)
|
lookyloo.send_mail(tree_uuid, as_admin=flask_login.current_user.is_authenticated, email=email, comment=comment)
|
||||||
flash("Email notification sent", 'success')
|
flash("Email notification sent", 'success')
|
||||||
return redirect(url_for('tree', tree_uuid=tree_uuid))
|
return redirect(url_for('tree', tree_uuid=tree_uuid))
|
||||||
|
|
||||||
|
@ -1219,8 +1251,8 @@ def tree(tree_uuid: str, node_uuid: str | None=None) -> Response | str | Werkzeu
|
||||||
enable_context_by_users=enable_context_by_users,
|
enable_context_by_users=enable_context_by_users,
|
||||||
enable_categorization=enable_categorization,
|
enable_categorization=enable_categorization,
|
||||||
enable_bookmark=enable_bookmark,
|
enable_bookmark=enable_bookmark,
|
||||||
misp_push=lookyloo.misps.available and lookyloo.misps.default_misp.enable_push,
|
misp_push=lookyloo.misps.available and lookyloo.misps.has_push(flask_login.current_user.is_authenticated),
|
||||||
misp_lookup=lookyloo.misps.available and lookyloo.misps.default_misp.enable_lookup,
|
misp_lookup=lookyloo.misps.available and lookyloo.misps.has_lookup(flask_login.current_user.is_authenticated),
|
||||||
blur_screenshot=blur_screenshot, urlnode_uuid=hostnode_to_highlight,
|
blur_screenshot=blur_screenshot, urlnode_uuid=hostnode_to_highlight,
|
||||||
auto_trigger_modules=auto_trigger_modules,
|
auto_trigger_modules=auto_trigger_modules,
|
||||||
confirm_message=confirm_message if confirm_message else 'Tick to confirm.',
|
confirm_message=confirm_message if confirm_message else 'Tick to confirm.',
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
</center>
|
</center>
|
||||||
|
|
||||||
<div id="allInstances">
|
<div id="allInstances">
|
||||||
|
{% if misps_occurrences %}
|
||||||
{% for name, occurrences in misps_occurrences.items() %}
|
{% for name, occurrences in misps_occurrences.items() %}
|
||||||
<div id="lookup_{{name.replace(' ', '_')}}" {%if name != current_misp%}style="display:none"{%endif%}>
|
<div id="lookup_{{name.replace(' ', '_')}}" {%if name != current_misp%}style="display:none"{%endif%}>
|
||||||
{% set hits, root_url = occurrences %}
|
{% set hits, root_url = occurrences %}
|
||||||
|
@ -36,4 +37,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
{%else%}
|
||||||
|
No hits in any of the instances available.
|
||||||
|
{%endif%}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
{%endif%}
|
{%endif%}
|
||||||
|
|
||||||
<div id="allInstances">
|
<div id="allInstances">
|
||||||
|
{%if misp_instances_settings %}
|
||||||
{%for name, misp_settings in misp_instances_settings.items() %}
|
{%for name, misp_settings in misp_instances_settings.items() %}
|
||||||
<div id="push_{{name.replace(' ', '_')}}" {%if name != current_misp%}style="display:none"{%endif%}>
|
<div id="push_{{name.replace(' ', '_')}}" {%if name != current_misp%}style="display:none"{%endif%}>
|
||||||
<form role="form" action="{{ url_for('web_misp_push_view', tree_uuid=tree_uuid) }}"
|
<form role="form" action="{{ url_for('web_misp_push_view', tree_uuid=tree_uuid) }}"
|
||||||
|
@ -60,4 +61,7 @@
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
{%endfor%}
|
{%endfor%}
|
||||||
|
{%else%}
|
||||||
|
None of the instances are available, please login.
|
||||||
|
{%endif%}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -211,6 +211,10 @@
|
||||||
<a href="{{ url_for('trigger_indexing', tree_uuid=tree_uuid) }}" role="button" class="btn btn-warning"
|
<a href="{{ url_for('trigger_indexing', tree_uuid=tree_uuid) }}" role="button" class="btn btn-warning"
|
||||||
title="The capture isn't (fully) indexed, index now.">Index capture</a>
|
title="The capture isn't (fully) indexed, index now.">Index capture</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if misp_lookup%}
|
||||||
|
<a href="#mispLookupModal" data-remote="{{ url_for('web_misp_lookup_view', tree_uuid=tree_uuid) }}"
|
||||||
|
data-bs-toggle="modal" data-bs-target="#mispLookupModal" role="button">Search events on MISP</a>
|
||||||
|
{% endif %}
|
||||||
<a href="#modulesModal" data-remote="{{ url_for('trigger_modules', tree_uuid=tree_uuid, force=False) }}"
|
<a href="#modulesModal" data-remote="{{ url_for('trigger_modules', tree_uuid=tree_uuid, force=False) }}"
|
||||||
data-bs-toggle="modal" data-bs-target="#modulesModal" role="button"
|
data-bs-toggle="modal" data-bs-target="#modulesModal" role="button"
|
||||||
title="Lookups from supported 3rd party services">Third Party Reports</a>
|
title="Lookups from supported 3rd party services">Third Party Reports</a>
|
||||||
|
@ -261,6 +265,10 @@
|
||||||
|
|
||||||
<a href="#downloadModal" data-bs-toggle="modal" data-bs-target="#downloadModal" role="button"
|
<a href="#downloadModal" data-bs-toggle="modal" data-bs-target="#downloadModal" role="button"
|
||||||
title="Download specific elements of the capture">Download elements</a>
|
title="Download specific elements of the capture">Download elements</a>
|
||||||
|
{% if misp_push%}
|
||||||
|
<a href="#mispPushModal" data-remote="{{ url_for('web_misp_push_view', tree_uuid=tree_uuid) }}"
|
||||||
|
data-bs-toggle="modal" data-bs-target="#mispPushModal" role="button">Prepare push to MISP</a>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -271,14 +279,6 @@
|
||||||
<a href="{{ url_for('rebuild_tree', tree_uuid=tree_uuid) }}" role="button">Rebuild capture</a>
|
<a href="{{ url_for('rebuild_tree', tree_uuid=tree_uuid) }}" role="button">Rebuild capture</a>
|
||||||
<a href="{{ url_for('hide_capture', tree_uuid=tree_uuid) }}" role="button">Hide capture</a>
|
<a href="{{ url_for('hide_capture', tree_uuid=tree_uuid) }}" role="button">Hide capture</a>
|
||||||
<a href="{{ url_for('remove_capture', tree_uuid=tree_uuid) }}" role="button" id="removeCapture">Remove capture</a>
|
<a href="{{ url_for('remove_capture', tree_uuid=tree_uuid) }}" role="button" id="removeCapture">Remove capture</a>
|
||||||
{% if misp_push%}
|
|
||||||
<a href="#mispPushModal" data-remote="{{ url_for('web_misp_push_view', tree_uuid=tree_uuid) }}"
|
|
||||||
data-bs-toggle="modal" data-bs-target="#mispPushModal" role="button">Prepare push to MISP</a>
|
|
||||||
{% endif %}
|
|
||||||
{% if misp_lookup%}
|
|
||||||
<a href="#mispLookupModal" data-remote="{{ url_for('web_misp_lookup_view', tree_uuid=tree_uuid) }}"
|
|
||||||
data-bs-toggle="modal" data-bs-target="#mispLookupModal" role="button">Search events on MISP</a>
|
|
||||||
{% endif %}
|
|
||||||
<a href="{{ url_for('logout') }}" role="button" style="color: red">Logout</a>
|
<a href="{{ url_for('logout') }}" role="button" style="color: red">Logout</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in New Issue