| #!/usr/bin/python |
| # Copyright (c) 2013 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import httplib2 |
| import json |
| import os |
| import re |
| import shutil |
| import urllib2 |
| |
| import common |
| |
| from autotest_lib.client.common_lib import utils |
| |
| version = 1 |
| |
| TEST_EXTENSION_ID = 'hfaagokkkhdbgiakmmlclaapfelnkoah' |
| UPDATE_CHECK_URL = ('https://clients2.google.com/service/update2/') |
| UPDATE_CHECK_PARAMETER = ('crx?x=id%%3D%s%%26v%%3D0%%26uc') |
| MANIFEST_KEY = ('MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+hlN5FB+tjCsBszmBIvI' |
| 'cD/djLLQm2zZfFygP4U4/o++ZM91EWtgII10LisoS47qT2TIOg4Un4+G57e' |
| 'lZ9PjEIhcJfANqkYrD3t9dpEzMNr936TLB2u683B5qmbB68Nq1Eel7KVc+F' |
| '0BqhBondDqhvDvGPEV0vBsbErJFlNH7SQIDAQAB') |
| |
| |
| def get_download_url_from_omaha(extension_id): |
| """Retrieves an update url from omaha for the specified extension id. |
| |
| @param extension_id: The extension id of the chromecast extension. |
| |
| @return: A url to download the extension from. |
| |
| @raises IOError: If the response returned by the omaha server is invalid. |
| """ |
| update_check_link = '%s%s' % (UPDATE_CHECK_URL, |
| UPDATE_CHECK_PARAMETER % extension_id) |
| response_xml = httplib2.Http().request(update_check_link, 'GET')[1] |
| codebase_match = re.compile(r'codebase="(.*crx)"').search(response_xml) |
| if codebase_match is not None: |
| return codebase_match.groups()[0] |
| raise IOError('Omaha response is invalid %s.' % response_xml) |
| |
| |
| def download_extension(dest_file): |
| """Retrieve the extension into a destination crx file. |
| |
| @param dest_file: Path to a destination file for the extension. |
| """ |
| download_url = get_download_url_from_omaha(TEST_EXTENSION_ID) |
| response = urllib2.urlopen(download_url) |
| with open(dest_file, 'w') as f: |
| f.write(response.read()) |
| |
| |
| def fix_public_key(extracted_extension_folder): |
| """Modifies the manifest.json to include a public key. |
| |
| This function will erase the content in the original manifest |
| and replace it with a new manifest that contains the key. |
| |
| @param extracted_extension_folder: The folder containing |
| the extracted extension. |
| """ |
| manifest_json_file = os.path.join(extracted_extension_folder, |
| 'manifest.json') |
| with open(manifest_json_file, 'r') as f: |
| manifest_json = json.loads(f.read()) |
| |
| manifest_json['key'] = MANIFEST_KEY |
| |
| with open(manifest_json_file, 'w') as f: |
| f.write(json.dumps(manifest_json)) |
| |
| |
| def setup(output_crx, unzipped_crx_dir): |
| """Setup for tests that need a chromecast extension. |
| |
| Download the extension from an omaha server, unzip it and modify its |
| manifest.json to include a public key. |
| |
| @param output_crx: The name of the crx file into which we will download |
| the extension. If this file already exists it will get |
| re-written. |
| @param unzipped_crx_dir: A directory for the unzipped extension. |
| |
| @raises CmdTimeoutError: If we timeout unzipping the extension. |
| """ |
| download_extension(output_crx) |
| unzip_cmd = 'unzip -o "%s" -d "%s"' % (output_crx, unzipped_crx_dir) |
| |
| # The unzip command will return a non-zero exit status if there are |
| # extra bytes at the start/end of the zipfile. This is not a critical |
| # failure and the extension will still work. |
| cmd_output = utils.run(unzip_cmd, ignore_status=True, timeout=1) |
| if not os.path.exists(unzipped_crx_dir): |
| raise IOError('Unzip failed, command %s, stderr %s', unzip_cmd, |
| cmd_output.stderr) |
| |
| # TODO(beeps): crbug.com/325869, investigate the limits of component |
| # extensions. For now this is ok because even sonic testing inlines a |
| # public key for their test extension. |
| fix_public_key(unzipped_crx_dir) |
| |
| |
| srcdir = os.path.join(os.getcwd(), 'src') |
| output_crx = os.path.join(srcdir, 'sonic_extension.crx') |
| unzipped_crx_dir = os.path.join(os.path.dirname(output_crx), |
| re.split('[.]', os.path.basename(output_crx))[0]) |
| |
| try: |
| setup(output_crx, unzipped_crx_dir) |
| except: |
| if os.path.exists(unzipped_crx_dir): |
| shutil.rmtree(unzipped_crx_dir, ignore_errors=True) |
| raise |
| finally: |
| if os.path.exists(output_crx): |
| os.remove(output_crx) |