cloudflare_client_rb 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +7 -0
  2. data/lib/cloudflare_client.rb +211 -0
  3. data/lib/cloudflare_client/certificate.rb +40 -0
  4. data/lib/cloudflare_client/organization.rb +26 -0
  5. data/lib/cloudflare_client/organization/access_rule.rb +76 -0
  6. data/lib/cloudflare_client/organization/invite.rb +53 -0
  7. data/lib/cloudflare_client/organization/member.rb +37 -0
  8. data/lib/cloudflare_client/organization/railgun.rb +79 -0
  9. data/lib/cloudflare_client/organization/role.rb +19 -0
  10. data/lib/cloudflare_client/railgun.rb +63 -0
  11. data/lib/cloudflare_client/version.rb +3 -0
  12. data/lib/cloudflare_client/virtual_dns_cluster.rb +133 -0
  13. data/lib/cloudflare_client/virtual_dns_cluster/analytic.rb +38 -0
  14. data/lib/cloudflare_client/zone.rb +129 -0
  15. data/lib/cloudflare_client/zone/analytics.rb +56 -0
  16. data/lib/cloudflare_client/zone/base.rb +9 -0
  17. data/lib/cloudflare_client/zone/custom_hostname.rb +86 -0
  18. data/lib/cloudflare_client/zone/custom_page.rb +28 -0
  19. data/lib/cloudflare_client/zone/custom_ssl.rb +62 -0
  20. data/lib/cloudflare_client/zone/dns.rb +66 -0
  21. data/lib/cloudflare_client/zone/firewall.rb +3 -0
  22. data/lib/cloudflare_client/zone/firewall/access_rule.rb +87 -0
  23. data/lib/cloudflare_client/zone/firewall/waf_package.rb +46 -0
  24. data/lib/cloudflare_client/zone/firewall/waf_package/base.rb +9 -0
  25. data/lib/cloudflare_client/zone/firewall/waf_package/rule.rb +46 -0
  26. data/lib/cloudflare_client/zone/firewall/waf_package/rule_group.rb +42 -0
  27. data/lib/cloudflare_client/zone/keyless_ssl.rb +56 -0
  28. data/lib/cloudflare_client/zone/log.rb +51 -0
  29. data/lib/cloudflare_client/zone/page_rule.rb +64 -0
  30. data/lib/cloudflare_client/zone/railgun_connections.rb +43 -0
  31. data/lib/cloudflare_client/zone/rate_limit.rb +73 -0
  32. data/lib/cloudflare_client/zone/ssl.rb +28 -0
  33. data/lib/cloudflare_client/zone/ssl/certificate_pack.rb +32 -0
  34. data/lib/cloudflare_client/zone/subscription.rb +55 -0
  35. metadata +76 -0
