def string_global(wrapper, arguments, traverser): if (not arguments or not arguments[0].get_literal_value(traverser)): return JSObject(traverser=traverser) return JSLiteral( utils.get_as_str(arguments[0].get_literal_value(traverser)), traverser=traverser)
def _get_member_exp_property(traverser, node): """Return the string value of a member expression's property.""" if node["property"]["type"] == "Identifier" and not node["computed"]: return unicode(node["property"]["name"]) else: eval_exp = traverser.traverse_node(node["property"]) return utils.get_as_str(eval_exp.get_literal_value(traverser))
def createElement(args, traverser, wrapper): """Handles createElement calls""" if not args: return first_as_str = utils.get_as_str(args[0].get_literal_value()) if first_as_str.lower() == u"script": _create_script_tag(traverser) elif not isinstance(args[0], jstypes.JSLiteral): _create_variable_element(traverser)
def createElementNS(args, traverser, wrapper): """Handles createElementNS calls""" if not args or len(args) < 2: return second_as_str = utils.get_as_str(args[1].get_literal_value()) if "script" in second_as_str.lower(): _create_script_tag(traverser) elif not isinstance(args[1], jstypes.JSLiteral): _create_variable_element(traverser)
def createElement(args, traverser, wrapper): """Handles createElement calls""" if not args: return first_as_str = utils.get_as_str(args[0].get_literal_value(traverser)) if first_as_str.lower() == u"script": _create_script_tag(traverser) elif not isinstance(args[0], jstypes.JSLiteral): _create_variable_element(traverser)
def createElementNS(args, traverser, wrapper): """Handles createElementNS calls""" if not args or len(args) < 2: return second_as_str = utils.get_as_str(args[1].get_literal_value(traverser)) if "script" in second_as_str.lower(): _create_script_tag(traverser) elif not isinstance(args[1], jstypes.JSLiteral): _create_variable_element(traverser)
def setAttribute(args, traverser, wrapper): """This ensures that setAttribute calls don't set on* attributes""" if not args: return first_as_str = utils.get_as_str(args[0].get_literal_value()) if first_as_str.lower().startswith("on"): warn(traverser.err, filename=traverser.filename, line=traverser.line, column=traverser.position, context=traverser.context, violation_type="setAttribute-on")
def setAttribute(args, traverser, wrapper): """This ensures that setAttribute calls don't set on* attributes""" if not args: return first_as_str = utils.get_as_str(args[0].get_literal_value(traverser)) if first_as_str.lower().startswith("on"): warn(traverser.err, filename=traverser.filename, line=traverser.line, column=traverser.position, context=traverser.context, violation_type="setAttribute-on")
def _process_literal(type_, literal): if type_ == "string": return utils.get_as_str(literal) elif type_ == "num": return utils.get_as_num(literal) return literal
def string_global(wrapper, arguments, traverser): if (not arguments or not arguments[0].get_literal_value(traverser)): return JSObject(traverser=traverser) return JSLiteral(utils.get_as_str( arguments[0].get_literal_value(traverser)), traverser=traverser)
def AssignmentExpression(traverser, node): traverser._debug("ASSIGNMENT_EXPRESSION") traverser.debug_level += 1 traverser._debug("ASSIGNMENT>>PARSING RIGHT") right = traverser.traverse_node(node["right"]) traverser._debug("ASSIGNMENT>>PARSING LEFT") orig_left = left = traverser.traverse_node(node["left"]) operator = node["operator"] def set_lvalue(value): node_left = node["left"] traverser._debug("ASSIGNING:DIRECT(%s)" % node_left["type"]) global_overwrite = False readonly_value = True if node_left["type"] == "Identifier": # Identifiers just need the ID name and a value to push. # Raise a global overwrite issue if the identifier is global. global_overwrite = traverser._is_global(node_left["name"]) # Get the readonly attribute and store its value if is_global if global_overwrite: from predefinedentities import GLOBAL_ENTITIES global_dict = GLOBAL_ENTITIES[node_left["name"]] readonly_value = global_dict.get("readonly", False) traverser._declare_variable(node_left["name"], value, type_="glob") elif node_left["type"] == "MemberExpression": member_object = MemberExpression(traverser, node_left["object"], instantiate=True) member_property = _get_member_exp_property(traverser, node_left) traverser._debug("ASSIGNMENT:MEMBER_PROPERTY(%s)" % member_property) if member_object is None: member_object = JSObject() member_object.set(member_property, value, traverser) # Treat direct assignment different than augmented assignment. if operator == "=": set_lvalue(right) return right elif operator not in ASSIGNMENT_OPERATORS: # We don't support that operator. (yet?) traverser._debug("ASSIGNMENT>>OPERATOR NOT FOUND", 1) return left if left.const: traverser.err.warning( err_id=("js", "AssignmentExpression", "aug_const_overwrite"), warning="Overwritten constant value", description="A variable declared as constant has been " "overwritten in some JS code by an augmented " "assignment.", filename=traverser.filename, line=traverser.line, column=traverser.position, context=traverser.context) return JSObject(traverser=traverser) traverser._debug("ASSIGNMENT>>DONE PARSING LEFT") traverser.debug_level -= 1 # If we're modifying a non-numeric type with a numeric operator, return # NaN. if (operator in NUMERIC_OPERATORS and not isinstance( left.get_literal_value(traverser) or 0, NUMERIC_TYPES)): set_lvalue(utils.get_NaN(traverser)) return left gleft, gright = utils.get_as_num(left), utils.get_as_num(right) traverser._debug("ASSIGNMENT>>OPERATION:%s" % operator) if operator in ("<<=", ">>=", ">>>=") and gright < 0: # The user is doing weird bitshifting that will return 0 in JS but # not in Python. set_lvalue(JSLiteral(0, traverser=traverser)) return left elif (operator in ("<<=", ">>=", ">>>=", "|=", "^=", "&=") and (abs(gleft) == float('inf') or abs(gright) == float('inf'))): # Don't bother handling infinity for integer-converted operations. set_lvalue(utils.get_NaN(traverser)) return left if operator == '+=': lit_left = left.get_literal_value(traverser) lit_right = right.get_literal_value(traverser) # Don't perform an operation on None. Python freaks out. if lit_left is None: lit_left = 0 if lit_right is None: lit_right = 0 # If either side of the assignment operator is a string, both sides # need to be cast to strings first. if (isinstance(lit_left, types.StringTypes) or isinstance(lit_right, types.StringTypes)): left = utils.get_as_str(lit_left) right = utils.get_as_str(lit_right) else: left, right = lit_left, lit_right output = ASSIGNMENT_OPERATORS[operator](left, right, gleft, gright) # Cap the length of analyzed strings. if isinstance(output, types.StringTypes) and len(output) > MAX_STR_SIZE: output = output[:MAX_STR_SIZE] traverser._debug("ASSIGNMENT::New value >> %s" % output, 1) set_lvalue(JSLiteral(output, traverser=traverser)) return orig_left
def BinaryExpression(traverser, node): traverser.debug_level += 1 # Select the proper operator. operator = node["operator"] traverser._debug("BIN_OPERATOR>>%s" % operator) # Traverse the left half of the binary expression. traverser._debug("BIN_EXP>>l-value") traverser.debug_level += 1 if (node["left"]["type"] == "BinaryExpression" and "__traversal" not in node["left"]): # Process the left branch of the binary expression directly. This keeps # the recursion cap in line and speeds up processing of large chains # of binary expressions. left = BinaryExpression(traverser, node["left"]) node["left"]["__traversal"] = left else: left = traverser.traverse_node(node["left"]) # Traverse the right half of the binary expression. traverser._debug("BIN_EXP>>r-value", -1) if (operator == "instanceof" and node["right"]["type"] == "Identifier" and node["right"]["name"] == "Function"): # We make an exception for instanceof's r-value if it's a dangerous # global, specifically Function. traverser.debug_level -= 1 return JSLiteral(True, traverser=traverser) else: right = traverser.traverse_node(node["right"]) traverser.debug_level -= 1 # Binary expressions are only executed on literals. left = left.get_literal_value(traverser) right_wrap = right right = right.get_literal_value(traverser) # Coerce the literals to numbers for numeric operations. gleft = utils.get_as_num(left) gright = utils.get_as_num(right) if operator in (">>", "<<", ">>>"): if left is None or right is None or gright < 0: return JSLiteral(False, traverser=traverser) elif abs(gleft) == float('inf') or abs(gright) == float('inf'): return utils.get_NaN(traverser) output = None if operator in BINARY_OPERATORS: # Concatenation can be silly, so always turn undefineds into empty # strings and if there are strings, make everything strings. if operator == "+": if left is None: left = "" if right is None: right = "" if (isinstance(left, types.StringTypes) or isinstance(right, types.StringTypes)): left = utils.get_as_str(left) right = utils.get_as_str(right) output = BINARY_OPERATORS[operator](left, right, gleft, gright) elif operator == "in": return JSLiteral(right_wrap.has_var(left, traverser=traverser), traverser=traverser) #TODO: `delete` operator # Cap the length of analyzed strings. if isinstance(output, types.StringTypes) and len(output) > MAX_STR_SIZE: output = output[:MAX_STR_SIZE] return JSLiteral(output, traverser=traverser)
def AssignmentExpression(traverser, node): traverser._debug("ASSIGNMENT_EXPRESSION") traverser.debug_level += 1 traverser._debug("ASSIGNMENT>>PARSING RIGHT") right = traverser.traverse_node(node["right"]) traverser._debug("ASSIGNMENT>>PARSING LEFT") orig_left = left = traverser.traverse_node(node["left"]) operator = node["operator"] def set_lvalue(value): node_left = node["left"] traverser._debug("ASSIGNING:DIRECT(%s)" % node_left["type"]) global_overwrite = False readonly_value = True if node_left["type"] == "Identifier": # Identifiers just need the ID name and a value to push. # Raise a global overwrite issue if the identifier is global. global_overwrite = traverser._is_global(node_left["name"]) # Get the readonly attribute and store its value if is_global if global_overwrite: from predefinedentities import GLOBAL_ENTITIES global_dict = GLOBAL_ENTITIES[node_left["name"]] readonly_value = global_dict.get("readonly", False) traverser._declare_variable(node_left["name"], value, type_="glob") elif node_left["type"] == "MemberExpression": member_object = MemberExpression(traverser, node_left["object"], instantiate=True) member_property = _get_member_exp_property(traverser, node_left) traverser._debug("ASSIGNMENT:MEMBER_PROPERTY(%s)" % member_property) if member_object is None: member_object = JSObject() member_object.set(member_property, value, traverser) # Treat direct assignment different than augmented assignment. if operator == "=": set_lvalue(right) return right elif operator not in ASSIGNMENT_OPERATORS: # We don't support that operator. (yet?) traverser._debug("ASSIGNMENT>>OPERATOR NOT FOUND", 1) return left if left.const: traverser.err.warning( err_id=("js", "AssignmentExpression", "aug_const_overwrite"), warning="Overwritten constant value", description="A variable declared as constant has been " "overwritten in some JS code by an augmented " "assignment.", filename=traverser.filename, line=traverser.line, column=traverser.position, context=traverser.context) return JSObject(traverser=traverser) traverser._debug("ASSIGNMENT>>DONE PARSING LEFT") traverser.debug_level -= 1 # If we're modifying a non-numeric type with a numeric operator, return # NaN. if (operator in NUMERIC_OPERATORS and not isinstance(left.get_literal_value(traverser) or 0, NUMERIC_TYPES)): set_lvalue(utils.get_NaN(traverser)) return left gleft, gright = utils.get_as_num(left), utils.get_as_num(right) traverser._debug("ASSIGNMENT>>OPERATION:%s" % operator) if operator in ("<<=", ">>=", ">>>=") and gright < 0: # The user is doing weird bitshifting that will return 0 in JS but # not in Python. set_lvalue(JSLiteral(0, traverser=traverser)) return left elif (operator in ("<<=", ">>=", ">>>=", "|=", "^=", "&=") and (abs(gleft) == float('inf') or abs(gright) == float('inf'))): # Don't bother handling infinity for integer-converted operations. set_lvalue(utils.get_NaN(traverser)) return left if operator == '+=': lit_left = left.get_literal_value(traverser) lit_right = right.get_literal_value(traverser) # Don't perform an operation on None. Python freaks out. if lit_left is None: lit_left = 0 if lit_right is None: lit_right = 0 # If either side of the assignment operator is a string, both sides # need to be cast to strings first. if (isinstance(lit_left, types.StringTypes) or isinstance(lit_right, types.StringTypes)): left = utils.get_as_str(lit_left) right = utils.get_as_str(lit_right) else: left, right = lit_left, lit_right output = ASSIGNMENT_OPERATORS[operator](left, right, gleft, gright) # Cap the length of analyzed strings. if isinstance(output, types.StringTypes) and len(output) > MAX_STR_SIZE: output = output[:MAX_STR_SIZE] traverser._debug("ASSIGNMENT::New value >> %s" % output, 1) set_lvalue(JSLiteral(output, traverser=traverser)) return orig_left