cloudflare 4.0.1 → 4.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 +4 -4
- data/.travis.yml +2 -1
- data/README.md +1 -1
- data/lib/cloudflare/accounts.rb +12 -16
- 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 +9 -18
- data/lib/cloudflare/firewall.rb +9 -16
- data/lib/cloudflare/kv/namespaces.rb +78 -0
- data/lib/cloudflare/paginate.rb +18 -20
- data/lib/cloudflare/representation.rb +32 -15
- data/lib/cloudflare/version.rb +1 -1
- data/lib/cloudflare/zones.rb +10 -14
- 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/kv/namespaces_spec.rb +71 -0
- data/spec/cloudflare/zone_spec.rb +13 -11
- data/spec/spec_helper.rb +60 -9
- metadata +17 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8f5bd083595954567afddacb3dccb6ad1dbe614d3d654d6ec5edfb7967d99e19
|
4
|
+
data.tar.gz: f1ac3f29decb6108455805f5a24d68cda0ab7a142cd781b0df991ed11014835f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6113d2ffeb66def38c41b35ed739a24f2d8b568596e0fc5623e55c8b49dd17954235e37c0288ccef0aaf0a370c54c8bec5a4321cb5b2bfdc5f461a438184300d
|
7
|
+
data.tar.gz: bc5c727f94c5078d0a506d9cf6006b7d46582802d24a3089dbc3a8000be48e28a14d072f7a7a6125f835a14d567cd51f1424f2142dea44e992dafcfaff7d0d29
|
data/.travis.yml
CHANGED
@@ -21,4 +21,5 @@ matrix:
|
|
21
21
|
|
22
22
|
env:
|
23
23
|
global:
|
24
|
-
|
24
|
+
- CLOUDFLARE_TEST_ZONE_MANAGEMENT=true
|
25
|
+
- secure: c5yG7N1r9nYuw47Y90jGeoHNvkL59AAC55dtPAhKP+gjXWW8hKbntj3oj+lVkxEqzRpzEQgYZzUElrP+6mJnb20ldclZg03L56243tMtVEcpGOx/MFhnIBkx3kKu1H6ydKKMxieHxjsLQ3vnpcIZ3p0skTQjYbjdu607tjbyg7s=
|
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
|
|
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
|
+
KV::Namespaces.new(@resource.with(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
|
@@ -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
|
data/lib/cloudflare/dns.rb
CHANGED
@@ -40,22 +40,22 @@ module Cloudflare
|
|
40
40
|
name: @record[:name],
|
41
41
|
content: content
|
42
42
|
)
|
43
|
-
|
43
|
+
|
44
44
|
@value = response.result
|
45
45
|
end
|
46
|
-
|
46
|
+
|
47
47
|
def type
|
48
48
|
value[:type]
|
49
49
|
end
|
50
|
-
|
50
|
+
|
51
51
|
def name
|
52
52
|
value[:name]
|
53
53
|
end
|
54
|
-
|
54
|
+
|
55
55
|
def content
|
56
56
|
value[:content]
|
57
57
|
end
|
58
|
-
|
58
|
+
|
59
59
|
def to_s
|
60
60
|
"#{@record[:name]} #{@record[:type]} #{@record[:content]}"
|
61
61
|
end
|
@@ -63,29 +63,20 @@ module Cloudflare
|
|
63
63
|
|
64
64
|
class Records < Representation
|
65
65
|
include Paginate
|
66
|
-
|
66
|
+
|
67
67
|
def representation
|
68
68
|
Record
|
69
69
|
end
|
70
|
-
|
70
|
+
|
71
71
|
TTL_AUTO = 1
|
72
72
|
|
73
73
|
def create(type, name, content, **options)
|
74
|
-
|
75
|
-
|
76
|
-
id = message.result[:id]
|
77
|
-
resource = @resource.with(path: id)
|
78
|
-
|
79
|
-
return representation.new(resource, metadata: message.headers, value: message.result)
|
74
|
+
represent_message(self.post(type: type, name: name, content: content, **options))
|
80
75
|
end
|
81
|
-
|
76
|
+
|
82
77
|
def find_by_name(name)
|
83
78
|
each(name: name).first
|
84
79
|
end
|
85
|
-
|
86
|
-
def find_by_id(id)
|
87
|
-
Record.new(@resource.with(path: id))
|
88
|
-
end
|
89
80
|
end
|
90
81
|
end
|
91
82
|
end
|
data/lib/cloudflare/firewall.rb
CHANGED
@@ -29,15 +29,15 @@ module Cloudflare
|
|
29
29
|
def mode
|
30
30
|
value[:mode]
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
33
|
def notes
|
34
34
|
value[:notes]
|
35
35
|
end
|
36
|
-
|
36
|
+
|
37
37
|
def configuration
|
38
38
|
value[:configuration]
|
39
39
|
end
|
40
|
-
|
40
|
+
|
41
41
|
def to_s
|
42
42
|
"#{configuration[:value]} - #{mode} - #{notes}"
|
43
43
|
end
|
@@ -45,14 +45,14 @@ module Cloudflare
|
|
45
45
|
|
46
46
|
class Rules < Representation
|
47
47
|
include Paginate
|
48
|
-
|
48
|
+
|
49
49
|
def representation
|
50
50
|
Rule
|
51
51
|
end
|
52
|
-
|
52
|
+
|
53
53
|
def set(mode, value, notes: nil, target: 'ip')
|
54
54
|
notes ||= "cloudflare gem [#{mode}] #{Time.now.strftime('%m/%d/%y')}"
|
55
|
-
|
55
|
+
|
56
56
|
message = self.post({
|
57
57
|
mode: mode.to_s,
|
58
58
|
notes: notes,
|
@@ -61,17 +61,10 @@ module Cloudflare
|
|
61
61
|
value: value.to_s,
|
62
62
|
}
|
63
63
|
})
|
64
|
-
|
65
|
-
|
66
|
-
resource = @resource.with(path: id)
|
67
|
-
|
68
|
-
return representation.new(resource, metadata: message.headers, value: message.result)
|
69
|
-
end
|
70
|
-
|
71
|
-
def find_by_id(id)
|
72
|
-
Rule.new(@resource.with(path: id))
|
64
|
+
|
65
|
+
represent_message(message)
|
73
66
|
end
|
74
|
-
|
67
|
+
|
75
68
|
def each_by_value(value, &block)
|
76
69
|
each(configuration_value: value, &block)
|
77
70
|
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# This implements the Worker KV Store API
|
4
|
+
# https://api.cloudflare.com/#workers-kv-namespace-properties
|
5
|
+
|
6
|
+
require_relative '../paginate'
|
7
|
+
require_relative '../representation'
|
8
|
+
|
9
|
+
module Cloudflare
|
10
|
+
module KV
|
11
|
+
class Key < Representation
|
12
|
+
def name
|
13
|
+
value[:name]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class Keys < Representation
|
18
|
+
include Paginate
|
19
|
+
|
20
|
+
def representation
|
21
|
+
Key
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class Namespace < Representation
|
26
|
+
def delete_value(name)
|
27
|
+
value_representation(name).delete.success?
|
28
|
+
end
|
29
|
+
|
30
|
+
def id
|
31
|
+
value[:id]
|
32
|
+
end
|
33
|
+
|
34
|
+
def keys
|
35
|
+
Keys.new(@resource.with(path: 'keys'))
|
36
|
+
end
|
37
|
+
|
38
|
+
def read_value(name)
|
39
|
+
value_representation(name).value
|
40
|
+
end
|
41
|
+
|
42
|
+
def rename(new_title)
|
43
|
+
put(title: new_title)
|
44
|
+
value[:title] = new_title
|
45
|
+
end
|
46
|
+
|
47
|
+
def title
|
48
|
+
value[:title]
|
49
|
+
end
|
50
|
+
|
51
|
+
def write_value(name, value)
|
52
|
+
value_representation(name).put(value).success?
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def value_representation(name)
|
58
|
+
Representation.new(@resource.with(path: "values/#{name}"))
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
class Namespaces < Representation
|
63
|
+
include Paginate
|
64
|
+
|
65
|
+
def representation
|
66
|
+
Namespace
|
67
|
+
end
|
68
|
+
|
69
|
+
def create(title)
|
70
|
+
represent_message(post(title: title))
|
71
|
+
end
|
72
|
+
|
73
|
+
def find_by_title(title)
|
74
|
+
each.find {|namespace| namespace.title == title }
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
data/lib/cloudflare/paginate.rb
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
# Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
|
-
#
|
2
|
+
#
|
3
3
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
4
|
# of this software and associated documentation files (the "Software"), to deal
|
5
5
|
# in the Software without restriction, including without limitation the rights
|
6
6
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
7
|
# copies of the Software, and to permit persons to whom the Software is
|
8
8
|
# furnished to do so, subject to the following conditions:
|
9
|
-
#
|
9
|
+
#
|
10
10
|
# The above copyright notice and this permission notice shall be included in
|
11
11
|
# all copies or substantial portions of the Software.
|
12
|
-
#
|
12
|
+
#
|
13
13
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
14
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
15
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
@@ -21,34 +21,32 @@
|
|
21
21
|
module Cloudflare
|
22
22
|
module Paginate
|
23
23
|
include Enumerable
|
24
|
-
|
25
|
-
def empty?
|
26
|
-
self.value.empty?
|
27
|
-
end
|
28
|
-
|
29
|
-
def representation
|
30
|
-
Representation
|
31
|
-
end
|
32
|
-
|
24
|
+
|
33
25
|
def each(page: 1, per_page: 50, **parameters)
|
34
26
|
return to_enum(:each, page: page, per_page: per_page, **parameters) unless block_given?
|
35
|
-
|
27
|
+
|
36
28
|
while true
|
37
29
|
zones = @resource.get(self.class, page: page, per_page: per_page, **parameters)
|
38
|
-
|
30
|
+
|
39
31
|
break if zones.empty?
|
40
|
-
|
32
|
+
|
41
33
|
Array(zones.value).each do |attributes|
|
42
|
-
|
43
|
-
|
44
|
-
yield representation.new(resource, metadata: zones.metadata, value: attributes)
|
34
|
+
yield represent(zones.metadata, attributes)
|
45
35
|
end
|
46
|
-
|
36
|
+
|
47
37
|
page += 1
|
48
|
-
|
38
|
+
|
49
39
|
# Was this the last page?
|
50
40
|
break if zones.value.count < per_page
|
51
41
|
end
|
52
42
|
end
|
43
|
+
|
44
|
+
def empty?
|
45
|
+
self.value.empty?
|
46
|
+
end
|
47
|
+
|
48
|
+
def find_by_id(id)
|
49
|
+
representation.new(@resource.with(path: id))
|
50
|
+
end
|
53
51
|
end
|
54
52
|
end
|
@@ -29,62 +29,79 @@ module Cloudflare
|
|
29
29
|
class RequestError < StandardError
|
30
30
|
def initialize(resource, errors)
|
31
31
|
super("#{resource}: #{errors.map{|attributes| attributes[:message]}.join(', ')}")
|
32
|
-
|
32
|
+
|
33
33
|
@representation = representation
|
34
34
|
end
|
35
|
-
|
35
|
+
|
36
36
|
attr_reader :representation
|
37
37
|
end
|
38
|
-
|
38
|
+
|
39
39
|
class Message
|
40
40
|
def initialize(response)
|
41
41
|
@response = response
|
42
42
|
@body = response.read
|
43
|
+
|
44
|
+
# Some endpoints return the value instead of a message object (like KV reads)
|
45
|
+
@body = { success: true, result: @body } unless @body.is_a?(Hash)
|
43
46
|
end
|
44
|
-
|
47
|
+
|
45
48
|
attr :response
|
46
49
|
attr :body
|
47
|
-
|
50
|
+
|
48
51
|
def headers
|
49
52
|
@response.headers
|
50
53
|
end
|
51
|
-
|
54
|
+
|
52
55
|
def result
|
53
56
|
@body[:result]
|
54
57
|
end
|
55
|
-
|
58
|
+
|
56
59
|
def read
|
57
60
|
@body[:result]
|
58
61
|
end
|
59
|
-
|
62
|
+
|
60
63
|
def results
|
61
64
|
Array(result)
|
62
65
|
end
|
63
|
-
|
66
|
+
|
64
67
|
def errors
|
65
68
|
@body[:errors]
|
66
69
|
end
|
67
|
-
|
70
|
+
|
68
71
|
def messages
|
69
72
|
@body[:messages]
|
70
73
|
end
|
71
|
-
|
74
|
+
|
72
75
|
def success?
|
73
76
|
@body[:success]
|
74
77
|
end
|
75
78
|
end
|
76
|
-
|
79
|
+
|
77
80
|
class Representation < Async::REST::Representation
|
78
81
|
def process_response(*)
|
79
82
|
message = Message.new(super)
|
80
|
-
|
83
|
+
|
81
84
|
unless message.success?
|
82
85
|
raise RequestError.new(@resource, message.errors)
|
83
86
|
end
|
84
|
-
|
87
|
+
|
85
88
|
return message
|
86
89
|
end
|
87
|
-
|
90
|
+
|
91
|
+
def representation
|
92
|
+
Representation
|
93
|
+
end
|
94
|
+
|
95
|
+
def represent(metadata, attributes)
|
96
|
+
resource = @resource.with(path: attributes[:id])
|
97
|
+
|
98
|
+
representation.new(resource, metadata: metadata, value: attributes)
|
99
|
+
end
|
100
|
+
|
101
|
+
def represent_message(message)
|
102
|
+
represent(message.headers, message.result)
|
103
|
+
end
|
104
|
+
|
88
105
|
def to_hash
|
89
106
|
if value.is_a?(Hash)
|
90
107
|
return value
|
data/lib/cloudflare/version.rb
CHANGED
data/lib/cloudflare/zones.rb
CHANGED
@@ -25,12 +25,17 @@
|
|
25
25
|
require_relative 'representation'
|
26
26
|
require_relative 'paginate'
|
27
27
|
|
28
|
+
require_relative 'custom_hostnames'
|
28
29
|
require_relative 'firewall'
|
29
30
|
require_relative 'dns'
|
30
31
|
require_relative 'logs'
|
31
32
|
|
32
33
|
module Cloudflare
|
33
34
|
class Zone < Representation
|
35
|
+
def custom_hostnames
|
36
|
+
CustomHostnames.new(@resource.with(path: 'custom_hostnames'))
|
37
|
+
end
|
38
|
+
|
34
39
|
def dns_records
|
35
40
|
DNS::Records.new(@resource.with(path: 'dns_records'))
|
36
41
|
end
|
@@ -48,9 +53,9 @@ module Cloudflare
|
|
48
53
|
}.freeze
|
49
54
|
|
50
55
|
def purge_cache(parameters = DEFAULT_PURGE_CACHE_PARAMS)
|
51
|
-
|
56
|
+
Zone.new(@resource.with(path: 'purge_cache')).post(parameters)
|
52
57
|
|
53
|
-
return
|
58
|
+
return self
|
54
59
|
end
|
55
60
|
|
56
61
|
def name
|
@@ -66,22 +71,13 @@ module Cloudflare
|
|
66
71
|
def representation
|
67
72
|
Zone
|
68
73
|
end
|
69
|
-
|
74
|
+
|
70
75
|
def create(name, account, jump_start = false)
|
71
|
-
|
72
|
-
|
73
|
-
id = message.result[:id]
|
74
|
-
resource = @resource.with(path: id)
|
75
|
-
|
76
|
-
return representation.new(resource, metadata: message.headers, value: message.result)
|
76
|
+
represent_message(self.post(name: name, account: account.to_hash, jump_start: jump_start))
|
77
77
|
end
|
78
|
-
|
78
|
+
|
79
79
|
def find_by_name(name)
|
80
80
|
each(name: name).first
|
81
81
|
end
|
82
|
-
|
83
|
-
def find_by_id(id)
|
84
|
-
Zone.new(@resource.with(path: id))
|
85
|
-
end
|
86
82
|
end
|
87
83
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe Cloudflare::Accounts, order: :defined, timeout: 30 do
|
4
|
+
include_context Cloudflare::Account
|
5
|
+
|
6
|
+
before do
|
7
|
+
account.id # Force a fetch if it hasn't happened yet
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'can list existing accounts' do
|
11
|
+
accounts = connection.accounts.to_a
|
12
|
+
expect(accounts.any? {|a| a.id == account.id }).to be true
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'can get a specific account' do
|
16
|
+
expect(connection.accounts.find_by_id(account.id).id).to eq account.id
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'can generate a representation for the KV namespace endpoint' do
|
20
|
+
ns = connection.accounts.find_by_id(account.id).kv_namespaces
|
21
|
+
expect(ns).to be_kind_of(Cloudflare::KV::Namespaces)
|
22
|
+
expect(ns.resource.reference.path).to end_with("/#{account.id}/storage/kv/namespaces")
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
RSpec.describe Cloudflare::CustomHostname::SSLAttribute::Settings do
|
2
|
+
|
3
|
+
subject { described_class.new({}) }
|
4
|
+
|
5
|
+
it 'has an accessor for ciphers' do
|
6
|
+
ciphers = double
|
7
|
+
expect(subject.ciphers).to be_nil
|
8
|
+
subject.ciphers = ciphers
|
9
|
+
expect(subject.ciphers).to be ciphers
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'has a boolean accessor for http2' do
|
13
|
+
expect(subject.http2).to be_nil
|
14
|
+
expect(subject.http2?).to be false
|
15
|
+
subject.http2 = true
|
16
|
+
expect(subject.http2).to eq 'on'
|
17
|
+
expect(subject.http2?).to be true
|
18
|
+
subject.http2 = false
|
19
|
+
expect(subject.http2).to eq 'off'
|
20
|
+
expect(subject.http2?).to be false
|
21
|
+
subject.http2 = 'on'
|
22
|
+
expect(subject.http2).to eq 'on'
|
23
|
+
expect(subject.http2?).to be true
|
24
|
+
subject.http2 = 'off'
|
25
|
+
expect(subject.http2).to eq 'off'
|
26
|
+
expect(subject.http2?).to be false
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'has an accessor for min_tls_version' do
|
30
|
+
tls_version = double
|
31
|
+
expect(subject.min_tls_version).to be_nil
|
32
|
+
subject.min_tls_version = tls_version
|
33
|
+
expect(subject.min_tls_version).to be tls_version
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'has a boolean accessor for tls_1_3' do
|
37
|
+
expect(subject.tls_1_3).to be_nil
|
38
|
+
expect(subject.tls_1_3?).to be false
|
39
|
+
subject.tls_1_3 = true
|
40
|
+
expect(subject.tls_1_3).to eq 'on'
|
41
|
+
expect(subject.tls_1_3?).to be true
|
42
|
+
subject.tls_1_3 = false
|
43
|
+
expect(subject.tls_1_3).to eq 'off'
|
44
|
+
expect(subject.tls_1_3?).to be false
|
45
|
+
subject.tls_1_3 = 'on'
|
46
|
+
expect(subject.tls_1_3).to eq 'on'
|
47
|
+
expect(subject.tls_1_3?).to be true
|
48
|
+
subject.tls_1_3 = 'off'
|
49
|
+
expect(subject.tls_1_3).to eq 'off'
|
50
|
+
expect(subject.tls_1_3?).to be false
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
RSpec.describe Cloudflare::CustomHostname::SSLAttribute do
|
2
|
+
|
3
|
+
accessors = [:cname, :cname_target, :http_body, :http_url, :method, :status, :type, :validation_errors]
|
4
|
+
|
5
|
+
let(:original_hash) { {} }
|
6
|
+
|
7
|
+
subject { described_class.new(original_hash) }
|
8
|
+
|
9
|
+
accessors.each do |key|
|
10
|
+
|
11
|
+
it "has an accessor for the #{key} value" do
|
12
|
+
test_value = double
|
13
|
+
expect(subject.send(key)).to be_nil
|
14
|
+
original_hash[key] = test_value
|
15
|
+
expect(subject.send(key)).to be test_value
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
it '#active? returns true when the status is "active" and false otherwise' do
|
21
|
+
expect(subject.active?).to be false
|
22
|
+
original_hash[:status] = 'initializing'
|
23
|
+
expect(subject.active?).to be false
|
24
|
+
original_hash[:status] = 'pending_validation'
|
25
|
+
expect(subject.active?).to be false
|
26
|
+
original_hash[:status] = 'pending_deployment'
|
27
|
+
expect(subject.active?).to be false
|
28
|
+
original_hash[:status] = 'active'
|
29
|
+
expect(subject.active?).to be true
|
30
|
+
end
|
31
|
+
|
32
|
+
it '#pending_validation? returns true when the status is "pending_validation" and false otherwise' do
|
33
|
+
expect(subject.pending_validation?).to be false
|
34
|
+
original_hash[:status] = 'initializing'
|
35
|
+
expect(subject.pending_validation?).to be false
|
36
|
+
original_hash[:status] = 'active'
|
37
|
+
expect(subject.pending_validation?).to be false
|
38
|
+
original_hash[:status] = 'pending_deployment'
|
39
|
+
expect(subject.pending_validation?).to be false
|
40
|
+
original_hash[:status] = 'pending_validation'
|
41
|
+
expect(subject.pending_validation?).to be true
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '#settings' do
|
45
|
+
|
46
|
+
it 'should return a Settings object' do
|
47
|
+
expect(subject.settings).to be_kind_of Cloudflare::CustomHostname::SSLAttribute::Settings
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'initailizes the settings object with the value from the settings key' do
|
51
|
+
settings = { min_tls_version: double }
|
52
|
+
original_hash[:settings] = settings
|
53
|
+
expect(subject.settings.min_tls_version).to be settings[:min_tls_version]
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'initializes the settings object with a new hash if the settings key does not exist' do
|
57
|
+
expected_value = double
|
58
|
+
expect(original_hash[:settings]).to be_nil
|
59
|
+
expect(subject.settings.min_tls_version).to be_nil
|
60
|
+
expect(original_hash[:settings]).not_to be_nil
|
61
|
+
original_hash[:settings][:min_tls_version] = expected_value
|
62
|
+
expect(subject.settings.min_tls_version).to be expected_value
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'updates the stored hash with values set on the settings object' do
|
66
|
+
expected_value = double
|
67
|
+
expect(subject.settings.min_tls_version).to be_nil
|
68
|
+
subject.settings.min_tls_version = expected_value
|
69
|
+
expect(original_hash[:settings][:min_tls_version]).to be expected_value
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
@@ -0,0 +1,213 @@
|
|
1
|
+
|
2
|
+
RSpec.describe Cloudflare::CustomHostnames, order: :defined, timeout: 30 do
|
3
|
+
include_context Cloudflare::Zone
|
4
|
+
|
5
|
+
let(:domain) { "www#{ENV['TRAVIS_JOB_ID'] || rand(1..5)}.ourtest.com" }
|
6
|
+
|
7
|
+
let(:record) { @record = zone.custom_hostnames.create(domain) }
|
8
|
+
|
9
|
+
let(:custom_origin) do
|
10
|
+
id = rand(1...100)
|
11
|
+
id += (job_id * 100) if job_id.positive?
|
12
|
+
subdomain = "origin-#{id}"
|
13
|
+
@dns_record = zone.dns_records.create("A", subdomain, "1.2.3.4") # This needs to exist or the calls will fail
|
14
|
+
"#{subdomain}.#{zone.name}"
|
15
|
+
end
|
16
|
+
|
17
|
+
after do
|
18
|
+
if defined? @record
|
19
|
+
expect(@record.delete).to be_success
|
20
|
+
end
|
21
|
+
|
22
|
+
if defined? @dns_record
|
23
|
+
expect(@dns_record.delete).to be_success
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'can create a custom hostname record' do
|
28
|
+
expect(record).to be_kind_of Cloudflare::CustomHostname
|
29
|
+
expect(record.custom_metadata).to be_nil
|
30
|
+
expect(record.hostname).to eq domain
|
31
|
+
expect(record.custom_origin).to be_nil
|
32
|
+
expect(record.ssl.method).to eq 'http'
|
33
|
+
expect(record.ssl.type).to eq 'dv'
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'can create a custom hostname record with a custom origin' do
|
37
|
+
begin
|
38
|
+
@record = zone.custom_hostnames.create(domain, origin: custom_origin)
|
39
|
+
|
40
|
+
expect(@record).to be_kind_of Cloudflare::CustomHostname
|
41
|
+
expect(@record.custom_metadata).to be_nil
|
42
|
+
expect(@record.hostname).to eq domain
|
43
|
+
expect(@record.custom_origin).to eq custom_origin
|
44
|
+
expect(@record.ssl.method).to eq 'http'
|
45
|
+
expect(@record.ssl.type).to eq 'dv'
|
46
|
+
rescue Cloudflare::RequestError => e
|
47
|
+
if e.message.include?('custom origin server has not been granted')
|
48
|
+
skip(e.message) # This currently doesn't work but might start eventually: https://github.com/socketry/async-rspec/issues/7
|
49
|
+
else
|
50
|
+
raise
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'can create a custom hostname record with different ssl options' do
|
56
|
+
@record = zone.custom_hostnames.create(domain, ssl: { method: 'cname' })
|
57
|
+
|
58
|
+
expect(@record).to be_kind_of Cloudflare::CustomHostname
|
59
|
+
expect(@record.custom_metadata).to be_nil
|
60
|
+
expect(@record.hostname).to eq domain
|
61
|
+
expect(@record.custom_origin).to be_nil
|
62
|
+
expect(@record.ssl.method).to eq 'cname'
|
63
|
+
expect(@record.ssl.type).to eq 'dv'
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'can create a custom hostname record with additional metadata' do
|
67
|
+
metadata = { a: rand(1..10) }
|
68
|
+
|
69
|
+
begin
|
70
|
+
@record = zone.custom_hostnames.create(domain, metadata: metadata)
|
71
|
+
|
72
|
+
expect(@record).to be_kind_of Cloudflare::CustomHostname
|
73
|
+
expect(@record.custom_metadata).to eq metadata
|
74
|
+
expect(@record.hostname).to eq domain
|
75
|
+
expect(@record.custom_origin).to be_nil
|
76
|
+
expect(@record.ssl.method).to eq 'http'
|
77
|
+
expect(@record.ssl.type).to eq 'dv'
|
78
|
+
rescue Cloudflare::RequestError => e
|
79
|
+
if e.message.include?('No custom metadata access has been allocated for this zone')
|
80
|
+
skip(e.message) # This currently doesn't work but might start eventually: https://github.com/socketry/async-rspec/issues/7
|
81
|
+
else
|
82
|
+
raise
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'can look up an existing custom hostname by the hostname or id' do
|
88
|
+
expect(zone.custom_hostnames.find_by_hostname(record.hostname).id).to eq record.id
|
89
|
+
expect(zone.custom_hostnames.find_by_id(record.id).id).to eq record.id
|
90
|
+
end
|
91
|
+
|
92
|
+
context 'with existing record' do
|
93
|
+
|
94
|
+
it 'returns the hostname when calling #to_s' do
|
95
|
+
expect(record.to_s).to eq domain
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'can update metadata' do
|
99
|
+
metadata = { c: rand(1..10) }
|
100
|
+
|
101
|
+
expect(record.custom_metadata).to be_nil
|
102
|
+
|
103
|
+
begin
|
104
|
+
record.update_settings(metadata: metadata)
|
105
|
+
|
106
|
+
# Make sure the existing object is updated
|
107
|
+
expect(record.custom_metadata).to eq metadata
|
108
|
+
|
109
|
+
# Verify that the server has the changes
|
110
|
+
found_record = zone.custom_hostnames.find_by_id(record.id)
|
111
|
+
|
112
|
+
expect(found_record.custom_metadata).to eq metadata
|
113
|
+
expect(found_record.hostname).to eq domain
|
114
|
+
expect(found_record.custom_origin).to be_nil
|
115
|
+
rescue Cloudflare::RequestError => e
|
116
|
+
if e.message.include?('No custom metadata access has been allocated for this zone')
|
117
|
+
skip(e.message) # This currently doesn't work but might start eventually: https://github.com/socketry/async-rspec/issues/7
|
118
|
+
else
|
119
|
+
raise
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'can update the custom origin' do
|
125
|
+
expect(record.custom_origin).to be_nil
|
126
|
+
|
127
|
+
begin
|
128
|
+
record.update_settings(origin: custom_origin)
|
129
|
+
|
130
|
+
# Make sure the existing object is updated
|
131
|
+
expect(record.custom_origin).to eq custom_origin
|
132
|
+
|
133
|
+
# Verify that the server has the changes
|
134
|
+
found_record = zone.custom_hostnames.find_by_id(record.id)
|
135
|
+
|
136
|
+
expect(found_record.custom_metadata).to be_nil
|
137
|
+
expect(found_record.hostname).to eq domain
|
138
|
+
expect(found_record.custom_origin).to eq custom_origin
|
139
|
+
rescue Cloudflare::RequestError => e
|
140
|
+
if e.message.include?('custom origin server has not been granted')
|
141
|
+
skip(e.message) # This currently doesn't work but might start eventually: https://github.com/socketry/async-rspec/issues/7
|
142
|
+
else
|
143
|
+
raise
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'can update ssl information' do
|
149
|
+
expect(record.ssl.method).to eq 'http'
|
150
|
+
|
151
|
+
record.update_settings(ssl: { method: 'cname', type: 'dv' })
|
152
|
+
|
153
|
+
# Make sure the existing object is updated
|
154
|
+
expect(record.ssl.method).to eq 'cname'
|
155
|
+
|
156
|
+
# Verify that the server has the changes
|
157
|
+
found_record = zone.custom_hostnames.find_by_id(record.id)
|
158
|
+
|
159
|
+
expect(found_record.custom_metadata).to be_nil
|
160
|
+
expect(found_record.hostname).to eq domain
|
161
|
+
expect(found_record.custom_origin).to be_nil
|
162
|
+
expect(found_record.ssl.method).to eq 'cname'
|
163
|
+
end
|
164
|
+
|
165
|
+
context 'has an ssl section' do
|
166
|
+
|
167
|
+
it 'wraps it in an SSLAttributes object' do
|
168
|
+
expect(record.ssl).to be_kind_of Cloudflare::CustomHostname::SSLAttribute
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'has some helpers for commonly used keys' do
|
172
|
+
# Make sure our values exist before we check to make sure that they are returned correctly
|
173
|
+
expect(record.value[:ssl].values_at(:method, :http_body, :http_url).compact).not_to be_empty
|
174
|
+
expect(record.ssl.method).to be record.value[:ssl][:method]
|
175
|
+
expect(record.ssl.http_body).to be record.value[:ssl][:http_body]
|
176
|
+
expect(record.ssl.http_url).to be record.value[:ssl][:http_url]
|
177
|
+
end
|
178
|
+
|
179
|
+
end
|
180
|
+
|
181
|
+
describe '#ssl_active?' do
|
182
|
+
|
183
|
+
it 'returns the result of calling ssl.active?' do
|
184
|
+
expected_value = double
|
185
|
+
expect(record.ssl).to receive(:active?).and_return(expected_value)
|
186
|
+
expect(record).not_to receive(:send_patch)
|
187
|
+
expect(record.ssl_active?).to be expected_value
|
188
|
+
end
|
189
|
+
|
190
|
+
it 'returns the result of calling ssl.active? without triggering an update if force_update is true and the ssl is not in the pending_validation state' do
|
191
|
+
expected_value = double
|
192
|
+
expect(record.ssl).to receive(:active?).and_return(expected_value)
|
193
|
+
expect(record.ssl.method).not_to be_nil
|
194
|
+
expect(record.ssl.type).not_to be_nil
|
195
|
+
expect(record.ssl.pending_validation?).to be false
|
196
|
+
expect(record).not_to receive(:send_patch).with(ssl: { method: record.ssl.method, type: record.ssl.type })
|
197
|
+
expect(record.ssl_active?(true)).to be expected_value
|
198
|
+
end
|
199
|
+
|
200
|
+
it 'returns the result of calling ssl.active? after triggering an update if force_update is true and the ssl is in the pending_validation state' do
|
201
|
+
expected_value = double
|
202
|
+
expect(record.ssl).to receive(:active?).and_return(expected_value)
|
203
|
+
expect(record.ssl.method).not_to be_nil
|
204
|
+
expect(record.ssl.type).not_to be_nil
|
205
|
+
record.value[:ssl][:status] = 'pending_validation'
|
206
|
+
expect(record).to receive(:send_patch).with(ssl: { method: record.ssl.method, type: record.ssl.type })
|
207
|
+
expect(record.ssl_active?(true)).to be expected_value
|
208
|
+
end
|
209
|
+
|
210
|
+
end
|
211
|
+
|
212
|
+
end
|
213
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
|
2
|
+
RSpec.describe Cloudflare::KV::Namespaces, kv_spec: true, order: :defined, timeout: 30 do
|
3
|
+
include_context Cloudflare::Account
|
4
|
+
|
5
|
+
let(:namespace) { @namespace = account.kv_namespaces.create(namespace_title) }
|
6
|
+
let(:namespace_title) { "Test NS ##{rand(1..100)}" }
|
7
|
+
|
8
|
+
after do
|
9
|
+
if defined? @namespace
|
10
|
+
expect(@namespace.delete).to be_success
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'can create a namespace' do
|
15
|
+
expect(namespace).to be_kind_of Cloudflare::KV::Namespace
|
16
|
+
expect(namespace.id).not_to be_nil
|
17
|
+
expect(namespace.title).to eq namespace_title
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'can find a namespace by title' do
|
21
|
+
namespace # Call this so that the namespace gets created
|
22
|
+
expect(account.kv_namespaces.find_by_title(namespace_title).id).to eq namespace.id
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'can rename the namespace' do
|
26
|
+
new_title = "#{namespace_title}-#{rand(1..100)}"
|
27
|
+
namespace.rename(new_title)
|
28
|
+
expect(namespace.title).to eq new_title
|
29
|
+
expect(account.kv_namespaces.find_by_title(new_title).id).to eq namespace.id
|
30
|
+
expect(account.kv_namespaces.find_by_title(namespace_title)).to be_nil
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'can store a key/value, read it back' do
|
34
|
+
key = "key-#{rand(1..100)}"
|
35
|
+
value = rand(100..999)
|
36
|
+
namespace.write_value(key, value)
|
37
|
+
expect(account.kv_namespaces.find_by_id(namespace.id).read_value(key)).to eq value.to_s
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'can read a previously stored key' do
|
41
|
+
key = "key-#{rand(1..100)}"
|
42
|
+
value = rand(100..999)
|
43
|
+
expect(account.kv_namespaces.find_by_id(namespace.id).write_value(key, value)).to be true
|
44
|
+
expect(namespace.read_value(key)).to eq value.to_s
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'can delete keys' do
|
48
|
+
key = "key-#{rand(1..100)}"
|
49
|
+
value = rand(100..999)
|
50
|
+
expect(namespace.write_value(key, value)).to be true
|
51
|
+
expect(namespace.read_value(key)).to eq value.to_s
|
52
|
+
expect(namespace.delete_value(key)).to be true
|
53
|
+
expect do
|
54
|
+
account.kv_namespaces.find_by_id(namespace.id).read_value(key)
|
55
|
+
end.to raise_error(Cloudflare::RequestError)
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'can get the keys that exist in the namespace' do
|
59
|
+
counter = 0
|
60
|
+
keys = Array.new(rand(1..9)) { "key-#{counter += 1}" } # Keep this single digits so ordering works
|
61
|
+
keys.each_with_index do |key, i|
|
62
|
+
namespace.write_value(key, i)
|
63
|
+
end
|
64
|
+
|
65
|
+
saved_keys = account.kv_namespaces.find_by_id(namespace.id).keys.to_a
|
66
|
+
expect(saved_keys.length).to eq keys.length
|
67
|
+
saved_keys.each_with_index do |key, i|
|
68
|
+
expect(key.name).to eq keys[i]
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -1,23 +1,25 @@
|
|
1
1
|
|
2
2
|
RSpec.describe Cloudflare::Zones, order: :defined, timeout: 30 do
|
3
3
|
include_context Cloudflare::Zone
|
4
|
-
|
5
|
-
|
6
|
-
if
|
7
|
-
|
4
|
+
|
5
|
+
if ENV['CLOUDFLARE_TEST_ZONE_MANAGEMENT'] == 'true'
|
6
|
+
it "can delete existing domain if exists" do
|
7
|
+
if zone = zones.find_by_name(name)
|
8
|
+
expect(zone.delete).to be_success
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
it "can create a zone" do
|
13
|
+
zone = zones.create(name, account)
|
14
|
+
expect(zone.value).to include(:id)
|
8
15
|
end
|
9
16
|
end
|
10
|
-
|
11
|
-
it "can create zone" do
|
12
|
-
zone = zones.create(name, account)
|
13
|
-
expect(zone.value).to include(:id)
|
14
|
-
end
|
15
|
-
|
17
|
+
|
16
18
|
it "can list zones" do
|
17
19
|
matching_zones = zones.select{|zone| zone.name == name}
|
18
20
|
expect(matching_zones).to_not be_empty
|
19
21
|
end
|
20
|
-
|
22
|
+
|
21
23
|
it "can get zone by name" do
|
22
24
|
found_zone = zones.find_by_name(name)
|
23
25
|
expect(found_zone.name).to be == name
|
data/spec/spec_helper.rb
CHANGED
@@ -1,3 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
AUTH_EMAIL = ENV['CLOUDFLARE_EMAIL']
|
4
|
+
AUTH_KEY = ENV['CLOUDFLARE_KEY']
|
5
|
+
|
6
|
+
if AUTH_EMAIL.nil? || AUTH_EMAIL.empty? || AUTH_KEY.nil? || AUTH_KEY.empty?
|
7
|
+
puts 'Please make sure you have defined CLOUDFLARE_EMAIL and CLOUDFLARE_KEY in your environment'
|
8
|
+
puts 'You can also specify CLOUDFLARE_ZONE_NAME to test with your own zone and'
|
9
|
+
puts 'CLOUDFLARE_ACCOUNT_ID to use a specific account'
|
10
|
+
exit(1)
|
11
|
+
end
|
12
|
+
|
13
|
+
ACCOUNT_ID = ENV['CLOUDFLARE_ACCOUNT_ID']
|
14
|
+
NAMES = ['testing', 'horse', 'cat', 'dog', 'fish', 'dolphin', 'lion', 'tiger'].freeze
|
15
|
+
JOB_ID = ENV.fetch('TRAVIS_JOB_ID', 0).to_i
|
16
|
+
ZONE_NAME = ENV['CLOUDFLARE_ZONE_NAME'] || "#{NAMES[JOB_ID % NAMES.size]}.com"
|
1
17
|
|
2
18
|
require 'covered/rspec'
|
3
19
|
require 'async/rspec'
|
@@ -5,18 +21,30 @@ require 'async/rspec'
|
|
5
21
|
require 'cloudflare/rspec/connection'
|
6
22
|
require 'cloudflare/zones'
|
7
23
|
|
8
|
-
RSpec.shared_context Cloudflare::
|
24
|
+
RSpec.shared_context Cloudflare::Account do
|
9
25
|
include_context Cloudflare::RSpec::Connection
|
10
|
-
|
11
|
-
let(:
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
26
|
+
|
27
|
+
let(:account) do
|
28
|
+
if ACCOUNT_ID
|
29
|
+
connection.accounts.find_by_id(ACCOUNT_ID)
|
30
|
+
else
|
31
|
+
connection.accounts.first
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
RSpec.shared_context Cloudflare::Zone do
|
38
|
+
include_context Cloudflare::Account
|
39
|
+
|
40
|
+
let(:job_id) { JOB_ID }
|
41
|
+
let(:names) { NAMES.dup }
|
42
|
+
let(:name) { ZONE_NAME.dup }
|
43
|
+
|
16
44
|
let(:zones) {connection.zones}
|
17
|
-
|
45
|
+
|
18
46
|
let(:zone) {@zone = zones.find_by_name(name) || zones.create(name, account)}
|
19
|
-
|
47
|
+
|
20
48
|
# after do
|
21
49
|
# if defined? @zone
|
22
50
|
# @zone.delete
|
@@ -31,4 +59,27 @@ RSpec.configure do |config|
|
|
31
59
|
config.expect_with :rspec do |c|
|
32
60
|
c.syntax = :expect
|
33
61
|
end
|
62
|
+
|
63
|
+
disabled_specs = {}
|
64
|
+
|
65
|
+
# Check for features the current account has enabled
|
66
|
+
Cloudflare.connect(key: AUTH_KEY, email: AUTH_EMAIL) do |conn|
|
67
|
+
begin
|
68
|
+
account = if ACCOUNT_ID
|
69
|
+
conn.accounts.find_by_id(ACCOUNT_ID)
|
70
|
+
else
|
71
|
+
conn.accounts.first
|
72
|
+
end
|
73
|
+
account.kv_namespaces.to_a
|
74
|
+
rescue Cloudflare::RequestError => e
|
75
|
+
if e.message.include?('your account is not permitted')
|
76
|
+
puts 'Disabling KV specs due to no access'
|
77
|
+
disabled_specs[:kv_spec] = true
|
78
|
+
else
|
79
|
+
raise
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
config.filter_run_excluding disabled_specs unless disabled_specs.empty?
|
34
85
|
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: 4.0
|
4
|
+
version: 4.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Marcin Prokop
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2019-
|
12
|
+
date: 2019-04-03 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: async-rest
|
@@ -113,8 +113,12 @@ files:
|
|
113
113
|
- lib/cloudflare.rb
|
114
114
|
- lib/cloudflare/accounts.rb
|
115
115
|
- lib/cloudflare/connection.rb
|
116
|
+
- lib/cloudflare/custom_hostname/ssl_attribute.rb
|
117
|
+
- lib/cloudflare/custom_hostname/ssl_attribute/settings.rb
|
118
|
+
- lib/cloudflare/custom_hostnames.rb
|
116
119
|
- lib/cloudflare/dns.rb
|
117
120
|
- lib/cloudflare/firewall.rb
|
121
|
+
- lib/cloudflare/kv/namespaces.rb
|
118
122
|
- lib/cloudflare/logs.rb
|
119
123
|
- lib/cloudflare/paginate.rb
|
120
124
|
- lib/cloudflare/representation.rb
|
@@ -122,8 +126,13 @@ files:
|
|
122
126
|
- lib/cloudflare/user.rb
|
123
127
|
- lib/cloudflare/version.rb
|
124
128
|
- lib/cloudflare/zones.rb
|
129
|
+
- spec/cloudflare/accounts_spec.rb
|
130
|
+
- spec/cloudflare/custom_hostname/ssl_attribute/settings_spec.rb
|
131
|
+
- spec/cloudflare/custom_hostname/ssl_attribute_spec.rb
|
132
|
+
- spec/cloudflare/custom_hostnames_spec.rb
|
125
133
|
- spec/cloudflare/dns_spec.rb
|
126
134
|
- spec/cloudflare/firewall_spec.rb
|
135
|
+
- spec/cloudflare/kv/namespaces_spec.rb
|
127
136
|
- spec/cloudflare/zone_spec.rb
|
128
137
|
- spec/spec_helper.rb
|
129
138
|
homepage: https://github.com/b4k3r/cloudflare
|
@@ -145,12 +154,17 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
145
154
|
- !ruby/object:Gem::Version
|
146
155
|
version: '0'
|
147
156
|
requirements: []
|
148
|
-
rubygems_version: 3.0.
|
157
|
+
rubygems_version: 3.0.3
|
149
158
|
signing_key:
|
150
159
|
specification_version: 4
|
151
160
|
summary: A Ruby wrapper for the Cloudflare API.
|
152
161
|
test_files:
|
162
|
+
- spec/cloudflare/accounts_spec.rb
|
163
|
+
- spec/cloudflare/custom_hostname/ssl_attribute/settings_spec.rb
|
164
|
+
- spec/cloudflare/custom_hostname/ssl_attribute_spec.rb
|
165
|
+
- spec/cloudflare/custom_hostnames_spec.rb
|
153
166
|
- spec/cloudflare/dns_spec.rb
|
154
167
|
- spec/cloudflare/firewall_spec.rb
|
168
|
+
- spec/cloudflare/kv/namespaces_spec.rb
|
155
169
|
- spec/cloudflare/zone_spec.rb
|
156
170
|
- spec/spec_helper.rb
|