def test_scripting_snippet():
    "Asserts that JS snippets are treated equally"

    err = ErrorBundle()
    err.supported_versions = {}
    scripting.test_js_snippet(err, "alert(1 + 1 == 2)", "bar.zap")
    assert not err.failed()

    err = ErrorBundle()
    err.supported_versions = {}
    scripting.test_js_snippet(err, "eval('foo');", "bar.zap")
    assert err.failed()
def test_scripting_snippet():
    'Assert that JS snippets are treated equally.'

    err = ErrorBundle()
    err.supported_versions = {}
    scripting.test_js_snippet(err, 'alert(1 + 1 == 2)', 'bar.zap')
    assert not err.failed()

    err = ErrorBundle()
    err.supported_versions = {}
    scripting.test_js_snippet(err, "eval('foo');", 'bar.zap')
    assert err.failed()
Esempio n. 3
0
def test_scripting_snippet():
    'Assert that JS snippets are treated equally.'

    err = ErrorBundle()
    err.supported_versions = {}
    scripting.test_js_snippet(err, 'alert(1 + 1 == 2)', 'bar.zap')
    assert not err.failed()

    err = ErrorBundle()
    err.supported_versions = {}
    scripting.test_js_snippet(err, "eval('foo');", 'bar.zap')
    assert err.failed()
Esempio n. 4
0
def test_scripting_snippet():
    "Asserts that JS snippets are treated equally"

    err = ErrorBundle()
    err.supported_versions = {}
    scripting.test_js_snippet(err, "alert(1 + 1 == 2)", "bar.zap")
    assert not err.failed()

    err = ErrorBundle()
    err.supported_versions = {}
    scripting.test_js_snippet(err, "eval('foo');", "bar.zap")
    assert err.failed()
    def handle_endtag(self, tag):

        tag = tag.lower()
        if tag == "xul:script":
            tag = "script"

        if DEBUG:  # pragma: no cover
            print "E: ", tag, self.xml_state

        if not self.xml_state:
            if "closing_tags" in self.reported or not self.strict:
                if DEBUG:
                    print "Unstrict; extra closing tags ------"
                return
            self.err.warning(("testcases_markup_markuptester",
                              "handle_endtag",
                              "extra_closing_tags"),
                             "Markup parsing error",
                             "The markup file has more closing tags than it "
                             "has opening tags.",
                             self.filename,
                             line=self.line,
                             context=self.context,
                             tier=2)
            self.reported.add("closing_tags")
            if DEBUG:  # pragma: no cover
                print "Too many closing tags ------"
            return

        elif "script" in self.xml_state[:-1]:
            # If we're in a script tag, nothing else matters. Just rush
            # everything possible into the xml buffer.

            self._save_to_buffer("</" + tag + ">")
            if DEBUG:
                print "Markup as text in script ------"
            return

        elif tag not in self.xml_state:
            # If the tag we're processing isn't on the stack, then
            # something is wrong.
            self.err.warning(("testcases_markup_markuptester",
                              "handle_endtag",
                              "extra_closing_tags"),
                             "Parse error: tag closed before opened",
                             ["Markup tags cannot be closed before they are "
                              "opened. Perhaps you were just a little "
                              "overzealous with forward-slashes?",
                              'Tag "%s" closed before it was opened' % tag],
                             self.filename,
                             line=self.line,
                             context=self.context,
                             tier=2)
            if DEBUG:  # pragma: no cover
                print "Tag closed before opened ------"
            return

        data_buffer = self.xml_buffer.pop()
        old_state = self.xml_state.pop()
        old_line = self.xml_line_stack.pop()

        # If the tag on the stack isn't what's being closed and it also
        # classifies as a self-closing tag, we just recursively close
        # down to the level of the tag we're actualy closing.
        if old_state != tag and old_state in SELF_CLOSING_TAGS:
            if DEBUG:
                print "Self closing tag cascading down ------"
            return self.handle_endtag(tag)

        # If this is an XML-derived language, everything must nest
        # properly. No overlapping tags.
        if (old_state != tag and
            self.extension[0] == 'x' and
            not self.strict):

            self.err.warning(("testcases_markup_markuptester",
                              "handle_endtag",
                              "invalid_nesting"),
                             "Markup invalidly nested",
                             "It has been determined that the document "
                             "invalidly nests its tags. This is not permitted "
                             "in the specified document type.",
                             self.filename,
                             line=self.line,
                             context=self.context,
                             tier=2)
            if DEBUG:  # pragma: no cover
                print "Invalid markup nesting ------"

        data_buffer = data_buffer.strip()

        # Perform analysis on collected data.
        if data_buffer:
            if tag == "script":
                scripting.test_js_snippet(err=self.err, data=data_buffer,
                                          filename=self.filename,
                                          line=old_line, context=self.context)
            elif tag == "style":
                csstester.test_css_file(self.err, self.filename, data_buffer,
                                        old_line)
    def handle_starttag(self, tag, attrs, self_closing=False):

        # Normalize!
        tag = tag.lower()
        # XUL scripts are identical to normal scripts. Treat them the same.
        if tag == "xul:script":
            tag = "script"

        orig_tag = tag

        # Be extra sure it's not a self-closing tag.
        if not self_closing:
            self_closing = tag in SELF_CLOSING_TAGS

        if DEBUG:  # pragma: no cover
            print "S: ", self.xml_state, tag, self_closing

        # A fictional tag for testing purposes.
        if tag == "xbannedxtestx":
            self.err.error(("testcases_markup_markuptester",
                            "handle_starttag",
                            "banned_element"),
                           "Banned element",
                           "A banned element was detected",
                           self.filename,
                           line=self.line,
                           context=self.context)

        # Test for banned XBL in themes.
        if self.err.detected_type == PACKAGE_THEME:
            if tag.startswith("xbl:"):
                self.xbl = True
                tag = tag[4:]

            # Find XBL elements.
            if self.xbl:
                if tag in UNSAFE_THEME_XBL:
                    self.err.warning(
                        err_id=("testcases_markup_markuptester",
                                "handle_starttag",
                                "unsafe_theme_xbl_element"),
                        warning="Banned XBL element in theme.",
                        description=["Certain XBL elements are disallowed in "
                                     "themes.",
                                     "Element: <xbl:%s>" % tag],
                        filename=self.filename,
                        line=self.line,
                        context=self.context)

                elif (tag == "property" and
                      any(a[0] in (u"onset", u"onget") for a in attrs)):
                    self.err.warning(
                        err_id=("testcases_markup_markuptester",
                                "handle_starttag",
                                "theme_xbl_property"),
                        warning="Themes are not allowed to use XBL properties",
                        description="XBL properties cannot be used in themes.",
                        filename=self.filename,
                        line=self.line,
                        context=self.context)


        # Test for banned elements in language pack and theme markup.
        if self.err.detected_type in (PACKAGE_LANGPACK, PACKAGE_THEME):
            if (tag in UNSAFE_TAGS or
                (self.err.detected_type == PACKAGE_THEME and
                 tag in UNSAFE_THEME_TAGS)):
                self.err.warning(("testcases_markup_markuptester",
                                  "handle_starttag",
                                  "unsafe_langpack_theme"),
                                 "Unsafe tag for add-on type",
                                 ["A tag in your markup has been marked as "
                                  "being potentially unsafe. Consider "
                                  "alternate means of accomplishing what the "
                                  "code executed by this tag performs.",
                                  'Tag "%s" is disallowed.' % tag],
                                 self.filename,
                                 line=self.line,
                                 context=self.context)
                if DEBUG:  # pragma: no cover
                    print "Unsafe Tag ------"

            # Make sure all src/href attributes are local
            for attr in attrs:
                if attr[0].lower() in ("src", "href") and \
                   not self._is_url_local(attr[1].lower()):
                    self.err.warning(("testcases_markup_markuptester",
                                      "handle_starttag",
                                      "remote_src_href"),
                                     "src/href attributes must be local.",
                                     "Language packs require that all src and "
                                     "href attributes are relative URLs.",
                                     self.filename,
                                     line=self.line,
                                     context=self.context)
                    self.err.reject = True

        if tag in ("iframe", "browser") and self.extension == "xul":
            # Bork if XUL iframe has no type attribute

            type_ = None
            src = None
            for attr in attrs:
                attr_name = attr[0].lower()
                if attr_name == "type":
                    type_ = attr[1].lower()
                elif attr_name == "src":
                    src = attr[1].lower()

            # We say it's true by default to catch elements that are
            # type="chrome" without an src="" attribute.
            remote_src = True
            if isinstance(src, types.StringTypes):
                remote_src = not self._is_url_local(src)

            if (type_ and
                not (type_ in SAFE_IFRAME_TYPES or
                     not remote_src)):
                self.err.warning(("testcases_markup_markuptester",
                                  "handle_starttag",
                                  "iframe_type_unsafe"),
                                 "iframe/browser missing 'type' attribute",
                                 "All iframe and browser elements must have "
                                 "either a valid `type` attribute or a `src` "
                                 "attribute that points to a local file.",
                                 self.filename,
                                 line=self.line,
                                 context=self.context)
            elif ((not type_ or
                   type_ not in SAFE_IFRAME_TYPES) and
                  remote_src):
                self.err.warning(("testcases_markup_markuptester",
                                  "handle_starttag",
                                  "iframe_type_unsafe"),
                                 "Typeless iframes/browsers must be local.",
                                 "iframe and browser elements that lack a type "
                                 "attribute must always have src attributes "
                                 "that reference local resources.",
                                 self.filename,
                                 line=self.line,
                                 context=self.context)

        elif tag == "script" and self.extension == "xul":
            # Per the Addon Validator Spec (v2), scripts in XUL
            # must not be remote.

            src = None
            for attr in attrs:
                if attr[0].lower() == "src":
                    src = attr[1].lower()

            if src and not self._is_url_local(src):
                self.err.warning(("testcases_markup_markuptester",
                                  "handle_starttag",
                                  "banned_remote_scripts"),
                                 "Scripts must not be remote in XUL",
                                 "In XUL, <script> tags must not be referenced "
                                 "to script files that are hosted remotely.",
                                 self.filename,
                                 line=self.line,
                                 context=self.context)

        # Find CSS and JS attributes and handle their values like they
        # would otherwise be handled by the standard parser flow.
        for attr in attrs:
            attr_name, attr_value = attr[0].lower(), attr[1]

            if (attr_name == "xmlns:xbl" and
                attr_value == "http://www.mozilla.org/xbl"):
                self.xbl = True

            if (self.err.detected_type == PACKAGE_THEME and
                attr_value.startswith(("data:", "javascript:"))):

                self.err.warning(
                        err_id=("testcases_markup_markuptester",
                                "handle_starttag",
                                "theme_attr_prefix"),
                        warning="Attribute contains banned prefix",
                        description=["A mark element's attribute contains a "
                                     "prefix which is not allowed in themes.",
                                     "Attribute: %s" % attr_name],
                        filename=self.filename,
                        line=self.line,
                        context=self.context)


            if attr_name == "style":
                csstester.test_css_snippet(self.err,
                                           self.filename,
                                           attr_value,
                                           self.line)
            elif attr_name.startswith("on"):  # JS attribute
                # Warn about DOM mutation event handlers.
                if attr_name in DOM_MUTATION_HANDLERS:
                    self.err.warning(
                        err_id=("testcases_markup_markuptester",
                                "handle_starttag",
                                "dom_manipulation_handler"),
                        warning="DOM Mutation Events Prohibited",
                        description="DOM mutation events are flagged because "
                                    "of their deprecated status, as well as "
                                    "their extreme inefficiency. Consider "
                                    "using a different event.",
                        filename=self.filename,
                        line=self.line,
                        context=self.context)

                scripting.test_js_snippet(err=self.err,
                                          data=attr_value,
                                          filename=self.filename,
                                          line=self.line,
                                          context=self.context)

            elif (self.extension == "xul" and
                  attr_name in ("insertbefore", "insertafter") and
                  any((id in attr[1]) for id in ("menu_pageSource",
                                                 "menu_pageinspect",
                                                 "javascriptConsole",
                                                 "webConsole"))):
                self.err.notice(
                    err_id=("testcases_markup_markuptester",
                            "handle_starttag",
                            "incompatible_menu_items"),
                    notice="Menu item has been moved",
                    description="Your add-on has an overlay that uses the "
                                "insertbefore or insertafter attribute "
                                "pointing to menuitems that have been moved "
                                "to a different menu item. Your overlay items "
                                "may appear in unexpected locations because "
                                "of this. See "
                        "https://bugzilla.mozilla.org/show_bug.cgi?id=653221"
                                " for more information.",
                    filename=self.filename,
                    line=self.line,
                    context=self.context,
                    for_appversions={
                        "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}":
                            version_range("firefox", "6.0a1", "7.0a1")},
                    compatibility_type="warning")


        # When the dev forgets their <!-- --> on a script tag, bad
        # things happen.
        if "script" in self.xml_state and tag != "script":
            self._save_to_buffer("<" + tag + self._format_args(attrs) + ">")
            return

        self.xml_state.append(orig_tag)
        self.xml_line_stack.append(self.line)
        self.xml_buffer.append(unicode(""))
