Exemple #1
0
def _get_json_body(view: "View", rows: Rows) -> str:
    painted_rows: List[List] = []

    header_row = []
    for cell in view.row_cells:
        header_row.append(escaping.strip_tags(cell.export_title()))
    painted_rows.append(header_row)

    for row in rows:
        painted_row: List[Union[str, Dict]] = []
        for cell in view.row_cells:
            joined_row = join_row(row, cell)
            content = cell.render_for_export(joined_row)
            if isinstance(content, dict):
                # Allow painters to return lists and dicts, then json encode them
                # as such data structures without wrapping them into strings
                pass

            else:
                content = escaping.strip_tags(content.replace("<br>", "\n"))

            painted_row.append(content)

        painted_rows.append(painted_row)

    return json.dumps(painted_rows, indent=True)
Exemple #2
0
    def _write_csv(self, csv_separator: str) -> None:
        rows = self.rows
        limit = self.limit
        omit_headers = self.options["omit_headers"]

        # Apply limit after search / sorting etc.
        if limit is not None:
            rows = rows[:limit]

        resp = []

        # If we have no group headers then paint the headers now
        if not omit_headers and self.rows and not isinstance(
                self.rows[0], GroupHeader):
            resp.append(
                csv_separator.join([
                    escaping.strip_tags(header.title) or ""
                    for header in self.headers
                ]) + "\n")

        for row in rows:
            if isinstance(row, GroupHeader):
                continue

            resp.append(
                csv_separator.join(
                    [escaping.strip_tags(cell.content) for cell in row.cells]))
            resp.append("\n")

        response.set_data("".join(resp))
Exemple #3
0
    def _export_audit_log(self,
                          audit: List[AuditLogStore.Entry]) -> ActionResult:
        response.set_content_type("text/csv")

        if self._options["display"] == "daily":
            filename = "wato-auditlog-%s_%s.csv" % (
                render.date(time.time()),
                render.time_of_day(time.time()),
            )
        else:
            filename = "wato-auditlog-%s_%s_days.csv" % (
                render.date(time.time()),
                self._options["display"][1],
            )

        response.headers[
            "Content-Disposition"] = 'attachment; filename="%s"' % filename

        titles = [
            _("Date"),
            _("Time"),
            _("Object type"),
            _("Object"),
            _("User"),
            _("Action"),
            _("Summary"),
        ]

        if self._show_details:
            titles.append(_("Details"))

        resp = []

        resp.append(",".join(titles) + "\n")
        for entry in audit:
            columns = [
                render.date(int(entry.time)),
                render.time_of_day(int(entry.time)),
                entry.object_ref.object_type.name if entry.object_ref else "",
                entry.object_ref.ident if entry.object_ref else "",
                entry.user_id,
                entry.action,
                '"' + escaping.strip_tags(entry.text).replace('"', "'") + '"',
            ]

            if self._show_details:
                columns.append(
                    '"' +
                    escaping.strip_tags(entry.diff_text).replace('"', "'") +
                    '"')

            resp.append(",".join(columns) + "\n")

        response.set_data("".join(resp))

        return FinalizeRequest(code=200)
Exemple #4
0
def _serialize_ruleset(ruleset: Ruleset) -> DomainObject:
    members = {}
    if ruleset.num_rules() > 0:
        members["rules"] = constructors.collection_property(
            name="rules",
            value=[],
            base="",
        )

    return constructors.domain_object(
        domain_type="ruleset",
        identifier=ruleset.name,
        title=ruleset.title() or ruleset.name,
        editable=False,
        deletable=False,
        members=members,
        extensions={
            "name": ruleset.name,
            "title": ruleset.title(),
            "item_type": ruleset.item_type(),
            "item_name": ruleset.item_name(),
            "item_enum": ruleset.item_enum(),
            "match_type": ruleset.match_type(),
            "help": strip_tags(ruleset.help()),
            "number_of_rules": ruleset.num_rules(),
        },
    )
