1 #!/usr/bin/python 2 # Copyright (c) 2013 The Chromium OS Authors. All rights reserved. 3 # Use of this source code is governed by a BSD-style license that can be 4 # found in the LICENSE file. 5 6 import httplib2 7 import json 8 import logging 9 import os 10 import re 11 import shutil 12 import urllib2 13 14 import common 15 16 from autotest_lib.client.common_lib import autotemp 17 from autotest_lib.client.common_lib import utils 18 19 20 TEST_EXTENSION_ID = 'hfaagokkkhdbgiakmmlclaapfelnkoah' 21 UPDATE_CHECK_URL = ('https://clients2.google.com/service/update2/') 22 UPDATE_CHECK_PARAMETER = ('crx?x=id%%3D%s%%26v%%3D0%%26uc') 23 MANIFEST_KEY = ('MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+hlN5FB+tjCsBszmBIvI' 24 'cD/djLLQm2zZfFygP4U4/o++ZM91EWtgII10LisoS47qT2TIOg4Un4+G57e' 25 'lZ9PjEIhcJfANqkYrD3t9dpEzMNr936TLB2u683B5qmbB68Nq1Eel7KVc+F' 26 '0BqhBondDqhvDvGPEV0vBsbErJFlNH7SQIDAQAB') 27 28 29 class SonicDownloaderException(Exception): 30 """Generic sonic dowloader exception.""" 31 pass 32 33 34 def get_download_url_from_omaha(extension_id): 35 """Retrieves an update url from omaha for the specified extension id. 36 37 @param extension_id: The extension id of the chromecast extension. 38 39 @return: A url to download the extension from. 40 41 @raises IOError: If the response returned by the omaha server is invalid. 42 """ 43 update_check_link = '%s%s' % (UPDATE_CHECK_URL, 44 UPDATE_CHECK_PARAMETER % extension_id) 45 response_xml = httplib2.Http().request(update_check_link, 'GET')[1] 46 codebase_match = re.compile(r'codebase="(.*crx)"').search(response_xml) 47 if codebase_match is not None: 48 logging.info('Omaha response while downloading extension: %s', 49 response_xml) 50 return codebase_match.groups()[0] 51 raise IOError('Omaha response is invalid %s.' % response_xml) 52 53 54 def download_extension(dest_file): 55 """Retrieve the extension into a destination crx file. 56 57 @param dest_file: Path to a destination file for the extension. 58 """ 59 download_url = get_download_url_from_omaha(TEST_EXTENSION_ID) 60 logging.info('Downloading extension from %s', download_url) 61 response = urllib2.urlopen(download_url) 62 with open(dest_file, 'w') as f: 63 f.write(response.read()) 64 65 66 def fix_public_key(extracted_extension_folder): 67 """Modifies the manifest.json to include a public key. 68 69 This function will erase the content in the original manifest 70 and replace it with a new manifest that contains the key. 71 72 @param extracted_extension_folder: The folder containing 73 the extracted extension. 74 """ 75 manifest_json_file = os.path.join(extracted_extension_folder, 76 'manifest.json') 77 with open(manifest_json_file, 'r') as f: 78 manifest_json = json.loads(f.read()) 79 80 manifest_json['key'] = MANIFEST_KEY 81 82 with open(manifest_json_file, 'w') as f: 83 f.write(json.dumps(manifest_json)) 84 85 86 def setup_extension(unzipped_crx_dir): 87 """Setup for tests that need a chromecast extension. 88 89 Download the extension from an omaha server, unzip it and modify its 90 manifest.json to include a public key. 91 92 @param unzipped_crx_dir: Destination directory for the unzipped extension. 93 94 @raises CmdTimeoutError: If we timeout unzipping the extension. 95 """ 96 output_crx_dir = autotemp.tempdir() 97 output_crx = os.path.join(output_crx_dir.name, 'sonic_extension.crx') 98 try: 99 download_extension(output_crx) 100 unzip_cmd = 'unzip -o "%s" -d "%s"' % (output_crx, unzipped_crx_dir) 101 102 # The unzip command will return a non-zero exit status if there are 103 # extra bytes at the start/end of the zipfile. This is not a critical 104 # failure and the extension will still work. 105 cmd_output = utils.run(unzip_cmd, ignore_status=True, timeout=1) 106 except Exception as e: 107 if os.path.exists(unzipped_crx_dir): 108 shutil.rmtree() 109 raise SonicDownloaderException(e) 110 finally: 111 if os.path.exists(output_crx): 112 os.remove(output_crx) 113 output_crx_dir.clean() 114 115 if not os.path.exists(unzipped_crx_dir): 116 raise SonicDownloaderException('Unable to download sonic extension.') 117 logging.info('Sonic extension successfully downloaded into %s.', 118 unzipped_crx_dir) 119 120 # TODO(beeps): crbug.com/325869, investigate the limits of component 121 # extensions. For now this is ok because even sonic testing inlines a 122 # public key for their test extension. 123 try: 124 fix_public_key(unzipped_crx_dir) 125 except Exception as e: 126 shutil.rmtree(unzipped_crx_dir) 127 raise SonicDownloaderException(e) 128