cloudinary 1.4.0 → 1.5.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.
@@ -16,6 +16,7 @@ class Cloudinary::Uploader
16
16
  options.keys.each { |key| options[key.to_sym] = options.delete(key) if key.is_a?(String) }
17
17
 
18
18
  params = {
19
+ :access_mode => options[:access_mode],
19
20
  :allowed_formats => Cloudinary::Utils.build_array(options[:allowed_formats]).join(","),
20
21
  :auto_tagging => options[:auto_tagging] && options[:auto_tagging].to_f,
21
22
  :background_removal => options[:background_removal],
@@ -5,10 +5,9 @@ require 'uri'
5
5
  require 'aws_cf_signer'
6
6
  require 'json'
7
7
  require 'cgi'
8
- require 'cloudinary/akamai'
8
+ require 'cloudinary/auth_token'
9
9
 
10
10
  class Cloudinary::Utils
11
- include Cloudinary::Akamai
12
11
  # @deprecated Use Cloudinary::SHARED_CDN
13
12
  SHARED_CDN = Cloudinary::SHARED_CDN
14
13
  DEFAULT_RESPONSIVE_WIDTH_TRANSFORMATION = {:width => :auto, :crop => :limit}
@@ -41,7 +40,7 @@ class Cloudinary::Utils
41
40
 
42
41
  symbolize_keys!(options)
43
42
 
44
- responsive_width = config_option_consume(options, :responsive_width)
43
+ responsive_width = config_option_consume(options, :responsive_width)
45
44
  size = options.delete(:size)
46
45
  options[:width], options[:height] = size.split("x") if size
47
46
  width = options[:width]
@@ -282,7 +281,7 @@ class Cloudinary::Utils
282
281
  transformation = breakpoint_settings.delete(:transformation) || breakpoint_settings.delete("transformation")
283
282
  if transformation
284
283
  breakpoint_settings[:transformation] = Cloudinary::Utils.generate_transformation_string(transformation.clone, true)
285
- end
284
+ end
286
285
  end
287
286
  breakpoint_settings
288
287
 
@@ -317,6 +316,10 @@ class Cloudinary::Utils
317
316
  sign_version = config_option_consume(options, :sign_version) # Deprecated behavior
318
317
  url_suffix = options.delete(:url_suffix)
319
318
  use_root_path = config_option_consume(options, :use_root_path)
319
+ auth_token = config_option_consume(options, :auth_token)
320
+ unless auth_token == false
321
+ auth_token = Cloudinary::AuthToken.merge_auth_token(Cloudinary.config.auth_token, auth_token)
322
+ end
320
323
 
321
324
  original_source = source
322
325
  return original_source if source.blank?
@@ -354,7 +357,7 @@ class Cloudinary::Utils
354
357
  version &&= "v#{version}"
355
358
 
356
359
  transformation = transformation.gsub(%r(([^:])//), '\1/')
357
- if sign_url
360
+ if sign_url && ( !auth_token || auth_token.empty?)
358
361
  to_sign = [transformation, sign_version && version, source_to_sign].reject(&:blank?).join("/")
359
362
  i = 0
360
363
  while to_sign != CGI.unescape(to_sign) && i <10
@@ -366,6 +369,13 @@ class Cloudinary::Utils
366
369
 
367
370
  prefix = unsigned_download_url_prefix(source, cloud_name, private_cdn, cdn_subdomain, secure_cdn_subdomain, cname, secure, secure_distribution)
368
371
  source = [prefix, resource_type, type, signature, transformation, version, source].reject(&:blank?).join("/")
372
+ if sign_url && auth_token && !auth_token.empty?
373
+ auth_token[:url] = URI.parse(source).path
374
+ token = Cloudinary::AuthToken.generate auth_token
375
+ source += "?#{token}"
376
+ end
377
+
378
+ source
369
379
  end
370
380
 
371
381
  def self.finalize_source(source, format, url_suffix)
@@ -496,7 +506,7 @@ class Cloudinary::Utils
496
506
  return Cloudinary::Utils.cloudinary_api_url("download", options) + "?" + hash_query_params(cloudinary_params)
497
507
  end
498
508
 
499
- # Utility method that uses the deprecated ZIP download API.
509
+ # Utility method that uses the deprecated ZIP download API.
500
510
  # @deprecated Replaced by {download_zip_url} that uses the more advanced and robust archive generation and download API
501
511
  def self.zip_download_url(tag, options = {})
502
512
  warn "zip_download_url is deprecated. Please use download_zip_url instead."
@@ -543,14 +553,19 @@ class Cloudinary::Utils
543
553
  end
544
554
 
545
555
  def self.signed_download_url(public_id, options = {})
546
- aws_private_key_path = options[:aws_private_key_path] || Cloudinary.config.aws_private_key_path || raise(CloudinaryException, "Must supply aws_private_key_path")
547
- aws_key_pair_id = options[:aws_key_pair_id] || Cloudinary.config.aws_key_pair_id || raise(CloudinaryException, "Must supply aws_key_pair_id")
548
- authenticated_distribution = options[:authenticated_distribution] || Cloudinary.config.authenticated_distribution || raise(CloudinaryException, "Must supply authenticated_distribution")
549
- @signers ||= Hash.new{|h,k| path, id = k; h[k] = AwsCfSigner.new(path, id)}
550
- signer = @signers[[aws_private_key_path, aws_key_pair_id]]
551
- url = Cloudinary::Utils.unsigned_download_url(public_id, {:type=>:authenticated}.merge(options).merge(:secure=>true, :secure_distribution=>authenticated_distribution, :private_cdn=>true))
552
- expires_at = options[:expires_at] || (Time.now+3600)
553
- signer.sign(url, :ending => expires_at)
556
+ aws_private_key_path = options[:aws_private_key_path] || Cloudinary.config.aws_private_key_path
557
+ if aws_private_key_path
558
+ aws_key_pair_id = options[:aws_key_pair_id] || Cloudinary.config.aws_key_pair_id || raise(CloudinaryException, "Must supply aws_key_pair_id")
559
+ authenticated_distribution = options[:authenticated_distribution] || Cloudinary.config.authenticated_distribution || raise(CloudinaryException, "Must supply authenticated_distribution")
560
+ @signers ||= Hash.new{|h,k| path, id = k; h[k] = AwsCfSigner.new(path, id)}
561
+ signer = @signers[[aws_private_key_path, aws_key_pair_id]]
562
+ url = Cloudinary::Utils.unsigned_download_url(public_id, {:type=>:authenticated}.merge(options).merge(:secure=>true, :secure_distribution=>authenticated_distribution, :private_cdn=>true))
563
+ expires_at = options[:expires_at] || (Time.now+3600)
564
+ return signer.sign(url, :ending => expires_at)
565
+ else
566
+ return Cloudinary::Utils.unsigned_download_url( public_id, options)
567
+ end
568
+
554
569
  end
555
570
 
556
571
  def self.cloudinary_url(public_id, options = {})
@@ -753,7 +768,7 @@ class Cloudinary::Utils
753
768
 
754
769
  #
755
770
  # @private
756
- # @param [String|Hash|Array] an eager transformation can be a string or hash, with or without a format. The parameter also accepts an array of eager transformations.
771
+ # @param [String|Hash|Array] eager an transformation as a string or hash, with or without a format. The parameter also accepts an array of eager transformations.
757
772
  def self.build_eager(eager)
758
773
  return nil if eager.nil?
759
774
  Cloudinary::Utils.build_array(eager).map do
@@ -769,6 +784,11 @@ class Cloudinary::Utils
769
784
  end.join("|")
770
785
  end
771
786
 
787
+ def self.generate_auth_token(options)
788
+ options = Cloudinary::AuthToken.merge_auth_token Cloudinary.config.auth_token, options
789
+ Cloudinary::AuthToken.generate options
790
+
791
+ end
772
792
  private
773
793
 
774
794
  def self.hash_query_params(hash)
@@ -1,4 +1,4 @@
1
1
  # Copyright Cloudinary
2
2
  module Cloudinary
3
- VERSION = "1.4.0"
3
+ VERSION = "1.5.2"
4
4
  end
@@ -4,7 +4,8 @@ require 'cloudinary'
4
4
  describe Cloudinary::Api do
5
5
  break puts("Please setup environment for api test to run") if Cloudinary.config.api_secret.blank?
6
6
  include_context "cleanup", TIMESTAMP_TAG
7
-
7
+ TEST_WIDTH = rand(1000)
8
+ TEST_TRANSFOMATION = "c_scale,w_#{TEST_WIDTH}"
8
9
  prefix = "api_test_#{Time.now.to_i}"
9
10
  test_id_1 = "#{prefix}_1"
10
11
  test_id_2 = "#{prefix}_2"
@@ -12,11 +13,11 @@ describe Cloudinary::Api do
12
13
  before(:all) do
13
14
 
14
15
  @api = Cloudinary::Api
15
- Cloudinary::Uploader.upload(TEST_IMG, :public_id => test_id_1, :tags => [TEST_TAG, TIMESTAMP_TAG], :context => "key=value", :eager =>[:width =>100, :crop =>:scale])
16
- Cloudinary::Uploader.upload(TEST_IMG, :public_id => test_id_2, :tags => [TEST_TAG, TIMESTAMP_TAG], :context => "key=value", :eager =>[:width =>100, :crop =>:scale])
17
- Cloudinary::Uploader.upload(TEST_IMG, :public_id => test_id_3, :tags => [TEST_TAG, TIMESTAMP_TAG], :context => "key=value", :eager =>[:width =>100, :crop =>:scale])
18
- Cloudinary::Uploader.upload(TEST_IMG, :public_id => test_id_1, :tags => [TEST_TAG, TIMESTAMP_TAG], :context => "test-key=test", :eager =>[:width =>100, :crop =>:scale])
19
- Cloudinary::Uploader.upload(TEST_IMG, :public_id => test_id_3, :tags => [TEST_TAG, TIMESTAMP_TAG], :context => "test-key=tasty", :eager =>[:width =>100, :crop =>:scale])
16
+ Cloudinary::Uploader.upload(TEST_IMG, :public_id => test_id_1, :tags => [TEST_TAG, TIMESTAMP_TAG], :context => "key=value", :eager =>[:width =>TEST_WIDTH, :crop =>:scale])
17
+ Cloudinary::Uploader.upload(TEST_IMG, :public_id => test_id_2, :tags => [TEST_TAG, TIMESTAMP_TAG], :context => "key=value", :eager =>[:width =>TEST_WIDTH, :crop =>:scale])
18
+ Cloudinary::Uploader.upload(TEST_IMG, :public_id => test_id_3, :tags => [TEST_TAG, TIMESTAMP_TAG], :context => "key=value", :eager =>[:width =>TEST_WIDTH, :crop =>:scale])
19
+ Cloudinary::Uploader.upload(TEST_IMG, :public_id => test_id_1, :tags => [TEST_TAG, TIMESTAMP_TAG], :context => "test-key=test", :eager =>[:width =>TEST_WIDTH, :crop =>:scale])
20
+ Cloudinary::Uploader.upload(TEST_IMG, :public_id => test_id_3, :tags => [TEST_TAG, TIMESTAMP_TAG], :context => "test-key=tasty", :eager =>[:width =>TEST_WIDTH, :crop =>:scale])
20
21
  end
21
22
 
22
23
  after(:all) do
@@ -198,37 +199,37 @@ describe Cloudinary::Api do
198
199
 
199
200
  describe 'transformations' do
200
201
  it "should allow listing transformations" do
201
- transformation = @api.transformations()["transformations"].find { |transformation| transformation["name"] == "c_scale,w_100" }
202
+ transformation = @api.transformations(max_results: 500)["transformations"].find { |transformation| transformation["name"] == TEST_TRANSFOMATION }
202
203
  expect(transformation).not_to be_blank
203
204
  expect(transformation["used"]).to eq(true)
204
205
  end
205
206
 
206
207
  it "should allow getting transformation metadata" do
207
- transformation = @api.transformation("c_scale,w_100")
208
+ transformation = @api.transformation(TEST_TRANSFOMATION)
208
209
  expect(transformation).not_to be_blank
209
- expect(transformation["info"]).to eq(["crop" => "scale", "width" => 100])
210
- transformation = @api.transformation("crop" => "scale", "width" => 100)
210
+ expect(transformation["info"]).to eq(["crop" => "scale", "width" => TEST_WIDTH])
211
+ transformation = @api.transformation("crop" => "scale", "width" => TEST_WIDTH)
211
212
  expect(transformation).not_to be_blank
212
- expect(transformation["info"]).to eq(["crop" => "scale", "width" => 100])
213
+ expect(transformation["info"]).to eq(["crop" => "scale", "width" => TEST_WIDTH])
213
214
  end
214
215
 
215
216
  it "should allow updating transformation allowed_for_strict" do
216
- @api.update_transformation("c_scale,w_100", :allowed_for_strict => true)
217
- transformation = @api.transformation("c_scale,w_100")
217
+ @api.update_transformation(TEST_TRANSFOMATION, :allowed_for_strict => true)
218
+ transformation = @api.transformation(TEST_TRANSFOMATION)
218
219
  expect(transformation).not_to be_blank
219
220
  expect(transformation["allowed_for_strict"]).to eq(true)
220
- @api.update_transformation("c_scale,w_100", :allowed_for_strict => false)
221
- transformation = @api.transformation("c_scale,w_100")
221
+ @api.update_transformation(TEST_TRANSFOMATION, :allowed_for_strict => false)
222
+ transformation = @api.transformation(TEST_TRANSFOMATION)
222
223
  expect(transformation).not_to be_blank
223
224
  expect(transformation["allowed_for_strict"]).to eq(false)
224
225
  end
225
226
 
226
227
  it "should fetch two different derived images using next_cursor" do
227
- result = @api.transformation("c_scale,w_100", :max_results=>1)
228
+ result = @api.transformation(TEST_TRANSFOMATION, :max_results=>1)
228
229
  expect(result["derived"]).not_to be_blank
229
230
  expect(result["derived"].length).to eq(1)
230
231
  expect(result["next_cursor"]).not_to be_blank
231
- result2 = @api.transformation("c_scale,w_100", :max_results=>1, :next_cursor=>result["next_cursor"])
232
+ result2 = @api.transformation(TEST_TRANSFOMATION, :max_results=>1, :next_cursor=>result["next_cursor"])
232
233
  expect(result2["derived"]).not_to be_blank
233
234
  expect(result2["derived"].length).to eq(1)
234
235
  expect(result2["derived"][0]["id"]).not_to eq(result["derived"][0]["id"] )
@@ -263,9 +264,9 @@ describe Cloudinary::Api do
263
264
 
264
265
  end
265
266
  it "should allow deleting implicit transformation" do
266
- @api.transformation("c_scale,w_100")
267
- @api.delete_transformation("c_scale,w_100")
268
- expect { @api.transformation("c_scale,w_100") }.to raise_error(Cloudinary::Api::NotFound)
267
+ @api.transformation(TEST_TRANSFOMATION)
268
+ @api.delete_transformation(TEST_TRANSFOMATION)
269
+ expect { @api.transformation(TEST_TRANSFOMATION) }.to raise_error(Cloudinary::Api::NotFound)
269
270
  end
270
271
  end
271
272
 
@@ -374,7 +375,7 @@ describe Cloudinary::Api do
374
375
  end
375
376
 
376
377
  it "should throw if folder is missing" do
377
- Cloudinary::Api.subfolders("I_do_not_exist")
378
+ expect{Cloudinary::Api.subfolders("I_do_not_exist")}.to raise_error(Cloudinary::Api::NotFound)
378
379
  end
379
380
 
380
381
  describe '.restore' do
@@ -395,4 +396,45 @@ describe Cloudinary::Api do
395
396
 
396
397
 
397
398
  end
399
+ describe "access_mode" do
400
+ i = 0
401
+
402
+ publicId = ""
403
+ access_mode_tag = ''
404
+ before(:each) do
405
+ i += 1
406
+ access_mode_tag = TEST_TAG + "access_mode" + i.to_s
407
+ result = Cloudinary::Uploader.upload TEST_IMG, access_mode: "authenticated", tags: [TEST_TAG, TIMESTAMP_TAG, access_mode_tag]
408
+ publicId = result["public_id"]
409
+ expect(result["access_mode"]).to eq("authenticated")
410
+ end
411
+
412
+ it "should update access mode by ids" do
413
+ result = Cloudinary::Api.update_resources_access_mode_by_ids "public", [publicId]
414
+
415
+ expect(result["updated"]).to be_an_instance_of(Array)
416
+ expect(result["updated"].length).to eq(1)
417
+ resource = result["updated"][0]
418
+ expect(resource["public_id"]).to eq(publicId)
419
+ expect(resource["access_mode"]).to eq('public')
420
+ end
421
+ it "should update access mode by prefix" do
422
+ result = Cloudinary::Api.update_resources_access_mode_by_prefix "public", publicId[0..-3]
423
+
424
+ expect(result["updated"]).to be_an_instance_of(Array)
425
+ expect(result["updated"].length).to eq(1)
426
+ resource = result["updated"][0]
427
+ expect(resource["public_id"]).to eq(publicId)
428
+ expect(resource["access_mode"]).to eq('public')
429
+ end
430
+ it "should update access mode by tag" do
431
+ result = Cloudinary::Api.update_resources_access_mode_by_tag "public", access_mode_tag
432
+
433
+ expect(result["updated"]).to be_an_instance_of(Array)
434
+ expect(result["updated"].length).to eq(1)
435
+ resource = result["updated"][0]
436
+ expect(resource["public_id"]).to eq(publicId)
437
+ expect(resource["access_mode"]).to eq('public')
438
+ end
439
+ end
398
440
  end
@@ -92,7 +92,7 @@ describe Cloudinary::Uploader do
92
92
  file_count
93
93
  )
94
94
  it "should include keys: #{expected_keys.join(', ')}" do
95
- expect(archive_result.keys).to match_array(expected_keys)
95
+ expect(archive_result.keys).to include(*expected_keys)
96
96
  end
97
97
  end
98
98
  describe '.create_zip' do
@@ -0,0 +1,82 @@
1
+ require 'rspec'
2
+ require 'spec_helper'
3
+ require 'cloudinary'
4
+
5
+ KEY = "00112233FF99"
6
+ ALT_KEY = "CCBB2233FF00"
7
+
8
+ describe 'auth_token' do
9
+ before :all do
10
+ @url_backup = ENV["CLOUDINARY_URL"]
11
+ end
12
+ before do
13
+ Cloudinary.config_from_url "cloudinary://a:b@test123"
14
+ Cloudinary.config.auth_token = { :key => KEY, :duration => 300, :start_time => 11111111 }
15
+ end
16
+ after do
17
+ ENV["CLOUDINARY_URL"] = @url_backup
18
+ Cloudinary::config_from_url @url_backup
19
+ end
20
+ it "should generate with start and duration" do
21
+ token = Cloudinary::Utils.generate_auth_token :start_time => 1111111111, :acl => "/image/*", :duration => 300
22
+ expect(token).to eq '__cld_token__=st=1111111111~exp=1111111411~acl=%2fimage%2f%2a~hmac=0d5b0c9c1485ee162c459879fe62e06caa23bc26fec92d58bd100f2e1592eac6'
23
+ end
24
+
25
+ describe "authenticated url" do
26
+ before do
27
+ Cloudinary.config :private_cdn => true
28
+
29
+ end
30
+ it "should add token if authToken is globally set and signed = true" do
31
+ url = Cloudinary::Utils.cloudinary_url "sample.jpg", :sign_url => true, :resource_type => "image", :type => "authenticated", :version => "1486020273"
32
+ expect(url).to eq("http://test123-res.cloudinary.com/image/authenticated/v1486020273/sample.jpg?__cld_token__=st=11111111~exp=11111411~hmac=8db0d753ee7bbb9e2eaf8698ca3797436ba4c20e31f44527e43b6a6e995cfdb3")
33
+
34
+ end
35
+ it "should add token for 'public' resource" do
36
+ url = Cloudinary::Utils.cloudinary_url "sample.jpg", :sign_url => true, :resource_type => "image", :type => "public", :version => "1486020273"
37
+ expect(url).to eq("http://test123-res.cloudinary.com/image/public/v1486020273/sample.jpg?__cld_token__=st=11111111~exp=11111411~hmac=c2b77d9f81be6d89b5d0ebc67b671557e88a40bcf03dd4a6997ff4b994ceb80e")
38
+
39
+ end
40
+ it "should not add token if signed is false" do
41
+ url = Cloudinary::Utils.cloudinary_url "sample.jpg", :type => "authenticated", :version => "1486020273"
42
+ expect(url).to eq("http://test123-res.cloudinary.com/image/authenticated/v1486020273/sample.jpg")
43
+
44
+ end
45
+ it "should not add token if authToken is globally set but null auth token is explicitly set and signed = true" do
46
+ url = Cloudinary::Utils.cloudinary_url "sample.jpg", :auth_token => false, :sign_url => true, :type => "authenticated", :version => "1486020273"
47
+ expect(url).to eq("http://test123-res.cloudinary.com/image/authenticated/s--v2fTPYTu--/v1486020273/sample.jpg")
48
+
49
+ end
50
+ it "explicit authToken should override global setting" do
51
+ url = Cloudinary::Utils.cloudinary_url "sample.jpg", :sign_url => true, :auth_token => { :key => ALT_KEY, :start_time => 222222222, :duration => 100 }, :type => "authenticated", :transformation => { :crop => "scale", :width => 300 }
52
+ expect(url).to eq("http://test123-res.cloudinary.com/image/authenticated/c_scale,w_300/sample.jpg?__cld_token__=st=222222222~exp=222222322~hmac=7d276841d70c4ecbd0708275cd6a82e1f08e47838fbb0bceb2538e06ddfa3029")
53
+
54
+ end
55
+ it "should compute expiration as start time + duration" do
56
+ token = { :key => KEY, :start_time => 11111111, :duration => 300 }
57
+ url = Cloudinary::Utils.cloudinary_url "sample.jpg", :sign_url => true, :auth_token => token, :resource_type => "image", :type => "authenticated", :version => "1486020273"
58
+ expect(url).to eq("http://test123-res.cloudinary.com/image/authenticated/v1486020273/sample.jpg?__cld_token__=st=11111111~exp=11111411~hmac=8db0d753ee7bbb9e2eaf8698ca3797436ba4c20e31f44527e43b6a6e995cfdb3")
59
+
60
+ end
61
+ it "should raise if key is not provided" do
62
+ Cloudinary.config.auth_token[:key] = nil
63
+ token = { :expiration => 111111, :duration => 0 }
64
+ expect{Cloudinary::Utils.generate_auth_token(token)}.to raise_error
65
+ end
66
+ it "should raise if expiration and duration are not provided" do
67
+ token = { :key => KEY, :expiration => 0, :duration => 0 }
68
+ expect{Cloudinary::Utils.generate_auth_token(token)}.to raise_error
69
+ end
70
+ end
71
+ describe "authentication token" do
72
+ it "should generate token string" do
73
+ user = "foobar" # we can't rely on the default "now" value in tests
74
+ tokenOptions = { :key => KEY, :duration => 300, :acl => "/*/t_#{user}" }
75
+ tokenOptions[:start_time] = 222222222 # we can't rely on the default "now" value in tests
76
+ cookieToken = Cloudinary::Utils.generate_auth_token tokenOptions
77
+ expect(cookieToken).to eq("__cld_token__=st=222222222~exp=222222522~acl=%2f%2a%2ft_foobar~hmac=1284376353c1c43d6f6a98f2813c5596f4ff6f34d837cd853fd8c3c9e7f8428c")
78
+
79
+ end
80
+ end
81
+ end
82
+
@@ -4,6 +4,8 @@ require 'cloudinary'
4
4
  require 'action_view'
5
5
  require 'cloudinary/helper'
6
6
 
7
+ KEY = "00112233FF99"
8
+
7
9
  helper_class = Class.new do
8
10
  include CloudinaryHelper
9
11
  end
@@ -127,4 +129,18 @@ RSpec.describe CloudinaryHelper do
127
129
  expect(tag['http-equiv']).to eq('Accept-CH')
128
130
  end
129
131
  end
132
+
133
+ context "auth_token" do
134
+ it "should add token to an image tag url" do
135
+ tag = helper.cl_image_tag "sample.jpg",
136
+ :cloud_name => 'test123',
137
+ :sign_url => true,
138
+ :type => "authenticated",
139
+ :version => "1486020273",
140
+ :auth_token => {key: KEY, start_time: 11111111, duration: 300}
141
+ expect(tag).to match /<img.*src="http:\/\/res.cloudinary.com\/test123\/image\/authenticated\/v1486020273\/sample.jpg\?__cld_token__=st=11111111~exp=11111411~hmac=9bd6f41e2a5893da8343dc8eb648de8bf73771993a6d1457d49851250caf3b80.*>/
142
+
143
+ end
144
+
145
+ end
130
146
  end
@@ -14,4 +14,19 @@ describe Cloudinary do
14
14
  expect(Cloudinary.USER_AGENT).to match( %r"Spec\/1.0 \(Test\) CloudinaryRuby/[\d.]+")
15
15
 
16
16
  end
17
+
18
+ describe 'config' do
19
+ before do
20
+ @url_backup = ENV["CLOUDINARY_URL"]
21
+ end
22
+ after do
23
+ ENV["CLOUDINARY_URL"] = @url_backup
24
+ Cloudinary::config_from_url @url_backup
25
+ end
26
+ it "should allow nested values in CLOUDINARY_URL" do
27
+ ENV["CLOUDINARY_URL"] = "cloudinary://key:secret@test123?foo[bar]=value"
28
+ Cloudinary::config_from_url ENV["CLOUDINARY_URL"]
29
+ expect(Cloudinary::config.foo.bar).to eq 'value'
30
+ end
31
+ end
17
32
  end
@@ -15,38 +15,5 @@ describe Utils do
15
15
  it "should parse a percent range value" do
16
16
  expect(Utils.instance_eval { norm_range_value("20p") }).to eq("20p")
17
17
  end
18
- describe 'Utils.generate_token' do
19
- config_backup = Cloudinary.config.clone
20
- before do
21
- Cloudinary.config.akamai_key = '00112233FF99'
22
- end
23
- after do
24
- Cloudinary.config.each_pair { |k, _| Cloudinary.config.delete_field(k) }
25
- Cloudinary.config(config_backup.to_h)
26
- end
27
- it "should generate an Akamai token with start_time and window" do
28
- token = Utils.generate_token start_time: 1111111111, acl: '/image/*', window: 300
29
- expect(token).to eq('__cld_token__=st=1111111111~exp=1111111411~acl=/image/*~hmac=0854e8b6b6a46471a80b2dc28c69bd352d977a67d031755cc6f3486c121b43af')
30
- end
31
- it "should generate an Akamai token with window" do
32
- first_exp = Time.new.getgm.to_i + 300
33
- # expiration is calculated automatically as now + window
34
- token = Utils.generate_token acl: '*', window: 300
35
- second_exp = Time.new.getgm.to_i + 300
36
- match = /exp=(\d+)/.match(token)
37
- expect(match[1]).to be_truthy
38
- expiration = match[1].to_i
39
- expect(expiration).to be_between(first_exp, second_exp)
40
- expect(Utils.generate_token acl: '*', end_time: expiration).to eq(token)
41
- end
42
18
 
43
- it "should accept a key" do
44
- expect(Utils.generate_token acl: '*', end_time: 10000000, key: '00aabbff')
45
- .to eq('__cld_token__=exp=10000000~acl=*~hmac=030eafb6b19e499659d699b3d43e7595e35e3c0060e8a71904b3b8c8759f4890')
46
- end
47
- it "should throw if no end_time or window is provided" do
48
- expect { Utils.generate_token acl: '*' }.to raise_error
49
-
50
- end
51
- end
52
19
  end