0

Fix extension id calculation to take into account Windows encoding.

BUG=243532
TEST=updated and ran telemetry unit tests
NOTRY=true

Review URL: https://chromiumcodereview.appspot.com/16346003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@204380 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
tengs@chromium.org
2013-06-06 01:28:05 +00:00
parent cc8ade08b5
commit ac56fb35b5
4 changed files with 62 additions and 25 deletions

@@ -75,7 +75,7 @@ def GetPublicKeyPacked(f):
pub_key = f.read(pub_key_len_bytes)
return pub_key
def GetPublicKeyFromPath(filepath):
def GetPublicKeyFromPath(filepath, is_win_path=False):
# Normalize the path for windows to have capital drive letters.
# We intentionally don't check if sys.platform == 'win32' and just
# check if this looks like drive letter so that we can test this
@@ -83,7 +83,15 @@ def GetPublicKeyFromPath(filepath):
if (len(filepath) >= 2 and
filepath[0].islower() and
filepath[1] == ':'):
return filepath[0].upper() + filepath[1:]
filepath = filepath[0].upper() + filepath[1:]
# On Windows, filepaths are encoded using UTF-16, little endian byte order,
# using "wide characters" that are 16 bits in size. On POSIX systems, the
# encoding is generally UTF-8, which has the property of being equivalent to
# ASCII when only ASCII characters are in the path.
if is_win_path:
filepath = filepath.encode('utf-16le')
return filepath
def GetPublicKeyUnpacked(f, filepath):
@@ -102,9 +110,10 @@ def HasPublicKey(filename):
return 'key' in manifest
return False
def GetPublicKey(filename, from_file_path):
def GetPublicKey(filename, from_file_path, is_win_path=False):
if from_file_path:
return GetPublicKeyFromPath(filename)
return GetPublicKeyFromPath(
filename, is_win_path=is_win_path)
pub_key = ''
if os.path.isdir(filename):
@@ -119,13 +128,13 @@ def GetPublicKey(filename, from_file_path):
f.close()
return pub_key
def GetCRXHash(filename, from_file_path=False):
pub_key = GetPublicKey(filename, from_file_path)
def GetCRXHash(filename, from_file_path=False, is_win_path=False):
pub_key = GetPublicKey(filename, from_file_path, is_win_path=is_win_path)
pub_key_hash = hashlib.sha256(pub_key).digest()
return HexTo256(pub_key_hash)
def GetCRXAppID(filename, from_file_path=False):
pub_key = GetPublicKey(filename, from_file_path)
def GetCRXAppID(filename, from_file_path=False, is_win_path=False):
pub_key = GetPublicKey(filename, from_file_path, is_win_path=is_win_path)
pub_key_hash = hashlib.sha256(pub_key).digest()
# AppID is the MPDecimal of only the first 128 bits of the hash.
return HexToMPDecimal(pub_key_hash[:128/8])

