def check_qtwebkit(self):
        '''Check that QML applications don't use QtWebKit'''
        if not self.is_click and not self.is_snap1:
            return

        t = 'info'
        n = self._get_check_name('qml_application_uses_QtWebKit')
        s = "OK"
        link = None

        qmls = []
        pat_mv = re.compile(r'\n\s*import\s+QtWebKit')
        for i in self.qml_files:
            qml = open_file_read(i).read()
            if pat_mv.search(qml):
                qmls.append(os.path.relpath(i, self.unpack_dir))

        if len(qmls) > 0:
            t = 'warn'
            s = "Found files that use unsupported QtWebKit (should use " + \
                "UbuntuWebview (Ubuntu.Components.Extras.Browser >= " + \
                "0.2) or Oxide instead): %s" % " ,".join(qmls)
            link = "http://askubuntu.com/questions/417342/what-does-functional-qml-application-uses-qtwebkit-mean/417343"

        self._add_result(t, n, s, link)

        t = 'info'
        n = self._get_check_name('qml_application_uses_UbuntuWebView_0.2')
        s = "OK"
        link = None

        if self.manifest is not None and \
                self.manifest['framework'] == "ubuntu-sdk-13.10":
            s = "SKIPPED (Oxide not available in ubuntu-sdk-13.10)"
        else:
            qmls = []
            pat_mv = re.compile(
                r'\n\s*import\s+Ubuntu\.Components\.Extras\.Browser\s+0\.1\s*\n'
            )
            for i in self.qml_files:
                qml = open_file_read(i).read()
                if pat_mv.search(qml):
                    qmls.append(os.path.relpath(i, self.unpack_dir))

            if len(qmls) > 0:
                t = 'warn'
                s = "Found files that use unsupported QtWebKit via " + \
                    "'Ubuntu.Components.Extras.Browser 0.1' (should use " + \
                    "Ubuntu.Components.Extras.Browser >= 0.2 or " + \
                    "Oxide instead): %s" % " ,".join(qmls)
                link = "http://askubuntu.com/questions/417342/what-does-functional-qml-application-uses-qtwebkit-mean/417343"

        self._add_result(t, n, s, link)
    def _extract_framework_policy(self):
        '''Get framework policy files'''
        policy_dict = dict()
        unknown = []
        fpdir = os.path.join(self.unpack_dir, "meta", "framework-policy")
        for i in glob.glob("%s/*" % fpdir):
            rel_i = os.path.basename(i)
            if not os.path.isdir(i) or rel_i not in self.framework_policy_dirs:
                unknown.append(os.path.relpath(i, self.unpack_dir))
                continue

            policy_dict[rel_i] = dict()
            for j in glob.glob("%s/*" % i):
                rel_j = os.path.basename(j)
                if not os.path.isdir(j) or \
                   rel_j not in self.framework_policy_subdirs:
                    unknown.append(os.path.relpath(j, self.unpack_dir))
                    continue

                policy_dict[rel_i][rel_j] = dict()
                for k in glob.glob("%s/*" % j):
                    rel_k = os.path.basename(k)
                    if not os.path.isfile(k):
                        unknown.append(os.path.relpath(k, self.unpack_dir))
                        continue

                    fh = open_file_read(k)
                    policy_dict[rel_i][rel_j][rel_k] = fh.read()
                    fh.close()
        return (policy_dict, unknown)
