condo 1.0.6 → 2.0.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.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/README.textile +19 -32
  3. data/lib/condo.rb +124 -127
  4. data/lib/condo/configuration.rb +41 -76
  5. data/lib/condo/engine.rb +32 -39
  6. data/lib/condo/errors.rb +6 -8
  7. data/lib/condo/strata/amazon_s3.rb +246 -294
  8. data/lib/condo/strata/google_cloud_storage.rb +238 -272
  9. data/lib/condo/strata/open_stack_swift.rb +251 -0
  10. data/lib/condo/version.rb +1 -1
  11. metadata +31 -96
  12. data/app/assets/javascripts/condo.js +0 -9
  13. data/app/assets/javascripts/condo/amazon.js +0 -403
  14. data/app/assets/javascripts/condo/condo.js +0 -184
  15. data/app/assets/javascripts/condo/config.js +0 -69
  16. data/app/assets/javascripts/condo/google.js +0 -338
  17. data/app/assets/javascripts/condo/md5/hash.worker.emulator.js +0 -23
  18. data/app/assets/javascripts/condo/md5/hash.worker.js +0 -11
  19. data/app/assets/javascripts/condo/md5/hasher.js +0 -119
  20. data/app/assets/javascripts/condo/md5/spark-md5.js +0 -599
  21. data/app/assets/javascripts/condo/rackspace.js +0 -326
  22. data/app/assets/javascripts/condo/services/abstract-md5.js.erb +0 -86
  23. data/app/assets/javascripts/condo/services/base64.js +0 -184
  24. data/app/assets/javascripts/condo/services/broadcaster.js +0 -26
  25. data/app/assets/javascripts/condo/services/uploader.js +0 -302
  26. data/app/assets/javascripts/core/core.js +0 -4
  27. data/app/assets/javascripts/core/services/1-safe-apply.js +0 -17
  28. data/app/assets/javascripts/core/services/2-messaging.js +0 -171
  29. data/lib/condo/strata/rackspace_cloud_files.rb +0 -245
  30. data/test/condo_test.rb +0 -27
  31. data/test/dummy/README.rdoc +0 -261
  32. data/test/dummy/Rakefile +0 -7
  33. data/test/dummy/app/assets/javascripts/application.js +0 -15
  34. data/test/dummy/app/assets/stylesheets/application.css +0 -13
  35. data/test/dummy/app/controllers/application_controller.rb +0 -3
  36. data/test/dummy/app/helpers/application_helper.rb +0 -2
  37. data/test/dummy/app/views/layouts/application.html.erb +0 -14
  38. data/test/dummy/config.ru +0 -4
  39. data/test/dummy/config/application.rb +0 -59
  40. data/test/dummy/config/boot.rb +0 -10
  41. data/test/dummy/config/database.yml +0 -25
  42. data/test/dummy/config/environment.rb +0 -5
  43. data/test/dummy/config/environments/development.rb +0 -37
  44. data/test/dummy/config/environments/production.rb +0 -67
  45. data/test/dummy/config/environments/test.rb +0 -37
  46. data/test/dummy/config/initializers/backtrace_silencers.rb +0 -7
  47. data/test/dummy/config/initializers/inflections.rb +0 -15
  48. data/test/dummy/config/initializers/mime_types.rb +0 -5
  49. data/test/dummy/config/initializers/secret_token.rb +0 -7
  50. data/test/dummy/config/initializers/session_store.rb +0 -8
  51. data/test/dummy/config/initializers/wrap_parameters.rb +0 -14
  52. data/test/dummy/config/locales/en.yml +0 -5
  53. data/test/dummy/config/routes.rb +0 -58
  54. data/test/dummy/public/404.html +0 -26
  55. data/test/dummy/public/422.html +0 -26
  56. data/test/dummy/public/500.html +0 -25
  57. data/test/dummy/public/favicon.ico +0 -0
  58. data/test/dummy/script/rails +0 -6
  59. data/test/integration/navigation_test.rb +0 -10
  60. data/test/test_helper.rb +0 -15
