예제 #1
0
 def testDomain(self):
     self.assertEqual("example.com",
                      trust.domain_from_url('http://example.com/foo'))
     self.assertRaises(SafeException,
                       lambda: trust.domain_from_url('/tmp/feed.xml'))
     self.assertRaises(SafeException,
                       lambda: trust.domain_from_url('http:///foo'))
     self.assertRaises(SafeException,
                       lambda: trust.domain_from_url('http://*/foo'))
     self.assertRaises(SafeException, lambda: trust.domain_from_url(''))
예제 #2
0
	def _queue_confirm_import_feed(self, pending, valid_sigs):
		# If we're already confirming something else, wait for that to finish...
		while self._current_confirm is not None:
			yield self._current_confirm

		# Check whether we still need to confirm. The user may have
		# already approved one of the keys while dealing with another
		# feed.
		from zeroinstall.injector import trust
		domain = trust.domain_from_url(pending.url)
		for sig in valid_sigs:
			is_trusted = trust.trust_db.is_trusted(sig.fingerprint, domain)
			if is_trusted:
				return

		# Take the lock and confirm this feed
		self._current_confirm = lock = tasks.Blocker('confirm key lock')
		try:
			done = self.confirm_import_feed(pending, valid_sigs)
			if done is not None:
				yield done
				tasks.check(done)
		finally:
			self._current_confirm = None
			lock.trigger()
예제 #3
0
    def confirm_keys(self, pending):

        assert pending.sigs

        from zeroinstall.injector import gpg
        valid_sigs = [s for s in pending.sigs if isinstance(s, gpg.ValidSig)]
        if not valid_sigs:
            def format_sig(sig):
                msg = str(sig)
                if sig.messages:
                    msg += "\nMessages from GPG:\n" + sig.messages
                return msg
            raise SafeException(_('No valid signatures found on "%(url)s". Signatures:%(signatures)s') %
                    {'url': pending.url, 'signatures': ''.join(['\n- ' + format_sig(s) for s in pending.sigs])})

        domain = trust.domain_from_url(pending.url)

        for sig in valid_sigs:
            if self.config.auto_approve_keys:
                existing_feed = self.config.iface_cache.get_feed(pending.url)
                if not existing_feed:
                    trust_db.trust_key(sig.fingerprint, domain)
                    trust_db.notify()

        # Take the lock and confirm this feed
        self._current_confirm = lock = tasks.Blocker('confirm key lock')
        self._current_confirm = None
        lock.trigger()
예제 #4
0
파일: stats.py 프로젝트: 0install/0mirror
	def add_feed(self, feed, active):
		self.active[feed] = active

		metadata = ET.Element('metadata')
		metadata.attrib["active"] = str(active)

		sig_data = sig_cache.get(feed.url)

		for sig in sig_data:
			fingerprint = sig.get("fingerprint")
			if fingerprint is None:
				signer = ET.SubElement(metadata, "signer")
				signer.attrib["error"] = sig["error"]
			else:
				fingerprint = aliases.get(fingerprint, fingerprint)
				assert fingerprint not in aliases, fingerprint
				if active:
					assert fingerprint not in test_keys, (fingerprint, feed)
				if fingerprint not in self.users:
					self.users[fingerprint] = User()
				self.users[fingerprint].add_feed(feed, sig, active)

				signer = ET.SubElement(metadata, "signer")
				signer.attrib["user"] = fingerprint
				signer.attrib["date"] = format_date(sig["date"])

		domain = trust.domain_from_url(feed.url)
		if domain not in self.sites:
			self.sites[domain] = []
		self.sites[domain].append(feed)

		self.feeds.append((feed, metadata))
예제 #5
0
    def _queue_confirm_import_feed(self, pending, valid_sigs):
        # If we're already confirming something else, wait for that to finish...
        while self._current_confirm is not None:
            yield self._current_confirm

        # Check whether we still need to confirm. The user may have
        # already approved one of the keys while dealing with another
        # feed.
        from zeroinstall.injector import trust
        domain = trust.domain_from_url(pending.url)
        for sig in valid_sigs:
            is_trusted = trust.trust_db.is_trusted(sig.fingerprint, domain)
            if is_trusted:
                return

        # Take the lock and confirm this feed
        self._current_confirm = lock = tasks.Blocker('confirm key lock')
        try:
            done = self.confirm_import_feed(pending, valid_sigs)
            if done is not None:
                yield done
                tasks.check(done)
        finally:
            self._current_confirm = None
            lock.trigger()
