module Brakeman::Util

This is a mixin containing utility methods.

Constants

ALL_COOKIES
ALL_PARAMETERS
COOKIES
COOKIES_SEXP
DIR_CONST
LITERALS
PARAMETERS
PARAMS_SEXP

These are never modified

PATH_PARAMETERS
QUERY_PARAMETERS
REQUEST_COOKIES
REQUEST_ENV
REQUEST_PARAMETERS
REQUEST_PARAMS
REQUEST_REQUEST_PARAMETERS
SAFE_LITERAL
SESSION
SESSION_SEXP
SIMPLE_LITERALS

Public Instance Methods

all_literals?(exp, expected_type = :array) click to toggle source
# File lib/brakeman/util.rb, line 326
def all_literals? exp, expected_type = :array
  node_type? exp, expected_type and
    exp.length > 1 and
    exp.all? { |e| e.is_a? Symbol or node_type? e, :lit, :str }
end
array?(exp) click to toggle source

Check if exp represents an array: s(:array, […])

# File lib/brakeman/util.rb, line 178
def array? exp
  exp.is_a? Sexp and exp.node_type == :array
end
block?(exp) click to toggle source

Check if exp represents a block of code

# File lib/brakeman/util.rb, line 236
def block? exp
  exp.is_a? Sexp and (exp.node_type == :block or
                      exp.node_type == :rlist)
end
call?(exp) click to toggle source

Check if exp represents a method call: s(:call, …)

# File lib/brakeman/util.rb, line 197
def call? exp
  exp.is_a? Sexp and
    (exp.node_type == :call or exp.node_type == :safe_call)
end
camelize(lower_case_and_underscored_word) click to toggle source

Convert a string from “something_like_this” to “SomethingLikeThis”

Taken from ActiveSupport.

# File lib/brakeman/util.rb, line 36
def camelize lower_case_and_underscored_word
  lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
end
class_name(exp) click to toggle source

Returns a class name as a Symbol. If class name cannot be determined, returns exp.

# File lib/brakeman/util.rb, line 62
def class_name exp
  case exp
  when Sexp
    case exp.node_type
    when :const, :colon3
      exp.value
    when :lvar
      exp.value.to_sym
    when :colon2
      "#{class_name(exp.lhs)}::#{exp.rhs}".to_sym
    when :self
      @current_class || @current_module || nil
    else
      exp
    end
  when Symbol
    exp
  when nil
    nil
  else
    exp
  end
end
constant?(exp) click to toggle source
# File lib/brakeman/util.rb, line 293
def constant? exp
  node_type? exp, :const, :colon2, :colon3
end
contains_class?(exp) click to toggle source

Returns true if the given exp contains a :class node.

Useful for checking if a module is just a module or if it is a namespace.

# File lib/brakeman/util.rb, line 345
def contains_class? exp
  todo = [exp]

  until todo.empty?
    current = todo.shift

    if node_type? current, :class
      return true
    elsif sexp? current
      todo = current.sexp_body.concat todo
    end
  end

  false
end
cookies?(exp) click to toggle source
# File lib/brakeman/util.rb, line 246
def cookies? exp
  recurse_check?(exp) { |child| child.node_type == :cookies or ALL_COOKIES.include? child }
end
dir_glob?(exp) click to toggle source

Dir.glob(…).whatever

# File lib/brakeman/util.rb, line 335
def dir_glob? exp
  exp = exp.block_call if node_type? exp, :iter
  return unless call? exp

  (exp.target == DIR_CONST and exp.method == :glob) or dir_glob? exp.target
end
false?(exp) click to toggle source

Check if exp represents a :false or :nil node

# File lib/brakeman/util.rb, line 230
def false? exp
  exp.is_a? Sexp and (exp.node_type == :false or
                      exp.node_type == :nil)
end
hash?(exp) click to toggle source

Check if exp represents a hash: s(:hash, {…}) This also includes pseudo hashes params, session, and cookies.

# File lib/brakeman/util.rb, line 170
def hash? exp
  exp.is_a? Sexp and (exp.node_type == :hash or
                      exp.node_type == :params or
                      exp.node_type == :session or
                      exp.node_type == :cookies)
end
hash_access(hash, key) click to toggle source

Get value from hash using key.

If key is a Symbol, it will be converted to a Sexp(:lit, key).

