import os, sys, re COMMENT_PREFIXES = ["//", "/*", "*", "\'", "\""] REQUIRE_RE = r"(? %s You must enable it with: let {Cc,Ci,Cu,Cr,Cm} = require('chrome'); """ CHROME_ALIASES = ["Cc", "Ci", "Cu", "Cr", "Cm"] def scan_chrome(fn, lines, stderr): filename = os.path.basename(fn) if filename == "cuddlefish.js" or filename == "securable-module.js": return False, False # these are the loader problems = False asks_for_chrome = set() # Cc,Ci in: var {Cc,Ci} = require("chrome") asks_for_all_chrome = False # e.g.: var c = require("chrome") uses_chrome = set() uses_components = False uses_chrome_at = [] for lineno,line in enumerate(lines): # note: this scanner is not obligated to spot all possible forms of # chrome access. The scanner is detecting voluntary requests for # chrome. Runtime tools will enforce allowance or denial of access. line = line.strip() iscomment = False for commentprefix in COMMENT_PREFIXES: if line.startswith(commentprefix): iscomment = True if iscomment: continue mo = re.search(REQUIRE_RE, line) if mo: if mo.group(1) == "chrome": for alias in CHROME_ALIASES: if alias in line: asks_for_chrome.add(alias) if not asks_for_chrome: asks_for_all_chrome = True alias_in_this_line = False for wanted in CHROME_ALIASES: if re.search(r'\b'+wanted+r'\b', line): alias_in_this_line = True uses_chrome.add(wanted) uses_chrome_at.append( (wanted, lineno+1, line) ) if not alias_in_this_line and "Components." in line: uses_components = True uses_chrome_at.append( (None, lineno+1, line) ) problems = True break if uses_components or (uses_chrome - asks_for_chrome): problems = True print >>stderr, "" print >>stderr, "To use chrome authority, as in:" print >>stderr, " %s" % fn for (alias, lineno, line) in uses_chrome_at: if alias not in asks_for_chrome: print >>stderr, " %d> %s" % (lineno, line) print >>stderr, "You must enable it with something like:" uses = sorted(uses_chrome) if uses_components: uses.append("components") needed = ",".join(uses) print >>stderr, ' const {%s} = require("chrome");' % needed wants_chrome = bool(asks_for_chrome) or asks_for_all_chrome return wants_chrome, problems def scan_module(fn, lines, stderr=sys.stderr): # barfs on /\s+/ in context-menu.js #requires = scan_requirements_with_jsscan(fn) requires = scan_requirements_with_grep(fn, lines) requires.discard("chrome") chrome, problems = scan_chrome(fn, lines, stderr) return sorted(requires), chrome, problems def scan_package(pkg_name, dirname, stderr=sys.stderr): manifest = [] has_problems = False for dirpath, dirnames, filenames in os.walk(dirname): for fn in [fn for fn in filenames if fn.endswith(".js")]: modname = os.path.splitext(fn)[0] # turn "packages/jetpack-core/lib/content/foo" into "content/foo" reldir = dirpath[len(dirname)+1:] if reldir: modname = "/".join(reldir.split(os.sep) + [modname]) absfn = os.path.join(dirpath, fn) lines = open(absfn).readlines() requires, chrome, problems = scan_module(absfn, lines, stderr) manifest.append( (pkg_name, modname, requires, chrome) ) if problems: has_problems = True return manifest, has_problems if __name__ == '__main__': for fn in sys.argv[1:]: requires,chrome,problems = scan_module(fn, open(fn).readlines()) print print "---", fn if problems: print "PROBLEMS" sys.exit(1) print "chrome: %s" % chrome print "requires: %s" % (",".join(requires))