cloudflare 4.0.1 → 4.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +13 -5
- data/.travis.yml +13 -2
- data/Gemfile +20 -0
- data/README.md +15 -4
- data/cloudflare.gemspec +1 -1
- data/lib/cloudflare.rb +5 -5
- data/lib/cloudflare/accounts.rb +12 -16
- data/lib/cloudflare/connection.rb +14 -10
- data/lib/cloudflare/custom_hostname/ssl_attribute.rb +62 -0
- data/lib/cloudflare/custom_hostname/ssl_attribute/settings.rb +71 -0
- data/lib/cloudflare/custom_hostnames.rb +82 -0
- data/lib/cloudflare/dns.rb +16 -20
- data/lib/cloudflare/firewall.rb +9 -16
- data/lib/cloudflare/kv/namespaces.rb +78 -0
- data/lib/cloudflare/paginate.rb +19 -21
- data/lib/cloudflare/representation.rb +32 -15
- data/lib/cloudflare/rspec/connection.rb +13 -1
- data/lib/cloudflare/version.rb +1 -1
- data/lib/cloudflare/zones.rb +13 -17
- data/spec/cloudflare/accounts_spec.rb +24 -0
- data/spec/cloudflare/custom_hostname/ssl_attribute/settings_spec.rb +54 -0
- data/spec/cloudflare/custom_hostname/ssl_attribute_spec.rb +73 -0
- data/spec/cloudflare/custom_hostnames_spec.rb +213 -0
- data/spec/cloudflare/dns_spec.rb +24 -6
- data/spec/cloudflare/kv/namespaces_spec.rb +71 -0
- data/spec/cloudflare/zone_spec.rb +13 -11
- data/spec/spec_helper.rb +60 -9
- metadata +21 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9da58bc3e8cf7394296aafbe26d50731d145f1587df2ecd940057c01de31585c
|
4
|
+
data.tar.gz: 0b8523d30369c61c1fa5aaf1d749daa9a05c03f36c1a9aa898bb5782e662fa6c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8079f41055721191fd999e1b4e948d0061bf5e710503940c07d4125a315c812cda8e5603cc891e50671f5992dbc75ab1e65d6a297c9f6656db0317e85784cc35
|
7
|
+
data.tar.gz: 9f6ac470ada76aea32143026ac1b7923b76b0b50775a362759817dd7fc3118b792d6ad36f4dcd2829e3b3faba097f3c1072e01db3d1a9d21ab5c653285421683
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
@@ -2,9 +2,13 @@ language: ruby
|
|
2
2
|
dist: xenial
|
3
3
|
cache: bundler
|
4
4
|
|
5
|
+
addons:
|
6
|
+
apt:
|
7
|
+
packages:
|
8
|
+
- squid
|
9
|
+
|
5
10
|
matrix:
|
6
11
|
include:
|
7
|
-
- rvm: 2.3
|
8
12
|
- rvm: 2.4
|
9
13
|
- rvm: 2.5
|
10
14
|
- rvm: 2.6
|
@@ -14,6 +18,12 @@ matrix:
|
|
14
18
|
env: JRUBY_OPTS="--debug -X+O"
|
15
19
|
- rvm: truffleruby
|
16
20
|
- rvm: ruby-head
|
21
|
+
- rvm: 2.6
|
22
|
+
env: CLOUDFLARE_PROXY=http://localhost:3128
|
23
|
+
before_script: sudo service squid start
|
24
|
+
- rvm: jruby-head
|
25
|
+
env: JRUBY_OPTS="--debug -X+O" CLOUDFLARE_PROXY=http://localhost:3128
|
26
|
+
before_script: sudo service squid start
|
17
27
|
allow_failures:
|
18
28
|
- rvm: ruby-head
|
19
29
|
- rvm: jruby-head
|
@@ -21,4 +31,5 @@ matrix:
|
|
21
31
|
|
22
32
|
env:
|
23
33
|
global:
|
24
|
-
|
34
|
+
- CLOUDFLARE_TEST_ZONE_MANAGEMENT=true
|
35
|
+
- secure: c5yG7N1r9nYuw47Y90jGeoHNvkL59AAC55dtPAhKP+gjXWW8hKbntj3oj+lVkxEqzRpzEQgYZzUElrP+6mJnb20ldclZg03L56243tMtVEcpGOx/MFhnIBkx3kKu1H6ydKKMxieHxjsLQ3vnpcIZ3p0skTQjYbjdu607tjbyg7s=
|
data/Gemfile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
source 'https://rubygems.org'
|
4
|
+
|
5
|
+
# Specify your gem's dependencies in cloudflare.gemspec
|
6
|
+
gemspec
|
7
|
+
|
8
|
+
gem 'async-http', '~> 0.48', '>= 0.48.2'
|
9
|
+
|
10
|
+
group :development do
|
11
|
+
gem 'pry'
|
12
|
+
gem 'pry-coolline'
|
13
|
+
end
|
14
|
+
|
15
|
+
group :test do
|
16
|
+
gem 'coveralls', require: false
|
17
|
+
gem 'simplecov'
|
18
|
+
gem 'sinatra'
|
19
|
+
gem 'webmock'
|
20
|
+
end
|
data/README.md
CHANGED
@@ -36,7 +36,7 @@ require 'cloudflare'
|
|
36
36
|
email = ENV['CLOUDFLARE_EMAIL']
|
37
37
|
key = ENV['CLOUDFLARE_KEY']
|
38
38
|
|
39
|
-
Cloudflare.connect(key: key, email: email) do
|
39
|
+
Cloudflare.connect(key: key, email: email) do |connection|
|
40
40
|
# Get all available zones:
|
41
41
|
zones = connection.zones
|
42
42
|
|
@@ -63,6 +63,20 @@ Cloudflare.connect(key: key, email: email) do
|
|
63
63
|
end
|
64
64
|
```
|
65
65
|
|
66
|
+
### Using a Bearer Token
|
67
|
+
|
68
|
+
You can read more about [bearer tokens here](https://blog.cloudflare.com/api-tokens-general-availability/). This allows you to limit priviledges.
|
69
|
+
|
70
|
+
```ruby
|
71
|
+
require 'cloudflare'
|
72
|
+
|
73
|
+
token = 'a_generated_api_token'
|
74
|
+
|
75
|
+
Cloudflare.connect(token: token) do |connection|
|
76
|
+
# ...
|
77
|
+
end
|
78
|
+
```
|
79
|
+
|
66
80
|
## Contributing
|
67
81
|
|
68
82
|
1. Fork it
|
@@ -101,6 +115,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
101
115
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
102
116
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
103
117
|
THE SOFTWARE.
|
104
|
-
|
105
|
-
|
106
|
-
|
data/cloudflare.gemspec
CHANGED
data/lib/cloudflare.rb
CHANGED
@@ -25,13 +25,13 @@ require 'async'
|
|
25
25
|
require_relative 'cloudflare/connection'
|
26
26
|
|
27
27
|
module Cloudflare
|
28
|
-
|
28
|
+
DEFAULT_ENDPOINT = Async::HTTP::Endpoint.parse('https://api.cloudflare.com/client/v4')
|
29
29
|
|
30
|
-
def self.connect(
|
31
|
-
representation = Connection.for(
|
30
|
+
def self.connect(endpoint = DEFAULT_ENDPOINT, **auth_info)
|
31
|
+
representation = Connection.for(endpoint)
|
32
32
|
|
33
|
-
if
|
34
|
-
representation = representation.authenticated(
|
33
|
+
if !auth_info.empty?
|
34
|
+
representation = representation.authenticated(**auth_info)
|
35
35
|
end
|
36
36
|
|
37
37
|
return representation unless block_given?
|
data/lib/cloudflare/accounts.rb
CHANGED
@@ -24,28 +24,24 @@
|
|
24
24
|
|
25
25
|
require_relative 'representation'
|
26
26
|
require_relative 'paginate'
|
27
|
+
require_relative 'kv/namespaces'
|
27
28
|
|
28
29
|
module Cloudflare
|
29
30
|
class Account < Representation
|
31
|
+
def id
|
32
|
+
value[:id]
|
33
|
+
end
|
34
|
+
|
35
|
+
def kv_namespaces
|
36
|
+
self.with(KV::Namespaces, path: 'storage/kv/namespaces')
|
37
|
+
end
|
30
38
|
end
|
31
|
-
|
39
|
+
|
32
40
|
class Accounts < Representation
|
33
41
|
include Paginate
|
34
|
-
|
35
|
-
def
|
36
|
-
|
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))
|
42
|
+
|
43
|
+
def representation
|
44
|
+
Account
|
49
45
|
end
|
50
46
|
end
|
51
47
|
end
|
@@ -28,29 +28,33 @@ require_relative 'user'
|
|
28
28
|
|
29
29
|
module Cloudflare
|
30
30
|
class Connection < Representation
|
31
|
-
def authenticated(key, email
|
31
|
+
def authenticated(token: nil, key: nil, email: nil)
|
32
32
|
headers = {}
|
33
33
|
|
34
|
-
if
|
35
|
-
headers['
|
36
|
-
|
37
|
-
|
38
|
-
|
34
|
+
if token
|
35
|
+
headers['Authorization'] = "Bearer #{token}"
|
36
|
+
elsif key
|
37
|
+
if email
|
38
|
+
headers['X-Auth-Key'] = key
|
39
|
+
headers['X-Auth-Email'] = email
|
40
|
+
else
|
41
|
+
headers['X-Auth-User-Service-Key'] = key
|
42
|
+
end
|
39
43
|
end
|
40
44
|
|
41
|
-
self.
|
45
|
+
self.with(headers: headers)
|
42
46
|
end
|
43
47
|
|
44
48
|
def zones
|
45
|
-
|
49
|
+
self.with(Zones, path: 'zones')
|
46
50
|
end
|
47
51
|
|
48
52
|
def accounts
|
49
|
-
|
53
|
+
self.with(Accounts, path: 'accounts')
|
50
54
|
end
|
51
55
|
|
52
56
|
def user
|
53
|
-
|
57
|
+
self.with(User, path: 'user')
|
54
58
|
end
|
55
59
|
end
|
56
60
|
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative './ssl_attribute/settings'
|
4
|
+
|
5
|
+
module Cloudflare
|
6
|
+
class CustomHostname < Representation
|
7
|
+
class SSLAttribute
|
8
|
+
def initialize(params)
|
9
|
+
@params = params
|
10
|
+
end
|
11
|
+
|
12
|
+
def active?
|
13
|
+
status == 'active'
|
14
|
+
end
|
15
|
+
|
16
|
+
def cname
|
17
|
+
@params[:cname]
|
18
|
+
end
|
19
|
+
|
20
|
+
def cname_target
|
21
|
+
@params[:cname_target]
|
22
|
+
end
|
23
|
+
|
24
|
+
def http_body
|
25
|
+
@params[:http_body]
|
26
|
+
end
|
27
|
+
|
28
|
+
def http_url
|
29
|
+
@params[:http_url]
|
30
|
+
end
|
31
|
+
|
32
|
+
def method
|
33
|
+
@params[:method]
|
34
|
+
end
|
35
|
+
|
36
|
+
def pending_validation?
|
37
|
+
status == 'pending_validation'
|
38
|
+
end
|
39
|
+
|
40
|
+
# Wraps the settings hash if it exists or initializes the settings hash and then wraps it
|
41
|
+
def settings
|
42
|
+
@settings ||= Settings.new(@params[:settings] ||= {})
|
43
|
+
end
|
44
|
+
|
45
|
+
def status
|
46
|
+
@params[:status]
|
47
|
+
end
|
48
|
+
|
49
|
+
def to_h
|
50
|
+
@params
|
51
|
+
end
|
52
|
+
|
53
|
+
def type
|
54
|
+
@params[:type]
|
55
|
+
end
|
56
|
+
|
57
|
+
def validation_errors
|
58
|
+
@params[:validation_errors]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Cloudflare
|
4
|
+
class CustomHostname < Representation
|
5
|
+
class SSLAttribute
|
6
|
+
class Settings
|
7
|
+
def initialize(settings)
|
8
|
+
@settings = settings
|
9
|
+
end
|
10
|
+
|
11
|
+
def ciphers
|
12
|
+
@settings[:ciphers]
|
13
|
+
end
|
14
|
+
|
15
|
+
def ciphers=(value)
|
16
|
+
@settings[:ciphers] = value
|
17
|
+
end
|
18
|
+
|
19
|
+
# This will return the raw value, it is needed because
|
20
|
+
# if a value is nil we can't assume that it means it is off
|
21
|
+
def http2
|
22
|
+
@settings[:http2]
|
23
|
+
end
|
24
|
+
|
25
|
+
# Always coerce into a boolean, if the key is not
|
26
|
+
# provided, this value may not be accurate
|
27
|
+
def http2?
|
28
|
+
http2 == 'on'
|
29
|
+
end
|
30
|
+
|
31
|
+
def http2=(value)
|
32
|
+
process_boolean(:http2, value)
|
33
|
+
end
|
34
|
+
|
35
|
+
def min_tls_version
|
36
|
+
@settings[:min_tls_version]
|
37
|
+
end
|
38
|
+
|
39
|
+
def min_tls_version=(value)
|
40
|
+
@settings[:min_tls_version] = value
|
41
|
+
end
|
42
|
+
|
43
|
+
# This will return the raw value, it is needed because
|
44
|
+
# if a value is nil we can't assume that it means it is off
|
45
|
+
def tls_1_3
|
46
|
+
@settings[:tls_1_3]
|
47
|
+
end
|
48
|
+
|
49
|
+
# Always coerce into a boolean, if the key is not
|
50
|
+
# provided, this value may not be accurate
|
51
|
+
def tls_1_3?
|
52
|
+
tls_1_3 == 'on'
|
53
|
+
end
|
54
|
+
|
55
|
+
def tls_1_3=(value)
|
56
|
+
process_boolean(:tls_1_3, value)
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def process_boolean(key, value)
|
62
|
+
if value.nil?
|
63
|
+
@settings.delete(key)
|
64
|
+
else
|
65
|
+
@settings[key] = !value || value == 'off' ? 'off' : 'on'
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# This implements the Custom Hostname API
|
4
|
+
# https://api.cloudflare.com/#custom-hostname-for-a-zone-properties
|
5
|
+
|
6
|
+
require_relative 'custom_hostname/ssl_attribute'
|
7
|
+
require_relative 'paginate'
|
8
|
+
require_relative 'representation'
|
9
|
+
|
10
|
+
module Cloudflare
|
11
|
+
class CustomHostname < Representation
|
12
|
+
# Only available if enabled for your zone
|
13
|
+
def custom_origin
|
14
|
+
value[:custom_origin_server]
|
15
|
+
end
|
16
|
+
|
17
|
+
# Only available if enabled for your zone
|
18
|
+
def custom_metadata
|
19
|
+
value[:custom_metadata]
|
20
|
+
end
|
21
|
+
|
22
|
+
def hostname
|
23
|
+
value[:hostname]
|
24
|
+
end
|
25
|
+
|
26
|
+
def id
|
27
|
+
value[:id]
|
28
|
+
end
|
29
|
+
|
30
|
+
def ssl
|
31
|
+
@ssl ||= SSLAttribute.new(value[:ssl])
|
32
|
+
end
|
33
|
+
|
34
|
+
# Check if the cert has been validated
|
35
|
+
# passing true will send a request to Cloudflare to try to validate the cert
|
36
|
+
def ssl_active?(force_update = false)
|
37
|
+
send_patch(ssl: { method: ssl.method, type: ssl.type }) if force_update && ssl.pending_validation?
|
38
|
+
ssl.active?
|
39
|
+
end
|
40
|
+
|
41
|
+
def update_settings(metadata: nil, origin: nil, ssl: nil)
|
42
|
+
attrs = {}
|
43
|
+
attrs[:custom_metadata] = metadata if metadata
|
44
|
+
attrs[:custom_origin_server] = origin if origin
|
45
|
+
attrs[:ssl] = ssl if ssl
|
46
|
+
|
47
|
+
send_patch(attrs)
|
48
|
+
end
|
49
|
+
|
50
|
+
alias :to_s :hostname
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def send_patch(data)
|
55
|
+
response = patch(data)
|
56
|
+
|
57
|
+
@ssl = nil # Kill off our cached version of the ssl object so it will be regenerated from the response
|
58
|
+
@value = response.result
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
class CustomHostnames < Representation
|
63
|
+
include Paginate
|
64
|
+
|
65
|
+
def representation
|
66
|
+
CustomHostname
|
67
|
+
end
|
68
|
+
|
69
|
+
# initializes a custom hostname object and yields it for customization before saving
|
70
|
+
def create(hostname, metadata: nil, origin: nil, ssl: {}, &block)
|
71
|
+
attrs = { hostname: hostname, ssl: { method: 'http', type: 'dv' }.merge(ssl) }
|
72
|
+
attrs[:custom_metadata] = metadata if metadata
|
73
|
+
attrs[:custom_origin_server] = origin if origin
|
74
|
+
|
75
|
+
represent_message(self.post(attrs))
|
76
|
+
end
|
77
|
+
|
78
|
+
def find_by_hostname(hostname)
|
79
|
+
each(hostname: hostname).first
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|