@@ -3,43 +3,40 @@ module Condo::Strata; end
3
3
 
4
4
 
5
5
  class Fog::Storage::Google::Real
6
- def condo_request(*args)
7
- request(*args)
8
- end
6
+ def condo_request(*args)
7
+ request(*args)
8
+ end
9
9
  end
10
10
 
11
11
 
12
12
  class Condo::Strata::GoogleCloudStorage
13
-
14
- def initialize(options)
15
- @options = {
16
- :name => :GoogleCloudStorage,
17
- :location => :na, # US or Europe, set at bucket creation time
18
- :fog => {
19
- :provider => 'Google',
20
- :google_storage_access_key_id => options[:fog_access_id] || options[:access_id],
21
- :google_storage_secret_access_key => options[:fog_secret_key] || options[:secret_key]
22
- },
23
- :api => 1
24
- }.merge!(options)
25
-
26
-
27
- raise ArgumentError, 'Google Access ID missing' if @options[:access_id].nil?
28
- raise ArgumentError, 'Google Secret Key missing' if @options[:secret_key].nil?
29
-
30
- if @options[:api] == 2
31
- @options[:secret_key] = OpenSSL::PKey::RSA.new(@options[:secret_key])
32
- end
33
-
34
- @options[:location] = @options[:location].to_sym
35
- end
36
-
37
-
38
- #
39
- # Enable CORS on a bucket for a domain
40
- #
41
- def enable_cors(bucket, origin = '*')
42
- data =
13
+ def initialize(options)
14
+ @options = {
15
+ :name => :GoogleCloudStorage,
16
+ :location => :na, # US or Europe, set at bucket creation time
17
+ :fog => {
18
+ :provider => 'Google',
19
+ :google_storage_access_key_id => options[:fog_access_id] || options[:access_id],
20
+ :google_storage_secret_access_key => options[:fog_secret_key] || options[:secret_key]
21
+ },
22
+ :api => 1
23
+ }.merge!(options)
24
+
25
+
26
+ raise ArgumentError, 'Google Access ID missing' if @options[:access_id].nil?
27
+ raise ArgumentError, 'Google Secret Key missing' if @options[:secret_key].nil?
28
+
29
+ if @options[:api] == 2
30
+ @options[:secret_key] = OpenSSL::PKey::RSA.new(@options[:secret_key])
31
+ end
32
+
33
+ @options[:location] = @options[:location].to_sym
34
+ end
35
+
36
+
37
+ # Enable CORS on a bucket for a domain
38
+ def enable_cors(bucket, origin = '*')
39
+ data =
43
40
  <<-DATA
44
41
  <?xml version="1.0" encoding="UTF-8"?>
45
42
  <CorsConfig>
@@ -70,246 +67,215 @@ class Condo::Strata::GoogleCloudStorage
70
67
  </Cors>
71
68
  </CorsConfig>
72
69
  DATA
