namecheap-dynamic-dns 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a35a8b0426385235c8b42ca47a6f1e1dbf8bcd76
4
+ data.tar.gz: f671de1c94d191c5e9ff7eb9c87a7206c47afe8f
5
+ SHA512:
6
+ metadata.gz: 1c8ce77cefa340465eb71616a04631b695292eefac0a684fa3b415df532985a552fdb94225e4616c8dc92527c1f0835f4ae5432e4c7b73e0535235f63a2407c8
7
+ data.tar.gz: e1f240fb68ed958e199c14fbf52c560f21649d03caac75a5df01b89cbefab9c109abfd8a3529206589831b63a27e10b84f0c31530196cc21c64974a204d5ff3b
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+
11
+ # rspec failure tracking
12
+ .rspec_status
13
+ /.idea
14
+ /domains.yml
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.4.1
5
+ before_install: gem install bundler -v 1.14.6
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in namecheap-dynamic-dns.gemspec
4
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Saimon Lovell
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,142 @@
1
+ # Namecheap Dynamic Dns
2
+
3
+ Imagine you want to host your development server from home. So you buy a domain from namecheap and point the sub-domains to your home I.P address. Now the problem is every couple of months or on every power failure (how ever rare they might be) you external I.P ends up changing. Now you have to login to your domain host and change the I.P for all of them.
4
+
5
+ This gem allows you to automatically easily change the I.P address of the subdomains that are pointing to your home Internet. It does this by checking your external I.P address with each specified subdomains to see if they match. Then if they don't match a call is made to namecheap to change it.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'namecheap-dynamic-dns'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install namecheap-dynamic-dns
22
+
23
+ ## Usage
24
+
25
+ In order to use this gem you must first create a YML file that tells this gem information about what are the domain/s to target and some additional information. You control the run time interval either through ruby script via cronjob or by rails. I recommend at least 5 minutes gap in-between checks. Some DNS takes time to update.
26
+
27
+ You will need to have connection to Internet.If you are in highly secure site then the following domains needs to be white listed:
28
+ * dynamicdns.park-your-domain.com
29
+ * whatismyip.akamai.com
30
+
31
+ ### YML
32
+
33
+ The file you are about to create can have any name. I named mine `domains.yml`. As long as you specify the file path you should be fine.
34
+
35
+ Create a YML file with the following:
36
+
37
+ ```yaml
38
+ ---
39
+ domains:
40
+ example.com:
41
+ password: 74gh9j3eufh86gh39jygh9f8h3f4
42
+
43
+ subdomains:
44
+ home:
45
+ test:
46
+ # Subdomain level
47
+ ip: 1.2.3.4
48
+
49
+ foo.com:
50
+ password: 3fj987jg0wi4u9e84fh0342jghjd
51
+ # Domain level
52
+ ip: 2.4.6.8
53
+
54
+ subdomains:
55
+ bar:
56
+ donkey:
57
+ ip: aaa.com
58
+ ```
59
+
60
+ #### Password
61
+ The `password` here you will get from NameCheap when you select a domain and under `Advanced DNS` and enable `DYNAMIC DNS` and you will see `Dynamic DNS Password`.
62
+
63
+ #### I.P
64
+ I.P can be host name as well. By default if you don't specify any I.P anywhere then the I.P will be the external I.P (wan) of the computer this gem is running from. If you specify an I.P address in domain level then any subdomains that did not specified an I.P address will user the I.P address of the domain. Any I.P you specifies in the subdomain level will only affect that subdomain. One thing to note which is if you are using a host name that uses load balancers then you may get different I.P on every call or every other call.
65
+
66
+ #### Explanation
67
+ The above settings translates to, example.com has two subdomains. First home.example.com will always have the external I.P address of the machine you are using this gem on. The last subdomain test.example.com will always have the I.P 1.2.3.4
68
+
69
+ The second part of the settings translates to, foo.com has two subdomains. First subdomain bar.foo.com will always have I.P 2.4.6.8 and the second subdomain donkey.foo.com will always have I.P address of host aaa.com
70
+
71
+ _NOTE: Make sure that you git ignore this file since it has your password in it._
72
+
73
+ ## Using Script
74
+
75
+ In your ruby script include the modules.
76
+
77
+ ```ruby
78
+ require 'namecheap-dynamic-dns'
79
+
80
+ include Namecheap::Dynamic::Dns
81
+
82
+ setup('domains.yml')
83
+ process_domains
84
+ ```
85
+
86
+ ## Using Rails
87
+
88
+ In you class enter the following.
89
+
90
+ ```ruby
91
+ class Example
92
+ include Namecheap::Dynamic::Dns
93
+
94
+ def initialize(config_file)
95
+ setup(config_file)
96
+ end
97
+ end
98
+ ```
99
+
100
+ Then to process the domains
101
+ ```ruby
102
+ foo = Example.new('config/domains.yml')
103
+ foo.process_domains
104
+ ```
105
+
106
+ ## Other Methods
107
+ These methods you won't need to use but can be useful for you in other way.
108
+
109
+ ```ruby
110
+ # Get external I.P
111
+ external_ip
112
+
113
+ # Get IP from hostname
114
+ host_to_ip('google.com')
115
+
116
+ # Valid IP?
117
+ an_ip?('1.2.3.4')
118
+
119
+ # Get list of domains
120
+ domains
121
+
122
+ # Chack is domain specified is valid
123
+ valid_domain?('google.com')
124
+
125
+ # Force reload config YML file
126
+ load_config
127
+
128
+ # See raw response
129
+ xml_response
130
+
131
+ # See JSON response
132
+ response
133
+ ```
134
+
135
+ ## Contributing
136
+
137
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/namecheap-dynamic-dns.
138
+
139
+
140
+ ## License
141
+
142
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "namecheap/dynamic/dns"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'xml/to/hash'
4
+
5
+ require 'open-uri'
6
+ require 'oj'
7
+ require 'active_support/core_ext/hash/indifferent_access'
8
+ require 'yaml'
9
+ require 'open-uri'
10
+ require 'resolv'
11
+ require 'ipaddress'
12
+ require 'logger'
13
+
14
+ require 'namecheap/dynamic/dns/version'
15
+ require 'namecheap/dynamic/dns/processor'
16
+ require 'namecheap/dynamic/dns/request'
17
+ require 'namecheap/dynamic/dns/settings'
18
+ require 'namecheap/dynamic/dns/network'
19
+
20
+ module Namecheap
21
+ module Dynamic
22
+ # This is the main module where all the rest loads from.
23
+ module Dns
24
+ include Processor
25
+ include Request
26
+ include Settings
27
+ include Network
28
+
29
+ attr_accessor :config_file, :config, :response, :xml_response, :ip, :updated_domains, :logger
30
+
31
+ def setup(config_file)
32
+ self.config_file = config_file
33
+ load_config
34
+ external_ip
35
+ self.logger = Logger.new(STDOUT)
36
+ logger.level = Logger::WARN
37
+ end
38
+
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Namecheap
4
+ module Dynamic
5
+ module Dns
6
+ # This module is designed for all network related functions.
7
+ module Network
8
+ def external_ip
9
+ self.ip = nil
10
+ begin
11
+ self.ip = open('http://whatismyip.akamai.com').read
12
+ rescue StandardError => err
13
+ logger.warn('Failed to retrieve external I.P.')
14
+ logger.debug(err)
15
+ end
16
+ end
17
+
18
+ def host_to_ip(host_name)
19
+ begin
20
+ Resolv.getaddress(host_name)
21
+ rescue StandardError => err
22
+ logger.fatal('Failed to retrieve host I.P. address')
23
+ logger.debug("Host Name: #{hostname}")
24
+ logger.error(err)
25
+ host_name
26
+ end
27
+ end
28
+
29
+ def an_ip?(host_name)
30
+ IPAddress.valid?(host_name)
31
+ end
32
+
33
+ def extract_ip(ip_or_host)
34
+ if an_ip?(ip_or_host)
35
+ ip_or_host
36
+ else
37
+ host_to_ip(ip_or_host)
38
+ end
39
+ end
40
+
41
+ def host_ip_match?(domain, target, target_ip)
42
+ host = %w(@ *).include?(target) ? domain : [target, domain].join('.')
43
+ host_to_ip(host) == target_ip
44
+ end
45
+
46
+ def valid_domain?(target_domain)
47
+ !target_domain.match(/\A[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,16}\z/ix).nil?
48
+ end
49
+
50
+ def got_external_ip?
51
+ return true unless ip.nil?
52
+ logger.error('No external ip detected. Aborting!!')
53
+ false
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Namecheap
4
+ module Dynamic
5
+ module Dns
6
+ # This module puts it all together and the main functions are here.
7
+ module Processor
8
+ def process_domains
9
+ return unless pre_check_domain
10
+ self.updated_domains = []
11
+
12
+ domains.each do |domain, attr|
13
+ next unless pre_check_sub_domains(domain, attr)
14
+ logger.info("Checking domain: #{domain}")
15
+ process_subdomains(domain,
16
+ attr[:subdomains],
17
+ attr[:password],
18
+ extract_ip(attr[:ip] ||= ip))
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def pre_check_domain
25
+ return false unless got_external_ip?
26
+ domains?
27
+ end
28
+
29
+ def pre_check_sub_domains(domain, attr)
30
+ return unless valid_domain?(domain)
31
+ return unless password?(attr)
32
+ return unless subdomains?(attr)
33
+ return if attr[:ip].nil? && ip.nil?
34
+ true
35
+ end
36
+
37
+ def process_subdomains(domain, subdomains, password, target_ip)
38
+ subdomains.each do |subdomain, attributes|
39
+ ip = process_ip(target_ip, attributes)
40
+
41
+ next unless valid_domain?([subdomain, domain].join('.'))
42
+
43
+ if host_ip_match?(domain, subdomain, ip)
44
+ logger.info(" - Host '#{subdomain}' is Valid.")
45
+ next
46
+ else
47
+ process_subdomain(domain, subdomain, password, ip)
48
+ end
49
+ end
50
+ end
51
+
52
+ def process_subdomain(domain, subdomain, password, ip)
53
+ logger.info(" - Updating host '#{subdomain}' !!")
54
+ request generate_url(subdomain, domain, password, ip)
55
+ updated_domains.push [subdomain, domain].join('.')
56
+ end
57
+
58
+ def process_ip(target_ip, attributes)
59
+ if attributes.key?(:ip) && !attributes[:ip].strip.empty?
60
+ target_ip = attributes[:ip]
61
+ end
62
+ extract_ip(target_ip)
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Namecheap
4
+ module Dynamic
5
+ module Dns
6
+ # This module is for handling all requests
7
+ module Request
8
+ def base_url
9
+ 'https://dynamicdns.park-your-domain.com/update?'
10
+ end
11
+
12
+ def generate_url(host, domain, password, ip = nil)
13
+ url = base_url
14
+ url += [:host, host].join('=')
15
+ url += ['&', :domain, '=', domain].join
16
+ url += ['&', :password, '=', password].join
17
+ url += ['&', :ip, '=', ip].join unless ip.nil?
18
+ url
19
+ end
20
+
21
+ def request(url)
22
+ self.xml_response = Nokogiri::XML(open(url))
23
+ self.response = xml_response.root.to_hash
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Namecheap
4
+ module Dynamic
5
+ module Dns
6
+ # This module is all about loading and processing configuration items
7
+ module Settings
8
+ def load_config
9
+ if config_file.empty? || !File.exist?(config_file)
10
+ raise 'Invalid YML config file!'
11
+ end
12
+ self.config = YAML.load_file(config_file)
13
+ self.config = ActiveSupport::HashWithIndifferentAccess.new(config)
14
+ end
15
+
16
+ def domains?
17
+ config.key?(:domains) && !config[:domains].empty?
18
+ end
19
+
20
+ def domains
21
+ config[:domains]
22
+ end
23
+
24
+ def subdomains?(domain)
25
+ return true if domain.key?(:subdomains) && !domain[:subdomains].empty?
26
+ logger.error('Subdomains are not found.')
27
+ false
28
+ end
29
+
30
+ def valid_domain?(domain)
31
+ unless valid_domain?(domain)
32
+ logger.error("Invalid domain found #{domain}.")
33
+ return false
34
+ end
35
+ true
36
+ end
37
+
38
+ def password?(attr)
39
+ unless attr.key?(:password)
40
+ logger.error("No password is specified for #{domain}.")
41
+ return false
42
+ end
43
+ true
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,7 @@
1
+ module Namecheap
2
+ module Dynamic
3
+ module Dns
4
+ VERSION = '0.0.1'.freeze
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,40 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'namecheap/dynamic/dns/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'namecheap-dynamic-dns'
8
+ spec.version = Namecheap::Dynamic::Dns::VERSION
9
+ spec.authors = ['Saimon Lovell']
10
+ spec.email = ['staysynchronize@gmail.com']
11
+
12
+ spec.summary = %q{NameCheap Dynamic DNS}
13
+ spec.description = %q{If you host your services from home your wan I.P can change over time.
14
+ This gem will help you by making sure the subdomains always point to your home wan ip.}
15
+ spec.homepage = 'https://github.com/SaimonL/namecheap-dynamic-dns'
16
+ spec.license = 'MIT'
17
+
18
+ if spec.respond_to?(:metadata)
19
+ spec.metadata['allowed_push_host'] = 'https://rubygems.org'
20
+ else
21
+ raise 'RubyGems 2.0 or newer is required to protect against public gem pushes.'
22
+ end
23
+
24
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
25
+ f.match(%r{^(test|spec|features)/})
26
+ end
27
+ spec.bindir = 'exe'
28
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
29
+ spec.require_paths = ['lib']
30
+
31
+ spec.add_dependency 'activesupport'
32
+ spec.add_dependency 'oj'
33
+ spec.add_dependency 'nokogiri'
34
+ spec.add_dependency 'xml-to-hash'
35
+ spec.add_dependency 'ipaddress'
36
+
37
+ spec.add_development_dependency 'bundler', '~> 1.14'
38
+ spec.add_development_dependency 'rake'
39
+ spec.add_development_dependency 'rspec', '~> 3.0'
40
+ end
metadata ADDED
@@ -0,0 +1,175 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: namecheap-dynamic-dns
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Saimon Lovell
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-04-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: oj
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: nokogiri
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: xml-to-hash
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: ipaddress
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: bundler
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.14'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.14'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rake
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rspec
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '3.0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '3.0'
125
+ description: |-
126
+ If you host your services from home your wan I.P can change over time.
127
+ This gem will help you by making sure the subdomains always point to your home wan ip.
128
+ email:
129
+ - staysynchronize@gmail.com
130
+ executables: []
131
+ extensions: []
132
+ extra_rdoc_files: []
133
+ files:
134
+ - ".gitignore"
135
+ - ".rspec"
136
+ - ".travis.yml"
137
+ - Gemfile
138
+ - LICENSE.txt
139
+ - README.md
140
+ - Rakefile
141
+ - bin/console
142
+ - bin/setup
143
+ - lib/namecheap/dynamic/dns.rb
144
+ - lib/namecheap/dynamic/dns/network.rb
145
+ - lib/namecheap/dynamic/dns/processor.rb
146
+ - lib/namecheap/dynamic/dns/request.rb
147
+ - lib/namecheap/dynamic/dns/settings.rb
148
+ - lib/namecheap/dynamic/dns/version.rb
149
+ - namecheap-dynamic-dns.gemspec
150
+ homepage: https://github.com/SaimonL/namecheap-dynamic-dns
151
+ licenses:
152
+ - MIT
153
+ metadata:
154
+ allowed_push_host: https://rubygems.org
155
+ post_install_message:
156
+ rdoc_options: []
157
+ require_paths:
158
+ - lib
159
+ required_ruby_version: !ruby/object:Gem::Requirement
160
+ requirements:
161
+ - - ">="
162
+ - !ruby/object:Gem::Version
163
+ version: '0'
164
+ required_rubygems_version: !ruby/object:Gem::Requirement
165
+ requirements:
166
+ - - ">="
167
+ - !ruby/object:Gem::Version
168
+ version: '0'
169
+ requirements: []
170
+ rubyforge_project:
171
+ rubygems_version: 2.6.11
172
+ signing_key:
173
+ specification_version: 4
174
+ summary: NameCheap Dynamic DNS
175
+ test_files: []