Skip to content

Commit 12fa0e2

Browse files
author
Amir Tocker
committed
Fix URL signature
CGI::unescape replaces '+' with a space.
1 parent 455f686 commit 12fa0e2

2 files changed

Lines changed: 28 additions & 5 deletions

File tree

lib/cloudinary/utils.rb

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -397,11 +397,7 @@ def self.unsigned_download_url(source, options = {})
397397
transformation = transformation.gsub(%r(([^:])//), '\1/')
398398
if sign_url && ( !auth_token || auth_token.empty?)
399399
to_sign = [transformation, sign_version && version, source_to_sign].reject(&:blank?).join("/")
400-
i = 0
401-
while to_sign != CGI.unescape(to_sign) && i <10
402-
to_sign = CGI.unescape(to_sign)
403-
i = i + 1
404-
end
400+
to_sign = fully_unescape(to_sign)
405401
signature = 's--' + Base64.urlsafe_encode64(Digest::SHA1.digest(to_sign + secret))[0,8] + '--'
406402
end
407403

@@ -848,8 +844,24 @@ def self.generate_auth_token(options)
848844
Cloudinary::AuthToken.generate options
849845

850846
end
847+
851848
private
852849

850+
851+
# Repeatedly unescapes the source until no more unescaping is possible or 10 cycles elapsed
852+
# @param [String] source - a (possibly) escaped string
853+
# @return [String] the fully unescaped string
854+
# @private
855+
def self.fully_unescape(source)
856+
i = 0
857+
while source != CGI.unescape(source) && i <10
858+
source = CGI.unescape(source.gsub('+', '%2B')) # don't let unescape replace '+' with space
859+
i = i + 1
860+
end
861+
source
862+
end
863+
private_class_method :fully_unescape
864+
853865
def self.hash_query_params(hash)
854866
if hash.respond_to?("to_query")
855867
hash.to_query

spec/utils_spec.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,17 @@
120120
.and empty_options
121121
end
122122

123+
it "should sign a url" do
124+
expected = Cloudinary::Utils.cloudinary_url "some_public_id.jpg",
125+
:cloud_name => "test",
126+
:api_key => "123456789012345",
127+
:api_secret => "AbcdEfghIjklmnopq1234567890",
128+
:type => "authenticated",
129+
:sign_url => true,
130+
:overlay => "text:Helvetica_50:test+text"
131+
expect(expected).to eq("http://res.cloudinary.com/test/image/authenticated/s--j5Z1ILxd--/l_text:Helvetica_50:test+text/some_public_id.jpg")
132+
end
133+
123134
it "should not sign the url_suffix" do
124135
expected_signture = Cloudinary::Utils.cloudinary_url("test", :format => "jpg", :sign_url => true).match(/s--[0-9A-Za-z_-]{8}--/).to_s
125136
expect(["test", { :url_suffix => "hello", :private_cdn => true, :format => "jpg", :sign_url => true }])

0 commit comments

Comments
 (0)