cloudinary 1.4.0 → 1.5.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +13 -5
- data/CHANGELOG.md +31 -0
- data/cloudinary.gemspec +6 -3
- data/lib/cloudinary.rb +67 -39
- data/lib/cloudinary/api.rb +46 -0
- data/lib/cloudinary/auth_token.rb +68 -0
- data/lib/cloudinary/carrier_wave/remote.rb +3 -3
- data/lib/cloudinary/ostruct2.rb +284 -0
- data/lib/cloudinary/uploader.rb +1 -0
- data/lib/cloudinary/utils.rb +35 -15
- data/lib/cloudinary/version.rb +1 -1
- data/spec/api_spec.rb +63 -21
- data/spec/archive_spec.rb +1 -1
- data/spec/auth_token_spec.rb +82 -0
- data/spec/cloudinary_helper_spec.rb +16 -0
- data/spec/cloudinary_spec.rb +15 -0
- data/spec/utils_methods_spec.rb +0 -33
- metadata +65 -34
- data/lib/cloudinary/akamai.rb +0 -50
data/lib/cloudinary/uploader.rb
CHANGED
@@ -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],
|
data/lib/cloudinary/utils.rb
CHANGED
@@ -5,10 +5,9 @@ require 'uri'
|
|
5
5
|
require 'aws_cf_signer'
|
6
6
|
require 'json'
|
7
7
|
require 'cgi'
|
8
|
-
require 'cloudinary/
|
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
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
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
|
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)
|
data/lib/cloudinary/version.rb
CHANGED
data/spec/api_spec.rb
CHANGED
@@ -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 =>
|
16
|
-
Cloudinary::Uploader.upload(TEST_IMG, :public_id => test_id_2, :tags => [TEST_TAG, TIMESTAMP_TAG], :context => "key=value", :eager =>[:width =>
|
17
|
-
Cloudinary::Uploader.upload(TEST_IMG, :public_id => test_id_3, :tags => [TEST_TAG, TIMESTAMP_TAG], :context => "key=value", :eager =>[:width =>
|
18
|
-
Cloudinary::Uploader.upload(TEST_IMG, :public_id => test_id_1, :tags => [TEST_TAG, TIMESTAMP_TAG], :context => "test-key=test", :eager =>[:width =>
|
19
|
-
Cloudinary::Uploader.upload(TEST_IMG, :public_id => test_id_3, :tags => [TEST_TAG, TIMESTAMP_TAG], :context => "test-key=tasty", :eager =>[:width =>
|
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"] ==
|
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(
|
208
|
+
transformation = @api.transformation(TEST_TRANSFOMATION)
|
208
209
|
expect(transformation).not_to be_blank
|
209
|
-
expect(transformation["info"]).to eq(["crop" => "scale", "width" =>
|
210
|
-
transformation = @api.transformation("crop" => "scale", "width" =>
|
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" =>
|
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(
|
217
|
-
transformation = @api.transformation(
|
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(
|
221
|
-
transformation = @api.transformation(
|
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(
|
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(
|
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(
|
267
|
-
@api.delete_transformation(
|
268
|
-
expect { @api.transformation(
|
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
|
data/spec/archive_spec.rb
CHANGED
@@ -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
|
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
|
data/spec/cloudinary_spec.rb
CHANGED
@@ -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
|
data/spec/utils_methods_spec.rb
CHANGED
@@ -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
|