Remove any version-modifier attribute when releasing. The idea is that you put '...
[0publish.git] / signing.py
blobd1fe430d41cc1b813d84e7ca59780f34fd0c211f
1 from zeroinstall import SafeException
2 from zeroinstall.injector import gpg
3 import tempfile, os, base64, sys, shutil
5 def check_signature(path):
6 data = file(path).read()
7 xml_comment = data.rfind('\n<!-- Base64 Signature')
8 if xml_comment >= 0:
9 data_stream, sigs = gpg.check_stream(file(path))
10 sign_fn = sign_xml
11 data = data[:xml_comment + 1]
12 data_stream.close()
13 elif data.startswith('-----BEGIN'):
14 data_stream, sigs = gpg.check_stream(file(path))
15 sign_fn = sign_plain
16 data = data_stream.read()
17 else:
18 return data, sign_unsigned, None
19 for sig in sigs:
20 if isinstance(sig, gpg.ValidSig):
21 return data, sign_fn, sig.fingerprint
22 print "ERROR: No valid signatures found!"
23 for sig in sigs:
24 print "Got:", sig
25 ok = raw_input('Ignore and load anyway? (y/N) ').lower()
26 if ok and 'yes'.startswith(ok):
27 import __main__
28 __main__.force_save = True
29 return data, sign_unsigned, None
30 sys.exit(1)
32 def write_tmp(path, data):
33 """Create a temporary file in the same directory as 'path' and write data to it."""
34 fd, tmp = tempfile.mkstemp(prefix = 'tmp-', dir = os.path.dirname(path))
35 stream = os.fdopen(fd, 'w')
36 stream.write(data)
37 stream.close()
38 return tmp
40 def run_gpg(default_key, *arguments):
41 arguments = list(arguments)
42 if default_key is not None:
43 arguments = ['--default-key', default_key] + arguments
44 arguments.insert(0, 'gpg')
45 if os.spawnvp(os.P_WAIT, 'gpg', arguments):
46 raise SafeException("Command '%s' failed" % arguments)
48 def sign_unsigned(path, data, key):
49 os.rename(write_tmp(path, data), path)
51 def sign_plain(path, data, key):
52 tmp = write_tmp(path, data)
53 try:
54 run_gpg(key, '--clearsign', tmp)
55 finally:
56 os.unlink(tmp)
57 os.rename(tmp + '.asc', path)
59 def sign_xml(path, data, key):
60 tmp = write_tmp(path, data)
61 try:
62 run_gpg(key, '--detach-sign', tmp)
63 finally:
64 os.unlink(tmp)
65 tmp += '.sig'
66 encoded = base64.encodestring(file(tmp).read())
67 os.unlink(tmp)
68 sig = "<!-- Base64 Signature\n" + encoded + "\n-->\n"
69 os.rename(write_tmp(path, data + sig), path)
71 def export_key(dir, fingerprint):
72 assert fingerprint is not None
73 # Convert fingerprint to key ID
74 stream = os.popen('gpg --with-colons --list-keys %s' % fingerprint)
75 try:
76 keyID = None
77 for line in stream:
78 parts = line.split(':')
79 if parts[0] == 'pub':
80 if keyID:
81 raise Exception('Two key IDs returned from GPG!')
82 keyID = parts[4]
83 finally:
84 stream.close()
85 key_file = os.path.join(dir, keyID + '.gpg')
86 if os.path.isfile(key_file):
87 return
88 key_stream = file(key_file, 'w')
89 stream = os.popen("gpg -a --export '%s'" % fingerprint)
90 shutil.copyfileobj(stream, key_stream)
91 stream.close()
92 key_stream.close()
93 print "Exported public key as '%s'" % key_file