Esempio n. 7
0
    def handle_endtag(self, tag):

        tag = tag.lower()
        if tag == "xul:script":
            tag = "script"

        if tag == "script" and len(self.xml_buffer[-1]) > 1000:
            self.err.warning(("markup", "complex_script"),
                             "Long inline script",
                             "Please store complex scripts in .js files "
                             "rather than inline script nodes.",
                             self.filename,
                             line=self.line,
                             context=self.context,
                             tier=2)

        if DEBUG:  # pragma: no cover
            print "E: ", tag, self.xml_state

        if not self.xml_state:
            if "closing_tags" in self.reported or not self.strict:
                if DEBUG:
                    print "Unstrict; extra closing tags ------"
                return
            self.err.warning(("markup", "endtag", "extra_closing_tags"),
                             "Markup parsing error",
                             "The markup file has more closing tags than it "
                             "has opening tags.",
                             self.filename,
                             line=self.line,
                             context=self.context,
                             tier=2)
            self.reported.add("closing_tags")
            if DEBUG:  # pragma: no cover
                print "Too many closing tags ------"
            return

        elif "script" in self.xml_state[:-1]:
            # If we're in a script tag, nothing else matters. Just rush
            # everything possible into the xml buffer.

            self._save_to_buffer("</" + tag + ">")
            if DEBUG:
                print "Markup as text in script ------"
            return

        elif tag not in self.xml_state:
            # If the tag we're processing isn't on the stack, then
            # something is wrong.
            self.err.warning(
                ("markup", "endtag", "extra_closing_tags"),
                "Parse error: tag closed before opened", [
                    "Markup tags cannot be closed before they are "
                    "opened. Perhaps you were just a little "
                    "overzealous with forward-slashes?",
                    'Tag "%s" closed before it was opened' % tag
                ],
                self.filename,
                line=self.line,
                context=self.context,
                tier=2)
            if DEBUG:  # pragma: no cover
                print "Tag closed before opened ------"
            return

        data_buffer = self.xml_buffer.pop()
        old_state = self.xml_state.pop()
        old_line = self.xml_line_stack.pop()
        script_type = True
        if old_state == "script":
            script_type = self.xml_state_scripts.pop()

        # If the tag on the stack isn't what's being closed and it also
        # classifies as a self-closing tag, we just recursively close
        # down to the level of the tag we're actualy closing.
        if old_state != tag and old_state in SELF_CLOSING_TAGS:
            if DEBUG:
                print "Self closing tag cascading down ------"
            return self.handle_endtag(tag)

        # If this is an XML-derived language, everything must nest
        # properly. No overlapping tags.
        if (old_state != tag and self.extension[0] == 'x' and not self.strict):

            self.err.warning(("markup", "endtag", "invalid_nesting"),
                             "Markup invalidly nested",
                             "It has been determined that the document "
                             "invalidly nests its tags. This is not permitted "
                             "in the specified document type.",
                             self.filename,
                             line=self.line,
                             context=self.context,
                             tier=2)
            if DEBUG:  # pragma: no cover
                print "Invalid markup nesting ------"

        data_buffer = data_buffer.strip()

        # Perform analysis on collected data.
        if data_buffer:
            if tag == "script" and not script_type:
                scripting.test_js_snippet(err=self.err,
                                          data=data_buffer,
                                          filename=self.filename,
                                          line=old_line,
                                          context=self.context)
            elif tag == "style":
                csstester.test_css_file(self.err, self.filename, data_buffer,
                                        old_line)
