cfc 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 40bb48cf72eeb9528ed6c44396499aea91a719845094f1b389a7d891edb64b4c
4
+ data.tar.gz: f2ffa1a259fdb63166799b050f4035a0023ca9424753336cb21ef4b138ddbc76
5
+ SHA512:
6
+ metadata.gz: ae3acc4b662407967520e549a66cd73846ab834a89159d4592a8775af0efccf15ffbdacd09da8464e7f88f3b1a48bf677411614094d5342e95242a795e45b87b
7
+ data.tar.gz: eccf63a35470b2ee94f33324dd733b1393d43c0e36055840855c711c229b11e708bfae42f50c12443b0a6f6dd8f3b81026bf9fd7c5088996c689afa46ad50458
data/LICENSE ADDED
@@ -0,0 +1,18 @@
1
+ Copyright 2020– The Codidact Foundation
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
4
+ this software and associated documentation files (the "Software"), to deal in
5
+ the Software without restriction, including without limitation the rights to
6
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7
+ the Software, and to permit persons to whom the Software is furnished to do so,
8
+ subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
15
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
16
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,24 @@
1
+ # cfc
2
+ Simple library for interacting with the Cloudflare API.
3
+
4
+ ## Install
5
+ Clone the repository. That's it!
6
+
7
+ ## Usage
8
+ This library is intended to be very lightweight, to help with usage in quick but effective scripts. Scripts that use
9
+ this library can be added to `scripts/` and run from there—it's *possible* for them to go anywhere, of course,
10
+ but relative `require`s are easier from a proximate directory.
11
+
12
+ You can use the library either by instantiating `CFC::API` and using that class to send API requests directly,
13
+ or, for simpler tasks, you can use pre-provided objects in `lib/objects/`, which represent a data type from the
14
+ Cloudflare API and may provide methods to perform common or simple tasks on those types. See
15
+ `lib/scripts/clear_cache.rb` for an example of how this may be done using `CFC::Zone` objects.
16
+
17
+ ## Contributing
18
+ As with all Codidact projects, contributions are welcome and must adhere to the
19
+ [Codidact Code of Conduct](https://meta.codidact.com/policy/code-of-conduct). Please create an issue to discuss any
20
+ major changes you propose to make, or if you think your changes may not be accepted for any reason—we'd always
21
+ rather discuss something unnecessarily than have to reject someone's hard work.
22
+
23
+ ## License
24
+ This project is licensed under the terms of the MIT license, which may be found in the LICENSE file.
data/lib/cfc/api.rb ADDED
@@ -0,0 +1,75 @@
1
+ require 'net/http'
2
+ require 'json'
3
+ require 'digest'
4
+ require 'yaml'
5
+ require_relative 'config'
6
+ require_relative 'cache'
7
+ require_relative 'errors/http_error.rb'
8
+
9
+ module CFC
10
+ class API
11
+ def initialize
12
+ @base = 'https://api.cloudflare.com/client/v4/'
13
+ @cache = CFC::Cache.new
14
+ end
15
+
16
+ def get(path, params: nil, headers: nil, cache: true, expiry: nil)
17
+ request(Net::HTTP::Get, build_uri(path, params), headers: headers, cache: cache, expiry: expiry)
18
+ end
19
+
20
+ def get_json(path, params: nil, headers: nil, cache: true, expiry: nil)
21
+ request_json(Net::HTTP::Get, build_uri(path, params), headers: headers, cache: cache, expiry: expiry)
22
+ end
23
+
24
+ [:post, :put, :patch].each do |method|
25
+ define_method method do |path, data, headers: nil, cache: false, expiry: nil|
26
+ request("Net::HTTP::#{method.capitalize}".constantize, URI("#{@base}#{path}"), data: data, headers: headers, cache: cache, expiry: expiry)
27
+ end
28
+
29
+ define_method "#{method}_to_json" do |path, data, headers: nil, cache: false, expiry: nil|
30
+ request_json(Object.const_get("Net::HTTP::#{method.capitalize}"), URI("#{@base}#{path}"), data: data, headers: headers, cache: cache,
31
+ expiry: expiry)
32
+ end
33
+ end
34
+
35
+ protected
36
+
37
+ def request(cls, uri, data: nil, headers: nil, cache: true, expiry: nil)
38
+ final_headers = (headers || {}).merge({
39
+ 'Authorization' => "Bearer #{CFC::Config.instance.token}",
40
+ 'Content-Type' => 'application/json'
41
+ })
42
+
43
+ rq = cls.new(uri, final_headers)
44
+ unless data.nil? || rq.is_a?(Net::HTTP::Head)
45
+ rq.body = JSON.dump(data)
46
+ end
47
+
48
+ response = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
49
+ if cache
50
+ @cache.fetch(Digest::SHA256.hexdigest("#{uri}|#{JSON.dump(final_headers)}"), expiry: expiry) do
51
+ http.request(rq)
52
+ end
53
+ else
54
+ http.request(rq)
55
+ end
56
+ end
57
+
58
+ if response.is_a?(Net::HTTPSuccess)
59
+ response
60
+ else
61
+ raise CFC::Errors::HTTPError.new(rq, response)
62
+ end
63
+ end
64
+
65
+ def request_json(cls, path, data: nil, headers: nil, cache: true, expiry: nil)
66
+ JSON.parse(request(cls, path, data: data, headers: headers, cache: cache, expiry: expiry).body)
67
+ end
68
+
69
+ def build_uri(path, params)
70
+ uri = URI("#{@base}#{path}")
71
+ uri.query = URI.encode_www_form((params || {}).to_a)
72
+ uri
73
+ end
74
+ end
75
+ end
data/lib/cfc/cache.rb ADDED
@@ -0,0 +1,42 @@
1
+ require 'ostruct'
2
+ require 'date'
3
+
4
+ module CFC
5
+ class Cache
6
+ def initialize
7
+ @cache = {}
8
+ end
9
+
10
+ def include?(key)
11
+ @cache.include?(key) && (@cache[key].expiry.nil? || @cache[key].expiry >= DateTime.now.to_time.to_i)
12
+ end
13
+
14
+ def [](key)
15
+ valid?(key) ? @cache[key].data : nil
16
+ end
17
+
18
+ def []=(key, value)
19
+ @cache[key] = OpenStruct.new(data: value, expiry: nil)
20
+ end
21
+
22
+ def write(key, value, expiry: nil)
23
+ @cache[key] = OpenStruct.new(data: value, expiry: expiry)
24
+ end
25
+
26
+ def read(key)
27
+ valid?(key) ? @cache[key].data : nil
28
+ end
29
+
30
+ def fetch(key, expiry: nil)
31
+ if valid?(key)
32
+ @cache[key].data
33
+ else
34
+ data = block_given? ? yield : nil
35
+ write(key, data, expiry: expiry)
36
+ data
37
+ end
38
+ end
39
+
40
+ alias_method :valid?, :include?
41
+ end
42
+ end
data/lib/cfc/config.rb ADDED
@@ -0,0 +1,12 @@
1
+ require 'singleton'
2
+
3
+ module CFC
4
+ class Config
5
+ include Singleton
6
+ attr_accessor :token
7
+
8
+ def self.configure
9
+ yield CFC::Config.instance
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,19 @@
1
+ require 'json'
2
+
3
+ module CFC
4
+ module Errors
5
+ class HTTPError < StandardError
6
+ attr_reader :request, :response
7
+
8
+ def initialize(request, response)
9
+ super "Cloudflare API request returned HTTP #{response.code}"
10
+ @request = request
11
+ @response = response
12
+ end
13
+
14
+ def data
15
+ JSON.parse(@response.body)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,14 @@
1
+ module CFC
2
+ module Errors
3
+ class MissingProperty < StandardError
4
+ def self.default_message(obj, property)
5
+ "This #{obj.class.name} does not have a `#{property}' property. If you are accessing this object from a relationship on " \
6
+ "another object, the property may not have been fetched."
7
+ end
8
+
9
+ def initialize(message)
10
+ super
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,9 @@
1
+ require_relative 'object'
2
+
3
+ module CFC
4
+ class Account < CFC::APIObject
5
+ def initialize(data)
6
+ super(data)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,55 @@
1
+ require_relative '../errors/missing_property'
2
+ require_relative '../api'
3
+
4
+ module CFC
5
+ class APIObject
6
+ @relationships = []
7
+
8
+ def self.relationships
9
+ @relationships
10
+ end
11
+
12
+ def initialize(data)
13
+ @data = data
14
+ @api = CFC::API.new
15
+ initialize_relationships
16
+ end
17
+
18
+ def method_missing(name)
19
+ if @data.include?(name.to_s)
20
+ @data[name.to_s]
21
+ else
22
+ raise CFC::Errors::MissingProperty,
23
+ CFC::Errors::MissingProperty.default_message(self, name)
24
+ end
25
+ end
26
+
27
+ def respond_to_missing?(name, *_args, **_opts)
28
+ @data.include?(name.to_s)
29
+ end
30
+
31
+ def inspect
32
+ "#<#{self.class.name}:0x#{(object_id << 1).to_s(16)} #{@data.map { |k, v| "#{k}=#{v.inspect}" }.join(', ')}>"
33
+ end
34
+
35
+ alias_method :to_s, :inspect
36
+
37
+ protected
38
+
39
+ def self.relationship(property, cls)
40
+ unless defined?(@relationships)
41
+ @relationships = []
42
+ end
43
+ @relationships << [property, cls]
44
+ end
45
+
46
+ private
47
+
48
+ def initialize_relationships
49
+ (self.class.relationships || []).each do |rel|
50
+ property, cls = rel
51
+ @data[property.to_s] = cls.new(@data[property.to_s])
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,21 @@
1
+ module CFC
2
+ class Record < CFC::APIObject
3
+ def initialize(data)
4
+ super(data)
5
+ end
6
+
7
+ def proxy
8
+ set_proxied(true)
9
+ end
10
+
11
+ def deproxy
12
+ set_proxied(false)
13
+ end
14
+
15
+ private
16
+
17
+ def set_proxied(to)
18
+ @api.patch_to_json("zones/#{zone_id}/dns_records/#{id}", { proxied: to })
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,9 @@
1
+ require_relative 'object'
2
+
3
+ module CFC
4
+ class User < CFC::APIObject
5
+ def initialize(data)
6
+ super(data)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,31 @@
1
+ require_relative 'object'
2
+ require_relative 'user'
3
+ require_relative 'account'
4
+ require_relative 'record'
5
+
6
+ module CFC
7
+ class Zone < CFC::APIObject
8
+ relationship :owner, CFC::User
9
+ relationship :account, CFC::Account
10
+
11
+ @api = CFC::API.new
12
+
13
+ def self.list
14
+ data = @api.get_json('zones')['result']
15
+ data.map { |z| new(z) }
16
+ end
17
+
18
+ def initialize(data)
19
+ super(data)
20
+ end
21
+
22
+ def purge_all_files
23
+ @api.post_to_json("zones/#{id}/purge_cache", { purge_everything: true })
24
+ end
25
+
26
+ def records
27
+ data = @api.get_json("zones/#{id}/dns_records")['result']
28
+ data.map { |r| CFC::Record.new(r) }
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,3 @@
1
+ module CFC
2
+ VERSION = '0.1.1'
3
+ end
data/lib/cfc.rb ADDED
@@ -0,0 +1,10 @@
1
+ require_relative 'cfc/api'
2
+ require_relative 'cfc/config'
3
+ require_relative 'cfc/version'
4
+
5
+ require_relative 'cfc/objects/account'
6
+ require_relative 'cfc/objects/record'
7
+ require_relative 'cfc/objects/user'
8
+ require_relative 'cfc/objects/zone'
9
+
10
+ module CFC; end
metadata ADDED
@@ -0,0 +1,56 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cfc
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - The Codidact Foundation
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-12-31 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: 'See GitHub for usage details: https://github.com/codidact/cfc'
14
+ email: gems@codidact.org
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - LICENSE
20
+ - README.md
21
+ - lib/cfc.rb
22
+ - lib/cfc/api.rb
23
+ - lib/cfc/cache.rb
24
+ - lib/cfc/config.rb
25
+ - lib/cfc/errors/http_error.rb
26
+ - lib/cfc/errors/missing_property.rb
27
+ - lib/cfc/objects/account.rb
28
+ - lib/cfc/objects/object.rb
29
+ - lib/cfc/objects/record.rb
30
+ - lib/cfc/objects/user.rb
31
+ - lib/cfc/objects/zone.rb
32
+ - lib/cfc/version.rb
33
+ homepage: https://github.com/codidact/cfc
34
+ licenses:
35
+ - MIT
36
+ metadata: {}
37
+ post_install_message:
38
+ rdoc_options: []
39
+ require_paths:
40
+ - lib
41
+ required_ruby_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: 2.1.0
46
+ required_rubygems_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: '0'
51
+ requirements: []
52
+ rubygems_version: 3.0.8
53
+ signing_key:
54
+ specification_version: 4
55
+ summary: Simple API library for interacting with the Cloudflare API.
56
+ test_files: []