예제 #6
0
	def confirm_import_feed(self, pending, valid_sigs):
		"""Sub-classes should override this method to interact with the user about new feeds.
		If multiple feeds need confirmation, L{confirm_keys} will only invoke one instance of this
		method at a time.
		@param pending: the new feed to be imported
		@type pending: L{PendingFeed}
		@param valid_sigs: maps signatures to a list of fetchers collecting information about the key
		@type valid_sigs: {L{gpg.ValidSig} : L{fetch.KeyInfoFetcher}}
		@since: 0.42
		@see: L{confirm_keys}"""
		from zeroinstall.injector import trust

		assert valid_sigs

		domain = trust.domain_from_url(pending.url)

		# Ask on stderr, because we may be writing XML to stdout
		print >>sys.stderr, _("Feed: %s") % pending.url
		print >>sys.stderr, _("The feed is correctly signed with the following keys:")
		for x in valid_sigs:
			print >>sys.stderr, "-", x

		def text(parent):
			text = ""
			for node in parent.childNodes:
				if node.nodeType == node.TEXT_NODE:
					text = text + node.data
			return text

		shown = set()
		key_info_fetchers = valid_sigs.values()
		while key_info_fetchers:
			old_kfs = key_info_fetchers
			key_info_fetchers = []
			for kf in old_kfs:
				infos = set(kf.info) - shown
				if infos:
					if len(valid_sigs) > 1:
						print "%s: " % kf.fingerprint
					for key_info in infos:
						print >>sys.stderr, "-", text(key_info)
						shown.add(key_info)
				if kf.blocker:
					key_info_fetchers.append(kf)
			if key_info_fetchers:
				for kf in key_info_fetchers: print >>sys.stderr, kf.status
				stdin = tasks.InputBlocker(0, 'console')
				blockers = [kf.blocker for kf in key_info_fetchers] + [stdin]
				yield blockers
				for b in blockers:
					try:
						tasks.check(b)
					except Exception, ex:
						warn(_("Failed to get key info: %s"), ex)
				if stdin.happened:
					print >>sys.stderr, _("Skipping remaining key lookups due to input from user")
					break
예제 #7
0
    def confirm_import_feed(self, pending, valid_sigs):
        """
        verify the feed
        """
        from zeroinstall.injector import trust

        assert valid_sigs

        domain = trust.domain_from_url(pending.url)

        # Ask on stderr, because we may be writing XML to stdout
        print "Feed: %s" % pending.url
        print "The feed is correctly signed with the following keys:"
        for x in valid_sigs:
            print "-", x

        def text(parent):
            text = ""
            for node in parent.childNodes:
                if node.nodeType == node.TEXT_NODE:
                    text = text + node.data
            return text

        shown = set()
        key_info_fetchers = valid_sigs.values()
        while key_info_fetchers:
            old_kfs = key_info_fetchers
            key_info_fetchers = []
            for kf in old_kfs:
                infos = set(kf.info) - shown
                if infos:
                    if len(valid_sigs) > 1:
                        print("%s: " % kf.fingerprint)
                    for key_info in infos:
                        print("-", text(key_info) )
                        shown.add(key_info)
                if kf.blocker:
                    key_info_fetchers.append(kf)
            if key_info_fetchers:
                for kf in key_info_fetchers: print(kf.status)
                stdin = tasks.InputBlocker(0, 'console')
                blockers = [kf.blocker for kf in key_info_fetchers] + [stdin]
                yield blockers
                for b in blockers:
                    try:
                        tasks.check(b)
                    except Exception as ex:
                        warn(_("Failed to get key info: %s"), ex)
                if stdin.happened:
                    print("Skipping remaining key lookups due to input from user")
                    break

        for key in valid_sigs:
            print("Trusting %(key_fingerprint)s for %(domain)s") % {'key_fingerprint': key.fingerprint, 'domain': domain}
            trust.trust_db.trust_key(key.fingerprint, domain)
예제 #8
0
    def confirm_import_feed(self, pending, gpg_sigs):
        from zeroinstall.injector import trust

        domain = trust.domain_from_url(pending.url)
        self._confirm_keys = []
        for sig in gpg_sigs.keys():
            self._confirm_keys.append(_Key(sig, domain))

        self._confirmed = tasks.Blocker('confirm_import_feed')
        self._confirm_next()

        yield [self._confirmed]
        tasks.check([self._confirmed])