Esempio n. 8
0
    def handle_starttag(self, tag, attrs, self_closing=False):

        # Normalize!
        tag = tag.lower()
        # XUL scripts are identical to normal scripts. Treat them the same.
        if tag == "xul:script":
            tag = "script"

        orig_tag = tag

        # Be extra sure it's not a self-closing tag.
        if not self_closing:
            self_closing = tag in SELF_CLOSING_TAGS

        if DEBUG:  # pragma: no cover
            print "S: ", self.xml_state, tag, self_closing

        # A fictional tag for testing purposes.
        if tag == "xbannedxtestx":
            self.err.error(err_id=("markup", "starttag", "banned_element"),
                           error="Banned markup element",
                           description="A banned markup element was found.",
                           filename=self.filename,
                           line=self.line,
                           context=self.context)

        # Test for banned XBL in themes.
        if self.err.detected_type == PACKAGE_THEME:
            if tag.startswith("xbl:"):
                self.xbl = True
                tag = tag[4:]

            # Find XBL elements.
            if self.xbl:
                if tag in UNSAFE_THEME_XBL:
                    self.err.warning(
                        err_id=("markup", "starttag",
                                "unsafe_theme_xbl_element"),
                        warning="Banned XBL element in theme.",
                        description=[
                            "Certain XBL elements are disallowed in "
                            "full themes.",
                            "Element: <xbl:%s>" % tag
                        ],
                        filename=self.filename,
                        line=self.line,
                        context=self.context)

                elif (tag == "property"
                      and any(a[0] in (u"onset", u"onget") for a in attrs)):
                    self.err.warning(
                        err_id=("markup", "starttag", "theme_xbl_property"),
                        warning="Themes are not allowed to use XBL properties",
                        description="XBL properties cannot be used in themes.",
                        filename=self.filename,
                        line=self.line,
                        context=self.context)

        # Test for banned elements in language pack and theme markup.
        if self.err.detected_type in (PACKAGE_LANGPACK, PACKAGE_THEME):
            if (tag in UNSAFE_TAGS or (self.err.detected_type == PACKAGE_THEME
                                       and tag in UNSAFE_THEME_TAGS)):
                self.err.warning(
                    err_id=("markup", "starttag", "unsafe_langpack_theme"),
                    warning="Unsafe tag for add-on type",
                    description=[
                        "A tag in your markup has been marked as "
                        "being potentially unsafe. Consider "
                        "alternate means of accomplishing what the "
                        "code executed by this tag performs.",
                        'Tag "%s" is disallowed.' % tag
                    ],
                    filename=self.filename,
                    line=self.line,
                    context=self.context)

            # Make sure all src/href attributes are local
            if any(not self._is_url_local(attr[1]) for attr in attrs
                   if attr[0] in ("src", "href")):
                self.err.warning(
                    err_id=("markup", "starttag", "remote_src_href"),
                    warning="`src`/`href` attributes must be local.",
                    description="Full Themes and language packs may not "
                    "reference remote resources.",
                    filename=self.filename,
                    line=self.line,
                    context=self.context)

        if tag == "prefwindow":
            # Flag <prefwindow> elements without IDs.

            if not any((key == "id") for key, val in attrs):
                self.err.warning(
                    err_id=("markup", "starttag", "prefwindow_id"),
                    warning="`<prefwindow>` elements must have IDs.",
                    description="`<prefwindow>` elements without `id` "
                    "attributes cause errors to be reported "
                    "in the error console and prevent "
                    "persistence of certain properties of the "
                    "dialog.",
                    filename=self.filename,
                    line=self.line,
                    context=self.context)

        elif tag in ("iframe", "browser") and self.extension == "xul":
            # Bork if XUL iframe has no type attribute

            type_ = None
            src = None
            for attr in attrs:
                attr_name = attr[0].lower()
                if attr_name == "type":
                    type_ = attr[1].lower()
                elif attr_name == "src":
                    src = attr[1].lower()

            # We say it's true by default to catch elements that are
            # type="chrome" without an src="" attribute.
            remote_src = True
            if isinstance(src, types.StringTypes):
                remote_src = not self._is_url_local(src)

            if (type_ and not (type_ in SAFE_IFRAME_TYPES or not remote_src)):
                self.err.warning(("markup", "starttag", "iframe_type_unsafe"),
                                 "iframe/browser missing 'type' attribute",
                                 "All iframe and browser elements must have "
                                 "either a valid `type` attribute or a `src` "
                                 "attribute that points to a local file.",
                                 self.filename,
                                 line=self.line,
                                 context=self.context)
            elif ((not type_ or type_ not in SAFE_IFRAME_TYPES)
                  and remote_src):
                self.err.warning(
                    ("markup", "starttag", "iframe_type_unsafe"),
                    "Typeless iframes/browsers must be local.",
                    "iframe and browser elements that lack a type "
                    "attribute must always have src attributes "
                    "that reference local resources.",
                    self.filename,
                    line=self.line,
                    context=self.context)

        elif tag == "script":
            # Per the Addon Validator Spec (v2), scripts
            # must not be remote.

            src = None
            for attr in attrs:
                if attr[0].lower() == "src":
                    src = attr[1].lower()
                    break

            if src:
                if not self._is_url_local(src):
                    self.err.warning(
                        err_id=("markup", "starttag", "banned_remote_scripts"),
                        warning="Scripts must not be remote",
                        description="<script> tags must not be referenced to "
                        "script files that are hosted remotely.",
                        filename=self.filename,
                        line=self.line,
                        context=self.context)
                else:
                    self.found_scripts.add(src)

        # Find CSS and JS attributes and handle their values like they
        # would otherwise be handled by the standard parser flow.
        for attr in attrs:
            attr_name, attr_value = attr[0].lower(), attr[1]

            # We don't care about valueless attributes.
            if attr_value is None:
                continue

            if (attr_name == "xmlns:xbl"
                    and attr_value == "http://www.mozilla.org/xbl"):
                self.xbl = True

            # Test that an absolute URI isn't referenced in Jetpack 1.4.
            if (self.is_jetpack and attr_value.startswith("resource://")
                    and "-data/" in attr_value):
                self.err.warning(
                    err_id=("markup", "starttag", "jetpack_abs_uri"),
                    warning="Absolute URI referenced in Jetpack 1.4",
                    description=[
                        "As of Jetpack 1.4, absolute URIs are no "
                        "longer allowed within add-ons.",
                        "See %s for more information." % JETPACK_URI_URL
                    ],
                    filename=self.filename,
                    line=self.line,
                    context=self.context,
                    compatibility_type="error")

            if (self.err.detected_type == PACKAGE_THEME
                    and attr_value.startswith(("data:", "javascript:"))):

                self.err.warning(err_id=("markup", "starttag",
                                         "theme_attr_prefix"),
                                 warning="Attribute contains banned prefix",
                                 description=[
                                     "A mark element's attribute contains a "
                                     "prefix which is not allowed in full "
                                     "themes.",
                                     "Attribute: %s" % attr_name
                                 ],
                                 filename=self.filename,
                                 line=self.line,
                                 context=self.context)

            if attr_name == "style":
                csstester.test_css_snippet(self.err, self.filename, attr_value,
                                           self.line)
            elif attr_name.startswith("on"):  # JS attribute
                # Warn about DOM mutation event handlers.
                if attr_name in DOM_MUTATION_HANDLERS:
                    self.err.warning(
                        err_id=("markup", "starttag",
                                "dom_manipulation_handler"),
                        warning="DOM Mutation Events Prohibited",
                        description="DOM mutation events are deprecated and "
                        "have severe performance implications. "
                        "Please use mutation observers instead: "
                        "https://developer.mozilla.org/docs/Web/"
                        "API/MutationObserver",
                        filename=self.filename,
                        line=self.line,
                        context=self.context)

                scripting.test_js_snippet(err=self.err,
                                          data=attr_value,
                                          filename=self.filename,
                                          line=self.line,
                                          context=self.context)

            elif (self.extension == "xul"
                  and attr_name in ("insertbefore", "insertafter") and any(
                      (id in attr_value)
                      for id in ("menu_pageSource", "menu_pageinspect",
                                 "javascriptConsole", "webConsole"))):
                self.err.notice(
                    err_id=("markup", "starttag", "incompatible_menu_items"),
                    notice="Menu item has been moved",
                    description="Your add-on has an overlay that uses the "
                    "insertbefore or insertafter attribute "
                    "pointing to menuitems that have been moved "
                    "to a different menu item. Your overlay items "
                    "may appear in unexpected locations because "
                    "of this. See https://bugzil.lz/653221 "
                    "for more information.",
                    filename=self.filename,
                    line=self.line,
                    context=self.context,
                    for_appversions=FX6_DEFINITION,
                    compatibility_type="warning")

            # Test for generic IDs
            if attr_name == "id" and attr_value in GENERIC_IDS:
                self.err.warning(
                    err_id=("markup", "starttag", "generic_ids"),
                    warning="Overlay contains generically-named IDs",
                    description="An overlay is using a generically-named ID "
                    "that could cause compatibility problems with "
                    "other add-ons. Add-ons must namespace all IDs "
                    "in the overlay, in the same way that "
                    "JavaScript objects must be namespaced.",
                    filename=self.filename,
                    line=self.line,
                    context=self.context)

        if tag == "script":
            self.xml_state_scripts.append(
                any((x[0] == "type" and "javascript" not in x[1])
                    for x in attrs))

        # When the dev forgets their <!-- --> on a script tag, bad
        # things happen.
        if "script" in self.xml_state and tag != "script":
            self._save_to_buffer("<" + tag + self._format_args(attrs) + ">")
            return

        self.xml_state.append(orig_tag)
        self.xml_line_stack.append(self.line)
        self.xml_buffer.append(unicode(""))
