2 Records who we trust to sign interfaces.
4 @var trust_db: Singleton trust database instance.
7 # Copyright (C) 2006, Thomas Leonard
8 # See the README file for details, or visit http://0install.net.
13 from namespaces
import config_site
, config_prog
, XMLNS_TRUST
15 class TrustDB(object):
16 """A database of trusted keys.
17 @ivar keys: maps trusted key fingerprints to a list of domains
18 @type keys: {str: set(str)}
19 @ivar watchers: callbacks invoked by L{notify}
20 @see: L{trust_db} - the singleton instance of this class"""
21 __slots__
= ['keys', 'watchers']
27 def is_trusted(self
, fingerprint
, domain
= None):
28 self
.ensure_uptodate()
30 domains
= self
.keys
.get(fingerprint
, None)
31 if not domains
: return False # Unknown key
34 return True # Deprecated
36 return domain
in domains
or '*' in domains
38 def get_trust_domains(self
, fingerprint
):
39 """Return the set of domains in which this key is trusted.
40 If the list includes '*' then the key is trusted everywhere.
42 self
.ensure_uptodate()
43 return self
.keys
.get(fingerprint
, sets
.Set())
45 def trust_key(self
, fingerprint
, domain
= '*'):
46 """Add key to the list of trusted fingerprints.
47 @param fingerprint: base 16 fingerprint without any spaces
48 @type fingerprint: str
49 @param domain: domain in which key is to be trusted
51 @note: call L{notify} after trusting one or more new keys"""
52 if self
.is_trusted(fingerprint
, domain
): return
54 int(fingerprint
, 16) # Ensure fingerprint is valid
56 if fingerprint
not in self
.keys
:
57 self
.keys
[fingerprint
] = sets
.Set()
60 # warn("Calling trust_key() without a domain is deprecated")
62 self
.keys
[fingerprint
].add(domain
)
65 def untrust_key(self
, key
):
66 self
.ensure_uptodate()
71 from xml
.dom
import minidom
74 doc
= minidom
.Document()
75 root
= doc
.createElementNS(XMLNS_TRUST
, 'trusted-keys')
76 root
.setAttribute('xmlns', XMLNS_TRUST
)
79 for fingerprint
in self
.keys
:
80 keyelem
= doc
.createElementNS(XMLNS_TRUST
, 'key')
81 root
.appendChild(keyelem
)
82 keyelem
.setAttribute('fingerprint', fingerprint
)
83 for domain
in self
.keys
[fingerprint
]:
84 domainelem
= doc
.createElementNS(XMLNS_TRUST
, 'domain')
85 domainelem
.setAttribute('value', domain
)
86 keyelem
.appendChild(domainelem
)
88 d
= basedir
.save_config_path(config_site
, config_prog
)
89 fd
, tmpname
= tempfile
.mkstemp(dir = d
, prefix
= 'trust-')
90 tmp
= os
.fdopen(fd
, 'wb')
91 doc
.writexml(tmp
, indent
= "", addindent
= " ", newl
= "\n")
94 os
.rename(tmpname
, os
.path
.join(d
, 'trustdb.xml'))
97 """Call all watcher callbacks.
98 This should be called after trusting one or more new keys.
100 for w
in self
.watchers
: w()
102 def ensure_uptodate(self
):
103 from xml
.dom
import minidom
105 # This is a bit inefficient... (could cache things)
108 trust
= basedir
.load_first_config(config_site
, config_prog
, 'trustdb.xml')
110 keys
= minidom
.parse(trust
).documentElement
111 for key
in keys
.getElementsByTagNameNS(XMLNS_TRUST
, 'key'):
113 self
.keys
[key
.getAttribute('fingerprint')] = domains
114 for domain
in key
.getElementsByTagNameNS(XMLNS_TRUST
, 'domain'):
115 domains
.add(domain
.getAttribute('value'))
117 # Convert old database to XML format
118 trust
= basedir
.load_first_config(config_site
, config_prog
, 'trust')
120 #print "Loading trust from", trust_db
121 for key
in file(trust
).read().split('\n'):
123 self
.keys
[key
] = sets
.Set('*')
125 def domain_from_url(url
):
126 """Extract the trust domain for a URL.
127 @param url: the feed's URL
129 @return: the trust domain
132 @raise SafeException: the URL can't be parsed"""
134 from zeroinstall
import SafeException
135 if url
.startswith('/'):
136 raise SafeException("Can't get domain from a local path: '%s'" % url
)
137 domain
= urlparse
.urlparse(url
)[1]
138 if domain
and domain
!= '*':
140 raise SafeException("Can't extract domain from URL '%s'" % url
)