ruby-thumbor 0.0.2 → 0.3.0
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.
- data/lib/ruby-thumbor.rb +84 -4
- data/spec/ruby-thumbor_spec.rb +350 -13
- data/tasks/rspec.rake +1 -1
- metadata +7 -5
data/lib/ruby-thumbor.rb
CHANGED
@@ -6,7 +6,7 @@ require 'base64'
|
|
6
6
|
require 'digest/md5'
|
7
7
|
|
8
8
|
module Thumbor
|
9
|
-
VERSION = '0.0
|
9
|
+
VERSION = '0.3.0'
|
10
10
|
|
11
11
|
class CryptoURL
|
12
12
|
attr_accessor :key
|
@@ -19,13 +19,93 @@ module Thumbor
|
|
19
19
|
s + ("{" * (16 - s.length % 16))
|
20
20
|
end
|
21
21
|
|
22
|
-
def
|
22
|
+
def calculate_width_and_height(url_parts, options)
|
23
|
+
width = options[:width]
|
24
|
+
height = options[:height]
|
25
|
+
|
26
|
+
if width and options[:flip]
|
27
|
+
width = width * -1
|
28
|
+
end
|
29
|
+
if height and options[:flop]
|
30
|
+
height = height * -1
|
31
|
+
end
|
32
|
+
|
33
|
+
if width or height
|
34
|
+
width = 0 if not width
|
35
|
+
height = 0 if not height
|
36
|
+
end
|
37
|
+
|
38
|
+
has_width = width
|
39
|
+
has_height = height
|
40
|
+
if options[:flip] and not has_width and not has_height
|
41
|
+
width = "-0"
|
42
|
+
height = '0' if not has_height and not options[:flop]
|
43
|
+
end
|
44
|
+
if options[:flop] and not has_width and not has_height
|
45
|
+
height = "-0"
|
46
|
+
width = '0' if not has_width and not options[:flip]
|
47
|
+
end
|
48
|
+
|
49
|
+
if width or height
|
50
|
+
width = width.to_s
|
51
|
+
height = height.to_s
|
52
|
+
url_parts.push(width << 'x' << height)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def url_for(options)
|
57
|
+
if not options[:image]
|
58
|
+
raise 'image is a required argument.'
|
59
|
+
end
|
60
|
+
|
61
|
+
url_parts = Array.new
|
62
|
+
|
63
|
+
if options[:meta]
|
64
|
+
url_parts.push('meta')
|
65
|
+
end
|
66
|
+
|
67
|
+
crop = options[:crop]
|
68
|
+
if crop:
|
69
|
+
crop_left = crop[0]
|
70
|
+
crop_top = crop[1]
|
71
|
+
crop_right = crop[2]
|
72
|
+
crop_bottom = crop[3]
|
73
|
+
|
74
|
+
if crop_left > 0 or crop_top > 0 or crop_bottom > 0 or crop_right > 0
|
75
|
+
url_parts.push(crop_left.to_s << 'x' << crop_top.to_s << ':' << crop_right.to_s << 'x' << crop_bottom.to_s)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
calculate_width_and_height(url_parts, options)
|
80
|
+
|
81
|
+
if options[:halign] and options[:halign] != 'center'
|
82
|
+
url_parts.push(options[:halign])
|
83
|
+
end
|
84
|
+
|
85
|
+
if options[:valign] and options[:valign] != 'middle'
|
86
|
+
url_parts.push(options[:valign])
|
87
|
+
end
|
88
|
+
|
89
|
+
if options[:smart]
|
90
|
+
url_parts.push('smart')
|
91
|
+
end
|
92
|
+
|
23
93
|
image_hash = Digest::MD5.hexdigest(options[:image])
|
24
|
-
|
94
|
+
url_parts.push(image_hash)
|
95
|
+
|
96
|
+
return url_parts.join('/')
|
97
|
+
end
|
98
|
+
|
99
|
+
def url_safe_base64(str)
|
100
|
+
Base64.encode64(str).gsub('+', '-').gsub('/', '_').gsub!(/[\n]/, '')
|
101
|
+
end
|
102
|
+
|
103
|
+
def generate(options)
|
104
|
+
url = pad(url_for(options))
|
25
105
|
cipher = OpenSSL::Cipher::Cipher.new('aes-128-ecb').encrypt
|
26
106
|
cipher.key = @key
|
27
107
|
encrypted = cipher.update(url)
|
28
|
-
based =
|
108
|
+
based = url_safe_base64(encrypted)
|
29
109
|
|
30
110
|
'/' << based << '/' << options[:image]
|
31
111
|
end
|
data/spec/ruby-thumbor_spec.rb
CHANGED
@@ -1,22 +1,359 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
image_url = 'my.domain.com/some/image/url.jpg'
|
5
|
+
image_md5 = 'f33af67e41168e80fcc5b00f8bd8061a'
|
6
|
+
key = 'my-security-key'
|
7
|
+
|
8
|
+
def decrypt_in_thumbor(str)
|
9
|
+
command = "python -c 'from thumbor.crypto import Crypto; cr = Crypto(\"my-security-keymy\"); print cr.decrypt(\"" << str << "\")'"
|
10
|
+
result = Array.new
|
11
|
+
IO.popen(command) { |f| result.push(f.gets) }
|
12
|
+
result = result.join('').strip
|
13
|
+
JSON.parse(result.gsub('"', "@@@").gsub("'", '"').gsub("@@@", '\\"').gsub('True', 'true').gsub('False', 'false'))
|
14
|
+
end
|
2
15
|
|
3
16
|
describe Thumbor::CryptoURL, "#new" do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
17
|
+
|
18
|
+
it "should create a new instance passing key and keep it" do
|
19
|
+
crypto = Thumbor::CryptoURL.new key
|
20
|
+
crypto.key.should == 'my-security-keymy'
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
describe Thumbor::CryptoURL, "#url_for" do
|
26
|
+
it "should return just the image hash if no arguments passed" do
|
27
|
+
crypto = Thumbor::CryptoURL.new key
|
28
|
+
|
29
|
+
url = crypto.url_for :image => image_url
|
30
|
+
|
31
|
+
url.should == image_md5
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should raise if no image passed" do
|
35
|
+
crypto = Thumbor::CryptoURL.new key
|
36
|
+
|
37
|
+
expect { crypto.url_for Hash.new }.to raise_error(RuntimeError)
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should return proper url for width-only" do
|
41
|
+
crypto = Thumbor::CryptoURL.new key
|
42
|
+
|
43
|
+
url = crypto.url_for :image => image_url, :width => 300
|
44
|
+
|
45
|
+
url.should == '300x0/' << image_md5
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should return proper url for height-only" do
|
49
|
+
crypto = Thumbor::CryptoURL.new key
|
50
|
+
|
51
|
+
url = crypto.url_for :image => image_url, :height => 300
|
52
|
+
|
53
|
+
url.should == '0x300/' << image_md5
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should return proper url for width and height" do
|
57
|
+
crypto = Thumbor::CryptoURL.new key
|
58
|
+
|
59
|
+
url = crypto.url_for :image => image_url, :width => 200, :height => 300
|
60
|
+
|
61
|
+
url.should == '200x300/' << image_md5
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should return proper smart url" do
|
65
|
+
crypto = Thumbor::CryptoURL.new key
|
66
|
+
|
67
|
+
url = crypto.url_for :image => image_url, :width => 200, :height => 300, :smart => true
|
68
|
+
|
69
|
+
url.should == '200x300/smart/' << image_md5
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should return proper flip url if no width and height" do
|
73
|
+
crypto = Thumbor::CryptoURL.new key
|
74
|
+
|
75
|
+
url = crypto.url_for :image => image_url, :flip => true
|
76
|
+
|
77
|
+
url.should == '-0x0/' << image_md5
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should return proper flop url if no width and height" do
|
81
|
+
crypto = Thumbor::CryptoURL.new key
|
82
|
+
|
83
|
+
url = crypto.url_for :image => image_url, :flop => true
|
84
|
+
|
85
|
+
url.should == '0x-0/' << image_md5
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should return proper flip-flop url if no width and height" do
|
89
|
+
crypto = Thumbor::CryptoURL.new key
|
90
|
+
|
91
|
+
url = crypto.url_for :image => image_url, :flip => true, :flop => true
|
92
|
+
|
93
|
+
url.should == '-0x-0/' << image_md5
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should return proper flip url if width" do
|
97
|
+
crypto = Thumbor::CryptoURL.new key
|
98
|
+
|
99
|
+
url = crypto.url_for :image => image_url, :width => 300, :flip => true
|
100
|
+
|
101
|
+
url.should == '-300x0/' << image_md5
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should return proper flip url if width" do
|
105
|
+
crypto = Thumbor::CryptoURL.new key
|
106
|
+
|
107
|
+
url = crypto.url_for :image => image_url, :height => 300, :flop => true
|
108
|
+
|
109
|
+
url.should == '0x-300/' << image_md5
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should return horizontal align" do
|
113
|
+
crypto = Thumbor::CryptoURL.new key
|
114
|
+
|
115
|
+
url = crypto.url_for :image => image_url, :halign => 'left'
|
116
|
+
|
117
|
+
url.should == 'left/' << image_md5
|
118
|
+
end
|
119
|
+
|
120
|
+
it "should not return horizontal align if it is center" do
|
121
|
+
crypto = Thumbor::CryptoURL.new key
|
122
|
+
|
123
|
+
url = crypto.url_for :image => image_url, :halign => 'center'
|
124
|
+
|
125
|
+
url.should == image_md5
|
126
|
+
end
|
127
|
+
|
128
|
+
it "should return vertical align" do
|
129
|
+
crypto = Thumbor::CryptoURL.new key
|
130
|
+
|
131
|
+
url = crypto.url_for :image => image_url, :valign => 'top'
|
132
|
+
|
133
|
+
url.should == 'top/' << image_md5
|
134
|
+
end
|
135
|
+
|
136
|
+
it "should not return vertical align if it is middle" do
|
137
|
+
crypto = Thumbor::CryptoURL.new key
|
138
|
+
|
139
|
+
url = crypto.url_for :image => image_url, :valign => 'middle'
|
140
|
+
|
141
|
+
url.should == image_md5
|
142
|
+
end
|
143
|
+
|
144
|
+
it "should return halign and valign properly" do
|
145
|
+
crypto = Thumbor::CryptoURL.new key
|
146
|
+
|
147
|
+
url = crypto.url_for :image => image_url, :halign => 'left', :valign => 'top'
|
148
|
+
|
149
|
+
url.should == 'left/top/' << image_md5
|
150
|
+
end
|
151
|
+
|
152
|
+
it "should return meta properly" do
|
153
|
+
crypto = Thumbor::CryptoURL.new key
|
154
|
+
|
155
|
+
url = crypto.url_for :image => image_url, :meta => true
|
156
|
+
|
157
|
+
url.should == 'meta/' << image_md5
|
158
|
+
end
|
159
|
+
|
160
|
+
it "should return proper crop url" do
|
161
|
+
crypto = Thumbor::CryptoURL.new key
|
162
|
+
|
163
|
+
url = crypto.url_for :image => image_url, :crop => [10, 20, 30, 40]
|
164
|
+
|
165
|
+
url.should == '10x20:30x40/' << image_md5
|
166
|
+
end
|
167
|
+
|
168
|
+
it "should ignore crop if all zeros" do
|
169
|
+
crypto = Thumbor::CryptoURL.new key
|
170
|
+
|
171
|
+
url = crypto.url_for :image => image_url, :crop => [0, 0, 0, 0]
|
172
|
+
|
173
|
+
url.should == image_md5
|
174
|
+
end
|
175
|
+
|
176
|
+
it "should have smart after halign and valign" do
|
177
|
+
crypto = Thumbor::CryptoURL.new key
|
178
|
+
|
179
|
+
url = crypto.url_for :image => image_url, :halign => 'left', :valign => 'top', :smart => true
|
180
|
+
|
181
|
+
url.should == 'left/top/smart/' << image_md5
|
182
|
+
end
|
183
|
+
|
10
184
|
end
|
11
185
|
|
12
186
|
describe Thumbor::CryptoURL, "#generate" do
|
13
|
-
|
14
|
-
it "should create a new instance passing key and keep it" do
|
15
|
-
crypto = Thumbor::CryptoURL.new 'my-security-key'
|
16
187
|
|
17
|
-
|
188
|
+
it "should create a new instance passing key and keep it" do
|
189
|
+
crypto = Thumbor::CryptoURL.new key
|
190
|
+
|
191
|
+
url = crypto.generate :width => 300, :height => 200, :image => image_url
|
192
|
+
|
193
|
+
url.should == '/qkLDiIbvtiks0Up9n5PACtmpOfX6dPXw4vP4kJU-jTfyF6y1GJBJyp7CHYh1H3R2/' << image_url
|
194
|
+
end
|
195
|
+
|
196
|
+
it "should allow thumbor to decrypt it properly" do
|
197
|
+
crypto = Thumbor::CryptoURL.new key
|
198
|
+
|
199
|
+
url = crypto.generate :width => 300, :height => 200, :image => image_url
|
200
|
+
|
201
|
+
encrypted = url.split('/')[1]
|
202
|
+
|
203
|
+
decrypted = decrypt_in_thumbor(encrypted)
|
204
|
+
|
205
|
+
decrypted["horizontal_flip"].should == false
|
206
|
+
decrypted["vertical_flip"].should == false
|
207
|
+
decrypted["smart"].should == false
|
208
|
+
decrypted["meta"].should == false
|
209
|
+
decrypted["crop"]["left"].should == 0
|
210
|
+
decrypted["crop"]["top"].should == 0
|
211
|
+
decrypted["crop"]["right"].should == 0
|
212
|
+
decrypted["crop"]["bottom"].should == 0
|
213
|
+
decrypted["valign"].should == 'middle'
|
214
|
+
decrypted["halign"].should == 'center'
|
215
|
+
decrypted["image_hash"].should == image_md5
|
216
|
+
decrypted["width"].should == 300
|
217
|
+
decrypted["height"].should == 200
|
218
|
+
|
219
|
+
end
|
220
|
+
|
221
|
+
it "should allow thumbor to decrypt it properly with meta" do
|
222
|
+
crypto = Thumbor::CryptoURL.new key
|
223
|
+
|
224
|
+
url = crypto.generate :width => 300, :height => 200, :meta => true, :image => image_url
|
225
|
+
|
226
|
+
encrypted = url.split('/')[1]
|
227
|
+
|
228
|
+
decrypted = decrypt_in_thumbor(encrypted)
|
229
|
+
|
230
|
+
decrypted["meta"].should == true
|
231
|
+
decrypted["image_hash"].should == image_md5
|
232
|
+
decrypted["width"].should == 300
|
233
|
+
decrypted["height"].should == 200
|
234
|
+
|
235
|
+
end
|
236
|
+
|
237
|
+
it "should allow thumbor to decrypt it properly with smart" do
|
238
|
+
crypto = Thumbor::CryptoURL.new key
|
239
|
+
|
240
|
+
url = crypto.generate :width => 300, :height => 200, :meta => true, :image => image_url, :smart => true
|
241
|
+
|
242
|
+
encrypted = url.split('/')[1]
|
243
|
+
|
244
|
+
decrypted = decrypt_in_thumbor(encrypted)
|
245
|
+
|
246
|
+
decrypted["meta"].should == true
|
247
|
+
decrypted["smart"].should == true
|
248
|
+
decrypted["image_hash"].should == image_md5
|
249
|
+
decrypted["width"].should == 300
|
250
|
+
decrypted["height"].should == 200
|
251
|
+
|
252
|
+
end
|
253
|
+
|
254
|
+
it "should allow thumbor to decrypt it properly with flip" do
|
255
|
+
crypto = Thumbor::CryptoURL.new key
|
256
|
+
|
257
|
+
url = crypto.generate :width => 300, :height => 200, :meta => true, :image => image_url, :smart => true, :flip => true
|
258
|
+
|
259
|
+
encrypted = url.split('/')[1]
|
260
|
+
|
261
|
+
decrypted = decrypt_in_thumbor(encrypted)
|
262
|
+
|
263
|
+
decrypted["meta"].should == true
|
264
|
+
decrypted["smart"].should == true
|
265
|
+
decrypted["image_hash"].should == image_md5
|
266
|
+
decrypted["width"].should == 300
|
267
|
+
decrypted["height"].should == 200
|
268
|
+
decrypted["flip_horizontally"] == true
|
269
|
+
|
270
|
+
end
|
271
|
+
|
272
|
+
it "should allow thumbor to decrypt it properly with flop" do
|
273
|
+
crypto = Thumbor::CryptoURL.new key
|
274
|
+
|
275
|
+
url = crypto.generate :width => 300, :height => 200, :meta => true, :image => image_url, :smart => true, :flip => true, :flop => true
|
276
|
+
|
277
|
+
encrypted = url.split('/')[1]
|
278
|
+
|
279
|
+
decrypted = decrypt_in_thumbor(encrypted)
|
280
|
+
|
281
|
+
decrypted["meta"].should == true
|
282
|
+
decrypted["smart"].should == true
|
283
|
+
decrypted["image_hash"].should == image_md5
|
284
|
+
decrypted["width"].should == 300
|
285
|
+
decrypted["height"].should == 200
|
286
|
+
decrypted["flip_horizontally"] == true
|
287
|
+
decrypted["flip_vertically"] == true
|
288
|
+
|
289
|
+
end
|
290
|
+
|
291
|
+
it "should allow thumbor to decrypt it properly with halign" do
|
292
|
+
crypto = Thumbor::CryptoURL.new key
|
293
|
+
|
294
|
+
url = crypto.generate :width => 300, :height => 200, :meta => true, :image => image_url, :smart => true, :flip => true, :flop => true,
|
295
|
+
:halign => 'left'
|
296
|
+
|
297
|
+
encrypted = url.split('/')[1]
|
298
|
+
|
299
|
+
decrypted = decrypt_in_thumbor(encrypted)
|
300
|
+
|
301
|
+
decrypted["meta"].should == true
|
302
|
+
decrypted["smart"].should == true
|
303
|
+
decrypted["image_hash"].should == image_md5
|
304
|
+
decrypted["width"].should == 300
|
305
|
+
decrypted["height"].should == 200
|
306
|
+
decrypted["flip_horizontally"] == true
|
307
|
+
decrypted["flip_vertically"] == true
|
308
|
+
decrypted["halign"] == "left"
|
309
|
+
|
310
|
+
end
|
311
|
+
|
312
|
+
it "should allow thumbor to decrypt it properly with valign" do
|
313
|
+
crypto = Thumbor::CryptoURL.new key
|
314
|
+
|
315
|
+
url = crypto.generate :width => 300, :height => 200, :meta => true, :image => image_url, :smart => true, :flip => true, :flop => true,
|
316
|
+
:halign => 'left', :valign => 'top'
|
317
|
+
|
318
|
+
encrypted = url.split('/')[1]
|
319
|
+
|
320
|
+
decrypted = decrypt_in_thumbor(encrypted)
|
321
|
+
|
322
|
+
decrypted["meta"].should == true
|
323
|
+
decrypted["smart"].should == true
|
324
|
+
decrypted["image_hash"].should == image_md5
|
325
|
+
decrypted["width"].should == 300
|
326
|
+
decrypted["height"].should == 200
|
327
|
+
decrypted["flip_horizontally"] == true
|
328
|
+
decrypted["flip_vertically"] == true
|
329
|
+
decrypted["halign"] == "left"
|
330
|
+
decrypted["valign"] == "top"
|
331
|
+
|
332
|
+
end
|
333
|
+
|
334
|
+
it "should allow thumbor to decrypt it properly with cropping" do
|
335
|
+
crypto = Thumbor::CryptoURL.new key
|
336
|
+
|
337
|
+
url = crypto.generate :width => 300, :height => 200, :image => image_url, :crop => [10, 20, 30, 40]
|
338
|
+
|
339
|
+
encrypted = url.split('/')[1]
|
340
|
+
|
341
|
+
decrypted = decrypt_in_thumbor(encrypted)
|
342
|
+
|
343
|
+
decrypted["horizontal_flip"].should == false
|
344
|
+
decrypted["vertical_flip"].should == false
|
345
|
+
decrypted["smart"].should == false
|
346
|
+
decrypted["meta"].should == false
|
347
|
+
decrypted["crop"]["left"].should == 10
|
348
|
+
decrypted["crop"]["top"].should == 20
|
349
|
+
decrypted["crop"]["right"].should == 30
|
350
|
+
decrypted["crop"]["bottom"].should == 40
|
351
|
+
decrypted["valign"].should == 'middle'
|
352
|
+
decrypted["halign"].should == 'center'
|
353
|
+
decrypted["image_hash"].should == image_md5
|
354
|
+
decrypted["width"].should == 300
|
355
|
+
decrypted["height"].should == 200
|
356
|
+
|
357
|
+
end
|
18
358
|
|
19
|
-
url.should == '/qkLDiIbvtiks0Up9n5PACtmpOfX6dPXw4vP4kJU-jTfyF6y1GJBJyp7CHYh1H3R2/my.domain.com/some/image/url.jpg'
|
20
|
-
end
|
21
|
-
|
22
359
|
end
|
data/tasks/rspec.rake
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-thumbor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 19
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
+
- 3
|
8
9
|
- 0
|
9
|
-
|
10
|
-
version: 0.0.2
|
10
|
+
version: 0.3.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Bernardo Heynemann
|
@@ -15,7 +15,8 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-04-03 00:00:00
|
18
|
+
date: 2011-04-03 00:00:00 -03:00
|
19
|
+
default_executable:
|
19
20
|
dependencies:
|
20
21
|
- !ruby/object:Gem::Dependency
|
21
22
|
name: hoe
|
@@ -59,6 +60,7 @@ files:
|
|
59
60
|
- spec/spec_helper.rb
|
60
61
|
- tasks/rspec.rake
|
61
62
|
- .gemtest
|
63
|
+
has_rdoc: true
|
62
64
|
homepage: http://github.com/heynemann/ruby-thumbor
|
63
65
|
licenses: []
|
64
66
|
|
@@ -89,7 +91,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
89
91
|
requirements: []
|
90
92
|
|
91
93
|
rubyforge_project: ruby-thumbor
|
92
|
-
rubygems_version: 1.
|
94
|
+
rubygems_version: 1.6.2
|
93
95
|
signing_key:
|
94
96
|
specification_version: 3
|
95
97
|
summary: ruby-thumbor is the client to the thumbor imaging service (http://github.com/globocom/thumbor).
|