 Issue 29322519:
  Issue 2796 - Added DeveloperIdentifier to Info.plist for Safari 9  (Closed)
    
  
    Issue 29322519:
  Issue 2796 - Added DeveloperIdentifier to Info.plist for Safari 9  (Closed) 
  | Left: | ||
| Right: | 
| OLD | NEW | 
|---|---|
| 1 # coding: utf-8 | 1 # coding: utf-8 | 
| 2 | 2 | 
| 3 # This Source Code Form is subject to the terms of the Mozilla Public | 3 # This Source Code Form is subject to the terms of the Mozilla Public | 
| 4 # License, v. 2.0. If a copy of the MPL was not distributed with this | 4 # License, v. 2.0. If a copy of the MPL was not distributed with this | 
| 5 # file, You can obtain one at http://mozilla.org/MPL/2.0/. | 5 # file, You can obtain one at http://mozilla.org/MPL/2.0/. | 
| 6 | 6 | 
| 7 import os | 7 import os | 
| 8 import re | 8 import re | 
| 9 import json | 9 import json | 
| 10 import ConfigParser | 10 import ConfigParser | 
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 82 author=get_optional('general', 'author'), | 82 author=get_optional('general', 'author'), | 
| 83 homepage=get_optional('general', 'homepage'), | 83 homepage=get_optional('general', 'homepage'), | 
| 84 updateURL=get_optional('general', 'updateURL'), | 84 updateURL=get_optional('general', 'updateURL'), | 
| 85 allowedDomains=allowedDomains, | 85 allowedDomains=allowedDomains, | 
| 86 allowAllDomains=allowAllDomains, | 86 allowAllDomains=allowAllDomains, | 
| 87 allowSecurePages=allowSecurePages, | 87 allowSecurePages=allowSecurePages, | 
| 88 startScripts=(get_optional('contentScripts', 'document_start') or '').split( ), | 88 startScripts=(get_optional('contentScripts', 'document_start') or '').split( ), | 
| 89 endScripts=(get_optional('contentScripts', 'document_end') or '').split(), | 89 endScripts=(get_optional('contentScripts', 'document_end') or '').split(), | 
| 90 menus=parse_section('menus', 2), | 90 menus=parse_section('menus', 2), | 
| 91 toolbarItems=parse_section('toolbar_items'), | 91 toolbarItems=parse_section('toolbar_items'), | 
| 92 popovers=parse_section('popovers') | 92 popovers=parse_section('popovers'), | 
| 93 developerIdentifier=params.get('developerIdentifier') | |
| 93 ).encode('utf-8') | 94 ).encode('utf-8') | 
| 94 | 95 | 
| 95 def createBackgroundPage(params): | 96 def createBackgroundPage(params): | 
| 96 template = getTemplate('background.html.tmpl', autoEscape=True) | 97 template = getTemplate('background.html.tmpl', autoEscape=True) | 
| 97 return template.render( | 98 return template.render( | 
| 98 backgroundScripts=params['metadata'].get( | 99 backgroundScripts=params['metadata'].get( | 
| 99 'general', 'backgroundScripts' | 100 'general', 'backgroundScripts' | 
| 100 ).split() | 101 ).split() | 
| 101 ).encode('utf-8') | 102 ).encode('utf-8') | 
| 102 | 103 | 
| 103 def createInfoModule(params): | 104 def createInfoModule(params): | 
| 104 template = getTemplate('safariInfo.js.tmpl') | 105 template = getTemplate('safariInfo.js.tmpl') | 
| 105 return template.render(params).encode('utf-8') | 106 return template.render(params).encode('utf-8') | 
| 106 | 107 | 
| 107 def fixAbsoluteUrls(files): | 108 def fixAbsoluteUrls(files): | 
| 108 for filename, content in files.iteritems(): | 109 for filename, content in files.iteritems(): | 
| 109 if os.path.splitext(filename)[1].lower() == '.html': | 110 if os.path.splitext(filename)[1].lower() == '.html': | 
| 110 files[filename] = re.sub( | 111 files[filename] = re.sub( | 
| 111 r'(<[^<>]*?\b(?:href|src)\s*=\s*["\']?)\/+', | 112 r'(<[^<>]*?\b(?:href|src)\s*=\s*["\']?)\/+', | 
| 112 r'\1' + '/'.join(['..'] * filename.count('/') + ['']), | 113 r'\1' + '/'.join(['..'] * filename.count('/') + ['']), | 
| 113 content, re.S | re.I | 114 content, re.S | re.I | 
| 114 ) | 115 ) | 
| 115 | 116 | 
| 116 def createSignedXarArchive(outFile, files, keyFile): | 117 def get_certificates_and_key(keyfile): | 
| 118 import M2Crypto | |
| 119 | |
| 120 certs = [] | |
| 121 bio = M2Crypto.BIO.openfile(keyfile) | |
| 122 | |
| 123 try: | |
| 124 key = M2Crypto.RSA.load_key_bio(bio) | |
| 125 bio.reset() | |
| 126 while True: | |
| 127 try: | |
| 128 certs.append(M2Crypto.X509.load_cert_bio(bio)) | |
| 129 except M2Crypto.X509.X509Error: | |
| 130 break | |
| 131 finally: | |
| 132 bio.close() | |
| 133 | |
| 134 return certs, key | |
| 135 | |
| 136 def get_developer_identifier(certs): | |
| 137 for cert in certs: | |
| 138 subject = cert.get_subject() | |
| 139 for entry in subject.get_entries_by_nid(subject.nid['CN']): | |
| 140 m = re.match(r'Safari Developer: \((.*?)\)', entry.get_data().as_text()) | |
| 141 if m: | |
| 142 return m.group(1) | |
| 143 | |
| 144 raise Exception('No Safari developer certificate found in chain') | |
| 145 | |
| 146 def createSignedXarArchive(outFile, files, certs, key): | |
| 117 import subprocess | 147 import subprocess | 
| 118 import tempfile | 148 import tempfile | 
| 119 import shutil | 149 import shutil | 
| 120 import M2Crypto | 150 import M2Crypto | 
| 121 | 151 | 
| 122 # write files to temporary directory and create a xar archive | 152 # write files to temporary directory and create a xar archive | 
| 123 dirname = tempfile.mkdtemp() | 153 dirname = tempfile.mkdtemp() | 
| 124 try: | 154 try: | 
| 125 for filename, contents in files.iteritems(): | 155 for filename, contents in files.iteritems(): | 
| 126 path = os.path.join(dirname, filename) | 156 path = os.path.join(dirname, filename) | 
| 127 | 157 | 
| 128 try: | 158 try: | 
| 129 os.makedirs(os.path.dirname(path)) | 159 os.makedirs(os.path.dirname(path)) | 
| 130 except OSError: | 160 except OSError: | 
| 131 pass | 161 pass | 
| 132 | 162 | 
| 133 with open(path, 'wb') as file: | 163 with open(path, 'wb') as file: | 
| 134 file.write(contents) | 164 file.write(contents) | 
| 135 | 165 | 
| 136 subprocess.check_output( | 166 subprocess.check_output( | 
| 137 ['xar', '-czf', os.path.abspath(outFile), '--distribution'] + os.listdir(d irname), | 167 ['xar', '-czf', os.path.abspath(outFile), '--distribution'] + os.listdir(d irname), | 
| 138 cwd=dirname | 168 cwd=dirname | 
| 139 ) | 169 ) | 
| 140 finally: | 170 finally: | 
| 141 shutil.rmtree(dirname) | 171 shutil.rmtree(dirname) | 
| 142 | 172 | 
| 143 certificate_filenames = [] | 173 certificate_filenames = [] | 
| 144 try: | 174 try: | 
| 145 # load key and certificates from the all-in-one key file | 175 # write each certificate in DER format to a seperate | 
| 
Wladimir Palant
2015/07/16 19:16:23
Nit: seperate => separate
 
