fog-internet-archive 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +53 -0
  3. data/.travis.yml +16 -0
  4. data/Gemfile +3 -0
  5. data/README.md +6 -0
  6. data/Rakefile +19 -0
  7. data/fog-internet-archive.gemspec +32 -0
  8. data/lib/fog/bin/internet_archive.rb +32 -0
  9. data/lib/fog/internet_archive.rb +1 -0
  10. data/lib/fog/internet_archive/core.rb +291 -0
  11. data/lib/fog/internet_archive/models/storage/directories.rb +39 -0
  12. data/lib/fog/internet_archive/models/storage/directory.rb +105 -0
  13. data/lib/fog/internet_archive/models/storage/file.rb +254 -0
  14. data/lib/fog/internet_archive/models/storage/files.rb +119 -0
  15. data/lib/fog/internet_archive/models/storage/ia_attributes.rb +36 -0
  16. data/lib/fog/internet_archive/parsers/storage/access_control_list.rb +42 -0
  17. data/lib/fog/internet_archive/parsers/storage/complete_multipart_upload.rb +20 -0
  18. data/lib/fog/internet_archive/parsers/storage/copy_object.rb +18 -0
  19. data/lib/fog/internet_archive/parsers/storage/cors_configuration.rb +38 -0
  20. data/lib/fog/internet_archive/parsers/storage/delete_multiple_objects.rb +45 -0
  21. data/lib/fog/internet_archive/parsers/storage/get_bucket.rb +58 -0
  22. data/lib/fog/internet_archive/parsers/storage/get_bucket_lifecycle.rb +64 -0
  23. data/lib/fog/internet_archive/parsers/storage/get_bucket_location.rb +16 -0
  24. data/lib/fog/internet_archive/parsers/storage/get_bucket_logging.rb +36 -0
  25. data/lib/fog/internet_archive/parsers/storage/get_bucket_website.rb +22 -0
  26. data/lib/fog/internet_archive/parsers/storage/get_request_payment.rb +16 -0
  27. data/lib/fog/internet_archive/parsers/storage/get_service.rb +28 -0
  28. data/lib/fog/internet_archive/parsers/storage/initiate_multipart_upload.rb +20 -0
  29. data/lib/fog/internet_archive/parsers/storage/list_multipart_uploads.rb +52 -0
  30. data/lib/fog/internet_archive/parsers/storage/list_parts.rb +36 -0
  31. data/lib/fog/internet_archive/requests/storage/abort_multipart_upload.rb +27 -0
  32. data/lib/fog/internet_archive/requests/storage/acl_utils.rb +60 -0
  33. data/lib/fog/internet_archive/requests/storage/complete_multipart_upload.rb +46 -0
  34. data/lib/fog/internet_archive/requests/storage/copy_object.rb +77 -0
  35. data/lib/fog/internet_archive/requests/storage/cors_utils.rb +39 -0
  36. data/lib/fog/internet_archive/requests/storage/delete_bucket.rb +42 -0
  37. data/lib/fog/internet_archive/requests/storage/delete_bucket_cors.rb +26 -0
  38. data/lib/fog/internet_archive/requests/storage/delete_bucket_lifecycle.rb +26 -0
  39. data/lib/fog/internet_archive/requests/storage/delete_bucket_policy.rb +26 -0
  40. data/lib/fog/internet_archive/requests/storage/delete_bucket_website.rb +26 -0
  41. data/lib/fog/internet_archive/requests/storage/delete_multiple_objects.rb +88 -0
  42. data/lib/fog/internet_archive/requests/storage/delete_object.rb +46 -0
  43. data/lib/fog/internet_archive/requests/storage/get_bucket.rb +108 -0
  44. data/lib/fog/internet_archive/requests/storage/get_bucket_acl.rb +65 -0
  45. data/lib/fog/internet_archive/requests/storage/get_bucket_cors.rb +61 -0
  46. data/lib/fog/internet_archive/requests/storage/get_bucket_lifecycle.rb +35 -0
  47. data/lib/fog/internet_archive/requests/storage/get_bucket_location.rb +54 -0
  48. data/lib/fog/internet_archive/requests/storage/get_bucket_logging.rb +45 -0
  49. data/lib/fog/internet_archive/requests/storage/get_bucket_policy.rb +31 -0
  50. data/lib/fog/internet_archive/requests/storage/get_bucket_website.rb +38 -0
  51. data/lib/fog/internet_archive/requests/storage/get_object.rb +163 -0
  52. data/lib/fog/internet_archive/requests/storage/get_object_acl.rb +72 -0
  53. data/lib/fog/internet_archive/requests/storage/get_object_http_url.rb +48 -0
  54. data/lib/fog/internet_archive/requests/storage/get_object_https_url.rb +30 -0
  55. data/lib/fog/internet_archive/requests/storage/get_object_torrent.rb +45 -0
  56. data/lib/fog/internet_archive/requests/storage/get_object_url.rb +49 -0
  57. data/lib/fog/internet_archive/requests/storage/get_request_payment.rb +45 -0
  58. data/lib/fog/internet_archive/requests/storage/get_service.rb +50 -0
  59. data/lib/fog/internet_archive/requests/storage/head_object.rb +57 -0
  60. data/lib/fog/internet_archive/requests/storage/initiate_multipart_upload.rb +42 -0
  61. data/lib/fog/internet_archive/requests/storage/list_multipart_uploads.rb +52 -0
  62. data/lib/fog/internet_archive/requests/storage/list_parts.rb +53 -0
  63. data/lib/fog/internet_archive/requests/storage/post_object_hidden_fields.rb +36 -0
  64. data/lib/fog/internet_archive/requests/storage/put_bucket.rb +70 -0
  65. data/lib/fog/internet_archive/requests/storage/put_bucket_acl.rb +69 -0
  66. data/lib/fog/internet_archive/requests/storage/put_bucket_cors.rb +47 -0
  67. data/lib/fog/internet_archive/requests/storage/put_bucket_lifecycle.rb +76 -0
  68. data/lib/fog/internet_archive/requests/storage/put_bucket_logging.rb +79 -0
  69. data/lib/fog/internet_archive/requests/storage/put_bucket_policy.rb +25 -0
  70. data/lib/fog/internet_archive/requests/storage/put_bucket_website.rb +59 -0
  71. data/lib/fog/internet_archive/requests/storage/put_object.rb +94 -0
  72. data/lib/fog/internet_archive/requests/storage/put_object_acl.rb +73 -0
  73. data/lib/fog/internet_archive/requests/storage/put_object_url.rb +43 -0
  74. data/lib/fog/internet_archive/requests/storage/put_request_payment.rb +45 -0
  75. data/lib/fog/internet_archive/requests/storage/sync_clock.rb +24 -0
  76. data/lib/fog/internet_archive/requests/storage/upload_part.rb +39 -0
  77. data/lib/fog/internet_archive/signaturev4.rb +71 -0
  78. data/lib/fog/internet_archive/storage.rb +381 -0
  79. data/lib/fog/internet_archive/version.rb +5 -0
  80. data/tasks/bundler.rake +3 -0
  81. data/tasks/console.rake +17 -0
  82. data/tasks/lint.rake +3 -0
  83. data/tasks/test.rake +7 -0
  84. data/tests/helper.rb +36 -0
  85. data/tests/helpers/collection_helper.rb +88 -0
  86. data/tests/helpers/formats_helper.rb +98 -0
  87. data/tests/helpers/formats_helper_tests.rb +106 -0
  88. data/tests/helpers/mock_helper.rb +13 -0
  89. data/tests/helpers/model_helper.rb +29 -0
  90. data/tests/helpers/responds_to_helper.rb +11 -0
  91. data/tests/helpers/schema_validator_tests.rb +101 -0
  92. data/tests/helpers/succeeds_helper.rb +9 -0
  93. data/tests/internet_archive/models/storage/directory_tests.rb +42 -0
  94. data/tests/internet_archive/models/storage/file_tests.rb +61 -0
  95. data/tests/internet_archive/models/storage/files_tests.rb +60 -0
  96. data/tests/internet_archive/models/storage/url_tests.rb +28 -0
  97. data/tests/internet_archive/requests/storage/acl_utils_tests.rb +209 -0
  98. data/tests/internet_archive/requests/storage/bucket_tests.rb +324 -0
  99. data/tests/internet_archive/requests/storage/cors_utils_tests.rb +108 -0
  100. data/tests/internet_archive/requests/storage/multipart_upload_tests.rb +132 -0
  101. data/tests/internet_archive/requests/storage/object_tests.rb +166 -0
  102. data/tests/internet_archive/signaturev4_tests.rb +41 -0
  103. data/tests/internet_archive/signed_params_tests.rb +5 -0
  104. data/tests/lorem.txt +1 -0
  105. metadata +322 -0
