zt 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.editorconfig +15 -0
- data/.env.example +1 -0
- data/.gitignore +31 -0
- data/.idea/codeStyles/Project.xml +52 -0
- data/.idea/codeStyles/codeStyleConfig.xml +5 -0
- data/.idea/dbnavigator.xml +454 -0
- data/.idea/inspectionProfiles/Project_Default.xml +13 -0
- data/.idea/markdown-exported-files.xml +8 -0
- data/.idea/markdown-navigator.xml +88 -0
- data/.idea/markdown-navigator/profiles_settings.xml +3 -0
- data/.idea/misc.xml +7 -0
- data/.idea/modules.xml +8 -0
- data/.idea/vcs.xml +6 -0
- data/.idea/workspace.xml +475 -0
- data/.idea/zt.iml +41 -0
- data/.rspec +3 -0
- data/.rubocop.yml +4457 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +7 -0
- data/.versions.conf +4 -0
- data/CODE_OF_CONDUCT.md +75 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +103 -0
- data/Rakefile +6 -0
- data/bin/console +13 -0
- data/bin/setup +8 -0
- data/exe/zt +4 -0
- data/lib/zt.rb +14 -0
- data/lib/zt/cli.rb +91 -0
- data/lib/zt/conf.rb +97 -0
- data/lib/zt/constants.rb +46 -0
- data/lib/zt/errors.rb +3 -0
- data/lib/zt/errors/conf_errors.rb +26 -0
- data/lib/zt/exporters.rb +32 -0
- data/lib/zt/exporters/_base_exporter.rb +16 -0
- data/lib/zt/exporters/hosts_file_exporter.rb +32 -0
- data/lib/zt/importers.rb +28 -0
- data/lib/zt/importers/_base_importer.rb +44 -0
- data/lib/zt/importers/network_importer.rb +46 -0
- data/lib/zt/importers/node_importer.rb +54 -0
- data/lib/zt/remote_api.rb +39 -0
- data/lib/zt/version.rb +5 -0
- data/zt.gemspec +57 -0
- metadata +259 -0
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
zt
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby-2.6.2
|
data/.travis.yml
ADDED
data/.versions.conf
ADDED
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
2
|
+
|
3
|
+
## Our Pledge
|
4
|
+
|
5
|
+
In the interest of fostering an open and welcoming environment, we as
|
6
|
+
contributors and maintainers pledge to making participation in our project and
|
7
|
+
our community a harassment-free experience for everyone, regardless of age, body
|
8
|
+
size, disability, ethnicity, gender identity and expression, level of
|
9
|
+
experience, nationality, personal appearance, race, religion, or sexual
|
10
|
+
identity and orientation.
|
11
|
+
|
12
|
+
## Our Standards
|
13
|
+
|
14
|
+
Examples of behavior that contributes to creating a positive environment
|
15
|
+
include:
|
16
|
+
|
17
|
+
* Using welcoming and inclusive language
|
18
|
+
* Being respectful of differing viewpoints and experiences
|
19
|
+
* Gracefully accepting constructive criticism
|
20
|
+
* Focusing on what is best for the community
|
21
|
+
* Showing empathy towards other community members
|
22
|
+
|
23
|
+
Examples of unacceptable behavior by participants include:
|
24
|
+
|
25
|
+
* The use of sexualized language or imagery and unwelcome sexual attention or
|
26
|
+
advances
|
27
|
+
* Trolling, insulting/derogatory comments, and personal or political attacks
|
28
|
+
* Public or private harassment
|
29
|
+
* Publishing others' private information, such as a physical or electronic
|
30
|
+
address, without explicit permission
|
31
|
+
* Other conduct which could reasonably be considered inappropriate in a
|
32
|
+
professional setting
|
33
|
+
|
34
|
+
## Our Responsibilities
|
35
|
+
|
36
|
+
Project maintainers are responsible for clarifying the standards of acceptable
|
37
|
+
behavior and are expected to take appropriate and fair corrective action in
|
38
|
+
response to any instances of unacceptable behavior.
|
39
|
+
|
40
|
+
Project maintainers have the right and responsibility to remove, edit, or
|
41
|
+
reject comments, commits, code, wiki edits, issues, and other contributions
|
42
|
+
that are not aligned to this Code of Conduct, or to ban temporarily or
|
43
|
+
permanently any contributor for other behaviors that they deem inappropriate,
|
44
|
+
threatening, offensive, or harmful.
|
45
|
+
|
46
|
+
## Scope
|
47
|
+
|
48
|
+
This Code of Conduct applies both within project spaces and in public spaces
|
49
|
+
when an individual is representing the project or its community. Examples of
|
50
|
+
representing a project or community include using an official project e-mail
|
51
|
+
address, posting via an official social media account, or acting as an appointed
|
52
|
+
representative at an online or offline event. Representation of a project may be
|
53
|
+
further defined and clarified by project maintainers.
|
54
|
+
|
55
|
+
## Enforcement
|
56
|
+
|
57
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
58
|
+
reported by contacting the project team by any method listed on
|
59
|
+
[https://keybase.io/dave](https://keybase.io/dave) . All complaints will be
|
60
|
+
reviewed and investigated and will result in a response that is deemed necessary
|
61
|
+
and appropriate to the circumstances. The project team is obligated to maintain
|
62
|
+
confidentiality with regard to the reporter of an incident. Further details of
|
63
|
+
specific enforcement policies may be posted separately.
|
64
|
+
|
65
|
+
Project maintainers who do not follow or enforce the Code of Conduct in good
|
66
|
+
faith may face temporary or permanent repercussions as determined by other
|
67
|
+
members of the project's leadership.
|
68
|
+
|
69
|
+
## Attribution
|
70
|
+
|
71
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
72
|
+
version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
|
73
|
+
|
74
|
+
[homepage]: http://contributor-covenant.org
|
75
|
+
[version]: http://contributor-covenant.org/version/1/4/
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2019 Dave Williams
|
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.
|
data/README.md
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
# zt
|
2
|
+
|
3
|
+
Utilities and glue to make working with ZeroTier networks a bit more
|
4
|
+
friendly
|
5
|
+
|
6
|
+
[![gem version][img-badge-gem]][link-badge-gem]
|
7
|
+
|
8
|
+
This document assumes a UNIX-like operating system.
|
9
|
+
|
10
|
+
For the vast majority of people, that means Linux, *BSD, and macOS.
|
11
|
+
|
12
|
+
It might work with Windows, but Ruby on Windows is an adventure in
|
13
|
+
itself so I'm afraid you're on your own. If you're stuck with Windows,
|
14
|
+
try setting one of the [Windows Subsystem for Linux][link-wsl] sandboxes
|
15
|
+
up - they work surprisingly well.
|
16
|
+
|
17
|
+
## Installation
|
18
|
+
|
19
|
+
At this point, `zt` is intended as a command-line tool first and a
|
20
|
+
library second (if at all). As such, instructions for usage with Bundler
|
21
|
+
or similar are not given.
|
22
|
+
|
23
|
+
If `zt` becomes useful as a library, instructions will be provided, and
|
24
|
+
if you want to try using it as a library anyway, then best of luck to
|
25
|
+
you.
|
26
|
+
|
27
|
+
`zt` can be installed with RubyGems, and is published to the default
|
28
|
+
repository. Simply install it like any other gem.
|
29
|
+
|
30
|
+
```bash
|
31
|
+
gem install zt
|
32
|
+
```
|
33
|
+
|
34
|
+
Depending on how your Ruby installation is set up, you may need to
|
35
|
+
install it as a superuser. If you're not sure, and if commands like
|
36
|
+
`rvm`, `rbenv`, and/or `ruby-build` don't ring any bells, you probably
|
37
|
+
need to install as a superuser using `sudo`.
|
38
|
+
|
39
|
+
```bash
|
40
|
+
sudo gem install zt
|
41
|
+
```
|
42
|
+
|
43
|
+
## Usage
|
44
|
+
|
45
|
+
<!-- TODO: the bit we're all here to see in the first place -->
|
46
|
+
|
47
|
+
## Development
|
48
|
+
|
49
|
+
- Fork the repository on GitHub.
|
50
|
+
- ![gem version][img-fork_button]
|
51
|
+
- Check out your fork.
|
52
|
+
- `git clone https://github.com/yourusername/zt`
|
53
|
+
- Enter the checkout directory.
|
54
|
+
- `cd zt`
|
55
|
+
- Install dependencies.
|
56
|
+
- `bin/setup`
|
57
|
+
- Run the tests.
|
58
|
+
- `rake spec`
|
59
|
+
- Make a new branch for your feature.
|
60
|
+
- `git branch your-amazing-new-feature`
|
61
|
+
- Check out your new branch.
|
62
|
+
- `git checkout your-amazing-new-feature`
|
63
|
+
- Hack away.
|
64
|
+
- `(you have to come up with this bit yourself)`
|
65
|
+
- Make sure you add tests for your work.
|
66
|
+
- `(this bit is boring but REALLY IMPORTANT)`
|
67
|
+
- Make sure all the tests pass, both old and new.
|
68
|
+
- `rake spec`
|
69
|
+
- Commit and push your now-tested work to your fork.
|
70
|
+
- `git commit && git push origin your-amazing-new-feature`
|
71
|
+
- Open a pull request and wait for a response.
|
72
|
+
|
73
|
+
**PROTIP:** You can also run `bin/console` for an interactive prompt
|
74
|
+
that will allow you to experiment.
|
75
|
+
|
76
|
+
The [Bundler guide to gem development][link-bundler-guide] may be
|
77
|
+
helpful if this is your first gem. It certainly helped me.
|
78
|
+
|
79
|
+
## Contributing
|
80
|
+
|
81
|
+
Bug reports and pull requests are welcome [on GitHub][link-repo]. This
|
82
|
+
project is intended to be a safe, welcoming space for collaboration, and
|
83
|
+
contributors are expected to adhere to the [code of conduct][link-coc].
|
84
|
+
|
85
|
+
## License
|
86
|
+
|
87
|
+
The gem is available as open source under the terms of the
|
88
|
+
[MIT License][link-mitlic].
|
89
|
+
|
90
|
+
## Code of Conduct
|
91
|
+
|
92
|
+
Everyone interacting in the zt project’s codebases, issue trackers, chat
|
93
|
+
rooms, and mailing lists, including the original author, is expected to
|
94
|
+
follow the [code of conduct][link-coc].
|
95
|
+
|
96
|
+
[link-repo]: https://github.com/daveio/zt
|
97
|
+
[link-coc]: https://github.com/daveio/zt/blob/master/CODE_OF_CONDUCT.md
|
98
|
+
[link-mitlic]: https://opensource.org/licenses/MIT
|
99
|
+
[link-bundler-guide]: https://bundler.io/v2.0/guides/creating_gem.html
|
100
|
+
[link-badge-gem]: https://badge.fury.io/rb/zt
|
101
|
+
[link-wsl]: https://en.wikipedia.org/wiki/Windows_Subsystem_for_Linux
|
102
|
+
[img-badge-gem]: https://badge.fury.io/rb/zt.svg
|
103
|
+
[img-fork_button]: https://zt.dave.io/images/fork_button.png
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "zt"
|
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
|
+
require "pry"
|
10
|
+
Pry.start
|
11
|
+
|
12
|
+
#require "irb"
|
13
|
+
#IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/exe/zt
ADDED
data/lib/zt.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'zt/cli'
|
4
|
+
require 'zt/conf'
|
5
|
+
require 'zt/constants'
|
6
|
+
require 'zt/errors'
|
7
|
+
require 'zt/exporters'
|
8
|
+
require 'zt/importers'
|
9
|
+
require 'zt/remote_api'
|
10
|
+
require 'zt/version'
|
11
|
+
|
12
|
+
# Top-level zt module
|
13
|
+
module Zt
|
14
|
+
end
|
data/lib/zt/cli.rb
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'thor'
|
4
|
+
require 'zt'
|
5
|
+
|
6
|
+
module Zt
|
7
|
+
# Base CLI class
|
8
|
+
class CLI < Thor
|
9
|
+
attr_accessor :conf
|
10
|
+
|
11
|
+
def initialize(thor_args = [], thor_options = {}, thor_config = {})
|
12
|
+
super(thor_args, thor_options, thor_config)
|
13
|
+
@conf = Conf.instance.conf
|
14
|
+
end
|
15
|
+
|
16
|
+
desc 'version', 'Show the zt version number'
|
17
|
+
def version
|
18
|
+
puts "zt version #{Zt::VERSION}"
|
19
|
+
end
|
20
|
+
|
21
|
+
desc 'pull',
|
22
|
+
'Fetch and save the current state of your networks'
|
23
|
+
def pull
|
24
|
+
puts '≫ pull started'
|
25
|
+
puts ' ≫ pulling'
|
26
|
+
rapi = Zt::RemoteAPI::ZeroTierAPI.new
|
27
|
+
print ' ≫ networks '
|
28
|
+
rnetworks = rapi.networks
|
29
|
+
column_width = rnetworks.map { |n| n['config']['name'].length }.max + 1
|
30
|
+
print ' ' * (column_width + 9)
|
31
|
+
puts '✅'
|
32
|
+
rnodes = {}
|
33
|
+
rnetworks.each do |net|
|
34
|
+
netid = net['id']
|
35
|
+
netname = net['config']['name']
|
36
|
+
print " ≫ nodes for network #{netname}"
|
37
|
+
rnodes[netid] = rapi.network_members(netid)
|
38
|
+
print ' ' * (column_width - netname.length)
|
39
|
+
puts '✅'
|
40
|
+
end
|
41
|
+
puts ' ≫ processing'
|
42
|
+
importer_results = Zt::Importers::Importer.new(rnetworks, rnodes).import
|
43
|
+
lnetworks = {}
|
44
|
+
ldomains = {}
|
45
|
+
lnodes = {}
|
46
|
+
importer_results.each do |importer_result|
|
47
|
+
if importer_result.key?(:networks)
|
48
|
+
importer_result[:networks].each_key do |netid|
|
49
|
+
ldomains[netid] =
|
50
|
+
importer_result[:networks][netid][:local][:dns_zone]
|
51
|
+
lnetworks[netid] = importer_result[:networks][netid]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
next unless importer_result.key?(:nodes)
|
56
|
+
|
57
|
+
importer_result[:nodes].each_key do |nodeid|
|
58
|
+
lnodes[nodeid] = importer_result[:nodes][nodeid]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
puts ' ≫ saving'
|
62
|
+
Zt::Conf.instance.conf.domains = ldomains
|
63
|
+
Zt::Conf.instance.conf.networks = lnetworks
|
64
|
+
Zt::Conf.instance.conf.nodes = lnodes
|
65
|
+
Zt::Conf.instance.save!
|
66
|
+
puts '≫ pull completed'
|
67
|
+
end
|
68
|
+
|
69
|
+
desc 'export',
|
70
|
+
'export the on-disk database to STDOUT in /etc/hosts format'
|
71
|
+
def export(format = :hosts)
|
72
|
+
output = Zt::Exporters::Exporter.new.export_one_format :hosts
|
73
|
+
puts output
|
74
|
+
end
|
75
|
+
|
76
|
+
desc 'auth [TOKEN]',
|
77
|
+
'Store an authentication token (unencrypted) in the config'
|
78
|
+
def auth(token)
|
79
|
+
token_regex = Constants::AUTH_TOKEN_REGEX
|
80
|
+
if token.length != Constants::AUTH_TOKEN_LENGTH
|
81
|
+
abort('Authentication token must be exactly 32 characters')
|
82
|
+
elsif !token_regex.match?(token)
|
83
|
+
abort('Authentication token contains invalid characters, only ' \
|
84
|
+
'alphanumerics are permitted.')
|
85
|
+
else
|
86
|
+
conf.zt['token'] = token
|
87
|
+
Zt::Conf.instance.save! :zt
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
data/lib/zt/conf.rb
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'ostruct'
|
4
|
+
require 'singleton'
|
5
|
+
require 'yaml'
|
6
|
+
require 'zt/constants'
|
7
|
+
require 'zt/errors'
|
8
|
+
|
9
|
+
module Zt
|
10
|
+
# Create initial config if it is not present already
|
11
|
+
class Conf
|
12
|
+
include Singleton
|
13
|
+
attr_accessor :conf
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
raise Errors::ZtConfDiskError unless ensure_config_on_disk
|
17
|
+
raise Errors::ZtConfSyntaxError unless read_config
|
18
|
+
end
|
19
|
+
|
20
|
+
def save!(*sections)
|
21
|
+
sections = %i[domains networks nodes zt] if sections.empty?
|
22
|
+
sections.each do |section|
|
23
|
+
File.open(full_path_for_section(section), 'w') do |f|
|
24
|
+
YAML.dump(@conf[section], f)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def full_path_for_section(section)
|
32
|
+
raise Errors::ZtConfInvalidSectionError unless
|
33
|
+
Constants::CONF_SECTIONS.key? section
|
34
|
+
|
35
|
+
"#{Constants::CONF_DIR}/#{Constants::CONF_SECTIONS[section]}"
|
36
|
+
end
|
37
|
+
|
38
|
+
def read_config
|
39
|
+
@conf = OpenStruct.new
|
40
|
+
Constants::CONF_SECTIONS.each_key do |section|
|
41
|
+
@conf[section] =
|
42
|
+
YAML.load_file(
|
43
|
+
"#{Constants::CONF_DIR}/#{Constants::CONF_SECTIONS[section]}"
|
44
|
+
)
|
45
|
+
end
|
46
|
+
true
|
47
|
+
rescue StandardError
|
48
|
+
false
|
49
|
+
end
|
50
|
+
|
51
|
+
def ensure_config_on_disk
|
52
|
+
ensure_config_dir && ensure_config_files
|
53
|
+
end
|
54
|
+
|
55
|
+
def ensure_config_files
|
56
|
+
existing_files = []
|
57
|
+
created_files = []
|
58
|
+
Constants::INITIAL_CONF.keys.each do |config_file|
|
59
|
+
if File.exist?("#{Constants::CONF_DIR}/#{config_file}")
|
60
|
+
existing_files.append(config_file)
|
61
|
+
elsif create_config_file("#{Constants::CONF_DIR}/#{config_file}",
|
62
|
+
Constants::INITIAL_CONF[config_file])
|
63
|
+
created_files.append(config_file)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
(existing_files + created_files).uniq.sort ==
|
67
|
+
Constants::INITIAL_CONF.keys.sort
|
68
|
+
end
|
69
|
+
|
70
|
+
def create_config_file(path, content)
|
71
|
+
File.open(path, 'w') do |f|
|
72
|
+
YAML.dump(content, f)
|
73
|
+
end
|
74
|
+
true
|
75
|
+
rescue StandardError
|
76
|
+
false
|
77
|
+
end
|
78
|
+
|
79
|
+
def ensure_config_dir
|
80
|
+
if Dir.exist? Constants::CONF_DIR
|
81
|
+
dir_exists = true
|
82
|
+
dir_created = false
|
83
|
+
else
|
84
|
+
dir_exists = false
|
85
|
+
dir_created = create_config_dir(Constants::CONF_DIR)
|
86
|
+
end
|
87
|
+
dir_created || dir_exists
|
88
|
+
end
|
89
|
+
|
90
|
+
def create_config_dir(path)
|
91
|
+
Dir.mkdir(path)
|
92
|
+
true
|
93
|
+
rescue StandardError
|
94
|
+
false
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|