Exemple #5
0
def _sort_rows(rows: TableRows, sort_col: int, sort_reverse: int) -> TableRows:
    # remove and remind fixed rows, add to separate list
    fixed_rows = []
    for index, row in enumerate(rows[:]):
        if row.fixed:
            rows.remove(row)
            fixed_rows.append((index, row))

    # Then use natural sorting to sort the list. Note: due to a
    # change in the number of columns of a table in different software
    # versions the cmp-function might fail. This is because the sorting
    # column is persisted in a user file. So we ignore exceptions during
    # sorting. This gives the user the chance to change the sorting and
    # see the table in the first place.
    try:
        rows.sort(
            key=lambda x: utils.key_num_split(
                escaping.strip_tags(x[0][sort_col][0])),
            reverse=sort_reverse == 1,
        )
    except IndexError:
        pass

    # Now re-add the removed "fixed" rows to the list again
    if fixed_rows:
        for index, cells in fixed_rows:
            rows.insert(index, cells)

    return rows
Exemple #6
0
    def render(self, row: Row, cell: Cell) -> CellSpec:
        classes = ["perfometer"]
        if is_stale(row):
            classes.append("stale")

        try:
            title, h = Perfometer(row).render()
            if title is None and h is None:
                return "", ""
        except Exception as e:
            logger.exception("error rendering performeter")
            if config.debug:
                raise
            return " ".join(classes), _("Exception: %s") % e

        assert h is not None
        content = (html.render_div(HTML(h), class_=["content"]) +
                   html.render_div(title, class_=["title"]) +
                   html.render_div("", class_=["glass"]))

        # pnpgraph_present: -1 means unknown (path not configured), 0: no, 1: yes
        if display_options.enabled(
                display_options.X) and row["service_pnpgraph_present"] != 0:
            url = cmk_graph_url(row, "service")
            disabled = False
        else:
            url = "javascript:void(0)"
            disabled = True

        return " ".join(classes), html.render_a(
            content=content,
            href=url,
            title=escaping.strip_tags(title),
            class_=["disabled" if disabled else None],
        )
Exemple #7
0
    def _render_message(
        self,
        msg: Union[HTML, str],
        msg_type: Literal["message", "warning", "error"] = "message",
    ) -> HTML:
        if msg_type == "message":
            cls = "success"
            prefix = _("MESSAGE")
        elif msg_type == "warning":
            cls = "warning"
            prefix = _("WARNING")
        elif msg_type == "error":
            cls = "error"
            prefix = _("ERROR")
        else:
            raise TypeError(msg_type)

        if self.output_format == "html":
            code = HTMLWriter.render_div(msg, class_=cls)
            if self.mobile:
                return HTMLWriter.render_center(code)
            return code
        return escaping.escape_to_html_permissive(
            "%s: %s\n" % (prefix, escaping.strip_tags(msg)),
            escape_links=False)
Exemple #8
0
    def _format_for_csv(self, raw_data: ExportCellContent) -> str:
        # raw_data can also be int, float, dict (labels)
        if isinstance(raw_data, dict):
            return ', '.join(
                ["%s: %s" % (key, value) for key, value in raw_data.items()])

        return escaping.strip_tags(raw_data).replace('\n',
                                                     '').replace('"', '""')
Exemple #9
0
def create_rule(param):
    """Create rule"""
    body = param["body"]
    folder = body["folder"]
    value = body["value_raw"]
    rulesets = watolib.FolderRulesets(folder)
    rulesets.load()
    try:
        ruleset = rulesets.get(body["ruleset"])
    except KeyError:
        return problem(
            status=400,
            detail=f"Ruleset {body['ruleset']!r} could not be found.",
        )

    try:
        ruleset.valuespec().validate_value(value, "")
    except exceptions.MKUserError as exc:
        if exc.varname is None:
            title = "A field has a problem"
        else:
            field_name = exc.varname.replace("_p_", "")
            title = f"Problem in (sub-)field {field_name!r}"

        return problem(
            status=400,
            detail=strip_tags(exc.message),
            title=title,
        )

    rule = watolib.Rule(
        gen_id(),
        folder,
        ruleset,
        RuleConditions(
            host_folder=folder,
            host_tags=body["conditions"].get("host_tag"),
            host_labels=body["conditions"].get("host_label"),
            host_name=body["conditions"].get("host_name"),
            service_description=body["conditions"].get("service_description"),
            service_labels=body["conditions"].get("service_label"),
        ),
        RuleOptions.from_config(body["properties"]),
        value,
    )
    index = ruleset.append_rule(folder, rule)
    rulesets.save()
    # TODO Duplicated code is in pages/rulesets.py:2670-
    # TODO Move to watolib
    add_change(
        "new-rule",
        _l('Created new rule #%d in ruleset "%s" in folder "%s"')
        % (index, ruleset.title(), folder.alias_path()),
        sites=folder.all_site_ids(),
        diff_text=make_diff_text({}, rule.to_log()),
        object_ref=rule.object_ref(),
    )
    return serve_json(_serialize_rule(folder, index, rule))
