jeff 2.0.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: 82378ea1928f533eef948deb4b9b399de0557052
4
- data.tar.gz: ed55093dec599ac419c8ebd0b9cd23ebf708591d
2
+ SHA256:
3
+ metadata.gz: dc9894a6715f02b0f754506e90c496c8d7e1b6cdb946f3c77ce7faa631326753
4
+ data.tar.gz: 9c6682d0ac05ecf197e63d699a26fa03b511217f99f6c5b27116d94b42a3c09d
5
5
  SHA512:
6
- metadata.gz: 0cca7126a19eb30bf2d1426e03c93b58dcd3fce5b1c173780758857a2f997b1c4d684f470877b829f2583259a4aa98917f7e6606dc6b0235e1deb69c650c35a8
7
- data.tar.gz: 68f2b190aeb08c4da0113f923ba89bbc4b9859885e461cdf632d353508e0445fa85f54abc15903922cc4eebfcac62aed80667c08a56f392a2eaf79ed8872a285
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,22 +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
- #{"move_query_to_body options" if method == "post"}
140
+ #{'move_query_to_body options' if method == 'post'}
139
141
  connection.request(options)
140
142
  end
141
- DEF
143
+ RUBY
142
144
  end
143
145
 
144
146
  private
145
147
 
146
148
  def default_connection_params
147
149
  {
148
- headers: { "User-Agent" => self.class.user_agent },
150
+ headers: { 'User-Agent' => self.class.user_agent },
149
151
  expects: 200,
150
152
  omit_default_port: true
151
153
  }
@@ -153,9 +155,10 @@ module Jeff
153
155
 
154
156
  def add_md5_digest(options)
155
157
  return unless options.key?(:body)
158
+
156
159
  md5 = Content.new(options[:body]).md5
157
160
  query = options[:query] ||= {}
158
- query.store("ContentMD5Value", md5)
161
+ query.store('ContentMD5Value', md5)
159
162
  end
160
163
 
161
164
  def sign(options)
@@ -165,8 +168,8 @@ module Jeff
165
168
 
166
169
  # Generate signature.
167
170
  signature = Signer
168
- .new(options[:method], connection.data[:host], options[:path] || connection.data[:path], query_string)
169
- .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)
170
173
 
171
174
  # Append escaped signature to query.
172
175
  options.store(:query, "#{query_string}&Signature=#{Utils.escape(signature)}")
@@ -176,20 +179,21 @@ module Jeff
176
179
  return if options[:body]
177
180
 
178
181
  options[:headers] ||= {}
