11d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)#!/usr/bin/env python
21d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)#
31d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)# Copyright (C) 2013 The Android Open Source Project
41d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)#
51d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)# Licensed under the Apache License, Version 2.0 (the 'License');
61d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)# you may not use this file except in compliance with the License.
71d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)# You may obtain a copy of the License at
81d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)#
91d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)#      http://www.apache.org/licenses/LICENSE-2.0
101d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)#
111d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)# Unless required by applicable law or agreed to in writing, software
121d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)# distributed under the License is distributed on an 'AS IS' BASIS,
131d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
141d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)# See the License for the specific language governing permissions and
151d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)# limitations under the License.
161d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)#
171d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)
181d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)"""Check that a jar file contains only allowed packages.
191d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)
201d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)Given a jar file (typically, the result of running jarjar to rename packages)
211d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)and a whitelist file of allowed package names, one per line, check that all the
221d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)classes in the jar are in one of those packages.
231d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)"""
241d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)
251d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)import contextlib
261d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)import sys
271d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)import zipfile
281d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)
291d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)
301d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)def JarCheck(jar_path, whitelist_path):
311d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)  """Checks that the files in the jar are in whitelisted packages.
321d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)
331d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)  Args:
341d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)    jar_path: The path to the .jar file to be checked.
351d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)    whitelist_path: The path to the whitelist file.
361d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)  Returns:
371d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)    A list of files that are not in whitelisted packages.
381d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)  """
391d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)  with open(whitelist_path) as whitelist_file:
401d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)    allowed_packages = tuple(x.replace('.', '/').replace('\n', '/')
411d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)                             for x in whitelist_file)
421d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)
431d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)  with contextlib.closing(zipfile.ZipFile(jar_path)) as jar:
441d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)    jar_contents = jar.namelist()
451d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)
461d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)  invalid_files = []
471d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)  for filename in jar_contents:
481d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)    # Zipfile entries with a trailing / are directories, we can ignore these.
491d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)    # Also ignore jar meta-info.
501d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)    if filename.endswith('/') or filename.startswith('META-INF/'):
511d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)      continue
521d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)    if not filename.startswith(allowed_packages):
531d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)      invalid_files.append(filename)
541d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)
551d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)  return invalid_files
561d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)
571d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)
581d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)def main(argv):
591d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)  if len(argv) != 3:
601d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)    print >>sys.stderr, 'Usage: %s jar_file whitelist_file' % argv[0]
611d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)    return 2
621d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)  invalid_files = JarCheck(argv[1], argv[2])
631d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)  invalid_file_count = len(invalid_files)
641d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)  if invalid_file_count == 0:
651d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)    return 0
661d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)  print >>sys.stderr, ('jar_check found %s files not in a whitelisted package:'
671d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)                       % invalid_file_count)
681d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)  for f in invalid_files:
691d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)    print >>sys.stderr, f
701d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)  return 1
711d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)
721d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)
731d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)if __name__ == '__main__':
741d6f99d5c9c776f5cfc638b0e020fb08dd536dcaTorne (Richard Coles)  sys.exit(main(sys.argv))
75