cloudflare 3.1.0 → 3.2.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 +5 -5
- data/.rubocop.yml +19 -0
- data/.ruby-version +1 -0
- data/.travis.yml +7 -3
- data/README.md +8 -0
- data/Rakefile +15 -13
- data/cloudflare.gemspec +12 -10
- data/lib/cloudflare.rb +5 -3
- data/lib/cloudflare/connection.rb +45 -41
- data/lib/cloudflare/response.rb +42 -42
- data/lib/cloudflare/rspec/connection.rb +14 -12
- data/lib/cloudflare/user.rb +9 -7
- data/lib/cloudflare/version.rb +3 -1
- data/lib/cloudflare/zone.rb +176 -163
- data/spec/cloudflare/zone_spec.rb +125 -91
- data/spec/fake_cloudflare/cloudflare.rb +17 -0
- data/spec/spec_helper.rb +171 -24
- metadata +24 -20
@@ -1,92 +1,126 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# rubocop:disable Metrics/BlockLength
|
4
|
+
RSpec.describe 'Cloudflare DNS Zones' do
|
5
|
+
include_context Cloudflare::RSpec::Connection
|
6
|
+
|
7
|
+
before(:each) { stub_get_zones }
|
8
|
+
it 'should list zones' do
|
9
|
+
zones = connection.zones.all
|
10
|
+
expect(zones).to be_any
|
11
|
+
end
|
12
|
+
|
13
|
+
describe Cloudflare::Zone, order: :defined do
|
14
|
+
before(:each) do
|
15
|
+
stub_get_zones
|
16
|
+
stub_purge_cache
|
17
|
+
end
|
18
|
+
|
19
|
+
let(:zone) { connection.zones.all.first }
|
20
|
+
|
21
|
+
describe '#purge_cache' do
|
22
|
+
it 'should purge cache' do
|
23
|
+
expect(zone.purge_cache).to eq(true)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe Cloudflare::DNSRecords, order: :defined do
|
29
|
+
before(:each) do
|
30
|
+
stub_get_zones
|
31
|
+
stub_get_dns_records
|
32
|
+
stub_create_dns_record
|
33
|
+
stub_delete_dns_record '123123123'
|
34
|
+
stub_find_dns_record_by_id '123123123'
|
35
|
+
end
|
36
|
+
let(:zone) { connection.zones.all.first }
|
37
|
+
|
38
|
+
let(:name) { 'test' }
|
39
|
+
let(:ip) { '123.123.123.123' }
|
40
|
+
|
41
|
+
it 'should get all records' do
|
42
|
+
result = zone.dns_records.all
|
43
|
+
expect(result.size).to be > 0
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should create dns record' do
|
47
|
+
response = zone.dns_records.post({
|
48
|
+
type: 'A',
|
49
|
+
name: name,
|
50
|
+
content: ip,
|
51
|
+
ttl: 240,
|
52
|
+
proxied: false
|
53
|
+
}.to_json, content_type: 'application/json')
|
54
|
+
|
55
|
+
expect(response).to be_successful
|
56
|
+
|
57
|
+
result = response.result
|
58
|
+
expect(result).to include(:id, :type, :name, :content, :ttl)
|
59
|
+
end
|
60
|
+
|
61
|
+
before do
|
62
|
+
stub_get_dns_record '1231231234'
|
63
|
+
stub_delete_dns_record '1231231234'
|
64
|
+
end
|
65
|
+
it 'should delete dns record' do
|
66
|
+
dns_record = zone.dns_records.find_by_id('1231231234')
|
67
|
+
response = dns_record.delete
|
68
|
+
expect(response).to be_successful
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe Cloudflare::FirewallRules, order: :defined do
|
73
|
+
let(:zone) { connection.zones.all.first }
|
74
|
+
let(:name) { 'test' }
|
75
|
+
let(:ip) { '123.123.123.123' }
|
76
|
+
let(:ip2) { '123.123.123.124' }
|
77
|
+
let(:notes) { 'gemtest' }
|
78
|
+
before do
|
79
|
+
stub_get_zones
|
80
|
+
stub_create_rule 'block', ip2, notes
|
81
|
+
stub_list_access_rules 1, [cf_access_rule('whitelist', ip, notes)]
|
82
|
+
stub_list_access_rules 2, [cf_access_rule('block', ip2, notes)]
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'should get all rules' do
|
86
|
+
result = zone.firewall_rules.all
|
87
|
+
|
88
|
+
puts "===> #{result.size} records returned"
|
89
|
+
expect(result.size).to be > 0
|
90
|
+
end
|
91
|
+
|
92
|
+
%i[block challenge whitelist].each do |mode|
|
93
|
+
it "should create a #{mode} rule" do
|
94
|
+
stub_create_rule mode, ip, notes
|
95
|
+
response = zone.firewall_rules.set(mode, ip, notes)
|
96
|
+
|
97
|
+
expect(response).to be_successful
|
98
|
+
|
99
|
+
result = response.result
|
100
|
+
expect(result).to include(:id, :mode, :notes, :configuration)
|
101
|
+
expect(result[:mode]).to eq mode.to_s
|
102
|
+
end
|
103
|
+
end
|
104
|
+
before do
|
105
|
+
stub_get_access_rule('123123123')
|
106
|
+
stub_delete_access_rule(id: '123123123')
|
107
|
+
end
|
108
|
+
it 'should delete firewall rule by record' do
|
109
|
+
response = zone.firewall_rules.unset('id', '123123123')
|
110
|
+
assert_requested stub_get_access_rule('123123123')
|
111
|
+
assert_requested stub_delete_access_rule(id: '123123123')
|
112
|
+
expect(response).to be_successful
|
113
|
+
end
|
114
|
+
|
115
|
+
before do
|
116
|
+
stub_find_rule_by_value ip: ip2
|
117
|
+
stub_get_access_rule '123123124'
|
118
|
+
stub_delete_access_rule id: '123123124'
|
119
|
+
end
|
120
|
+
it 'should delete firewall rule by ip' do
|
121
|
+
response = zone.firewall_rules.unset('ip', ip2)
|
122
|
+
expect(response).to be_successful
|
123
|
+
end
|
124
|
+
end
|
92
125
|
end
|
126
|
+
# rubocop:enable Metrics/BlockLength
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'sinatra/base'
|
4
|
+
|
5
|
+
class FakeCloudFlare < Sinatra::Base
|
6
|
+
get '/zones/:id/dns_records/?page=1&per_page=50&scope_type=organization' do
|
7
|
+
json_response 200, 'get_all_zones.json'
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def json_response(response_code, file_name)
|
13
|
+
content_type :json
|
14
|
+
status response_code
|
15
|
+
File.open(File.dirname(__FILE__) + '/fixtures/' + file_name, 'rb').read
|
16
|
+
end
|
17
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,30 +1,177 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
|
2
3
|
if ENV['COVERAGE'] || ENV['TRAVIS']
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
require
|
20
|
-
|
21
|
-
|
4
|
+
begin
|
5
|
+
require 'simplecov'
|
6
|
+
|
7
|
+
SimpleCov.start do
|
8
|
+
add_filter '/spec/'
|
9
|
+
end
|
10
|
+
rescue LoadError
|
11
|
+
warn "Could not load simplecov: #{$ERROR_INFO}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
require 'webmock/rspec'
|
16
|
+
WebMock.disable_net_connect!(allow_localhost: true)
|
17
|
+
|
18
|
+
require 'bundler/setup'
|
19
|
+
require 'cloudflare'
|
20
|
+
require 'cloudflare/rspec/connection'
|
21
|
+
|
22
|
+
def base_url
|
23
|
+
%(https://api.cloudflare.com/client/v4)
|
24
|
+
end
|
25
|
+
|
26
|
+
def zone_id
|
27
|
+
'1337z0n31d3n71f13r'
|
28
|
+
end
|
29
|
+
|
30
|
+
def stub_get_zones
|
31
|
+
stub_request(:get, "#{base_url}/zones/?page=1&per_page=50&scope_type=organization")
|
32
|
+
.with(cf_headers)
|
33
|
+
.to_return(status: 200, body: cf_results([{
|
34
|
+
name: 'example.com',
|
35
|
+
ip: '123.123.123.123',
|
36
|
+
id: zone_id
|
37
|
+
}]),
|
38
|
+
headers: {})
|
39
|
+
end
|
40
|
+
|
41
|
+
def stub_get_dns_records
|
42
|
+
dns_record = {
|
43
|
+
"id": 'b12a037696862c2fc1d45a0e288c82a5',
|
44
|
+
"type": 'A',
|
45
|
+
"name": 'www.example.com',
|
46
|
+
"content": '123.123.123.123',
|
47
|
+
"ttl": 1,
|
48
|
+
"zone_id": zone_id,
|
49
|
+
"zone_name": 'example.com'
|
50
|
+
}
|
51
|
+
stub_request(:get, "#{base_url}/zones/#{zone_id}/dns_records/?page=1&per_page=50&scope_type=organization")
|
52
|
+
.with(cf_headers)
|
53
|
+
.to_return(status: 200,
|
54
|
+
body: cf_results([dns_record]),
|
55
|
+
headers: {})
|
56
|
+
end
|
57
|
+
|
58
|
+
def stub_create_dns_record
|
59
|
+
stub_request(:post, "#{base_url}/zones/#{zone_id}/dns_records")
|
60
|
+
.with(cf_headers('Content-Type': 'application/json'))
|
61
|
+
.with(
|
62
|
+
body: hash_including(:type, :name, :content, :ttl, :proxied)
|
63
|
+
)
|
64
|
+
.to_return(status: 200,
|
65
|
+
body: cf_results(id: '123231123', type: 'A', name: 'test', content: '123.123.123.123', ttl: 240),
|
66
|
+
headers: {})
|
67
|
+
end
|
68
|
+
|
69
|
+
def stub_find_dns_record_by_id(id)
|
70
|
+
stub_request(:get, "#{base_url}/zones/#{zone_id}/dns_records")
|
71
|
+
.with(query: {id: id})
|
72
|
+
.with(cf_headers)
|
73
|
+
.to_return(status: 200,
|
74
|
+
body: cf_results(
|
75
|
+
id: '123231123',
|
76
|
+
type: 'A',
|
77
|
+
name: 'test',
|
78
|
+
content: '123.123.123.123',
|
79
|
+
ttl: 240
|
80
|
+
),
|
81
|
+
headers: {})
|
82
|
+
end
|
83
|
+
|
84
|
+
def stub_get_dns_record(id)
|
85
|
+
stub_request(:get, "#{base_url}/zones/#{zone_id}/dns_records/#{id}")
|
86
|
+
.with(cf_headers)
|
87
|
+
.to_return(status: 200,
|
88
|
+
body: cf_results(
|
89
|
+
id: '123231123',
|
90
|
+
type: 'A',
|
91
|
+
name: 'test',
|
92
|
+
content: '123.123.123.123',
|
93
|
+
ttl: 240
|
94
|
+
),
|
95
|
+
headers: {})
|
96
|
+
end
|
97
|
+
|
98
|
+
def stub_delete_dns_record(id)
|
99
|
+
stub_request(:delete, "#{base_url}/zones/#{zone_id}/dns_records/#{id}")
|
100
|
+
.with(cf_headers)
|
101
|
+
.to_return(status: 200, body: cf_results(id: id), headers: {})
|
102
|
+
end
|
103
|
+
|
104
|
+
def stub_find_rule_by_value(ip:)
|
105
|
+
stub_request(:get, "#{base_url}/zones/#{zone_id}/firewall/access_rules/rules/?configuration_value=#{ip}")
|
106
|
+
.with(cf_headers)
|
107
|
+
.to_return(status: 200,
|
108
|
+
body: cf_results([cf_access_rule('block', '123.123.123.124', 'gemtest')]),
|
109
|
+
headers: {})
|
110
|
+
end
|
111
|
+
|
112
|
+
def stub_list_access_rules(page, rules)
|
113
|
+
query = URI.encode_www_form(page: page, per_page: 50, scope_type: :organization)
|
114
|
+
stub_request(:get, "#{base_url}/zones/#{zone_id}/firewall/access_rules/rules/?#{query}")
|
115
|
+
.with(cf_headers)
|
116
|
+
.to_return(status: 200, body: cf_results(rules), headers: {})
|
117
|
+
end
|
118
|
+
|
119
|
+
def stub_get_access_rule(id)
|
120
|
+
stub_request(:get, "#{base_url}/zones/#{zone_id}/firewall/access_rules/rules/#{id}")
|
121
|
+
.with(cf_headers)
|
122
|
+
.to_return(status: 200,
|
123
|
+
body: cf_results(cf_access_rule('whitelist', '123.123.123.124', 'gemtest', id)),
|
124
|
+
headers: {})
|
125
|
+
end
|
126
|
+
|
127
|
+
def stub_delete_access_rule(id: nil)
|
128
|
+
stub_request(:delete, "#{base_url}/zones/#{zone_id}/firewall/access_rules/rules/#{id}")
|
129
|
+
.with(cf_headers)
|
130
|
+
.to_return(status: 200, body: cf_results(id: id), headers: {})
|
131
|
+
end
|
132
|
+
|
133
|
+
def stub_create_rule(mode, ip, note)
|
134
|
+
notes = "cloudflare gem firewall_rules [#{mode}] #{note} #{Time.now.strftime('%m/%d/%y')}"
|
135
|
+
body = "{\"mode\":\"#{mode}\",\"configuration\":{\"target\":\"ip\",\"value\":\"#{ip}\",\"notes\":\"#{notes}\"}}"
|
136
|
+
stub_request(:post, "https://api.cloudflare.com/client/v4/zones/#{zone_id}/firewall/access_rules/rules")
|
137
|
+
.with(cf_headers(
|
138
|
+
'Content-Length' => body.bytesize,
|
139
|
+
'Content-Type' => 'application/json'
|
140
|
+
))
|
141
|
+
.with(body: body)
|
142
|
+
.to_return(status: 200, body: cf_results(cf_access_rule(mode, ip, notes)), headers: {})
|
143
|
+
end
|
144
|
+
|
145
|
+
def stub_purge_cache
|
146
|
+
stub_request(:post, "#{base_url}/zones/#{zone_id}/purge_cache")
|
147
|
+
.with(cf_headers)
|
148
|
+
.to_return(status: 200, body: cf_results(id: zone_id), headers: {})
|
149
|
+
end
|
22
150
|
|
23
151
|
RSpec.configure do |config|
|
24
|
-
|
25
|
-
|
152
|
+
# Enable flags like --only-failures and --next-failure
|
153
|
+
config.example_status_persistence_file_path = '.rspec_status'
|
154
|
+
|
155
|
+
config.expect_with :rspec do |c|
|
156
|
+
c.syntax = :expect
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def cf_results(result, messages = [], errors = [])
|
161
|
+
{result: result, success: true, messages: messages, errors: errors}.to_json
|
162
|
+
end
|
163
|
+
|
164
|
+
def cf_headers(extra = {})
|
165
|
+
{headers: {
|
166
|
+
'Accept' => '*/*',
|
167
|
+
'Accept-Encoding' => 'gzip, deflate',
|
168
|
+
'Host' => 'api.cloudflare.com',
|
169
|
+
'X-Auth-Email' => 'jake@example.net',
|
170
|
+
'X-Auth-Key' => '5up3rS3cr3tAuthK3y',
|
171
|
+
'X-Auth-User-Service-Key' => ''
|
172
|
+
}.merge(extra)}
|
173
|
+
end
|
26
174
|
|
27
|
-
|
28
|
-
|
29
|
-
end
|
175
|
+
def cf_access_rule(mode, ip, note, id = '12312312' + ip.slice(-1))
|
176
|
+
{id: id, mode: mode, notes: note, configuration: {}}
|
30
177
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cloudflare
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Marcin Prokop
|
@@ -9,36 +9,22 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2018-06-07 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rest-client
|
16
|
-
requirement: !ruby/object:Gem::Requirement
|
17
|
-
requirements:
|
18
|
-
- - ">="
|
19
|
-
- !ruby/object:Gem::Version
|
20
|
-
version: '0'
|
21
|
-
type: :runtime
|
22
|
-
prerelease: false
|
23
|
-
version_requirements: !ruby/object:Gem::Requirement
|
24
|
-
requirements:
|
25
|
-
- - ">="
|
26
|
-
- !ruby/object:Gem::Version
|
27
|
-
version: '0'
|
28
|
-
- !ruby/object:Gem::Dependency
|
29
|
-
name: rspec
|
30
16
|
requirement: !ruby/object:Gem::Requirement
|
31
17
|
requirements:
|
32
18
|
- - "~>"
|
33
19
|
- !ruby/object:Gem::Version
|
34
|
-
version:
|
35
|
-
type: :
|
20
|
+
version: 2.0.2
|
21
|
+
type: :runtime
|
36
22
|
prerelease: false
|
37
23
|
version_requirements: !ruby/object:Gem::Requirement
|
38
24
|
requirements:
|
39
25
|
- - "~>"
|
40
26
|
- !ruby/object:Gem::Version
|
41
|
-
version:
|
27
|
+
version: 2.0.2
|
42
28
|
- !ruby/object:Gem::Dependency
|
43
29
|
name: bundler
|
44
30
|
requirement: !ruby/object:Gem::Requirement
|
@@ -67,6 +53,20 @@ dependencies:
|
|
67
53
|
- - ">="
|
68
54
|
- !ruby/object:Gem::Version
|
69
55
|
version: '0'
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: rspec
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - "~>"
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '3.6'
|
63
|
+
type: :development
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - "~>"
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '3.6'
|
70
70
|
description:
|
71
71
|
email:
|
72
72
|
- marcin@prokop.co
|
@@ -77,6 +77,8 @@ extra_rdoc_files: []
|
|
77
77
|
files:
|
78
78
|
- ".gitignore"
|
79
79
|
- ".rspec"
|
80
|
+
- ".rubocop.yml"
|
81
|
+
- ".ruby-version"
|
80
82
|
- ".travis.yml"
|
81
83
|
- Gemfile
|
82
84
|
- README.md
|
@@ -90,6 +92,7 @@ files:
|
|
90
92
|
- lib/cloudflare/version.rb
|
91
93
|
- lib/cloudflare/zone.rb
|
92
94
|
- spec/cloudflare/zone_spec.rb
|
95
|
+
- spec/fake_cloudflare/cloudflare.rb
|
93
96
|
- spec/spec_helper.rb
|
94
97
|
homepage: https://github.com/b4k3r/cloudflare
|
95
98
|
licenses:
|
@@ -111,10 +114,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
111
114
|
version: '0'
|
112
115
|
requirements: []
|
113
116
|
rubyforge_project:
|
114
|
-
rubygems_version: 2.6
|
117
|
+
rubygems_version: 2.7.6
|
115
118
|
signing_key:
|
116
119
|
specification_version: 4
|
117
120
|
summary: A Ruby wrapper for the Cloudflare API.
|
118
121
|
test_files:
|
119
122
|
- spec/cloudflare/zone_spec.rb
|
123
|
+
- spec/fake_cloudflare/cloudflare.rb
|
120
124
|
- spec/spec_helper.rb
|