jeff 2.0.0 → 2.0.2

Sign up to get free protection for your applications and to get access to all the features.
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