Esempio n. 9
0
    def handle_starttag(self, tag, attrs, self_closing=False):

        # Normalize!
        tag = tag.lower()
        # XUL scripts are identical to normal scripts. Treat them the same.
        if tag == 'xul:script':
            tag = 'script'

        orig_tag = tag

        # Be extra sure it's not a self-closing tag.
        if not self_closing:
            self_closing = tag in SELF_CLOSING_TAGS

        if DEBUG:  # pragma: no cover
            print 'S: ', self.xml_state, tag, self_closing

        # A fictional tag for testing purposes.
        if tag == 'xbannedxtestx':
            self.err.error(err_id=('markup', 'starttag', 'banned_element'),
                           error='Banned markup element',
                           description='A banned markup element was found.',
                           filename=self.filename,
                           line=self.line,
                           context=self.context)

        # Test for banned XBL in themes.
        if self.err.detected_type == PACKAGE_THEME:
            if tag.startswith('xbl:'):
                self.xbl = True
                tag = tag[4:]

            # Find XBL elements.
            if self.xbl:
                if tag in UNSAFE_THEME_XBL:
                    self.err.warning(
                        err_id=('markup', 'starttag',
                                'unsafe_theme_xbl_element'),
                        warning='Banned XBL element in theme.',
                        description=('Certain XBL elements are disallowed in '
                                     'full themes.',
                                     'Element: <xbl:%s>' % tag),
                        filename=self.filename,
                        line=self.line,
                        context=self.context)

                elif (tag == 'property'
                      and any(a[0] in (u'onset', u'onget') for a in attrs)):
                    self.err.warning(
                        err_id=('markup', 'starttag', 'theme_xbl_property'),
                        warning='Themes are not allowed to use XBL properties',
                        description='XBL properties cannot be used in themes.',
                        filename=self.filename,
                        line=self.line,
                        context=self.context)

        # Test for banned elements in language pack and theme markup.
        if self.err.detected_type in (PACKAGE_LANGPACK, PACKAGE_THEME):
            if (tag in UNSAFE_TAGS or (self.err.detected_type == PACKAGE_THEME
                                       and tag in UNSAFE_THEME_TAGS)):
                self.err.warning(
                    err_id=('markup', 'starttag', 'unsafe_langpack_theme'),
                    warning='Unsafe tag for add-on type',
                    description=('A tag in your markup has been marked as '
                                 'being potentially unsafe. Consider '
                                 'alternate means of accomplishing what the '
                                 'code executed by this tag performs.',
                                 'Tag "%s" is disallowed.' % tag),
                    filename=self.filename,
                    line=self.line,
                    context=self.context)

            # Make sure all src/href attributes are local
            if any(not self._is_url_local(attr[1]) for attr in attrs
                   if attr[0] in ('src', 'href')):
                self.err.warning(
                    err_id=('markup', 'starttag', 'remote_src_href'),
                    warning='`src`/`href` attributes must be local.',
                    description='Full Themes and language packs may not '
                    'reference remote resources.',
                    filename=self.filename,
                    line=self.line,
                    context=self.context)

        if tag == 'prefwindow':
            # Flag <prefwindow> elements without IDs.

            if not any((key == 'id') for key, val in attrs):
                self.err.warning(
                    err_id=('markup', 'starttag', 'prefwindow_id'),
                    warning='`<prefwindow>` elements must have IDs.',
                    description='`<prefwindow>` elements without `id` '
                    'attributes cause errors to be reported '
                    'in the error console and prevent '
                    'persistence of certain properties of the '
                    'dialog.',
                    filename=self.filename,
                    line=self.line,
                    context=self.context)

        elif tag in ('iframe', 'browser') and self.extension == 'xul':
            # Bork if XUL iframe has no type attribute

            type_ = None
            src = None
            for attr in attrs:
                attr_name = attr[0].lower()
                if attr_name == 'type':
                    type_ = attr[1].lower()
                elif attr_name == 'src':
                    src = attr[1].lower()

            # We say it's true by default to catch elements that are
            # type="chrome" without an src="" attribute.
            remote_src = True
            if isinstance(src, types.StringTypes):
                remote_src = not self._is_url_local(src)

            if (type_ and not (type_ in SAFE_IFRAME_TYPES or not remote_src)):
                self.err.warning(
                    ('markup', 'starttag', 'iframe_type_unsafe'),
                    'iframe/browser missing or unsafe `type` '
                    'attribute', 'All iframe and browser elements must have '
                    'either a valid and safe `type` attribute or a'
                    '`src` attribute that points to a local file.',
                    self.filename,
                    line=self.line,
                    context=self.context)
            elif ((not type_ or type_ not in SAFE_IFRAME_TYPES)
                  and remote_src):
                self.err.warning(
                    ('markup', 'starttag', 'iframe_type_unsafe'),
                    'Typeless iframes/browsers must be local.',
                    'iframe and browser elements that lack a type '
                    'attribute must always have src attributes '
                    'that reference local resources.',
                    self.filename,
                    line=self.line,
                    context=self.context)

        elif tag == 'script':
            # Per the Addon Validator Spec (v2), scripts
            # must not be remote.

            src = None
            for attr in attrs:
                if attr[0].lower() == 'src':
                    src = attr[1].lower()
                    break

            if src:
                if not self._is_url_local(src):
                    self.err.warning(
                        err_id=('markup', 'starttag', 'banned_remote_scripts'),
                        warning='Scripts must not be remote',
                        description='<script> tags must not be referenced to '
                        'script files that are hosted remotely.',
                        signing_help='Please do not attempt to load remote '
                        'scripts into any privileged contexts. '
                        'If you cannot avoid using remote '
                        'scripts, please consider loading a '
                        'remote document into an iframe, and '
                        'allow that document to load the '
                        'remote scripts that you need.',
                        signing_severity='high',
                        filename=self.filename,
                        line=self.line,
                        context=self.context)
                else:
                    self.found_scripts.add(src)

        # Find CSS and JS attributes and handle their values like they
        # would otherwise be handled by the standard parser flow.
        for attr in attrs:
            attr_name, attr_value = attr[0].lower(), attr[1]

            # We don't care about valueless attributes.
            if attr_value is None:
                continue

            if (attr_name == 'xmlns:xbl'
                    and attr_value == 'http://www.mozilla.org/xbl'):
                self.xbl = True

            # Test that an absolute URI isn't referenced in Jetpack 1.4.
            if (self.is_jetpack and attr_value.startswith('resource://')
                    and '-data/' in attr_value):
                self.err.warning(
                    err_id=('markup', 'starttag', 'jetpack_abs_uri'),
                    warning='Absolute URI referenced in Jetpack 1.4',
                    description=('As of Jetpack 1.4, absolute URIs are no '
                                 'longer allowed within add-ons.',
                                 'See %s for more information.' %
                                 JETPACK_URI_URL),
                    filename=self.filename,
                    line=self.line,
                    context=self.context,
                    compatibility_type='error')

            if (self.err.detected_type == PACKAGE_THEME
                    and attr_value.startswith(('data:', 'javascript:'))):

                self.err.warning(
                    err_id=('markup', 'starttag', 'theme_attr_prefix'),
                    warning='Attribute contains banned prefix',
                    description=("A mark element's attribute contains a "
                                 'prefix which is not allowed in full '
                                 'themes.', 'Attribute: %s' % attr_name),
                    filename=self.filename,
                    line=self.line,
                    context=self.context)

            if attr_name == 'style':
                csstester.test_css_snippet(self.err, self.filename, attr_value,
                                           self.line)
            elif attr_name.startswith('on'):  # JS attribute
                # Warn about DOM mutation event handlers.
                if attr_name in DOM_MUTATION_HANDLERS:
                    self.err.warning(
                        err_id=('markup', 'starttag',
                                'dom_manipulation_handler'),
                        warning='DOM Mutation Events Prohibited',
                        description='DOM mutation events are deprecated and '
                        'have severe performance implications. '
                        'Please use mutation observers instead: '
                        'https://developer.mozilla.org/docs/Web/'
                        'API/MutationObserver',
                        filename=self.filename,
                        line=self.line,
                        context=self.context)

                scripting.test_js_snippet(err=self.err,
                                          data=attr_value,
                                          filename=self.filename,
                                          line=self.line,
                                          context=self.context)

            # Test for generic IDs
            if attr_name == 'id' and attr_value in GENERIC_IDS:
                self.err.warning(
                    err_id=('markup', 'starttag', 'generic_ids'),
                    warning='Overlay contains generically-named IDs',
                    description='An overlay is using a generically-named ID '
                    'that could cause compatibility problems with '
                    'other add-ons. Add-ons must namespace all IDs '
                    'in the overlay, in the same way that '
                    'JavaScript objects must be namespaced.',
                    filename=self.filename,
                    line=self.line,
                    context=self.context)

        if tag == 'script':
            self.xml_state_scripts.append(
                any((x[0] == 'type' and 'javascript' not in x[1])
                    for x in attrs))

        # When the dev forgets their <!-- --> on a script tag, bad
        # things happen.
        if 'script' in self.xml_state and tag != 'script':
            self._save_to_buffer('<' + tag + self._format_args(attrs) + '>')
            return

        self.xml_state.append(orig_tag)
        self.xml_line_stack.append(self.line)
        self.xml_buffer.append(unicode(''))