示例#3
0
    def _extract_push_helper(self, app):
        '''Get push-helper hook content'''
        c = self.manifest['hooks'][app]['push-helper']
        fn = os.path.join(self.unpack_dir, c)

        bn = os.path.basename(fn)
        if not os.path.exists(fn):
            error("Could not find '%s'" % bn)

        fh = open_file_read(fn)
        contents = ""
        for line in fh.readlines():
                contents += line
        fh.close()

        try:
            jd = json.loads(contents)
        except Exception as e:
            error("push-helper json unparseable: %s (%s):\n%s" % (bn,
                  str(e), contents))

        if not isinstance(jd, dict):
            error("push-helper json is malformed: %s:\n%s" % (bn, contents))

        return (fn, jd)
    def check_desktop_duplicate_entries(self):
        '''Check desktop for duplicate entries'''
        if not self.is_click and not self.is_snap1:
            return

        for app in sorted(self.desktop_entries):
            found = []
            dupes = []
            t = 'info'
            n = self._get_check_name('duplicate_keys', app=app)
            s = 'OK'
            fn = self._get_desktop_filename(app)
            content = open_file_read(fn).readlines()
            for line in content:
                tmp = line.split('=')
                if len(tmp) < 2:
                    continue
                if tmp[0] in found:
                    dupes.append(tmp[0])
                else:
                    found.append(tmp[0])
            if len(dupes) > 0:
                t = 'error'
                s = 'found duplicate keys: %s' % ",".join(dupes)
            self._add_result(t, n, s)
    def _extract_desktop_entry(self, app):
        '''Get DesktopEntry for desktop file and verify it'''
        d = self.manifest['hooks'][app]['desktop']
        fn = os.path.join(self.unpack_dir, d)

        bn = os.path.basename(fn)
        if not os.path.exists(fn):
            error("Could not find '%s'" % bn)

        fh = open_file_read(fn)
        contents = ""
        for line in fh.readlines():
            contents += line
        fh.close()

        try:
            de = DesktopEntry(fn)
        except xdgParsingError as e:
            error("desktop file unparseable: %s (%s):\n%s" %
                  (bn, str(e), contents))
        try:
            de.parse(fn)
        except Exception as e:
            error("desktop file unparseable: %s (%s):\n%s" %
                  (bn, str(e), contents))
        return de, fn
    def _extract_url_dispatcher(self, app):
        '''Get url dispatcher json'''
        u = self.manifest['hooks'][app]['urls']
        if not u:
            error("'urls' definition is empty for '%s'" % app)
        fn = os.path.join(self.unpack_dir, u)
        if not os.path.isfile(fn):
            error("'%s' is not a file" % fn)

        bn = os.path.basename(fn)
        if not os.path.exists(fn):
            error("Could not find '%s'" % bn)

        fh = open_file_read(fn)
        contents = ""
        for line in fh.readlines():
            contents += line
        fh.close()

        try:
            jd = json.loads(contents)
        except Exception as e:
            error("url-dispatcher json unparseable: %s (%s):\n%s" % (bn,
                  str(e), contents))

        if not isinstance(jd, list):
            error("url-dispatcher json is malformed: %s:\n%s" % (bn, contents))

        return (fn, jd)
    def _extract_webapp_manifests(self):
        '''Extract webapp manifest file'''
        files = sorted(
            glob.glob("%s/unity-webapps-*/manifest.json" % self.unpack_dir))

        manifests = dict()
        for fn in files:
            key = os.path.relpath(fn, self.unpack_dir)
            try:
                manifests[key] = json.load(open_file_read(fn))
            except Exception:
                manifests[key] = None
                error("Could not parse '%s'" % fn, do_exit=False)

        return manifests
    def _extract_framework(self, app):
        '''Get framework for app'''
        rel = self.manifest['hooks'][app]['framework']
        fn = os.path.join(self.unpack_dir, rel)
        if not os.path.exists(fn):
            error("Could not find '%s'" % rel)

        data = dict()
        fh = open_file_read(fn)
        for line in fh.readlines():
            tmp = line.split(':')
            if len(tmp) != 2:
                continue
            data[tmp[0].strip()] = tmp[1].strip()
        fh.close()

        return (fn, data)
