From 168e52f97821c84d33e3987c5cba3f8b3e210712 Mon Sep 17 00:00:00 2001 From: David Rosenbloom Date: Mon, 24 Jul 2017 17:17:59 -0400 Subject: [PATCH 01/29] Initial WAFRules. Tabs replaced. --- .gitignore | 4 + lib/cloudflare/connection.rb | 50 ++++---- lib/cloudflare/version.rb | 2 +- lib/cloudflare/zone.rb | 219 +++++++++++++++++++++-------------- 4 files changed, 164 insertions(+), 111 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7c64ce0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +t/ +Gemfile* +*.gem +tags diff --git a/lib/cloudflare/connection.rb b/lib/cloudflare/connection.rb index fd4743d..a4c3618 100644 --- a/lib/cloudflare/connection.rb +++ b/lib/cloudflare/connection.rb @@ -27,29 +27,29 @@ require_relative 'response' module Cloudflare - DEFAULT_URL = "https://api.cloudflare.com/client/v4/" - TIMEOUT = 10 # Default is 5 seconds - - class Resource < RestClient::Resource - # @param api_key [String] `X-Auth-Key` or `X-Auth-User-Service-Key` if no email provided. - # @param email [String] `X-Auth-Email`, your email address for the account. - def initialize(url = DEFAULT_URL, key: nil, email: nil, **options) - headers = options[:headers] || {} - - if email.nil? - headers['X-Auth-User-Service-Key'] = key - else - headers['X-Auth-Key'] = key - headers['X-Auth-Email'] = email - end - - # Convert HTTP API responses to our own internal response class: - super(url, headers: headers, accept: 'application/json', **options) do |response| - Response.new(response.request.url, response.body) - end - end - end - - class Connection < Resource - end + DEFAULT_URL = "https://api.cloudflare.com/client/v4/" + TIMEOUT = 10 # Default is 5 seconds + + class Resource < RestClient::Resource + # @param api_key [String] `X-Auth-Key` or `X-Auth-User-Service-Key` if no email provided. + # @param email [String] `X-Auth-Email`, your email address for the account. + def initialize(url = DEFAULT_URL, key: nil, email: nil, **options) + headers = options[:headers] || {} + + if email.nil? + headers['X-Auth-User-Service-Key'] = key + else + headers['X-Auth-Key'] = key + headers['X-Auth-Email'] = email + end + + # Convert HTTP API responses to our own internal response class: + super(url, headers: headers, accept: 'application/json', **options) do |response| + Response.new(response.request.url, response.body) + end + end + end + + class Connection < Resource + end end diff --git a/lib/cloudflare/version.rb b/lib/cloudflare/version.rb index 24392ba..eb5119b 100644 --- a/lib/cloudflare/version.rb +++ b/lib/cloudflare/version.rb @@ -20,5 +20,5 @@ # THE SOFTWARE. module Cloudflare - VERSION = '3.0.0' + VERSION = '3.0.2' end diff --git a/lib/cloudflare/zone.rb b/lib/cloudflare/zone.rb index 5918247..96c84c4 100644 --- a/lib/cloudflare/zone.rb +++ b/lib/cloudflare/zone.rb @@ -22,89 +22,138 @@ require_relative 'connection' module Cloudflare - class Connection < Resource - def zones - @zones ||= Zones.new(concat_urls(url, 'zones'), options) - end - end - - class DNSRecord < Resource - def initialize(url, record = nil, **options) - super(url, **options) - - @record = record || self.get.result - end - - attr :record - - def to_s - "#{@record[:name]} #{@record[:type]} #{@record[:content]}" - end - end - - class DNSRecords < Resource - def initialize(url, zone, **options) - super(url, **options) - - @zone = zone - end - - attr :zone - - def all - self.get.results.map{|record| DNSRecord.new(concat_urls(url, record[:id]), record, **options)} - end - - def find_by_name(name) - response = self.get(params: {name: name}) - - unless response.empty? - record = response.results.first - - DNSRecord.new(concat_urls(url, record[:id]), record, **options) - end - end - - def find_by_id(id) - DNSRecord.new(concat_urls(url, id), **options) - end - end - - class Zone < Resource - def initialize(url, record = nil, **options) - super(url, **options) - - @record = record || self.get.result - end - - attr :record - - def dns_records - @dns_records ||= DNSRecords.new(concat_urls(url, 'dns_records'), self, **options) - end - - def to_s - @record[:name] - end - end - - class Zones < Resource - def all - self.get.results.map{|record| Zone.new(concat_urls(url, record[:id]), record, **options)} - end - - def find_by_name(name) - record = self.get(params: {name: name}).result - - unless response.empty? - record = response.results.first - - Zone.new(concat_urls(url, record[:id]), record, **options) - end - end - - def find_by_id(id) - Zone.new(concat_urls(url, id), **options) - end - end + class Connection < Resource + def zones + @zones ||= Zones.new(concat_urls(url, 'zones'), options) + end + end + + class DNSRecord < Resource + def initialize(url, record = nil, **options) + super(url, **options) + + @record = record || self.get.result + end + + attr :record + + def to_s + "#{@record[:name]} #{@record[:type]} #{@record[:content]}" + end + end + + class DNSRecords < Resource + def initialize(url, zone, **options) + super(url, **options) + + @zone = zone + end + + attr :zone + + def all + self.get.results.map{|record| DNSRecord.new(concat_urls(url, record[:id]), record, **options)} + end + + def find_by_name(name) + response = self.get(params: {name: name}) + + unless response.empty? + record = response.results.first + + DNSRecord.new(concat_urls(url, record[:id]), record, **options) + end + end + + def find_by_id(id) + DNSRecord.new(concat_urls(url, id), **options) + end + end +################# + class WAFAccessRule < Resource + def initialize(url, record = nil, **options) + super(url, **options) + + @record = record || self.get.result + end + + attr :record + + def to_s + "#{@record[:name]} #{@record[:type]} #{@record[:content]}" + end + end + + class WAFAccessRules < Resource + def initialize(url, zone, **options) + super(url, **options) + + @zone = zone + end + + attr :zone + + def all + self.get.results.map{|record| WAFAccessRule.new(concat_urls(url, record[:id]), record, **options)} + end + + def find_by_name(name) + response = self.get(params: {name: name}) + + unless response.empty? + record = response.results.first + + WAFAccessRule.new(concat_urls(url, record[:id]), record, **options) + end + end + + def find_by_id(id) + WAFAccessRule.new(concat_urls(url, id), **options) + end + end + + +################## + class Zone < Resource + def initialize(url, record = nil, **options) + super(url, **options) + + @record = record || self.get.result + end + + attr :record + + def dns_records + @dns_records ||= DNSRecords.new(concat_urls(url, 'dns_records'), self, **options) + end + + def waf_access_rules + @waf_access_rules ||= WAFAccessRules.new(concat_urls(url, 'firewall/access_rules/rules'), self, **options) + end + + + def to_s + @record[:name] + end + end + + class Zones < Resource + def all + self.get.results.map{|record| Zone.new(concat_urls(url, record[:id]), record, **options)} + end + + def find_by_name(name) + record = self.get(params: {name: name}).result + + unless response.empty? + record = response.results.first + + Zone.new(concat_urls(url, record[:id]), record, **options) + end + end + + def find_by_id(id) + Zone.new(concat_urls(url, id), **options) + end + end end From 54250d40f76ab6701ec9f50944db01a752fbfe14 Mon Sep 17 00:00:00 2001 From: David Rosenbloom Date: Mon, 24 Jul 2017 17:56:47 -0400 Subject: [PATCH 02/29] WIP: begin to page WAF results. --- cloudflare.gemspec | 1 + lib/cloudflare/version.rb | 2 +- lib/cloudflare/zone.rb | 6 ++++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/cloudflare.gemspec b/cloudflare.gemspec index 72652b2..823f99c 100644 --- a/cloudflare.gemspec +++ b/cloudflare.gemspec @@ -24,4 +24,5 @@ Gem::Specification.new do |spec| spec.add_development_dependency "rspec", "~> 3.6" spec.add_development_dependency "bundler", "~> 1.3" spec.add_development_dependency "rake" + spec.add_development_dependency "byebug" end diff --git a/lib/cloudflare/version.rb b/lib/cloudflare/version.rb index eb5119b..cee9cc2 100644 --- a/lib/cloudflare/version.rb +++ b/lib/cloudflare/version.rb @@ -20,5 +20,5 @@ # THE SOFTWARE. module Cloudflare - VERSION = '3.0.2' + VERSION = '3.0.3' end diff --git a/lib/cloudflare/zone.rb b/lib/cloudflare/zone.rb index 96c84c4..f19bdbd 100644 --- a/lib/cloudflare/zone.rb +++ b/lib/cloudflare/zone.rb @@ -18,7 +18,7 @@ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. - +# require 'byebug' require_relative 'connection' module Cloudflare @@ -94,6 +94,8 @@ def initialize(url, zone, **options) attr :zone def all + # byebug + # ?scope_type=organization&mode=block&per_page=100&page=#{page}\ self.get.results.map{|record| WAFAccessRule.new(concat_urls(url, record[:id]), record, **options)} end @@ -128,7 +130,7 @@ def dns_records end def waf_access_rules - @waf_access_rules ||= WAFAccessRules.new(concat_urls(url, 'firewall/access_rules/rules'), self, **options) + @waf_access_rules ||= WAFAccessRules.new(concat_urls(url, 'firewall/access_rules/rules?scope_type=organization&mode=block&per_page=100'), self, **options) end From 18d9c6724adb80c16133909d30e9575efe28df11 Mon Sep 17 00:00:00 2001 From: David Rosenbloom Date: Tue, 25 Jul 2017 12:04:31 -0400 Subject: [PATCH 03/29] Added paging for WAFRules. --- .gitignore | 1 + lib/cloudflare/zone.rb | 26 +++++++++++++++++++------- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 7c64ce0..6741120 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ t/ Gemfile* *.gem tags +.byebug_history diff --git a/lib/cloudflare/zone.rb b/lib/cloudflare/zone.rb index f19bdbd..cd07fd8 100644 --- a/lib/cloudflare/zone.rb +++ b/lib/cloudflare/zone.rb @@ -70,7 +70,7 @@ def find_by_id(id) end end ################# - class WAFAccessRule < Resource + class WAFRule < Resource def initialize(url, record = nil, **options) super(url, **options) @@ -84,7 +84,7 @@ def to_s end end - class WAFAccessRules < Resource + class WAFRules < Resource def initialize(url, zone, **options) super(url, **options) @@ -96,7 +96,7 @@ def initialize(url, zone, **options) def all # byebug # ?scope_type=organization&mode=block&per_page=100&page=#{page}\ - self.get.results.map{|record| WAFAccessRule.new(concat_urls(url, record[:id]), record, **options)} + self.get.results.map{|record| WAFRule.new(concat_urls(url, record[:id]), record, **options)} end def find_by_name(name) @@ -105,12 +105,12 @@ def find_by_name(name) unless response.empty? record = response.results.first - WAFAccessRule.new(concat_urls(url, record[:id]), record, **options) + WAFRule.new(concat_urls(url, record[:id]), record, **options) end end def find_by_id(id) - WAFAccessRule.new(concat_urls(url, id), **options) + WAFRule.new(concat_urls(url, id), **options) end end @@ -129,8 +129,20 @@ def dns_records @dns_records ||= DNSRecords.new(concat_urls(url, 'dns_records'), self, **options) end - def waf_access_rules - @waf_access_rules ||= WAFAccessRules.new(concat_urls(url, 'firewall/access_rules/rules?scope_type=organization&mode=block&per_page=100'), self, **options) + def waf_rules + page = 0 + ruleset = [] + page_size = 100 + + @waf_rules ||= { + loop do # fetch and aggregate all pages + page += 1 + rules = WAFRules.new(concat_urls(url, "firewall/access_rules/rules?scope_type=organization&mode=block&per_page=#{page_size}&page=#{page}"), self, **options) + ruleset += rules + break if rules.size < page_size + end + ruleset + } end From 2cabecbbc42977d7ba953cea9b4d8e4e09b313ee Mon Sep 17 00:00:00 2001 From: David Rosenbloom Date: Tue, 25 Jul 2017 14:04:11 -0400 Subject: [PATCH 04/29] Updated WAF to Firewall, _rules to _blocks for greater naming accuracy. --- lib/cloudflare/version.rb | 2 +- lib/cloudflare/zone.rb | 40 +++++++++++++++++++++------------------ 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/lib/cloudflare/version.rb b/lib/cloudflare/version.rb index cee9cc2..03a23d2 100644 --- a/lib/cloudflare/version.rb +++ b/lib/cloudflare/version.rb @@ -20,5 +20,5 @@ # THE SOFTWARE. module Cloudflare - VERSION = '3.0.3' + VERSION = '3.0.4' end diff --git a/lib/cloudflare/zone.rb b/lib/cloudflare/zone.rb index cd07fd8..e3866e7 100644 --- a/lib/cloudflare/zone.rb +++ b/lib/cloudflare/zone.rb @@ -18,7 +18,9 @@ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -# require 'byebug' + +# added firewall rules support: david rosenbloom|davidr@artifactory.com|artifactory +# require_relative 'connection' module Cloudflare @@ -69,8 +71,9 @@ def find_by_id(id) DNSRecord.new(concat_urls(url, id), **options) end end -################# - class WAFRule < Resource + + # Firewall Access Rules + class FirewallRule < Resource def initialize(url, record = nil, **options) super(url, **options) @@ -84,7 +87,7 @@ def to_s end end - class WAFRules < Resource + class FirewallRules < Resource def initialize(url, zone, **options) super(url, **options) @@ -94,9 +97,7 @@ def initialize(url, zone, **options) attr :zone def all - # byebug - # ?scope_type=organization&mode=block&per_page=100&page=#{page}\ - self.get.results.map{|record| WAFRule.new(concat_urls(url, record[:id]), record, **options)} + self.get.results.map{|record| FirewallRule.new(concat_urls(url, record[:id]), record, **options)} end def find_by_name(name) @@ -105,17 +106,15 @@ def find_by_name(name) unless response.empty? record = response.results.first - WAFRule.new(concat_urls(url, record[:id]), record, **options) + FirewallRule.new(concat_urls(url, record[:id]), record, **options) end end def find_by_id(id) - WAFRule.new(concat_urls(url, id), **options) + FirewallRule.new(concat_urls(url, id), **options) end end - -################## class Zone < Resource def initialize(url, record = nil, **options) super(url, **options) @@ -129,20 +128,25 @@ def dns_records @dns_records ||= DNSRecords.new(concat_urls(url, 'dns_records'), self, **options) end - def waf_rules + def firewall_blocks page = 0 - ruleset = [] page_size = 100 + ruleset = nil - @waf_rules ||= { + @fw_rules ||= ( loop do # fetch and aggregate all pages page += 1 - rules = WAFRules.new(concat_urls(url, "firewall/access_rules/rules?scope_type=organization&mode=block&per_page=#{page_size}&page=#{page}"), self, **options) - ruleset += rules - break if rules.size < page_size + rules = FirewallRules.new(concat_urls(url, "firewall/access_rules/rules?scope_type=organization&mode=block&per_page=#{page_size}&page=#{page}"), self, **options) + ruleset = + if ruleset.nil? + rules + else + ruleset += rules + end + break if rules.all.size < page_size end ruleset - } + ) end From 340f7739a872c163463b7a5674a2b195eb90fec2 Mon Sep 17 00:00:00 2001 From: David Rosenbloom Date: Tue, 25 Jul 2017 16:09:05 -0400 Subject: [PATCH 05/29] Genericized firewall_blocks to firewall_rules(mode); added firewalled_ips. --- lib/cloudflare/zone.rb | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/cloudflare/zone.rb b/lib/cloudflare/zone.rb index e3866e7..a9f1d5a 100644 --- a/lib/cloudflare/zone.rb +++ b/lib/cloudflare/zone.rb @@ -72,7 +72,7 @@ def find_by_id(id) end end - # Firewall Access Rules + # Firewall Rules class FirewallRule < Resource def initialize(url, record = nil, **options) super(url, **options) @@ -83,7 +83,7 @@ def initialize(url, record = nil, **options) attr :record def to_s - "#{@record[:name]} #{@record[:type]} #{@record[:content]}" + "#{@record[:configuration][:value]} - #{@record[:mode]} - #{@record[:notes]}" end end @@ -128,7 +128,7 @@ def dns_records @dns_records ||= DNSRecords.new(concat_urls(url, 'dns_records'), self, **options) end - def firewall_blocks + def firewall_rules(mode) page = 0 page_size = 100 ruleset = nil @@ -136,7 +136,7 @@ def firewall_blocks @fw_rules ||= ( loop do # fetch and aggregate all pages page += 1 - rules = FirewallRules.new(concat_urls(url, "firewall/access_rules/rules?scope_type=organization&mode=block&per_page=#{page_size}&page=#{page}"), self, **options) + rules = FirewallRules.new(concat_urls(url, "firewall/access_rules/rules?scope_type=organization&mode=#{mode}&per_page=#{page_size}&page=#{page}"), self, **options) ruleset = if ruleset.nil? rules @@ -149,6 +149,10 @@ def firewall_blocks ) end + def firewalled_ips(mode) + firewall_rules(mode).all.collect {|r| r.record[:configuration][:value]} + end + def to_s @record[:name] From 687283ad8c4ded747c12dd7568c4bb02aa0eb44e Mon Sep 17 00:00:00 2001 From: denis Date: Wed, 26 Jul 2017 01:18:38 +0300 Subject: [PATCH 06/29] fix find_by_name for zones --- lib/cloudflare/zone.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cloudflare/zone.rb b/lib/cloudflare/zone.rb index 5918247..2295e28 100644 --- a/lib/cloudflare/zone.rb +++ b/lib/cloudflare/zone.rb @@ -94,7 +94,7 @@ def all end def find_by_name(name) - record = self.get(params: {name: name}).result + response = self.get(params: {name: name}) unless response.empty? record = response.results.first From 005274d491bf4890951234a4dc98cb6490c63bb8 Mon Sep 17 00:00:00 2001 From: David Rosenbloom Date: Thu, 27 Jul 2017 14:01:55 -0400 Subject: [PATCH 07/29] Fixed firewall_rules; filtered search on mode, ip. --- lib/cloudflare/zone.rb | 66 ++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 38 deletions(-) diff --git a/lib/cloudflare/zone.rb b/lib/cloudflare/zone.rb index a9f1d5a..0a15a01 100644 --- a/lib/cloudflare/zone.rb +++ b/lib/cloudflare/zone.rb @@ -22,7 +22,7 @@ # added firewall rules support: david rosenbloom|davidr@artifactory.com|artifactory # require_relative 'connection' - +require 'byebug' module Cloudflare class Connection < Resource def zones @@ -72,9 +72,9 @@ def find_by_id(id) end end - # Firewall Rules class FirewallRule < Resource def initialize(url, record = nil, **options) + # 0 - Rule init super(url, **options) @record = record || self.get.result @@ -89,6 +89,8 @@ def to_s class FirewallRules < Resource def initialize(url, zone, **options) + # 1 - Rules init + # byebug super(url, **options) @zone = zone @@ -96,29 +98,12 @@ def initialize(url, zone, **options) attr :zone - def all - self.get.results.map{|record| FirewallRule.new(concat_urls(url, record[:id]), record, **options)} - end - - def find_by_name(name) - response = self.get(params: {name: name}) - - unless response.empty? - record = response.results.first - - FirewallRule.new(concat_urls(url, record[:id]), record, **options) - end - end - - def find_by_id(id) - FirewallRule.new(concat_urls(url, id), **options) - end end class Zone < Resource def initialize(url, record = nil, **options) + # byebug super(url, **options) - @record = record || self.get.result end @@ -128,25 +113,30 @@ def dns_records @dns_records ||= DNSRecords.new(concat_urls(url, 'dns_records'), self, **options) end - def firewall_rules(mode) - page = 0 + def validate_args(mode, ip) + raise "Bad mode arg: #{mode}" if mode and !['block', 'whitelist', 'challenge'].include?(mode) + raise "Bad ip arg: #{ip}" if ip and !(ip =~ /[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*/) # TODO: add ranges, e.g. /24 + end + + def firewall_rules(mode = nil, ip = nil, notes = nil) + # 4 - rules request + validate_args(mode, ip) + fw_url ="firewall/access_rules/rules?scope_type=organization" + fw_url.concat("&mode=#{mode}") if mode + fw_url.concat("&configuration_value=#{ip}") if ip + fw_url.concat("¬es=#{notes}") if notes + page = 1 page_size = 100 - ruleset = nil - - @fw_rules ||= ( - loop do # fetch and aggregate all pages - page += 1 - rules = FirewallRules.new(concat_urls(url, "firewall/access_rules/rules?scope_type=organization&mode=#{mode}&per_page=#{page_size}&page=#{page}"), self, **options) - ruleset = - if ruleset.nil? - rules - else - ruleset += rules - end - break if rules.all.size < page_size - end - ruleset - ) + results = [] + + loop do # fetch and aggregate all pages + rules = FirewallRules.new(concat_urls(url, "#{fw_url}&per_page=#{page_size}&page=#{page}"), self, **options) + results += rules.get.results + break if results.size % page_size != 0 + page += 1 + end + + results.map{|record| FirewallRule.new(concat_urls(url, record[:id]), record, **options)} end def firewalled_ips(mode) From 59f6c34aba3ab60d092933e59890553a9dbb949e Mon Sep 17 00:00:00 2001 From: David Rosenbloom Date: Thu, 27 Jul 2017 14:36:37 -0400 Subject: [PATCH 08/29] Bumped version. --- lib/cloudflare/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cloudflare/version.rb b/lib/cloudflare/version.rb index 03a23d2..f9c1c88 100644 --- a/lib/cloudflare/version.rb +++ b/lib/cloudflare/version.rb @@ -20,5 +20,5 @@ # THE SOFTWARE. module Cloudflare - VERSION = '3.0.4' + VERSION = '3.1.0' end From 79930c802bbc6cc077f05973b0b8a4dd788ffa13 Mon Sep 17 00:00:00 2001 From: David Rosenbloom Date: Thu, 27 Jul 2017 14:44:52 -0400 Subject: [PATCH 09/29] Modified firewalled_ips. --- lib/cloudflare/zone.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cloudflare/zone.rb b/lib/cloudflare/zone.rb index 0a15a01..7b86350 100644 --- a/lib/cloudflare/zone.rb +++ b/lib/cloudflare/zone.rb @@ -139,8 +139,8 @@ def firewall_rules(mode = nil, ip = nil, notes = nil) results.map{|record| FirewallRule.new(concat_urls(url, record[:id]), record, **options)} end - def firewalled_ips(mode) - firewall_rules(mode).all.collect {|r| r.record[:configuration][:value]} + def firewalled_ips(rules) + rules.collect {|r| r.record[:configuration][:value]} end From 54553035fcd90be52ce0c23dd3120ecc9dca1ffb Mon Sep 17 00:00:00 2001 From: David Rosenbloom Date: Thu, 27 Jul 2017 15:49:54 -0400 Subject: [PATCH 10/29] Added resource access for firewall rules to allow for posts etc. TODO: resolve language inconsistencies with existing classes. --- lib/cloudflare/zone.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/cloudflare/zone.rb b/lib/cloudflare/zone.rb index 7b86350..b09568c 100644 --- a/lib/cloudflare/zone.rb +++ b/lib/cloudflare/zone.rb @@ -118,6 +118,11 @@ def validate_args(mode, ip) raise "Bad ip arg: #{ip}" if ip and !(ip =~ /[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*/) # TODO: add ranges, e.g. /24 end + def firewall_rules_resource + FirewallRules.new(concat_urls(url, "firewall/access_rules/rules?scope_type=organization"), self, **options) + end + + def firewall_rules(mode = nil, ip = nil, notes = nil) # 4 - rules request validate_args(mode, ip) @@ -143,7 +148,6 @@ def firewalled_ips(rules) rules.collect {|r| r.record[:configuration][:value]} end - def to_s @record[:name] end From 349645c513be78c68ac9a876e6fd8111de34d550 Mon Sep 17 00:00:00 2001 From: David Rosenbloom Date: Thu, 27 Jul 2017 17:27:26 -0400 Subject: [PATCH 11/29] Make class more consistent wih existing; update readme. --- README.md | 26 ++++++++++++++++++ lib/cloudflare/version.rb | 2 +- lib/cloudflare/zone.rb | 55 +++++++++++++++++++-------------------- 3 files changed, 54 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index f687930..52ae7a4 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,29 @@ puts records.first.record[:name] puts records ``` +Get firewall rules: + +``` ruby +all_rules = zones.first.firewall_rules.all +block_rules = zones.first.firewall_rules.all("block") # or "whitelist" or "challenge" +``` + +Get blocked ips: + +``` ruby +block_rules = zones.first.firewall_rules.all("block") +blocked_ips = zones.first.firewall_rules.firewalled_ips(block_rules) +``` + +Block an ip: + +``` ruby +# ip = "nnn.nnn.nnn.nnn" +# note: "some note about the block" +data = {"mode":"block","configuration":{"target":"ip","value":"#{ip}"},"notes":"#{note} #{Time.now.strftime("%m/%d/%y")} "} +response = zones.first.firewall_rules.post(data.to_json, content_type: 'application/json') + +``` ## Contributing 1. Fork it @@ -103,3 +126,6 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + + diff --git a/lib/cloudflare/version.rb b/lib/cloudflare/version.rb index f9c1c88..7521847 100644 --- a/lib/cloudflare/version.rb +++ b/lib/cloudflare/version.rb @@ -20,5 +20,5 @@ # THE SOFTWARE. module Cloudflare - VERSION = '3.1.0' + VERSION = '3.1.1' end diff --git a/lib/cloudflare/zone.rb b/lib/cloudflare/zone.rb index b09568c..db81939 100644 --- a/lib/cloudflare/zone.rb +++ b/lib/cloudflare/zone.rb @@ -98,34 +98,9 @@ def initialize(url, zone, **options) attr :zone - end - - class Zone < Resource - def initialize(url, record = nil, **options) - # byebug - super(url, **options) - @record = record || self.get.result - end - - attr :record - - def dns_records - @dns_records ||= DNSRecords.new(concat_urls(url, 'dns_records'), self, **options) - end - - def validate_args(mode, ip) - raise "Bad mode arg: #{mode}" if mode and !['block', 'whitelist', 'challenge'].include?(mode) - raise "Bad ip arg: #{ip}" if ip and !(ip =~ /[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*/) # TODO: add ranges, e.g. /24 - end - - def firewall_rules_resource - FirewallRules.new(concat_urls(url, "firewall/access_rules/rules?scope_type=organization"), self, **options) - end - - - def firewall_rules(mode = nil, ip = nil, notes = nil) - # 4 - rules request - validate_args(mode, ip) + def all(mode = nil, ip = nil, notes = nil) + # although this is within the resource, the initialized resource is not leveraged; rather, new resource instances are created to fetch paginated data. + validate_rules_filters(mode, ip) fw_url ="firewall/access_rules/rules?scope_type=organization" fw_url.concat("&mode=#{mode}") if mode fw_url.concat("&configuration_value=#{ip}") if ip @@ -148,6 +123,30 @@ def firewalled_ips(rules) rules.collect {|r| r.record[:configuration][:value]} end + def validate_rules_filters(mode, ip) + raise "Bad mode arg: #{mode}" if mode and !['block', 'whitelist', 'challenge'].include?(mode) + raise "Bad ip arg: #{ip}" if ip and !(ip =~ /[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*/) # TODO: add ranges, e.g. /24 + end + + end + + class Zone < Resource + def initialize(url, record = nil, **options) + # byebug + super(url, **options) + @record = record || self.get.result + end + + attr :record + + def dns_records + @dns_records ||= DNSRecords.new(concat_urls(url, 'dns_records'), self, **options) + end + + def firewall_rules + @firewall_rules ||= FirewallRules.new(concat_urls(url, "firewall/access_rules/rules?scope_type=organization"), self, **options) + end + def to_s @record[:name] end From 1f9e68858db1f622fb8178670b64556d517e9151 Mon Sep 17 00:00:00 2001 From: david rosenbloom Date: Fri, 28 Jul 2017 12:02:22 -0400 Subject: [PATCH 12/29] Update cloudflare.gemspec Removed byebug. --- cloudflare.gemspec | 1 - 1 file changed, 1 deletion(-) diff --git a/cloudflare.gemspec b/cloudflare.gemspec index 823f99c..72652b2 100644 --- a/cloudflare.gemspec +++ b/cloudflare.gemspec @@ -24,5 +24,4 @@ Gem::Specification.new do |spec| spec.add_development_dependency "rspec", "~> 3.6" spec.add_development_dependency "bundler", "~> 1.3" spec.add_development_dependency "rake" - spec.add_development_dependency "byebug" end From cd67fd9e1d731739bbad30fddab736abcd8c1984 Mon Sep 17 00:00:00 2001 From: david rosenbloom Date: Fri, 28 Jul 2017 12:02:59 -0400 Subject: [PATCH 13/29] Update zone.rb Removed byebug --- lib/cloudflare/zone.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/cloudflare/zone.rb b/lib/cloudflare/zone.rb index db81939..2ae223f 100644 --- a/lib/cloudflare/zone.rb +++ b/lib/cloudflare/zone.rb @@ -22,7 +22,6 @@ # added firewall rules support: david rosenbloom|davidr@artifactory.com|artifactory # require_relative 'connection' -require 'byebug' module Cloudflare class Connection < Resource def zones From 7ffa245b092fe442a7563826cf041e70f518c1fb Mon Sep 17 00:00:00 2001 From: David Rosenbloom Date: Fri, 28 Jul 2017 12:25:05 -0400 Subject: [PATCH 14/29] Restored tabs. --- README.md | 2 +- lib/cloudflare/connection.rb | 50 +++---- lib/cloudflare/zone.rb | 282 +++++++++++++++++------------------ 3 files changed, 167 insertions(+), 167 deletions(-) diff --git a/README.md b/README.md index 52ae7a4..cecf988 100644 --- a/README.md +++ b/README.md @@ -106,7 +106,7 @@ response = zones.first.firewall_rules.post(data.to_json, content_type: 'applicat Released under the MIT license. -Copyright, 2012, 2014, by [Marcin Prokop](https://github.com/b4k3r). +Copyright, 2012, 2014, by [Marcin Prokop](https://github.com/b4k3r). Copyright, 2017, by [Samuel G. D. Williams](http://www.codeotaku.com/samuel-williams). Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/lib/cloudflare/connection.rb b/lib/cloudflare/connection.rb index a4c3618..2a59649 100644 --- a/lib/cloudflare/connection.rb +++ b/lib/cloudflare/connection.rb @@ -27,29 +27,29 @@ require_relative 'response' module Cloudflare - DEFAULT_URL = "https://api.cloudflare.com/client/v4/" - TIMEOUT = 10 # Default is 5 seconds - - class Resource < RestClient::Resource - # @param api_key [String] `X-Auth-Key` or `X-Auth-User-Service-Key` if no email provided. - # @param email [String] `X-Auth-Email`, your email address for the account. - def initialize(url = DEFAULT_URL, key: nil, email: nil, **options) - headers = options[:headers] || {} - - if email.nil? - headers['X-Auth-User-Service-Key'] = key - else - headers['X-Auth-Key'] = key - headers['X-Auth-Email'] = email - end - - # Convert HTTP API responses to our own internal response class: - super(url, headers: headers, accept: 'application/json', **options) do |response| - Response.new(response.request.url, response.body) - end - end - end - - class Connection < Resource - end + DEFAULT_URL = "https://api.cloudflare.com/client/v4/" + TIMEOUT = 10 # Default is 5 seconds + + class Resource < RestClient::Resource + # @param api_key [String] `X-Auth-Key` or `X-Auth-User-Service-Key` if no email provided. + # @param email [String] `X-Auth-Email`, your email address for the account. + def initialize(url = DEFAULT_URL, key: nil, email: nil, **options) + headers = options[:headers] || {} + + if email.nil? + headers['X-Auth-User-Service-Key'] = key + else + headers['X-Auth-Key'] = key + headers['X-Auth-Email'] = email + end + + # Convert HTTP API responses to our own internal response class: + super(url, headers: headers, accept: 'application/json', **options) do |response| + Response.new(response.request.url, response.body) + end + end + end + + class Connection < Resource + end end diff --git a/lib/cloudflare/zone.rb b/lib/cloudflare/zone.rb index db81939..3a16a80 100644 --- a/lib/cloudflare/zone.rb +++ b/lib/cloudflare/zone.rb @@ -24,151 +24,151 @@ require_relative 'connection' require 'byebug' module Cloudflare - class Connection < Resource - def zones - @zones ||= Zones.new(concat_urls(url, 'zones'), options) - end - end + class Connection < Resource + def zones + @zones ||= Zones.new(concat_urls(url, 'zones'), options) + end + end - class DNSRecord < Resource - def initialize(url, record = nil, **options) - super(url, **options) - - @record = record || self.get.result - end - - attr :record + class DNSRecord < Resource + def initialize(url, record = nil, **options) + super(url, **options) + + @record = record || self.get.result + end + + attr :record - def to_s - "#{@record[:name]} #{@record[:type]} #{@record[:content]}" - end - end - - class DNSRecords < Resource - def initialize(url, zone, **options) - super(url, **options) - - @zone = zone - end - - attr :zone - - def all - self.get.results.map{|record| DNSRecord.new(concat_urls(url, record[:id]), record, **options)} - end - - def find_by_name(name) - response = self.get(params: {name: name}) - - unless response.empty? - record = response.results.first + def to_s + "#{@record[:name]} #{@record[:type]} #{@record[:content]}" + end + end + + class DNSRecords < Resource + def initialize(url, zone, **options) + super(url, **options) + + @zone = zone + end + + attr :zone + + def all + self.get.results.map{|record| DNSRecord.new(concat_urls(url, record[:id]), record, **options)} + end + + def find_by_name(name) + response = self.get(params: {name: name}) + + unless response.empty? + record = response.results.first - DNSRecord.new(concat_urls(url, record[:id]), record, **options) - end - end + DNSRecord.new(concat_urls(url, record[:id]), record, **options) + end + end - def find_by_id(id) - DNSRecord.new(concat_urls(url, id), **options) - end - end - - class FirewallRule < Resource - def initialize(url, record = nil, **options) - # 0 - Rule init - super(url, **options) - - @record = record || self.get.result - end - - attr :record - - def to_s - "#{@record[:configuration][:value]} - #{@record[:mode]} - #{@record[:notes]}" - end - end - - class FirewallRules < Resource - def initialize(url, zone, **options) - # 1 - Rules init - # byebug - super(url, **options) - - @zone = zone - end - - attr :zone - - def all(mode = nil, ip = nil, notes = nil) - # although this is within the resource, the initialized resource is not leveraged; rather, new resource instances are created to fetch paginated data. - validate_rules_filters(mode, ip) - fw_url ="firewall/access_rules/rules?scope_type=organization" - fw_url.concat("&mode=#{mode}") if mode - fw_url.concat("&configuration_value=#{ip}") if ip - fw_url.concat("¬es=#{notes}") if notes - page = 1 - page_size = 100 - results = [] - - loop do # fetch and aggregate all pages - rules = FirewallRules.new(concat_urls(url, "#{fw_url}&per_page=#{page_size}&page=#{page}"), self, **options) - results += rules.get.results - break if results.size % page_size != 0 - page += 1 - end - - results.map{|record| FirewallRule.new(concat_urls(url, record[:id]), record, **options)} - end - - def firewalled_ips(rules) - rules.collect {|r| r.record[:configuration][:value]} - end - - def validate_rules_filters(mode, ip) - raise "Bad mode arg: #{mode}" if mode and !['block', 'whitelist', 'challenge'].include?(mode) - raise "Bad ip arg: #{ip}" if ip and !(ip =~ /[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*/) # TODO: add ranges, e.g. /24 - end - - end + def find_by_id(id) + DNSRecord.new(concat_urls(url, id), **options) + end + end + + class FirewallRule < Resource + def initialize(url, record = nil, **options) + # 0 - Rule init + super(url, **options) + + @record = record || self.get.result + end + + attr :record + + def to_s + "#{@record[:configuration][:value]} - #{@record[:mode]} - #{@record[:notes]}" + end + end + + class FirewallRules < Resource + def initialize(url, zone, **options) + # 1 - Rules init + # byebug + super(url, **options) + + @zone = zone + end + + attr :zone + + def all(mode = nil, ip = nil, notes = nil) + # although this is within the resource, the initialized resource is not leveraged; rather, new resource instances are created to fetch paginated data. + validate_rules_filters(mode, ip) + fw_url ="firewall/access_rules/rules?scope_type=organization" + fw_url.concat("&mode=#{mode}") if mode + fw_url.concat("&configuration_value=#{ip}") if ip + fw_url.concat("¬es=#{notes}") if notes + page = 1 + page_size = 100 + results = [] + + loop do # fetch and aggregate all pages + rules = FirewallRules.new(concat_urls(url, "#{fw_url}&per_page=#{page_size}&page=#{page}"), self, **options) + results += rules.get.results + break if results.size % page_size != 0 + page += 1 + end + + results.map{|record| FirewallRule.new(concat_urls(url, record[:id]), record, **options)} + end + + def firewalled_ips(rules) + rules.collect {|r| r.record[:configuration][:value]} + end + + def validate_rules_filters(mode, ip) + raise "Bad mode arg: #{mode}" if mode and !['block', 'whitelist', 'challenge'].include?(mode) + raise "Bad ip arg: #{ip}" if ip and !(ip =~ /[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*/) # TODO: add ranges, e.g. /24 + end + + end - class Zone < Resource - def initialize(url, record = nil, **options) - # byebug - super(url, **options) - @record = record || self.get.result - end + class Zone < Resource + def initialize(url, record = nil, **options) + # byebug + super(url, **options) + @record = record || self.get.result + end - attr :record - - def dns_records - @dns_records ||= DNSRecords.new(concat_urls(url, 'dns_records'), self, **options) - end - - def firewall_rules - @firewall_rules ||= FirewallRules.new(concat_urls(url, "firewall/access_rules/rules?scope_type=organization"), self, **options) - end - - def to_s - @record[:name] - end - end - - class Zones < Resource - def all - self.get.results.map{|record| Zone.new(concat_urls(url, record[:id]), record, **options)} - end - - def find_by_name(name) - record = self.get(params: {name: name}).result - - unless response.empty? - record = response.results.first - - Zone.new(concat_urls(url, record[:id]), record, **options) - end - end - - def find_by_id(id) - Zone.new(concat_urls(url, id), **options) - end - end + attr :record + + def dns_records + @dns_records ||= DNSRecords.new(concat_urls(url, 'dns_records'), self, **options) + end + + def firewall_rules + @firewall_rules ||= FirewallRules.new(concat_urls(url, "firewall/access_rules/rules?scope_type=organization"), self, **options) + end + + def to_s + @record[:name] + end + end + + class Zones < Resource + def all + self.get.results.map{|record| Zone.new(concat_urls(url, record[:id]), record, **options)} + end + + def find_by_name(name) + record = self.get(params: {name: name}).result + + unless response.empty? + record = response.results.first + + Zone.new(concat_urls(url, record[:id]), record, **options) + end + end + + def find_by_id(id) + Zone.new(concat_urls(url, id), **options) + end + end end From abf7d77905a402d661bd9bcc4ed2baff4e0cf79c Mon Sep 17 00:00:00 2001 From: david rosenbloom Date: Fri, 28 Jul 2017 12:40:45 -0400 Subject: [PATCH 15/29] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cecf988..039b8dc 100644 --- a/README.md +++ b/README.md @@ -106,7 +106,7 @@ response = zones.first.firewall_rules.post(data.to_json, content_type: 'applicat Released under the MIT license. -Copyright, 2012, 2014, by [Marcin Prokop](https://github.com/b4k3r). +Copyright, 2012, 2014, by [Marcin Prokop](https://github.com/b4k3r). Copyright, 2017, by [Samuel G. D. Williams](http://www.codeotaku.com/samuel-williams). Permission is hereby granted, free of charge, to any person obtaining a copy From 1fadef7c45fdaa41a558fcfb0a8f681b8effebd0 Mon Sep 17 00:00:00 2001 From: david rosenbloom Date: Fri, 28 Jul 2017 12:45:31 -0400 Subject: [PATCH 16/29] Update zone.rb --- lib/cloudflare/zone.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/cloudflare/zone.rb b/lib/cloudflare/zone.rb index 39bf86c..6d0d507 100644 --- a/lib/cloudflare/zone.rb +++ b/lib/cloudflare/zone.rb @@ -88,8 +88,6 @@ def to_s class FirewallRules < Resource def initialize(url, zone, **options) - # 1 - Rules init - # byebug super(url, **options) @zone = zone From 975bb0566d219c2de7cabf18cb8e75c29a360db1 Mon Sep 17 00:00:00 2001 From: moli Date: Sat, 29 Jul 2017 00:45:39 +0800 Subject: [PATCH 17/29] update record content --- lib/cloudflare/zone.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/cloudflare/zone.rb b/lib/cloudflare/zone.rb index 2295e28..5c84499 100644 --- a/lib/cloudflare/zone.rb +++ b/lib/cloudflare/zone.rb @@ -34,7 +34,12 @@ def initialize(url, record = nil, **options) @record = record || self.get.result end - + + def update_content(content) + response = self.put({type: @record[:type], name: @record[:name], content: content}.to_json, content_type: 'application/json') + response.successful? + end + attr :record def to_s From dc6d4d61fcd1e4574caf8bdd60ca7c3120c4c36e Mon Sep 17 00:00:00 2001 From: david rosenbloom Date: Fri, 28 Jul 2017 12:47:22 -0400 Subject: [PATCH 18/29] Update zone.rb --- lib/cloudflare/zone.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/cloudflare/zone.rb b/lib/cloudflare/zone.rb index 6d0d507..63170d6 100644 --- a/lib/cloudflare/zone.rb +++ b/lib/cloudflare/zone.rb @@ -73,7 +73,6 @@ def find_by_id(id) class FirewallRule < Resource def initialize(url, record = nil, **options) - # 0 - Rule init super(url, **options) @record = record || self.get.result From ea557adb6c4b581d6f6c669eb92456324c5c91d9 Mon Sep 17 00:00:00 2001 From: David Rosenbloom Date: Mon, 31 Jul 2017 10:35:44 -0400 Subject: [PATCH 19/29] Restored original connection.rb to minimize PR whitespace annoyance. --- lib/cloudflare/connection.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/cloudflare/connection.rb b/lib/cloudflare/connection.rb index 2a59649..fd4743d 100644 --- a/lib/cloudflare/connection.rb +++ b/lib/cloudflare/connection.rb @@ -29,27 +29,27 @@ module Cloudflare DEFAULT_URL = "https://api.cloudflare.com/client/v4/" TIMEOUT = 10 # Default is 5 seconds - + class Resource < RestClient::Resource # @param api_key [String] `X-Auth-Key` or `X-Auth-User-Service-Key` if no email provided. # @param email [String] `X-Auth-Email`, your email address for the account. def initialize(url = DEFAULT_URL, key: nil, email: nil, **options) headers = options[:headers] || {} - + if email.nil? headers['X-Auth-User-Service-Key'] = key else headers['X-Auth-Key'] = key headers['X-Auth-Email'] = email end - + # Convert HTTP API responses to our own internal response class: super(url, headers: headers, accept: 'application/json', **options) do |response| Response.new(response.request.url, response.body) end end end - + class Connection < Resource end end From 950f1f68131e3c2f4599416285aa9ce3c494d6fb Mon Sep 17 00:00:00 2001 From: David Rosenbloom Date: Mon, 31 Jul 2017 10:57:16 -0400 Subject: [PATCH 20/29] Replaced regex check of ip with IPAddr.ipv4? --- lib/cloudflare/zone.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/cloudflare/zone.rb b/lib/cloudflare/zone.rb index 63170d6..5542fde 100644 --- a/lib/cloudflare/zone.rb +++ b/lib/cloudflare/zone.rb @@ -22,6 +22,7 @@ # added firewall rules support: david rosenbloom|davidr@artifactory.com|artifactory # require_relative 'connection' + module Cloudflare class Connection < Resource def zones @@ -121,7 +122,7 @@ def firewalled_ips(rules) def validate_rules_filters(mode, ip) raise "Bad mode arg: #{mode}" if mode and !['block', 'whitelist', 'challenge'].include?(mode) - raise "Bad ip arg: #{ip}" if ip and !(ip =~ /[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*/) # TODO: add ranges, e.g. /24 + raise "Bad ip arg: #{ip}" if ip and !IPAddr.new(ip).ipv4? end end @@ -156,7 +157,7 @@ def all def find_by_name(name) response = self.get(params: {name: name}) - + unless response.empty? record = response.results.first From 8c7ee98bb50ccf73a5de98b6e091044454006ddd Mon Sep 17 00:00:00 2001 From: David Rosenbloom Date: Mon, 31 Jul 2017 15:37:01 -0400 Subject: [PATCH 21/29] WIP: firewall_rules spec. --- lib/cloudflare/zone.rb | 300 +++++++++++++++++++---------------- spec/cloudflare/zone_spec.rb | 101 +++++++----- 2 files changed, 223 insertions(+), 178 deletions(-) diff --git a/lib/cloudflare/zone.rb b/lib/cloudflare/zone.rb index 5542fde..e4ff088 100644 --- a/lib/cloudflare/zone.rb +++ b/lib/cloudflare/zone.rb @@ -24,150 +24,170 @@ require_relative 'connection' module Cloudflare - class Connection < Resource - def zones - @zones ||= Zones.new(concat_urls(url, 'zones'), options) - end - end + class Connection < Resource + def zones + @zones ||= Zones.new(concat_urls(url, 'zones'), options) + end + end - class DNSRecord < Resource - def initialize(url, record = nil, **options) - super(url, **options) + class DNSRecord < Resource + def initialize(url, record = nil, **options) + super(url, **options) - @record = record || self.get.result - end + @record = record || self.get.result + end + + attr :record + + def to_s + "#{@record[:name]} #{@record[:type]} #{@record[:content]}" + end + end + + class DNSRecords < Resource + def initialize(url, zone, **options) + super(url, **options) + + @zone = zone + end + + attr :zone + + def all + self.get.results.map{|record| DNSRecord.new(concat_urls(url, record[:id]), record, **options)} + end + + def find_by_name(name) + response = self.get(params: {name: name}) + + unless response.empty? + record = response.results.first + + DNSRecord.new(concat_urls(url, record[:id]), record, **options) + end + end + + def find_by_id(id) + DNSRecord.new(concat_urls(url, id), **options) + end + end + + class FirewallRule < Resource + def initialize(url, record = nil, **options) + super(url, **options) + + @record = record || self.get.result + end - attr :record + attr :record + + def to_s + "#{@record[:configuration][:value]} - #{@record[:mode]} - #{@record[:notes]}" + end + end - def to_s - "#{@record[:name]} #{@record[:type]} #{@record[:content]}" - end - end + class FirewallRules < Resource + def initialize(url, zone, **options) + super(url, **options) + + @zone = zone + end + + attr :zone + + def all(mode = nil, ip = nil, notes = nil) + # although this is within the resource, the initialized resource is not leveraged; rather, new resource instances are created to fetch paginated data. + validate_rules_filters(mode, ip) + fw_url ="firewall/access_rules/rules?scope_type=organization" + fw_url.concat("&mode=#{mode}") if mode + fw_url.concat("&configuration_value=#{ip}") if ip + fw_url.concat("¬es=#{notes}") if notes + page = 1 + page_size = 100 + results = [] + + loop do # fetch and aggregate all pages + rules = FirewallRules.new(concat_urls(url, "#{fw_url}&per_page=#{page_size}&page=#{page}"), self, **options) + results += rules.get.results + break if results.size % page_size != 0 + page += 1 + end + + results.map{|record| FirewallRule.new(concat_urls(url, record[:id]), record, **options)} + end + + def firewalled_ips(rules) + rules.collect {|r| r.record[:configuration][:value]} + end + + def validate_rules_filters(mode, ip) + raise "Bad mode arg: #{mode}" if mode and !['block', 'whitelist', 'challenge'].include?(mode) + raise "Bad ip arg: #{ip}" if ip and !IPAddr.new(ip).ipv4? + end + + def blocked_ips + firewalled_ips(all("block")) + end - class DNSRecords < Resource - def initialize(url, zone, **options) - super(url, **options) - - @zone = zone - end + def set(mode, ip, note) + data = {"mode":"#{mode}","configuration":{"target":"ip","value":"#{ip}"},"notes":"cloudflare gem firewall_rules [#{mode}] #{note} #{Time.now.strftime("%m/%d/%y")} "} + post(data.to_json, content_type: 'application/json') + end - attr :zone - - def all - self.get.results.map{|record| DNSRecord.new(concat_urls(url, record[:id]), record, **options)} - end - - def find_by_name(name) - response = self.get(params: {name: name}) - - unless response.empty? - record = response.results.first - - DNSRecord.new(concat_urls(url, record[:id]), record, **options) - end - end - - def find_by_id(id) - DNSRecord.new(concat_urls(url, id), **options) - end - end - - class FirewallRule < Resource - def initialize(url, record = nil, **options) - super(url, **options) - - @record = record || self.get.result - end - - attr :record - - def to_s - "#{@record[:configuration][:value]} - #{@record[:mode]} - #{@record[:notes]}" - end - end - - class FirewallRules < Resource - def initialize(url, zone, **options) - super(url, **options) - - @zone = zone - end - - attr :zone - - def all(mode = nil, ip = nil, notes = nil) - # although this is within the resource, the initialized resource is not leveraged; rather, new resource instances are created to fetch paginated data. - validate_rules_filters(mode, ip) - fw_url ="firewall/access_rules/rules?scope_type=organization" - fw_url.concat("&mode=#{mode}") if mode - fw_url.concat("&configuration_value=#{ip}") if ip - fw_url.concat("¬es=#{notes}") if notes - page = 1 - page_size = 100 - results = [] - - loop do # fetch and aggregate all pages - rules = FirewallRules.new(concat_urls(url, "#{fw_url}&per_page=#{page_size}&page=#{page}"), self, **options) - results += rules.get.results - break if results.size % page_size != 0 - page += 1 - end - - results.map{|record| FirewallRule.new(concat_urls(url, record[:id]), record, **options)} - end - - def firewalled_ips(rules) - rules.collect {|r| r.record[:configuration][:value]} - end - - def validate_rules_filters(mode, ip) - raise "Bad mode arg: #{mode}" if mode and !['block', 'whitelist', 'challenge'].include?(mode) - raise "Bad ip arg: #{ip}" if ip and !IPAddr.new(ip).ipv4? - end - - end - - class Zone < Resource - def initialize(url, record = nil, **options) - # byebug - super(url, **options) - @record = record || self.get.result - end - - attr :record - - def dns_records - @dns_records ||= DNSRecords.new(concat_urls(url, 'dns_records'), self, **options) - end - - def firewall_rules - @firewall_rules ||= FirewallRules.new(concat_urls(url, "firewall/access_rules/rules?scope_type=organization"), self, **options) - end - - def to_s - @record[:name] - end - end - - class Zones < Resource - def all - self.get.results.map{|record| Zone.new(concat_urls(url, record[:id]), record, **options)} - end - - def find_by_name(name) - - response = self.get(params: {name: name}) - - - unless response.empty? - record = response.results.first - - Zone.new(concat_urls(url, record[:id]), record, **options) - end - end - - def find_by_id(id) - Zone.new(concat_urls(url, id), **options) - end - end + def unset(record) + puts self.url + puts record.inspect + rule = find_by_id(record[:id]) + rule.delete + end + + def find_by_id(id) + FirewallRule.new(concat_urls(url, id), **options) + end + end + + class Zone < Resource + def initialize(url, record = nil, **options) + # byebug + super(url, **options) + @record = record || self.get.result + end + + attr :record + + def dns_records + @dns_records ||= DNSRecords.new(concat_urls(url, 'dns_records'), self, **options) + end + + def firewall_rules + # @firewall_rules ||= FirewallRules.new(concat_urls(url, "firewall/access_rules/rules?scope_type=organization"), self, **options) + @firewall_rules ||= FirewallRules.new(concat_urls(url, "firewall/access_rules/rules"), self, **options) + end + + def to_s + @record[:name] + end + end + + class Zones < Resource + def all + self.get.results.map{|record| Zone.new(concat_urls(url, record[:id]), record, **options)} + end + + def find_by_name(name) + + response = self.get(params: {name: name}) + + + unless response.empty? + record = response.results.first + + Zone.new(concat_urls(url, record[:id]), record, **options) + end + end + + def find_by_id(id) + Zone.new(concat_urls(url, id), **options) + end + end end diff --git a/spec/cloudflare/zone_spec.rb b/spec/cloudflare/zone_spec.rb index 8d7a90e..9c3bf7c 100644 --- a/spec/cloudflare/zone_spec.rb +++ b/spec/cloudflare/zone_spec.rb @@ -1,41 +1,66 @@ RSpec.describe "Cloudflare DNS Zones" do - include_context Cloudflare::RSpec::Connection - - it "should list zones" do - zones = connection.zones.all - - expect(zones).to be_any - end - - describe Cloudflare::DNSRecords, order: :defined do - let(:zone) {connection.zones.all.first} - let(:name) {"test"} - - it "should create dns record" do - response = zone.dns_records.post({ - type: "A", - name: name, - content: "127.0.0.1", - ttl: 240, - proxied: false - }.to_json, content_type: 'application/json') - - expect(response).to be_successful - - result = response.result - expect(result).to include(:id, :type, :name, :content, :ttl) - end - - it "should delete dns record" do - dns_records = zone.dns_records.all - - expect(dns_records).to be_any - - dns_records.each do |record| - response = record.delete - expect(response).to be_successful - end - end - end + include_context Cloudflare::RSpec::Connection + + it "should list zones" do + zones = connection.zones.all + + expect(zones).to be_any + end + + describe Cloudflare::DNSRecords, order: :defined do + let(:zone) {connection.zones.all.first} + let(:name) {"test"} + + # it "should create dns record" do + # response = zone.dns_records.post({ + # type: "A", + # name: name, + # content: "127.0.0.1", + # ttl: 240, + # proxied: false + # }.to_json, content_type: 'application/json') + + # expect(response).to be_successful + + # result = response.result + # expect(result).to include(:id, :type, :name, :content, :ttl) + # end + + # it "should delete dns record" do + # dns_records = zone.dns_records.all + + # expect(dns_records).to be_any + + # dns_records.each do |record| + # response = record.delete + # expect(response).to be_successful + # end + # end + end + + describe Cloudflare::FirewallRules, order: :defined do + let(:zone) {connection.zones.all.first} + let(:name) {"test"} + record = nil + + it "should create firewall rules" do + + ['block', 'challenge', 'whitelist'].each do |mode| + response = zone.firewall_rules.set(mode,'123.123.123.123', "gemtest") + expect(response).to be_successful + + result = response.result + expect(result).to include(:id, :mode, :notes, :configuration) + expect(result[:mode]).to eq mode + record = result + end + puts record.inspect + end + it "should delete firewall rule" do + response = zone.firewall_rules.unset(record) + + expect(response).to be_successful + end + end end From dc29f6f50148bb57d57b55cc39bb9f084cc6cd6b Mon Sep 17 00:00:00 2001 From: David Rosenbloom Date: Mon, 31 Jul 2017 17:52:36 -0400 Subject: [PATCH 22/29] --amend --- lib/cloudflare/zone.rb | 23 ++++-------- spec/cloudflare/zone_spec.rb | 73 ++++++++++++++++++++++-------------- 2 files changed, 52 insertions(+), 44 deletions(-) diff --git a/lib/cloudflare/zone.rb b/lib/cloudflare/zone.rb index e4ff088..6c7e118 100644 --- a/lib/cloudflare/zone.rb +++ b/lib/cloudflare/zone.rb @@ -96,8 +96,6 @@ def initialize(url, zone, **options) attr :zone def all(mode = nil, ip = nil, notes = nil) - # although this is within the resource, the initialized resource is not leveraged; rather, new resource instances are created to fetch paginated data. - validate_rules_filters(mode, ip) fw_url ="firewall/access_rules/rules?scope_type=organization" fw_url.concat("&mode=#{mode}") if mode fw_url.concat("&configuration_value=#{ip}") if ip @@ -120,35 +118,32 @@ def firewalled_ips(rules) rules.collect {|r| r.record[:configuration][:value]} end - def validate_rules_filters(mode, ip) - raise "Bad mode arg: #{mode}" if mode and !['block', 'whitelist', 'challenge'].include?(mode) - raise "Bad ip arg: #{ip}" if ip and !IPAddr.new(ip).ipv4? - end - def blocked_ips firewalled_ips(all("block")) end def set(mode, ip, note) - data = {"mode":"#{mode}","configuration":{"target":"ip","value":"#{ip}"},"notes":"cloudflare gem firewall_rules [#{mode}] #{note} #{Time.now.strftime("%m/%d/%y")} "} + data = {"mode":"#{mode.to_s}","configuration":{"target":"ip","value":"#{ip}"},"notes":"cloudflare gem firewall_rules [#{mode}] #{note} #{Time.now.strftime("%m/%d/%y")} "} post(data.to_json, content_type: 'application/json') end - def unset(record) - puts self.url - puts record.inspect - rule = find_by_id(record[:id]) + def unset(mode, value) + rule = send("find_by_#{mode}", value) rule.delete end def find_by_id(id) FirewallRule.new(concat_urls(url, id), **options) end + + def find_by_ip(ip) + rule = FirewallRule.new(concat_urls(url, "?configuration_value=#{ip}"), **options) + FirewallRule.new(concat_urls(url, rule.record.first[:id]), **options) + end end class Zone < Resource def initialize(url, record = nil, **options) - # byebug super(url, **options) @record = record || self.get.result end @@ -175,10 +170,8 @@ def all end def find_by_name(name) - response = self.get(params: {name: name}) - unless response.empty? record = response.results.first diff --git a/spec/cloudflare/zone_spec.rb b/spec/cloudflare/zone_spec.rb index 9c3bf7c..02b964c 100644 --- a/spec/cloudflare/zone_spec.rb +++ b/spec/cloudflare/zone_spec.rb @@ -11,54 +11,69 @@ describe Cloudflare::DNSRecords, order: :defined do let(:zone) {connection.zones.all.first} let(:name) {"test"} + let(:ip) {"123.123.123.123"} + record = nil - # it "should create dns record" do - # response = zone.dns_records.post({ - # type: "A", - # name: name, - # content: "127.0.0.1", - # ttl: 240, - # proxied: false - # }.to_json, content_type: 'application/json') - - # expect(response).to be_successful - - # result = response.result - # expect(result).to include(:id, :type, :name, :content, :ttl) - # end + it "should create dns record" do + response = zone.dns_records.post({ + type: "A", + name: name, + content: ip, + ttl: 240, + proxied: false + }.to_json, content_type: 'application/json') - # it "should delete dns record" do - # dns_records = zone.dns_records.all + expect(response).to be_successful - # expect(dns_records).to be_any + result = response.result + expect(result).to include(:id, :type, :name, :content, :ttl) + puts result.inspect + record = result + end - # dns_records.each do |record| - # response = record.delete - # expect(response).to be_successful - # end - # end + it "should delete dns record" do + dns_records = zone.dns_records.all + expect(dns_records).to be_any + puts dns_records.first.inspect + dns_record = zone.dns_records.find_by_id(record[:id]) + puts dns_record + response = dns_record.delete + expect(response).to be_successful + end end describe Cloudflare::FirewallRules, order: :defined do let(:zone) {connection.zones.all.first} let(:name) {"test"} + let(:ip) {'123.123.123.123'} + let(:ip2) {'123.123.123.124'} + let(:notes) {"gemtest"} record = nil + before do + response = zone.firewall_rules.set('block', ip2, notes) + end - it "should create firewall rules" do + it "should create firewall rules for 'block', 'challenge', 'whitelist'" do - ['block', 'challenge', 'whitelist'].each do |mode| - response = zone.firewall_rules.set(mode,'123.123.123.123', "gemtest") + [:block, :challenge, :whitelist].each do |mode| + response = zone.firewall_rules.set(mode, ip, notes) expect(response).to be_successful result = response.result expect(result).to include(:id, :mode, :notes, :configuration) - expect(result[:mode]).to eq mode + expect(result[:mode]).to eq mode.to_s record = result end - puts record.inspect end - it "should delete firewall rule" do - response = zone.firewall_rules.unset(record) + + it "should delete firewall rule by record" do + response = zone.firewall_rules.unset('id', record[:id]) + + expect(response).to be_successful + end + + it "should delete firewall rule by ip" do + response = zone.firewall_rules.unset('ip', ip2) expect(response).to be_successful end From 2b3fbedd1e510bb078f89adf715d5ad957dfc243 Mon Sep 17 00:00:00 2001 From: David Rosenbloom Date: Mon, 31 Jul 2017 17:53:05 -0400 Subject: [PATCH 23/29] WIP: tests added for firewall_rules; tests for dns_records delete restricted to test record; methods added to firewall_rules. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 6741120..34e0a27 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ Gemfile* *.gem tags .byebug_history +.rspec_status From 5a25ec7b8c3ca669e7a0c7c5182267022e79e999 Mon Sep 17 00:00:00 2001 From: David Rosenbloom Date: Mon, 31 Jul 2017 17:56:01 -0400 Subject: [PATCH 24/29] --amend --- spec/cloudflare/zone_spec.rb | 5 ----- 1 file changed, 5 deletions(-) diff --git a/spec/cloudflare/zone_spec.rb b/spec/cloudflare/zone_spec.rb index 02b964c..cf1c159 100644 --- a/spec/cloudflare/zone_spec.rb +++ b/spec/cloudflare/zone_spec.rb @@ -27,16 +27,11 @@ result = response.result expect(result).to include(:id, :type, :name, :content, :ttl) - puts result.inspect record = result end it "should delete dns record" do - dns_records = zone.dns_records.all - expect(dns_records).to be_any - puts dns_records.first.inspect dns_record = zone.dns_records.find_by_id(record[:id]) - puts dns_record response = dns_record.delete expect(response).to be_successful end From fbd92de36245727e6587260297c4ff910e62ad7e Mon Sep 17 00:00:00 2001 From: David Rosenbloom Date: Tue, 1 Aug 2017 17:37:02 -0400 Subject: [PATCH 25/29] Fixed bug introduced to firewall_rules.all by previous change; added spec for :all for both dns_records and firewall_rules. --- lib/cloudflare/zone.rb | 18 ++++++++++++++++-- spec/cloudflare/zone_spec.rb | 15 +++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/lib/cloudflare/zone.rb b/lib/cloudflare/zone.rb index 6c7e118..9aa15df 100644 --- a/lib/cloudflare/zone.rb +++ b/lib/cloudflare/zone.rb @@ -54,7 +54,21 @@ def initialize(url, zone, **options) attr :zone def all - self.get.results.map{|record| DNSRecord.new(concat_urls(url, record[:id]), record, **options)} + # self.get.results.map{|record| DNSRecord.new(concat_urls(url, record[:id]), record, **options)} + dns_url = "?scope_type=organization" + page = 1 + page_size = 100 + results = [] + + loop do # fetch and aggregate all pages + rules = DNSRecords.new(concat_urls(url, "#{dns_url}&per_page=#{page_size}&page=#{page}"), self, **options) + results += rules.get.results + break if results.size % page_size != 0 + page += 1 + end + + results.map{|record| DNSRecord.new(concat_urls(url, record[:id]), record, **options)} + end def find_by_name(name) @@ -96,7 +110,7 @@ def initialize(url, zone, **options) attr :zone def all(mode = nil, ip = nil, notes = nil) - fw_url ="firewall/access_rules/rules?scope_type=organization" + fw_url = "?scope_type=organization" fw_url.concat("&mode=#{mode}") if mode fw_url.concat("&configuration_value=#{ip}") if ip fw_url.concat("¬es=#{notes}") if notes diff --git a/spec/cloudflare/zone_spec.rb b/spec/cloudflare/zone_spec.rb index cf1c159..64e70aa 100644 --- a/spec/cloudflare/zone_spec.rb +++ b/spec/cloudflare/zone_spec.rb @@ -14,6 +14,14 @@ let(:ip) {"123.123.123.123"} record = nil + it "should get all records" do + result = zone.dns_records.all + + puts "===> #{result.size} records returned" + expect(result.size).to be > 0 + end + + it "should create dns record" do response = zone.dns_records.post({ type: "A", @@ -48,6 +56,13 @@ response = zone.firewall_rules.set('block', ip2, notes) end + it "should get all rules" do + result = zone.firewall_rules.all + + puts "===> #{result.size} records returned" + expect(result.size).to be > 0 + end + it "should create firewall rules for 'block', 'challenge', 'whitelist'" do [:block, :challenge, :whitelist].each do |mode| From fb1d935ffc49d133640aff5012ad2e4068c4f2d1 Mon Sep 17 00:00:00 2001 From: David Rosenbloom Date: Tue, 1 Aug 2017 17:42:15 -0400 Subject: [PATCH 26/29] Deleted commented line. --- lib/cloudflare/zone.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/cloudflare/zone.rb b/lib/cloudflare/zone.rb index 9aa15df..444cba0 100644 --- a/lib/cloudflare/zone.rb +++ b/lib/cloudflare/zone.rb @@ -169,7 +169,6 @@ def dns_records end def firewall_rules - # @firewall_rules ||= FirewallRules.new(concat_urls(url, "firewall/access_rules/rules?scope_type=organization"), self, **options) @firewall_rules ||= FirewallRules.new(concat_urls(url, "firewall/access_rules/rules"), self, **options) end From 0b74c7bda0f9bc0250c04a4942d67eba35b7cf1f Mon Sep 17 00:00:00 2001 From: David Rosenbloom Date: Tue, 1 Aug 2017 17:57:26 -0400 Subject: [PATCH 27/29] Whitespace conversion. --- lib/cloudflare/zone.rb | 334 ++++++++++++++++++++--------------------- 1 file changed, 167 insertions(+), 167 deletions(-) diff --git a/lib/cloudflare/zone.rb b/lib/cloudflare/zone.rb index 444cba0..a318e2f 100644 --- a/lib/cloudflare/zone.rb +++ b/lib/cloudflare/zone.rb @@ -24,176 +24,176 @@ require_relative 'connection' module Cloudflare - class Connection < Resource - def zones - @zones ||= Zones.new(concat_urls(url, 'zones'), options) - end - end + class Connection < Resource + def zones + @zones ||= Zones.new(concat_urls(url, 'zones'), options) + end + end - class DNSRecord < Resource - def initialize(url, record = nil, **options) - super(url, **options) + class DNSRecord < Resource + def initialize(url, record = nil, **options) + super(url, **options) - @record = record || self.get.result - end + @record = record || self.get.result + end - attr :record + attr :record - def to_s - "#{@record[:name]} #{@record[:type]} #{@record[:content]}" - end - end - - class DNSRecords < Resource - def initialize(url, zone, **options) - super(url, **options) - - @zone = zone - end + def to_s + "#{@record[:name]} #{@record[:type]} #{@record[:content]}" + end + end + + class DNSRecords < Resource + def initialize(url, zone, **options) + super(url, **options) + + @zone = zone + end - attr :zone - - def all - # self.get.results.map{|record| DNSRecord.new(concat_urls(url, record[:id]), record, **options)} - dns_url = "?scope_type=organization" - page = 1 - page_size = 100 - results = [] - - loop do # fetch and aggregate all pages - rules = DNSRecords.new(concat_urls(url, "#{dns_url}&per_page=#{page_size}&page=#{page}"), self, **options) - results += rules.get.results - break if results.size % page_size != 0 - page += 1 - end - - results.map{|record| DNSRecord.new(concat_urls(url, record[:id]), record, **options)} - - end - - def find_by_name(name) - response = self.get(params: {name: name}) - - unless response.empty? - record = response.results.first - - DNSRecord.new(concat_urls(url, record[:id]), record, **options) - end - end - - def find_by_id(id) - DNSRecord.new(concat_urls(url, id), **options) - end - end - - class FirewallRule < Resource - def initialize(url, record = nil, **options) - super(url, **options) - - @record = record || self.get.result - end - - attr :record - - def to_s - "#{@record[:configuration][:value]} - #{@record[:mode]} - #{@record[:notes]}" - end - end - - class FirewallRules < Resource - def initialize(url, zone, **options) - super(url, **options) - - @zone = zone - end - - attr :zone - - def all(mode = nil, ip = nil, notes = nil) - fw_url = "?scope_type=organization" - fw_url.concat("&mode=#{mode}") if mode - fw_url.concat("&configuration_value=#{ip}") if ip - fw_url.concat("¬es=#{notes}") if notes - page = 1 - page_size = 100 - results = [] - - loop do # fetch and aggregate all pages - rules = FirewallRules.new(concat_urls(url, "#{fw_url}&per_page=#{page_size}&page=#{page}"), self, **options) - results += rules.get.results - break if results.size % page_size != 0 - page += 1 - end - - results.map{|record| FirewallRule.new(concat_urls(url, record[:id]), record, **options)} - end - - def firewalled_ips(rules) - rules.collect {|r| r.record[:configuration][:value]} - end - - def blocked_ips - firewalled_ips(all("block")) - end - - def set(mode, ip, note) - data = {"mode":"#{mode.to_s}","configuration":{"target":"ip","value":"#{ip}"},"notes":"cloudflare gem firewall_rules [#{mode}] #{note} #{Time.now.strftime("%m/%d/%y")} "} - post(data.to_json, content_type: 'application/json') - end - - def unset(mode, value) - rule = send("find_by_#{mode}", value) - rule.delete - end - - def find_by_id(id) - FirewallRule.new(concat_urls(url, id), **options) - end - - def find_by_ip(ip) - rule = FirewallRule.new(concat_urls(url, "?configuration_value=#{ip}"), **options) - FirewallRule.new(concat_urls(url, rule.record.first[:id]), **options) - end - end - - class Zone < Resource - def initialize(url, record = nil, **options) - super(url, **options) - @record = record || self.get.result - end - - attr :record - - def dns_records - @dns_records ||= DNSRecords.new(concat_urls(url, 'dns_records'), self, **options) - end - - def firewall_rules - @firewall_rules ||= FirewallRules.new(concat_urls(url, "firewall/access_rules/rules"), self, **options) - end - - def to_s - @record[:name] - end - end - - class Zones < Resource - def all - self.get.results.map{|record| Zone.new(concat_urls(url, record[:id]), record, **options)} - end - - def find_by_name(name) - response = self.get(params: {name: name}) - - unless response.empty? - record = response.results.first - - Zone.new(concat_urls(url, record[:id]), record, **options) - end - end - - def find_by_id(id) - Zone.new(concat_urls(url, id), **options) - end - end + attr :zone + + def all + # self.get.results.map{|record| DNSRecord.new(concat_urls(url, record[:id]), record, **options)} + dns_url = "?scope_type=organization" + page = 1 + page_size = 100 + results = [] + + loop do # fetch and aggregate all pages + rules = DNSRecords.new(concat_urls(url, "#{dns_url}&per_page=#{page_size}&page=#{page}"), self, **options) + results += rules.get.results + break if results.size % page_size != 0 + page += 1 + end + + results.map{|record| DNSRecord.new(concat_urls(url, record[:id]), record, **options)} + + end + + def find_by_name(name) + response = self.get(params: {name: name}) + + unless response.empty? + record = response.results.first + + DNSRecord.new(concat_urls(url, record[:id]), record, **options) + end + end + + def find_by_id(id) + DNSRecord.new(concat_urls(url, id), **options) + end + end + + class FirewallRule < Resource + def initialize(url, record = nil, **options) + super(url, **options) + + @record = record || self.get.result + end + + attr :record + + def to_s + "#{@record[:configuration][:value]} - #{@record[:mode]} - #{@record[:notes]}" + end + end + + class FirewallRules < Resource + def initialize(url, zone, **options) + super(url, **options) + + @zone = zone + end + + attr :zone + + def all(mode = nil, ip = nil, notes = nil) + fw_url = "?scope_type=organization" + fw_url.concat("&mode=#{mode}") if mode + fw_url.concat("&configuration_value=#{ip}") if ip + fw_url.concat("¬es=#{notes}") if notes + page = 1 + page_size = 100 + results = [] + + loop do # fetch and aggregate all pages + rules = FirewallRules.new(concat_urls(url, "#{fw_url}&per_page=#{page_size}&page=#{page}"), self, **options) + results += rules.get.results + break if results.size % page_size != 0 + page += 1 + end + + results.map{|record| FirewallRule.new(concat_urls(url, record[:id]), record, **options)} + end + + def firewalled_ips(rules) + rules.collect {|r| r.record[:configuration][:value]} + end + + def blocked_ips + firewalled_ips(all("block")) + end + + def set(mode, ip, note) + data = {"mode":"#{mode.to_s}","configuration":{"target":"ip","value":"#{ip}"},"notes":"cloudflare gem firewall_rules [#{mode}] #{note} #{Time.now.strftime("%m/%d/%y")} "} + post(data.to_json, content_type: 'application/json') + end + + def unset(mode, value) + rule = send("find_by_#{mode}", value) + rule.delete + end + + def find_by_id(id) + FirewallRule.new(concat_urls(url, id), **options) + end + + def find_by_ip(ip) + rule = FirewallRule.new(concat_urls(url, "?configuration_value=#{ip}"), **options) + FirewallRule.new(concat_urls(url, rule.record.first[:id]), **options) + end + end + + class Zone < Resource + def initialize(url, record = nil, **options) + super(url, **options) + @record = record || self.get.result + end + + attr :record + + def dns_records + @dns_records ||= DNSRecords.new(concat_urls(url, 'dns_records'), self, **options) + end + + def firewall_rules + @firewall_rules ||= FirewallRules.new(concat_urls(url, "firewall/access_rules/rules"), self, **options) + end + + def to_s + @record[:name] + end + end + + class Zones < Resource + def all + self.get.results.map{|record| Zone.new(concat_urls(url, record[:id]), record, **options)} + end + + def find_by_name(name) + response = self.get(params: {name: name}) + + unless response.empty? + record = response.results.first + + Zone.new(concat_urls(url, record[:id]), record, **options) + end + end + + def find_by_id(id) + Zone.new(concat_urls(url, id), **options) + end + end end From 7b308869ed04da3948f934ebdb38ea5be42ea01c Mon Sep 17 00:00:00 2001 From: David Rosenbloom Date: Tue, 1 Aug 2017 18:03:56 -0400 Subject: [PATCH 28/29] Bumped minor rev #. --- lib/cloudflare/version.rb | 2 +- lib/cloudflare/zone.rb | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/cloudflare/version.rb b/lib/cloudflare/version.rb index 7521847..dc53548 100644 --- a/lib/cloudflare/version.rb +++ b/lib/cloudflare/version.rb @@ -20,5 +20,5 @@ # THE SOFTWARE. module Cloudflare - VERSION = '3.1.1' + VERSION = '3.1.2' end diff --git a/lib/cloudflare/zone.rb b/lib/cloudflare/zone.rb index a318e2f..0f45bc1 100644 --- a/lib/cloudflare/zone.rb +++ b/lib/cloudflare/zone.rb @@ -54,7 +54,6 @@ def initialize(url, zone, **options) attr :zone def all - # self.get.results.map{|record| DNSRecord.new(concat_urls(url, record[:id]), record, **options)} dns_url = "?scope_type=organization" page = 1 page_size = 100 From 168ebed3ca46a7cb662d7ed6c483e25bcfd33589 Mon Sep 17 00:00:00 2001 From: David Rosenbloom Date: Wed, 2 Aug 2017 11:02:27 -0400 Subject: [PATCH 29/29] Extract pagination. --- lib/cloudflare/connection.rb | 25 +++++++++++++++++++++---- lib/cloudflare/version.rb | 2 +- lib/cloudflare/zone.rb | 33 ++++++--------------------------- 3 files changed, 28 insertions(+), 32 deletions(-) diff --git a/lib/cloudflare/connection.rb b/lib/cloudflare/connection.rb index fd4743d..57a08bf 100644 --- a/lib/cloudflare/connection.rb +++ b/lib/cloudflare/connection.rb @@ -29,27 +29,44 @@ module Cloudflare DEFAULT_URL = "https://api.cloudflare.com/client/v4/" TIMEOUT = 10 # Default is 5 seconds - + class Resource < RestClient::Resource + include Enumerable # @param api_key [String] `X-Auth-Key` or `X-Auth-User-Service-Key` if no email provided. # @param email [String] `X-Auth-Email`, your email address for the account. def initialize(url = DEFAULT_URL, key: nil, email: nil, **options) headers = options[:headers] || {} - + if email.nil? headers['X-Auth-User-Service-Key'] = key else headers['X-Auth-Key'] = key headers['X-Auth-Email'] = email end - + # Convert HTTP API responses to our own internal response class: super(url, headers: headers, accept: 'application/json', **options) do |response| Response.new(response.request.url, response.body) end end + + def paginate(obj, url, url_args = "") + page = 1 + page_size = 100 + results = [] + + loop do # fetch and aggregate all pages + rules = obj.new(concat_urls(url, "?scope_type=organization#{url_args}&per_page=#{page_size}&page=#{page}"), self, **options) + results += rules.get.results + break if results.size % page_size != 0 + page += 1 + end + results end - + + + end + class Connection < Resource end end diff --git a/lib/cloudflare/version.rb b/lib/cloudflare/version.rb index dc53548..abc2b82 100644 --- a/lib/cloudflare/version.rb +++ b/lib/cloudflare/version.rb @@ -20,5 +20,5 @@ # THE SOFTWARE. module Cloudflare - VERSION = '3.1.2' + VERSION = '3.1.3' end diff --git a/lib/cloudflare/zone.rb b/lib/cloudflare/zone.rb index 44d2a24..51e3f37 100644 --- a/lib/cloudflare/zone.rb +++ b/lib/cloudflare/zone.rb @@ -60,20 +60,8 @@ def initialize(url, zone, **options) attr :zone def all - dns_url = "?scope_type=organization" - page = 1 - page_size = 100 - results = [] - - loop do # fetch and aggregate all pages - rules = DNSRecords.new(concat_urls(url, "#{dns_url}&per_page=#{page_size}&page=#{page}"), self, **options) - results += rules.get.results - break if results.size % page_size != 0 - page += 1 - end - + results = paginate(DNSRecords, url) results.map{|record| DNSRecord.new(concat_urls(url, record[:id]), record, **options)} - end def find_by_name(name) @@ -115,21 +103,12 @@ def initialize(url, zone, **options) attr :zone def all(mode = nil, ip = nil, notes = nil) - fw_url = "?scope_type=organization" - fw_url.concat("&mode=#{mode}") if mode - fw_url.concat("&configuration_value=#{ip}") if ip - fw_url.concat("¬es=#{notes}") if notes - page = 1 - page_size = 100 - results = [] - - loop do # fetch and aggregate all pages - rules = FirewallRules.new(concat_urls(url, "#{fw_url}&per_page=#{page_size}&page=#{page}"), self, **options) - results += rules.get.results - break if results.size % page_size != 0 - page += 1 - end + url_args = "" + url_args.concat("&mode=#{mode}") if mode + url_args.concat("&configuration_value=#{ip}") if ip + url_args.concat("¬es=#{notes}") if notes + results = paginate(FirewallRules, url, url_args) results.map{|record| FirewallRule.new(concat_urls(url, record[:id]), record, **options)} end