Esempio n. 10
0
    def handle_starttag(self, tag, attrs, self_closing=False):

        # Normalize!
        tag = tag.lower()
        # XUL scripts are identical to normal scripts. Treat them the same.
        if tag == "xul:script":
            tag = "script"

        orig_tag = tag

        # Be extra sure it's not a self-closing tag.
        if not self_closing:
            self_closing = tag in SELF_CLOSING_TAGS

        if DEBUG:  # pragma: no cover
            print "S: ", self.xml_state, tag, self_closing

        # A fictional tag for testing purposes.
        if tag == "xbannedxtestx":
            self.err.error(
                err_id=("markup", "starttag", "banned_element"),
                error="Banned markup element",
                description="A banned markup element was found.",
                filename=self.filename,
                line=self.line,
                context=self.context)

        # Test for banned XBL in themes.
        if self.err.detected_type == PACKAGE_THEME:
            if tag.startswith("xbl:"):
                self.xbl = True
                tag = tag[4:]

            # Find XBL elements.
            if self.xbl:
                if tag in UNSAFE_THEME_XBL:
                    self.err.warning(
                        err_id=("markup", "starttag",
                                "unsafe_theme_xbl_element"),
                        warning="Banned XBL element in theme.",
                        description=["Certain XBL elements are disallowed in "
                                     "full themes.",
                                     "Element: <xbl:%s>" % tag],
                        filename=self.filename,
                        line=self.line,
                        context=self.context)

                elif (tag == "property" and
                      any(a[0] in (u"onset", u"onget") for a in attrs)):
                    self.err.warning(
                        err_id=("markup", "starttag",
                                "theme_xbl_property"),
                        warning="Themes are not allowed to use XBL properties",
                        description="XBL properties cannot be used in themes.",
                        filename=self.filename,
                        line=self.line,
                        context=self.context)

        # Test for banned elements in language pack and theme markup.
        if self.err.detected_type in (PACKAGE_LANGPACK, PACKAGE_THEME):
            if (tag in UNSAFE_TAGS or
                (self.err.detected_type == PACKAGE_THEME and
                 tag in UNSAFE_THEME_TAGS)):
                self.err.warning(
                    err_id=("markup", "starttag", "unsafe_langpack_theme"),
                    warning="Unsafe tag for add-on type",
                    description=["A tag in your markup has been marked as "
                                 "being potentially unsafe. Consider "
                                 "alternate means of accomplishing what the "
                                 "code executed by this tag performs.",
                                 'Tag "%s" is disallowed.' % tag],
                    filename=self.filename,
                    line=self.line,
                    context=self.context)

            # Make sure all src/href attributes are local
            if any(not self._is_url_local(attr[1]) for attr in attrs if
                   attr[0] in ("src", "href")):
                self.err.warning(
                    err_id=("markup", "starttag", "remote_src_href"),
                    warning="`src`/`href` attributes must be local.",
                    description="Full Themes and language packs may not "
                                "reference remote resources.",
                    filename=self.filename,
                    line=self.line,
                    context=self.context)

        if tag == "prefwindow":
            # Flag <prefwindow> elements without IDs.

            if not any((key == "id") for key, val in attrs):
                self.err.warning(
                        err_id=("markup", "starttag", "prefwindow_id"),
                        warning="`<prefwindow>` elements must have IDs.",
                        description="`<prefwindow>` elements without `id` "
                                    "attributes cause errors to be reported "
                                    "in the error console and prevent "
                                    "persistence of certain properties of the "
                                    "dialog.",
                        filename=self.filename,
                        line=self.line,
                        context=self.context)

        elif tag in ("iframe", "browser") and self.extension == "xul":
            # Bork if XUL iframe has no type attribute

            type_ = None
            src = None
            for attr in attrs:
                attr_name = attr[0].lower()
                if attr_name == "type":
                    type_ = attr[1].lower()
                elif attr_name == "src":
                    src = attr[1].lower()

            # We say it's true by default to catch elements that are
            # type="chrome" without an src="" attribute.
            remote_src = True
            if isinstance(src, types.StringTypes):
                remote_src = not self._is_url_local(src)

            if (type_ and
                not (type_ in SAFE_IFRAME_TYPES or
                     not remote_src)):
                self.err.warning(("markup", "starttag", "iframe_type_unsafe"),
                                 "iframe/browser missing 'type' attribute",
                                 "All iframe and browser elements must have "
                                 "either a valid `type` attribute or a `src` "
                                 "attribute that points to a local file.",
                                 self.filename,
                                 line=self.line,
                                 context=self.context)
            elif ((not type_ or
                   type_ not in SAFE_IFRAME_TYPES) and
                  remote_src):
                self.err.warning(("markup", "starttag", "iframe_type_unsafe"),
                                 "Typeless iframes/browsers must be local.",
                                 "iframe and browser elements that lack a type "
                                 "attribute must always have src attributes "
                                 "that reference local resources.",
                                 self.filename,
                                 line=self.line,
                                 context=self.context)

        elif tag == "script" and self.extension == "xul":
            # Per the Addon Validator Spec (v2), scripts in XUL
            # must not be remote.

            src = None
            for attr in attrs:
                if attr[0].lower() == "src":
                    src = attr[1].lower()
                    break

            if src:
                if not self._is_url_local(src):
                    self.err.warning(
                        err_id=("markup", "starttag",
                                "banned_remote_scripts"),
                        warning="Scripts must not be remote in XUL",
                        description="In XUL, <script> tags must not be "
                                    "referenced to script files that are "
                                    "hosted remotely.",
                        filename=self.filename,
                        line=self.line,
                        context=self.context)
                else:
                    self.found_scripts.add(src)

        # Find CSS and JS attributes and handle their values like they
        # would otherwise be handled by the standard parser flow.
        for attr in attrs:
            attr_name, attr_value = attr[0].lower(), attr[1]

            # We don't care about valueless attributes.
            if attr_value is None:
                continue

            if (attr_name == "xmlns:xbl" and
                attr_value == "http://www.mozilla.org/xbl"):
                self.xbl = True

            # Test that an absolute URI isn't referenced in Jetpack 1.4.
            if (self.is_jetpack and
                attr_value.startswith("resource://") and
                "-data/" in attr_value):
                self.err.warning(
                        err_id=("markup", "starttag",
                                "jetpack_abs_uri"),
                        warning="Absolute URI referenced in Jetpack 1.4",
                        description=["As of Jetpack 1.4, absolute URIs are no "
                                     "longer allowed within add-ons.",
                                     "See %s for more information." %
                                         JETPACK_URI_URL],
                        filename=self.filename,
                        line=self.line,
                        context=self.context,
                        compatibility_type="error")

            if (self.err.detected_type == PACKAGE_THEME and
                attr_value.startswith(("data:", "javascript:"))):

                self.err.warning(
                        err_id=("markup", "starttag",
                                "theme_attr_prefix"),
                        warning="Attribute contains banned prefix",
                        description=["A mark element's attribute contains a "
                                     "prefix which is not allowed in full "
                                     "themes.",
                                     "Attribute: %s" % attr_name],
                        filename=self.filename,
                        line=self.line,
                        context=self.context)

            if attr_name == "style":
                csstester.test_css_snippet(self.err,
                                           self.filename,
                                           attr_value,
                                           self.line)
            elif attr_name.startswith("on"):  # JS attribute
                # Warn about DOM mutation event handlers.
                if attr_name in DOM_MUTATION_HANDLERS:
                    self.err.warning(
                        err_id=("markup", "starttag",
                                "dom_manipulation_handler"),
                        warning="DOM Mutation Events Prohibited",
                        description="DOM mutation events are flagged because "
                                    "of their deprecated status, as well as "
                                    "their extreme inefficiency. Consider "
                                    "using a different event.",
                        filename=self.filename,
                        line=self.line,
                        context=self.context)

                scripting.test_js_snippet(
                    err=self.err, data=attr_value,
                    filename=self.filename, line=self.line,
                    context=self.context)

            elif (self.extension == "xul" and
                  attr_name in ("insertbefore", "insertafter") and
                  any((id in attr_value) for id in ("menu_pageSource",
                                                    "menu_pageinspect",
                                                    "javascriptConsole",
                                                    "webConsole"))):
                self.err.notice(
                    err_id=("markup", "starttag",
                            "incompatible_menu_items"),
                    notice="Menu item has been moved",
                    description="Your add-on has an overlay that uses the "
                                "insertbefore or insertafter attribute "
                                "pointing to menuitems that have been moved "
                                "to a different menu item. Your overlay items "
                                "may appear in unexpected locations because "
                                "of this. See "
                        "https://bugzilla.mozilla.org/show_bug.cgi?id=653221"
                                " for more information.",
                    filename=self.filename,
                    line=self.line,
                    context=self.context,
                    for_appversions=FX6_DEFINITION,
                    compatibility_type="warning")


            # Test for generic IDs
            if attr_name == "id" and attr_value in GENERIC_IDS:
                self.err.warning(
                    err_id=("markup",
                            "starttag", "generic_ids"),
                    warning="Overlay contains generically-named IDs",
                    description="An overlay is using a generically-named ID "
                                "that could cause compatibility problems with "
                                "other add-ons. Add-ons must namespace all IDs "
                                "in the overlay, in the same way that "
                                "JavaScript objects must be namespaced.",
                    filename=self.filename,
                    line=self.line,
                    context=self.context)

        if tag == "script":
            self.xml_state_scripts.append(any(
                (x[0] == "type" and "javascript" not in x[1]) for x in attrs))

        # When the dev forgets their <!-- --> on a script tag, bad
        # things happen.
        if "script" in self.xml_state and tag != "script":
            self._save_to_buffer("<" + tag + self._format_args(attrs) + ">")
            return

        self.xml_state.append(orig_tag)
        self.xml_line_stack.append(self.line)
        self.xml_buffer.append(unicode(""))