Exemple #10
0
def log_audit(action: str,
              message: LogMessage,
              object_ref: Optional[ObjectRef] = None,
              user_id: Optional[UserId] = None,
              diff_text: Optional[str] = None) -> None:

    if config.wato_use_git:
        if isinstance(message, HTML):
            message = escaping.strip_tags(message.value)
        cmk.gui.watolib.git.add_message(message)

    _log_entry(action, message, object_ref, user_id, diff_text)
Exemple #11
0
def do_site_login(site_id: SiteId, name: UserId, password: str) -> str:
    sites = SiteManagementFactory().factory().load_sites()
    site = sites[site_id]
    if not name:
        raise MKUserError(
            "_name",
            _("Please specify your administrator login on the remote site."))
    if not password:
        raise MKUserError("_passwd", _("Please specify your password."))

    # Trying basic auth AND form based auth to ensure the site login works.
    # Adding _ajaxid makes the web service fail silently with an HTTP code and
    # not output HTML code for an error screen.
    url = site["multisiteurl"] + "login.py"
    post_data = {
        "_login":
        "******",
        "_username":
        name,
        "_password":
        password,
        "_origtarget":
        "automation_login.py?_version=%s&_edition_short=%s" %
        (cmk_version.__version__, cmk_version.edition_short()),
        "_plain_error":
        "1",
    }
    response = get_url(url,
                       site.get("insecure", False),
                       auth=(name, password),
                       data=post_data).strip()
    if "<html>" in response.lower():
        message = _("Authentication to web service failed.<br>Message:<br>%s"
                    ) % escaping.strip_tags(escaping.strip_scripts(response))
        if config.debug:
            message += "<br>" + _("Automation URL:") + " <tt>%s</tt><br>" % url
        raise MKAutomationException(message)
    if not response:
        raise MKAutomationException(_("Empty response from web service"))
    try:
        eval_response = ast.literal_eval(response)
    except SyntaxError:
        raise MKAutomationException(response)
    if isinstance(eval_response, dict):
        if cmk_version.is_managed_edition(
        ) and eval_response["edition_short"] != "cme":
            raise MKUserError(
                None,
                _("The Check_MK Managed Services Edition can only "
                  "be connected with other sites using the CME."),
            )
        return eval_response["login_secret"]
    return eval_response
Exemple #12
0
def _show_crash_dump_message(
    crash: "GUICrashReport", plain_text: bool, fail_silently: bool, show_crash_link: Optional[bool]
) -> None:
    """Create a crash dump from a GUI exception and display a message to the user"""

    if show_crash_link is None:
        show_crash_link = user.may("general.see_crash_reports")

    title = _("Internal error")
    message = "%s: %s<br>\n<br>\n" % (title, crash.crash_info["exc_value"])
    # Do not reveal crash context information to unauthenticated users or not permitted
    # users to prevent disclosure of internal information
    if not show_crash_link:
        message += _(
            "An internal error occurred while processing your request. "
            "You can report this issue to your Checkmk administrator. "
            "Detailed information can be found on the crash report page "
            "or in <tt>var/log/web.log</tt>."
        )
    else:
        crash_url = makeuri(
            request,
            [
                ("site", omd_site()),
                ("crash_id", crash.ident_to_text()),
            ],
            filename="crash.py",
        )
        message += (
            _(
                "An internal error occured while processing your request. "
                "You can report this issue to the Checkmk team to help "
                'fixing this issue. Please open the <a href="%s">crash report page</a> '
                "and use the form for reporting the problem."
            )
            % crash_url
        )

    if plain_text:
        response.set_content_type("text/plain")
        response.set_data("%s\n" % escaping.strip_tags(message))
        return

    if fail_silently:
        return

    html.header(title, Breadcrumb())
    html.show_error(message)
    html.footer()
