From 4dc39244f376181fd2b9ce15867f0d27284202a3 Mon Sep 17 00:00:00 2001 From: Thomas Leonard Date: Sun, 11 Mar 2007 11:20:15 +0000 Subject: [PATCH] The trust database is now an XML-format file. The old file will be converted automatically to the new format on the first run. The new format lists all the domains in which the key is trusted, or '*' for all domains. This is currently not used. git-svn-id: file:///home/talex/Backups/sf.net/Subversion/zero-install/trunk/0launch@1592 9f8c893c-44ee-0310-b757-c8ca8341c71e --- tests/testtrust.py | 20 ++++++++ zeroinstall/injector/namespaces.py | 1 + zeroinstall/injector/trust.py | 97 ++++++++++++++++++++++++++++---------- 3 files changed, 93 insertions(+), 25 deletions(-) diff --git a/tests/testtrust.py b/tests/testtrust.py index 5373270..df5f120 100755 --- a/tests/testtrust.py +++ b/tests/testtrust.py @@ -30,6 +30,26 @@ class TestTrust(BaseTest): trust.trust_db.untrust_key("1234") assert not trust.trust_db.is_trusted("1234") + def testAddDomain(self): + assert not trust.trust_db.is_trusted("1234", "0install.net") + trust.trust_db.trust_key("1234") + + assert trust.trust_db.is_trusted("1234") + assert trust.trust_db.is_trusted("1234", "0install.net") + assert trust.trust_db.is_trusted("1234", "rox.sourceforge.net") + assert not trust.trust_db.is_trusted("1236") + + trust.trust_db.untrust_key("1234") + assert not trust.trust_db.is_trusted("1234") + assert not trust.trust_db.is_trusted("1234", "rox.sourceforge.net") + + trust.trust_db.trust_key("1234", "0install.net") + trust.trust_db.trust_key("1234", "gimp.org") + assert trust.trust_db.is_trusted("1234") + assert trust.trust_db.is_trusted("1234", "0install.net") + assert trust.trust_db.is_trusted("1234", "gimp.org") + assert not trust.trust_db.is_trusted("1234", "rox.sourceforge.net") + def testParallel(self): a = trust.TrustDB() b = trust.TrustDB() diff --git a/zeroinstall/injector/namespaces.py b/zeroinstall/injector/namespaces.py index 20da7e5..fc16856 100644 --- a/zeroinstall/injector/namespaces.py +++ b/zeroinstall/injector/namespaces.py @@ -12,6 +12,7 @@ # See the README file for details, or visit http://0install.net. XMLNS_IFACE = 'http://zero-install.sourceforge.net/2004/injector/interface' +XMLNS_TRUST = 'http://zero-install.sourceforge.net/2007/injector/trust' config_site = '0install.net' config_prog = 'injector' diff --git a/zeroinstall/injector/trust.py b/zeroinstall/injector/trust.py index 48c5e0a..7baa7d9 100644 --- a/zeroinstall/injector/trust.py +++ b/zeroinstall/injector/trust.py @@ -7,14 +7,15 @@ Records who we trust to sign interfaces. # Copyright (C) 2006, Thomas Leonard # See the README file for details, or visit http://0install.net. -import os +import os, sets import basedir -from namespaces import config_site, config_prog +from namespaces import config_site, config_prog, XMLNS_TRUST class TrustDB(object): """A database of trusted keys. - @ivar keys: a list of trusted key fingerprints + @ivar keys: maps trusted key fingerprints to a list of domains + @type keys: {str: set(str)} @ivar watchers: callbacks invoked by L{notify} @see: L{trust_db} - the singleton instance of this class""" __slots__ = ['keys', 'watchers'] @@ -23,18 +24,35 @@ class TrustDB(object): self.keys = None self.watchers = [] - def is_trusted(self, key): + def is_trusted(self, fingerprint, domain = None): self.ensure_uptodate() - return key in self.keys - - def trust_key(self, key): + + domains = self.keys.get(fingerprint, None) + if not domains: return False # Unknown key + + if domain is None: + return True # Deprecated + + return domain in domains or '*' in domains + + def trust_key(self, fingerprint, domain = '*'): """Add key to the list of trusted fingerprints. - @param key: base 16 fingerprint without any spaces + @param fingerprint: base 16 fingerprint without any spaces + @type fingerprint: str + @param domain: domain in which key is to be trusted + @type domain: str @note: call L{notify} after trusting one or more new keys""" - self.ensure_uptodate() - if key in self.keys: return - int(key, 16) # Ensure fingerprint is valid - self.keys[key] = True + if self.is_trusted(fingerprint, domain): return + + int(fingerprint, 16) # Ensure fingerprint is valid + + if fingerprint not in self.keys: + self.keys[fingerprint] = sets.Set() + + #if domain == '*': + # warn("Calling trust_key() without a domain is deprecated") + + self.keys[fingerprint].add(domain) self.save() def untrust_key(self, key): @@ -43,12 +61,30 @@ class TrustDB(object): self.save() def save(self): + from xml.dom import minidom + import tempfile + + doc = minidom.Document() + root = doc.createElementNS(XMLNS_TRUST, 'trusted-keys') + root.setAttribute('xmlns', XMLNS_TRUST) + doc.appendChild(root) + + for fingerprint in self.keys: + keyelem = doc.createElementNS(XMLNS_TRUST, 'key') + root.appendChild(keyelem) + keyelem.setAttribute('fingerprint', fingerprint) + for domain in self.keys[fingerprint]: + domainelem = doc.createElementNS(XMLNS_TRUST, 'domain') + domainelem.setAttribute('value', domain) + keyelem.appendChild(domainelem) + d = basedir.save_config_path(config_site, config_prog) - # XXX - f = file(os.path.join(d, 'trust'), 'w') - for key in self.keys: - print >>f, key - f.close() + fd, tmpname = tempfile.mkstemp(dir = d, prefix = 'trust-') + tmp = os.fdopen(fd, 'wb') + doc.writexml(tmp, indent = "", addindent = " ", newl = "\n") + tmp.close() + + os.rename(tmpname, os.path.join(d, 'trustdb.xml')) def notify(self): """Call all watcher callbacks. @@ -57,15 +93,26 @@ class TrustDB(object): for w in self.watchers: w() def ensure_uptodate(self): - # This is a bit inefficient... - trust = basedir.load_first_config(config_site, config_prog, - 'trust') - # By default, trust our own key + from xml.dom import minidom + + # This is a bit inefficient... (could cache things) self.keys = {} + + trust = basedir.load_first_config(config_site, config_prog, 'trustdb.xml') if trust: - #print "Loading trust from", trust_db - for key in file(trust).read().split('\n'): - if key: - self.keys[key] = True + keys = minidom.parse(trust).documentElement + for key in keys.getElementsByTagNameNS(XMLNS_TRUST, 'key'): + domains = sets.Set() + self.keys[key.getAttribute('fingerprint')] = domains + for domain in key.getElementsByTagNameNS(XMLNS_TRUST, 'domain'): + domains.add(domain.getAttribute('value')) + else: + # Convert old database to XML format + trust = basedir.load_first_config(config_site, config_prog, 'trust') + if trust: + #print "Loading trust from", trust_db + for key in file(trust).read().split('\n'): + if key: + self.keys[key] = sets.Set('*') trust_db = TrustDB() -- 2.11.4.GIT