# File lib/brakeman/util.rb, line 135
def hash_access hash, key
  if key.is_a? Symbol
    key = Sexp.new(:lit, key)
  end

  if index = hash.find_index(key) and index > 0
    return hash[index + 1]
  end

  nil
end
hash_insert(hash, key, value) click to toggle source

Insert value into Hash Sexp

# File lib/brakeman/util.rb, line 117
def hash_insert hash, key, value
  index = 1
  hash_iterate hash.dup do |k,v|
    if k == key
      hash[index + 1] = value
      return hash
    end
    index += 2
  end

  hash << key << value

  hash
end
hash_iterate(hash) { |hash, hash| ... } click to toggle source

Takes an Sexp like

(:hash, (:lit, :key), (:str, "value"))

and yields the key and value pairs to the given block.

For example:

h = Sexp.new(:hash, (:lit, :name), (:str, "bob"), (:lit, :name), (:str, "jane"))
names = []
hash_iterate(h) do |key, value|
  if symbol? key and key[1] == :name
    names << value[1]
  end
end
names #["bob"]
# File lib/brakeman/util.rb, line 100
def hash_iterate hash
  hash = remove_kwsplat(hash)

  1.step(hash.length - 1, 2) do |i|
    yield hash[i], hash[i + 1]
  end
end
hash_values(hash) click to toggle source
# File lib/brakeman/util.rb, line 147
def hash_values hash
  values = hash.each_sexp.each_slice(2).map do |_, value|
    value
  end

  Sexp.new(:array).concat(values).line(hash.line)
end
integer?(exp) click to toggle source

Check if exp represents an Integer: s(:lit, …)

# File lib/brakeman/util.rb, line 208
def integer? exp
  exp.is_a? Sexp and exp.node_type == :lit and exp[1].is_a? Integer
end
kwsplat?(exp) click to toggle source
# File lib/brakeman/util.rb, line 297
def kwsplat? exp
  exp.is_a? Sexp and
    exp.node_type == :hash and
    exp[1].is_a? Sexp and
    exp[1].node_type == :kwsplat
end
literal?(exp) click to toggle source
# File lib/brakeman/util.rb, line 322
def literal? exp
  exp.is_a? Sexp and LITERALS.include? exp.node_type
end
make_call(target, method, *args) click to toggle source
# File lib/brakeman/util.rb, line 361
def make_call target, method, *args
  call = Sexp.new(:call, target, method)

  if args.empty? or args.first.empty?
    #nothing to do
  elsif node_type? args.first, :arglist
    call.concat args.first.sexp_body
  elsif args.first.node_type.is_a? Sexp #just a list of args
    call.concat args.first
  else
    call.concat args
  end

  call
end
node_type?(exp, *types) click to toggle source

Check if exp is a Sexp and the node type matches one of the given types.

# File lib/brakeman/util.rb, line 310
def node_type? exp, *types
  exp.is_a? Sexp and types.include? exp.node_type
end
number?(exp) click to toggle source

Check if exp represents a number: s(:lit, …)

# File lib/brakeman/util.rb, line 213
def number? exp
  exp.is_a? Sexp and exp.node_type == :lit and exp[1].is_a? Numeric
end
params?(exp) click to toggle source

Check if exp is a params hash

# File lib/brakeman/util.rb, line 242
def params? exp
  recurse_check?(exp) { |child| child.node_type == :params or ALL_PARAMETERS.include? child }
end
pluralize(word) click to toggle source

stupid simple, used to delegate to ActiveSupport

# File lib/brakeman/util.rb, line 52
def pluralize word
  if word.end_with? 's'
    word + 'es'
  else
    word + 's'
  end
end
rails_version() click to toggle source
# File lib/brakeman/util.rb, line 393
def rails_version
  @tracker.config.rails_version
end
recurse_check?(exp) { |exp| ... } click to toggle source
# File lib/brakeman/util.rb, line 250
def recurse_check? exp, &check
  if exp.is_a? Sexp
    return true if yield(exp)

    if call? exp
      if recurse_check? exp[1], &check
        return true
      elsif exp[2] == :[]
        return recurse_check? exp[1], &check
      end
    end
  end

  false
end
regexp?(exp) click to toggle source

Check if exp represents a Regexp: s(:lit, /…/)

# File lib/brakeman/util.rb, line 203
def regexp? exp
  exp.is_a? Sexp and exp.node_type == :lit and exp[1].is_a? Regexp