Exemple #13
0
def section(
    title: Union[None, HTML, str] = None,
    checkbox: Union[None, HTML, str, Tuple[str, bool, str]] = None,
    section_id: Optional[str] = None,
    simple: bool = False,
    hide: bool = False,
    legend: bool = True,
    css: Optional[str] = None,
    is_show_more: bool = False,
    is_changed: bool = False,
    is_required: bool = False,
) -> None:
    global g_section_open
    section_close()
    html.open_tr(
        id_=section_id,
        class_=[
            css,
            "show_more_mode" if is_show_more and not is_changed else "basic"
        ],
        style="display:none;" if hide else None,
    )

    if legend:
        html.open_td(class_=["legend", "simple" if simple else None])
        if title:
            html.open_div(
                class_=["title", "withcheckbox" if checkbox else None],
                title=escaping.strip_tags(title),
            )
            html.write_text(title)
            html.span("." * 200,
                      class_=["dots", "required" if is_required else None])
            html.close_div()
        if checkbox:
            html.open_div(class_="checkbox")
            if isinstance(checkbox, (str, HTML)):
                html.write_text(checkbox)
            else:
                name, active, attrname = checkbox
                html.checkbox(name,
                              active,
                              onclick="cmk.wato.toggle_attribute(this, '%s')" %
                              attrname)
            html.close_div()
        html.close_td()
    html.open_td(class_=["content", "simple" if simple else None])
    g_section_open = True
Exemple #14
0
def _export_python(view: "View", rows: Rows) -> None:
    resp = []
    resp.append("[\n")
    resp.append(repr([cell.export_title() for cell in view.row_cells]))
    resp.append(",\n")
    for row in rows:
        resp.append("[")
        for cell in view.row_cells:
            joined_row = join_row(row, cell)
            content = cell.render_for_export(joined_row)

            # The aggr_treestate painters are returning a dictionary data structure (see
            # paint_aggregated_tree_state()) in case the output_format is not HTML. Only
            # remove the HTML tags from the top level strings produced by painters.
            if isinstance(content, str):
                content = escaping.strip_tags(content)

            resp.append(repr(content))
            resp.append(",")
        resp.append("],")
    resp.append("\n]\n")
    response.set_data("".join(resp))
Exemple #15
0
def collect_attributes(
    object_type: ObjectType,
    context: ObjectContext,
) -> List[Attr]:
    """Collect all attributes for a specific use case

    Use cases can be host or folder creation or updating.

    Args:
        object_type:
            Either 'host', 'folder' or 'cluster'

        context:
            Either 'create' or 'update'

    Returns:
        A list of attribute describing named-tuples.

    Examples:

        >>> attrs = collect_attributes('host', 'create')
        >>> assert len(attrs) > 10, len(attrs)

        >>> attrs = collect_attributes('host', 'update')
        >>> assert len(attrs) > 10, len(attrs)

        >>> attrs = collect_attributes('cluster', 'create')
        >>> assert len(attrs) > 10, len(attrs)

        >>> attrs = collect_attributes('cluster', 'update')
        >>> assert len(attrs) > 10, len(attrs)

        >>> attrs = collect_attributes('folder', 'create')
        >>> assert len(attrs) > 10, len(attrs)

        >>> attrs = collect_attributes('folder', 'update')
        >>> assert len(attrs) > 10

    To check the content of the list, uncomment this one.

        # >>> import pprint
        # >>> pprint.pprint(attrs)

    """
    something = TypeVar("something")

    def _ensure(optional: Optional[something]) -> something:
        if optional is None:
            raise ValueError
        return optional

    T = typing.TypeVar("T")

    def maybe_call(func: Optional[Callable[[], T]]) -> Optional[T]:
        if func is None:
            return None
        return func()

    # NOTE:
    #   We want to get all the topics, so we don't miss any attributes. We filter them later.
    #   new=True may also be new=False, it doesn't matter in this context.
    result = []
    for topic_id, topic_title in watolib.get_sorted_host_attribute_topics(
            "always", new=True):
        for attr in watolib.get_sorted_host_attributes_by_topic(topic_id):
            if object_type == "folder" and not attr.show_in_folder():
                continue

            if context in ["create", "update"] and not attr.openapi_editable():
                continue

            help_text: str = strip_tags(attr.help()) or ""
            # TODO: what to do with attr.depends_on_tags()?
            attr_entry = Attr(
                name=attr.name(),
                description=help_text,
                section=topic_title,
                mandatory=attr.is_mandatory(),
                field=maybe_call(getattr(attr, "openapi_field", None)),
            )
            result.append(attr_entry)

    tag_config = load_tag_config()
    tag_config += BuiltinTagConfig()

    def _format(tag_id: Optional[str]) -> str:
        if tag_id is None:
            return "`null`"
        return f'`"{tag_id}"`'

    tag_group: TagGroup
    for tag_group in tag_config.tag_groups:
        description: List[str] = []
        if tag_group.help:
            description.append(tag_group.help)

        if tag_group.tags:
            description.append("Choices:")
            for tag in tag_group.tags:
                description.append(f" * {_format(tag.id)}: {tag.title}")

        result.append(
            Attr(
                name=_ensure(f"tag_{tag_group.id}"),
                section=tag_group.topic or "No topic",
                mandatory=False,
                description="\n\n".join(description),
                enum=[tag.id for tag in tag_group.tags],
                field=None,
            ))

    return result