예제 #9
0
    def confirm_trust_keys(self, interface, sigs, iface_xml):
        """We don't trust any of the signatures yet. Ask the user.
		When done update the L{trust} database, and then call L{trust.TrustDB.notify}.
		@deprecated: see L{confirm_keys}
		@arg interface: the interface being updated
		@arg sigs: a list of signatures (from L{gpg.check_stream})
		@arg iface_xml: the downloaded data (not yet trusted)
		@return: a blocker, if confirmation will happen asynchronously, or None
		@rtype: L{tasks.Blocker}"""
        import warnings
        warnings.warn(_("Use confirm_keys, not confirm_trust_keys"),
                      DeprecationWarning,
                      stacklevel=2)
        from zeroinstall.injector import trust, gpg
        assert sigs
        valid_sigs = [s for s in sigs if isinstance(s, gpg.ValidSig)]
        if not valid_sigs:
            raise SafeException(
                'No valid signatures found on "%s". Signatures:%s' %
                (interface.uri, ''.join(['\n- ' + str(s) for s in sigs])))

        domain = trust.domain_from_url(interface.uri)

        # Ask on stderr, because we may be writing XML to stdout
        print >> sys.stderr, "\nInterface:", interface.uri
        print >> sys.stderr, "The interface is correctly signed with the following keys:"
        for x in valid_sigs:
            print >> sys.stderr, "-", x

        if len(valid_sigs) == 1:
            print >> sys.stderr, "Do you want to trust this key to sign feeds from '%s'?" % domain
        else:
            print >> sys.stderr, "Do you want to trust all of these keys to sign feeds from '%s'?" % domain
        while True:
            print >> sys.stderr, "Trust [Y/N] ",
            i = raw_input()
            if not i: continue
            if i in 'Nn':
                raise NoTrustedKeys(_('Not signed with a trusted key'))
            if i in 'Yy':
                break
        for key in valid_sigs:
            print >> sys.stderr, "Trusting", key.fingerprint, "for", domain
            trust.trust_db.trust_key(key.fingerprint, domain)

        trust.trust_db.notify()
예제 #10
0
	def confirm_trust_keys(self, interface, sigs, iface_xml):
		"""We don't trust any of the signatures yet. Ask the user.
		When done update the L{trust} database, and then call L{trust.TrustDB.notify}.
		@deprecated: see L{confirm_keys}
		@arg interface: the interface being updated
		@arg sigs: a list of signatures (from L{gpg.check_stream})
		@arg iface_xml: the downloaded data (not yet trusted)
		@return: a blocker, if confirmation will happen asynchronously, or None
		@rtype: L{tasks.Blocker}"""
		import warnings
		warnings.warn("Use confirm_keys, not confirm_trust_keys", DeprecationWarning, stacklevel = 2)
		from zeroinstall.injector import trust, gpg
		assert sigs
		valid_sigs = [s for s in sigs if isinstance(s, gpg.ValidSig)]
		if not valid_sigs:
			raise SafeException('No valid signatures found on "%s". Signatures:%s' %
					(interface.uri, ''.join(['\n- ' + str(s) for s in sigs])))

		domain = trust.domain_from_url(interface.uri)

		# Ask on stderr, because we may be writing XML to stdout
		print >>sys.stderr, "\nInterface:", interface.uri
		print >>sys.stderr, _("The feed is correctly signed with the following keys:")
		for x in valid_sigs:
			print >>sys.stderr, "-", x

		if len(valid_sigs) == 1:
			print >>sys.stderr, _("Do you want to trust this key to sign feeds from '%s'?") % domain
		else:
			print >>sys.stderr, _("Do you want to trust all of these keys to sign feeds from '%s'?") % domain
		while True:
			print >>sys.stderr, _("Trust [Y/N] "),
			i = raw_input()
			if not i: continue
			if i in 'Nn':
				raise NoTrustedKeys(_('Not signed with a trusted key'))
			if i in 'Yy':
				break
		for key in valid_sigs:
			print >>sys.stderr, _("Trusting %s for %s") % (key.fingerprint, domain)
			trust.trust_db.trust_key(key.fingerprint, domain)

		trust.trust_db.notify()
예제 #11
0
    def confirm_keys(self, pending):

        assert pending.sigs

        from zeroinstall.injector import gpg
        valid_sigs = [s for s in pending.sigs if isinstance(s, gpg.ValidSig)]
        if not valid_sigs:

            def format_sig(sig):
                msg = str(sig)
                if sig.messages:
                    msg += "\nMessages from GPG:\n" + sig.messages
                return msg

            raise SafeException(
                _('No valid signatures found on "%(url)s". Signatures:%(signatures)s'
                  ) % {
                      'url':
                      pending.url,
                      'signatures':
                      ''.join(['\n- ' + format_sig(s) for s in pending.sigs])
                  })

        domain = trust.domain_from_url(pending.url)

        for sig in valid_sigs:
            if self.config.auto_approve_keys:
                existing_feed = self.config.iface_cache.get_feed(pending.url)
                if not existing_feed:
                    trust_db.trust_key(sig.fingerprint, domain)
                    trust_db.notify()

        # Take the lock and confirm this feed
        self._current_confirm = lock = tasks.Blocker('confirm key lock')
        self._current_confirm = None
        lock.trigger()
