Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Delta Between Two Patch Sets: xarfile.py

Issue 29349885: Issue 4340 - Drop dependency on external xar tool (Closed)
Left Patch Set: Added template for ToC generation and rebased Created Aug. 17, 2016, 10:04 a.m.
Right Patch Set: Addressed more nits Created Aug. 17, 2016, 7:21 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « packagerSafari.py ('k') | xartoc.xml.tmpl » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 # This Source Code Form is subject to the terms of the Mozilla Public 1 # This Source Code Form is subject to the terms of the Mozilla Public
2 # License, v. 2.0. If a copy of the MPL was not distributed with this 2 # License, v. 2.0. If a copy of the MPL was not distributed with this
3 # file, You can obtain one at http://mozilla.org/MPL/2.0/. 3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
4 4
5 import re 5 import re
6 import struct 6 import struct
7 import time 7 import time
8 import zlib 8 import zlib
9 9
10 from Crypto.Hash import SHA 10 from Crypto.Hash import SHA
11 from Crypto.PublicKey import RSA 11 from Crypto.PublicKey import RSA
12 from Crypto.Signature import PKCS1_v1_5 12 from Crypto.Signature import PKCS1_v1_5
13 13
14 from buildtools.packager import getTemplate 14 from buildtools.packager import getTemplate
15 15
16 XAR_HEADER = struct.Struct('>IHHQQI')
16 XAR_HEADER_MAGIC = 0x78617221 17 XAR_HEADER_MAGIC = 0x78617221
17 XAR_HEADER_SIZE = 28
18 XAR_VERSION = 1 18 XAR_VERSION = 1
19 XAR_CKSUM_SHA1 = 1 19 XAR_CKSUM_SHA1 = 1
20 20
21 PRIVATE_KEY_REGEXP = r'-+BEGIN PRIVATE KEY-+(.*?)-+END PRIVATE KEY-+'
22 CERTIFICATE_REGEXP = r'-+BEGIN CERTIFICATE-+(.*?)-+END CERTIFICATE-+'
23 21
24 22 def read_certificates_and_key(keyfile):
25 def read_key(keyfile):
26 with open(keyfile, 'r') as file: 23 with open(keyfile, 'r') as file:
27 data = file.read() 24 data = file.read()
28 match = re.search(PRIVATE_KEY_REGEXP, data, re.S)
Sebastian Noack 2016/08/17 12:53:45 You can leave the with block after the data has be
Wladimir Palant 2016/08/17 14:11:40 Done.
29 if not match:
30 raise Exception('Cound not find private key in file')
31 return RSA.importKey(match.group(0))
32 25
26 certificates = []
27 key = None
28 for match in re.finditer(r'-+BEGIN (.*?)-+(.*?)-+END \1-+', data, re.S):
29 section = match.group(1)
30 if section == 'CERTIFICATE':
31 certificates.append(re.sub(r'\s+', '', match.group(2)))
32 elif section == 'PRIVATE KEY':
33 key = RSA.importKey(match.group(0))
34 if not key:
35 raise Exception('Could not find private key in file')
33 36
34 def read_certificates(keyfile): 37 return certificates, key
35 certificates = []
36 with open(keyfile, 'r') as file:
37 data = file.read()
38 for match in re.finditer(CERTIFICATE_REGEXP, data, re.S):
39 certificates.append(re.sub(r'\s+', '', match.group(1)))
40 return certificates
41 38
42 39
43 def get_checksum(data): 40 def get_checksum(data):
44 return SHA.new(data).digest() 41 return SHA.new(data).digest()
45 42
46 43
47 def get_hexchecksum(data): 44 def get_hexchecksum(data):
48 return SHA.new(data).hexdigest() 45 return SHA.new(data).hexdigest()
49 46
50 47
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
93 'offset': offset, 90 'offset': offset,
94 } 91 }
95 file_id += 1 92 file_id += 1
96 offset += len(compressed) 93 offset += len(compressed)
97 directory_stack[-1][1].append(file) 94 directory_stack[-1][1].append(file)
98 compressed_data.append(compressed) 95 compressed_data.append(compressed)
99 return compressed_data 96 return compressed_data
100 97
101 98
102 def create(archivepath, contents, keyfile): 99 def create(archivepath, contents, keyfile):
103 key = read_key(keyfile) 100 certificates, key = read_certificates_and_key(keyfile)
104 checksum_length = len(get_checksum('')) 101 checksum_length = len(get_checksum(''))
Sebastian Noack 2016/08/17 12:53:45 No need to hash any (empty) data to get the digest
Wladimir Palant 2016/08/17 14:11:40 Strictly speaking - no, it's not necessary. Howeve
105 params = { 102 params = {
106 'certificates': read_certificates(keyfile), 103 'certificates': certificates,
107 104
108 # Timestamp epoch starts at 2001-01-01T00:00:00.000Z 105 # Timestamp epoch starts at 2001-01-01T00:00:00.000Z
109 'timestamp_numerical': time.time() - 978307200, 106 'timestamp_numerical': time.time() - 978307200,
110 'timestamp_iso': time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime()), 107 'timestamp_iso': time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime()),
111 108
112 'checksum': { 109 'checksum': {
113 'offset': 0, 110 'offset': 0,
114 'size': checksum_length, 111 'size': checksum_length,
115 }, 112 },
116 'signature': { 113 'signature': {
117 'offset': checksum_length, 114 'offset': checksum_length,
118 'size': len(get_signature(key, '')), 115 'size': len(get_signature(key, '')),
119 }, 116 },
120 'files': [], 117 'files': [],
121 } 118 }
122 119
123 offset = params['signature']['offset'] + params['signature']['size'] 120 offset = params['signature']['offset'] + params['signature']['size']
124 compressed_data = compress_files(contents, params['files'], offset) 121 compressed_data = compress_files(contents, params['files'], offset)
125 122
126 template = getTemplate('xartoc.xml.tmpl', autoEscape=True) 123 template = getTemplate('xartoc.xml.tmpl', autoEscape=True)
127 toc_uncompressed = template.render(params).encode('utf-8') 124 toc_uncompressed = template.render(params).encode('utf-8')
128 toc_compressed = zlib.compress(toc_uncompressed, 9) 125 toc_compressed = zlib.compress(toc_uncompressed, 9)
129 126
130 with open(archivepath, 'wb') as file: 127 with open(archivepath, 'wb') as file:
131 # The file starts with a minimalistic header 128 # The file starts with a minimalistic header
132 header = struct.pack('>IHHQQI', XAR_HEADER_MAGIC, XAR_HEADER_SIZE, 129 file.write(XAR_HEADER.pack(XAR_HEADER_MAGIC, XAR_HEADER.size,
Sebastian Noack 2016/08/17 12:53:45 Note that you could avoid hard-coding the header s
Wladimir Palant 2016/08/17 14:11:40 Done.
133 XAR_VERSION, len(toc_compressed), 130 XAR_VERSION, len(toc_compressed),
134 len(toc_uncompressed), XAR_CKSUM_SHA1) 131 len(toc_uncompressed), XAR_CKSUM_SHA1))
135 file.write(header)
136 132
137 # It's followed up with a compressed XML table of contents 133 # It's followed up with a compressed XML table of contents
138 file.write(toc_compressed) 134 file.write(toc_compressed)
139 135
140 # Now the actual data, all the offsets are in the table of contents 136 # Now the actual data, all the offsets are in the table of contents
141 file.write(get_checksum(toc_compressed)) 137 file.write(get_checksum(toc_compressed))
142 file.write(get_signature(key, toc_compressed)) 138 file.write(get_signature(key, toc_compressed))
143 for blob in compressed_data: 139 for blob in compressed_data:
144 file.write(blob) 140 file.write(blob)
LEFTRIGHT

Powered by Google App Engine
This is Rietveld