end
remove_kwsplat(exp) click to toggle source
# File lib/brakeman/util.rb, line 108
def remove_kwsplat exp
  if exp.any? { |e| node_type? e, :kwsplat }
    exp.reject { |e| node_type? e, :kwsplat }
  else
    exp
  end
end
request_headers?(exp) click to toggle source

Only return true when accessing request headers via request.env

# File lib/brakeman/util.rb, line 267
def request_headers? exp
  return unless sexp? exp

  if exp[1] == REQUEST_ENV
    if exp.method == :[]
      if string? exp.first_arg
        # Only care about HTTP headers, which are prefixed by 'HTTP_'
        exp.first_arg.value.start_with?('HTTP_'.freeze)
      else
        true # request.env[something]
      end
    else
      false # request.env.something
    end
  else
    false
  end
end
request_value?(exp) click to toggle source

Check if exp is params, cookies, or request_headers

# File lib/brakeman/util.rb, line 287
def request_value? exp
  params? exp or
  cookies? exp or
  request_headers? exp
end
result?(exp) click to toggle source

Check if exp represents a result: s(:result, …)

# File lib/brakeman/util.rb, line 218
def result? exp
  exp.is_a? Sexp and exp.node_type == :result
end
safe_literal(line = nil) click to toggle source
# File lib/brakeman/util.rb, line 377
def safe_literal line = nil
  s(:lit, :BRAKEMAN_SAFE_LITERAL).line(line || 0)
end
safe_literal?(exp) click to toggle source
# File lib/brakeman/util.rb, line 381
def safe_literal? exp
  exp == SAFE_LITERAL
end
safe_literal_target?(exp) click to toggle source
# File lib/brakeman/util.rb, line 385
def safe_literal_target? exp
  if call? exp
    safe_literal_target? exp.target
  else
    safe_literal? exp
  end
end
set_env_defaults() click to toggle source

Adds params, session, and cookies to environment so they can be replaced by their respective Sexps.

# File lib/brakeman/util.rb, line 162
def set_env_defaults
  @env[PARAMETERS] = PARAMS_SEXP
  @env[SESSION] = SESSION_SEXP
  @env[COOKIES] = COOKIES_SEXP
end
sexp?(exp) click to toggle source

Check if exp is a Sexp.

# File lib/brakeman/util.rb, line 305
def sexp? exp
  exp.is_a? Sexp
end
simple_literal?(exp) click to toggle source
# File lib/brakeman/util.rb, line 316
def simple_literal? exp
  exp.is_a? Sexp and SIMPLE_LITERALS.include? exp.node_type
end
string?(exp) click to toggle source

Check if exp represents a String: s(:str, “…”)

# File lib/brakeman/util.rb, line 183
def string? exp
  exp.is_a? Sexp and exp.node_type == :str
end
string_interp?(exp) click to toggle source
# File lib/brakeman/util.rb, line 187
def string_interp? exp
  exp.is_a? Sexp and exp.node_type == :dstr
end
symbol?(exp) click to toggle source

Check if exp represents a Symbol: s(:lit, :…)

# File lib/brakeman/util.rb, line 192
def symbol? exp
  exp.is_a? Sexp and exp.node_type == :lit and exp[1].is_a? Symbol
end
template_path_to_name(path) click to toggle source

Convert path/filename to view name

views/test/something.html.erb -> test/something
# File lib/brakeman/util.rb, line 400
def template_path_to_name path
  names = path.relative.split('/')
  names.last.gsub!(/(\.(html|js)\..*|\.(rhtml|haml|erb|slim))$/, '')

  if names.include? 'views'
    names[(names.index('views') + 1)..-1]
  else
    names
  end.join('/').to_sym
end
true?(exp) click to toggle source

Check if exp represents a :true, :lit, or :string node

# File lib/brakeman/util.rb, line 223
def true? exp
  exp.is_a? Sexp and (exp.node_type == :true or
                      exp.node_type == :lit or
                      exp.node_type == :string)
end
underscore(camel_cased_word) click to toggle source

Convert a string from “Something::LikeThis” to “something/like_this”

Taken from ActiveSupport.

# File lib/brakeman/util.rb, line 43
def underscore camel_cased_word
  camel_cased_word.to_s.gsub(/::/, '/').
    gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
    gsub(/([a-z\d])([A-Z])/,'\1_\2').
    tr("-", "_").
    downcase
end