예제 #12
0
    def __init__(self, pending, valid_sigs, parent):
        """@since: 0.42"""
        assert valid_sigs

        gtk.Dialog.__init__(self)
        self.set_has_separator(False)
        self.set_position(gtk.WIN_POS_CENTER)
        self.set_transient_for(parent)

        self.closed = tasks.Blocker(_("confirming keys with user"))

        domain = trust.domain_from_url(pending.url)
        assert domain

        def destroy(box):
            self.closed.trigger()

        self.connect('destroy', destroy)

        self.set_title(_('Confirm trust'))

        vbox = gtk.VBox(False, 4)
        vbox.set_border_width(4)
        self.vbox.pack_start(vbox, True, True, 0)

        notebook = gtk.Notebook()

        if len(valid_sigs) == 1:
            notebook.set_show_tabs(False)

        label = left(_('Checking: %s') % pending.url)
        label.set_padding(4, 4)
        vbox.pack_start(label, False, True, 0)

        currently_trusted_keys = trust.trust_db.get_keys_for_domain(domain)
        if currently_trusted_keys:
            keys = [
                gpg.load_key(fingerprint)
                for fingerprint in currently_trusted_keys
            ]
            descriptions = [
                _("%(key_name)s\n(fingerprint: %(key_fingerprint)s)") % {
                    'key_name': key.name,
                    'key_fingerprint': pretty_fp(key.fingerprint)
                } for key in keys
            ]
        else:
            descriptions = [_('None')]
        frame(vbox,
              _('Keys already approved for "%s"') % domain,
              '\n'.join(descriptions))

        label = left(
            translation.ngettext('This key signed the feed:',
                                 'These keys signed the feed:',
                                 len(valid_sigs)))

        label.set_padding(4, 4)
        vbox.pack_start(label, False, True, 0)

        vbox.pack_start(notebook, True, True, 0)

        self.add_button(gtk.STOCK_HELP, gtk.RESPONSE_HELP)
        self.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
        self.add_button(gtk.STOCK_ADD, gtk.RESPONSE_OK)
        self.set_default_response(gtk.RESPONSE_OK)

        trust_checkbox = {}  # Sig -> CheckButton

        def ok_sensitive():
            trust_any = False
            for toggle in trust_checkbox.values():
                if toggle.get_active():
                    trust_any = True
                    break
            self.set_response_sensitive(gtk.RESPONSE_OK, trust_any)

        first = True
        for sig in valid_sigs:
            if hasattr(sig, 'get_details'):
                name = '<unknown>'
                details = sig.get_details()
                for item in details:
                    if item[0] == 'uid' and len(item) > 9:
                        name = item[9]
                        break
            else:
                name = None
            page = gtk.VBox(False, 4)
            page.set_border_width(8)

            frame(page, _('Fingerprint'), pretty_fp(sig.fingerprint))

            if name is not None:
                frame(page, _('Claimed identity'), name)

            frame(page, _('Unreliable hints database says'),
                  make_hints_area(self.closed, valid_sigs[sig]))

            already_trusted = trust.trust_db.get_trust_domains(sig.fingerprint)
            if already_trusted:
                frame(page, _('You already trust this key for these domains'),
                      '\n'.join(already_trusted))

            trust_checkbox[sig] = gtk.CheckButton(_('_Trust this key'))
            page.pack_start(trust_checkbox[sig], False, True, 0)
            trust_checkbox[sig].connect('toggled', lambda t: ok_sensitive())

            notebook.append_page(page, gtk.Label(name or 'Signature'))

            if first:
                trust_checkbox[sig].set_active(True)
                first = False

        ok_sensitive()
        self.vbox.show_all()

        if len(valid_sigs) == 1:
            for box in trust_checkbox.values():
                box.hide()

        def response(box, resp):
            if resp == gtk.RESPONSE_HELP:
                trust_help.display()
                return
            if resp == gtk.RESPONSE_OK:
                to_trust = [
                    sig for sig in trust_checkbox
                    if trust_checkbox[sig].get_active()
                ]

                if not self._confirm_unknown_keys(to_trust, valid_sigs):
                    return

                self.trust_keys(to_trust, domain)
            self.destroy()

        self.connect('response', response)
예제 #13
0
	def testDomain(self):
		self.assertEqual("example.com", trust.domain_from_url('http://example.com/foo'))
		self.assertRaises(SafeException, lambda: trust.domain_from_url('/tmp/feed.xml'))
		self.assertRaises(SafeException, lambda: trust.domain_from_url('http:///foo'))
		self.assertRaises(SafeException, lambda: trust.domain_from_url('http://*/foo'))
		self.assertRaises(SafeException, lambda: trust.domain_from_url(''))