179
- options[:headers].store("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
182
+ options[:headers].store('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8')
180
183
  options.store(:body, options.delete(:query))
181
184
  end
182
185
 
183
186
  def default_query_values
184
187
  self.class.params
185
- .reduce({}) do |qv, (k, v)|
186
- 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
187
190
 
188
- # Ignore keys with nil values
189
- v.nil? ? qv : qv.update(k => v)
190
- end
191
+ # Ignore keys with nil values
192
+ v.nil? ? qv : qv.update(k => v)
193
+ end
191
194
  end
192
195
 
196
+ # Defines class-level methods
193
197
  module ClassMethods
194
198
  # Gets/updates default request parameters.
195
199
  def params(hsh = {})
@@ -208,7 +212,7 @@ module Jeff
208
212
  # identify the application, its version number, programming language, and
209
213
  # host.
210
214
  def default_user_agent
211
- "Jeff/#{VERSION} (Language=Ruby; #{`hostname`.chomp})"
215
+ "Jeff/#{VERSION} (Language=Ruby; #{Socket.gethostname})"
212
216
  end
213
217
  end
214
218
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Jeff
2
- VERSION = "2.0.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: 2.0.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: 2017-01-31 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.6.8
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,12 +0,0 @@
1
- language: ruby
2
- matrix:
3
- allow_failures:
4
- - rvm: ruby-head
5
- rvm:
6
- - 2.1
7
- - 2.2
8
- - 2.3.3
9
- - 2.4.0
10
- - jruby-9000
11
- - ruby-head
12
- sudo: false
@@ -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,10 +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
- t.ruby_opts += ['-W1']
8
- end
9
-
10
- 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,171 +0,0 @@
1
- require "minitest/autorun"
2
- require "minitest/pride"
3
- require_relative "../lib/jeff"
4
-
5
- # We may need to set ciphers explicitly on jRuby
6
- # see https://github.com/jruby/warbler/issues/340
7
- Excon.defaults[:ciphers] = "DEFAULT" if RUBY_ENGINE == "jruby"
8
-
9
- class TestJeff < Minitest::Test
10
- def setup
11
- @klass = Class.new { include Jeff }
12
- end
13
-
14
- def test_delegates_unset_aws_credential_to_env_vars
15
- key = "123456"
16
- client = @klass.new
17
- %w(aws_access_key_id aws_secret_access_key).each do |attr|
18
- ENV[attr.upcase] = key
19
- assert_equal key, client.send(attr)
20
- ENV[attr.upcase] = nil
21
- refute_equal key, client.send(attr)
22
- end
23
- end
24
-
25
- def test_has_required_request_query_parameters
26
- %w(AWSAccessKeyId SignatureMethod SignatureVersion Timestamp).each do |key|
27
- assert @klass.params.key?(key)
28
- end
29
- end
30
-
31
- def test_configures_request_query_parameters
32
- @klass.params "Foo" => "bar"
33
- assert @klass.params.key?("Foo")
34
- end
35
-
36
- def test_allows_dynamic_values_for_request_query_parameters
37
- @klass.params "Foo" => -> { bar }
38
- client = @klass.new
39
- def client.bar; "baz"; end
40
- assert client.bar, client.send(:default_query_values).fetch("Foo")
41
- assert_kind_of Proc, @klass.params["Foo"]
42
- end
43
-
44
- def test_discards_request_query_parameters_with_nil_values
45
- @klass.params "Foo" => -> { bar }
46
- client = @klass.new
47
- def client.bar; end
48
- refute client.send(:default_query_values).key?("Foo")
49
- end
50
-
51
- def test_requires_signature
52
- signature = Jeff::Signature.new(nil)
53
- assert_raises(ArgumentError) { signature.sign("foo") }
54
- end
55
-
56
- def test_sorts_request_query_parameters_lexicographically
57
- query = Jeff::Query.new("A10" => 1, "A1" => 1)
58
- assert_equal "A1=1&A10=1", query.to_s
59
- end
60
-
61
- def test_handles_symbol_keys
62
- query = Jeff::Query.new(foo: 1, bar: 2)
63
- assert_equal "bar=2&foo=1", query.to_s
64
- end
65
-
66
- def test_sets_user_agent_header
67
- client = @klass.new
68
- client.aws_endpoint = "http://example.com/"
69
- assert_includes client.connection.data[:headers]["User-Agent"], "Jeff"
70
- end
71
-
72
- def test_allows_customizing_user_agent
73
- @klass.user_agent = "CustomApp/1.0"
74
- client = @klass.new
75
- client.aws_endpoint = "http://example.com/"
76
- assert_equal "CustomApp/1.0", client.connection.data[:headers]["User-Agent"]
77
- end
78
-
79
- def test_escapes_space
80
- assert_equal "%20", Jeff::Utils.escape(" ")
81
- query = Jeff::Query.new("foo" => "bar baz")
82
- assert_equal "foo=bar%20baz", query.to_s
83
- end
84
-
85
- def test_escapes_multibyte_character
86
- assert_equal "%E2%80%A6", Jeff::Utils.escape("…")
87
- end
88
-
89
- def test_does_not_escape_tilde
90
- assert_equal "~%2C", Jeff::Utils.escape("~,")
91
- end
92
- end
93
-
94
- class TestJeffInAction < Minitest::Test
95
- def setup
96
- klass = Class.new { include Jeff }
97
- @client = klass.new
98
- @client.aws_endpoint = "http://example.com/"
99
- @client.aws_access_key_id = "foo"
100
- @client.aws_secret_access_key = "bar"
101
- end
102
-
103
- def teardown
104
- Excon.stubs.clear
105
- end
106
-
107
- Excon::HTTP_VERBS.each do |method|
108
- define_method "test_makes_#{method}_request" do
109
- Excon.stub({}, status: 200)
110
- assert_equal 200, @client.send(method, mock: true).status
111
- end
112
- end
113
-
114
- def test_adds_content_md5_request_header_if_given_a_request_body
115
- Excon.stub({}) do |request_params|
116
- { body: request_params[:query]["ContentMD5Value"] }
117
- end
118
- refute_empty @client.post(body: "foo", mock: true).body
119
- end
120
-
121
- def test_moves_query_to_body_if_post
122
- Excon.stub({}) do |request_params|
123
- { body: request_params[:body] }
124
- end
125
-
126
- res = @client.post(query: { foo: "bar" }, mock: true)
127
- assert_includes res.body, "foo=bar"
128
- end
129
-
130
- def test_does_not_move_query_to_body_if_body_is_set
131
- Excon.stub({}) do |request_params|
132
- { body: request_params[:body] }
133
- end
134
-
135
- res = @client.post(query: { foo: "bar" }, body: "baz", mock: true)
136
- assert_equal "baz", res.body
137
- end
138
-
139
- def test_does_not_move_query_to_body_if_not_post
140
- Excon.stub({}) do |request_params|
141
- { body: request_params[:body] }
142
- end
143
-
144
- res = @client.get(query: { foo: "bar" }, mock: true)
145
- assert_nil res.body
146
- end
147
-
148
- def test_sets_proper_encoding_header
149
- Excon.stub({}) do |request_params|
150
- { headers: request_params[:headers] }
151
- end
152
-
153
- res = @client.post(query: { foo: "bar" }, mock: true)
154
- assert_includes res.headers["Content-Type"], "UTF-8"
155
- end
156
-
157
- def test_gets_from_an_actual_endpoint
158
- @client.aws_endpoint = "https://mws.amazonservices.com/Sellers/2011-07-01"
159
- res = @client.post(query: { "Action" => "GetServiceStatus" })
160
- assert_equal 200, res.status
161
- end
162
-
163
- def test_has_no_proxy_by_default
164
- refute @client.connection.proxy
165
- end
166
-
167
- def test_sets_proxy
168
- @client.proxy = "http://my.proxy:4321"
169
- assert @client.connection.proxy
170
- end
171
- end