class RuboCop::Cop::Rails::LinkToBlank

This cop checks for calls to `link_to` that contain a `target: '_blank'` but no `rel: 'noopener'`. This can be a security risk as the loaded page will have control over the previous page and could change its location for phishing purposes.

The option `rel: 'noreferrer'` also blocks this behavior and removes the http-referrer header.

@example

# bad
link_to 'Click here', url, target: '_blank'

# good
link_to 'Click here', url, target: '_blank', rel: 'noopener'

# good
link_to 'Click here', url, target: '_blank', rel: 'noreferrer'

Constants

MSG
RESTRICT_ON_SEND

Public Instance Methods

on_send(node) click to toggle source
# File lib/rubocop/cop/rails/link_to_blank.rb, line 41
def on_send(node)
  option_nodes = node.each_child_node(:hash)

  option_nodes.map(&:children).each do |options|
    blank = options.find { |o| blank_target?(o) }
    next unless blank && options.none? { |o| includes_noopener?(o) }

    add_offense(blank) do |corrector|
      autocorrect(corrector, node, blank, option_nodes)
    end
  end
end

Private Instance Methods

add_rel(send_node, offense_node, corrector) click to toggle source
# File lib/rubocop/cop/rails/link_to_blank.rb, line 78
def add_rel(send_node, offense_node, corrector)
  opening_quote = offense_node.children.last.source[0]
  closing_quote = opening_quote == ':' ? '' : opening_quote
  new_rel_exp = ", rel: #{opening_quote}noopener#{closing_quote}"
  range = if (last_argument = send_node.last_argument).hash_type?
            last_argument.pairs.last.source_range
          else
            last_argument.source_range
          end

  corrector.insert_after(range, new_rel_exp)
end
append_to_rel(rel_node, corrector) click to toggle source
# File lib/rubocop/cop/rails/link_to_blank.rb, line 69
def append_to_rel(rel_node, corrector)
  existing_rel = rel_node.children.last.value
  str_range = rel_node.children.last.loc.expression.adjust(
    begin_pos: 1,
    end_pos: -1
  )
  corrector.replace(str_range, "#{existing_rel} noopener")
end
autocorrect(corrector, send_node, node, option_nodes) click to toggle source
# File lib/rubocop/cop/rails/link_to_blank.rb, line 56
def autocorrect(corrector, send_node, node, option_nodes)
  rel_node = nil
  option_nodes.map(&:children).each do |options|
    rel_node ||= options.find { |o| rel_node?(o) }
  end

  if rel_node
    append_to_rel(rel_node, corrector)
  else
    add_rel(send_node, node, corrector)
  end
end
contains_noopener?(value) click to toggle source
# File lib/rubocop/cop/rails/link_to_blank.rb, line 91
def contains_noopener?(value)
  return false unless value

  rel_array = value.to_s.split
  rel_array.include?('noopener') || rel_array.include?('noreferrer')
end