예제 #14
0
    def confirm_import_feed(self, pending, valid_sigs):
        """
        verify the feed
        """
        from zeroinstall.injector import trust

        assert valid_sigs

        domain = trust.domain_from_url(pending.url)

        # Ask on stderr, because we may be writing XML to stdout
        print "Feed: %s" % pending.url
        print "The feed is correctly signed with the following keys:"
        for x in valid_sigs:
            print "-", x

        def text(parent):
            text = ""
            for node in parent.childNodes:
                if node.nodeType == node.TEXT_NODE:
                    text = text + node.data
            return text

        shown = set()
        key_info_fetchers = valid_sigs.values()
        while key_info_fetchers:
            old_kfs = key_info_fetchers
            key_info_fetchers = []
            for kf in old_kfs:
                infos = set(kf.info) - shown
                if infos:
                    if len(valid_sigs) > 1:
                        print("%s: " % kf.fingerprint)
                    for key_info in infos:
                        print("-", text(key_info))
                        shown.add(key_info)
                if kf.blocker:
                    key_info_fetchers.append(kf)
            if key_info_fetchers:
                for kf in key_info_fetchers:
                    print(kf.status)
                stdin = tasks.InputBlocker(0, 'console')
                blockers = [kf.blocker for kf in key_info_fetchers] + [stdin]
                yield blockers
                for b in blockers:
                    try:
                        tasks.check(b)
                    except Exception as ex:
                        warn(_("Failed to get key info: %s"), ex)
                if stdin.happened:
                    print(
                        "Skipping remaining key lookups due to input from user"
                    )
                    break

        for key in valid_sigs:
            print("Trusting %(key_fingerprint)s for %(domain)s") % {
                'key_fingerprint': key.fingerprint,
                'domain': domain
            }
            trust.trust_db.trust_key(key.fingerprint, domain)
예제 #15
0
	def confirm_import_feed(self, pending, valid_sigs):
		"""Sub-classes should override this method to interact with the user about new feeds.
		If multiple feeds need confirmation, L{trust.TrustMgr.confirm_keys} will only invoke one instance of this
		method at a time.
		@param pending: the new feed to be imported
		@type pending: L{PendingFeed}
		@param valid_sigs: maps signatures to a list of fetchers collecting information about the key
		@type valid_sigs: {L{gpg.ValidSig} : L{fetch.KeyInfoFetcher}}
		@since: 0.42"""
		from zeroinstall.injector import trust

		assert valid_sigs

		domain = trust.domain_from_url(pending.url)

		# Ask on stderr, because we may be writing XML to stdout
		print(_("Feed: %s") % pending.url, file=sys.stderr)
		print(_("The feed is correctly signed with the following keys:"), file=sys.stderr)
		for x in valid_sigs:
			print("-", x, file=sys.stderr)

		def text(parent):
			text = ""
			for node in parent.childNodes:
				if node.nodeType == node.TEXT_NODE:
					text = text + node.data
			return text

		shown = set()
		key_info_fetchers = valid_sigs.values()
		while key_info_fetchers:
			old_kfs = key_info_fetchers
			key_info_fetchers = []
			for kf in old_kfs:
				infos = set(kf.info) - shown
				if infos:
					if len(valid_sigs) > 1:
						print("%s: " % kf.fingerprint)
					for key_info in infos:
						print("-", text(key_info), file=sys.stderr)
						shown.add(key_info)
				if kf.blocker:
					key_info_fetchers.append(kf)
			if key_info_fetchers:
				for kf in key_info_fetchers: print(kf.status, file=sys.stderr)
				stdin = tasks.InputBlocker(0, 'console')
				blockers = [kf.blocker for kf in key_info_fetchers] + [stdin]
				yield blockers
				for b in blockers:
					try:
						tasks.check(b)
					except Exception as ex:
						logger.warning(_("Failed to get key info: %s"), ex)
				if stdin.happened:
					print(_("Skipping remaining key lookups due to input from user"), file=sys.stderr)
					break
		if not shown:
			print(_("Warning: Nothing known about this key!"), file=sys.stderr)

		if len(valid_sigs) == 1:
			print(_("Do you want to trust this key to sign feeds from '%s'?") % domain, file=sys.stderr)
		else:
			print(_("Do you want to trust all of these keys to sign feeds from '%s'?") % domain, file=sys.stderr)
		while True:
			print(_("Trust [Y/N] "), end=' ', file=sys.stderr)
			i = support.raw_input()
			if not i: continue
			if i in 'Nn':
				raise NoTrustedKeys(_('Not signed with a trusted key'))
			if i in 'Yy':
				break
		trust.trust_db._dry_run = self.dry_run
		for key in valid_sigs:
			print(_("Trusting %(key_fingerprint)s for %(domain)s") % {'key_fingerprint': key.fingerprint, 'domain': domain}, file=sys.stderr)
			trust.trust_db.trust_key(key.fingerprint, domain)
