cloudinary 1.4.0 → 1.5.2

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