Exemple #16
0
def test_strip_tags(inp, out):
    assert escaping.strip_tags(inp) == out
Exemple #17
0
    def _show_configuration_variables(self) -> None:
        search = self._search

        at_least_one_painted = False
        html.open_div(class_="globalvars")
        for group, config_variables in self.iter_all_configuration_variables():
            header_is_painted = False  # needed for omitting empty groups

            for config_variable in config_variables:
                varname = config_variable.ident()
                valuespec = config_variable.valuespec()

                if self._show_only_modified and varname not in self._current_settings:
                    continue

                help_text = valuespec.help() or ""
                title_text = valuespec.title() or ""

                if (search and search not in group.title().lower() and search
                        not in config_variable.domain().ident().lower()
                        and search not in varname
                        and search not in help_text.lower()
                        and search not in title_text.lower()):
                    continue  # skip variable when search is performed and nothing matches
                at_least_one_painted = True

                if not header_is_painted:
                    # always open headers when searching
                    forms.header(group.title(),
                                 isopen=search or self._show_only_modified)
                    header_is_painted = True

                default_value = self._default_values[varname]

                edit_url = folder_preserving_link([
                    ("mode", self.edit_mode_name),
                    ("varname", varname),
                    ("site", request.var("site", "")),
                ])
                title = HTMLWriter.render_a(
                    title_text,
                    href=edit_url,
                    class_="modified"
                    if varname in self._current_settings else None,
                    title=escaping.strip_tags(help_text),
                )

                if varname in self._current_settings:
                    value = self._current_settings[varname]
                elif varname in self._global_settings:
                    value = self._global_settings[varname]
                else:
                    value = default_value

                try:
                    to_text = valuespec.value_to_html(value)
                except Exception:
                    logger.exception("error converting %r to text", value)
                    to_text = html.render_error(
                        _("Failed to render value: %r") % value)

                # Is this a simple (single) value or not? change styling in these cases...
                simple = True
                if "\n" in to_text or "<td>" in to_text:
                    simple = False
                forms.section(title, simple=simple)

                if varname in self._current_settings:
                    modified_cls = ["modified"]
                    value_title: Optional[str] = _(
                        "This option has been modified.")
                elif varname in self._global_settings:
                    modified_cls = ["modified globally"]
                    value_title = _(
                        "This option has been modified in global settings.")
                else:
                    modified_cls = []
                    value_title = None

                if is_a_checkbox(valuespec):
                    html.open_div(class_=["toggle_switch_container"] +
                                  modified_cls + (["on"] if value else []))
                    html.toggle_switch(
                        enabled=value,
                        help_txt=_("Immediately toggle this setting"),
                        href=makeactionuri(request, transactions,
                                           [("_action", "toggle"),
                                            ("_varname", varname)]),
                        class_=modified_cls,
                        title=value_title,
                    )
                    html.close_div()

                else:
                    html.a(to_text,
                           href=edit_url,
                           class_=modified_cls,
                           title=value_title)

            if header_is_painted:
                forms.end()
        if not at_least_one_painted and search:
            html.show_message(
                _("Did not find any global setting matching your search."))
        html.close_div()