-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathdigest.py
85 lines (69 loc) · 2.18 KB
/
digest.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
from xml.dom import minidom
from zeroinstall.injector import namespaces
from zeroinstall.zerostore import manifest, Stores, NotStored
import xmltools
from logging import info
stores = Stores()
def digests(impl):
id = impl.getAttribute('id')
if '=' in id:
yield id.split('=', 1)
for x in xmltools.children(impl, 'manifest-digest'):
for name, value in x.attributes.itemsNS():
if name[0] is None:
yield name[1], value
def get_version(impl):
while impl:
v = impl.getAttribute('version')
if v: return v
impl = impl.parentNode
def add_digest(impl, alg_name):
alg = manifest.get_algorithm(alg_name)
# Scan through the existing digests
# - If we've already got the one we need, return
# - Otherwise, find a cached implementation we can use
existing_path = None
for a, value in digests(impl):
if a in ('sha1', 'sha1new', 'sha256'):
digest = '%s=%s' % (a, value)
else:
digest = '%s_%s' % (a, value)
if a == alg_name:
return False # Already signed with this algorithm
if not existing_path:
try:
existing_path = stores.lookup(digest)
if existing_path:
existing_digest = digest
except NotStored:
pass # OK
if existing_path is None:
print("No implementations of %s cached; can't calculate new digest" % get_version(impl))
return False
info("Verifying %s", existing_path)
manifest.verify(existing_path, existing_digest)
print("Adding new digest to version %s" % get_version(impl))
new_digest = alg.new_digest()
for line in alg.generate_manifest(existing_path):
new_digest.update((line + '\n').encode())
for md in xmltools.children(impl, 'manifest-digest'):
break
else:
md = xmltools.create_element(impl, 'manifest-digest')
_, digest_value = manifest.splitID(alg.getID(new_digest))
md.setAttribute(alg_name, digest_value)
return True
def add_digests(data, alg = None):
doc = minidom.parseString(data)
if alg is None:
alg = 'sha1new'
changed = False
for impl in doc.documentElement.getElementsByTagNameNS(namespaces.XMLNS_IFACE, 'implementation'):
if impl.getAttribute('id') in "./":
continue # Local implementation
if add_digest(impl, alg):
changed = True
if changed:
return doc.toxml('utf-8')
else:
return data