73
-
74
- fog_connection.condo_request(
75
- :expects => 200,
76
- :body => data,
77
- :method => 'PUT',
78
- :headers => {},
79
- :host => "#{bucket}.storage.googleapis.com",
80
- :idempotent => true,
81
- :path => '?cors' # There is an issue with Fog where this isn't included as a canonical_resource
82
- )
83
- end
84
-
85
-
86
- def name
87
- @options[:name]
88
- end
89
-
90
-
91
- def location
92
- @options[:location]
93
- end
94
-
95
-
96
- #
97
- # Create a signed URL for accessing a private file
98
- #
99
- def get_object(options)
100
- options = {}.merge!(options) # Need to deep copy here
101
- options[:object_options] = {
102
- :expires => 5.minutes.from_now,
103
- :verb => :get,
104
- :headers => {},
105
- :parameters => {},
106
- :protocol => :https
107
- }.merge!(options[:object_options] || {})
108
- options.merge!(@options)
109
-
110
- #
111
- # provide the signed request
112
- #
113
- sign_request(options)[:url]
114
- end
115
-
116
-
117
- #
118
- # Creates a new upload request (either single shot or multi-part)
119
- # => Passed: bucket_name, object_key, object_options, file_size
120
- #
121
- def new_upload(options)
122
- options = {}.merge!(options) # Need to deep copy here
123
- options[:object_options] = {
124
- :permissions => :private,
125
- :expires => 5.minutes.from_now,
126
- :verb => :put, # put for direct uploads
127
- :headers => {},
128
- :parameters => {},
129
- :protocol => :https
130
- }.merge!(options[:object_options] || {})
131
- options.merge!(@options)
132
-
133
-
134
- options[:object_options][:headers]['x-goog-api-version'] = @options[:api]
135
-
136
- if options[:object_options][:headers]['x-goog-acl'].nil?
137
- options[:object_options][:headers]['x-goog-acl'] = case options[:object_options][:permissions]
138
- when :public
139
- :'public-read'
140
- else
141
- :private
142
- end
143
- end
144
-
145
- options[:object_options][:headers]['Content-Type'] = 'binary/octet-stream' if options[:object_options][:headers]['Content-Type'].nil?
146
-
147
-
148
- #
149
- # Decide what type of request is being sent
150
- #
151
- if options[:file_size] > 1.megabytes
152
- # Resumables may not support the md5 header at this time - have to compare ETag and fail on the client side
153
- options[:object_options][:verb] = :post
154
- options[:object_options][:headers]['x-goog-resumable'] = 'start'
155
- return {
156
- :signature => sign_request(options),
157
- :type => :chunked_upload # triggers resumable
158
- }
159
- else
160
- options[:object_options][:headers]['Content-Md5'] = options[:file_id] if options[:file_id].present? && options[:object_options][:headers]['Content-Md5'].nil?
161
- return {
162
- :signature => sign_request(options),
163
- :type => :direct_upload
164
- }
165
- end
166
- end
167
-
168
-
169
- #
170
- # Creates a request for the byte we were up to
171
- #
172
- def get_parts(options, setting_parts = false)
173
- options[:object_options] = {
174
- :expires => 5.minutes.from_now,
175
- :verb => :put, # put for direct uploads
176
- :headers => {},
177
- :parameters => {},
178
- :protocol => :https
179
- }.merge!(options[:object_options] || {})
180
- options.merge!(@options)
181
-
182
- #
183
- # Set the upload and request the range of bytes we are after
184
- #
185
- if setting_parts
186
- options[:object_options][:headers]['Content-Md5'] = options[:file_id] if options[:file_id].present? && options[:object_options][:headers]['Content-Md5'].nil?
187
- options[:object_options][:headers]['Content-Range'] = "bytes #{options[:part]}-#{options[:file_size] - 1}/#{options[:file_size]}"
188
- else
189
- options[:object_options][:headers]['Content-Range'] = "bytes */#{options[:file_size]}"
190
- end
191
- options[:object_options][:headers]['x-goog-api-version'] = @options[:api]
192
- options[:object_options][:parameters]['upload_id'] = options[:resumable_id]
193
-
194
- #
195
- # provide the signed request
196
- #
197
- {
198
- :expected => 308,
199
- :type => :status,
200
- :signature => sign_request(options)
201
- }
202
- end
203
-
204
-
205
- #
206
- # Returns the requests for uploading parts and completing a resumable upload
207
- #
208
- def set_part(options)
209
- resp = get_parts(options, true)
210
- resp[:type] = :resume_upload
211
- resp[:type] = :resume_upload
212
- return resp
213
- end
214
-
215
-
216
- def fog_connection
217
- @fog = @fog || Fog::Storage.new(@options[:fog])
218
- return @fog
219
- end
220
-
221
-
222
- def destroy(upload)
223
- connection = fog_connection
224
- directory = connection.directories.get(upload.bucket_name) # it is assumed this exists - if not then the upload wouldn't have taken place
225
- file = directory.files.get(upload.object_key) # NOTE:: I only assume this works with resumables... should look into it
226
-
227
- return true if file.nil?
228
- return file.destroy
229
- end
230
-
231
-
232
-
233
- protected
234
-
235
-
236
-
237
- def sign_request(options)
238
-
239
- #
240
- # Build base URL
241
- #
242
- verb = options[:object_options][:verb].to_s.upcase.to_sym
243
- options[:object_options][:expires] = options[:object_options][:expires].utc.to_i
244
-
245
- url = "/#{options[:object_key]}"
246
-
247
-
248
- #
249
- # Add signed request params
250
- #
251
- other_params = ''
252
- signed_params = '?'
253
- (options[:object_options][:parameters] || {}).each do |key, value|
70
+
71
+ fog_connection.condo_request(
72
+ :expects => 200,
73
+ :body => data,
74
+ :method => 'PUT',
75
+ :headers => {},
76
+ :host => "#{bucket}.storage.googleapis.com",
77
+ :idempotent => true,
78
+ :path => '?cors' # There is an issue with Fog where this isn't included as a canonical_resource
79
+ )
80
+ end
81
+
82
+
83
+ def name
84
+ @options[:name]
85
+ end
86
+
87
+
88
+ def location
89
+ @options[:location]
90
+ end
91
+
92
+
93
+ # Create a signed URL for accessing a private file
94
+ def get_object(options)
95
+ options = {}.merge!(options) # Need to deep copy here
96
+ options[:object_options] = {
97
+ :expires => 5.minutes.from_now,
98
+ :verb => :get,
99
+ :headers => {},
100
+ :parameters => {},
101
+ :protocol => :https
102
+ }.merge!(options[:object_options] || {})
103
+ options.merge!(@options)
104
+
105
+ #
106
+ # provide the signed request
107
+ #
108
+ sign_request(options)[:url]
109
+ end
110
+
111
+
112
+ # Creates a new upload request (either single shot or multi-part)
113
+ # => Passed: bucket_name, object_key, object_options, file_size
114
+ def new_upload(options)
115
+ options = {}.merge!(options) # Need to deep copy here
116
+ options[:object_options] = {
117
+ :permissions => :private,
118
+ :expires => 5.minutes.from_now,
119
+ :verb => :put, # put for direct uploads
120
+ :headers => {},
121
+ :parameters => {},
122
+ :protocol => :https
123
+ }.merge!(options[:object_options] || {})
124
+ options.merge!(@options)
125
+
126
+
127
+ options[:object_options][:headers]['x-goog-api-version'] = @options[:api]
128
+
129
+ if options[:object_options][:headers]['x-goog-acl'].nil?
130
+ options[:object_options][:headers]['x-goog-acl'] = case options[:object_options][:permissions]
131
+ when :public
132
+ :'public-read'
133
+ else
134
+ :private
135
+ end
136
+ end
137
+
138
+ options[:object_options][:headers]['Content-Type'] = 'binary/octet-stream' if options[:object_options][:headers]['Content-Type'].nil?
139
+
140
+
141
+ # Decide what type of request is being sent
142
+ if options[:file_size] > 1.megabytes
143
+ # Resumables may not support the md5 header at this time - have to compare ETag and fail on the client side
144
+ options[:object_options][:verb] = :post
145
+ options[:object_options][:headers]['x-goog-resumable'] = 'start'
146
+ return {
147
+ :signature => sign_request(options),
148
+ :type => :chunked_upload # triggers resumable
149
+ }
150
+ else
151
+ options[:object_options][:headers]['Content-Md5'] = options[:file_id] if options[:file_id].present? && options[:object_options][:headers]['Content-Md5'].nil?
152
+ return {
153
+ :signature => sign_request(options),
154
+ :type => :direct_upload
155
+ }
156
+ end
157
+ end
158
+
159
+
160
+ # Creates a request for the byte we were up to
161
+ def get_parts(options, setting_parts = false)
162
+ options[:object_options] = {
163
+ :expires => 5.minutes.from_now,
164
+ :verb => :put, # put for direct uploads
165
+ :headers => {},
166
+ :parameters => {},
167
+ :protocol => :https
168
+ }.merge!(options[:object_options] || {})
169
+ options.merge!(@options)
170
+
171
+ # Set the upload and request the range of bytes we are after
172
+ if setting_parts
173
+ options[:object_options][:headers]['Content-Md5'] = options[:file_id] if options[:file_id].present? && options[:object_options][:headers]['Content-Md5'].nil?
174
+ options[:object_options][:headers]['Content-Range'] = "bytes #{options[:part]}-#{options[:file_size] - 1}/#{options[:file_size]}"
175
+ else
176
+ options[:object_options][:headers]['Content-Range'] = "bytes */#{options[:file_size]}"
177
+ end
178
+ options[:object_options][:headers]['x-goog-api-version'] = @options[:api]
179
+ options[:object_options][:parameters]['upload_id'] = options[:resumable_id]
180
+
181
+ # provide the signed request
182
+ {
183
+ :expected => 308,
184
+ :type => :status,
185
+ :signature => sign_request(options)
186
+ }
187
+ end
188
+
189
+
190
+ # Returns the requests for uploading parts and completing a resumable upload
191
+ def set_part(options)
192
+ resp = get_parts(options, true)
193
+ resp[:type] = :resume_upload
194
+ resp[:type] = :resume_upload
195
+ return resp
196
+ end
197
+
198
+
199
+ def fog_connection
200
+ @fog = @fog || Fog::Storage.new(@options[:fog])
201
+ return @fog
202
+ end
203
+
204
+
205
+ def destroy(upload)
206
+ connection = fog_connection
207
+ directory = connection.directories.get(upload.bucket_name) # it is assumed this exists - if not then the upload wouldn't have taken place
208
+ file = directory.files.get(upload.object_key) # NOTE:: I only assume this works with resumables... should look into it
209
+
210
+ return true if file.nil?
211
+ return file.destroy
212
+ end
213
+
214
+
215
+
216
+ protected
217
+
218
+
219
+
220
+ def sign_request(options)
221
+
222
+ # Build base URL
223
+ verb = options[:object_options][:verb].to_s.upcase.to_sym
224
+ options[:object_options][:expires] = options[:object_options][:expires].utc.to_i
225
+
226
+ url = "/#{options[:object_key]}"
227
+
228
+ # Add signed request params
229
+ other_params = ''
230
+ signed_params = '?'
231
+ (options[:object_options][:parameters] || {}).each do |key, value|
254
232
  if ['acl', 'cors', 'location', 'logging', 'requestPayment', 'torrent', 'versions', 'versioning'].include?(key)
