Left: | ||
Right: |
LEFT | RIGHT |
---|---|
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 base64 | 5 import base64 |
6 import ConfigParser | 6 import ConfigParser |
7 import json | 7 import json |
8 import math | |
9 import os | 8 import os |
10 import re | 9 import re |
11 from urlparse import urlparse | 10 from urlparse import urlparse |
12 | 11 |
13 from packager import readMetadata, getDefaultFileName, getBuildVersion, getTempl ate, Files | 12 from packager import readMetadata, getDefaultFileName, getBuildVersion, getTempl ate, Files |
14 from packagerChrome import convertJS, importGeckoLocales, getIgnoredFiles, getPa ckageFiles, defaultLocale, createScriptPage | 13 from packagerChrome import convertJS, importGeckoLocales, getIgnoredFiles, getPa ckageFiles, defaultLocale, createScriptPage |
15 | 14 |
16 | 15 |
17 def processFile(path, data, params): | 16 def processFile(path, data, params): |
18 return data | 17 return data |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
107 files[filename] = re.sub( | 106 files[filename] = re.sub( |
108 r'(<[^<>]*?\b(?:href|src)\s*=\s*["\']?)\/+', | 107 r'(<[^<>]*?\b(?:href|src)\s*=\s*["\']?)\/+', |
109 r'\1' + '/'.join(['..'] * filename.count('/') + ['']), | 108 r'\1' + '/'.join(['..'] * filename.count('/') + ['']), |
110 content, re.S | re.I | 109 content, re.S | re.I |
111 ) | 110 ) |
112 | 111 |
113 | 112 |
114 def get_certificates_and_key(keyfile): | 113 def get_certificates_and_key(keyfile): |
115 from Crypto.PublicKey import RSA | 114 from Crypto.PublicKey import RSA |
116 | 115 |
117 certs = [] | |
118 with open(keyfile, 'r') as file: | 116 with open(keyfile, 'r') as file: |
119 data = file.read() | 117 data = file.read() |
120 keydata = re.sub(r'(-+END PRIVATE KEY-+).*', r'\1', data, flags=re.S) | 118 |
Sebastian Noack
2016/08/16 16:32:05
Is this even necessary? I would expect RSA.importK
Wladimir Palant
2016/08/16 17:06:04
Yes, I would expect that as well. However, I get "
Sebastian Noack
2016/08/17 08:43:07
I just noticed that this code assumes the key to b
Wladimir Palant
2016/08/17 10:03:15
True, PyCrypto seems to be angry about certificate
| |
121 key = RSA.importKey(keydata) | 119 certificates = [] |
122 | 120 key = None |
123 for match in re.finditer(r'-+BEGIN CERTIFICATE-+(.*?)-+END CERTIFICATE-+', d ata, re.S): | 121 for match in re.finditer(r'-+BEGIN (.*?)-+(.*?)-+END \1-+', data, re.S): |
124 certs.append(base64.b64decode(match.group(1))) | 122 section = match.group(1) |
125 | 123 if section == 'CERTIFICATE': |
126 return certs, key | 124 certificates.append(base64.b64decode(match.group(2))) |
125 elif section == 'PRIVATE KEY': | |
126 key = RSA.importKey(match.group(0)) | |
127 if not key: | |
128 raise Exception('Could not find private key in file') | |
129 | |
130 return certificates, key | |
131 | |
132 | |
133 def _get_sequence(data): | |
134 from Crypto.Util import asn1 | |
135 sequence = asn1.DerSequence() | |
136 sequence.decode(data) | |
137 return sequence | |
127 | 138 |
128 | 139 |
129 def get_developer_identifier(certs): | 140 def get_developer_identifier(certs): |
130 from Crypto.Util import asn1 | |
131 def get_sequence(data): | |
Sebastian Noack
2016/08/16 16:32:05
Any reason this is a nested function, and not just
Wladimir Palant
2016/08/16 17:06:04
It isn't exactly a general-purpose function - mere
Sebastian Noack
2016/08/17 08:43:07
It doesn't need to be general-purpose to go on the
Wladimir Palant
2016/08/17 10:03:15
Done.
| |
132 sequence = asn1.DerSequence() | |
133 sequence.decode(data) | |
134 return sequence | |
135 | |
136 for cert in certs: | 141 for cert in certs: |
137 # See https://tools.ietf.org/html/rfc5280#section-4 | 142 # See https://tools.ietf.org/html/rfc5280#section-4 |
138 tbsCertificate = get_sequence(cert)[0] | 143 tbscertificate = _get_sequence(cert)[0] |
Sebastian Noack
2016/08/16 16:32:05
Nit: camel case
Wladimir Palant
2016/08/16 17:06:04
I know. But that's how this field is named in the
Sebastian Noack
2016/08/17 08:43:07
That doesn't seem a reason to me, to violate PEP-8
Wladimir Palant
2016/08/17 10:03:15
Done.
| |
139 subject = get_sequence(tbsCertificate)[5] | 144 subject = _get_sequence(tbscertificate)[5] |
140 | 145 |
141 # We could decode the subject but since we have to apply a regular | 146 # We could decode the subject but since we have to apply a regular |
142 # expression on CN entry anyway we can just skip that. | 147 # expression on CN entry anyway we can just skip that. |
143 m = re.search(r'Safari Developer: \((\S*?)\)', subject) | 148 m = re.search(r'Safari Developer: \((\S*?)\)', subject) |
144 if m: | 149 if m: |
145 return m.group(1) | 150 return m.group(1) |
146 | 151 |
147 raise Exception('No Safari developer certificate found in chain') | 152 raise Exception('No Safari developer certificate found in chain') |
148 | 153 |
149 | 154 |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
198 os.close(fd) | 203 os.close(fd) |
199 | 204 |
200 # add certificates and placeholder signature | 205 # add certificates and placeholder signature |
201 # to the xar archive, and get data to sign | 206 # to the xar archive, and get data to sign |
202 fd, digest_filename = tempfile.mkstemp() | 207 fd, digest_filename = tempfile.mkstemp() |
203 os.close(fd) | 208 os.close(fd) |
204 try: | 209 try: |
205 subprocess.check_call( | 210 subprocess.check_call( |
206 [ | 211 [ |
207 'xar', '--sign', '-f', outFile, | 212 'xar', '--sign', '-f', outFile, |
208 '--data-to-sign', digest_filename, | 213 '--data-to-sign', digest_filename, |
Wladimir Palant
2016/08/16 15:12:08
For reference: despite the misleading name, --data
Wladimir Palant
2016/08/16 15:37:38
Actually, I finally realized what's going on there
| |
209 '--sig-size', str(len(sign_digest(key, ''))) | 214 '--sig-size', str(len(sign_digest(key, ''))) |
210 ] + [ | 215 ] + [ |
211 arg for cert in certificate_filenames for arg in ('--cert-lo c', cert) | 216 arg for cert in certificate_filenames for arg in ('--cert-lo c', cert) |
212 ] | 217 ] |
213 ) | 218 ) |
214 | 219 |
215 with open(digest_filename, 'rb') as file: | 220 with open(digest_filename, 'rb') as file: |
216 digest = file.read() | 221 digest = file.read() |
217 finally: | 222 finally: |
218 os.unlink(digest_filename) | 223 os.unlink(digest_filename) |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
283 fixAbsoluteUrls(files) | 288 fixAbsoluteUrls(files) |
284 | 289 |
285 dirname = metadata.get('general', 'basename') + '.safariextension' | 290 dirname = metadata.get('general', 'basename') + '.safariextension' |
286 for filename in files.keys(): | 291 for filename in files.keys(): |
287 files[os.path.join(dirname, filename)] = files.pop(filename) | 292 files[os.path.join(dirname, filename)] = files.pop(filename) |
288 | 293 |
289 if not devenv and keyFile: | 294 if not devenv and keyFile: |
290 createSignedXarArchive(outFile, files, certs, key) | 295 createSignedXarArchive(outFile, files, certs, key) |
291 else: | 296 else: |
292 files.zip(outFile) | 297 files.zip(outFile) |
LEFT | RIGHT |