cloudimage 0.2.1 → 0.3.0

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
2
  SHA256:
3
- metadata.gz: 278e88b372ae0e007da88f05ede4180b1db4203c5b36dca72acf56e1f510d2e6
4
- data.tar.gz: e4761b0f0ceb55bc6311e2966472a0b52dbc7694f37833f3dec6a6c8baf80a9c
3
+ metadata.gz: 06d221bc041ab617d9997d66e6d2c4b9f03dcbdcbbf4c05cb6b54f1c66f7c5f1
4
+ data.tar.gz: 2ed732e2099d6a3b1a9649da9840b303bef144f43b0cd2801e09f6d080361c28
5
5
  SHA512:
6
- metadata.gz: 323332b25479d79a894406a05dda4f9e91d119dd1d4b43f8a4880a61aa9bd5a2fa4756ec9b33e803241bef2c616f4eefdfda0e32683234f1255d4815bf582110
7
- data.tar.gz: af73227c277fb3b7b63150135e730536a7c40018e90b39c7478a4fb6592981e389e883a5529fb5ce76e217a2e117c353b1a9f6dbddde4d590a2b347dc916ccb1
6
+ metadata.gz: 5385f01daa66e04d394c8cc2d0257f367ba5f18f3f553ccc71a7341c4149975c94a5b707305cf3e3a6c93a6ff5a2346a459c623d7ca80aff35ca65c886dd0cb9
7
+ data.tar.gz: f4130b0bf5d7b40325e5a04f69a5e8dcbe117519369a517d4665788c3c78d0e84ba976d1c542bf0a06a38082893dd2342e695b8906e2ef9df54df0f807a389e9
@@ -1,4 +1,17 @@
1
- ## master
1
+ # Changelog
2
+
3
+ ## [Unreleased](https://github.com/scaleflex/cloudimage-rb/tree/HEAD)
4
+
5
+ [Full Changelog](https://github.com/scaleflex/cloudimage-rb/compare/v0.2.1...HEAD)
6
+
7
+ **Closed issues:**
8
+
9
+ - Add automatic changelog generation [\#11](https://github.com/scaleflex/cloudimage-rb/issues/11)
10
+
11
+ **Merged pull requests:**
12
+
13
+ - Use changelog generation [\#16](https://github.com/scaleflex/cloudimage-rb/pull/16) ([janklimo](https://github.com/janklimo))
14
+ - Add test coverage with SimpleCov [\#9](https://github.com/scaleflex/cloudimage-rb/pull/9) ([janklimo](https://github.com/janklimo))
2
15
 
3
16
  ## 0.2.1 (2020-06-29)
4
17
 
@@ -23,3 +36,6 @@
23
36
 
24
37
  - Set up Github actions for CI.
25
38
  [#1](https://github.com/scaleflex/cloudimage-rb/pull/1) (@janklimo)
39
+
40
+
41
+ \* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)*
data/README.md CHANGED
@@ -15,11 +15,13 @@ Supports Ruby `2.4` and above, `JRuby`, and `TruffleRuby`.
15
15
  - [Aliases](#aliases)
16
16
  - [Custom helpers](#custom-helpers)
17
17
  - [Security](#security)
18
+ - [URL signature](#url-signature)
19
+ - [URL sealing](#url-sealing)
18
20
  - [Development](#development)
19
- - [TODOs](#todos)
20
21
  - [Contributing](#contributing)
21
22
  - [License](#license)
22
23
  - [Code of Conduct](#code-of-conduct)
24
+ - [Showcase](#showcase)
23
25
 
24
26
  ## Installation
25
27
 
@@ -59,6 +61,7 @@ Cloudimage client accepts the following options:
59
61
  | `salt` | No | See [Security](#security). |
60
62
  | `signature_length` | No | Integer value in the range `6..40`. Defaults to 18. |
61
63
  | `api_version` | No | Defaults to the current stable version. |
64
+ | `sign_urls` | No | Defaults to `true`. See [Security](#security). |
62
65
 
63
66
  Calling `path` on the client object returns an instance of `Cloudimage::URI`.
64
67
  It accepts path to the image as a string and we we will use it to build
@@ -121,6 +124,8 @@ For a list of custom helpers available to you, please consult
121
124
 
122
125
  ### Security
123
126
 
127
+ #### URL signature
128
+
124
129
  If `salt` is defined, all URLs will be signed.
125
130
 
126
131
  You can control the length of the generated signature by specifying `signature_length`
@@ -133,6 +138,46 @@ uri.w(200).h(400).to_url
133
138
  # => "https://mysecrettoken.cloudimg.io/v7/assets/image.png?h=400&w=200&ci_sign=79cfbc458b"
134
139
  ```
135
140
 
141
+ #### URL sealing
142
+
143
+ Whereas URL signatures let you protect your URL from any kind of
144
+ tampering, URL sealing protects the params you specify while making
145
+ it possible to append additional params on the fly.
146
+
147
+ This is useful when working with Cloudimage's
148
+ [responsive frontend libraries](https://docs.cloudimage.io/go/cloudimage-documentation-v7/en/responsive-images).
149
+ A common use case would be sealing your watermark but letting the
150
+ React client request the best possible width.
151
+
152
+ To seal your URLs, initialize client with `salt` and set
153
+ `sign_urls` to `false`. `signature_length` setting is applied
154
+ to control the length of the generated `ci_seal` value.
155
+
156
+ Use the `seal_params` helper to specify which params to seal
157
+ as a list of arguments. These could be symbols or strings.
158
+
159
+ ```ruby
160
+ client = Cloudimage::Client.new(token: 'demoseal', salt: 'test', sign_urls: false)
161
+
162
+ client
163
+ .path('/sample.li/birds.jpg')
164
+ .f('bright:10,contrast:20')
165
+ .w(300)
166
+ .h(400)
167
+ .seal_params(:w, :f)
168
+ .to_url
169
+ # => "https://demoseal.cloudimg.io/v7/sample.li/birds.jpg?ci_eqs=Zj1icmlnaHQlM0ExMCUyQ2NvbnRyYXN0JTNBMjAmdz0zMDA&ci_seal=67dd8cc44f6ba44ee5&h=400"
170
+
171
+ # Alternative approach:
172
+ client
173
+ .path('/sample.li/birds.jpg')
174
+ .to_url(f: 'bright:10,contrast:20', w: 300, h: 400, seal_params: [:w, :f])
175
+ # => "https://demoseal.cloudimg.io/v7/sample.li/birds.jpg?ci_eqs=Zj1icmlnaHQlM0ExMCUyQ2NvbnRyYXN0JTNBMjAmdz0zMDA&ci_seal=67dd8cc44f6ba44ee5&h=400"
176
+ ```
177
+
178
+ This approach protects `w` and `f` values from being edited but
179
+ makes it possible to freely modify the value of `h`.
180
+
136
181
  ## Development
137
182
 
138
183
  After checking out the repo, run `bin/setup` to install dependencies.
@@ -140,13 +185,6 @@ Then, run `bundle exec rake` to run the tests. You can also run
140
185
  `bin/console` for an interactive prompt that will allow you to
141
186
  experiment.
142
187
 
143
- ### TODOs
144
-
145
- - URL sealing
146
- - Add support for custom CNAMEs
147
- - `srcset` generation
148
- - Purge cache API
149
-
150
188
  ## Contributing
151
189
 
152
190
  Bug reports and pull requests are welcome. This project is intended
@@ -164,3 +202,12 @@ The gem is available as open source under the terms of the
164
202
  Everyone interacting with the project's codebase, issues, and pull
165
203
  requests is expected to follow the
166
204
  [code of conduct](https://github.com/scaleflex/cloudimage-rb/blob/master/CODE_OF_CONDUCT.md).
205
+
206
+ ## Showcase
207
+
208
+ Among others, `cloudimage` is used to power the following apps:
209
+
210
+ - [Robin PRO](https://apps.shopify.com/robin-pro-image-gallery) - Fast, beautiful, mobile-friendly image galleries for Shopify stores.
211
+
212
+ Using this gem in your app? Let us know in [this issue](https://github.com/scaleflex/cloudimage-rb/issues/8)
213
+ so that we can feature it.
@@ -18,6 +18,7 @@ module Cloudimage
18
18
  @config[:signature_length] =
19
19
  options[:signature_length] || DEFAULT_SIGNATURE_LENGTH
20
20
  @config[:api_version] = API_VERSION
21
+ @config[:sign_urls] = options[:sign_urls].nil? ? true : false
21
22
 
22
23
  ensure_valid_config
23
24
  end
@@ -5,5 +5,11 @@ module Cloudimage
5
5
  def positionable_crop(origin_x:, origin_y:, width:, height:)
6
6
  tl_px(origin_x, origin_y).br_px(origin_x + width, origin_y + height)
7
7
  end
8
+
9
+ def seal_params(*query_params)
10
+ # URI#query_values returns hash where keys are strings.
11
+ sealed_params.merge(query_params.map(&:to_s))
12
+ self
13
+ end
8
14
  end
9
15
  end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cloudimage
4
+ module Refinements
5
+ unless {}.respond_to?(:slice)
6
+ refine Hash do
7
+ def slice(*keys)
8
+ keys.each_with_object({}) do |k, acc|
9
+ acc[k] = self[k] if key?(k)
10
+ end
11
+ end
12
+ end
13
+ end
14
+
15
+ unless ''.respond_to?(:delete_prefix)
16
+ refine String do
17
+ def delete_prefix(prefix)
18
+ sub(/\A#{prefix}/, '')
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'digest'
4
+ require 'base64'
5
+
6
+ require_relative 'refinements'
7
+
8
+ module Cloudimage
9
+ class Security
10
+ using Refinements
11
+
12
+ attr_reader :uri, :config
13
+
14
+ def initialize(uri, **config)
15
+ @uri = uri
16
+ @config = config
17
+ end
18
+
19
+ def sign_url(request_uri)
20
+ query = uri.query_values || {}
21
+ uri.query_values = query.merge(ci_sign: signature(request_uri))
22
+ end
23
+
24
+ def seal_url(path, sealed_params)
25
+ query = uri.query_values || {}
26
+ sealed_query = query.slice(*sealed_params)
27
+ query.keep_if { |k, _| !sealed_query.key?(k) }
28
+ eqs = eqs(sealed_query)
29
+ query[:ci_eqs] = eqs unless eqs.empty?
30
+ query[:ci_seal] = seal(path, eqs)
31
+ uri.query_values = query
32
+ end
33
+
34
+ private
35
+
36
+ def signature(request_uri)
37
+ digest = Digest::SHA1.hexdigest(config[:salt] + request_uri)
38
+ trim(digest, config[:signature_length])
39
+ end
40
+
41
+ def eqs(query_params)
42
+ uri = Addressable::URI.new
43
+ uri.query_values = query_params
44
+ Base64.urlsafe_encode64(uri.query, padding: false)
45
+ end
46
+
47
+ def seal(path, eqs)
48
+ digest = Digest::SHA1.hexdigest(path + eqs + config[:salt])
49
+ trim(digest, config[:signature_length])
50
+ end
51
+
52
+ def trim(signature, length)
53
+ signature[0, length]
54
+ end
55
+ end
56
+ end
@@ -1,31 +1,31 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'digest'
4
-
5
3
  require_relative 'params'
6
4
  require_relative 'custom_helpers'
5
+ require_relative 'security'
6
+ require_relative 'refinements'
7
7
 
8
8
  module Cloudimage
9
9
  class URI
10
+ using Refinements
11
+
10
12
  include Params
11
13
  include CustomHelpers
12
14
 
13
- attr_reader :uri, :params, :config
15
+ attr_reader :path, :uri, :params, :config, :sealed_params
14
16
 
15
17
  def initialize(path, **config)
16
18
  @config = config
17
19
  @params = {}
18
- @uri = build_uri_from(path)
20
+ @sealed_params = Set.new
21
+ @path = ensure_path_format(path)
22
+ @uri = build_uri
19
23
  end
20
24
 
21
25
  PARAMS.each do |param|
22
26
  define_method param do |*args|
23
- @params[param] = if args.any?
24
- args.join(',')
25
- else
26
- # Flag params don't need to pass in arguments.
27
- @params[param] = 1
28
- end
27
+ # Flag params don't need to pass in arguments.
28
+ params[param] = args.any? ? args.join(',') : 1
29
29
  self
30
30
  end
31
31
  end
@@ -36,43 +36,50 @@ module Cloudimage
36
36
 
37
37
  def to_url(**extra_params)
38
38
  set_uri_params(**extra_params)
39
- sign_url
39
+ secure_url
40
+ uri.to_s
40
41
  end
41
42
 
42
43
  private
43
44
 
44
- def base_url
45
+ def site
45
46
  "https://#{config[:token]}.cloudimg.io"
46
47
  end
47
48
 
48
- def base_url_with_api_version
49
- "#{base_url}/#{config[:api_version]}"
49
+ def api_version
50
+ "/#{config[:api_version]}"
50
51
  end
51
52
 
52
- def build_uri_from(path)
53
- formatted_path = path.start_with?('/') ? path : "/#{path}"
54
- Addressable::URI.parse(base_url_with_api_version + formatted_path)
53
+ def ensure_path_format(path)
54
+ path.start_with?('/') ? path : "/#{path}"
55
+ end
56
+
57
+ def request_uri
58
+ uri.request_uri.delete_prefix(api_version)
59
+ end
60
+
61
+ def build_uri
62
+ Addressable::URI.parse(site + api_version + path)
55
63
  end
56
64
 
57
65
  def set_uri_params(**extra_params)
66
+ seal_params(*extra_params.delete(:seal_params))
58
67
  url_params = params.merge(**extra_params)
59
68
  return unless url_params.any?
60
69
 
61
70
  uri.query_values = url_params
62
71
  end
63
72
 
64
- def sign_url
65
- url = uri.to_s
66
-
67
- return url if config[:salt].nil?
73
+ def secure_url
74
+ return uri.to_s if config[:salt].nil?
68
75
 
69
- url + "#{uri.query_values ? '&' : '?'}ci_sign=#{signature}"
70
- end
76
+ security = Security.new(uri, **config)
71
77
 
72
- def signature
73
- path = uri.to_s.sub(base_url_with_api_version, '')
74
- digest = Digest::SHA1.hexdigest(config[:salt] + path)
75
- digest[0..(config[:signature_length] - 1)]
78
+ if config[:sign_urls]
79
+ security.sign_url(request_uri)
80
+ else
81
+ security.seal_url(path, sealed_params)
82
+ end
76
83
  end
77
84
  end
78
85
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Cloudimage
4
- VERSION = '0.2.1'
4
+ VERSION = '0.3.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cloudimage
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jan Klimo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-06-29 00:00:00.000000000 Z
11
+ date: 2020-07-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: addressable
@@ -24,6 +24,34 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '2.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: github_changelog_generator
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 1.15.2
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 1.15.2
41
+ - !ruby/object:Gem::Dependency
42
+ name: pry
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.13'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.13'
27
55
  description: Fast and easy image resizing, transformation, and acceleration in the
28
56
  Cloud.
29
57
  email:
@@ -41,6 +69,8 @@ files:
41
69
  - lib/cloudimage/client.rb
42
70
  - lib/cloudimage/custom_helpers.rb
43
71
  - lib/cloudimage/params.rb
72
+ - lib/cloudimage/refinements.rb
73
+ - lib/cloudimage/security.rb
44
74
  - lib/cloudimage/uri.rb
45
75
  - lib/cloudimage/version.rb
46
76
  homepage: https://github.com/scaleflex/cloudimage-rb