예제 #16
0
	def confirm_import_feed(self, pending, valid_sigs):
		"""Sub-classes should override this method to interact with the user about new feeds.
		If multiple feeds need confirmation, L{trust.TrustMgr.confirm_keys} will only invoke one instance of this
		method at a time.
		@param pending: the new feed to be imported
		@type pending: L{PendingFeed}
		@param valid_sigs: maps signatures to a list of fetchers collecting information about the key
		@type valid_sigs: {L{gpg.ValidSig} : L{fetch.KeyInfoFetcher}}
		@since: 0.42"""
		from zeroinstall.injector import trust

		assert valid_sigs

		domain = trust.domain_from_url(pending.url)

		# Ask on stderr, because we may be writing XML to stdout
		print >>sys.stderr, _("Feed: %s") % pending.url
		print >>sys.stderr, _("The feed is correctly signed with the following keys:")
		for x in valid_sigs:
			print >>sys.stderr, "-", x

		def text(parent):
			text = ""
			for node in parent.childNodes:
				if node.nodeType == node.TEXT_NODE:
					text = text + node.data
			return text

		shown = set()
		key_info_fetchers = valid_sigs.values()
		while key_info_fetchers:
			old_kfs = key_info_fetchers
			key_info_fetchers = []
			for kf in old_kfs:
				infos = set(kf.info) - shown
				if infos:
					if len(valid_sigs) > 1:
						print "%s: " % kf.fingerprint
					for key_info in infos:
						print >>sys.stderr, "-", text(key_info)
						shown.add(key_info)
				if kf.blocker:
					key_info_fetchers.append(kf)
			if key_info_fetchers:
				for kf in key_info_fetchers: print >>sys.stderr, kf.status
				stdin = tasks.InputBlocker(0, 'console')
				blockers = [kf.blocker for kf in key_info_fetchers] + [stdin]
				yield blockers
				for b in blockers:
					try:
						tasks.check(b)
					except Exception as ex:
						warn(_("Failed to get key info: %s"), ex)
				if stdin.happened:
					print >>sys.stderr, _("Skipping remaining key lookups due to input from user")
					break
		if not shown:
			print >>sys.stderr, _("Warning: Nothing known about this key!")

		if len(valid_sigs) == 1:
			print >>sys.stderr, _("Do you want to trust this key to sign feeds from '%s'?") % domain
		else:
			print >>sys.stderr, _("Do you want to trust all of these keys to sign feeds from '%s'?") % domain
		while True:
			print >>sys.stderr, _("Trust [Y/N] "),
			i = raw_input()
			if not i: continue
			if i in 'Nn':
				raise NoTrustedKeys(_('Not signed with a trusted key'))
			if i in 'Yy':
				break
		for key in valid_sigs:
			print >>sys.stderr, _("Trusting %(key_fingerprint)s for %(domain)s") % {'key_fingerprint': key.fingerprint, 'domain': domain}
			trust.trust_db.trust_key(key.fingerprint, domain)
