jeff 1.5.0 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: adbc3ba7741d6e6a2c3189261d378a7cb656c96d
4
- data.tar.gz: d5bd6f51e1f17d0e9b930ef0caef33e1f2f3da97
2
+ SHA256:
3
+ metadata.gz: dc9894a6715f02b0f754506e90c496c8d7e1b6cdb946f3c77ce7faa631326753
4
+ data.tar.gz: 9c6682d0ac05ecf197e63d699a26fa03b511217f99f6c5b27116d94b42a3c09d
5
5
  SHA512:
6
- metadata.gz: 6ac54c0f6fb21fcc6809a84ee58df5f90e1b2ea34b31bb16a2cf33f376b12849e39ac1507475b5f06699cc4b9cd890ff3da935374e2b8f319681a72aaca46282
7
- data.tar.gz: 4cf3385e17a3803ff09d0faed83ea476a6c54da32636162adee8bdb6c82a3316cf6ae64c8f53ea11f11a63222571074fc0c20e85d8a7d1e52ae0bfe5b662c14e
6
+ metadata.gz: ee5723d12feee028535333062240988d6784073b31d5da7e523eac3f522dde158da75aeed3ff82b814121b9eda018a5085a9bb0587f250e4d059c69910e378b4
7
+ data.tar.gz: a4d102f669bdd2cef1ceff5b169a6c2d63582b7314d613ea50538b08df81fcdcc60e69f23db541a395570f6d09fd69b83c1072207a3eff119518a4a003e888ac
data/README.md CHANGED
@@ -1,9 +1,10 @@
1
1
  # Jeff
2
2
 