@@ -0,0 +1,73 @@
1
+ module Fog
2
+ module Storage
3
+ class InternetArchive
4
+ class Real
5
+ require 'fog/internet_archive/requests/storage/acl_utils'
6
+
7
+ # Change access control list for an S3 object
8
+ #
9
+ # @param bucket_name [String] name of bucket to modify
10
+ # @param object_name [String] name of object to get access control list for
11
+ # @param acl [Hash]:
12
+ # * Owner [Hash]
13
+ # * ID [String] id of owner
14
+ # * DisplayName [String] display name of owner
15
+ # * AccessControlList [Array]
16
+ # * Grantee [Hash]
17
+ # * DisplayName [String] Display name of grantee
18
+ # * ID [String] Id of grantee
19
+ # or
20
+ # * EmailAddress [String] Email address of grantee
21
+ # or
22
+ # * URI [String] URI of group to grant access for
23
+ # * Permission [String] Permission, in [FULL_CONTROL, WRITE, WRITE_ACP, READ, READ_ACP]
24
+ # @param acl [String] Permissions, must be in ['private', 'public-read', 'public-read-write', 'authenticated-read']
25
+ # @param options [Hash]
26
+ #
27
+ # @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTObjectPUTacl.html
28
+
29
+ def put_object_acl(bucket_name, object_name, acl, options = {})
30
+ query = {'acl' => nil}
31
+ data = ""
32
+ headers = {}
33
+
34
+ if acl.is_a?(Hash)
35
+ data = Fog::Storage::InternetArchive.hash_to_acl(acl)
36
+ else
37
+ if !['private', 'public-read', 'public-read-write', 'authenticated-read'].include?(acl)
38
+ raise Excon::Errors::BadRequest.new('invalid x-amz-acl')
39
+ end
40
+ headers['x-amz-acl'] = acl
41
+ end
42
+
43
+ headers['Content-MD5'] = Base64.encode64(Digest::MD5.digest(data)).strip
44
+ headers['Content-Type'] = 'application/json'
45
+ headers['Date'] = Fog::Time.now.to_date_header
46
+
47
+ request({
48
+ :body => data,
49
+ :expects => 200,
50
+ :headers => headers,
51
+ :host => "#{bucket_name}.#{@host}",
52
+ :method => 'PUT',
53
+ :path => CGI.escape(object_name),
54
+ :query => query
55
+ })
56
+ end
57
+ end
58
+
59
+ class Mock
60
+ def put_object_acl(bucket_name, object_name, acl, options = {})
61
+ if acl.is_a?(Hash)
62
+ self.data[:acls][:object][bucket_name][object_name] = Fog::Storage::InternetArchive.hash_to_acl(acl)
63
+ else
64
+ if !['private', 'public-read', 'public-read-write', 'authenticated-read'].include?(acl)
65
+ raise Excon::Errors::BadRequest.new('invalid x-amz-acl')
66
+ end
67
+ self.data[:acls][:object][bucket_name][object_name] = acl
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,43 @@
1
+ module Fog
2
+ module Storage
3
+ class InternetArchive
4
+ module PutObjectUrl
5
+ def put_object_url(bucket_name, object_name, expires, headers = {}, options = {})
6
+ unless bucket_name
7
+ raise ArgumentError.new('bucket_name is required')
8
+ end
9
+ unless object_name
10
+ raise ArgumentError.new('object_name is required')
11
+ end
12
+ scheme_host_path_query({
13
+ :scheme => options[:scheme],
14
+ :headers => headers,
15
+ :host => @host,
16
+ :port => @port,
17
+ :method => 'PUT',
18
+ :path => "#{bucket_name}/#{object_name}"
19
+ }, expires)
20
+ end
21
+ end
22
+
23
+ class Real
24
+ # Get an expiring object url from S3 for putting an object
25
+ #
26
+ # @param bucket_name [String] Name of bucket containing object
27
+ # @param object_name [String] Name of object to get expiring url for
28
+ # @param expires [Time] An expiry time for this url
29
+ #
30
+ # @return [Excon::Response] response:
31
+ # * body [String] url for object
32
+ #
33
+ # @see http://docs.amazonwebservices.com/AmazonS3/latest/dev/S3_QSAuth.html
34
+
35
+ include PutObjectUrl
36
+ end
37
+
38
+ class Mock # :nodoc:all
39
+ include PutObjectUrl
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,45 @@
1
+ module Fog
2
+ module Storage
3
+ class InternetArchive
4
+ class Real
5
+ # Change who pays for requests to an S3 bucket
6
+ #
7
+ # @param bucket_name [String] name of bucket to modify
8
+ # @param payer [String] valid values are BucketOwner or Requester
9
+ #
10
+ # @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTrequestPaymentPUT.html
11
+
12
+ def put_request_payment(bucket_name, payer)
13
+ data =
14
+ <<-DATA
15
+ <RequestPaymentConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
16
+ <Payer>#{payer}</Payer>
17
+ </RequestPaymentConfiguration>
18
+ DATA
19
+ request({
20
+ :body => data,
21
+ :expects => 200,
22
+ :headers => {},
23
+ :host => "#{bucket_name}.#{@host}",
24
+ :method => 'PUT',
25
+ :query => {'requestPayment' => nil}
26
+ })
27
+ end
28
+ end
29
+
30
+ class Mock # :nodoc:all
31
+ def put_request_payment(bucket_name, payer)
32
+ response = Excon::Response.new
33
+ if bucket = self.data[:buckets][bucket_name]
34
+ response.status = 200
35
+ bucket['Payer'] = payer
36
+ else
37
+ response.status = 404
38
+ raise(Excon::Errors.status_error({:expects => 200}, response))
39
+ end
40
+ response
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,24 @@
1
+ module Fog
2
+ module Storage
3
+ class InternetArchive
4
+ class Real
5
+ # Sync clock against S3 to avoid skew errors
6
+ #
7
+ def sync_clock
8
+ response = begin
9
+ get_service
10
+ rescue Excon::Errors::HTTPStatusError => error
11
+ error.response
12
+ end
13
+ Fog::Time.now = Time.parse(response.headers['Date'])
14
+ end
15
+ end # Real
16
+
17
+ class Mock # :nodoc:all
18
+ def sync_clock
19
+ true
20
+ end
21
+ end # Mock
22
+ end # Storage
23
+ end # InternetArchive
24
+ end # Fog
@@ -0,0 +1,39 @@
1
+ module Fog
2
+ module Storage
3
+ class InternetArchive
4
+ class Real
5
+ # Upload a part for a multipart upload
6
+ #
7
+ # @param bucket_name [String] Name of bucket to add part to
8
+ # @param object_name [String] Name of object to add part to
9
+ # @param upload_id [String] Id of upload to add part to
10
+ # @param part_number [String] Index of part in upload
11
+ # @param data [File||String] Content for part
12
+ # @param options [Hash]
13
+ # @option options Content-MD5 [String] Base64 encoded 128-bit MD5 digest of message
14
+ #
15
+ # @return [Excon::Response] response
16
+ # * headers [Hash]:
17
+ # * ETag [String] etag of new object (will be needed to complete upload)
18
+ #
19
+ # @see http://docs.amazonwebservices.com/AmazonS3/latest/API/mpUploadUploadPart.html
20
+ #
21
+ def upload_part(bucket_name, object_name, upload_id, part_number, data, options = {})
22
+ data = Fog::Storage.parse_data(data)
23
+ headers = options
24
+ headers['Content-Length'] = data[:headers]['Content-Length']
25
+ request({
26
+ :body => data[:body],
27
+ :expects => 200,
28
+ :idempotent => true,
29
+ :headers => headers,
30
+ :host => "#{bucket_name}.#{@host}",
31
+ :method => 'PUT',
32
+ :path => CGI.escape(object_name),
33
+ :query => {'uploadId' => upload_id, 'partNumber' => part_number}
34
+ })
35
+ end
36
+ end # Real
37
+ end # Storage
38
+ end # InternetArchive
39
+ end # Fog
@@ -0,0 +1,71 @@
1
+ # See http://docs.amazonwebservices.com/general/latest/gr/signature-version-4.html
2
+ #
3
+ module Fog
4
+ module InternetArchive
5
+ class SignatureV4
6
+ def initialize(ia_access_key_id, secret_key, region,service)
7
+ @region = region
8
+ @service = service
9
+ @ia_access_key_id = ia_access_key_id
10
+ @hmac = Fog::HMAC.new('sha256', 'AWS4' + secret_key)
11
+ end
12
+
13
+ def sign(params, date)
14
+ canonical_request = <<-DATA
15
+ #{params[:method].to_s.upcase}
16
+ #{params[:path]}
17
+ #{canonical_query_string(params[:query])}
18
+ #{canonical_headers(params[:headers])}
19
+ #{signed_headers(params[:headers])}
20
+ #{Digest::SHA256.hexdigest(params[:body] || '')}
21
+ DATA
22
+ canonical_request.chop!
23
+ credential_scope = "#{date.utc.strftime('%Y%m%d')}/#{@region}/#{@service}/aws4_request"
24
+ string_to_sign = <<-DATA
25
+ AWS4-HMAC-SHA256
26
+ #{date.to_iso8601_basic}
27
+ #{credential_scope}
28
+ #{Digest::SHA256.hexdigest(canonical_request)}
29
+ DATA
30
+
31
+ string_to_sign.chop!
32
+
33
+ signature = derived_hmac(date).sign(string_to_sign)
34
+
35
+ "AWS4-HMAC-SHA256 Credential=#{@ia_access_key_id}/#{credential_scope}, SignedHeaders=#{signed_headers(params[:headers])}, Signature=#{signature.unpack('H*').first}"
36
+ end
37
+
38
+ protected
39
+
40
+ def canonical_query_string(query)
41
+ canonical_query_string = []
42
+ for key in (query || {}).keys.sort_by {|k| k.to_s}
43
+ component = "#{Fog::InternetArchive.escape(key.to_s)}=#{Fog::InternetArchive.escape(query[key].to_s)}"
44
+ canonical_query_string << component
45
+ end
46
+ canonical_query_string.join("&")
47
+ end
48
+
49
+ def canonical_headers(headers)
50
+ canonical_headers = ''
51
+
52
+ for key in headers.keys.sort_by {|k| k.to_s}
53
+ canonical_headers << "#{key.to_s.downcase}:#{headers[key].to_s.strip}\n"
54
+ end
55
+ canonical_headers
56
+ end
57
+
58
+ def signed_headers(headers)
59
+ headers.keys.map {|key| key.to_s}.sort.map {|key| key.downcase}.join(';')
60
+ end
61
+
62
+ def derived_hmac(date)
63
+ kDate = @hmac.sign(date.utc.strftime('%Y%m%d'))
64
+ kRegion = Fog::HMAC.new('sha256', kDate).sign(@region)
65
+ kService = Fog::HMAC.new('sha256', kRegion).sign(@service)
66
+ kSigning = Fog::HMAC.new('sha256', kService).sign('aws4_request')
67
+ Fog::HMAC.new('sha256', kSigning)
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,381 @@
1
+ require 'fog/internet_archive/core'
2
+
3
+ module Fog
4
+ module Storage
5
+ class InternetArchive < Fog::Service
6
+ requires :ia_access_key_id, :ia_secret_access_key
7
+ recognizes :endpoint, :region, :host, :path, :port, :scheme, :persistent, :ia_session_token, :ia_credentials_expire_at
8
+
9
+ secrets :ia_secret_access_key, :hmac
10
+
11
+ model_path 'fog/internet_archive/models/storage'
12
+ collection :directories
13
+ model :directory
14
+ collection :files
15
+ model :file
16
+
17
+ request_path 'fog/internet_archive/requests/storage'
18
+ request :abort_multipart_upload
19
+ request :complete_multipart_upload
20
+ request :copy_object
21
+ request :delete_bucket
22
+ request :delete_bucket_cors
23
+ request :delete_bucket_lifecycle
24
+ request :delete_bucket_policy
25
+ request :delete_bucket_website
26
+ request :delete_object
27
+ request :delete_multiple_objects
28
+ request :get_bucket
29
+ request :get_bucket_acl
30
+ request :get_bucket_cors
31
+ request :get_bucket_lifecycle
32
+ request :get_bucket_location
33
+ request :get_bucket_logging
34
+ request :get_bucket_policy
35
+ request :get_bucket_website
36
+ request :get_object
37
+ request :get_object_acl
38
+ request :get_object_torrent
39
+ request :get_object_http_url
40
+ request :get_object_https_url
41
+ request :get_object_url
42
+ request :get_request_payment
43
+ request :get_service
44
+ request :head_object
45
+ request :initiate_multipart_upload
46
+ request :list_multipart_uploads
47
+ request :list_parts
48
+ request :post_object_hidden_fields
49
+ request :put_bucket
50
+ request :put_bucket_acl
51
+ request :put_bucket_cors
52
+ request :put_bucket_lifecycle
53
+ request :put_bucket_logging
54
+ request :put_bucket_policy
55
+ request :put_bucket_website
56
+ request :put_object
57
+ request :put_object_acl
58
+ request :put_object_url
59
+ request :put_request_payment
60
+ request :sync_clock
61
+ request :upload_part
62
+
63
+ module Utils
64
+ attr_accessor :region
65
+
66
+ def http_url(params, expires)
67
+ scheme_host_path_query(params.merge(:scheme => 'http', :port => 80), expires)
68
+ end
69
+
70
+ def https_url(params, expires)
71
+ scheme_host_path_query(params.merge(:scheme => 'https', :port => 443), expires)
72
+ end
73
+
74
+ def url(params, expires)
75
+ Fog::Logger.deprecation("Fog::Storage::InternetArchive => #url is deprecated, use #https_url instead [light_black](#{caller.first})[/]")
76
+ http_url(params, expires)
77
+ end
78
+
79
+ private
80
+
81
+ def scheme_host_path_query(params, expires)
82
+ params[:scheme] ||= @scheme
83
+ if params[:port] == 80 && params[:scheme] == 'http'
84
+ params.delete(:port)
85
+ end
86
+ if params[:port] == 443 && params[:scheme] == 'https'
87
+ params.delete(:port)
88
+ end
89
+ params[:headers] ||= {}
90
+ params[:headers]['Date'] = expires.to_i
91
+ params[:path] = Fog::InternetArchive.escape(params[:path]).gsub('%2F', '/')
92
+ query = []
93
+ params[:headers]['x-amz-security-token'] = @ia_session_token if @ia_session_token
94
+ if params[:query]
95
+ for key, value in params[:query]
96
+ query << "#{key}=#{Fog::InternetArchive.escape(value)}"
97
+ end
98
+ end
99
+ query << "AWSAccessKeyId=#{@ia_access_key_id}"
100
+ query << "Signature=#{Fog::InternetArchive.escape(signature(params))}"
101
+ query << "Expires=#{params[:headers]['Date']}"
102
+ query << "x-amz-security-token=#{Fog::InternetArchive.escape(@ia_session_token)}" if @ia_session_token
103
+ port_part = params[:port] && ":#{params[:port]}"
104
+ "#{params[:scheme]}://#{params[:host]}#{port_part}/#{params[:path]}?#{query.join('&')}"
105
+ end
106
+ end
107
+
108
+ class Mock
109
+ include Utils
110
+
111
+ def self.acls(type)
112
+ case type
113
+ when 'private'
114
+ {
115
+ "AccessControlList" => [
116
+ {
117
+ "Permission" => "FULL_CONTROL",
118
+ "Grantee" => {"DisplayName" => "me", "ID" => "2744ccd10c7533bd736ad890f9dd5cab2adb27b07d500b9493f29cdc420cb2e0"}
119
+ }
120
+ ],
121
+ "Owner" => {"DisplayName" => "me", "ID" => "2744ccd10c7533bd736ad890f9dd5cab2adb27b07d500b9493f29cdc420cb2e0"}
122
+ }
123
+ when 'public-read'
124
+ {
125
+ "AccessControlList" => [
126
+ {
127
+ "Permission" => "FULL_CONTROL",
128
+ "Grantee" => {"DisplayName" => "me", "ID" => "2744ccd10c7533bd736ad890f9dd5cab2adb27b07d500b9493f29cdc420cb2e0"}
129
+ },
130
+ {
131
+ "Permission" => "READ",
132
+ "Grantee" => {"URI" => "http://acs.amazonaws.com/groups/global/AllUsers"}
133
+ }
134
+ ],
135
+ "Owner" => {"DisplayName" => "me", "ID" => "2744ccd10c7533bd736ad890f9dd5cab2adb27b07d500b9493f29cdc420cb2e0"}
136
+ }
137
+ when 'public-read-write'
138
+ {
139
+ "AccessControlList" => [
140
+ {
141
+ "Permission" => "FULL_CONTROL",
142
+ "Grantee" => {"DisplayName" => "me", "ID" => "2744ccd10c7533bd736ad890f9dd5cab2adb27b07d500b9493f29cdc420cb2e0"}
143
+ },
144
+ {
145
+ "Permission" => "READ",
146
+ "Grantee" => {"URI" => "http://acs.amazonaws.com/groups/global/AllUsers"}
147
+ },
148
+ {
149
+ "Permission" => "WRITE",
150
+ "Grantee" => {"URI" => "http://acs.amazonaws.com/groups/global/AllUsers"}
151
+ }
152
+ ],
153
+ "Owner" => {"DisplayName" => "me", "ID" => "2744ccd10c7533bd736ad890f9dd5cab2adb27b07d500b9493f29cdc420cb2e0"}
154
+ }
155
+ when 'authenticated-read'
156
+ {
157
+ "AccessControlList" => [
158
+ {
159
+ "Permission" => "FULL_CONTROL",
160
+ "Grantee" => {"DisplayName" => "me", "ID" => "2744ccd10c7533bd736ad890f9dd5cab2adb27b07d500b9493f29cdc420cb2e0"}
161
+ },
162
+ {
163
+ "Permission" => "READ",
164
+ "Grantee" => {"URI" => "http://acs.amazonaws.com/groups/global/AuthenticatedUsers"}
165
+ }
166
+ ],
167
+ "Owner" => {"DisplayName" => "me", "ID" => "2744ccd10c7533bd736ad890f9dd5cab2adb27b07d500b9493f29cdc420cb2e0"}
168
+ }
169
+ end
170
+ end
171
+
172
+ def self.data
173
+ @data ||= Hash.new do |hash, region|
174
+ hash[region] = Hash.new do |region_hash, key|
175
+ region_hash[key] = {
176
+ :acls => {
177
+ :bucket => {},
178
+ :object => {}
179
+ },
180
+ :buckets => {},
181
+ :cors => {
182
+ :bucket => {}
183
+ }
184
+ }
185
+ end
186
+ end
187
+ end
188
+
189
+ def self.reset
190
+ @data = nil
191
+ end
192
+
193
+ def initialize(options={})
194
+ setup_credentials(options)
195
+ options[:region] ||= 'us-east-1'
196
+ @host = options[:host] || Fog::InternetArchive::API_DOMAIN_NAME
197
+ @scheme = options[:scheme] || 'http'
198
+ @region = options[:region]
199
+ end
200
+
201
+ def data
202
+ self.class.data[@region][@ia_access_key_id]
203
+ end
204
+
205
+ def reset_data
206
+ self.class.data[@region].delete(@ia_access_key_id)
207
+ end
208
+
209
+ def signature(params)
210
+ "foo"
211
+ end
212
+
213
+ def setup_credentials(options)
214
+ @ia_access_key_id = options[:ia_access_key_id]
215
+ @ia_secret_access_key = options[:ia_secret_access_key]
216
+ @ia_session_token = options[:ia_session_token]
217
+ @ia_credentials_expire_at = options[:ia_credentials_expire_at]
218
+ end
219
+ end
220
+
221
+ class Real
222
+ include Utils
223
+ # include Fog::InternetArchive::CredentialFetcher::ConnectionMethods
224
+ # Initialize connection to S3
225
+ #
226
+ # ==== Notes
227
+ # options parameter must include values for :ia_access_key_id and
228
+ # :ia_secret_access_key in order to create a connection
229
+ #
230
+ # ==== Examples
231
+ # s3 = Fog::Storage.new(
232
+ # :provider => "InternetArchive",
233
+ # :ia_access_key_id => your_ia_access_key_id,
234
+ # :ia_secret_access_key => your_ia_secret_access_key
235
+ # )
236
+ #
237
+ # ==== Parameters
238
+ # * options<~Hash> - config arguments for connection. Defaults to {}.
239
+ #
240
+ # ==== Returns
241
+ # * S3 object with connection to aws.
242
+ def initialize(options={})
243
+
244
+ setup_credentials(options)
245
+ @connection_options = options[:connection_options] || {}
246
+
247
+ if @endpoint = options[:endpoint]
248
+ endpoint = URI.parse(@endpoint)
249
+ @host = endpoint.host
250
+ @path = if endpoint.path.empty?
251
+ '/'
252
+ else
253
+ endpoint.path
254
+ end
255
+ @port = endpoint.port
256
+ @scheme = endpoint.scheme
257
+ else
258
+ options[:region] ||= 'us-east-1'
259
+ @region = options[:region]
260
+ @host = options[:host] || Fog::InternetArchive::API_DOMAIN_NAME
261
+ @path = options[:path] || '/'
262
+ @persistent = options.fetch(:persistent, false)
263
+ @port = options[:port] || 80
264
+ @scheme = options[:scheme] || 'http'
265
+ end
266
+ @connection = Fog::XML::Connection.new("#{@scheme}://#{@host}:#{@port}#{@path}", @persistent, @connection_options)
267
+ end
268
+
269
+ def reload
270
+ @connection.reset
271
+ end
272
+
273
+ def signature(params)
274
+ string_to_sign =
275
+ <<-DATA
276
+ #{params[:method].to_s.upcase}
277
+ #{params[:headers]['Content-MD5']}
278
+ #{params[:headers]['Content-Type']}
279
+ #{params[:headers]['Date']}
280
+ DATA
281
+
282
+ amz_headers, canonical_amz_headers = {}, ''
283
+ for key, value in params[:headers]
284
+ if key[0..5] == 'x-amz-'
285
+ amz_headers[key] = value
286
+ end
287
+ end
288
+ amz_headers = amz_headers.sort {|x, y| x[0] <=> y[0]}
289
+ for key, value in amz_headers
290
+ canonical_amz_headers << "#{key}:#{value}\n"
291
+ end
292
+ string_to_sign << canonical_amz_headers
293
+
294
+ subdomain = params[:host].split(".#{@host}").first
295
+ unless subdomain =~ /^(?:[a-z]|\d(?!\d{0,2}(?:\.\d{1,3}){3}$))(?:[a-z0-9]|\.(?![\.\-])|\-(?![\.])){1,61}[a-z0-9]$/
296
+ Fog::Logger.warning("fog: the specified s3 bucket name(#{subdomain}) is not a valid dns name, which will negatively impact performance. For details see: http://docs.amazonwebservices.com/AmazonS3/latest/dev/BucketRestrictions.html")
297
+ params[:host] = params[:host].split("#{subdomain}.")[-1]
298
+ if params[:path]
299
+ params[:path] = "#{subdomain}/#{params[:path]}"
300
+ else
301
+ params[:path] = subdomain
302
+ end
303
+ subdomain = nil
304
+ end
305
+
306
+ canonical_resource = @path.dup
307
+ unless subdomain.nil? || subdomain == @host
308
+ canonical_resource << "#{Fog::InternetArchive.escape(subdomain).downcase}/"
309
+ end
310
+ canonical_resource << params[:path].to_s
311
+ canonical_resource << '?'
312
+ for key in (params[:query] || {}).keys.sort
313
+ if %w{
314
+ acl
315
+ cors
316
+ delete
317
+ lifecycle
318
+ location
319
+ logging
320
+ notification
321
+ partNumber
322
+ policy
323
+ requestPayment
324
+ response-cache-control
325
+ response-content-disposition
326
+ response-content-encoding
327
+ response-content-language
328
+ response-content-type
329
+ response-expires
330
+ torrent
331
+ uploadId
332
+ uploads
333
+ versionId
334
+ versioning
335
+ versions
336
+ website
337
+ }.include?(key)
338
+ canonical_resource << "#{key}#{"=#{params[:query][key]}" unless params[:query][key].nil?}&"
339
+ end
340
+ end
341
+ canonical_resource.chop!
342
+ string_to_sign << canonical_resource
343
+
344
+ signed_string = @hmac.sign(string_to_sign)
345
+ Base64.encode64(signed_string).chomp!
346
+ end
347
+
348
+ private
349
+
350
+ def setup_credentials(options)
351
+ @ia_access_key_id = options[:ia_access_key_id]
352
+ @ia_secret_access_key = options[:ia_secret_access_key]
353
+ @ia_session_token = options[:ia_session_token]
354
+ @ia_credentials_expire_at = options[:ia_credentials_expire_at]
355
+
356
+ @hmac = Fog::HMAC.new('sha1', @ia_secret_access_key)
357
+ end
358
+
359
+ def request(params, &block)
360
+ # refresh_credentials_if_expired
361
+
362
+ params[:headers]['Date'] = Fog::Time.now.to_date_header
363
+ params[:headers]['x-amz-security-token'] = @ia_session_token if @ia_session_token
364
+ params[:headers]['Authorization'] = "AWS #{@ia_access_key_id}:#{signature(params)}"
365
+ # FIXME: ToHashParser should make this not needed
366
+ original_params = params.dup
367
+
368
+ begin
369
+ response = @connection.request(params, &block)
370
+ rescue Excon::Errors::TemporaryRedirect => error
371
+ uri = URI.parse(error.response.headers['location'])
372
+ Fog::Logger.warning("fog: followed redirect to #{uri.host}, connecting to the matching region will be more performant")
373
+ response = Fog::XML::Connection.new("#{@scheme}://#{uri.host}:#{@port}", false, @connection_options).request(original_params, &block)
374
+ end
375
+
376
+ response
377
+ end
378
+ end
379
+ end
380
+ end
381
+ end