예제 #17
0
파일: install.py 프로젝트: res2k/0export
	def do_install(self, archive_stream, progress_bar, archive_offset):
		# Step 1. Import GPG keys

		# Maybe GPG has never been run before. Let it initialse, or we'll get an error code
		# from the first import... (ignore return value here)
		subprocess.call([get_gpg(), '--check-trustdb', '-q'])

		key_dir = os.path.join(mydir, 'keys')
		for key in os.listdir(key_dir):
			check_call([get_gpg(), '--import', '-q', os.path.join(key_dir, key)])

		# Step 2. Import feeds and trust their signing keys
		for root, dirs, files in os.walk(os.path.join(mydir, 'feeds')):
			if 'latest.xml' in files:
				feed_path = os.path.join(root, 'latest.xml')
				icon_path = os.path.join(root, 'icon.png')

				# Get URI
				feed_stream = file(feed_path)
				doc = qdom.parse(feed_stream)
				uri = doc.getAttribute('uri')
				assert uri, "Missing 'uri' attribute on root element in '%s'" % feed_path
				domain = trust.domain_from_url(uri)

				feed_stream.seek(0)
				stream, sigs = gpg.check_stream(feed_stream)
				for s in sigs:
					if not trust.trust_db.is_trusted(s.fingerprint, domain):
						print "Adding key %s to trusted list for %s" % (s.fingerprint, domain)
						trust.trust_db.trust_key(s.fingerprint, domain)
				oldest_sig = min([s.get_timestamp() for s in sigs])
				try:
					config.iface_cache.update_feed_from_network(uri, stream.read(), oldest_sig)
				except iface_cache.ReplayAttack:
					# OK, the user has a newer copy already
					pass
				if feed_stream != stream:
					feed_stream.close()
				stream.close()

				if os.path.exists(icon_path):
					icons_cache = basedir.save_cache_path(namespaces.config_site, 'interface_icons')
					icon_file = os.path.join(icons_cache, model.escape(uri))
					if not os.path.exists(icon_file):
						shutil.copyfile(icon_path, icon_file)

		# Step 3. Solve to find out which implementations we actually need
		archive_stream.seek(archive_offset)

		extract_impls = {}	# Impls we need but which are compressed (ID -> Impl)
		tmp = tempfile.mkdtemp(prefix = '0export-')
		try:
			# Create a "fake store" with the implementation in the archive
			archive = tarfile.open(name=archive_stream.name, mode='r|', fileobj=archive_stream)
			fake_store = FakeStore()
			for tarmember in archive:
				if tarmember.name.startswith('implementations'):
					impl = os.path.basename(tarmember.name).split('.')[0]
					fake_store.impls.add(impl)

			bootstrap_store = zerostore.Store(os.path.join(mydir, 'implementations'))
			stores = config.stores

			toplevel_uris = [uri.strip() for uri in file(os.path.join(mydir, 'toplevel_uris'))]
			ZEROINSTALL_URI = "@ZEROINSTALL_URI@"
			for uri in [ZEROINSTALL_URI] + toplevel_uris:
				# This is so the solver treats versions in the setup archive as 'cached',
				# meaning that it will prefer using them to doing a download
				stores.stores.append(bootstrap_store)
				stores.stores.append(fake_store)

				# Shouldn't need to download anything, but we might not have all feeds
				r = requirements.Requirements(uri)
				d = driver.Driver(config = config, requirements = r)
				config.network_use = model.network_minimal
				download_feeds = d.solve_with_downloads()
				h.wait_for_blocker(download_feeds)
				assert d.solver.ready, d.solver.get_failure_reason()

				# Add anything chosen from the setup store to the main store
				stores.stores.remove(fake_store)
				stores.stores.remove(bootstrap_store)
				for iface, impl in d.get_uncached_implementations():
					print >>sys.stderr, "Need to import", impl
					if impl.id in fake_store.impls:
						# Delay extraction
						extract_impls[impl.id] = impl
					else:
						impl_src = os.path.join(mydir, 'implementations', impl.id)

						if os.path.isdir(impl_src):
							stores.add_dir_to_cache(impl.id, impl_src)
						else:
							print >>sys.stderr, "Required impl %s (for %s) not present" % (impl, iface)

				# Remember where we copied 0launch to, because we'll need it after
				# the temporary directory is deleted.
				if uri == ZEROINSTALL_URI:
					global copied_0launch_in_cache
					impl = d.solver.selections.selections[uri]
					if not impl.id.startswith('package:'):
						copied_0launch_in_cache = impl.get_path(stores = config.stores)
					# (else we selected the distribution version of Zero Install)
		finally:
			shutil.rmtree(tmp)

		# Count total number of bytes to extract
		extract_total = 0
		for impl in extract_impls.values():
			impl_info = archive.getmember('implementations/' + impl.id + '.tar.bz2')
			extract_total += impl_info.size

		self.sent = 0

		# Actually extract+import implementations in archive
		archive_stream.seek(archive_offset)
		archive = tarfile.open(name=archive_stream.name, mode='r|',
                fileobj=archive_stream)

		for tarmember in archive:
			if not tarmember.name.startswith('implementations'):
				continue
			impl_id = tarmember.name.split('/')[1].split('.')[0]
			if impl_id not in extract_impls:
				print "Skip", impl_id
				continue
			print "Extracting", impl_id
			tmp = tempfile.mkdtemp(prefix = '0export-')
			try:
				impl_stream = archive.extractfile(tarmember)
				self.child = subprocess.Popen('bunzip2|tar xf -', shell = True, stdin = subprocess.PIPE, cwd = tmp)
				mainloop = gobject.MainLoop(gobject.main_context_default())

				def pipe_ready(src, cond):
					data = impl_stream.read(4096)
					if not data:
						mainloop.quit()
						self.child.stdin.close()
						return False
					self.sent += len(data)
					if progress_bar:
						progress_bar.set_fraction(float(self.sent) / extract_total)
					self.child.stdin.write(data)
					return True
				gobject.io_add_watch(self.child.stdin, gobject.IO_OUT | gobject.IO_HUP, pipe_ready, priority = gobject.PRIORITY_LOW)

				mainloop.run()

				self.child.wait()
				if self.child.returncode:
					raise Exception("Failed to unpack archive (code %d)" % self.child.returncode)

				stores.add_dir_to_cache(impl_id, tmp)

			finally:
				shutil.rmtree(tmp)

		return toplevel_uris