Sebastian Noack
2015/07/17 11:07:22
Done.
 | |
| 146 # and write each certificate in DER format to a seperate | |
| 147 # temporary file, that they can be passed to xar | 176 # temporary file, that they can be passed to xar | 
| 148 bio = M2Crypto.BIO.openfile(keyFile) | 177 for cert in certs: | 
| 149 try: | 178 fd, filename = tempfile.mkstemp() | 
| 150 key = M2Crypto.RSA.load_key_bio(bio) | 179 try: | 
| 151 | 180 certificate_filenames.append(filename) | 
| 152 bio.reset() | 181 os.write(fd, cert.as_der()) | 
| 153 while True: | 182 finally: | 
| 154 try: | 183 os.close(fd) | 
| 155 cert = M2Crypto.X509.load_cert_bio(bio) | |
| 156 except M2Crypto.X509.X509Error: | |
| 157 break | |
| 158 | |
| 159 fd, filename = tempfile.mkstemp() | |
| 160 try: | |
| 161 certificate_filenames.append(filename) | |
| 162 os.write(fd, cert.as_der()) | |
| 163 finally: | |
| 164 os.close(fd) | |
| 165 finally: | |
| 166 bio.close() | |
| 167 | 184 | 
| 168 # add certificates and placeholder signature | 185 # add certificates and placeholder signature | 
| 169 # to the xar archive, and get data to sign | 186 # to the xar archive, and get data to sign | 
| 170 fd, digestinfo_filename = tempfile.mkstemp() | 187 fd, digestinfo_filename = tempfile.mkstemp() | 
| 171 os.close(fd) | 188 os.close(fd) | 
| 172 try: | 189 try: | 
| 173 subprocess.check_call( | 190 subprocess.check_call( | 
| 174 [ | 191 [ | 
| 175 'xar', '--sign', '-f', outFile, | 192 'xar', '--sign', '-f', outFile, | 
| 176 '--digestinfo-to-sign', digestinfo_filename, | 193 '--digestinfo-to-sign', digestinfo_filename, | 
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 234 | 251 | 
| 235 if metadata.has_section('preprocess'): | 252 if metadata.has_section('preprocess'): | 
| 236 files.preprocess( | 253 files.preprocess( | 
| 237 [f for f, _ in metadata.items('preprocess')], | 254 [f for f, _ in metadata.items('preprocess')], | 
| 238 {'needsExt': True} | 255 {'needsExt': True} | 
| 239 ) | 256 ) | 
| 240 | 257 | 
| 241 if metadata.has_section('import_locales'): | 258 if metadata.has_section('import_locales'): | 
| 242 importGeckoLocales(params, files) | 259 importGeckoLocales(params, files) | 
| 243 | 260 | 
| 261 if keyFile: | |
| 262 certs, key = get_certificates_and_key(keyFile) | |
| 263 params['developerIdentifier'] = get_developer_identifier(certs) | |
| 264 | |
| 244 files['lib/info.js'] = createInfoModule(params) | 265 files['lib/info.js'] = createInfoModule(params) | 
| 245 files['background.html'] = createBackgroundPage(params) | 266 files['background.html'] = createBackgroundPage(params) | 
| 246 files['Info.plist'] = createManifest(params, files) | 267 files['Info.plist'] = createManifest(params, files) | 
| 247 | 268 | 
| 248 fixAbsoluteUrls(files) | 269 fixAbsoluteUrls(files) | 
| 249 | 270 | 
| 250 dirname = metadata.get('general', 'basename') + '.safariextension' | 271 dirname = metadata.get('general', 'basename') + '.safariextension' | 
| 251 for filename in files.keys(): | 272 for filename in files.keys(): | 
| 252 files[os.path.join(dirname, filename)] = files.pop(filename) | 273 files[os.path.join(dirname, filename)] = files.pop(filename) | 
| 253 | 274 | 
| 254 if not devenv and keyFile: | 275 if not devenv and keyFile: | 
| 255 createSignedXarArchive(outFile, files, keyFile) | 276 createSignedXarArchive(outFile, files, certs, key) | 
| 256 else: | 277 else: | 
| 257 files.zip(outFile) | 278 files.zip(outFile) | 
| OLD | NEW |