bucket_client 0.1.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.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/.gitlab-ci.yml +70 -0
- data/.idea/bucket_client.iml +105 -0
- data/.idea/encodings.xml +4 -0
- data/.idea/misc.xml +7 -0
- data/.idea/modules.xml +8 -0
- data/.idea/runConfigurations/Integration_Test.xml +37 -0
- data/.idea/runConfigurations/Unit_Test.xml +37 -0
- data/.rspec +3 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +114 -0
- data/LICENSE.txt +21 -0
- data/README.md +870 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/bucket_client.gemspec +46 -0
- data/integration/aws_blob_spec.rb +134 -0
- data/integration/aws_bucket_spec.rb +145 -0
- data/integration/azure_blob_spec.rb +132 -0
- data/integration/azure_bucket_spec.rb +132 -0
- data/integration/dev_blob_spec.rb +131 -0
- data/integration/dev_bucket_spec.rb +140 -0
- data/integration/do_blob_spec.rb +134 -0
- data/integration/do_bucket_spec.rb +144 -0
- data/integration/gcp_blob_spec.rb +132 -0
- data/integration/gcp_bucket_spec.rb +132 -0
- data/integration/img.jpg +0 -0
- data/lib/bucket_client.rb +66 -0
- data/lib/bucket_client/aws/aws_bucket.rb +85 -0
- data/lib/bucket_client/aws/aws_client.rb +195 -0
- data/lib/bucket_client/aws/aws_http_client.rb +32 -0
- data/lib/bucket_client/aws/aws_policy_factory.rb +26 -0
- data/lib/bucket_client/aws4_request_signer.rb +133 -0
- data/lib/bucket_client/azure/azure_bucket.rb +83 -0
- data/lib/bucket_client/azure/azure_client.rb +197 -0
- data/lib/bucket_client/bucket.rb +388 -0
- data/lib/bucket_client/bucket_operation_exception.rb +8 -0
- data/lib/bucket_client/client.rb +408 -0
- data/lib/bucket_client/dev/local_bucket.rb +84 -0
- data/lib/bucket_client/dev/local_client.rb +148 -0
- data/lib/bucket_client/digital_ocean/digital_ocean_acl_factory.rb +39 -0
- data/lib/bucket_client/digital_ocean/digital_ocean_bucket.rb +81 -0
- data/lib/bucket_client/digital_ocean/digital_ocean_client.rb +275 -0
- data/lib/bucket_client/digital_ocean/digital_ocean_http_client.rb +31 -0
- data/lib/bucket_client/gcp/gcp_bucket.rb +79 -0
- data/lib/bucket_client/gcp/gcp_client.rb +171 -0
- data/lib/bucket_client/operation_result.rb +33 -0
- data/lib/bucket_client/version.rb +3 -0
- metadata +246 -0
@@ -0,0 +1,148 @@
|
|
1
|
+
require "fileutils"
|
2
|
+
module BucketClient
|
3
|
+
class LocalClient < Client
|
4
|
+
|
5
|
+
attr_reader :path, :principal
|
6
|
+
|
7
|
+
def initialize(path, principal = nil)
|
8
|
+
@path = path
|
9
|
+
@principal = principal || path
|
10
|
+
unless File.directory? path
|
11
|
+
FileUtils.mkdir_p path
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# @param [String] key
|
16
|
+
def exist_bucket(key)
|
17
|
+
raise ArgumentError.new("Cannot contain slash") if key.count("/") > 0 || key.count("\\") > 0
|
18
|
+
File.directory? bucket_dir(key)
|
19
|
+
end
|
20
|
+
|
21
|
+
def get_bucket!(key)
|
22
|
+
LocalBucket.new(self, key)
|
23
|
+
end
|
24
|
+
|
25
|
+
def put_bucket(key)
|
26
|
+
val = get_bucket! key
|
27
|
+
dir = bucket_dir key
|
28
|
+
FileUtils.mkdir_p dir unless File.directory? dir
|
29
|
+
OperationResult.new(true, "OK", val, 200)
|
30
|
+
end
|
31
|
+
|
32
|
+
def create_bucket(key)
|
33
|
+
exist = exist_bucket key
|
34
|
+
if exist
|
35
|
+
OperationResult.new(false, "Bucket already exist", nil, 409)
|
36
|
+
else
|
37
|
+
put_bucket key
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def delete_bucket_if_exist(key)
|
42
|
+
dir = bucket_dir key
|
43
|
+
FileUtils.remove_dir dir if File.directory? dir
|
44
|
+
OperationResult.new(true, "OK", nil, 204)
|
45
|
+
end
|
46
|
+
|
47
|
+
def delete_bucket(key)
|
48
|
+
exist = exist_bucket key
|
49
|
+
if exist
|
50
|
+
delete_bucket_if_exist key
|
51
|
+
else
|
52
|
+
OperationResult.new(false, "Bucket does not exist", nil, 404)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def set_read_policy(key, access)
|
57
|
+
raise ArgumentError.new("Read Policy not accepted") if access != :public && access != :private
|
58
|
+
exist = exist_bucket key
|
59
|
+
OperationResult.new(exist, "", nil, exist ? 200 : 404)
|
60
|
+
end
|
61
|
+
|
62
|
+
def set_get_cors(key, _)
|
63
|
+
exist = exist_bucket key
|
64
|
+
OperationResult.new(exist, "", nil, exist ? 200 : 404)
|
65
|
+
end
|
66
|
+
|
67
|
+
def get_blob(uri)
|
68
|
+
begin
|
69
|
+
path = get_blob_path uri
|
70
|
+
bin = IO.binread path
|
71
|
+
OperationResult.new(true, "OK", bin, 200)
|
72
|
+
rescue StandardError => e
|
73
|
+
OperationResult.new(false, e.message, nil, 400)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def exist_blob(uri)
|
78
|
+
path = get_blob_path uri
|
79
|
+
Pathname.new(path).exist?
|
80
|
+
end
|
81
|
+
|
82
|
+
def put_blob(payload, uri)
|
83
|
+
begin
|
84
|
+
path = get_blob_path uri
|
85
|
+
dir = File.dirname path
|
86
|
+
FileUtils.mkdir_p dir unless File.directory? dir
|
87
|
+
IO.binwrite path, payload
|
88
|
+
OperationResult.new(true, "OK", uri, 204)
|
89
|
+
rescue StandardError => e
|
90
|
+
OperationResult.new(false, e.message, nil, 400)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def update_blob(payload, uri)
|
95
|
+
exist = exist_blob uri
|
96
|
+
if exist
|
97
|
+
put_blob payload, uri
|
98
|
+
else
|
99
|
+
OperationResult.new(false, "Blob does not exist", nil, 404)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def delete_blob_if_exist(uri)
|
104
|
+
begin
|
105
|
+
path = get_blob_path uri
|
106
|
+
FileUtils.rm_f path if exist_blob uri
|
107
|
+
OperationResult.new(true, "Deleted", nil, 204)
|
108
|
+
rescue StandardError => e
|
109
|
+
OperationResult.new(false, e.message, nil, 400)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def delete_blob(uri)
|
114
|
+
exist = exist_blob uri
|
115
|
+
if exist
|
116
|
+
delete_blob_if_exist uri
|
117
|
+
else
|
118
|
+
OperationResult.new(false, "Bucket does not exist", nil, 404)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
private
|
123
|
+
|
124
|
+
def get_blob_path(uri)
|
125
|
+
data = break_uri uri
|
126
|
+
blob_dir data[:bucket], data[:blob]
|
127
|
+
end
|
128
|
+
|
129
|
+
def break_uri(uri)
|
130
|
+
url = Addressable::URI.parse uri
|
131
|
+
path = ("/" + url.path).split(principal).drop(1).join(principal)
|
132
|
+
arr = path.split "/"
|
133
|
+
{:bucket => arr[0], :blob => arr.drop(1).join("/")}
|
134
|
+
end
|
135
|
+
|
136
|
+
def bucket_dir(key)
|
137
|
+
combine(@path, key)
|
138
|
+
end
|
139
|
+
|
140
|
+
def blob_dir(bucket, key)
|
141
|
+
combine(@path, bucket, key)
|
142
|
+
end
|
143
|
+
|
144
|
+
def combine(*args)
|
145
|
+
Pathname.new(File.join(args)).cleanpath.to_s
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
class DigitalOceanACLFactory
|
2
|
+
def generate_acl(access, owner_id)
|
3
|
+
if access === :public
|
4
|
+
"<AccessControlPolicy xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\">
|
5
|
+
<Owner>
|
6
|
+
<ID>#{owner_id}</ID>
|
7
|
+
</Owner>
|
8
|
+
<AccessControlList>
|
9
|
+
<Grant>
|
10
|
+
<Grantee xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"CanonicalUser\">
|
11
|
+
<ID>#{owner_id}</ID>
|
12
|
+
</Grantee>
|
13
|
+
<Permission>FULL_CONTROL</Permission>
|
14
|
+
</Grant>
|
15
|
+
<Grant>
|
16
|
+
<Grantee xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"Group\">
|
17
|
+
<URI>http://acs.amazonaws.com/groups/global/AllUsers</URI>
|
18
|
+
</Grantee>
|
19
|
+
<Permission>READ</Permission>
|
20
|
+
</Grant>
|
21
|
+
</AccessControlList>
|
22
|
+
</AccessControlPolicy>"
|
23
|
+
else
|
24
|
+
"<AccessControlPolicy xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\">
|
25
|
+
<Owner>
|
26
|
+
<ID>#{owner_id}</ID>
|
27
|
+
</Owner>
|
28
|
+
<AccessControlList>
|
29
|
+
<Grant>
|
30
|
+
<Grantee xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"CanonicalUser\">
|
31
|
+
<ID>#{owner_id}</ID>
|
32
|
+
</Grantee>
|
33
|
+
<Permission>FULL_CONTROL</Permission>
|
34
|
+
</Grant>
|
35
|
+
</AccessControlList>
|
36
|
+
</AccessControlPolicy>"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module BucketClient
|
2
|
+
class DigitalOceanBucket < Bucket
|
3
|
+
attr_reader :key
|
4
|
+
# @param [String] region the region of the bucket
|
5
|
+
# @param [DigitalOceanHttpClient] http the Digital Ocean http client
|
6
|
+
# @param [DigitalOceanClient] client the parent client
|
7
|
+
# @param [String] key the key of this bucket
|
8
|
+
def initialize(region, http, client, key)
|
9
|
+
@region = region
|
10
|
+
@http = http
|
11
|
+
@bucket_client = client
|
12
|
+
@key = key
|
13
|
+
end
|
14
|
+
|
15
|
+
def get_uri(key)
|
16
|
+
"https://#{@region}.digitaloceanspaces.com/#{@key}/#{key}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def get_blob_with_uri(uri)
|
20
|
+
@bucket_client.get_blob uri
|
21
|
+
end
|
22
|
+
|
23
|
+
def exist_blob_with_uri(uri)
|
24
|
+
@bucket_client.exist_blob(uri)
|
25
|
+
end
|
26
|
+
|
27
|
+
def put_blob_with_uri(payload, uri)
|
28
|
+
@bucket_client.put_blob payload, uri
|
29
|
+
end
|
30
|
+
|
31
|
+
def update_blob_with_uri(payload, uri)
|
32
|
+
exist = exist_blob_with_uri uri
|
33
|
+
if exist
|
34
|
+
put_blob_with_uri payload, uri
|
35
|
+
else
|
36
|
+
OperationResult.new false, "Blob does not exist", nil, 400
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def delete_blob_with_uri(uri)
|
41
|
+
@bucket_client.delete_blob(uri)
|
42
|
+
end
|
43
|
+
|
44
|
+
def delete_blob_if_exist_with_uri(uri)
|
45
|
+
@bucket_client.delete_blob_if_exist(uri)
|
46
|
+
end
|
47
|
+
|
48
|
+
def get_blob(key)
|
49
|
+
get_blob_with_uri(get_uri key)
|
50
|
+
end
|
51
|
+
|
52
|
+
def exist_blob(key)
|
53
|
+
exist_blob_with_uri(get_uri key)
|
54
|
+
end
|
55
|
+
|
56
|
+
def put_blob(payload, key)
|
57
|
+
put_blob_with_uri(payload, get_uri(key))
|
58
|
+
end
|
59
|
+
|
60
|
+
def create_blob(payload, key)
|
61
|
+
exist = exist_blob key
|
62
|
+
if exist
|
63
|
+
OperationResult.new false, "Blob already exist", nil, 400
|
64
|
+
else
|
65
|
+
put_blob payload, key
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def update_blob(payload, key)
|
70
|
+
update_blob_with_uri(payload, get_uri(key))
|
71
|
+
end
|
72
|
+
|
73
|
+
def delete_blob(key)
|
74
|
+
delete_blob_with_uri(get_uri key)
|
75
|
+
end
|
76
|
+
|
77
|
+
def delete_blob_if_exist(key)
|
78
|
+
delete_blob_if_exist_with_uri(get_uri key)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,275 @@
|
|
1
|
+
require "bucket_client/client"
|
2
|
+
require "bucket_client/aws4_request_signer"
|
3
|
+
require "bucket_client/operation_result"
|
4
|
+
require "json"
|
5
|
+
require "mimemagic"
|
6
|
+
require "bucket_client/digital_ocean/digital_ocean_http_client"
|
7
|
+
require "bucket_client/digital_ocean/digital_ocean_bucket"
|
8
|
+
require "bucket_client/digital_ocean/digital_ocean_acl_factory"
|
9
|
+
require "addressable/uri"
|
10
|
+
require "ox"
|
11
|
+
|
12
|
+
module ArrayHash
|
13
|
+
def access(symbol)
|
14
|
+
raise ArgumentError "Cannot find symbol #{symbol.to_s}" unless has_key symbol
|
15
|
+
r = find {|x| !x[symbol].nil?}[symbol]
|
16
|
+
r.extend(ArrayHash)
|
17
|
+
r
|
18
|
+
end
|
19
|
+
|
20
|
+
def get(symbol)
|
21
|
+
raise ArgumentError "Cannot find symbol #{symbol.to_s}" if self[symbol].nil?
|
22
|
+
r = self[symbol]
|
23
|
+
r.extend(ArrayHash)
|
24
|
+
r
|
25
|
+
end
|
26
|
+
|
27
|
+
def has_key(symbol)
|
28
|
+
self.any? {|x| !x[symbol].nil?}
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
module BucketClient
|
33
|
+
class DigitalOceanClient < Client
|
34
|
+
# @param [KirinHttp::Client] client Basic http client
|
35
|
+
# @param [String] id AWS id
|
36
|
+
# @param [String] secret AWS secret
|
37
|
+
# @param [String] region Region for bucket
|
38
|
+
def initialize(client, id, secret, region)
|
39
|
+
signer = AWS4RequestSigner.new(id, secret)
|
40
|
+
@region = region
|
41
|
+
@http = DigitalOceanHttpClient.new(signer, region, client)
|
42
|
+
@acl_factory = DigitalOceanACLFactory.new
|
43
|
+
end
|
44
|
+
|
45
|
+
def exist_bucket(key)
|
46
|
+
resp = @http.query(:head, "https://#{@region}.digitaloceanspaces.com/#{key}")
|
47
|
+
resp.code == 200
|
48
|
+
end
|
49
|
+
|
50
|
+
def put_bucket(key)
|
51
|
+
exist = exist_bucket key
|
52
|
+
if exist
|
53
|
+
bucket = get_bucket! key
|
54
|
+
OperationResult.new(true, "OK", bucket, 200)
|
55
|
+
else
|
56
|
+
create_bucket key
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def create_bucket(key)
|
61
|
+
endpoint = "https://#{@region}.digitaloceanspaces.com/#{key}"
|
62
|
+
resp = @http.query(:put, endpoint)
|
63
|
+
success = resp.code === 200
|
64
|
+
if success
|
65
|
+
bucket = get_bucket! key
|
66
|
+
OperationResult.new(success, "Bucket created", bucket, 200)
|
67
|
+
else
|
68
|
+
OperationResult.new(success, resp.content, nil, resp.code)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def delete_bucket_if_exist(key)
|
73
|
+
exist = exist_bucket key
|
74
|
+
if exist
|
75
|
+
delete_bucket key
|
76
|
+
else
|
77
|
+
OperationResult.new(true, "Bucket already deleted", nil, 204)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def delete_bucket(key)
|
82
|
+
endpoint = "https://#{@region}.digitaloceanspaces.com/#{key}"
|
83
|
+
resp = @http.query(:delete, endpoint)
|
84
|
+
success = resp.code === 204
|
85
|
+
if success
|
86
|
+
OperationResult.new(success, "Bucket deleted", nil, resp.code)
|
87
|
+
else
|
88
|
+
OperationResult.new(success, resp.content, nil, resp.code)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def get_bucket!(key)
|
93
|
+
DigitalOceanBucket.new(@region, @http, self, key)
|
94
|
+
end
|
95
|
+
|
96
|
+
def set_get_cors(key, cors)
|
97
|
+
resp = set_cors key, cors, 10
|
98
|
+
OperationResult.new(resp.code === 200, resp.content, nil, resp.code)
|
99
|
+
end
|
100
|
+
|
101
|
+
def set_read_policy(key, access)
|
102
|
+
raise ArgumentError.new("Read Policy not accepted") if access != :public && access != :private
|
103
|
+
resp = set_bucket_acl key, access, 10
|
104
|
+
return resp unless resp.success
|
105
|
+
object_uri_resp = get_all_object_uri key
|
106
|
+
return object_uri_resp unless object_uri_resp.success
|
107
|
+
object_uri_resp.value.each do |uri|
|
108
|
+
acl_resp = set_blob_acl uri, access, 10
|
109
|
+
return acl_resp unless acl_resp.success
|
110
|
+
end
|
111
|
+
resp
|
112
|
+
end
|
113
|
+
|
114
|
+
def get_blob(uri)
|
115
|
+
resp = @http.query :get, uri
|
116
|
+
success = resp.code === 200
|
117
|
+
if success
|
118
|
+
OperationResult.new(success, "OK", resp.content, resp.code)
|
119
|
+
else
|
120
|
+
OperationResult.new(success, resp.content, nil, resp.code)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def exist_blob(uri)
|
125
|
+
@http.query(:head, uri).code === 200
|
126
|
+
end
|
127
|
+
|
128
|
+
def put_blob(payload, uri)
|
129
|
+
mime = MimeMagic.by_magic payload
|
130
|
+
resp = @http.query :put, uri, payload, mime.type, "application/xml"
|
131
|
+
return OperationResult.new(false, resp.content, nil, 400) unless resp.code === 200
|
132
|
+
url = Addressable::URI.parse uri
|
133
|
+
bucket = url.path.split("/").find {|x| !x.nil? && !x.empty?}
|
134
|
+
domain = url.host.split(".").first
|
135
|
+
bucket = domain unless domain == @region
|
136
|
+
is_public = bucket_public bucket
|
137
|
+
return is_public unless is_public.success
|
138
|
+
access = is_public.value ? :public : :private
|
139
|
+
resp = set_blob_acl uri, access, 10
|
140
|
+
return resp unless resp.code === 200
|
141
|
+
OperationResult.new(true, "OK", uri, resp.code)
|
142
|
+
end
|
143
|
+
|
144
|
+
def update_blob(payload, uri)
|
145
|
+
exist = exist_blob uri
|
146
|
+
if exist
|
147
|
+
put_blob payload, uri
|
148
|
+
else
|
149
|
+
OperationResult.new(false, "Blob does not exist", nil, 404)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def delete_blob_if_exist(uri)
|
154
|
+
resp = @http.query :delete, uri
|
155
|
+
success = resp.code === 204
|
156
|
+
if success
|
157
|
+
OperationResult.new(success, "Blob deleted", nil, resp.code)
|
158
|
+
else
|
159
|
+
OperationResult.new(success, resp.content, nil, resp.code)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def delete_blob(uri)
|
164
|
+
exist = exist_blob uri
|
165
|
+
if exist
|
166
|
+
delete_blob_if_exist uri
|
167
|
+
else
|
168
|
+
OperationResult.new(false, "Blob does not exist", nil, 404)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
private
|
173
|
+
|
174
|
+
def bucket_public(key)
|
175
|
+
endpoint = "https://#{@region}.digitaloceanspaces.com/#{key}/?acl="
|
176
|
+
resp = @http.query :get, endpoint
|
177
|
+
success = resp.code === 200
|
178
|
+
if success
|
179
|
+
acl_xml = Ox.load(resp.content, mode: :hash)[:AccessControlPolicy]
|
180
|
+
acl_xml.extend(ArrayHash)
|
181
|
+
begin
|
182
|
+
uri = acl_xml.access(:AccessControlList).get(:Grant).access(:Grantee).access(:URI)
|
183
|
+
value = uri === "http://acs.amazonaws.com/groups/global/AllUsers"
|
184
|
+
rescue
|
185
|
+
value = false
|
186
|
+
end
|
187
|
+
OperationResult.new(success, "OK", value, 200)
|
188
|
+
else
|
189
|
+
OperationResult.new(success, resp.content, nil, resp.code)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
def set_cors(key, cors, max, count = 0)
|
194
|
+
failure = "Failed too many times due to conflict"
|
195
|
+
return OperationResult.new(false, failure, nil, 400) if ++count === max
|
196
|
+
endpoint = "https://#{@region}.digitaloceanspaces.com/#{key}/?cors="
|
197
|
+
if cors.length > 0
|
198
|
+
xml = cors_xml cors
|
199
|
+
resp = @http.query :put, endpoint, xml
|
200
|
+
else
|
201
|
+
resp = @http.query :delete, endpoint, nil, "text/plain"
|
202
|
+
end
|
203
|
+
if resp.code === 409
|
204
|
+
set_cors key, cors, max, count
|
205
|
+
else
|
206
|
+
resp
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
def cors_xml(cors)
|
211
|
+
rules = cors.map(&method(:cors_rule))
|
212
|
+
"<CORSConfiguration>#{rules.join "\n"}</CORSConfiguration>"
|
213
|
+
end
|
214
|
+
|
215
|
+
def cors_rule(cors)
|
216
|
+
"<CORSRule>
|
217
|
+
<AllowedOrigin>#{cors}</AllowedOrigin>
|
218
|
+
<AllowedMethod>GET</AllowedMethod>
|
219
|
+
<AllowedHeader>*</AllowedHeader>
|
220
|
+
<MaxAgeSeconds>3000</MaxAgeSeconds>
|
221
|
+
</CORSRule>"
|
222
|
+
end
|
223
|
+
|
224
|
+
def get_all_object_uri(key)
|
225
|
+
endpoint = "https://#{@region}.digitaloceanspaces.com/#{key}/"
|
226
|
+
resp = @http.query :get, endpoint
|
227
|
+
if resp.code === 200
|
228
|
+
value = Ox.load(resp.content, mode: :hash)[:ListBucketResult]
|
229
|
+
.select {|k| !k[:Contents].nil?}
|
230
|
+
.map {|k| endpoint + k[:Contents][:Key]}
|
231
|
+
OperationResult.new(true, "OK", value, resp.code)
|
232
|
+
else
|
233
|
+
OperationResult.new(false, resp.content, nil, resp.code)
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
def set_blob_acl(uri, access, max, count = 0)
|
238
|
+
endpoint = uri + "?acl="
|
239
|
+
set_acl endpoint, access, max, count
|
240
|
+
end
|
241
|
+
|
242
|
+
def set_bucket_acl(key, access, max, count = 0)
|
243
|
+
endpoint = "https://#{@region}.digitaloceanspaces.com/#{key}/?acl="
|
244
|
+
set_acl endpoint, access, max, count
|
245
|
+
end
|
246
|
+
|
247
|
+
def set_acl(endpoint, access, max, count)
|
248
|
+
error = "Failed too many times due to conflict"
|
249
|
+
return OperationResult.new(false, error, nil, 400) if ++count === max
|
250
|
+
acl = @http.query :get, endpoint
|
251
|
+
return OperationResult.new(false, acl.content, nil, acl.code) if acl.code != 200
|
252
|
+
acl_xml = Ox.load(acl.content, mode: :hash)
|
253
|
+
return OperationResult.new(false, "ACL XML Malformed? Check value for XML", acl_xml, 400) if acl_malformed acl_xml
|
254
|
+
owner_id = acl_owner acl_xml
|
255
|
+
new_xml = @acl_factory.generate_acl access, owner_id
|
256
|
+
resp = @http.query :put, endpoint, new_xml
|
257
|
+
if resp.code === 409
|
258
|
+
set_blob_acl uri, access, max, count
|
259
|
+
else
|
260
|
+
OperationResult.new resp.code === 200, resp.content, nil, resp.code
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
def acl_malformed(acl_xml)
|
265
|
+
policy = acl_xml[:AccessControlPolicy]
|
266
|
+
policy.nil? || policy.select {|k| !k[:Owner].nil?}.length == 0
|
267
|
+
end
|
268
|
+
|
269
|
+
def acl_owner(acl_xml)
|
270
|
+
acl_xml[:AccessControlPolicy].select {|k| !k[:Owner].nil?}.first[:Owner][:ID]
|
271
|
+
end
|
272
|
+
|
273
|
+
|
274
|
+
end
|
275
|
+
end
|