예제 #18
0
	def __init__(self, pending, valid_sigs, parent):
		"""@since: 0.42"""
		assert valid_sigs

		gtk.Dialog.__init__(self)
		self.set_has_separator(False)
		self.set_position(gtk.WIN_POS_CENTER)
		self.set_transient_for(parent)

		self.closed = tasks.Blocker(_("confirming keys with user"))

		domain = trust.domain_from_url(pending.url)
		assert domain

		def destroy(box):
			self.closed.trigger()

		self.connect('destroy', destroy)

		self.set_title(_('Confirm trust'))

		vbox = gtk.VBox(False, 4)
		vbox.set_border_width(4)
		self.vbox.pack_start(vbox, True, True, 0)

		notebook = gtk.Notebook()

		if len(valid_sigs) == 1:
			notebook.set_show_tabs(False)

		label = left(_('Checking: %s') % pending.url)
		label.set_padding(4, 4)
		vbox.pack_start(label, False, True, 0)

		currently_trusted_keys = trust.trust_db.get_keys_for_domain(domain)
		if currently_trusted_keys:
			keys = [gpg.load_key(fingerprint) for fingerprint in currently_trusted_keys]
			descriptions = [_("%(key_name)s\n(fingerprint: %(key_fingerprint)s)") % {'key_name': key.name, 'key_fingerprint': pretty_fp(key.fingerprint)}
					for key in keys]
		else:
			descriptions = [_('None')]
		frame(vbox, _('Keys already approved for "%s"') % domain, '\n'.join(descriptions))

		label = left(translation.ngettext('This key signed the feed:', 'These keys signed the feed:', len(valid_sigs)))

		label.set_padding(4, 4)
		vbox.pack_start(label, False, True, 0)

		vbox.pack_start(notebook, True, True, 0)

		self.add_button(gtk.STOCK_HELP, gtk.RESPONSE_HELP)
		self.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
		self.add_button(gtk.STOCK_ADD, gtk.RESPONSE_OK)
		self.set_default_response(gtk.RESPONSE_OK)

		trust_checkbox = {}	# Sig -> CheckButton
		def ok_sensitive():
			trust_any = False
			for toggle in trust_checkbox.values():
				if toggle.get_active():
					trust_any = True
					break
			self.set_response_sensitive(gtk.RESPONSE_OK, trust_any)

		first = True
		for sig in valid_sigs:
			if hasattr(sig, 'get_details'):
				name = '<unknown>'
				details = sig.get_details()
				for item in details:
					if item[0] == 'uid' and len(item) > 9:
						name = item[9]
						break
			else:
				name = None
			page = gtk.VBox(False, 4)
			page.set_border_width(8)

			frame(page, _('Fingerprint'), pretty_fp(sig.fingerprint))

			if name is not None:
				frame(page, _('Claimed identity'), name)

			frame(page, _('Unreliable hints database says'), make_hints_area(self.closed, valid_sigs[sig]))

			already_trusted = trust.trust_db.get_trust_domains(sig.fingerprint)
			if already_trusted:
				frame(page, _('You already trust this key for these domains'),
					'\n'.join(already_trusted))

			trust_checkbox[sig] = gtk.CheckButton(_('_Trust this key'))
			page.pack_start(trust_checkbox[sig], False, True, 0)
			trust_checkbox[sig].connect('toggled', lambda t: ok_sensitive())

			notebook.append_page(page, gtk.Label(name or 'Signature'))

			if first:
				trust_checkbox[sig].set_active(True)
				first = False

		ok_sensitive()
		self.vbox.show_all()

		if len(valid_sigs) == 1:
			for box in trust_checkbox.values():
				box.hide()

		def response(box, resp):
			if resp == gtk.RESPONSE_HELP:
				trust_help.display()
				return
			if resp == gtk.RESPONSE_OK:
				to_trust = [sig for sig in trust_checkbox if trust_checkbox[sig].get_active()]

				if not self._confirm_unknown_keys(to_trust, valid_sigs):
					return

				self.trust_keys(to_trust, domain)
			self.destroy()
		self.connect('response', response)
예제 #19
0
    def confirm_import_feed(self, pending, valid_sigs):
        """Sub-classes should override this method to interact with the user about new feeds.
		If multiple feeds need confirmation, L{confirm_keys} will only invoke one instance of this
		method at a time.
		@param pending: the new feed to be imported
		@type pending: L{PendingFeed}
		@param valid_sigs: maps signatures to a list of fetchers collecting information about the key
		@type valid_sigs: {L{gpg.ValidSig} : L{fetch.KeyInfoFetcher}}
		@since: 0.42
		@see: L{confirm_keys}"""
        from zeroinstall.injector import trust

        assert valid_sigs

        domain = trust.domain_from_url(pending.url)

        # Ask on stderr, because we may be writing XML to stdout
        print >> sys.stderr, _("Feed: %s") % pending.url
        print >> sys.stderr, _(
            "The feed is correctly signed with the following keys:")
        for x in valid_sigs:
            print >> sys.stderr, "-", x

        def text(parent):
            text = ""
            for node in parent.childNodes:
                if node.nodeType == node.TEXT_NODE:
                    text = text + node.data
            return text

        shown = set()
        key_info_fetchers = valid_sigs.values()
        while key_info_fetchers:
            old_kfs = key_info_fetchers
            key_info_fetchers = []
            for kf in old_kfs:
                infos = set(kf.info) - shown
                if infos:
                    if len(valid_sigs) > 1:
                        print "%s: " % kf.fingerprint
                    for info in infos:
                        print >> sys.stderr, "-", text(info)
                        shown.add(info)
                if kf.blocker:
                    key_info_fetchers.append(kf)
            if key_info_fetchers:
                for kf in key_info_fetchers:
                    print >> sys.stderr, kf.status
                stdin = tasks.InputBlocker(0, 'console')
                blockers = [kf.blocker for kf in key_info_fetchers] + [stdin]
                yield blockers
                for b in blockers:
                    try:
                        tasks.check(b)
                    except Exception, ex:
                        warn(_("Failed to get key info: %s"), ex)
                if stdin.happened:
                    print >> sys.stderr, _(
                        "Skipping remaining key lookups due to input from user"
                    )
                    break