Module: Brakeman::Util
- Included in:
- AliasProcessor, BaseCheck, BaseProcessor, BasicProcessor, Collection, Config, Constants, FindReturnValue, OutputProcessor, Processor, Report::Base, RescanReport, Rescanner, TemplateParser
- Defined in:
- lib/brakeman/util.rb
Overview
This is a mixin containing utility methods.
Constant Summary collapse
- QUERY_PARAMETERS =
Sexp.new(:call, Sexp.new(:call, nil, :request), :query_parameters)
- PATH_PARAMETERS =
Sexp.new(:call, Sexp.new(:call, nil, :request), :path_parameters)
- REQUEST_PARAMETERS =
Sexp.new(:call, Sexp.new(:call, nil, :request), :request_parameters)
- REQUEST_PARAMS =
Sexp.new(:call, Sexp.new(:call, nil, :request), :parameters)
- REQUEST_ENV =
Sexp.new(:call, Sexp.new(:call, nil, :request), :env)
- PARAMETERS =
Sexp.new(:call, nil, :params)
- COOKIES =
Sexp.new(:call, nil, :cookies)
- REQUEST_COOKIES =
s(:call, s(:call, nil, :request), :cookies)
- SESSION =
Sexp.new(:call, nil, :session)
- ALL_PARAMETERS =
Set[PARAMETERS, QUERY_PARAMETERS, PATH_PARAMETERS, REQUEST_PARAMETERS, REQUEST_PARAMS]
- ALL_COOKIES =
Set[COOKIES, REQUEST_COOKIES]
- SAFE_LITERAL =
s(:lit, :BRAKEMAN_SAFE_LITERAL)
- PARAMS_SEXP =
These are never modified
Sexp.new(:params)
- SESSION_SEXP =
Sexp.new(:session)
- COOKIES_SEXP =
Sexp.new(:cookies)
Instance Method Summary collapse
-
#array?(exp) ⇒ Boolean
Check if exp represents an array: s(:array, […]).
-
#block?(exp) ⇒ Boolean
Check if exp represents a block of code.
-
#call?(exp) ⇒ Boolean
Check if exp represents a method call: s(:call, …).
-
#camelize(lower_case_and_underscored_word) ⇒ Object
Convert a string from “something_like_this” to “SomethingLikeThis”.
-
#class_name(exp) ⇒ Object
Returns a class name as a Symbol.
- #constant?(exp) ⇒ Boolean
-
#contains_class?(exp) ⇒ Boolean
Returns true if the given exp contains a :class node.
-
#context_for(app_tree, warning, tracker = nil) ⇒ Object
Return array of lines surrounding the warning location from the original file.
- #cookies?(exp) ⇒ Boolean
-
#false?(exp) ⇒ Boolean
Check if exp represents a :false or :nil node.
-
#file_by_name(name, type, tracker = nil) ⇒ Object
Attempt to determine path to context file based on the reported name in the warning.
-
#file_for(warning, tracker = nil) ⇒ Object
Return file name related to given warning.
- #github_url(file, line = nil) ⇒ Object
-
#hash?(exp) ⇒ Boolean
Check if exp represents a hash: s(:hash, …) This also includes pseudo hashes params, session, and cookies.
-
#hash_access(hash, key) ⇒ Object
Get value from hash using key.
-
#hash_insert(hash, key, value) ⇒ Object
Insert value into Hash Sexp.
-
#hash_iterate(hash) ⇒ Object
Takes an Sexp like (:hash, (:lit, :key), (:str, “value”)) and yields the key and value pairs to the given block.
-
#integer?(exp) ⇒ Boolean
Check if exp represents an Integer: s(:lit, …).
- #make_call(target, method, *args) ⇒ Object
-
#node_type?(exp, *types) ⇒ Boolean
Check if exp is a Sexp and the node type matches one of the given types.
-
#number?(exp) ⇒ Boolean
Check if exp represents a number: s(:lit, …).
-
#params?(exp) ⇒ Boolean
Check if exp is a params hash.
-
#pluralize(word) ⇒ Object
stupid simple, used to delegate to ActiveSupport.
- #rails_version ⇒ Object
-
#regexp?(exp) ⇒ Boolean
Check if exp represents a Regexp: s(:lit, /…/).
- #relative_path(file) ⇒ Object
- #request_env?(exp) ⇒ Boolean
-
#request_value?(exp) ⇒ Boolean
Check if exp is params, cookies, or request_env.
-
#result?(exp) ⇒ Boolean
Check if exp represents a result: s(:result, …).
- #safe_literal(line = nil) ⇒ Object
- #safe_literal?(exp) ⇒ Boolean
- #safe_literal_target?(exp) ⇒ Boolean
-
#set_env_defaults ⇒ Object
Adds params, session, and cookies to environment so they can be replaced by their respective Sexps.
-
#sexp?(exp) ⇒ Boolean
Check if exp is a Sexp.
-
#string?(exp) ⇒ Boolean
Check if exp represents a String: s(:str, “…”).
- #string_interp?(exp) ⇒ Boolean
-
#symbol?(exp) ⇒ Boolean
Check if exp represents a Symbol: s(:lit, :…).
-
#table_to_csv(table) ⇒ Object
rely on Terminal::Table to build the structure, extract the data out in CSV format.
-
#template_path_to_name(path) ⇒ Object
Convert path/filename to view name.
-
#true?(exp) ⇒ Boolean
Check if exp represents a :true, :lit, or :string node.
- #truncate_table(str) ⇒ Object
-
#underscore(camel_cased_word) ⇒ Object
Convert a string from “Something::LikeThis” to “something/like_this”.
Instance Method Details
#array?(exp) ⇒ Boolean
Check if exp represents an array: s(:array, […])
156 157 158 |
# File 'lib/brakeman/util.rb', line 156 def array? exp exp.is_a? Sexp and exp.node_type == :array end |
#block?(exp) ⇒ Boolean
Check if exp represents a block of code
214 215 216 217 |
# File 'lib/brakeman/util.rb', line 214 def block? exp exp.is_a? Sexp and (exp.node_type == :block or exp.node_type == :rlist) end |
#call?(exp) ⇒ Boolean
Check if exp represents a method call: s(:call, …)
175 176 177 178 |
# File 'lib/brakeman/util.rb', line 175 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) ⇒ Object
Convert a string from “something_like_this” to “SomethingLikeThis”
Taken from ActiveSupport.
34 35 36 |
# File 'lib/brakeman/util.rb', line 34 def camelize lower_case_and_underscored_word lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase } end |
#class_name(exp) ⇒ Object
Returns a class name as a Symbol. If class name cannot be determined, returns exp.
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/brakeman/util.rb', line 56 def class_name exp case exp when Sexp case exp.node_type when :const exp.value when :lvar exp.value.to_sym when :colon2 "#{class_name(exp.lhs)}::#{exp.rhs}".to_sym when :colon3 "::#{exp.value}".to_sym when :self @current_class || @current_module || nil else exp end when Symbol exp when nil nil else exp end end |
#constant?(exp) ⇒ Boolean
263 264 265 |
# File 'lib/brakeman/util.rb', line 263 def constant? exp node_type? exp, :const, :colon2, :colon3 end |
#contains_class?(exp) ⇒ Boolean
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.
280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 |
# File 'lib/brakeman/util.rb', line 280 def contains_class? exp todo = [exp] until todo.empty? current = todo.shift if node_type? current, :class return true elsif sexp? current todo = current[1..-1].concat todo end end false end |
#context_for(app_tree, warning, tracker = nil) ⇒ Object
Return array of lines surrounding the warning location from the original file.
410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 |
# File 'lib/brakeman/util.rb', line 410 def context_for app_tree, warning, tracker = nil file = file_for warning, tracker context = [] return context unless warning.line and file and @app_tree.path_exists? file current_line = 0 start_line = warning.line - 5 end_line = warning.line + 5 start_line = 1 if start_line < 0 File.open file do |f| f.each_line do |line| current_line += 1 next if line.strip == "" if current_line > end_line break end if current_line >= start_line context << [current_line, line] end end end context end |
#cookies?(exp) ⇒ Boolean
236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 |
# File 'lib/brakeman/util.rb', line 236 def exp if exp.is_a? Sexp return true if exp.node_type == :cookies or ALL_COOKIES.include? exp if call? exp if exp[1] return true elsif exp[2] == :[] return exp[1] end end end false end |
#false?(exp) ⇒ Boolean
Check if exp represents a :false or :nil node
208 209 210 211 |
# File 'lib/brakeman/util.rb', line 208 def false? exp exp.is_a? Sexp and (exp.node_type == :false or exp.node_type == :nil) end |
#file_by_name(name, type, tracker = nil) ⇒ Object
Attempt to determine path to context file based on the reported name in the warning.
For example,
file_by_name FileController #=> "/rails/root/app/controllers/file_controller.rb
364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 |
# File 'lib/brakeman/util.rb', line 364 def file_by_name name, type, tracker = nil return nil unless name string_name = name.to_s name = name.to_sym unless type if string_name =~ /Controller$/ type = :controller elsif camelize(string_name) == string_name # This is not always true type = :model else type = :template end end path = tracker.app_path case type when :controller if tracker.controllers[name] path = tracker.controllers[name].file else path += "/app/controllers/#{underscore(string_name)}.rb" end when :model if tracker.models[name] path = tracker.models[name].file else path += "/app/models/#{underscore(string_name)}.rb" end when :template if tracker.templates[name] and tracker.templates[name].file path = tracker.templates[name].file elsif string_name.include? " " name = string_name.split[0].to_sym path = file_for tracker, name, :template else path = nil end end path end |
#file_for(warning, tracker = nil) ⇒ Object
Return file name related to given warning. Uses warning.file
if it exists
333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 |
# File 'lib/brakeman/util.rb', line 333 def file_for warning, tracker = nil if tracker.nil? tracker = @tracker || self.tracker end if warning.file File. warning.file, tracker.app_path elsif warning.template and warning.template.file warning.template.file else case warning.warning_set when :controller file_by_name warning.controller, :controller, tracker when :template file_by_name warning.template.name, :template, tracker when :model file_by_name warning.model, :model, tracker when :warning file_by_name warning.class, nil, tracker else nil end end end |
#github_url(file, line = nil) ⇒ Object
458 459 460 461 462 463 464 465 |
# File 'lib/brakeman/util.rb', line 458 def github_url file, line=nil if repo_url = @tracker.[:github_url] and file and not file.empty? and file.start_with? '/' url = "#{repo_url}/#{relative_path(file)}" url << "#L#{line}" if line else nil end end |
#hash?(exp) ⇒ Boolean
Check if exp represents a hash: s(:hash, …) This also includes pseudo hashes params, session, and cookies.
148 149 150 151 152 153 |
# File 'lib/brakeman/util.rb', line 148 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) ⇒ Object
Get value from hash using key.
If key is a Symbol, it will be converted to a Sexp(:lit, key).
121 122 123 124 125 126 127 128 129 130 131 |
# File 'lib/brakeman/util.rb', line 121 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) ⇒ Object
Insert value into Hash Sexp
103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/brakeman/util.rb', line 103 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) ⇒ Object
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”]
96 97 98 99 100 |
# File 'lib/brakeman/util.rb', line 96 def hash_iterate hash 1.step(hash.length - 1, 2) do |i| yield hash[i], hash[i + 1] end end |
#integer?(exp) ⇒ Boolean
Check if exp represents an Integer: s(:lit, …)
186 187 188 |
# File 'lib/brakeman/util.rb', line 186 def integer? exp exp.is_a? Sexp and exp.node_type == :lit and exp[1].is_a? Integer end |
#make_call(target, method, *args) ⇒ Object
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 |
# File 'lib/brakeman/util.rb', line 296 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[1..-1] 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) ⇒ Boolean
Check if exp is a Sexp and the node type matches one of the given types.
273 274 275 |
# File 'lib/brakeman/util.rb', line 273 def node_type? exp, *types exp.is_a? Sexp and types.include? exp.node_type end |
#number?(exp) ⇒ Boolean
Check if exp represents a number: s(:lit, …)
191 192 193 |
# File 'lib/brakeman/util.rb', line 191 def number? exp exp.is_a? Sexp and exp.node_type == :lit and exp[1].is_a? Numeric end |
#params?(exp) ⇒ Boolean
Check if exp is a params hash
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 |
# File 'lib/brakeman/util.rb', line 220 def params? exp if exp.is_a? Sexp return true if exp.node_type == :params or ALL_PARAMETERS.include? exp if call? exp if params? exp[1] return true elsif exp[2] == :[] return params? exp[1] end end end false end |
#pluralize(word) ⇒ Object
stupid simple, used to delegate to ActiveSupport
50 51 52 |
# File 'lib/brakeman/util.rb', line 50 def pluralize word word + "s" end |
#rails_version ⇒ Object
328 329 330 |
# File 'lib/brakeman/util.rb', line 328 def rails_version @tracker.config.rails_version end |
#regexp?(exp) ⇒ Boolean
Check if exp represents a Regexp: s(:lit, /…/)
181 182 183 |
# File 'lib/brakeman/util.rb', line 181 def regexp? exp exp.is_a? Sexp and exp.node_type == :lit and exp[1].is_a? Regexp end |
#relative_path(file) ⇒ Object
440 441 442 443 444 445 446 447 |
# File 'lib/brakeman/util.rb', line 440 def relative_path file pname = Pathname.new file if file and not file.empty? and pname.absolute? pname.relative_path_from(Pathname.new(@tracker.app_path)).to_s else file end end |
#request_env?(exp) ⇒ Boolean
252 253 254 |
# File 'lib/brakeman/util.rb', line 252 def request_env? exp call? exp and (exp == REQUEST_ENV or exp[1] == REQUEST_ENV) end |
#request_value?(exp) ⇒ Boolean
Check if exp is params, cookies, or request_env
257 258 259 260 261 |
# File 'lib/brakeman/util.rb', line 257 def request_value? exp params? exp or exp or request_env? exp end |
#result?(exp) ⇒ Boolean
Check if exp represents a result: s(:result, …)
196 197 198 |
# File 'lib/brakeman/util.rb', line 196 def result? exp exp.is_a? Sexp and exp.node_type == :result end |
#safe_literal(line = nil) ⇒ Object
312 313 314 |
# File 'lib/brakeman/util.rb', line 312 def safe_literal line = nil s(:lit, :BRAKEMAN_SAFE_LITERAL).line(line || 0) end |
#safe_literal?(exp) ⇒ Boolean
316 317 318 |
# File 'lib/brakeman/util.rb', line 316 def safe_literal? exp exp == SAFE_LITERAL end |
#safe_literal_target?(exp) ⇒ Boolean
320 321 322 323 324 325 326 |
# File 'lib/brakeman/util.rb', line 320 def safe_literal_target? exp if call? exp safe_literal_target? exp.target else safe_literal? exp end end |
#set_env_defaults ⇒ Object
Adds params, session, and cookies to environment so they can be replaced by their respective Sexps.
140 141 142 143 144 |
# File 'lib/brakeman/util.rb', line 140 def set_env_defaults @env[PARAMETERS] = PARAMS_SEXP @env[SESSION] = SESSION_SEXP @env[COOKIES] = COOKIES_SEXP end |
#sexp?(exp) ⇒ Boolean
Check if exp is a Sexp.
268 269 270 |
# File 'lib/brakeman/util.rb', line 268 def sexp? exp exp.is_a? Sexp end |
#string?(exp) ⇒ Boolean
Check if exp represents a String: s(:str, “…”)
161 162 163 |
# File 'lib/brakeman/util.rb', line 161 def string? exp exp.is_a? Sexp and exp.node_type == :str end |
#string_interp?(exp) ⇒ Boolean
165 166 167 |
# File 'lib/brakeman/util.rb', line 165 def string_interp? exp exp.is_a? Sexp and exp.node_type == :dstr end |
#symbol?(exp) ⇒ Boolean
Check if exp represents a Symbol: s(:lit, :…)
170 171 172 |
# File 'lib/brakeman/util.rb', line 170 def symbol? exp exp.is_a? Sexp and exp.node_type == :lit and exp[1].is_a? Symbol end |
#table_to_csv(table) ⇒ Object
rely on Terminal::Table to build the structure, extract the data out in CSV format
488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 |
# File 'lib/brakeman/util.rb', line 488 def table_to_csv table return "" unless table Brakeman.load_brakeman_dependency 'terminal-table' headings = table.headings if headings.is_a? Array headings = headings.first end output = CSV.generate_line(headings.cells.map{|cell| cell.to_s.strip}) table.rows.each do |row| output << CSV.generate_line(row.cells.map{|cell| cell.to_s.strip}) end output end |
#template_path_to_name(path) ⇒ Object
Convert path/filename to view name
views/test/something.html.erb -> test/something
452 453 454 455 456 |
# File 'lib/brakeman/util.rb', line 452 def template_path_to_name path names = path.split("/") names.last.gsub!(/(\.(html|js)\..*|\.(rhtml|haml|erb|slim))$/, '') names[(names.index("views") + 1)..-1].join("/").to_sym end |
#true?(exp) ⇒ Boolean
Check if exp represents a :true, :lit, or :string node
201 202 203 204 205 |
# File 'lib/brakeman/util.rb', line 201 def true? exp exp.is_a? Sexp and (exp.node_type == :true or exp.node_type == :lit or exp.node_type == :string) end |
#truncate_table(str) ⇒ Object
467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 |
# File 'lib/brakeman/util.rb', line 467 def truncate_table str @terminal_width ||= if @tracker.[:table_width] @tracker.[:table_width] elsif $stdin && $stdin.tty? Brakeman.load_brakeman_dependency 'highline' ::HighLine.new.terminal_size[0] else 80 end lines = str.lines lines.map do |line| if line.chomp.length > @terminal_width line[0..(@terminal_width - 3)] + ">>\n" else line end end.join end |
#underscore(camel_cased_word) ⇒ Object
Convert a string from “Something::LikeThis” to “something/like_this”
Taken from ActiveSupport.
41 42 43 44 45 46 47 |
# File 'lib/brakeman/util.rb', line 41 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 |