lib/rubocop/cop/bundler/insecure_protocol_source.rb
# frozen_string_literal: true
module RuboCop
module Cop
module Bundler
# Passing symbol arguments to `source` (e.g. `source :rubygems`) is
# deprecated because they default to using HTTP requests. Instead, specify
# `'https://rubygems.org'` if possible, or `'http://rubygems.org'` if not.
#
# When autocorrecting, this cop will replace symbol arguments with
# `'https://rubygems.org'`.
#
# This cop will not replace existing sources that use `http://`. This may
# be necessary where HTTPS is not available. For example, where using an
# internal gem server via an intranet, or where HTTPS is prohibited.
# However, you should strongly prefer `https://` where possible, as it is
# more secure.
#
# If you don't allow `http://`, please set `false` to `AllowHttpProtocol`.
# This option is `true` by default for safe autocorrection.
#
# @example
# # bad
# source :gemcutter
# source :rubygems
# source :rubyforge
#
# # good
# source 'https://rubygems.org' # strongly recommended
#
# @example AllowHttpProtocol: true (default)
#
# # good
# source 'http://rubygems.org' # use only if HTTPS is unavailable
#
# @example AllowHttpProtocol: false
#
# # bad
# source 'http://rubygems.org'
#
class InsecureProtocolSource < Base
include RangeHelp
extend AutoCorrector
MSG = 'The source `:%<source>s` is deprecated because HTTP requests ' \
'are insecure. ' \
"Please change your source to 'https://rubygems.org' " \
"if possible, or 'http://rubygems.org' if not."
MSG_HTTP_PROTOCOL = 'Use `https://rubygems.org` instead of `http://rubygems.org`.'
RESTRICT_ON_SEND = %i[source].freeze
# @!method insecure_protocol_source?(node)
def_node_matcher :insecure_protocol_source?, <<~PATTERN
(send nil? :source
${(sym :gemcutter) (sym :rubygems) (sym :rubyforge) (:str "http://rubygems.org")})
PATTERN
def on_send(node)
insecure_protocol_source?(node) do |source_node|
source = source_node.value
use_http_protocol = source == 'http://rubygems.org'
return if allow_http_protocol? && use_http_protocol
message = if use_http_protocol
MSG_HTTP_PROTOCOL
else
format(MSG, source: source)
end
add_offense(source_node, message: message) do |corrector|
corrector.replace(source_node, "'https://rubygems.org'")
end
end
end
private
def allow_http_protocol?
cop_config.fetch('AllowHttpProtocol', true)
end
end
end
end
end