@@ -63,13 +63,22 @@ class CrxIdUnittest(unittest.TestCase):
self.assertEqual(crx_id.GetCRXAppID('/tmp/temp_extension',
from_file_path=True),
'ajbbicncdkdlchpjplgjaglppbcbmaji')
def testFromWindowsPath(self):
self.assertEqual(crx_id.GetCRXAppID(r'D:\Documents\chrome\test_extension',
from_file_path=True,
is_win_path=True),
'fegemedmbnhglnecjgbdhekaghkccplm')
# Test drive letter normalization.
kWinPathId = 'popnagglbbhjlobnnbcjnckakjoegnjp'
self.assertEqual(crx_id.GetCRXAppID('c:\temp_extension',
from_file_path=True),
kWinPathId = 'aiinlcdagjihibappcdnnhcccdokjlaf'
self.assertEqual(crx_id.GetCRXAppID(r'c:\temp_extension',
from_file_path=True,
is_win_path=True),
kWinPathId)
self.assertEqual(crx_id.GetCRXAppID('C:\temp_extension',
from_file_path=True),
self.assertEqual(crx_id.GetCRXAppID(r'C:\temp_extension',
from_file_path=True,
is_win_path=True),
kWinPathId)
if __name__ == '__main__':

@@ -12,7 +12,7 @@ class MissingPublicKeyException(Exception):
pass
class ExtensionToLoad(object):
def __init__(self, path, is_component=False):
def __init__(self, path, browser_type, is_component=False):
if not os.path.isdir(path):
raise ExtensionPathNonExistentException(
'Extension path not a directory %s' % path)
@@ -23,6 +23,14 @@ class ExtensionToLoad(object):
raise MissingPublicKeyException(
'Component extension %s must have a public key' % path)
# It is possible that we are running telemetry on Windows targeting
# a remote CrOS or Android device. In this case, we need the
# browser_type argument to determine how we should encode
# the extension path.
self._is_win = (os.name == 'nt'
and not (browser_type.startswith('android')
or browser_type.startswith('cros')))
@property
def extension_id(self):
"""Unique extension id of this extension."""
@@ -31,8 +39,10 @@ class ExtensionToLoad(object):
return crx_id.GetCRXAppID(os.path.realpath(self._path))
else:
# Calculate extension id based on the path on the device.
return crx_id.GetCRXAppID(os.path.realpath(self._local_path),
from_file_path=True)
return crx_id.GetCRXAppID(
os.path.realpath(self._local_path),
from_file_path=True,
is_win_path=self._is_win)
@property
def path(self):

@@ -16,9 +16,10 @@ class ExtensionTest(unittest.TestCase):
def setUp(self):
extension_path = os.path.join(os.path.dirname(__file__),
'..', '..', 'unittest_data', 'simple_extension')
load_extension = extension_to_load.ExtensionToLoad(extension_path)
options = options_for_unittests.GetCopy()
load_extension = extension_to_load.ExtensionToLoad(
extension_path, options.browser_type)
options.extensions_to_load = [load_extension]
browser_to_create = browser_finder.FindBrowser(options)
@@ -60,15 +61,18 @@ class NonExistentExtensionTest(unittest.TestCase):
"""Test that a non-existent extension path will raise an exception."""
extension_path = os.path.join(os.path.dirname(__file__),
'..', '..', 'unittest_data', 'foo')
options = options_for_unittests.GetCopy()
self.assertRaises(extension_to_load.ExtensionPathNonExistentException,
lambda: extension_to_load.ExtensionToLoad(extension_path))
lambda: extension_to_load.ExtensionToLoad(
extension_path, options.browser_type))
def testExtensionNotLoaded(self):
"""Querying an extension that was not loaded will return None"""
extension_path = os.path.join(os.path.dirname(__file__),
'..', '..', 'unittest_data', 'simple_extension')
load_extension = extension_to_load.ExtensionToLoad(extension_path)
options = options_for_unittests.GetCopy()
load_extension = extension_to_load.ExtensionToLoad(
extension_path, options.browser_type)
browser_to_create = browser_finder.FindBrowser(options)
with browser_to_create.Create() as b:
if b.supports_extensions:
@@ -88,9 +92,10 @@ class MultipleExtensionTest(unittest.TestCase):
for d in self._extension_dirs:
shutil.copy(manifest_path, d)
shutil.copy(script_path, d)
self._extensions_to_load = [extension_to_load.ExtensionToLoad(d)
for d in self._extension_dirs]
options = options_for_unittests.GetCopy()
self._extensions_to_load = [extension_to_load.ExtensionToLoad(
d, options.browser_type)
for d in self._extension_dirs]
options.extensions_to_load = self._extensions_to_load
browser_to_create = browser_finder.FindBrowser(options)
self._browser = None
@@ -125,9 +130,10 @@ class ComponentExtensionTest(unittest.TestCase):
def testComponentExtensionBasic(self):
extension_path = os.path.join(os.path.dirname(__file__),
'..', '..', 'unittest_data', 'component_extension')
load_extension = extension_to_load.ExtensionToLoad(extension_path, True)
options = options_for_unittests.GetCopy()
load_extension = extension_to_load.ExtensionToLoad(
extension_path, options.browser_type, is_component=True)
options.extensions_to_load = [load_extension]
browser_to_create = browser_finder.FindBrowser(options)
if not browser_to_create:
@@ -144,6 +150,9 @@ class ComponentExtensionTest(unittest.TestCase):
# simple_extension does not have a public key.
extension_path = os.path.join(os.path.dirname(__file__),
'..', '..', 'unittest_data', 'simple_extension')
options = options_for_unittests.GetCopy()
self.assertRaises(extension_to_load.MissingPublicKeyException,
lambda: extension_to_load.ExtensionToLoad(extension_path,
True))
lambda: extension_to_load.ExtensionToLoad(
extension_path,
browser_type=options.browser_type,
is_component=True))