3
- Jeff is a small mixin that [signs requests][signature] to some Amazon Web Services. My gems [Vacuum][vacuum] and [Peddler][peddler] build on Jeff.
3
+ [![Build](https://github.com/hakanensari/jeff/workflows/build/badge.svg)](https://github.com/hakanensari/jeff/actions)
4
+
5
+ Jeff is a small mixin that signs requests to Amazon with their legacy [Signature Version 2][signature]. Currently, my [Peddler][peddler] gem still uses Jeff.
4
6
 
5
7
  <img src="http://cl.ly/XatM/jeff.gif" style="display: inline-block; max-width: 300px; margin: 1em auto;">
6
8
 
7
- [signature]: http://docs.amazonwebservices.com/general/latest/gr/signature-version-2.html
8
- [vacuum]: https://github.com/hakanensari/vacuum
9
+ [signature]: https://docs.amazonwebservices.com/general/latest/gr/signature-version-2.html
9
10
  [peddler]: https://github.com/papercavalier/peddler
@@ -1,12 +1,12 @@
1
- # Jeff's only external dependency.
2
- require "excon"
1
+ # frozen_string_literal: true
3
2
 
4
- # Standard library dependencies.
5
- require "base64"
6
- require "openssl"
7
- require "time"
3
+ require 'excon'
8
4
 
9
- require "jeff/version"
5
+ require 'base64'
6
+ require 'openssl'
7
+ require 'time'
8
+
9
+ require 'jeff/version'
10
10
 
11
11
  # Jeff mixes in client behaviour for Amazon Web Services (AWS) that require
12
12
  # Signature version 2 authentication.
@@ -22,7 +22,7 @@ module Jeff
22
22
  def to_s
23
23
  values
24
24
  .sort { |a, b| a[0].to_s <=> b[0].to_s }
25
- .map { |k, v| "#{k}=#{Utils.escape(v)}" }.join("&")
25
+ .map { |k, v| "#{k}=#{Utils.escape(v)}" }.join('&')
26
26
  end
27
27
  end
28
28
 
@@ -61,7 +61,7 @@ module Jeff
61
61
 
62
62
  # Calculates an RFC 2104-compliant HMAC signature.
63
63
  class Signature
64
- SHA256 = OpenSSL::Digest::SHA256.new
64
+ SHA256 = OpenSSL::Digest.new('SHA256')
65
65
 
66
66
  def initialize(secret)
67
67
  @secret = secret
@@ -72,18 +72,18 @@ module Jeff
72
72
  end
73
73
 
74
74
  def secret
75
- @secret || fail(ArgumentError, "Missing secret")
75
+ @secret || raise(ArgumentError, 'Missing secret')
76
76
  end
77
77
  end
78
78
 
79
79
  # Because Ruby's CGI escapes tilde, use a custom escape.
80
80
  module Utils
81
- UNRESERVED = /([^\w.~-]+)/
81
+ UNRESERVED = /([^\w.~-]+)/.freeze
82
82
 
83
83
  def self.escape(val)
84
84
  val.to_s.gsub(UNRESERVED) do
85
85
  match = Regexp.last_match[1]
86
- "%" + match.unpack("H2" * match.bytesize).join("%").upcase
86
+ "%#{match.unpack('H2' * match.bytesize).join('%')}".upcase
87
87
  end
88
88
  end
89
89
  end
@@ -96,11 +96,13 @@ module Jeff
96
96
  # Add other common parameters using `Jeff.params` if required in your
97
97
  # implementation.
98
98
  base.params(
99
- "AWSAccessKeyId" => -> { aws_access_key_id },
100
- "SignatureVersion" => "2",
101
- "SignatureMethod" => "HmacSHA256",
102
- "Timestamp" => -> { Time.now.utc.iso8601 }
99
+ 'AWSAccessKeyId' => -> { aws_access_key_id },
100
+ 'SignatureVersion' => '2',
101
+ 'SignatureMethod' => 'HmacSHA256',
102
+ 'Timestamp' => -> { Time.now.utc.iso8601 }
103
103
  )
104
+
105
+ super
104
106
  end
105
107
 
106
108
  # A reusable HTTP connection.
@@ -117,11 +119,11 @@ module Jeff
117
119
  attr_writer :aws_access_key_id, :aws_secret_access_key
118
120
 
119
121
  def aws_access_key_id
120
- @aws_access_key_id || ENV["AWS_ACCESS_KEY_ID"]
122
+ @aws_access_key_id || ENV['AWS_ACCESS_KEY_ID']
121
123
  end
122
124
 
123
125
  def aws_secret_access_key
124
- @aws_secret_access_key || ENV["AWS_SECRET_ACCESS_KEY"]
126
+ @aws_secret_access_key || ENV['AWS_SECRET_ACCESS_KEY']
125
127
  end
126
128
 
127
129
  def proxy=(url)
@@ -130,28 +132,22 @@ module Jeff
130
132
 
131
133
  # Generate HTTP request verb methods.
132
134
  Excon::HTTP_VERBS.each do |method|
133
- eval <<-DEF
135
+ eval <<-RUBY, binding, __FILE__, __LINE__ + 1
134
136
  def #{method}(options = {})
135
137
  options.store(:method, :#{method})
136
138
  add_md5_digest options
137
139
  sign options
138
-
139
- begin
140
- connection.request(options)
141
- rescue Excon::Errors::RequestURITooLong
142
- raise if options[:body] || options[:method] != :post
143
- move_query_to_body options
144
- retry
145
- end
140
+ #{'move_query_to_body options' if method == 'post'}
141
+ connection.request(options)
146
142
  end
147
- DEF
143
+ RUBY
148
144
  end
149
145
 
150
146
  private
151
147
 
152
148
  def default_connection_params
153
149
  {
154
- headers: { "User-Agent" => self.class.user_agent },
150
+ headers: { 'User-Agent' => self.class.user_agent },
155
151
  expects: 200,
156
152
  omit_default_port: true
157
153
  }
@@ -159,8 +155,10 @@ module Jeff
159
155
 
160
156
  def add_md5_digest(options)
161
157
  return unless options.key?(:body)
158
+
162
159
  md5 = Content.new(options[:body]).md5
163
- (options[:headers] ||= {}).store("Content-MD5", md5)
160
+ query = options[:query] ||= {}
161
+ query.store('ContentMD5Value', md5)
164
162
  end
165
163
 
166
164
  def sign(options)
@@ -170,29 +168,32 @@ module Jeff
170
168
 
171
169
  # Generate signature.
172
170
  signature = Signer
173
- .new(options[:method], connection.data[:host], options[:path] || connection.data[:path], query_string)
174
- .sign_with(aws_secret_access_key)
171
+ .new(options[:method], connection.data[:host], options[:path] || connection.data[:path], query_string)
172
+ .sign_with(aws_secret_access_key)
175
173
 
176
174
  # Append escaped signature to query.
177
175
  options.store(:query, "#{query_string}&Signature=#{Utils.escape(signature)}")
178
176
  end
179
177
 
180
178
  def move_query_to_body(options)
179
+ return if options[:body]
180
+
181
181
  options[:headers] ||= {}
182
- options[:headers].store("Content-Type", "application/x-www-form-urlencoded")
182
+ options[:headers].store('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8')
183
183
  options.store(:body, options.delete(:query))
184
184
  end
185
185
 
186
186
  def default_query_values
187
187
  self.class.params
188
- .reduce({}) do |qv, (k, v)|
189
- v = v.respond_to?(:call) ? instance_exec(&v) : v
188
+ .reduce({}) do |qv, (k, v)|
189
+ v = v.respond_to?(:call) ? instance_exec(&v) : v
190
190
 
191
- # Ignore keys with nil values
192
- v.nil? ? qv : qv.update(k => v)
193
- end
191
+ # Ignore keys with nil values
192
+ v.nil? ? qv : qv.update(k => v)
193
+ end
194
194
  end
195
195
 
196
+ # Defines class-level methods
196
197
  module ClassMethods
197
198
  # Gets/updates default request parameters.
198
199
  def params(hsh = {})
@@ -211,7 +212,7 @@ module Jeff
211
212
  # identify the application, its version number, programming language, and
212
213
  # host.
213
214
  def default_user_agent
214
- "Jeff/#{VERSION} (Language=Ruby; #{`hostname`.chomp})"
215
+ "Jeff/#{VERSION} (Language=Ruby; #{Socket.gethostname})"
215
216
  end
216
217
  end
217
218
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Jeff
2
- VERSION = "1.5.0"
4
+ VERSION = '2.0.2'
3
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jeff
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.0
4
+ version: 2.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hakan Ensari
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-07-15 00:00:00.000000000 Z
11
+ date: 2020-08-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: excon
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 0.22.1
19
+ version: '0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 0.22.1
26
+ version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: minitest
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubocop
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  description: An Amazon Web Services client
56
70
  email:
57
71
  - me@hakanensari.com
@@ -59,23 +73,15 @@ executables: []
59
73
  extensions: []
60
74
  extra_rdoc_files: []
61
75
  files:
62
- - ".gitignore"
63
- - ".rubocop.yml"
64
- - ".travis.yml"
65
- - CHANGELOG.md
66
- - Gemfile
67
76
  - LICENSE
68
77
  - README.md
69
- - Rakefile
70
- - jeff.gemspec
71
78
  - lib/jeff.rb
72
79
  - lib/jeff/version.rb
73
- - test/test_jeff.rb
74
80
  homepage: https://github.com/hakanensari/jeff
75
81
  licenses:
76
82
  - MIT
77
83
  metadata: {}
78
- post_install_message:
84
+ post_install_message:
79
85
  rdoc_options: []
80
86
  require_paths:
81
87
  - lib
@@ -83,17 +89,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
83
89
  requirements:
84
90
  - - ">="
85
91
  - !ruby/object:Gem::Version
86
- version: '1.9'
92
+ version: '2.5'
87
93
  required_rubygems_version: !ruby/object:Gem::Requirement
88
94
  requirements:
89
95
  - - ">="
90
96
  - !ruby/object:Gem::Version
91
97
  version: '0'
92
98
  requirements: []
93
- rubyforge_project:
94
- rubygems_version: 2.4.5
95
- signing_key:
99
+ rubygems_version: 3.1.2
100
+ signing_key:
96
101
  specification_version: 4
97
102
  summary: An AWS client
98
- test_files:
99
- - test/test_jeff.rb
103
+ test_files: []
data/.gitignore DELETED
@@ -1,4 +0,0 @@
1
- Gemfile.lock
2
- .bundle
3
- bin
4
- pkg
@@ -1,2 +0,0 @@
1
- StringLiterals:
2
- EnforcedStyle: double_quotes
@@ -1,6 +0,0 @@
1
- rvm:
2
- - 1.9.3
3
- - 2.0.0
4
- - 2.1.0
5
- - jruby-19mode
6
- - rbx-2
@@ -1,20 +0,0 @@
1
- # 1.3.0 15/4/2015
2
-
3
- - Handle overly long request queries
4
- See https://github.com/hakanensari/peddler/issues/36
5
-
6
- # 1.2.0 23/1/2015
7
-
8
- - Discard parameters with nil values
9
-
10
- # 1.1.0 15/10/2014
11
-
12
- - Allow customising user agent
13
-
14
- # 1.0.1 18/12/2013
15
-
16
- - Relax Excon dependency version
17
-
18
- # 1.0.0 25/11/2013
19
-
20
- - First stable release
data/Gemfile DELETED
@@ -1,5 +0,0 @@
1
- source "https://rubygems.org"
2
- gemspec
3
-
4
- gem "jruby-openssl", platform: :jruby
5
- gem "rubysl", platform: :rbx
data/Rakefile DELETED
@@ -1,9 +0,0 @@
1
- require "bundler/gem_tasks"
2
- require "rake/testtask"
3
-
4
- Rake::TestTask.new do |t|
5
- t.libs.push "lib"
6
- t.test_files = FileList["test/test_*.rb"]
7
- end
8
-
9
- task default: :test
@@ -1,24 +0,0 @@
1
- # -*- encoding: utf-8 -*-
2
- $:.push File.expand_path("../lib", __FILE__)
3
- require File.expand_path("../lib/jeff/version.rb", __FILE__)
4
-
5
- Gem::Specification.new do |gem|
6
- gem.authors = ["Hakan Ensari"]
7
- gem.email = ["me@hakanensari.com"]
8
- gem.description = %q{An Amazon Web Services client}
9
- gem.summary = %q{An AWS client}
10
- gem.homepage = "https://github.com/hakanensari/jeff"
11
- gem.license = "MIT"
12
-
13
- gem.files = `git ls-files`.split($\)
14
- gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
15
- gem.name = "jeff"
16
- gem.require_paths = ["lib"]
17
- gem.version = Jeff::VERSION
18
-
19
- gem.add_dependency "excon", ">= 0.22.1"
20
- gem.add_development_dependency "minitest"
21
- gem.add_development_dependency "rake"
22
-
23
- gem.required_ruby_version = ">= 1.9"
24
- end
@@ -1,138 +0,0 @@
1
- require "minitest/autorun"
2
- require "minitest/pride"
3
- require_relative "../lib/jeff"
4
-
5
- class TestJeff < Minitest::Test
6
- def setup
7
- @klass = Class.new { include Jeff }
8
- end
9
-
10
- def test_delegates_unset_aws_credential_to_env_vars
11
- key = "123456"
12
- client = @klass.new
13
- %w(aws_access_key_id aws_secret_access_key).each do |attr|
14
- ENV[attr.upcase] = key
15
- assert_equal key, client.send(attr)
16
- ENV[attr.upcase] = nil
17
- refute_equal key, client.send(attr)
18
- end
19
- end
20
-
21
- def test_has_required_request_query_parameters
22
- %w(AWSAccessKeyId SignatureMethod SignatureVersion Timestamp).each do |key|
23
- assert @klass.params.key?(key)
24
- end
25
- end
26
-
27
- def test_configures_request_query_parameters
28
- @klass.params "Foo" => "bar"
29
- assert @klass.params.key?("Foo")
30
- end
31
-
32
- def test_allows_dynamic_values_for_request_query_parameters
33
- @klass.params "Foo" => -> { bar }
34
- client = @klass.new
35
- def client.bar; "baz"; end
36
- assert client.bar, client.send(:default_query_values).fetch("Foo")
37
- assert_kind_of Proc, @klass.params["Foo"]
38
- end
39
-
40
- def test_discards_request_query_parameters_with_nil_values
41
- @klass.params "Foo" => -> { bar }
42
- client = @klass.new
43
- def client.bar; end
44
- refute client.send(:default_query_values).key?("Foo")
45
- end
46
-
47
- def test_requires_signature
48
- signature = Jeff::Signature.new(nil)
49
- assert_raises(ArgumentError) { signature.sign("foo") }
50
- end
51
-
52
- def test_sorts_request_query_parameters_lexicographically
53
- query = Jeff::Query.new("A10" => 1, "A1" => 1)
54
- assert_equal "A1=1&A10=1", query.to_s
55
- end
56
-
57
- def test_handles_symbol_keys
58
- query = Jeff::Query.new(foo: 1, bar: 2)
59
- assert_equal "bar=2&foo=1", query.to_s
60
- end
61
-
62
- def test_sets_user_agent_header
63
- client = @klass.new
64
- client.aws_endpoint = "http://example.com/"
65
- assert_includes client.connection.data[:headers]["User-Agent"], "Jeff"
66
- end
67
-
68
- def test_allows_customizing_user_agent
69
- @klass.user_agent = "CustomApp/1.0"
70
- client = @klass.new
71
- client.aws_endpoint = "http://example.com/"
72
- assert_equal "CustomApp/1.0", client.connection.data[:headers]["User-Agent"]
73
- end
74
-
75
- def test_does_not_escape_tilde
76
- assert_equal "~%2C", Jeff::Utils.escape("~,")
77
- end
78
- end
79
-
80
- class TestJeffInAction < Minitest::Test
81
- def setup
82
- klass = Class.new { include Jeff }
83
- @client = klass.new
84
- @client.aws_endpoint = "http://example.com/"
85
- @client.aws_access_key_id = "foo"
86
- @client.aws_secret_access_key = "bar"
87
- end
88
-
89
- def teardown
90
- Excon.stubs.clear
91
- end
92
-
93
- Excon::HTTP_VERBS.each do |method|
94
- define_method "test_makes_#{method}_request" do
95
- Excon.stub({}, status: 200)
96
- assert_equal 200, @client.send(method, mock: true).status
97
- end
98
- end
99
-
100
- def test_adds_content_md5_request_header_if_given_a_request_body
101
- Excon.stub({}) do |request_params|
102
- { body: request_params[:headers]["Content-MD5"] }
103
- end
104
- refute_empty @client.post(body: "foo", mock: true).body
105
- end
106
-
107
- def test_moves_query_to_body_if_uri_is_too_long
108
- Excon.stub({}) do |request_params|
109
- { status: request_params[:query] ? 414 : 200 }
110
- end
111
-
112
- res = @client.post(query: { foo: "bar" }, mock: true)
113
- assert_equal 200, res.status
114
-
115
- assert_raises(Excon::Errors::RequestURITooLong) do
116
- @client.post(query: { foo: "bar" }, body: "baz", mock: true)
117
- end
118
-
119
- assert_raises(Excon::Errors::RequestURITooLong) do
120
- @client.get(query: { foo: "bar" }, mock: true)
121
- end
122
- end
123
-
124
- def test_gets_from_an_actual_endpoint
125
- @client.aws_endpoint = "https://mws.amazonservices.com/Sellers/2011-07-01"
126
- res = @client.post(query: { "Action" => "GetServiceStatus" })
127
- assert_equal 200, res.status
128
- end
129
-
130
- def test_has_no_proxy_by_default
131
- refute @client.connection.proxy
132
- end
133
-
134
- def test_sets_proxy
135
- @client.proxy = "http://my.proxy:4321"
136
- assert @client.connection.proxy
137
- end
138
- end