Class: Bundler::S3Fetcher

Inherits:
Fetcher
  • Object
show all
Defined in:
lib/bundler/s3_fetcher.rb

Constant Summary collapse

BASE64_URI_TRANSLATE =
{ '+' => '%2B', '/' => '%2F', '=' => '%3D' }.freeze

Constants inherited from Fetcher

Fetcher::AUTH_ERRORS

Instance Method Summary collapse

Methods inherited from Fetcher

#_use_api, #connection, download_gem_from_uri, #fetch_remote_specs, #fetch_spec, #gemspec_cached_path, #initialize, #inspect, #specs, #uri, #use_api, user_agent

Constructor Details

This class inherits a constructor from Bundler::Fetcher

Instance Method Details

#default_expirationObject


32
33
34
# File 'lib/bundler/s3_fetcher.rb', line 32

def default_expiration
  (Time.now + 3600).to_i # one hour from now
end

#fetch(uri, counter = 0) ⇒ Object


7
8
9
# File 'lib/bundler/s3_fetcher.rb', line 7

def fetch(uri, counter = 0)
  super(sign(uri), counter)
end

#sign(uri, expiration = default_expiration) ⇒ Object

Instead of taking a dependency on aws-sdk, use a method modeled on the signing method in github.com/rubygems/rubygems/pull/856


13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/bundler/s3_fetcher.rb', line 13

def sign(uri, expiration = default_expiration)
  uri = uri.dup
  unless uri.user && uri.password
    raise AuthenticationRequiredError.new("credentials needed in s3 source, like s3://key:[email protected]/")
  end

  payload = "GET\n\n\n#{expiration}\n/#{uri.host}#{uri.path}"
  digest = OpenSSL::HMAC.digest('sha1', uri.password, payload)
  # URI.escape is deprecated, and there isn't yet a replacement that does quite what we want
  signature = Base64.encode64(digest).gsub("\n", '').gsub(/[\+\/=]/) { |c| BASE64_URI_TRANSLATE[c] }
  uri.query = [uri.query, "AWSAccessKeyId=#{uri.user}&Expires=#{expiration}&Signature=#{signature}"].compact.join('&')
  uri.user = nil
  uri.password = nil
  uri.scheme = "https"
  uri.host = [uri.host, "s3.amazonaws.com"].join('.')

  URI.parse(uri.to_s)
end