255
- signed_params << "#{key}&"
256
- else
257
- other_params << (value.empty? ? "#{key}&" : "#{key}=#{value}&")
233
+ signed_params << "#{key}&"
234
+ else
235
+ other_params << (value.blank? ? "#{key}&" : "#{key}=#{value}&")
236
+ end
237
+ end
238
+ signed_params.chop!
239
+
240
+ url << signed_params
241
+
242
+ # Build a request signature
243
+ signature = "#{verb}\n#{options[:object_options][:headers]['Content-Md5']}\n#{options[:object_options][:headers]['Content-Type']}\n#{options[:object_options][:expires]}\n"
244
+ if verb != :GET
245
+ options[:object_options][:headers]['x-goog-date'] ||= Time.now.utc.httpdate
246
+
247
+ google_headers, canonical_google_headers = {}, '' # Copied from https://github.com/fog/fog/blob/master/lib/fog/google/storage.rb
248
+ for key, value in options[:object_options][:headers]
249
+ if key[0..6] == 'x-goog-'
250
+ google_headers[key] = value
251
+ end
258
252
  end
259
- end
260
- signed_params.chop!
261
-
262
- url << signed_params
263
-
264
-
265
- #
266
- # Build a request signature
267
- #
268
- signature = "#{verb}\n#{options[:object_options][:headers]['Content-Md5']}\n#{options[:object_options][:headers]['Content-Type']}\n#{options[:object_options][:expires]}\n"
269
- if verb != :GET
270
- options[:object_options][:headers]['x-goog-date'] ||= Time.now.utc.httpdate
271
-
272
- google_headers, canonical_google_headers = {}, '' # Copied from https://github.com/fog/fog/blob/master/lib/fog/google/storage.rb
273
- for key, value in options[:object_options][:headers]
274
- if key[0..6] == 'x-goog-'
275
- google_headers[key] = value
276
- end
277
- end
278
-
279
- google_headers = google_headers.sort {|x, y| x[0] <=> y[0]}
280
- for key, value in google_headers
281
- signature << "#{key}:#{value}\n"
282
- end
283
- end
284
-
285
- signature << "/#{options[:bucket_name]}#{url}"
286
-
287
-
288
- #
289
- # Encode the request signature
290
- #
291
- if @options[:api] == 1
292
- signature = Base64.encode64(OpenSSL::HMAC.digest(OpenSSL::Digest::Digest.new('sha1'), @options[:secret_key], signature)).gsub("\n","")
293
- options[:object_options][:headers]['Authorization'] = "GOOG1 #{@options[:access_id]}:#{signature}"
294
- else
295
- signature = Base64.encode64(@options[:secret_key].sign(OpenSSL::Digest::SHA256.new, signature)).gsub("\n","")
296
- end
297
-
298
-
299
- url += signed_params.present? ? '&' : '?'
300
- url = "#{options[:object_options][:protocol]}://#{options[:bucket_name]}.storage.googleapis.com#{url}#{other_params}GoogleAccessId=#{@options[:access_id]}&Expires=#{options[:object_options][:expires]}&Signature=#{CGI::escape(signature)}"
301
-
302
-
303
- #
304
- # Finish building the request
305
- #
306
- return {
307
- :verb => options[:object_options][:verb].to_s.upcase,
308
- :url => url,
309
- :headers => options[:object_options][:headers]
310
- }
311
- end
312
-
313
-
253
+
254
+ google_headers = google_headers.sort {|x, y| x[0] <=> y[0]}
255
+ for key, value in google_headers
256
+ signature << "#{key}:#{value}\n"
257
+ end
258
+ end
259
+
260
+ signature << "/#{options[:bucket_name]}#{url}"
261
+
262
+ # Encode the request signature
263
+ if @options[:api] == 1
264
+ signature = Base64.encode64(OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha1'), @options[:secret_key], signature)).gsub("\n","")
265
+ options[:object_options][:headers]['Authorization'] = "GOOG1 #{@options[:access_id]}:#{signature}"
266
+ else
267
+ signature = Base64.encode64(@options[:secret_key].sign(OpenSSL::Digest::SHA256.new, signature)).gsub("\n","")
268
+ end
269
+
270
+ url += signed_params.present? ? '&' : '?'
271
+ url = "#{options[:object_options][:protocol]}://#{options[:bucket_name]}.storage.googleapis.com#{url}#{other_params}GoogleAccessId=#{@options[:access_id]}&Expires=#{options[:object_options][:expires]}&Signature=#{CGI::escape(signature)}"
272
+
273
+ # Finish building the request
274
+ return {
275
+ :verb => options[:object_options][:verb].to_s.upcase,
276
+ :url => url,
277
+ :headers => options[:object_options][:headers]
278
+ }
279
+ end
314
280
  end
315
281