cloudflare 3.2.1 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +14 -16
- data/README.md +9 -9
- data/Rakefile +10 -8
- data/cloudflare.gemspec +19 -17
- data/lib/cloudflare.rb +20 -5
- data/lib/cloudflare/{response.rb → accounts.rb} +25 -47
- data/lib/cloudflare/connection.rb +31 -52
- data/lib/cloudflare/dns.rb +91 -0
- data/lib/cloudflare/firewall.rb +80 -0
- data/lib/cloudflare/logs.rb +41 -0
- data/lib/cloudflare/paginate.rb +54 -0
- data/lib/cloudflare/representation.rb +94 -0
- data/lib/cloudflare/rspec/connection.rb +18 -11
- data/lib/cloudflare/user.rb +10 -9
- data/lib/cloudflare/version.rb +1 -1
- data/lib/cloudflare/zones.rb +85 -0
- data/spec/cloudflare/dns_spec.rb +32 -0
- data/spec/cloudflare/firewall_spec.rb +48 -0
- data/spec/cloudflare/zone_spec.rb +23 -124
- data/spec/spec_helper.rb +25 -169
- metadata +37 -19
- data/.rubocop.yml +0 -19
- data/.ruby-version +0 -1
- data/lib/cloudflare/zone.rb +0 -202
- data/spec/fake_cloudflare/cloudflare.rb +0 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0bdda4cf1d75b71db4667d63da7382958e2cbebedb052e51adce192bf5db2a81
|
4
|
+
data.tar.gz: ea73942a2251da8f3de0e9a4b46af6a0f877cb1d52b39567ea5aee0c5514aff3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cbe1fe27c1dcbdf5bcf1480c21058e8b2f82d3c43829c606355e864e56390b9f0e128e80af3d6274ce09c45a40548e0a5ce29d1dd70d9ca9bfa707a86982a477
|
7
|
+
data.tar.gz: d1c18b4b98110472759b0e3400f3e22717d91cb1022292a997b21920eca74ceabefa78b830c22231f9338efda14d99ff99e0310b1f33ffbd2f637b0a092b5d21
|
data/.travis.yml
CHANGED
@@ -1,24 +1,22 @@
|
|
1
1
|
language: ruby
|
2
|
-
|
3
|
-
dist: trusty
|
2
|
+
dist: xenial
|
4
3
|
cache: bundler
|
5
4
|
|
6
|
-
before_script:
|
7
|
-
- gem update --system
|
8
|
-
- gem install bundler
|
9
|
-
|
10
|
-
rvm:
|
11
|
-
- 2.2
|
12
|
-
- 2.3
|
13
|
-
- 2.4
|
14
|
-
- 2.5
|
15
|
-
- 2.6
|
16
|
-
- jruby-head
|
17
|
-
- ruby-head
|
18
5
|
matrix:
|
6
|
+
include:
|
7
|
+
- rvm: 2.3
|
8
|
+
- rvm: 2.4
|
9
|
+
- rvm: 2.5
|
10
|
+
- rvm: 2.6
|
11
|
+
- rvm: jruby-head
|
12
|
+
env: JRUBY_OPTS="--debug -X+O"
|
13
|
+
- rvm: truffleruby
|
14
|
+
- rvm: ruby-head
|
19
15
|
allow_failures:
|
20
|
-
|
21
|
-
|
16
|
+
- rvm: ruby-head
|
17
|
+
- rvm: jruby-head
|
18
|
+
- rvm: truffleruby
|
19
|
+
|
22
20
|
env:
|
23
21
|
global:
|
24
22
|
secure: c5yG7N1r9nYuw47Y90jGeoHNvkL59AAC55dtPAhKP+gjXWW8hKbntj3oj+lVkxEqzRpzEQgYZzUElrP+6mJnb20ldclZg03L56243tMtVEcpGOx/MFhnIBkx3kKu1H6ydKKMxieHxjsLQ3vnpcIZ3p0skTQjYbjdu607tjbyg7s=
|
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
It is a Ruby wrapper for the Cloudflare V4 API. It provides a light weight wrapper using `RestClient::Resource`. The wrapper functionality is limited to zones and DNS records at this time, *PRs welcome*.
|
4
4
|
|
5
|
-
[![Build Status](https://secure.travis-ci.org/
|
5
|
+
[![Build Status](https://secure.travis-ci.org/socketry/cloudflare.svg)](http://travis-ci.org/socketry/cloudflare)
|
6
6
|
|
7
7
|
## Installation
|
8
8
|
|
@@ -42,7 +42,7 @@ connection = Cloudflare.connect(key: key, email: email)
|
|
42
42
|
Get all available zones:
|
43
43
|
|
44
44
|
```ruby
|
45
|
-
zones = connection.zones
|
45
|
+
zones = connection.zones
|
46
46
|
```
|
47
47
|
|
48
48
|
Get a specific zone:
|
@@ -55,7 +55,7 @@ zone = connection.zones.find_by_name("example.com")
|
|
55
55
|
Get DNS records for a given zone:
|
56
56
|
|
57
57
|
```ruby
|
58
|
-
dns_records = zones.first.dns_records
|
58
|
+
dns_records = zones.first.dns_records
|
59
59
|
```
|
60
60
|
|
61
61
|
Show some details of the DNS record:
|
@@ -69,14 +69,14 @@ puts records
|
|
69
69
|
Get firewall rules:
|
70
70
|
|
71
71
|
```ruby
|
72
|
-
all_rules =
|
73
|
-
block_rules = zones.first.firewall_rules
|
72
|
+
all_rules = zones.first.firewall_rules
|
73
|
+
block_rules = zones.first.firewall_rules("block") # or "whitelist" or "challenge"
|
74
74
|
```
|
75
75
|
|
76
76
|
Get blocked ips:
|
77
77
|
|
78
78
|
```ruby
|
79
|
-
block_rules = zones.first.firewall_rules
|
79
|
+
block_rules = zones.first.firewall_rules("block")
|
80
80
|
blocked_ips = zones.first.firewall_rules.firewalled_ips(block_rules)
|
81
81
|
```
|
82
82
|
|
@@ -89,7 +89,7 @@ data = {"mode":"block","configuration":{"target":"ip","value":"#{ip}"},"notes":"
|
|
89
89
|
response = zones.first.firewall_rules.post(data.to_json, content_type: 'application/json')
|
90
90
|
```
|
91
91
|
|
92
|
-
Add a DNS record dynamically.
|
92
|
+
Add a DNS record dynamically. Here we add an A record for `batman.example.com`:
|
93
93
|
|
94
94
|
```ruby
|
95
95
|
client = Cloudflare.connect(key: CF_KEY, email: CF_EMAIL)
|
@@ -114,9 +114,9 @@ zone.dns_records.post({"type":"A","name":"batman","content":"127.0.0.1","proxied
|
|
114
114
|
|
115
115
|
Released under the MIT license.
|
116
116
|
|
117
|
-
Copyright,
|
118
|
-
Copyright, 2017, by [Samuel G. D. Williams](http://www.codeotaku.com/samuel-williams).
|
117
|
+
Copyright, 2018, by [Samuel G. D. Williams](http://www.codeotaku.com/samuel-williams).
|
119
118
|
Copyright, 2017, by [David Rosenbloom](http://artifactory.com).
|
119
|
+
Copyright, 2012, 2014, by [Marcin Prokop](https://github.com/b4k3r).
|
120
120
|
|
121
121
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
122
122
|
of this software and associated documentation files (the "Software"), to deal
|
data/Rakefile
CHANGED
@@ -8,17 +8,19 @@ RSpec::Core::RakeTask.new(:test)
|
|
8
8
|
task default: :test
|
9
9
|
|
10
10
|
task :coverage do
|
11
|
-
|
11
|
+
ENV['COVERAGE'] = 'y'
|
12
12
|
end
|
13
13
|
|
14
14
|
task :console do
|
15
|
-
|
16
|
-
|
15
|
+
require_relative 'lib/cloudflare'
|
16
|
+
require 'pry'
|
17
17
|
|
18
|
-
|
19
|
-
|
18
|
+
email = ENV.fetch('CLOUDFLARE_EMAIL')
|
19
|
+
key = ENV.fetch('CLOUDFLARE_KEY')
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
Async.run do
|
22
|
+
connection = Cloudflare.connect(key: key, email: email)
|
23
|
+
|
24
|
+
binding.pry
|
25
|
+
end
|
24
26
|
end
|
data/cloudflare.gemspec
CHANGED
@@ -4,26 +4,28 @@
|
|
4
4
|
require_relative 'lib/cloudflare/version'
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
spec.name = 'cloudflare'
|
8
|
+
spec.version = Cloudflare::VERSION
|
9
|
+
spec.platform = Gem::Platform::RUBY
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
11
|
+
spec.summary = 'A Ruby wrapper for the Cloudflare API.'
|
12
|
+
spec.authors = ['Marcin Prokop', 'Samuel Williams']
|
13
|
+
spec.email = ['marcin@prokop.co', 'samuel.williams@oriontransfer.co.nz']
|
14
|
+
spec.homepage = 'https://github.com/b4k3r/cloudflare'
|
15
|
+
spec.licenses = ['MIT']
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
17
|
+
spec.files = `git ls-files`.split("\n")
|
18
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
19
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
20
|
+
spec.require_paths = ['lib']
|
21
21
|
|
22
|
-
|
22
|
+
spec.required_ruby_version = '>= 2.0.0'
|
23
23
|
|
24
|
-
|
24
|
+
spec.add_dependency 'async-rest'
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
|
26
|
+
spec.add_development_dependency 'async-rspec'
|
27
|
+
|
28
|
+
spec.add_development_dependency 'bundler'
|
29
|
+
spec.add_development_dependency 'rake'
|
30
|
+
spec.add_development_dependency 'rspec', '~> 3.6'
|
29
31
|
end
|
data/lib/cloudflare.rb
CHANGED
@@ -21,12 +21,27 @@
|
|
21
21
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22
22
|
# THE SOFTWARE.
|
23
23
|
|
24
|
+
require 'async'
|
24
25
|
require_relative 'cloudflare/connection'
|
25
|
-
require_relative 'cloudflare/zone'
|
26
|
-
require_relative 'cloudflare/user'
|
27
26
|
|
28
27
|
module Cloudflare
|
29
|
-
|
30
|
-
|
31
|
-
|
28
|
+
DEFAULT_URL = 'https://api.cloudflare.com/client/v4'
|
29
|
+
|
30
|
+
def self.connect(key: nil, email: nil)
|
31
|
+
representation = Connection.for(DEFAULT_URL)
|
32
|
+
|
33
|
+
if key
|
34
|
+
representation = representation.authenticated(key, email)
|
35
|
+
end
|
36
|
+
|
37
|
+
return representation unless block_given?
|
38
|
+
|
39
|
+
Async do
|
40
|
+
begin
|
41
|
+
yield representation
|
42
|
+
ensure
|
43
|
+
representation.close
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
32
47
|
end
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
# Copyright, 2012, by Marcin Prokop.
|
4
4
|
# Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
5
|
+
# Copyright, 2017, by David Rosenbloom. <http://artifactory.com>
|
5
6
|
#
|
6
7
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
8
|
# of this software and associated documentation files (the "Software"), to deal
|
@@ -21,53 +22,30 @@
|
|
21
22
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22
23
|
# THE SOFTWARE.
|
23
24
|
|
24
|
-
|
25
|
+
require_relative 'representation'
|
26
|
+
require_relative 'paginate'
|
25
27
|
|
26
28
|
module Cloudflare
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
body[:result]
|
50
|
-
end
|
51
|
-
|
52
|
-
# Treat result as an array (often it is).
|
53
|
-
def results
|
54
|
-
Array(result)
|
55
|
-
end
|
56
|
-
|
57
|
-
def empty?
|
58
|
-
result.empty?
|
59
|
-
end
|
60
|
-
|
61
|
-
def successful?
|
62
|
-
body[:success]
|
63
|
-
end
|
64
|
-
|
65
|
-
def errors
|
66
|
-
body[:errors]
|
67
|
-
end
|
68
|
-
|
69
|
-
def messages
|
70
|
-
body[:messages]
|
71
|
-
end
|
72
|
-
end
|
29
|
+
class Account < Representation
|
30
|
+
end
|
31
|
+
|
32
|
+
class Accounts < Representation
|
33
|
+
include Paginate
|
34
|
+
|
35
|
+
def represent(metadata, attributes)
|
36
|
+
resource = @resource.with(path: attributes[:id])
|
37
|
+
|
38
|
+
return Account.new(resource, metadata: metadata, value: attributes)
|
39
|
+
end
|
40
|
+
|
41
|
+
def create(name)
|
42
|
+
response = self.post(name: name)
|
43
|
+
|
44
|
+
return represent(response.headers, response.read)
|
45
|
+
end
|
46
|
+
|
47
|
+
def find_by_id(id)
|
48
|
+
Zone.new(@resource.with(path: id))
|
49
|
+
end
|
50
|
+
end
|
73
51
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Copyright,
|
4
|
-
# Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
3
|
+
# Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
5
4
|
#
|
6
5
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
6
|
# of this software and associated documentation files (the "Software"), to deal
|
@@ -21,57 +20,37 @@
|
|
21
20
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22
21
|
# THE SOFTWARE.
|
23
22
|
|
24
|
-
|
25
|
-
require 'json'
|
23
|
+
require_relative 'representation'
|
26
24
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
require_relative 'response'
|
25
|
+
require_relative 'zones'
|
26
|
+
require_relative 'accounts'
|
27
|
+
require_relative 'user'
|
31
28
|
|
32
29
|
module Cloudflare
|
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
|
-
page = 1
|
60
|
-
page_size = 50
|
61
|
-
results = []
|
62
|
-
|
63
|
-
# fetch and aggregate all pages
|
64
|
-
loop do
|
65
|
-
query = URI.encode_www_form scope_type: :organization, per_page: page_size, page: page
|
66
|
-
rules = obj.new(concat_urls(url, "?#{query}#{url_args}"), self, **options)
|
67
|
-
results += rules.get.results
|
68
|
-
break if results.empty? || results.size % page_size != 0
|
69
|
-
page += 1
|
70
|
-
end
|
71
|
-
results
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
class Connection < Resource
|
76
|
-
end
|
30
|
+
class Connection < Representation
|
31
|
+
def authenticated(key, email = nil)
|
32
|
+
headers = {}
|
33
|
+
|
34
|
+
if email.nil?
|
35
|
+
headers['X-Auth-User-Service-Key'] = key
|
36
|
+
else
|
37
|
+
headers['X-Auth-Key'] = key
|
38
|
+
headers['X-Auth-Email'] = email
|
39
|
+
end
|
40
|
+
|
41
|
+
self.class.new(@resource.with(headers: headers))
|
42
|
+
end
|
43
|
+
|
44
|
+
def zones
|
45
|
+
Zones.new(@resource.with(path: 'zones'))
|
46
|
+
end
|
47
|
+
|
48
|
+
def accounts
|
49
|
+
Accounts.new(@resource.with(path: 'accounts'))
|
50
|
+
end
|
51
|
+
|
52
|
+
def user
|
53
|
+
User.new(@resource.with(path: 'user'))
|
54
|
+
end
|
55
|
+
end
|
77
56
|
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright, 2012, by Marcin Prokop.
|
4
|
+
# Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
5
|
+
# Copyright, 2017, by David Rosenbloom. <http://artifactory.com>
|
6
|
+
#
|
7
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
8
|
+
# of this software and associated documentation files (the "Software"), to deal
|
9
|
+
# in the Software without restriction, including without limitation the rights
|
10
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11
|
+
# copies of the Software, and to permit persons to whom the Software is
|
12
|
+
# furnished to do so, subject to the following conditions:
|
13
|
+
#
|
14
|
+
# The above copyright notice and this permission notice shall be included in
|
15
|
+
# all copies or substantial portions of the Software.
|
16
|
+
#
|
17
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23
|
+
# THE SOFTWARE.
|
24
|
+
|
25
|
+
require_relative 'representation'
|
26
|
+
require_relative 'paginate'
|
27
|
+
|
28
|
+
module Cloudflare
|
29
|
+
module DNS
|
30
|
+
class Record < Representation
|
31
|
+
def initialize(url, record = nil, **options)
|
32
|
+
super(url, **options)
|
33
|
+
|
34
|
+
@record = record || get.result
|
35
|
+
end
|
36
|
+
|
37
|
+
def update_content(content)
|
38
|
+
response = put(
|
39
|
+
type: @record[:type],
|
40
|
+
name: @record[:name],
|
41
|
+
content: content
|
42
|
+
)
|
43
|
+
|
44
|
+
@value = response.result
|
45
|
+
end
|
46
|
+
|
47
|
+
def type
|
48
|
+
value[:type]
|
49
|
+
end
|
50
|
+
|
51
|
+
def name
|
52
|
+
value[:name]
|
53
|
+
end
|
54
|
+
|
55
|
+
def content
|
56
|
+
value[:content]
|
57
|
+
end
|
58
|
+
|
59
|
+
def to_s
|
60
|
+
"#{@record[:name]} #{@record[:type]} #{@record[:content]}"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class Records < Representation
|
65
|
+
include Paginate
|
66
|
+
|
67
|
+
def representation
|
68
|
+
Record
|
69
|
+
end
|
70
|
+
|
71
|
+
TTL_AUTO = 1
|
72
|
+
|
73
|
+
def create(type, name, content, **options)
|
74
|
+
message = self.post(type: type, name: name, content: content, **options)
|
75
|
+
|
76
|
+
id = message.result[:id]
|
77
|
+
resource = @resource.with(path: id)
|
78
|
+
|
79
|
+
return representation.new(resource, metadata: message.headers, value: message.result)
|
80
|
+
end
|
81
|
+
|
82
|
+
def find_by_name(name)
|
83
|
+
each(name: name).first
|
84
|
+
end
|
85
|
+
|
86
|
+
def find_by_id(id)
|
87
|
+
Record.new(@resource.with(path: id))
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|