Esempio n. 11
0
    def handle_starttag(self, tag, attrs, self_closing=False):

        # Normalize!
        tag = tag.lower()
        # XUL scripts are identical to normal scripts. Treat them the same.
        if tag == 'xul:script':
            tag = 'script'

        orig_tag = tag

        # Be extra sure it's not a self-closing tag.
        if not self_closing:
            self_closing = tag in SELF_CLOSING_TAGS

        if DEBUG:  # pragma: no cover
            print 'S: ', self.xml_state, tag, self_closing

        # A fictional tag for testing purposes.
        if tag == 'xbannedxtestx':
            self.err.error(
                err_id=('markup', 'starttag', 'banned_element'),
                error='Banned markup element',
                description='A banned markup element was found.',
                filename=self.filename,
                line=self.line,
                context=self.context)

        # Test for banned XBL in themes.
        if self.err.detected_type == PACKAGE_THEME:
            if tag.startswith('xbl:'):
                self.xbl = True
                tag = tag[4:]

            # Find XBL elements.
            if self.xbl:
                if tag in UNSAFE_THEME_XBL:
                    self.err.warning(
                        err_id=('markup', 'starttag',
                                'unsafe_theme_xbl_element'),
                        warning='Banned XBL element in theme.',
                        description=('Certain XBL elements are disallowed in '
                                     'full themes.',
                                     'Element: <xbl:%s>' % tag),
                        filename=self.filename,
                        line=self.line,
                        context=self.context)

                elif (tag == 'property' and
                      any(a[0] in (u'onset', u'onget') for a in attrs)):
                    self.err.warning(
                        err_id=('markup', 'starttag',
                                'theme_xbl_property'),
                        warning='Themes are not allowed to use XBL properties',
                        description='XBL properties cannot be used in themes.',
                        filename=self.filename,
                        line=self.line,
                        context=self.context)

        # Test for banned elements in language pack and theme markup.
        if self.err.detected_type in (PACKAGE_LANGPACK, PACKAGE_THEME):
            if (tag in UNSAFE_TAGS or
                (self.err.detected_type == PACKAGE_THEME and
                 tag in UNSAFE_THEME_TAGS)):
                self.err.warning(
                    err_id=('markup', 'starttag', 'unsafe_langpack_theme'),
                    warning='Unsafe tag for add-on type',
                    description=('A tag in your markup has been marked as '
                                 'being potentially unsafe. Consider '
                                 'alternate means of accomplishing what the '
                                 'code executed by this tag performs.',
                                 'Tag "%s" is disallowed.' % tag),
                    filename=self.filename,
                    line=self.line,
                    context=self.context)

            # Make sure all src/href attributes are local
            if any(not self._is_url_local(attr[1]) for attr in attrs if
                   attr[0] in ('src', 'href')):
                self.err.warning(
                    err_id=('markup', 'starttag', 'remote_src_href'),
                    warning='`src`/`href` attributes must be local.',
                    description='Full Themes and language packs may not '
                                'reference remote resources.',
                    filename=self.filename,
                    line=self.line,
                    context=self.context)

        if tag == 'prefwindow':
            # Flag <prefwindow> elements without IDs.

            if not any((key == 'id') for key, val, pos in attrs):
                self.err.warning(
                    err_id=('markup', 'starttag', 'prefwindow_id'),
                    warning='`<prefwindow>` elements must have IDs.',
                    description='`<prefwindow>` elements without `id` '
                                'attributes cause errors to be reported '
                                'in the error console and prevent '
                                'persistence of certain properties of the '
                                'dialog.',
                    filename=self.filename,
                    line=self.line,
                    context=self.context)

        elif tag in ('iframe', 'browser') and self.extension == 'xul':
            # Bork if XUL iframe has no type attribute

            type_ = None
            src = None
            for attr in attrs:
                attr_name = attr[0].lower()
                if attr_name == 'type':
                    type_ = attr[1].lower()
                elif attr_name == 'src':
                    src = attr[1].lower()

            # We say it's true by default to catch elements that are
            # type="chrome" without an src="" attribute.
            remote_src = True
            if isinstance(src, types.StringTypes):
                remote_src = not self._is_url_local(src)

            if (type_ and
                not (type_ in SAFE_IFRAME_TYPES or
                     not remote_src)):
                self.err.warning(('markup', 'starttag', 'iframe_type_unsafe'),
                                 "iframe/browser missing 'type' attribute",
                                 'All iframe and browser elements must have '
                                 'either a valid `type` attribute or a `src` '
                                 'attribute that points to a local file.',
                                 self.filename,
                                 line=self.line,
                                 context=self.context)
            elif ((not type_ or
                   type_ not in SAFE_IFRAME_TYPES) and
                  remote_src):
                self.err.warning(('markup', 'starttag', 'iframe_type_unsafe'),
                                 'Typeless iframes/browsers must be local.',
                                 'iframe and browser elements that lack a '
                                 'type attribute must always have src '
                                 'attributes that reference local resources.',
                                 self.filename,
                                 line=self.line,
                                 context=self.context)

        elif tag == 'script':
            # Per the Addon Validator Spec (v2), scripts
            # must not be remote.

            src = None
            for attr in attrs:
                if attr[0].lower() == 'src':
                    src = attr[1].lower()
                    break

            if src:
                if not self._is_url_local(src):
                    self.err.warning(
                        err_id=('markup', 'starttag',
                                'banned_remote_scripts'),
                        warning='Scripts must not be remote',
                        description='<script> tags must not be referenced to '
                                    'script files that are hosted remotely.',
                        signing_help='Please do not attempt to load remote '
                                     'scripts into any privileged contexts. '
                                     'If you cannot avoid using remote '
                                     'scripts, please consider loading a '
                                     'remote document into an iframe, and '
                                     'allow that document to load the '
                                     'remote scripts that you need.',
                        signing_severity='high',
                        filename=self.filename,
                        line=self.line,
                        context=self.context)
                else:
                    self.err.add_script_load(self.filename, src)
                    self.found_scripts.add(src)

        # Find CSS and JS attributes and handle their values like they
        # would otherwise be handled by the standard parser flow.
        for attr in attrs:
            attr_name, attr_value = attr[0].lower(), attr[1]
            position = attr[2]

            # We don't care about valueless attributes.
            if attr_value is None:
                continue

            if (attr_name == 'xmlns:xbl' and
                    attr_value == 'http://www.mozilla.org/xbl'):
                self.xbl = True

            if (self.err.detected_type == PACKAGE_THEME and
                    attr_value.startswith(('data:', 'javascript:'))):

                self.err.warning(
                    err_id=('markup', 'starttag',
                            'theme_attr_prefix'),
                    warning='Attribute contains banned prefix',
                    description=("A mark element's attribute contains a "
                                 'prefix which is not allowed in full '
                                 'themes.',
                                 'Attribute: %s' % attr_name),
                    filename=self.filename,
                    line=self.line,
                    context=self.context)

            if attr_name == 'style':
                csstester.test_css_snippet(self.err,
                                           self.filename,
                                           attr_value,
                                           self.line)
            elif attr_name.startswith('on'):  # JS attribute
                # Warn about DOM mutation event handlers.
                if attr_name in DOM_MUTATION_HANDLERS:
                    self.err.warning(
                        err_id=('markup', 'starttag',
                                'dom_manipulation_handler'),
                        warning='DOM Mutation Events Prohibited',
                        description='DOM mutation events are deprecated and '
                                    'have severe performance implications. '
                                    'Please use mutation observers instead: '
                                    'https://developer.mozilla.org/docs/Web/'
                                    'API/MutationObserver',
                        filename=self.filename,
                        line=self.line,
                        context=self.context)

                self.err.add_script_load(self.filename, self.filename)
                scripting.test_js_snippet(
                    err=self.err, data=attr_value,
                    filename=self.filename, line=position[0],
                    column=position[1], context=self.context)

            # Test for generic IDs
            if attr_name == 'id' and attr_value in GENERIC_IDS:
                self.err.warning(
                    err_id=('markup',
                            'starttag', 'generic_ids'),
                    warning='Overlay contains generically-named IDs',
                    description='An overlay is using a generically-named ID '
                                'that could cause compatibility problems with '
                                'other add-ons. Add-ons must namespace all '
                                'IDs in the overlay, in the same way that '
                                'JavaScript objects must be namespaced.',
                    filename=self.filename,
                    line=self.line,
                    context=self.context)

        if tag == 'script':
            self.xml_state_scripts.append(any(
                (x[0] == 'type' and 'javascript' not in x[1]) for x in attrs))

        # When the dev forgets their <!-- --> on a script tag, bad
        # things happen.
        if 'script' in self.xml_state and tag != 'script':
            self._save_to_buffer('<' + tag + self._format_args(attrs) + '>')
            return

        self.xml_state.append(orig_tag)
        self.xml_line_stack.append(self.line)
        self.xml_position_stack.append(None)
        self.xml_buffer.append(unicode(''))
