def _set_agents_summary(self): results = env.dataprovider.query(["max(heartbeat.create_time)", "heartbeat.analyzer(-1).analyzerid/group_by"]) if not results: return c = Criterion() for create_time, analyzerid in results: c |= Criterion("heartbeat.create_time", "==", create_time) & Criterion("heartbeat.analyzer(-1).analyzerid", "==", analyzerid) agents = { "up": utils.AttrObj(count=0, title=_("Online"), label="label-success", status=["online"]), "down": utils.AttrObj(count=0, title=_("Offline"), label="label-danger", status=["offline", "missing", "unknown"]) } heartbeat_error_margin = env.config.general.get_int("heartbeat_error_margin", 3) for heartbeat in env.dataprovider.get(c): heartbeat = heartbeat["heartbeat"] analyzer = heartbeat["analyzer"][-1] analyzer.status = utils.get_analyzer_status_from_latest_heartbeat(heartbeat, heartbeat_error_margin)[0] for key, values in agents.items(): if analyzer.status in values.status: values.count += 1 parameters = env.request.menu_parameters val = agents["down"] if agents["down"].count else agents["up"] data = resource.HTMLNode("a", localization.format_number(val.count), title=val.title, _class="label " + val.label, href=url_for("Agents.agents", status=val.status, **parameters)) return utils.AttrObj( name="agents", title=resource.HTMLNode("a", _("Agents"), href=url_for("Agents.agents", **parameters)), data=[data] )
def _format_nonstring(self, field, value): if isinstance(value, list): value = ", ".join(value) return resource.HTMLNode("span", resource.HTMLNode("span", value), _class="selectable", **{"data-field": field})
def _build_table(self, idmefd): rows = [] for key, value in sorted(idmefd.items()): colkey = resource.HTMLNode("td", key) colval = resource.HTMLNode( "td", ", ".join(value) if isinstance(value, list) else value) rows.append(resource.HTMLNode("tr", colkey, colval)) return resource.HTMLNode("table", *rows, _class="table table-condensed")
def _set_logs_summary(self): count = localization.format_number(env.dataprovider.query( ["count(1)"], env.request.menu.get_criteria(), type="log")[0][0], short=True) data = resource.HTMLNode("a", count, title=_("Log"), _class="label label-info", href=url_for("LogDataSearch.dashboard", **env.request.menu_parameters)) return utils.AttrObj(name="archive", title=resource.HTMLNode("span", _("Archive")), data=[data])
def __init__(self, color, progress, text): txtspan = resource.HTMLNode('span', text) pgdiv = resource.HTMLNode( 'div', txtspan, **{ 'class': "progress-bar progress-bar-%s progress-bar-striped" % color, 'aria-valuenow': progress, 'aria-valuemin': 0, 'aria-valuemax': 100, 'style': "width: %s%%" % progress }) resource.HTMLNode.__init__(self, 'div', pgdiv, _class='progress')
def _get_analyzers(self, reqstatus): # Do not take the control menu into account. # The expected behavior is yet to be determined. results = env.dataprovider.query(["max(heartbeat.create_time)", "heartbeat.analyzer(-1).analyzerid/group_by"]) if not results: return c = Criterion() for create_time, analyzerid in results: c |= Criterion("heartbeat.create_time", "==", create_time) & Criterion("heartbeat.analyzer(-1).analyzerid", "==", analyzerid) for heartbeat in env.dataprovider.get(c): heartbeat = heartbeat["heartbeat"] status, status_text = utils.get_analyzer_status_from_latest_heartbeat( heartbeat, self._heartbeat_error_margin ) if reqstatus and status not in reqstatus: continue delta = heartbeat.get("create_time") - utils.timeutil.now() analyzerid = heartbeat["analyzer(-1).analyzerid"] heartbeat_listing = url_for("HeartbeatDataSearch.forensic", criteria=Criterion("heartbeat.analyzer(-1).analyzerid", "==", analyzerid), _default=None) alert_listing = url_for("AlertDataSearch.forensic", criteria=Criterion("alert.analyzer.analyzerid", "==", analyzerid), _default=None) heartbeat_analyze = url_for(".analyze", analyzerid=analyzerid) analyzer = heartbeat["analyzer(-1)"] node_name = analyzer["node.name"] or _("Node name n/a") osversion = analyzer["osversion"] or _("OS version n/a") ostype = analyzer["ostype"] or _("OS type n/a") yield { "id": analyzerid, "label": "%s - %s %s" % (node_name, ostype, osversion), "location": analyzer["node.location"] or _("Node location n/a"), "node": node_name, "name": analyzer["name"], "model": analyzer["model"], "class": analyzer["class"], "version": analyzer["version"], "latest_heartbeat": localization.format_timedelta(delta, add_direction=True), "status": status, "status_text": status_text, "links": [ resource.HTMLNode("a", _("Alert listing"), href=alert_listing), resource.HTMLNode("a", _("Heartbeat listing"), href=heartbeat_listing), resource.HTMLNode("a", _("Heartbeat analysis"), href=heartbeat_analyze) ] }
def compute_charts_infos(chart_infos, tooltips=None): cinfos = [] for title, categories, charts in chart_infos: s = sc = resource.HTMLSource("%s") % _(title) if categories: sub_info = resource.HTMLSource(", ").join( resource.HTMLNode("abbr", _(c), title=_(tooltips[c]), **{'data-toggle': 'tooltip'}) for c in categories) sub_info_c = resource.HTMLSource(", ").join( resource.HTMLSource("%s") % _(c) for c in categories) s += resource.HTMLSource(" (%s)") % sub_info sc += resource.HTMLSource(" (%s)") % sub_info_c cinfos += [{ 'title': s, 'title_c': sc, 'category': 'text', 'width': 12, 'height': 1 }] + charts return cinfos
def listing(self): env.request.user.check("USER_MANAGEMENT") objects = self._getObjects(search=env.request.parameters.get("query")) reverse = env.request.parameters.get("sort_order") == "desc" objects = sorted(objects, key=operator.attrgetter("name"), reverse=reverse) page = int(env.request.parameters.get("page", 1)) nb_rows = int(env.request.parameters.get("rows", 10)) rows = [] for obj in objects[(page - 1) * nb_rows:page * nb_rows]: permissions = self._getPermissions(obj) row = { "id": obj.id, "cell": { "name": resource.HTMLNode("a", obj.name, href=url_for(self._link, name=obj.name), title=_(self._title) % obj.name) } } for perm in usergroup.ACTIVE_PERMISSIONS: row["cell"][perm] = perm in permissions rows.append(row) return GridAjaxResponse(rows, len(objects))
def listing(self): dataset = {} data = [] for fltr in self._db.get_filters(env.request.user): elem = { "id": fltr.id_, "name": resource.HTMLNode("a", fltr.name, href=url_for(".edit", name=fltr.name), title=_("Filter %s") % fltr.name), "category": fltr.category, "description": fltr.description } for typ in fltr.criteria: elem[typ] = True data.append(elem) dataset["data"] = data dataset["columns"] = self._get_types() return template.PrewikkaTemplate( __name__, "templates/filterlisting.mak").render(**dataset)
def _format_classification(self, finfo, root, obj): return resource.HTMLNode( "ul", self._format_value( root.get("alert.classification"), prelude.IDMEFClass("alert.classification.text"), label=False, tooltip=root.get("alert.assessment.impact.description")))
def __init__(self, phrase): self.value = self.get_clean_value(phrase) parsed_phrase = [ self.word_prepare(word) for word in self.split_phrase(phrase) ] self.html = resource.HTMLNode("span", *parsed_phrase, _class="selectable")
def _get_link(self, label, value, arg, path=None): d = {"data-path": path} if path else {} if callable(value): value = value(arg) else: value = value.replace("$value", utils.url.quote_plus(arg.encode("utf-8"))) return resource.HTMLNode("a", _(label.capitalize()), href=value, **d)
def ajax_groupby(self): limit = int(env.request.parameters["limit"]) page = int(env.request.parameters.get("page", 1)) search = self._prepare(page, limit) step = search.get_step() results = search.get_result() resrows = [] # We need to reorder results according to what is expected permutation = [ search.get_index(f) for f in ["_aggregation"] + search.groupby ] for i, result in enumerate(results): values = [result[permutation[idx]] for idx in range(len(result))] cells = {} for idx, group in enumerate(search.groupby): label = values[idx + 1] if isinstance(label, datetime.datetime): label = label.strftime(step.unit_format) elif isinstance(label, datetime.timedelta): label = format_timedelta(label) link = search.get_groupby_link([group], [values[idx + 1]], step, cview='.forensic') cells[group] = resource.HTMLNode("a", label, href=link) link = search.get_groupby_link(search.groupby, values[1:], step, cview='.forensic') cells["_aggregation"] = resource.HTMLNode("a", values[0], href=link) resrows.append({"id": text_type(i), "cell": cells}) total = (page if len(resrows) < limit else page + 1) * limit return utils.viewhelpers.GridAjaxResponse( resrows, total).add_html_content(mainmenu.HTMLMainMenu(update=True))
def get_forensic_actions(self): return [ resource.HTMLNode("button", _("CSV export"), formaction=url_for(".csv_download"), type="submit", form="datasearch_export_form", _class="btn btn-default needone", _sortkey="download", _icon="fa-file-excel-o") ]
def _format_object(self, root, child, iclass): out2 = [] key = text_type(iclass) child = child if isinstance(child, collections.Iterable) else [child] for j in filter(None, map(lambda x: self._format_generic(root, x), child)): out2.append( resource.HTMLNode("ul", *j, _class="object %s dp-%d" % (key, self._get_priority(iclass)))) if out2: if iclass.isList(): return resource.HTMLNode( "ul", *[resource.HTMLNode("li", o) for o in out2], _class="list %s dp-%d" % (key, self._get_priority(iclass))) else: return resource.HTMLNode( "", resource.HTMLNode("label", key, _class=key), out2[0])
class Formatter(object): highlighter = HighLighter ignore_fields = frozenset() _converters = { datetime.datetime: lambda f, r, o: resource.HTMLNode( "span", format_datetime(o), **{ "data-field": f.field, "data-value": o }) } def __init__(self, data_type): self._enrich_data_cb = [ elem[1] for elem in sorted( hookmanager.trigger( "HOOK_DATASEARCH_FORMATTER_ENRICH_CALLBACK")) ] self.type = data_type def _format_nonstring(self, field, value): if isinstance(value, list): value = ", ".join(value) return resource.HTMLNode("span", resource.HTMLNode("span", value), _class="selectable", **{"data-field": field}) def format_value(self, field, value): if not isinstance(value, text_type): return self._format_nonstring(field, value) hl = self.highlighter(value or "n/a") node, value = hl.html, hl.value node.attrs["data-field"] = field for i in self._enrich_data_cb: node = i(node, value, self.type) return node def format(self, finfo, root, obj): if finfo.type in self._converters: return self._converters[finfo.type](finfo, root, obj) if finfo.field in self.ignore_fields: return obj return self.format_value(finfo.field, obj)
def _set_alerts_summary(self): severities = ["info", "low", "medium", "high"] alerts = dict( env.dataprovider.query([ "alert.assessment.impact.severity/group_by", "count(alert.messageid)" ], env.request.menu.get_criteria())) labels = { "info": utils.AttrObj(title=_("Minimal severity"), label="label-info"), "low": utils.AttrObj(title=_("Low severity"), label="label-success"), "medium": utils.AttrObj(title=_("Medium severity"), label="label-warning"), "high": utils.AttrObj(title=_("High severity"), label="label-danger") } data = [] for i in reversed(severities): data.append( resource.HTMLNode( "a", localization.format_number(alerts.get(i, 0), short=True), title=labels[i].title, _class="label " + labels[i].label, href=url_for("AlertDataSearch.forensic", criteria=Criterion( "alert.assessment.impact.severity", "==", i)))) return utils.AttrObj(name="alerts", title=resource.HTMLNode( "a", _("Alerts"), href=url_for("AlertDataSearch.forensic")), data=data)
def _format_value(self, obj, iclass, default="", label=True, _class="", tooltip=None): key = text_type(iclass) if not obj: return default value = obj.get(key) if not value: return default if label: label = resource.HTMLNode("label", key, ":") else: label = "" field = ".".join([obj.path.split(".", 1)[-1], key]) kwargs = {} if tooltip: kwargs = { "title": tooltip, "data-toggle": "tooltip", "data-placement": "top", "data-container": "#main" } return resource.HTMLNode("li", label, self.format_value(field, value), _class="%s %s dp-%d" % (_class, key, self._get_priority(iclass)), **kwargs)
def _format_time(self, finfo, root, obj): href = None if root["%s.messageid" % self.type]: href = url_for("%ssummary.render" % self.type, messageid=root["%s.messageid" % self.type], _default=None, **env.request.menu.get_parameters()) return resource.HTMLNode("a", format_datetime(obj), href=href, title=_("See IDMEF details"), **{ "data-toggle": "tooltip", "data-container": "#main" })
def get_forensic_actions(self): ret = [] if env.request.user.has("IDMEF_ALTER"): ret = [ resource.HTMLNode( "button", _("Delete"), **{ "form": "datasearch_grid_form", "type": "submit", "formaction": url_for(".delete"), "formmethod": "POST", "class": "btn btn-danger needone", "data-confirm": _(self._delete_confirm), }) ] return datasearch.DataSearch.get_forensic_actions(self) + ret
def _add_original_log_link(self, alert, meaning, value): detect_time = alert.get("detect_time") if meaning != "Original Log" or not detect_time: return query = [] host = next(hookmanager.trigger("HOOK_LOG_EXTRACT_IDMEF_HOST", alert), None) if host: query.append('host:"%s"' % host) detect_time = utils.timeutil.get_timestamp_from_datetime(detect_time) return resource.HTMLNode("a", _("Context"), href=url_for("LogDataSearch.forensic", query=" ".join(query), query_mode="lucene", timeline_start=detect_time - 5, timeline_end=detect_time + 30, timeline_mode="custom"))
def _format_generic(self, root, obj): out = [] for iclass in sorted(self.get_childs(obj), key=self._get_priority): child = obj.get(text_type(iclass)) if child is None: continue if self._get_priority(iclass) != 0: continue vtype = iclass.getValueType() if vtype == prelude.IDMEFValue.TYPE_CLASS: o = self._format_object(root, child, iclass) ret = resource.HTMLNode("li", o) if o else None else: ret = self._format_value(obj, iclass) if ret: out.append(ret) return out
def word_prepare(cls, word): return resource.HTMLNode("span", word)
def ajax_listing(self): now = utils.timeutil.utcnow() sort_index = env.request.parameters.get("sort_index", "name") sort_order = env.request.parameters.get("sort_order", "asc") sort_func = { "name": lambda x: _(crontab.format(x.ext_type, x.name)).lower(), "user": lambda x: text_type(x.user) if x.user else _("SYSTEM"), "last": lambda x: x.base, "next": lambda x: x.next_schedule - now if x.enabled else datetime.timedelta.max, } sort_key = sort_func.get(sort_index, sort_func["name"]) rows = [] for i in sorted(crontab.list(), key=sort_key, reverse=(sort_order == "desc")): if not i.enabled: next = _("Disabled") else: next = i.next_schedule - now if next.total_seconds() < 0: next = _("Pending") else: next = localization.format_timedelta(next, granularity="minute") if i.runcnt > 0: last = localization.format_timedelta(i.base - now, add_direction=True) else: last = _("n/a") if i.error: last = resource.HTMLNode("a", _("Error"), _class="cronjob-error") rows.append({ "id": i.id, "name": resource.HTMLNode("a", _(crontab.format(i.ext_type, i.name)), href=url_for(".edit", id=i.id)), "schedule": crontab.format_schedule(i.schedule), "user": text_type(i.user) if i.user else _("SYSTEM"), "last": last, "next": next, "error": i.error }) return GridAjaxResponse(rows, len(rows))
def word_prepare(cls, word): if not cls._highlighted(word): return resource.HTMLNode("span", word) return resource.HTMLNode("span", cls.get_clean_value(word), _class="hl")
def get_forensic_actions(self): return datasearch.DataSearch.get_forensic_actions(self) + \ [resource.HTMLNode("button", _("Syslog export"), formaction=url_for(".syslog_download"), type="submit", form="datasearch_export_form", _class="btn btn-default needone", _icon="fa-file-text-o", _sortkey="download")]
def buildAdditionalData(self, msg, ptype, ignore=[], ignored={}, ip_options=[], tcp_options=[]): self.beginSection(_("Additional data")) self.beginTable() self.newTableCol(0, _("Meaning"), header=True) self.newTableCol(0, _("Value"), header=True) index = 1 for ad in msg["additional_data"]: value = None meaning = ad["meaning"] if meaning == "ip_option_code": ip_options.append((ad["data"], 0, None)) ignored[meaning] = "" if meaning == "ip_option_data": data = ad["data"] ip_options[-1] = (ip_options[-1][0], len(data), data) ignored[meaning] = "" if meaning == "tcp_option_code": tcp_options.append((ad["data"], 0, None)) ignored[meaning] = "" if meaning == "tcp_option_data": data = ad["data"] tcp_options[-1] = (tcp_options[-1][0], len(data), data) ignored[meaning] = "" if ad["data"] is not None: value = ad["data"] if ad["type"] == "byte-string" and meaning != "payload": value = html.escape(utils.hexdump(value)).replace(" ", resource.HTMLSource(" ")) value = resource.HTMLSource("<span class='fixed'>%s</span>" % value) for field in ignore: if meaning is not None and meaning == field[0]: ignored[meaning] = value break links = resource.HTMLSource() for obj in filter(None, hookmanager.trigger("HOOK_%sSUMMARY_MEANING_LINK" % ptype.upper(), msg, meaning, value)): links += obj if links: meaning = resource.HTMLNode("a", meaning, **{ "data-toggle": "popover", "data-placement": "bottom", "data-html": "true", "data-content": '<span class="popup-menu">%s</span>' % links, "data-template": POPOVER_HTML, }) if meaning not in ignored: self.newTableCol(index, resource.HTMLSource(meaning or "Data content")) self.newTableCol(index, html.escape(value) if value is not None else None) index += 1 self.endTable() self.endSection()