@@ -0,0 +1,56 @@
1
+ class CloudflareClient::Zone::Analytics < CloudflareClient::Zone::Base
2
+ ##
3
+ # zone analytics (free, pro, business, enterprise)
4
+
5
+ ##
6
+ # return dashboard data for a given zone or colo
7
+ def zone_dashboard
8
+ cf_get(path: "/zones/#{zone_id}/analytics/dashboard")
9
+ end
10
+
11
+ ##
12
+ # creturn analytics for colos for a time window.
13
+ # since and untill must be RFC 3339 timestamps
14
+ # TODO: support continuous
15
+ def colo_dashboard(since_ts: nil, until_ts: nil)
16
+ raise 'since_ts must be a valid timestamp' if since_ts.nil? || !date_rfc3339?(since_ts)
17
+ raise 'until_ts must be a valid timestamp' if until_ts.nil? || !date_rfc3339?(until_ts)
18
+
19
+ cf_get(path: "/zones/#{zone_id}/analytics/dashboard")
20
+ end
21
+
22
+ ##
23
+ # DNS analytics
24
+
25
+ ##
26
+ # return a table of analytics
27
+ def dns_table
28
+ cf_get(path: "/zones/#{zone_id}/dns_analytics/report")
29
+ end
30
+
31
+ ##
32
+ # return analytics by time
33
+ def dns_by_time(dimensions: [],
34
+ metrics: [],
35
+ sort: [],
36
+ filters: [],
37
+ since_ts: nil,
38
+ until_ts: nil,
39
+ limit: 100,
40
+ time_delta: 'hour')
41
+ # TODO: what are valid dimensions?
42
+ # TODO: what are valid metrics?
43
+ unless since_ts.nil?
44
+ raise 'since_ts must be a valid timestamp' unless date_rfc3339?(since_ts)
45
+ end
46
+ unless until_ts.nil?
47
+ raise 'until_ts must be a valid timestamp' unless date_rfc3339?(until_ts)
48
+ end
49
+
50
+ params = {limit: limit, time_delta: time_delta}
51
+ params['since'] = since_ts
52
+ params['until'] = until_ts
53
+
54
+ cf_get(path: "/zones/#{zone_id}/dns_analytics/report/bytime", params: params)
55
+ end
56
+ end
@@ -0,0 +1,9 @@
1
+ class CloudflareClient::Zone::Base < CloudflareClient::Zone
2
+ attr_reader :zone_id
3
+
4
+ def initialize(args)
5
+ @zone_id = args.delete(:zone_id)
6
+ id_check('zone_id', zone_id)
7
+ super
8
+ end
9
+ end
@@ -0,0 +1,86 @@
1
+ # https://api.cloudflare.com/#custom-hostname-for-a-zone-list-custom-hostnames
2
+ class CloudflareClient::Zone::CustomHostname < CloudflareClient::Zone::Base
3
+ VALID_METHODS = %w[http email cname].freeze
4
+ VALID_TYPES = ['read only', 'dv'].freeze
5
+ VALID_ORDERS = %w[ssl ssl_status].freeze
6
+ DEFAULT_SSL_PROPERTIES = { method: 'http', type: 'dv' }.freeze
7
+
8
+ ##
9
+ # create custom_hostname
10
+ # - :custom_metadata may only work for enterprise or better customers
11
+ # - :ssl has undocumented properties: 'custom_certificate' and 'custom_key', or can be nulled
12
+ def create(hostname:, ssl: DEFAULT_SSL_PROPERTIES, custom_metadata: {})
13
+ #FIXME: implement checks for the custom_metedata/find out of it's going to be exposed to anyone else
14
+ #"custom_metadata":{"origin_override":"hostname.zendesk.com"}
15
+ #"custom_metadata":{"hsts_enabled":"true"}
16
+ #"custom_metadata":{"hsts_enabled":"true","custom_maxage":value}
17
+ id_check('hostname', hostname)
18
+
19
+ if ssl && ssl[:method] && ssl[:type]
20
+ valid_value_check(:method, ssl[:method], VALID_METHODS)
21
+ valid_value_check(:type, ssl[:type], VALID_TYPES)
22
+ end
23
+
24
+ data = { hostname: hostname, ssl: ssl }
25
+ data[:custom_metadata] = custom_metadata unless custom_metadata.empty?
26
+
27
+ cf_post(path: "/zones/#{zone_id}/custom_hostnames", data: data)
28
+ end
29
+
30
+ ##
31
+ # list custom_hostnames
32
+ def list(hostname: nil, id: nil, page: 1, per_page: 50, order: 'ssl', direction: 'desc', ssl: 0)
33
+ raise 'cannot use both hostname and id' if hostname && id
34
+ valid_value_check(:order, order, VALID_ORDERS)
35
+ valid_value_check(:direction, direction, VALID_DIRECTIONS)
36
+ valid_value_check(:ssl, ssl, [0, 1])
37
+
38
+ params = {page: page, per_page: per_page, order: order, direction: direction, ssl: ssl}
39
+ params[:hostname] = hostname if hostname
40
+ params[:id] = id if id
41
+
42
+ cf_get(path: "/zones/#{zone_id}/custom_hostnames", params: params)
43
+ end
44
+
45
+ ##
46
+ # details of a custom hostname
47
+ def show(id:)
48
+ id_check('id', id)
49
+
50
+ cf_get(path: "/zones/#{zone_id}/custom_hostnames/#{id}")
51
+ end
52
+
53
+ ##
54
+ # update a custom hosntame
55
+ # https://api.cloudflare.com/#custom-hostname-for-a-zone-update-custom-hostname-configuration
56
+ def update(id:, ssl: {}, custom_metadata: nil)
57
+ id_check('id', id)
58
+
59
+ data = {}
60
+
61
+ if ssl && ssl[:method] && ssl[:type]
62
+ valid_value_check(:method, ssl[:method], VALID_METHODS)
63
+ valid_value_check(:type, ssl[:type], VALID_TYPES)
64
+ end
65
+
66
+ # Setting this to "null" requests removal of the attached certificate. We're
67
+ # using {} as the default value to denote "don't alter the SSL".
68
+ data[:ssl] = ssl unless ssl == {}
69
+
70
+ unless custom_metadata.nil?
71
+ raise 'custom_metadata must be an object' unless custom_metadata.is_a?(Hash)
72
+
73
+ data[:custom_metadata] = custom_metadata
74
+ end
75
+
76
+ cf_patch(path: "/zones/#{zone_id}/custom_hostnames/#{id}", data: data)
77
+ end
78
+
79
+ ##
80
+ # delete a custom hostname and ssl certs
81
+ def delete(id:)
82
+ id_check('id', id)
83
+
84
+ cf_delete(path: "/zones/#{zone_id}/custom_hostnames/#{id}")
85
+ end
86
+ end
@@ -0,0 +1,28 @@
1
+ class CloudflareClient::Zone::CustomPage < CloudflareClient::Zone::Base
2
+ ##
3
+ # Custom pages for a zone
4
+ ##
5
+ # custom_pages list all avaialble custom_pages
6
+ def list
7
+ cf_get(path: "/zones/#{zone_id}/custom_pages")
8
+ end
9
+
10
+ ##
11
+ # custom_page details
12
+ def show(id:)
13
+ raise 'id must not be nil' if id.nil?
14
+ cf_get(path: "/zones/#{zone_id}/custom_pages/#{id}")
15
+ end
16
+
17
+ ##
18
+ # update_custom_page
19
+ def update(id:, url:, state:)
20
+ id_check('id', id)
21
+ id_check('url', url)
22
+ raise 'state must be either default | customized' unless %w[default customized].include?(state)
23
+
24
+ data = {url: url, state: state}
25
+
26
+ cf_put(path: "/zones/#{zone_id}/custom_pages/#{id}", data: data)
27
+ end
28
+ end
@@ -0,0 +1,62 @@
1
+ class CloudflareClient::Zone::CustomSSL < CloudflareClient::Zone::Base
2
+ VALID_ORDERS = %w[status issuer priority expires_on].freeze
3
+
4
+ ##
5
+ # Custom SSL for a zone
6
+
7
+ ##
8
+ # create custom ssl for a zone
9
+ def create(certificate:, private_key:, bundle_method: nil)
10
+ id_check('certificate', certificate)
11
+ id_check('private_key', private_key)
12
+ bundle_method_check(bundle_method) unless bundle_method.nil?
13
+ # TODO: validate the cert/key using openssl? Could be difficult if they are
14
+ # privately generated
15
+ data = {certificate: certificate, private_key: private_key}
16
+ data[:bundle_method] = bundle_method unless bundle_method.nil?
17
+ cf_post(path: "/zones/#{zone_id}/custom_certificates", data: data)
18
+ end
19
+
20
+ ##
21
+ # list custom ssl configurations
22
+ def list(page: 1, per_page: 50, order: 'priority', direction: 'asc', match: 'all')
23
+ raise ("order must be one of #{VALID_ORDERS}") unless VALID_ORDERS.include?(order)
24
+ raise ('direction must be asc || desc') unless (direction == 'asc' || direction == 'desc')
25
+ raise ('match must be all || any') unless (match == 'any' || match == 'all')
26
+ params = {page: page, per_page: per_page}
27
+ params[:match] = match
28
+ params[:direction] = direction
29
+ cf_get(path: "/zones/#{zone_id}/custom_certficates", params: params)
30
+ end
31
+
32
+ ##
33
+ # details of a single config
34
+ def show(configuration_id:)
35
+ raise 'ssl configuration id required' if configuration_id.nil?
36
+ cf_get(path: "/zones/#{zone_id}/custom_certificates/#{configuration_id}")
37
+ end
38
+
39
+ ##
40
+ # updates a custom ssl record
41
+ def update(id:, private_key: nil, certificate: nil, bundle_method: nil)
42
+ id_check('id', id)
43
+ id_check('private_key must be provided') if private_key.nil?
44
+ bundle_method_check(bundle_method)
45
+ data = {private_key: private_key, certificate: certificate, bundle_method: bundle_method}
46
+ cf_patch(path: "/zones/#{zone_id}/custom_certificates/#{id}", data: data)
47
+ end
48
+
49
+ ##
50
+ # re-prioritize ssl certs data = [{id: "cert_id", priority: 2}, {id: "cert_id", priority: 1}]
51
+ def prioritize(data: [])
52
+ raise 'must provide an array of certifiates and priorities' unless data.is_a?(Array) && !data.empty?
53
+ cf_put(path: "/zones/#{zone_id}/custom_certificates/prioritize", data: data)
54
+ end
55
+
56
+ ##
57
+ # delete a custom ssl cert
58
+ def delete(id:)
59
+ id_check('id', id)
60
+ cf_delete(path: "/zones/#{zone_id}/custom_certificates/#{id}")
61
+ end
62
+ end
@@ -0,0 +1,66 @@
1
+ class CloudflareClient::Zone::DNS < CloudflareClient::Zone::Base
2
+ VALID_TYPES = ['A', 'AAAA', 'CNAME', 'TXT', 'SRV', 'LOC', 'MX', 'NS', 'SPF', 'read only'].freeze
3
+
4
+ ##
5
+ # DNS methods
6
+
7
+ ##
8
+ # Create a dns record
9
+ def create(name:, type:, content:, ttl: nil, proxied: nil)
10
+ raise ("type must be one of #{VALID_TYPES.flatten}") unless VALID_TYPES.include?(type)
11
+ data = {name: name, type: type, content: content}
12
+ cf_post(path: "/zones/#{zone_id}/dns_records", data: data)
13
+ end
14
+
15
+ ##
16
+ # list/search for dns records in a given zone
17
+ def list(name: nil, content: nil, per_page: 50, page_no: 1, order: 'type', match: 'all', type: nil)
18
+ raise('match must be either all | any') unless %w[all any].include?(match)
19
+ params = {per_page: per_page, page: page_no, order: order}
20
+ params[:name] = name unless name.nil?
21
+ params[:content] = content unless content.nil?
22
+ params[:type] = type unless type.nil?
23
+ cf_get(path: "/zones/#{zone_id}/dns_records", params: params)
24
+ end
25
+
26
+ ##
27
+ # details for a given dns_record
28
+ def show(id:)
29
+ id_check('dns record id', id)
30
+ cf_get(path: "/zones/#{zone_id}/dns_records/#{id}")
31
+ end
32
+
33
+ ##
34
+ # update a dns record.
35
+ # zone_id, id, type, and name are all required. ttl and proxied are optional
36
+ def update(id:, type:, name:, content:, ttl: nil, proxied: nil)
37
+ id_check('dns record id', id)
38
+ id_check('dns record type', type)
39
+ id_check('dns record name', name)
40
+ id_check('dns record content', content)
41
+ raise('must suply type, name, and content') if (type.nil? || name.nil? || content.nil?)
42
+ data = {type: type, name: name, content: content}
43
+ data[:ttl] = ttl unless ttl.nil?
44
+ data[:proxied] = proxied unless proxied.nil?
45
+ cf_put(path: "/zones/#{zone_id}/dns_records/#{id}", data: data)
46
+ end
47
+
48
+ ##
49
+ # delete a dns record
50
+ # id is required. ttl and proxied are optional
51
+ def delete(id:)
52
+ id_check('id', id)
53
+ cf_delete(path: "/zones/#{zone_id}/dns_records/#{id}")
54
+ end
55
+
56
+ ##
57
+ # import a BIND formatted zone file
58
+ # def import_zone_file(path_to_file: nil)
59
+ # # FIXME: not tested
60
+ # raise("full path of file to import") if path_to_file.nil?
61
+ # # TODO: ensure that this is a bind file?
62
+ # raise("import file_name does not exist") if File.exists?(path_to_file)
63
+ # data = { file: Faraday::UploadIO.new(path_to_file, 'multipart/form-data') }
64
+ # cf_post(path: "/v4/zones/#{zone_id}/dns_records/import", data: data)
65
+ # end
66
+ end
@@ -0,0 +1,3 @@
1
+ class CloudflareClient::Zone::Firewall < CloudflareClient::Zone::Base
2
+ Dir[File.expand_path('../firewall/*.rb', __FILE__)].each {|f| require f}
3
+ end
@@ -0,0 +1,87 @@
1
+ class CloudflareClient::Zone::Firewall::AccessRule < CloudflareClient::Zone::Firewall
2
+ VALID_MODES = %w[block challenge whitelist].freeze
3
+ VALID_SCOPE_TYPES = %w[user organization zone].freeze
4
+ VALID_CONFIG_TARGETS = %w[ip ip_range country].freeze
5
+ VALID_ORDERS = %w[scope_type configuration_target configuration_value mode].freeze
6
+ VALID_CASCADES = %w[none basic aggressive].freeze
7
+
8
+ ##
9
+ # firewall_access_rules_for_a_zone
10
+ def list(notes: nil, mode: nil, match: nil, scope_type: nil, configuration_value: nil, order: nil, page: 1, per_page: 50, configuration_target: nil, direction: 'desc')
11
+ params = {page: page, per_page: per_page}
12
+ params[:notes] = notes unless notes.nil?
13
+ params[:configuration_value] = configuration_value unless configuration_value.nil?
14
+
15
+ unless mode.nil?
16
+ valid_value_check(:mode, mode, VALID_MODES)
17
+ params[:mode] = mode
18
+ end
19
+
20
+ unless match.nil?
21
+ valid_value_check(:match, match, VALID_MATCHES)
22
+ params[:match] = match
23
+ end
24
+
25
+ unless scope_type.nil?
26
+ valid_value_check(:scope_type, scope_type, VALID_SCOPE_TYPES)
27
+ params[:scope_type] = scope_type
28
+ end
29
+
30
+ unless configuration_target.nil?
31
+ valid_value_check(:configuration_target, configuration_target, VALID_CONFIG_TARGETS)
32
+ params[:configuration_target] = configuration_target
33
+ end
34
+
35
+ unless direction.nil?
36
+ valid_value_check(:direction, direction, VALID_DIRECTIONS)
37
+ params[:direction] = direction
38
+ end
39
+
40
+ unless order.nil?
41
+ valid_value_check(:order, order, VALID_ORDERS)
42
+ params[:order] = order
43
+ end
44
+
45
+ cf_get(path: "/zones/#{zone_id}/firewall/access_rules/rules", params: params)
46
+ end
47
+
48
+ ##
49
+ # create firewall access rule
50
+ def create(mode:, configuration:, notes: nil)
51
+ valid_value_check(:mode, mode, VALID_MODES)
52
+ if configuration.is_a?(Hash)
53
+ unless configuration.keys.map(&:to_sym).sort == [:target, :value]
54
+ raise 'configuration must contain valid a valid target and value'
55
+ end
56
+ else
57
+ raise 'configuration must be a valid configuration object'
58
+ end
59
+
60
+ data = {mode: mode, configuration: configuration}
61
+ data[:notes] = notes unless notes.nil?
62
+
63
+ cf_post(path: "/zones/#{zone_id}/firewall/access_rules/rules", data: data)
64
+ end
65
+
66
+ ##
67
+ # updates firewall_access_rule
68
+ def update(id:, mode: nil, notes: nil)
69
+ id_check('id', id)
70
+ valid_value_check(:mode, mode, VALID_MODES) unless mode.nil?
71
+
72
+ data = {}
73
+ data[:mode] = mode unless mode.nil?
74
+ data[:notes] = notes unless notes.nil?
75
+
76
+ cf_patch(path: "/zones/#{zone_id}/firewall/access_rules/rules/#{id}", data: data)
77
+ end
78
+
79
+ ##
80
+ # delete a firewall access rule
81
+ def delete(id:, cascade: 'none')
82
+ id_check('id', id)
83
+ valid_value_check(:cascade, cascade, VALID_CASCADES)
84
+
85
+ cf_delete(path: "/zones/#{zone_id}/firewall/access_rules/rules/#{id}")
86
+ end
87
+ end
@@ -0,0 +1,46 @@
1
+ class CloudflareClient::Zone::Firewall::WAFPackage < CloudflareClient::Zone::Firewall
2
+ require_relative './waf_package/base.rb'
3
+ Dir[File.expand_path('../waf_package/*.rb', __FILE__)].each {|f| require f}
4
+
5
+ VALID_ORDERS = %w[status name].freeze
6
+ VALID_SENSITIVITIES = %w[high low off].freeze
7
+ VALID_ACTION_MODES = %w[simulate block challenge].freeze
8
+
9
+ ##
10
+ # lists waf_rule_packages
11
+ def list(name: nil, page: 1, per_page: 50, order: 'status', direction: 'desc', match: 'all')
12
+ params = {page: page, per_page: per_page}
13
+ params[:name] = name unless name.nil?
14
+
15
+ valid_value_check(:order, order, VALID_ORDERS)
16
+ params[:order] = order
17
+
18
+ valid_value_check(:direction, direction, VALID_DIRECTIONS)
19
+ params[:direction] = direction
20
+
21
+ valid_value_check(:match, match, VALID_MATCHES)
22
+ params[:match] = match
23
+
24
+ cf_get(path: "/zones/#{zone_id}/firewall/waf/packages", params: params)
25
+ end
26
+
27
+ ##
28
+ # shows details of a single package
29
+ def show(id:)
30
+ id_check('id', id)
31
+
32
+ cf_get(path: "/zones/#{zone_id}/firewall/waf/packages/#{id}")
33
+ end
34
+
35
+ ##
36
+ # changes the sensitivity and action for an anomaly detection type WAF rule package
37
+ def update(id:, sensitivity: 'high', action_mode: 'challange')
38
+ id_check('id', id)
39
+ valid_value_check(:sensitivity, sensitivity, VALID_SENSITIVITIES)
40
+ valid_value_check(:action_mode, action_mode, VALID_ACTION_MODES)
41
+
42
+ data = {sensitivity: sensitivity, action_mode: action_mode}
43
+
44
+ cf_patch(path: "/zones/#{zone_id}/firewall/waf/packages/#{id}", data: data)
45
+ end
46
+ end