示例#9
0
    def _extract_account(self, app, account_type):
        '''Extract accounts'''
        if self.manifest is None:
            return

        a = self.manifest['hooks'][app][account_type]
        fn = os.path.join(self.unpack_dir, a)

        bn = os.path.basename(fn)
        if not os.path.exists(fn):
            error("Could not find '%s'" % bn)

        # qml-plugin points to a QML file, so just set that we have the
        # the hook present for now
        if account_type == "account-qml-plugin":
            return (fn, True)
        elif account_type == "accounts":
            fh = open_file_read(fn)
            contents = ""
            for line in fh.readlines():
                contents += line
            fh.close()

            try:
                jd = json.loads(contents)
            except Exception as e:
                error("accounts json unparseable: %s (%s):\n%s" %
                      (bn, str(e), contents))

            if not isinstance(jd, dict):
                error("accounts json is malformed: %s:\n%s" % (bn, contents))

            return (fn, jd)
        else:
            try:
                tree = etree.parse(fn)
                xml = tree.getroot()
            except Exception as e:
                error("accounts xml unparseable: %s (%s)" % (bn, str(e)))
            return (fn, xml)
    def check_friends(self):
        '''Check that QML applications don't use deprecated Friends API'''
        if not self.is_click and not self.is_snap1:
            return

        t = 'info'
        n = self._get_check_name('qml_application_uses_friends')
        s = "OK"
        link = None

        qmls = []
        pat_mv = re.compile(r'\n\s*import\s+Friends')
        for i in self.qml_files:
            qml = open_file_read(i).read()
            if pat_mv.search(qml):
                qmls.append(os.path.relpath(i, self.unpack_dir))

        if len(qmls) > 0:
            t = 'error'
            s = "Found files that use deprecated Friends API: %s" % " ,".join(
                qmls)
            link = "http://askubuntu.com/questions/497551/what-does-functional-qml-application-uses-friends-mean"

        self._add_result(t, n, s, link)
    def check_applicationName(self):
        '''Check applicationName matches click manifest'''
        if not self.is_click and not self.is_snap1:
            return

        if self.manifest is None:
            return

        t = 'info'
        n = self._get_check_name('qml_applicationName_matches_manifest')
        s = "OK"
        link = None

        # find file with MainView in the QML
        mv = '\s*MainView\s*(\s+{)?'
        pat_mv = re.compile(r'\n%s' % mv)
        qmls = dict()

        for i in self.qml_files:
            qml = open_file_read(i).read()
            if pat_mv.search(qml):
                qmls[i] = qml

        # LP: #1256841 - QML apps with C++ using QSettings shouldn't
        # typically set applicationName in the QML
        for i in self.pkg_bin_files:
            f = open(i, 'rb')
            data = str(binascii.b2a_qp(f.read()))
            f.close()
            if 'QSettings' in data:
                s = "OK (binary uses QSettings)"
                self._add_result(t, n, s)
                return

        if len(self.qml_files) == 0:
            s = "OK (not QML)"
            self._add_result(t, n, s)
            return
        elif len(qmls) == 0:
            s = "SKIP: could not find MainView in QML files"
            self._add_result(t, n, s)
            return

        pat_mvl = re.compile(r'^%s' % mv)
        pat_appname = re.compile(r'^\s*applicationName\s*:\s*["\']')

        ok = False
        appnames = dict()
        for k in qmls.keys():
            in_mainview = False
            for line in qmls[k].splitlines():
                if in_mainview and pat_appname.search(line):
                    appname = line.split(':', 1)[1].strip('"\' \t\n\r\f\v;')
                    appnames[os.path.relpath(k, self.unpack_dir)] = appname
                    if appname == self.click_pkgname:
                        ok = True
                        break
                elif pat_mvl.search(line):
                    in_mainview = True
                if ok:
                    break

        if len(appnames) == 0 or not ok:
            if len(self.pkg_bin_files) == 0:
                t = "warn"
                link = 'http://askubuntu.com/questions/417371/what-does-functional-qml-applicationname-matches-manifest-mean/417372'

            if len(appnames) == 0:
                s = "could not find applicationName in: %s" % \
                    ", ".join(sorted(list(map(
                        lambda x: os.path.relpath(x, self.unpack_dir), qmls))))
            else:  # not ok
                s = "click manifest name '%s' not found in: " % \
                    self.click_pkgname + "%s" % \
                    ", ".join(sorted(list(map(
                        lambda x: "%s ('%s')" % (x, appnames[x]), appnames))))

            if len(self.pkg_bin_files) == 0:
                s += ". Application may not work properly when confined."
            else:
                s += ". May be ok (detected as compiled application)."

        self._add_result(t, n, s, link)