Esempio n. 12
0
 def handle_starttag(self, tag, attrs, self_closing=False):
     
     # Normalize!
     tag = tag.lower()
     
     # Be extra sure it's not a self-closing tag.
     if not self_closing:
         self_closing = tag in SELF_CLOSING_TAGS
     
     if DEBUG: # pragma: no cover
         print self.xml_state, tag, self_closing
     
     # A fictional tag for testing purposes.
     if tag == "xbannedxtestx":
         self.err.error(("testcases_markup_markuptester",
                         "handle_starttag",
                         "banned_element"),
                        "Banned element",
                        "A banned element was detected",
                        self.filename,
                        line=self.line,
                        context=self.context)
     
     if self.err.detected_type == PACKAGE_LANGPACK:
         
         if tag in UNSAFE_TAGS:
             self.err.warning(("testcases_markup_markuptester",
                               "handle_starttag",
                               "unsafe_langpack"),
                              "Unsafe tag in language pack",
                              ["""A tag in your markup has been marked
                               as being potentially unsafe. Consider
                               alternate means of accomplishing what
                               the code executed by this tag
                               performs.""",
                               'Tag "%s" is disallowed.' % tag],
                              self.filename,
                              line=self.line,
                              context=self.context)
             if DEBUG: # pragma: no cover
                 print "Unsafe Tag ------"
         
         # Make sure all src/href attributes are local
         for attr in attrs:
             if attr[0].lower() in ("src", "href") and \
                not self._is_url_local(attr[1].lower()):
                 self.err.warning(("testcases_markup_markuptester",
                                   "handle_starttag",
                                   "remote_src_href"),
                                  "src/href attributes must be local.",
                                  "Language packs require that all src and "
                                  "href attributes are relative URLs.",
                                  self.filename,
                                  line=self.line,
                                  context=self.context)
                 self.err.reject = True
     
     if tag in ("iframe", "browser") and self.extension == "xul":
         # Bork if XUL iframe has no type attribute
         
         type_ = None
         src = None
         for attr in attrs:
             attr_name = attr[0].lower()
             if attr_name == "type":
                 type_ = attr[1].lower()
             elif attr_name == "src":
                 src = attr[1].lower()
         
         # We say it's true by default to catch elements that are
         # type="chrome" without an src="" attribute.
         remote_src = True
         if isinstance(src, str):
             remote_src = not self._is_url_local(src)
             
         if type_ and \
            not (type_ in SAFE_IFRAME_TYPES or 
                 not remote_src):
             self.err.warning(("testcases_markup_markuptester",
                               "handle_starttag",
                               "iframe_type_unsafe"),
                              "iframe/browser missing 'type' attribute",
                              """All iframe and browser elements must have
                              either a valid `type` attribute or a `src`
                              attribute that points to a local file.""",
                              self.filename,
                              line=self.line,
                              context=self.context)
         elif (not type_ or 
               type_ not in SAFE_IFRAME_TYPES) and \
              remote_src:
             self.err.warning(("testcases_markup_markuptester",
                               "handle_starttag",
                               "iframe_type_unsafe"),
                              "Typeless iframes/browsers must be local.",
                              """iframe and browser elements that lack a
                              type attribute must always have src
                              attributes that reference local
                              resources.""",
                              self.filename,
                              line=self.line,
                              context=self.context)
         
     elif tag == "script" and self.extension == "xul":
         # Per the Addon Validator Spec (v2), scripts in XUL
         # must not be remote.
         
         src = None
         for attr in attrs:
             if attr[0].lower() == "src":
                 src = attr[1].lower()
         
         if src and not self._is_url_local(src):
             self.err.warning(("testcases_markup_markuptester",
                               "handle_starttag",
                               "banned_remote_scripts"),
                              "Scripts must not be remote in XUL",
                              """In XUL, <script> tags must not be
                              referenced to script files that are
                              hosted remotely.""",
                              self.filename,
                              line=self.line,
                              context=self.context)
     
     # Find CSS and JS attributes and handle their values like they
     # would otherwise be handled by the standard parser flow.
     for attr in attrs:
         attr_name = attr[0].lower()
         if attr_name == "style":
             csstester.test_css_snippet(self.err,
                                        self.filename,
                                        attr[1],
                                        self.line)
         elif attr_name.startswith("on"): # JS attribute
             scripting.test_js_snippet(err=self.err,
                                       data=attr[1],
                                       filename=self.filename)
     
     # When the dev forgets their <!-- --> on a script tag, bad
     # things happen.
     if "script" in self.xml_state and tag != "script":
         self._save_to_buffer("<" + tag + self._format_args(attrs) + ">")
         return
     
     self.xml_state.append(tag)
     self.xml_buffer.append("")
    def handle_endtag(self, tag):

        tag = tag.lower()
        if tag == 'xul:script':
            tag = 'script'

        if tag == 'script' and len(self.xml_buffer[-1]) > 1000:
            self.err.warning(('markup', 'complex_script'),
                             'Long inline script',
                             'Please store complex scripts in .js files '
                             'rather than inline script nodes.',
                             self.filename,
                             line=self.line,
                             context=self.context,
                             tier=2)

        if DEBUG:  # pragma: no cover
            print 'E: ', tag, self.xml_state

        if not self.xml_state:
            if 'closing_tags' in self.reported or not self.strict:
                if DEBUG:
                    print 'Unstrict; extra closing tags ------'
                return
            self.err.warning(('markup',
                              'endtag',
                              'extra_closing_tags'),
                             'Markup parsing error',
                             'The markup file has more closing tags than it '
                             'has opening tags.',
                             self.filename,
                             line=self.line,
                             context=self.context,
                             tier=2)
            self.reported.add('closing_tags')
            if DEBUG:  # pragma: no cover
                print 'Too many closing tags ------'
            return

        elif 'script' in self.xml_state[:-1]:
            # If we're in a script tag, nothing else matters. Just rush
            # everything possible into the xml buffer.

            self._save_to_buffer('</' + tag + '>')
            if DEBUG:
                print 'Markup as text in script ------'
            return

        elif tag not in self.xml_state:
            # If the tag we're processing isn't on the stack, then
            # something is wrong.
            self.err.warning(('markup',
                              'endtag',
                              'extra_closing_tags'),
                             'Parse error: tag closed before opened',
                             ['Markup tags cannot be closed before they are '
                              'opened. Perhaps you were just a little '
                              'overzealous with forward-slashes?',
                              'Tag "%s" closed before it was opened' % tag],
                             self.filename,
                             line=self.line,
                             context=self.context,
                             tier=2)
            if DEBUG:  # pragma: no cover
                print 'Tag closed before opened ------'
            return

        data_buffer = self.xml_buffer.pop()
        old_state = self.xml_state.pop()
        old_line = self.xml_line_stack.pop()
        script_type = True
        if old_state == 'script':
            script_type = self.xml_state_scripts.pop()

        # If the tag on the stack isn't what's being closed and it also
        # classifies as a self-closing tag, we just recursively close
        # down to the level of the tag we're actualy closing.
        if old_state != tag and old_state in SELF_CLOSING_TAGS:
            if DEBUG:
                print 'Self closing tag cascading down ------'
            return self.handle_endtag(tag)

        # If this is an XML-derived language, everything must nest
        # properly. No overlapping tags.
        if (old_state != tag and
            self.extension[0] == 'x' and
            not self.strict):

            self.err.warning(('markup',
                              'endtag',
                              'invalid_nesting'),
                             'Markup invalidly nested',
                             'It has been determined that the document '
                             'invalidly nests its tags. This is not permitted '
                             'in the specified document type.',
                             self.filename,
                             line=self.line,
                             context=self.context,
                             tier=2)
            if DEBUG:  # pragma: no cover
                print 'Invalid markup nesting ------'

        data_buffer = data_buffer.strip()

        # Perform analysis on collected data.
        if data_buffer:
            if tag == 'script' and not script_type:
                scripting.test_js_snippet(err=self.err, data=data_buffer,
                                          filename=self.filename,
                                          line=old_line, context=self.context)
            elif tag == 'style':
                csstester.test_css_file(self.err, self.filename, data_buffer,
                                        old_line)