Added full JS unicode support
This commit is contained in:
Родитель
b6c800a8d4
Коммит
509ef8872d
|
@ -287,12 +287,14 @@ def _call_expression(traverser, node):
|
|||
result = dangerous(a=args, t=t)
|
||||
if result:
|
||||
# Generate a string representation of the params
|
||||
params = ", ".join([str(t(p).get_literal_value()) for p in args])
|
||||
params = ", ".join([unicode(t(p).get_literal_value()) for
|
||||
p in args])
|
||||
traverser.err.warning(("testcases_javascript_actions",
|
||||
"_call_expression",
|
||||
"called_dangerous_global"),
|
||||
"Global called in dangerous manner",
|
||||
result if isinstance(result, str) else
|
||||
result if isinstance(result,
|
||||
types.StringTypes) else
|
||||
"A global function was called using a set "
|
||||
"of dangerous parameters. These parameters "
|
||||
"have been disallowed.",
|
||||
|
@ -414,10 +416,10 @@ def _expr_assignment(traverser, node):
|
|||
if lit_right is None:
|
||||
lit_right = 0
|
||||
|
||||
if isinstance(lit_left, (str, unicode)) or \
|
||||
isinstance(lit_right, (str, unicode)):
|
||||
lit_left = str(lit_left)
|
||||
lit_right = str(lit_right)
|
||||
if isinstance(lit_left, types.StringTypes) or \
|
||||
isinstance(lit_right, types.StringTypes):
|
||||
lit_left = unicode(lit_left)
|
||||
lit_right = unicode(lit_right)
|
||||
|
||||
gleft = _get_as_num(left)
|
||||
gright = _get_as_num(right)
|
||||
|
@ -442,8 +444,8 @@ def _expr_assignment(traverser, node):
|
|||
traverser.debug_level -= 1
|
||||
return left
|
||||
|
||||
traverser._debug("ASSIGNMENT::LEFT>>%s" % str(left.is_global))
|
||||
traverser._debug("ASSIGNMENT::RIGHT>>%s" % str(operators[token]()))
|
||||
traverser._debug("ASSIGNMENT::LEFT>>%s" % unicode(left.is_global))
|
||||
traverser._debug("ASSIGNMENT::RIGHT>>%s" % unicode(operators[token]()))
|
||||
left.set_value(operators[token](), traverser=traverser)
|
||||
traverser.debug_level -= 1
|
||||
return left
|
||||
|
@ -465,7 +467,7 @@ def _expr_binary(traverser, node):
|
|||
left = traverser._traverse_node(node["left"])
|
||||
if not isinstance(left, JSWrapper):
|
||||
left = JSWrapper(left, traverser=traverser)
|
||||
traverser._debug(str(left.dirty))
|
||||
traverser._debug(unicode(left.dirty))
|
||||
|
||||
traverser.debug_level -= 1
|
||||
|
||||
|
@ -475,7 +477,7 @@ def _expr_binary(traverser, node):
|
|||
right = traverser._traverse_node(node["right"])
|
||||
if not isinstance(right, JSWrapper):
|
||||
right = JSWrapper(right, traverser=traverser)
|
||||
traverser._debug(str(right.dirty))
|
||||
traverser._debug(unicode(right.dirty))
|
||||
|
||||
if left.dirty:
|
||||
return left
|
||||
|
@ -585,7 +587,7 @@ def _get_as_num(value):
|
|||
return False
|
||||
|
||||
try:
|
||||
if isinstance(value, str):
|
||||
if isinstance(value, types.StringTypes):
|
||||
return float(value)
|
||||
elif isinstance(value, int) or isinstance(value, float):
|
||||
return value
|
||||
|
|
|
@ -9,7 +9,7 @@ traverser
|
|||
node
|
||||
the current node being evaluated
|
||||
"""
|
||||
|
||||
import types
|
||||
from jstypes import *
|
||||
|
||||
|
||||
|
@ -21,10 +21,11 @@ def createElement(args, traverser, node):
|
|||
|
||||
simple_args = [traverser._traverse_node(a) for a in args]
|
||||
|
||||
if str(simple_args[0].get_literal_value()).lower() == "script":
|
||||
if unicode(simple_args[0].get_literal_value()).lower() == u"script":
|
||||
_create_script_tag(traverser)
|
||||
elif not (simple_args[0].is_literal() or
|
||||
isinstance(simple_args[0].get_literal_value(), str)):
|
||||
isinstance(simple_args[0].get_literal_value(),
|
||||
types.StringTypes)):
|
||||
_create_variable_element(traverser)
|
||||
|
||||
|
||||
|
@ -36,10 +37,11 @@ def createElementNS(args, traverser, node):
|
|||
|
||||
simple_args = [traverser._traverse_node(a) for a in args]
|
||||
|
||||
if "script" in str(simple_args[1].get_literal_value()).lower():
|
||||
if "script" in unicode(simple_args[1].get_literal_value()).lower():
|
||||
_create_script_tag(traverser)
|
||||
elif not (simple_args[1].is_literal() or
|
||||
isinstance(simple_args[1].get_literal_value(), str)):
|
||||
isinstance(simple_args[1].get_literal_value(),
|
||||
types.StringTypes)):
|
||||
_create_variable_element(traverser)
|
||||
|
||||
|
||||
|
@ -85,7 +87,7 @@ def setAttribute(args, traverser, node):
|
|||
|
||||
simple_args = [traverser._traverse_node(a) for a in args]
|
||||
|
||||
if str(simple_args[0].get_literal_value()).lower().startswith("on"):
|
||||
if unicode(simple_args[0].get_literal_value()).lower().startswith("on"):
|
||||
traverser.err.notice(
|
||||
err_id=("testcases_javascript_instanceactions", "setAttribute",
|
||||
"setting_on*"),
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
import re
|
||||
import types
|
||||
|
||||
import jstypes
|
||||
|
||||
def set_innerHTML(new_value, traverser):
|
||||
"Tests that values being assigned to innerHTML are not dangerous"
|
||||
|
||||
if not isinstance(new_value, jstypes.JSWrapper):
|
||||
new_value = jstypes.JSWrapper(new_value, traverser=traverser)
|
||||
literal_value = new_value.get_literal_value()
|
||||
if isinstance(literal_value, types.StringTypes):
|
||||
# Static string assignments
|
||||
|
@ -16,9 +19,11 @@ def set_innerHTML(new_value, traverser):
|
|||
err_id=("testcases_javascript_instancetypes", "set_innerHTML",
|
||||
"event_assignment"),
|
||||
warning="Event handler assignment via innerHTML",
|
||||
description="When assigning event handlers, innerHTML "
|
||||
"should never be used. Rather, use a "
|
||||
"proper technique, like addEventListener.",
|
||||
description=["When assigning event handlers, innerHTML "
|
||||
"should never be used. Rather, use a "
|
||||
"proper technique, like addEventListener.",
|
||||
"Event handler code: %s" %
|
||||
literal_value.encode("ascii", "replace")],
|
||||
filename=traverser.filename,
|
||||
line=traverser.line,
|
||||
column=traverser.position,
|
||||
|
|
|
@ -19,7 +19,7 @@ class JSObject(object):
|
|||
|
||||
def get(self, name):
|
||||
"Returns the value associated with a property name"
|
||||
name = str(name)
|
||||
name = unicode(name)
|
||||
return self.data[name] if name in self.data else None
|
||||
|
||||
def get_literal_value(self):
|
||||
|
@ -36,11 +36,11 @@ class JSObject(object):
|
|||
self.data[name] = value
|
||||
|
||||
def has_var(self, name):
|
||||
name = str(name)
|
||||
name = unicode(name)
|
||||
return name in self.data
|
||||
|
||||
def output(self):
|
||||
return str(self.data)
|
||||
return unicode(self.data)
|
||||
|
||||
|
||||
class JSContext(JSObject):
|
||||
|
@ -56,7 +56,7 @@ class JSContext(JSObject):
|
|||
def output(self):
|
||||
output = {}
|
||||
for (name, item) in self.data.items():
|
||||
output[name] = str(item)
|
||||
output[name] = unicode(item)
|
||||
return json.dumps(output)
|
||||
|
||||
|
||||
|
@ -273,7 +273,7 @@ class JSWrapper(object):
|
|||
|
||||
def __str__(self):
|
||||
"""Returns a textual version of the object."""
|
||||
return str(self.get_literal_value())
|
||||
return unicode(self.get_literal_value())
|
||||
|
||||
|
||||
class JSLiteral(JSObject):
|
||||
|
@ -309,7 +309,7 @@ class JSPrototype(JSObject):
|
|||
|
||||
def get(self, name):
|
||||
"Enables static analysis of `with` statements"
|
||||
name = str(name)
|
||||
name = unicode(name)
|
||||
output = None
|
||||
if name in self.data:
|
||||
output = self.data[name]
|
||||
|
@ -351,7 +351,7 @@ class JSArray(JSObject):
|
|||
# Interestingly enough, this allows for things like:
|
||||
# x = [4]
|
||||
# y = x * 3 // y = 12 since x equals "4"
|
||||
return ",".join([str(w.get_literal_value()) for w in self.elements])
|
||||
return ",".join([unicode(w.get_literal_value()) for w in self.elements])
|
||||
|
||||
def set(self, index, value, traverser=None):
|
||||
"""Follow the rules of JS for creating an array"""
|
||||
|
|
|
@ -16,92 +16,92 @@ BANNED_IDENTIFIERS = ("newThread", )
|
|||
|
||||
# GLOBAL_ENTITIES is also representative of the `window` object.
|
||||
GLOBAL_ENTITIES = {
|
||||
"window": {"value": lambda: GLOBAL_ENTITIES},
|
||||
"document":
|
||||
{"value": {"createElement":
|
||||
u"window": {"value": lambda: GLOBAL_ENTITIES},
|
||||
u"document":
|
||||
{"value": {u"createElement":
|
||||
{"dangerous":
|
||||
lambda a, t: t(a[0]).get_literal_value()
|
||||
.lower() == "script"},
|
||||
"createElementNS":
|
||||
u"createElementNS":
|
||||
{"dangerous":
|
||||
lambda a, t: t(a[0]).get_literal_value()
|
||||
.lower() == "script"}}},
|
||||
|
||||
# The nefariuos timeout brothers!
|
||||
"setTimeout": {"dangerous": actions._call_settimeout},
|
||||
"setInterval": {"dangerous": actions._call_settimeout},
|
||||
u"setTimeout": {"dangerous": actions._call_settimeout},
|
||||
u"setInterval": {"dangerous": actions._call_settimeout},
|
||||
|
||||
"encodeURI": {"readonly": True},
|
||||
"decodeURI": {"readonly": True},
|
||||
"encodeURIComponent": {"readonly": True},
|
||||
"decodeURIComponent": {"readonly": True},
|
||||
"escape": {"readonly": True},
|
||||
"unescape": {"readonly": True},
|
||||
"isFinite": {"readonly": True},
|
||||
"isNaN": {"readonly": True},
|
||||
"parseFloat": {"readonly": True},
|
||||
"parseInt": {"readonly": True},
|
||||
u"encodeURI": {"readonly": True},
|
||||
u"decodeURI": {"readonly": True},
|
||||
u"encodeURIComponent": {"readonly": True},
|
||||
u"decodeURIComponent": {"readonly": True},
|
||||
u"escape": {"readonly": True},
|
||||
u"unescape": {"readonly": True},
|
||||
u"isFinite": {"readonly": True},
|
||||
u"isNaN": {"readonly": True},
|
||||
u"parseFloat": {"readonly": True},
|
||||
u"parseInt": {"readonly": True},
|
||||
|
||||
"eval": {"dangerous": True},
|
||||
"Function": {"dangerous": True},
|
||||
"Object": {"value": {"prototype": {"dangerous": True},
|
||||
"constructor": # Just an experiment for now
|
||||
{"value": lambda: GLOBAL_ENTITIES["Function"]}}},
|
||||
"String": {"value": {"prototype": {"dangerous": True}}},
|
||||
"Array": {"value": {"prototype": {"dangerous": True}}},
|
||||
"Number": {"value": {"prototype": {"dangerous": True}}},
|
||||
"Boolean": {"value": {"prototype": {"dangerous": True}}},
|
||||
"RegExp": {"value": {"prototype": {"dangerous": True}}},
|
||||
"Date": {"value": {"prototype": {"dangerous": True}}},
|
||||
u"eval": {"dangerous": True},
|
||||
u"Function": {"dangerous": True},
|
||||
u"Object": {"value": {"prototype": {"dangerous": True},
|
||||
"constructor": # Just an experiment for now
|
||||
{"value": lambda: GLOBAL_ENTITIES["Function"]}}},
|
||||
u"String": {"value": {"prototype": {"dangerous": True}}},
|
||||
u"Array": {"value": {"prototype": {"dangerous": True}}},
|
||||
u"Number": {"value": {"prototype": {"dangerous": True}}},
|
||||
u"Boolean": {"value": {"prototype": {"dangerous": True}}},
|
||||
u"RegExp": {"value": {"prototype": {"dangerous": True}}},
|
||||
u"Date": {"value": {"prototype": {"dangerous": True}}},
|
||||
|
||||
"Math": {"readonly": True},
|
||||
u"Math": {"readonly": True},
|
||||
|
||||
"netscape":
|
||||
{"value": {"security":
|
||||
{"value": {"PrivilegeManager":
|
||||
{"value": {"enablePrivilege":
|
||||
u"netscape":
|
||||
{"value": {u"security":
|
||||
{"value": {u"PrivilegeManager":
|
||||
{"value": {u"enablePrivilege":
|
||||
{"dangerous": True}}}}}}},
|
||||
|
||||
"navigator":
|
||||
{"value": {"wifi": {"dangerous": True},
|
||||
"geolocation": {"dangerous": True}}},
|
||||
u"navigator":
|
||||
{"value": {u"wifi": {"dangerous": True},
|
||||
u"geolocation": {"dangerous": True}}},
|
||||
|
||||
"Components":
|
||||
u"Components":
|
||||
{"readonly": True,
|
||||
"value":
|
||||
{"classes":
|
||||
{"xpcom_wildcard": True,
|
||||
{u"classes":
|
||||
{u"xpcom_wildcard": True,
|
||||
"value":
|
||||
{"createInstance":
|
||||
{u"createInstance":
|
||||
{"return": call_definitions.xpcom_createInstance}}},
|
||||
"utils":
|
||||
{"value": {"evalInSandbox":
|
||||
u"utils":
|
||||
{"value": {u"evalInSandbox":
|
||||
{"dangerous": True},
|
||||
"import":
|
||||
u"import":
|
||||
{"dangerous":
|
||||
lambda a, t:
|
||||
a and \
|
||||
str(t(a[0]).get_literal_value())
|
||||
.count("ctypes.jsm")}}},
|
||||
"interfaces":
|
||||
{"value": {"nsIXMLHttpRequest":
|
||||
unicode(t(a[0]).get_literal_value())
|
||||
.count("ctypes.jsm")}}},
|
||||
u"interfaces":
|
||||
{"value": {u"nsIXMLHttpRequest":
|
||||
{"xpcom_map":
|
||||
lambda:
|
||||
GLOBAL_ENTITIES["XMLHttpRequest"]},
|
||||
"nsIProcess":
|
||||
u"nsIProcess":
|
||||
{"dangerous": True},
|
||||
"nsIDOMGeoGeolocation":
|
||||
u"nsIDOMGeoGeolocation":
|
||||
{"dangerous": True},
|
||||
"nsIX509CertDB":
|
||||
u"nsIX509CertDB":
|
||||
{"dangerous": True},
|
||||
"mozIJSSubScriptLoader":
|
||||
u"mozIJSSubScriptLoader":
|
||||
{"dangerous": True}}}}},
|
||||
"extensions": {"dangerous": True},
|
||||
"xpcnativewrappers": {"dangerous": True},
|
||||
u"extensions": {"dangerous": True},
|
||||
u"xpcnativewrappers": {"dangerous": True},
|
||||
|
||||
"XMLHttpRequest":
|
||||
u"XMLHttpRequest":
|
||||
{"value":
|
||||
{"open": {"dangerous":
|
||||
{u"open": {"dangerous":
|
||||
# Ban syncrhonous XHR by making sure the third arg
|
||||
# is absent and false.
|
||||
lambda a, t:
|
||||
|
@ -114,7 +114,7 @@ GLOBAL_ENTITIES = {
|
|||
"connections."}}},
|
||||
|
||||
# Global properties are inherently read-only, though this formalizes it.
|
||||
"Infinity": {"readonly": True},
|
||||
"NaN": {"readonly": True},
|
||||
"undefined": {"readonly": True},
|
||||
u"Infinity": {"readonly": True},
|
||||
u"NaN": {"readonly": True},
|
||||
u"undefined": {"readonly": True},
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ def get_tree(code, err=None, filename=None, shell=None):
|
|||
str_exc = str(exc).strip("'\"")
|
||||
if ("SyntaxError" in str_exc or
|
||||
"ReferenceError" in str_exc):
|
||||
open("testfiles/foo.js", mode="w+b").write(code)
|
||||
err.warning(("testcases_scripting",
|
||||
"test_js_file",
|
||||
"syntax_error"),
|
||||
|
|
|
@ -42,10 +42,12 @@ class MockBundler:
|
|||
|
||||
self.ids.append(id)
|
||||
|
||||
error = unicode(error)
|
||||
|
||||
print "-" * 30
|
||||
print error
|
||||
print error.encode("ascii", "replace")
|
||||
print "~" * len(error)
|
||||
if isinstance(description, str):
|
||||
if isinstance(description, types.StringTypes):
|
||||
print description
|
||||
else:
|
||||
# Errors can have multiple lines
|
||||
|
@ -105,12 +107,14 @@ class Traverser:
|
|||
output = data
|
||||
if isinstance(data, JSObject) or isinstance(data, JSContext):
|
||||
output = data.output()
|
||||
print ". " * self.debug_level + output
|
||||
|
||||
output = unicode(output)
|
||||
print ". " * self.debug_level + output.encode("ascii", "replace")
|
||||
|
||||
def run(self, data):
|
||||
if DEBUG:
|
||||
x = open("/tmp/output.js", "w")
|
||||
x.write(str(data))
|
||||
x.write(unicode(data))
|
||||
x.close()
|
||||
|
||||
if "type" not in data or not self._can_handle_node(data["type"]):
|
||||
|
@ -189,7 +193,7 @@ class Traverser:
|
|||
if action is not None:
|
||||
action_result = action(self, node)
|
||||
self._debug("ACTION>>%s (%s)" %
|
||||
("halt>>%s" % str(action_result) if
|
||||
("halt>>%s" % unicode(action_result) if
|
||||
action_result else
|
||||
"continue",
|
||||
node["type"]))
|
||||
|
@ -350,7 +354,8 @@ class Traverser:
|
|||
"_build_global",
|
||||
"dangerous_global"),
|
||||
"Dangerous Global Object",
|
||||
[dang if isinstance(dang, str) else
|
||||
[dang if
|
||||
isinstance(dang, types.StringTypes) else
|
||||
"A dangerous or banned global object was "
|
||||
"accessed by some JavaScript code.",
|
||||
"Accessed object: %s" % name],
|
||||
|
|
Загрузка…
Ссылка в новой задаче